Browse Source

Merge ../linux-2.6

Mauro Carvalho Chehab 17 years ago
parent
commit
eb703027ac
100 changed files with 3188 additions and 1199 deletions
  1. 1 0
      Documentation/sound/alsa/ALSA-Configuration.txt
  2. 4 4
      Documentation/sparse.txt
  3. 1 2
      Kbuild
  4. 70 45
      Makefile
  5. 18 1
      arch/avr32/boards/atstk1000/atstk1002.c
  6. 1 1
      arch/avr32/boards/atstk1000/atstk1003.c
  7. 1 1
      arch/avr32/boards/atstk1000/atstk1004.c
  8. 5 1
      arch/avr32/kernel/time.c
  9. 38 18
      arch/avr32/mach-at32ap/at32ap700x.c
  10. 3 2
      arch/ia64/kvm/kvm-ia64.c
  11. 3 2
      arch/powerpc/kvm/44x_tlb.c
  12. 1 1
      arch/powerpc/kvm/emulate.c
  13. 33 29
      arch/s390/kvm/gaccess.h
  14. 10 4
      arch/s390/kvm/intercept.c
  15. 7 14
      arch/s390/kvm/interrupt.c
  16. 7 2
      arch/s390/kvm/kvm-s390.c
  17. 3 2
      arch/s390/kvm/sigp.c
  18. 7 0
      arch/x86/kvm/mmu.c
  19. 8 2
      arch/x86/kvm/svm.c
  20. 12 10
      arch/x86/kvm/vmx.c
  21. 43 66
      arch/x86/kvm/x86.c
  22. 34 15
      drivers/crypto/talitos.c
  23. 7 2
      drivers/firewire/Kconfig
  24. 1 1
      drivers/firewire/fw-card.c
  25. 3 3
      drivers/firewire/fw-cdev.c
  26. 24 13
      drivers/firewire/fw-ohci.c
  27. 0 2
      drivers/firewire/fw-topology.c
  28. 30 49
      drivers/firewire/fw-transaction.c
  29. 1 0
      drivers/isdn/hardware/mISDN/Kconfig
  30. 1 1
      drivers/isdn/mISDN/layer2.c
  31. 1 1
      drivers/isdn/mISDN/layer2.h
  32. 1 1
      drivers/isdn/mISDN/tei.c
  33. 13 0
      drivers/md/dm-mpath.c
  34. 12 12
      drivers/message/fusion/mptbase.c
  35. 2 2
      drivers/message/fusion/mptctl.c
  36. 4 4
      drivers/message/fusion/mptfc.c
  37. 13 13
      drivers/message/fusion/mptlan.c
  38. 27 27
      drivers/message/fusion/mptsas.c
  39. 2 2
      drivers/message/fusion/mptscsih.c
  40. 1 1
      drivers/misc/Kconfig
  41. 0 1
      drivers/misc/atmel-ssc.c
  42. 9 8
      drivers/mmc/host/atmel-mci.c
  43. 1 1
      drivers/s390/kvm/Makefile
  44. 30 10
      drivers/scsi/3w-9xxx.c
  45. 5 4
      drivers/scsi/3w-9xxx.h
  46. 1 0
      drivers/scsi/Kconfig
  47. 2 0
      drivers/scsi/Makefile
  48. 1 1
      drivers/scsi/advansys.c
  49. 6 6
      drivers/scsi/aha152x.c
  50. 2 2
      drivers/scsi/aic94xx/aic94xx.h
  51. 1 1
      drivers/scsi/aic94xx/aic94xx_hwi.c
  52. 23 23
      drivers/scsi/aic94xx/aic94xx_scb.c
  53. 1 1
      drivers/scsi/aic94xx/aic94xx_task.c
  54. 9 9
      drivers/scsi/aic94xx/aic94xx_tmf.c
  55. 2 2
      drivers/scsi/arm/fas216.c
  56. 1 0
      drivers/scsi/ch.c
  57. 8 0
      drivers/scsi/device_handler/Kconfig
  58. 1 0
      drivers/scsi/device_handler/Makefile
  59. 415 31
      drivers/scsi/device_handler/scsi_dh.c
  60. 802 0
      drivers/scsi/device_handler/scsi_dh_alua.c
  61. 409 235
      drivers/scsi/device_handler/scsi_dh_emc.c
  62. 261 87
      drivers/scsi/device_handler/scsi_dh_hp_sw.c
  63. 132 130
      drivers/scsi/device_handler/scsi_dh_rdac.c
  64. 177 27
      drivers/scsi/ibmvscsi/ibmvfc.c
  65. 40 4
      drivers/scsi/ibmvscsi/ibmvfc.h
  66. 1 1
      drivers/scsi/ibmvscsi/ibmvstgt.c
  67. 1 1
      drivers/scsi/imm.c
  68. 3 3
      drivers/scsi/ipr.h
  69. 8 8
      drivers/scsi/libsas/sas_ata.c
  70. 6 6
      drivers/scsi/libsas/sas_expander.c
  71. 2 2
      drivers/scsi/libsas/sas_port.c
  72. 15 15
      drivers/scsi/libsas/sas_scsi_host.c
  73. 1 1
      drivers/scsi/libsrp.c
  74. 2 2
      drivers/scsi/lpfc/lpfc_init.c
  75. 1 1
      drivers/scsi/lpfc/lpfc_scsi.c
  76. 3 3
      drivers/scsi/lpfc/lpfc_sli.c
  77. 1 1
      drivers/scsi/megaraid/mega_common.h
  78. 8 8
      drivers/scsi/megaraid/megaraid_mbox.c
  79. 2 2
      drivers/scsi/megaraid/megaraid_mm.c
  80. 2 2
      drivers/scsi/nsp32.c
  81. 1 1
      drivers/scsi/nsp32_debug.c
  82. 2 2
      drivers/scsi/pcmcia/nsp_cs.c
  83. 1 1
      drivers/scsi/pcmcia/nsp_debug.c
  84. 1 1
      drivers/scsi/ppa.c
  85. 6 6
      drivers/scsi/qla1280.c
  86. 61 57
      drivers/scsi/qla2xxx/qla_attr.c
  87. 1 1
      drivers/scsi/qla2xxx/qla_dbg.c
  88. 8 4
      drivers/scsi/qla2xxx/qla_def.h
  89. 4 1
      drivers/scsi/qla2xxx/qla_gbl.h
  90. 6 0
      drivers/scsi/qla2xxx/qla_gs.c
  91. 73 60
      drivers/scsi/qla2xxx/qla_init.c
  92. 8 6
      drivers/scsi/qla2xxx/qla_iocb.c
  93. 0 4
      drivers/scsi/qla2xxx/qla_isr.c
  94. 6 3
      drivers/scsi/qla2xxx/qla_mbx.c
  95. 6 10
      drivers/scsi/qla2xxx/qla_mid.c
  96. 59 35
      drivers/scsi/qla2xxx/qla_os.c
  97. 45 3
      drivers/scsi/qla2xxx/qla_sup.c
  98. 1 1
      drivers/scsi/qla2xxx/qla_version.h
  99. 3 1
      drivers/scsi/qla4xxx/ql4_os.c
  100. 48 7
      drivers/scsi/scsi.c

+ 1 - 0
Documentation/sound/alsa/ALSA-Configuration.txt

@@ -1024,6 +1024,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 	  intel-mac-v3	Intel Mac Type 3
 	  intel-mac-v3	Intel Mac Type 3
 	  intel-mac-v4	Intel Mac Type 4
 	  intel-mac-v4	Intel Mac Type 4
 	  intel-mac-v5	Intel Mac Type 5
 	  intel-mac-v5	Intel Mac Type 5
+	  intel-mac-auto Intel Mac (detect type according to subsystem id)
 	  macmini	Intel Mac Mini (equivalent with type 3)
 	  macmini	Intel Mac Mini (equivalent with type 3)
 	  macbook	Intel Mac Book (eq. type 5)
 	  macbook	Intel Mac Book (eq. type 5)
 	  macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)
 	  macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)

+ 4 - 4
Documentation/sparse.txt

@@ -73,10 +73,10 @@ recompiled, or use "make C=2" to run sparse on the files whether they need to
 be recompiled or not.  The latter is a fast way to check the whole tree if you
 be recompiled or not.  The latter is a fast way to check the whole tree if you
 have already built it.
 have already built it.
 
 
-The optional make variable CHECKFLAGS can be used to pass arguments to sparse.
-The build system passes -Wbitwise to sparse automatically.  To perform
-endianness checks, you may define __CHECK_ENDIAN__:
+The optional make variable CF can be used to pass arguments to sparse.  The
+build system passes -Wbitwise to sparse automatically.  To perform endianness
+checks, you may define __CHECK_ENDIAN__:
 
 
-        make C=2 CHECKFLAGS="-D__CHECK_ENDIAN__"
+        make C=2 CF="-D__CHECK_ENDIAN__"
 
 
 These checks are disabled by default as they generate a host of warnings.
 These checks are disabled by default as they generate a host of warnings.

+ 1 - 2
Kbuild

@@ -43,7 +43,7 @@ $(obj)/$(bounds-file): kernel/bounds.s Kbuild
 # 2) Generate asm-offsets.h
 # 2) Generate asm-offsets.h
 #
 #
 
 
-offsets-file := include/asm-$(SRCARCH)/asm-offsets.h
+offsets-file := include/asm/asm-offsets.h
 
 
 always  += $(offsets-file)
 always  += $(offsets-file)
 targets += $(offsets-file)
 targets += $(offsets-file)
@@ -81,7 +81,6 @@ arch/$(SRCARCH)/kernel/asm-offsets.s: arch/$(SRCARCH)/kernel/asm-offsets.c \
 	$(call if_changed_dep,cc_s_c)
 	$(call if_changed_dep,cc_s_c)
 
 
 $(obj)/$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s Kbuild
 $(obj)/$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s Kbuild
-	$(Q)mkdir -p $(dir $@)
 	$(call cmd,offsets)
 	$(call cmd,offsets)
 
 
 #####
 #####

+ 70 - 45
Makefile

@@ -205,6 +205,9 @@ ifeq ($(ARCH),x86_64)
         SRCARCH := x86
         SRCARCH := x86
 endif
 endif
 
 
+# Where to locate arch specific headers
+hdr-arch       := $(SRCARCH)
+
 KCONFIG_CONFIG	?= .config
 KCONFIG_CONFIG	?= .config
 
 
 # SHELL used by kbuild
 # SHELL used by kbuild
@@ -326,7 +329,8 @@ AFLAGS_KERNEL	=
 # Needed to be compatible with the O= option
 # Needed to be compatible with the O= option
 LINUXINCLUDE    := -Iinclude \
 LINUXINCLUDE    := -Iinclude \
                    $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
                    $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
-		   -include include/linux/autoconf.h
+                   -I$(srctree)/arch/$(hdr-arch)/include               \
+                   -include include/linux/autoconf.h
 
 
 KBUILD_CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
 KBUILD_CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
 
 
@@ -922,7 +926,9 @@ ifneq ($(KBUILD_SRC),)
 		/bin/false; \
 		/bin/false; \
 	fi;
 	fi;
 	$(Q)if [ ! -d include2 ]; then mkdir -p include2; fi;
 	$(Q)if [ ! -d include2 ]; then mkdir -p include2; fi;
-	$(Q)ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm
+	$(Q)if [ -e $(srctree)/include/asm-$(SRCARCH)/system.h ]; then  \
+	    ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm;     \
+	    fi
 endif
 endif
 
 
 # prepare2 creates a makefile if using a separate output directory
 # prepare2 creates a makefile if using a separate output directory
@@ -948,22 +954,34 @@ export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)
 
 
 # The asm symlink changes when $(ARCH) changes.
 # The asm symlink changes when $(ARCH) changes.
 # Detect this and ask user to run make mrproper
 # Detect this and ask user to run make mrproper
-
-include/asm: FORCE
-	$(Q)set -e; asmlink=`readlink include/asm | cut -d '-' -f 2`;   \
-	if [ -L include/asm ]; then                                     \
-		if [ "$$asmlink" != "$(SRCARCH)" ]; then                \
+define check-symlink
+	set -e;                                                            \
+	if [ -L include/asm ]; then                                        \
+		asmlink=`readlink include/asm | cut -d '-' -f 2`;          \
+		if [ "$$asmlink" != "$(SRCARCH)" ]; then                   \
 			echo "ERROR: the symlink $@ points to asm-$$asmlink but asm-$(SRCARCH) was expected"; \
 			echo "ERROR: the symlink $@ points to asm-$$asmlink but asm-$(SRCARCH) was expected"; \
 			echo "       set ARCH or save .config and run 'make mrproper' to fix it";             \
 			echo "       set ARCH or save .config and run 'make mrproper' to fix it";             \
-			exit 1;                                         \
-		fi;                                                     \
-	else                                                            \
-		echo '  SYMLINK $@ -> include/asm-$(SRCARCH)';          \
-		if [ ! -d include ]; then                               \
-			mkdir -p include;                               \
-		fi;                                                     \
-		ln -fsn asm-$(SRCARCH) $@;                              \
+			exit 1;                                            \
+		fi;                                                        \
 	fi
 	fi
+endef
+
+# We create the target directory of the symlink if it does
+# not exist so the test in chack-symlink works and we have a
+# directory for generated filesas used by some architectures.
+define create-symlink
+	if [ ! -L include/asm ]; then                                      \
+			echo '  SYMLINK $@ -> include/asm-$(SRCARCH)';     \
+			if [ ! -d include/asm-$(SRCARCH) ]; then           \
+				mkdir -p include/asm-$(SRCARCH);           \
+			fi;                                                \
+			ln -fsn asm-$(SRCARCH) $@;                         \
+	fi
+endef
+
+include/asm: FORCE
+	$(Q)$(check-symlink)
+	$(Q)$(create-symlink)
 
 
 # Generate some files
 # Generate some files
 # ---------------------------------------------------------------------------
 # ---------------------------------------------------------------------------
@@ -1010,36 +1028,43 @@ firmware_install: FORCE
 
 
 # ---------------------------------------------------------------------------
 # ---------------------------------------------------------------------------
 # Kernel headers
 # Kernel headers
-INSTALL_HDR_PATH=$(objtree)/usr
-export INSTALL_HDR_PATH
 
 
-HDRFILTER=generic i386 x86_64
-HDRARCHES=$(filter-out $(HDRFILTER),$(patsubst $(srctree)/include/asm-%/Kbuild,%,$(wildcard $(srctree)/include/asm-*/Kbuild)))
+#Default location for installed headers
+export INSTALL_HDR_PATH = $(objtree)/usr
 
 
-PHONY += headers_install_all
-headers_install_all: include/linux/version.h scripts_basic FORCE
+hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
+# Find out where the Kbuild file is located to support
+# arch/$(ARCH)/include/asm
+hdr-dir = $(strip                                                         \
+          $(if $(wildcard $(srctree)/arch/$(hdr-arch)/include/asm/Kbuild), \
+               arch/$(hdr-arch)/include/asm, include/asm-$(hdr-arch)))
+
+# If we do an all arch process set dst to asm-$(hdr-arch)
+hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
+
+PHONY += __headers
+__headers: include/linux/version.h scripts_basic FORCE
 	$(Q)$(MAKE) $(build)=scripts scripts/unifdef
 	$(Q)$(MAKE) $(build)=scripts scripts/unifdef
-	$(Q)for arch in $(HDRARCHES); do \
-	 $(MAKE) ARCH=$$arch -f $(srctree)/scripts/Makefile.headersinst obj=include BIASMDIR=-bi-$$arch ;\
-	 done
+
+PHONY += headers_install_all
+headers_install_all:
+	$(Q)$(CONFIG_SHELL) $(srctree)/scripts/headers.sh install
 
 
 PHONY += headers_install
 PHONY += headers_install
-headers_install: include/linux/version.h scripts_basic FORCE
-	@if [ ! -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \
-	  echo '*** Error: Headers not exportable for this architecture ($(SRCARCH))'; \
-	  exit 1 ; fi
-	$(Q)$(MAKE) $(build)=scripts scripts/unifdef
-	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst ARCH=$(SRCARCH) obj=include
+headers_install: __headers
+	$(if $(wildcard $(srctree)/$(hdr-dir)/Kbuild),, \
+	$(error Headers not exportable for the $(SRCARCH) architecture))
+	$(Q)$(MAKE) $(hdr-inst)=include
+	$(Q)$(MAKE) $(hdr-inst)=$(hdr-dir) $(hdr-dst)
 
 
 PHONY += headers_check_all
 PHONY += headers_check_all
 headers_check_all: headers_install_all
 headers_check_all: headers_install_all
-	$(Q)for arch in $(HDRARCHES); do \
-	 $(MAKE) ARCH=$$arch -f $(srctree)/scripts/Makefile.headersinst obj=include BIASMDIR=-bi-$$arch HDRCHECK=1 ;\
-	 done
+	$(Q)$(CONFIG_SHELL) $(srctree)/scripts/headers.sh check
 
 
 PHONY += headers_check
 PHONY += headers_check
 headers_check: headers_install
 headers_check: headers_install
-	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.headersinst ARCH=$(SRCARCH) obj=include HDRCHECK=1
+	$(Q)$(MAKE) $(hdr-inst)=include HDRCHECK=1
+	$(Q)$(MAKE) $(hdr-inst)=$(hdr-dir) $(hdr-dst) HDRCHECK=1
 
 
 # ---------------------------------------------------------------------------
 # ---------------------------------------------------------------------------
 # Modules
 # Modules
@@ -1131,7 +1156,7 @@ MRPROPER_FILES += .config .config.old include/asm .version .old_version \
                   include/linux/autoconf.h include/linux/version.h      \
                   include/linux/autoconf.h include/linux/version.h      \
                   include/linux/utsrelease.h                            \
                   include/linux/utsrelease.h                            \
                   include/linux/bounds.h include/asm*/asm-offsets.h     \
                   include/linux/bounds.h include/asm*/asm-offsets.h     \
-		  Module.symvers tags TAGS cscope*
+		  Module.symvers Module.markers tags TAGS cscope*
 
 
 # clean - Delete most, but leave enough to build external modules
 # clean - Delete most, but leave enough to build external modules
 #
 #
@@ -1150,7 +1175,7 @@ clean: archclean $(clean-dirs)
 		\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
 		\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
 		-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
 		-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
 		-o -name '*.symtypes' -o -name 'modules.order' \
 		-o -name '*.symtypes' -o -name 'modules.order' \
-		-o -name 'Module.markers' \) \
+		-o -name 'Module.markers' -o -name '.tmp_*.o.*' \) \
 		-type f -print | xargs rm -f
 		-type f -print | xargs rm -f
 
 
 # mrproper - Delete all generated files, including .config
 # mrproper - Delete all generated files, including .config
@@ -1224,21 +1249,17 @@ help:
 	@echo  '  cscope	  - Generate cscope index'
 	@echo  '  cscope	  - Generate cscope index'
 	@echo  '  kernelrelease	  - Output the release version string'
 	@echo  '  kernelrelease	  - Output the release version string'
 	@echo  '  kernelversion	  - Output the version stored in Makefile'
 	@echo  '  kernelversion	  - Output the version stored in Makefile'
-	@if [ -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \
-	 echo  '  headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
+	@echo  '  headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
 	 echo  '                    (default: $(INSTALL_HDR_PATH))'; \
 	 echo  '                    (default: $(INSTALL_HDR_PATH))'; \
-	 fi
-	@echo  ''
+	 echo  ''
 	@echo  'Static analysers'
 	@echo  'Static analysers'
 	@echo  '  checkstack      - Generate a list of stack hogs'
 	@echo  '  checkstack      - Generate a list of stack hogs'
 	@echo  '  namespacecheck  - Name space analysis on compiled kernel'
 	@echo  '  namespacecheck  - Name space analysis on compiled kernel'
 	@echo  '  versioncheck    - Sanity check on version.h usage'
 	@echo  '  versioncheck    - Sanity check on version.h usage'
 	@echo  '  includecheck    - Check for duplicate included header files'
 	@echo  '  includecheck    - Check for duplicate included header files'
 	@echo  '  export_report   - List the usages of all exported symbols'
 	@echo  '  export_report   - List the usages of all exported symbols'
-	@if [ -r $(srctree)/include/asm-$(SRCARCH)/Kbuild ]; then \
-	 echo  '  headers_check   - Sanity check on exported headers'; \
-	 fi
-	@echo  ''
+	@echo  '  headers_check   - Sanity check on exported headers'; \
+	 echo  ''
 	@echo  'Kernel packaging:'
 	@echo  'Kernel packaging:'
 	@$(MAKE) $(build)=$(package-dir) help
 	@$(MAKE) $(build)=$(package-dir) help
 	@echo  ''
 	@echo  ''
@@ -1411,7 +1432,11 @@ define find-sources
 	       \( -name config -o -name 'asm-*' \) -prune \
 	       \( -name config -o -name 'asm-*' \) -prune \
 	       -o -name $1 -print; \
 	       -o -name $1 -print; \
 	  for arch in $(ALLINCLUDE_ARCHS) ; do \
 	  for arch in $(ALLINCLUDE_ARCHS) ; do \
-	       find $(__srctree)include/asm-$${arch} $(RCS_FIND_IGNORE) \
+	       test -e $(__srctree)include/asm-$${arch} && \
+                 find $(__srctree)include/asm-$${arch} $(RCS_FIND_IGNORE) \
+	            -name $1 -print; \
+	       test -e $(__srctree)arch/$${arch}/include/asm && \
+	         find $(__srctree)arch/$${arch}/include/asm $(RCS_FIND_IGNORE) \
 	            -name $1 -print; \
 	            -name $1 -print; \
 	  done ; \
 	  done ; \
 	  find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
 	  find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \

+ 18 - 1
arch/avr32/boards/atstk1000/atstk1002.c

@@ -21,6 +21,8 @@
 
 
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/setup.h>
+#include <asm/atmel-mci.h>
+
 #include <asm/arch/at32ap700x.h>
 #include <asm/arch/at32ap700x.h>
 #include <asm/arch/board.h>
 #include <asm/arch/board.h>
 #include <asm/arch/init.h>
 #include <asm/arch/init.h>
@@ -260,6 +262,21 @@ void __init setup_board(void)
 	at32_setup_serial_console(0);
 	at32_setup_serial_console(0);
 }
 }
 
 
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+
+/* MMC card detect requires MACB0 *NOT* be used */
+#ifdef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+	.detect_pin	= GPIO_PIN_PC(14),	/* gpio30/sdcd */
+	.wp_pin		= GPIO_PIN_PC(15),	/* gpio31/sdwp */
+};
+#define MCI_PDATA	&mci0_data
+#else
+#define MCI_PDATA	NULL
+#endif	/* SW6 for sd{cd,wp} routing */
+
+#endif	/* SW2 for MMC signal routing */
+
 static int __init atstk1002_init(void)
 static int __init atstk1002_init(void)
 {
 {
 	/*
 	/*
@@ -309,7 +326,7 @@ static int __init atstk1002_init(void)
 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #endif
 #ifndef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
 #ifndef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
-	at32_add_device_mci(0, NULL);
+	at32_add_device_mci(0, MCI_PDATA);
 #endif
 #endif
 #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
 #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
 	set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
 	set_hw_addr(at32_add_device_eth(1, &eth_data[1]));

+ 1 - 1
arch/avr32/boards/atstk1000/atstk1003.c

@@ -154,7 +154,7 @@ static int __init atstk1003_init(void)
 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-	at32_add_device_mci(0);
+	at32_add_device_mci(0, NULL);
 #endif
 #endif
 	at32_add_device_usba(0, NULL);
 	at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM

+ 1 - 1
arch/avr32/boards/atstk1000/atstk1004.c

@@ -137,7 +137,7 @@ static int __init atstk1004_init(void)
 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-	at32_add_device_mci(0);
+	at32_add_device_mci(0, NULL);
 #endif
 #endif
 	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
 	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
 			     fbmem_start, fbmem_size, 0);
 			     fbmem_start, fbmem_size, 0);

+ 5 - 1
arch/avr32/kernel/time.c

@@ -43,6 +43,9 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
 {
 	struct clock_event_device *evdev = dev_id;
 	struct clock_event_device *evdev = dev_id;
 
 
+	if (unlikely(!(intc_get_pending(0) & 1)))
+		return IRQ_NONE;
+
 	/*
 	/*
 	 * Disable the interrupt until the clockevent subsystem
 	 * Disable the interrupt until the clockevent subsystem
 	 * reprograms it.
 	 * reprograms it.
@@ -55,7 +58,8 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 
 
 static struct irqaction timer_irqaction = {
 static struct irqaction timer_irqaction = {
 	.handler	= timer_interrupt,
 	.handler	= timer_interrupt,
-	.flags		= IRQF_TIMER | IRQF_DISABLED,
+	/* Oprofile uses the same irq as the timer, so allow it to be shared */
+	.flags		= IRQF_TIMER | IRQF_DISABLED | IRQF_SHARED,
 	.name		= "avr32_comparator",
 	.name		= "avr32_comparator",
 };
 };
 
 

+ 38 - 18
arch/avr32/mach-at32ap/at32ap700x.c

@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
+#include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <linux/usb/atmel_usba_udc.h>
 #include <linux/usb/atmel_usba_udc.h>
 
 
@@ -1285,7 +1286,6 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
 {
 {
 	struct mci_platform_data	_data;
 	struct mci_platform_data	_data;
 	struct platform_device		*pdev;
 	struct platform_device		*pdev;
-	struct dw_dma_slave		*dws;
 
 
 	if (id != 0)
 	if (id != 0)
 		return NULL;
 		return NULL;
@@ -1300,7 +1300,9 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
 
 
 	if (!data) {
 	if (!data) {
 		data = &_data;
 		data = &_data;
-		memset(data, 0, sizeof(struct mci_platform_data));
+		memset(data, -1, sizeof(struct mci_platform_data));
+		data->detect_pin = GPIO_PIN_NONE;
+		data->wp_pin = GPIO_PIN_NONE;
 	}
 	}
 
 
 	if (platform_device_add_data(pdev, data,
 	if (platform_device_add_data(pdev, data,
@@ -1314,12 +1316,10 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
 	select_peripheral(PA(14), PERIPH_A, 0);	/* DATA2 */
 	select_peripheral(PA(14), PERIPH_A, 0);	/* DATA2 */
 	select_peripheral(PA(15), PERIPH_A, 0);	/* DATA3 */
 	select_peripheral(PA(15), PERIPH_A, 0);	/* DATA3 */
 
 
-	if (data) {
-		if (data->detect_pin != GPIO_PIN_NONE)
-			at32_select_gpio(data->detect_pin, 0);
-		if (data->wp_pin != GPIO_PIN_NONE)
-			at32_select_gpio(data->wp_pin, 0);
-	}
+	if (gpio_is_valid(data->detect_pin))
+		at32_select_gpio(data->detect_pin, 0);
+	if (gpio_is_valid(data->wp_pin))
+		at32_select_gpio(data->wp_pin, 0);
 
 
 	atmel_mci0_pclk.dev = &pdev->dev;
 	atmel_mci0_pclk.dev = &pdev->dev;
 
 
@@ -1853,11 +1853,11 @@ at32_add_device_cf(unsigned int id, unsigned int extint,
 	if (at32_init_ide_or_cf(pdev, data->cs, extint))
 	if (at32_init_ide_or_cf(pdev, data->cs, extint))
 		goto fail;
 		goto fail;
 
 
-	if (data->detect_pin != GPIO_PIN_NONE)
+	if (gpio_is_valid(data->detect_pin))
 		at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
 		at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
-	if (data->reset_pin != GPIO_PIN_NONE)
+	if (gpio_is_valid(data->reset_pin))
 		at32_select_gpio(data->reset_pin, 0);
 		at32_select_gpio(data->reset_pin, 0);
-	if (data->vcc_pin != GPIO_PIN_NONE)
+	if (gpio_is_valid(data->vcc_pin))
 		at32_select_gpio(data->vcc_pin, 0);
 		at32_select_gpio(data->vcc_pin, 0);
 	/* READY is used as extint, so we can't select it as gpio */
 	/* READY is used as extint, so we can't select it as gpio */
 
 
@@ -1937,9 +1937,11 @@ static struct clk atmel_ac97c0_pclk = {
 	.index		= 10,
 	.index		= 10,
 };
 };
 
 
-struct platform_device *__init at32_add_device_ac97c(unsigned int id)
+struct platform_device *__init
+at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data)
 {
 {
 	struct platform_device *pdev;
 	struct platform_device *pdev;
+	struct ac97c_platform_data _data;
 
 
 	if (id != 0)
 	if (id != 0)
 		return NULL;
 		return NULL;
@@ -1950,19 +1952,37 @@ struct platform_device *__init at32_add_device_ac97c(unsigned int id)
 
 
 	if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
 	if (platform_device_add_resources(pdev, atmel_ac97c0_resource,
 				ARRAY_SIZE(atmel_ac97c0_resource)))
 				ARRAY_SIZE(atmel_ac97c0_resource)))
-		goto err_add_resources;
+		goto fail;
+
+	if (!data) {
+		data = &_data;
+		memset(data, 0, sizeof(struct ac97c_platform_data));
+		data->reset_pin = GPIO_PIN_NONE;
+	}
 
 
-	select_peripheral(PB(20), PERIPH_B, 0);	/* SYNC	*/
-	select_peripheral(PB(21), PERIPH_B, 0);	/* SDO	*/
-	select_peripheral(PB(22), PERIPH_B, 0);	/* SDI	*/
-	select_peripheral(PB(23), PERIPH_B, 0);	/* SCLK	*/
+	data->dma_rx_periph_id = 3;
+	data->dma_tx_periph_id = 4;
+	data->dma_controller_id = 0;
+
+	if (platform_device_add_data(pdev, data,
+				sizeof(struct ac97c_platform_data)))
+		goto fail;
+
+	select_peripheral(PB(20), PERIPH_B, 0);	/* SDO	*/
+	select_peripheral(PB(21), PERIPH_B, 0);	/* SYNC	*/
+	select_peripheral(PB(22), PERIPH_B, 0);	/* SCLK	*/
+	select_peripheral(PB(23), PERIPH_B, 0);	/* SDI	*/
+
+	/* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */
+	if (data->reset_pin != GPIO_PIN_NONE)
+		at32_select_gpio(data->reset_pin, 0);
 
 
 	atmel_ac97c0_pclk.dev = &pdev->dev;
 	atmel_ac97c0_pclk.dev = &pdev->dev;
 
 
 	platform_device_add(pdev);
 	platform_device_add(pdev);
 	return pdev;
 	return pdev;
 
 
-err_add_resources:
+fail:
 	platform_device_put(pdev);
 	platform_device_put(pdev);
 	return NULL;
 	return NULL;
 }
 }

+ 3 - 2
arch/ia64/kvm/kvm-ia64.c

@@ -125,9 +125,9 @@ void kvm_arch_hardware_enable(void *garbage)
 				PAGE_KERNEL));
 				PAGE_KERNEL));
 	local_irq_save(saved_psr);
 	local_irq_save(saved_psr);
 	slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
 	slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
+	local_irq_restore(saved_psr);
 	if (slot < 0)
 	if (slot < 0)
 		return;
 		return;
-	local_irq_restore(saved_psr);
 
 
 	spin_lock(&vp_lock);
 	spin_lock(&vp_lock);
 	status = ia64_pal_vp_init_env(kvm_vsa_base ?
 	status = ia64_pal_vp_init_env(kvm_vsa_base ?
@@ -160,9 +160,9 @@ void kvm_arch_hardware_disable(void *garbage)
 
 
 	local_irq_save(saved_psr);
 	local_irq_save(saved_psr);
 	slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
 	slot = ia64_itr_entry(0x3, KVM_VMM_BASE, pte, KVM_VMM_SHIFT);
+	local_irq_restore(saved_psr);
 	if (slot < 0)
 	if (slot < 0)
 		return;
 		return;
-	local_irq_restore(saved_psr);
 
 
 	status = ia64_pal_vp_exit_env(host_iva);
 	status = ia64_pal_vp_exit_env(host_iva);
 	if (status)
 	if (status)
@@ -1253,6 +1253,7 @@ static int vti_vcpu_setup(struct kvm_vcpu *vcpu, int id)
 uninit:
 uninit:
 	kvm_vcpu_uninit(vcpu);
 	kvm_vcpu_uninit(vcpu);
 fail:
 fail:
+	local_irq_restore(psr);
 	return r;
 	return r;
 }
 }
 
 

+ 3 - 2
arch/powerpc/kvm/44x_tlb.c

@@ -177,7 +177,8 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid,
 	                                            vcpu->arch.msr & MSR_PR);
 	                                            vcpu->arch.msr & MSR_PR);
 }
 }
 
 
-void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, u64 eaddr, u64 asid)
+void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, gva_t eaddr,
+                           gva_t eend, u32 asid)
 {
 {
 	unsigned int pid = asid & 0xff;
 	unsigned int pid = asid & 0xff;
 	int i;
 	int i;
@@ -191,7 +192,7 @@ void kvmppc_mmu_invalidate(struct kvm_vcpu *vcpu, u64 eaddr, u64 asid)
 		if (!get_tlb_v(stlbe))
 		if (!get_tlb_v(stlbe))
 			continue;
 			continue;
 
 
-		if (eaddr < get_tlb_eaddr(stlbe))
+		if (eend < get_tlb_eaddr(stlbe))
 			continue;
 			continue;
 
 
 		if (eaddr > get_tlb_end(stlbe))
 		if (eaddr > get_tlb_end(stlbe))

+ 1 - 1
arch/powerpc/kvm/emulate.c

@@ -137,7 +137,7 @@ static int kvmppc_emul_tlbwe(struct kvm_vcpu *vcpu, u32 inst)
 	if (tlbe->word0 & PPC44x_TLB_VALID) {
 	if (tlbe->word0 & PPC44x_TLB_VALID) {
 		eaddr = get_tlb_eaddr(tlbe);
 		eaddr = get_tlb_eaddr(tlbe);
 		asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
 		asid = (tlbe->word0 & PPC44x_TLB_TS) | tlbe->tid;
-		kvmppc_mmu_invalidate(vcpu, eaddr, asid);
+		kvmppc_mmu_invalidate(vcpu, eaddr, get_tlb_end(tlbe), asid);
 	}
 	}
 
 
 	switch (ws) {
 	switch (ws) {

+ 33 - 29
arch/s390/kvm/gaccess.h

@@ -18,11 +18,11 @@
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 
 
 static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu,
 static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu,
-					       u64 guestaddr)
+					       unsigned long guestaddr)
 {
 {
-	u64 prefix  = vcpu->arch.sie_block->prefix;
-	u64 origin  = vcpu->kvm->arch.guest_origin;
-	u64 memsize = vcpu->kvm->arch.guest_memsize;
+	unsigned long prefix  = vcpu->arch.sie_block->prefix;
+	unsigned long origin  = vcpu->kvm->arch.guest_origin;
+	unsigned long memsize = vcpu->kvm->arch.guest_memsize;
 
 
 	if (guestaddr < 2 * PAGE_SIZE)
 	if (guestaddr < 2 * PAGE_SIZE)
 		guestaddr += prefix;
 		guestaddr += prefix;
@@ -37,7 +37,7 @@ static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu,
 	return (void __user *) guestaddr;
 	return (void __user *) guestaddr;
 }
 }
 
 
-static inline int get_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr,
+static inline int get_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr,
 				u64 *result)
 				u64 *result)
 {
 {
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
@@ -47,10 +47,10 @@ static inline int get_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr,
 	if (IS_ERR((void __force *) uptr))
 	if (IS_ERR((void __force *) uptr))
 		return PTR_ERR((void __force *) uptr);
 		return PTR_ERR((void __force *) uptr);
 
 
-	return get_user(*result, (u64 __user *) uptr);
+	return get_user(*result, (unsigned long __user *) uptr);
 }
 }
 
 
-static inline int get_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr,
+static inline int get_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr,
 				u32 *result)
 				u32 *result)
 {
 {
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
@@ -63,7 +63,7 @@ static inline int get_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr,
 	return get_user(*result, (u32 __user *) uptr);
 	return get_user(*result, (u32 __user *) uptr);
 }
 }
 
 
-static inline int get_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr,
+static inline int get_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr,
 				u16 *result)
 				u16 *result)
 {
 {
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
@@ -76,7 +76,7 @@ static inline int get_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr,
 	return get_user(*result, (u16 __user *) uptr);
 	return get_user(*result, (u16 __user *) uptr);
 }
 }
 
 
-static inline int get_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr,
+static inline int get_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr,
 			       u8 *result)
 			       u8 *result)
 {
 {
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
@@ -87,7 +87,7 @@ static inline int get_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr,
 	return get_user(*result, (u8 __user *) uptr);
 	return get_user(*result, (u8 __user *) uptr);
 }
 }
 
 
-static inline int put_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr,
+static inline int put_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr,
 				u64 value)
 				u64 value)
 {
 {
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
@@ -100,7 +100,7 @@ static inline int put_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr,
 	return put_user(value, (u64 __user *) uptr);
 	return put_user(value, (u64 __user *) uptr);
 }
 }
 
 
-static inline int put_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr,
+static inline int put_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr,
 				u32 value)
 				u32 value)
 {
 {
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
@@ -113,7 +113,7 @@ static inline int put_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr,
 	return put_user(value, (u32 __user *) uptr);
 	return put_user(value, (u32 __user *) uptr);
 }
 }
 
 
-static inline int put_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr,
+static inline int put_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr,
 				u16 value)
 				u16 value)
 {
 {
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
@@ -126,7 +126,7 @@ static inline int put_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr,
 	return put_user(value, (u16 __user *) uptr);
 	return put_user(value, (u16 __user *) uptr);
 }
 }
 
 
-static inline int put_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr,
+static inline int put_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr,
 			       u8 value)
 			       u8 value)
 {
 {
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
@@ -138,7 +138,8 @@ static inline int put_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr,
 }
 }
 
 
 
 
-static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, u64 guestdest,
+static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu,
+				       unsigned long guestdest,
 				       const void *from, unsigned long n)
 				       const void *from, unsigned long n)
 {
 {
 	int rc;
 	int rc;
@@ -153,12 +154,12 @@ static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, u64 guestdest,
 	return 0;
 	return 0;
 }
 }
 
 
-static inline int copy_to_guest(struct kvm_vcpu *vcpu, u64 guestdest,
+static inline int copy_to_guest(struct kvm_vcpu *vcpu, unsigned long guestdest,
 				const void *from, unsigned long n)
 				const void *from, unsigned long n)
 {
 {
-	u64 prefix  = vcpu->arch.sie_block->prefix;
-	u64 origin  = vcpu->kvm->arch.guest_origin;
-	u64 memsize = vcpu->kvm->arch.guest_memsize;
+	unsigned long prefix  = vcpu->arch.sie_block->prefix;
+	unsigned long origin  = vcpu->kvm->arch.guest_origin;
+	unsigned long memsize = vcpu->kvm->arch.guest_memsize;
 
 
 	if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE))
 	if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE))
 		goto slowpath;
 		goto slowpath;
@@ -189,7 +190,8 @@ slowpath:
 }
 }
 
 
 static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to,
 static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to,
-					 u64 guestsrc, unsigned long n)
+					 unsigned long guestsrc,
+					 unsigned long n)
 {
 {
 	int rc;
 	int rc;
 	unsigned long i;
 	unsigned long i;
@@ -204,11 +206,11 @@ static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to,
 }
 }
 
 
 static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to,
 static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to,
-				  u64 guestsrc, unsigned long n)
+				  unsigned long guestsrc, unsigned long n)
 {
 {
-	u64 prefix  = vcpu->arch.sie_block->prefix;
-	u64 origin  = vcpu->kvm->arch.guest_origin;
-	u64 memsize = vcpu->kvm->arch.guest_memsize;
+	unsigned long prefix  = vcpu->arch.sie_block->prefix;
+	unsigned long origin  = vcpu->kvm->arch.guest_origin;
+	unsigned long memsize = vcpu->kvm->arch.guest_memsize;
 
 
 	if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE))
 	if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE))
 		goto slowpath;
 		goto slowpath;
@@ -238,11 +240,12 @@ slowpath:
 	return __copy_from_guest_slow(vcpu, to, guestsrc, n);
 	return __copy_from_guest_slow(vcpu, to, guestsrc, n);
 }
 }
 
 
-static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, u64 guestdest,
+static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu,
+					 unsigned long guestdest,
 					 const void *from, unsigned long n)
 					 const void *from, unsigned long n)
 {
 {
-	u64 origin  = vcpu->kvm->arch.guest_origin;
-	u64 memsize = vcpu->kvm->arch.guest_memsize;
+	unsigned long origin  = vcpu->kvm->arch.guest_origin;
+	unsigned long memsize = vcpu->kvm->arch.guest_memsize;
 
 
 	if (guestdest + n > memsize)
 	if (guestdest + n > memsize)
 		return -EFAULT;
 		return -EFAULT;
@@ -256,10 +259,11 @@ static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, u64 guestdest,
 }
 }
 
 
 static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to,
 static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to,
-					   u64 guestsrc, unsigned long n)
+					   unsigned long guestsrc,
+					   unsigned long n)
 {
 {
-	u64 origin  = vcpu->kvm->arch.guest_origin;
-	u64 memsize = vcpu->kvm->arch.guest_memsize;
+	unsigned long origin  = vcpu->kvm->arch.guest_origin;
+	unsigned long memsize = vcpu->kvm->arch.guest_memsize;
 
 
 	if (guestsrc + n > memsize)
 	if (guestsrc + n > memsize)
 		return -EFAULT;
 		return -EFAULT;

+ 10 - 4
arch/s390/kvm/intercept.c

@@ -20,7 +20,7 @@
 #include "kvm-s390.h"
 #include "kvm-s390.h"
 #include "gaccess.h"
 #include "gaccess.h"
 
 
-static int handle_lctg(struct kvm_vcpu *vcpu)
+static int handle_lctlg(struct kvm_vcpu *vcpu)
 {
 {
 	int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
 	int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
 	int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
 	int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
@@ -30,7 +30,7 @@ static int handle_lctg(struct kvm_vcpu *vcpu)
 	u64 useraddr;
 	u64 useraddr;
 	int reg, rc;
 	int reg, rc;
 
 
-	vcpu->stat.instruction_lctg++;
+	vcpu->stat.instruction_lctlg++;
 	if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f)
 	if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f)
 		return -ENOTSUPP;
 		return -ENOTSUPP;
 
 
@@ -38,9 +38,12 @@ static int handle_lctg(struct kvm_vcpu *vcpu)
 	if (base2)
 	if (base2)
 		useraddr += vcpu->arch.guest_gprs[base2];
 		useraddr += vcpu->arch.guest_gprs[base2];
 
 
+	if (useraddr & 7)
+		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
 	reg = reg1;
 	reg = reg1;
 
 
-	VCPU_EVENT(vcpu, 5, "lctg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
+	VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
 		   disp2);
 		   disp2);
 
 
 	do {
 	do {
@@ -74,6 +77,9 @@ static int handle_lctl(struct kvm_vcpu *vcpu)
 	if (base2)
 	if (base2)
 		useraddr += vcpu->arch.guest_gprs[base2];
 		useraddr += vcpu->arch.guest_gprs[base2];
 
 
+	if (useraddr & 3)
+		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
 	VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
 	VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
 		   disp2);
 		   disp2);
 
 
@@ -99,7 +105,7 @@ static intercept_handler_t instruction_handlers[256] = {
 	[0xae] = kvm_s390_handle_sigp,
 	[0xae] = kvm_s390_handle_sigp,
 	[0xb2] = kvm_s390_handle_priv,
 	[0xb2] = kvm_s390_handle_priv,
 	[0xb7] = handle_lctl,
 	[0xb7] = handle_lctl,
-	[0xeb] = handle_lctg,
+	[0xeb] = handle_lctlg,
 };
 };
 
 
 static int handle_noop(struct kvm_vcpu *vcpu)
 static int handle_noop(struct kvm_vcpu *vcpu)

+ 7 - 14
arch/s390/kvm/interrupt.c

@@ -13,6 +13,7 @@
 #include <asm/lowcore.h>
 #include <asm/lowcore.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <linux/kvm_host.h>
 #include <linux/kvm_host.h>
+#include <linux/signal.h>
 #include "kvm-s390.h"
 #include "kvm-s390.h"
 #include "gaccess.h"
 #include "gaccess.h"
 
 
@@ -246,15 +247,10 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
 	default:
 	default:
 		BUG();
 		BUG();
 	}
 	}
-
 	if (exception) {
 	if (exception) {
-		VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering"
-			   " interrupt");
-		kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
-		if (inti->type == KVM_S390_PROGRAM_INT) {
-			printk(KERN_WARNING "kvm: recursive program check\n");
-			BUG();
-		}
+		printk("kvm: The guest lowcore is not mapped during interrupt "
+			"delivery, killing userspace\n");
+		do_exit(SIGKILL);
 	}
 	}
 }
 }
 
 
@@ -277,14 +273,11 @@ static int __try_deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
 		__LC_EXT_NEW_PSW, sizeof(psw_t));
 		__LC_EXT_NEW_PSW, sizeof(psw_t));
 	if (rc == -EFAULT)
 	if (rc == -EFAULT)
 		exception = 1;
 		exception = 1;
-
 	if (exception) {
 	if (exception) {
-		VCPU_EVENT(vcpu, 1, "%s", "program exception while delivering" \
-			   " ckc interrupt");
-		kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
-		return 0;
+		printk("kvm: The guest lowcore is not mapped during interrupt "
+			"delivery, killing userspace\n");
+		do_exit(SIGKILL);
 	}
 	}
-
 	return 1;
 	return 1;
 }
 }
 
 

+ 7 - 2
arch/s390/kvm/kvm-s390.c

@@ -39,7 +39,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
 	{ "exit_instruction", VCPU_STAT(exit_instruction) },
 	{ "exit_instruction", VCPU_STAT(exit_instruction) },
 	{ "exit_program_interruption", VCPU_STAT(exit_program_interruption) },
 	{ "exit_program_interruption", VCPU_STAT(exit_program_interruption) },
 	{ "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) },
 	{ "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) },
-	{ "instruction_lctg", VCPU_STAT(instruction_lctg) },
+	{ "instruction_lctlg", VCPU_STAT(instruction_lctlg) },
 	{ "instruction_lctl", VCPU_STAT(instruction_lctl) },
 	{ "instruction_lctl", VCPU_STAT(instruction_lctl) },
 	{ "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) },
 	{ "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) },
 	{ "deliver_service_signal", VCPU_STAT(deliver_service_signal) },
 	{ "deliver_service_signal", VCPU_STAT(deliver_service_signal) },
@@ -112,7 +112,12 @@ long kvm_arch_dev_ioctl(struct file *filp,
 
 
 int kvm_dev_ioctl_check_extension(long ext)
 int kvm_dev_ioctl_check_extension(long ext)
 {
 {
-	return 0;
+	switch (ext) {
+	case KVM_CAP_USER_MEMORY:
+		return 1;
+	default:
+		return 0;
+	}
 }
 }
 
 
 /* Section: vm related */
 /* Section: vm related */

+ 3 - 2
arch/s390/kvm/sigp.c

@@ -43,7 +43,8 @@
 #define SIGP_STAT_RECEIVER_CHECK    0x00000001UL
 #define SIGP_STAT_RECEIVER_CHECK    0x00000001UL
 
 
 
 
-static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, u64 *reg)
+static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
+			unsigned long *reg)
 {
 {
 	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
 	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
 	int rc;
 	int rc;
@@ -167,7 +168,7 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
 }
 }
 
 
 static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
 static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
-			     u64 *reg)
+			     unsigned long *reg)
 {
 {
 	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
 	struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
 	struct kvm_s390_local_interrupt *li;
 	struct kvm_s390_local_interrupt *li;

+ 7 - 0
arch/x86/kvm/mmu.c

@@ -1814,6 +1814,7 @@ int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
 	spin_unlock(&vcpu->kvm->mmu_lock);
 	spin_unlock(&vcpu->kvm->mmu_lock);
 	return r;
 	return r;
 }
 }
+EXPORT_SYMBOL_GPL(kvm_mmu_unprotect_page_virt);
 
 
 void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 {
 {
@@ -1870,6 +1871,12 @@ void kvm_enable_tdp(void)
 }
 }
 EXPORT_SYMBOL_GPL(kvm_enable_tdp);
 EXPORT_SYMBOL_GPL(kvm_enable_tdp);
 
 
+void kvm_disable_tdp(void)
+{
+	tdp_enabled = false;
+}
+EXPORT_SYMBOL_GPL(kvm_disable_tdp);
+
 static void free_mmu_pages(struct kvm_vcpu *vcpu)
 static void free_mmu_pages(struct kvm_vcpu *vcpu)
 {
 {
 	struct kvm_mmu_page *sp;
 	struct kvm_mmu_page *sp;

+ 8 - 2
arch/x86/kvm/svm.c

@@ -453,7 +453,8 @@ static __init int svm_hardware_setup(void)
 	if (npt_enabled) {
 	if (npt_enabled) {
 		printk(KERN_INFO "kvm: Nested Paging enabled\n");
 		printk(KERN_INFO "kvm: Nested Paging enabled\n");
 		kvm_enable_tdp();
 		kvm_enable_tdp();
-	}
+	} else
+		kvm_disable_tdp();
 
 
 	return 0;
 	return 0;
 
 
@@ -1007,10 +1008,13 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 	struct kvm *kvm = svm->vcpu.kvm;
 	struct kvm *kvm = svm->vcpu.kvm;
 	u64 fault_address;
 	u64 fault_address;
 	u32 error_code;
 	u32 error_code;
+	bool event_injection = false;
 
 
 	if (!irqchip_in_kernel(kvm) &&
 	if (!irqchip_in_kernel(kvm) &&
-		is_external_interrupt(exit_int_info))
+	    is_external_interrupt(exit_int_info)) {
+		event_injection = true;
 		push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
 		push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
+	}
 
 
 	fault_address  = svm->vmcb->control.exit_info_2;
 	fault_address  = svm->vmcb->control.exit_info_2;
 	error_code = svm->vmcb->control.exit_info_1;
 	error_code = svm->vmcb->control.exit_info_1;
@@ -1024,6 +1028,8 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
 			    (u32)fault_address, (u32)(fault_address >> 32),
 			    (u32)fault_address, (u32)(fault_address >> 32),
 			    handler);
 			    handler);
 
 
+	if (event_injection)
+		kvm_mmu_unprotect_page_virt(&svm->vcpu, fault_address);
 	return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
 	return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
 }
 }
 
 

+ 12 - 10
arch/x86/kvm/vmx.c

@@ -2298,6 +2298,8 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 		cr2 = vmcs_readl(EXIT_QUALIFICATION);
 		cr2 = vmcs_readl(EXIT_QUALIFICATION);
 		KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2,
 		KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2,
 			    (u32)((u64)cr2 >> 32), handler);
 			    (u32)((u64)cr2 >> 32), handler);
+		if (vect_info & VECTORING_INFO_VALID_MASK)
+			kvm_mmu_unprotect_page_virt(vcpu, cr2);
 		return kvm_mmu_page_fault(vcpu, cr2, error_code);
 		return kvm_mmu_page_fault(vcpu, cr2, error_code);
 	}
 	}
 
 
@@ -3116,15 +3118,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
 		return ERR_PTR(-ENOMEM);
 		return ERR_PTR(-ENOMEM);
 
 
 	allocate_vpid(vmx);
 	allocate_vpid(vmx);
-	if (id == 0 && vm_need_ept()) {
-		kvm_mmu_set_base_ptes(VMX_EPT_READABLE_MASK |
-			VMX_EPT_WRITABLE_MASK |
-			VMX_EPT_DEFAULT_MT << VMX_EPT_MT_EPTE_SHIFT);
-		kvm_mmu_set_mask_ptes(0ull, VMX_EPT_FAKE_ACCESSED_MASK,
-				VMX_EPT_FAKE_DIRTY_MASK, 0ull,
-				VMX_EPT_EXECUTABLE_MASK);
-		kvm_enable_tdp();
-	}
 
 
 	err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
 	err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
 	if (err)
 	if (err)
@@ -3303,8 +3296,17 @@ static int __init vmx_init(void)
 	vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_ESP);
 	vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_ESP);
 	vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_EIP);
 	vmx_disable_intercept_for_msr(vmx_msr_bitmap, MSR_IA32_SYSENTER_EIP);
 
 
-	if (cpu_has_vmx_ept())
+	if (vm_need_ept()) {
 		bypass_guest_pf = 0;
 		bypass_guest_pf = 0;
+		kvm_mmu_set_base_ptes(VMX_EPT_READABLE_MASK |
+			VMX_EPT_WRITABLE_MASK |
+			VMX_EPT_DEFAULT_MT << VMX_EPT_MT_EPTE_SHIFT);
+		kvm_mmu_set_mask_ptes(0ull, VMX_EPT_FAKE_ACCESSED_MASK,
+				VMX_EPT_FAKE_DIRTY_MASK, 0ull,
+				VMX_EPT_EXECUTABLE_MASK);
+		kvm_enable_tdp();
+	} else
+		kvm_disable_tdp();
 
 
 	if (bypass_guest_pf)
 	if (bypass_guest_pf)
 		kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull);
 		kvm_mmu_set_nonpresent_ptes(~0xffeull, 0ull);

+ 43 - 66
arch/x86/kvm/x86.c

@@ -3184,6 +3184,10 @@ static void seg_desct_to_kvm_desct(struct desc_struct *seg_desc, u16 selector,
 	kvm_desct->base |= seg_desc->base2 << 24;
 	kvm_desct->base |= seg_desc->base2 << 24;
 	kvm_desct->limit = seg_desc->limit0;
 	kvm_desct->limit = seg_desc->limit0;
 	kvm_desct->limit |= seg_desc->limit << 16;
 	kvm_desct->limit |= seg_desc->limit << 16;
+	if (seg_desc->g) {
+		kvm_desct->limit <<= 12;
+		kvm_desct->limit |= 0xfff;
+	}
 	kvm_desct->selector = selector;
 	kvm_desct->selector = selector;
 	kvm_desct->type = seg_desc->type;
 	kvm_desct->type = seg_desc->type;
 	kvm_desct->present = seg_desc->p;
 	kvm_desct->present = seg_desc->p;
@@ -3223,6 +3227,7 @@ static void get_segment_descritptor_dtable(struct kvm_vcpu *vcpu,
 static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
 static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
 					 struct desc_struct *seg_desc)
 					 struct desc_struct *seg_desc)
 {
 {
+	gpa_t gpa;
 	struct descriptor_table dtable;
 	struct descriptor_table dtable;
 	u16 index = selector >> 3;
 	u16 index = selector >> 3;
 
 
@@ -3232,13 +3237,16 @@ static int load_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
 		kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc);
 		kvm_queue_exception_e(vcpu, GP_VECTOR, selector & 0xfffc);
 		return 1;
 		return 1;
 	}
 	}
-	return kvm_read_guest(vcpu->kvm, dtable.base + index * 8, seg_desc, 8);
+	gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, dtable.base);
+	gpa += index * 8;
+	return kvm_read_guest(vcpu->kvm, gpa, seg_desc, 8);
 }
 }
 
 
 /* allowed just for 8 bytes segments */
 /* allowed just for 8 bytes segments */
 static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
 static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
 					 struct desc_struct *seg_desc)
 					 struct desc_struct *seg_desc)
 {
 {
+	gpa_t gpa;
 	struct descriptor_table dtable;
 	struct descriptor_table dtable;
 	u16 index = selector >> 3;
 	u16 index = selector >> 3;
 
 
@@ -3246,7 +3254,9 @@ static int save_guest_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector,
 
 
 	if (dtable.limit < index * 8 + 7)
 	if (dtable.limit < index * 8 + 7)
 		return 1;
 		return 1;
-	return kvm_write_guest(vcpu->kvm, dtable.base + index * 8, seg_desc, 8);
+	gpa = vcpu->arch.mmu.gva_to_gpa(vcpu, dtable.base);
+	gpa += index * 8;
+	return kvm_write_guest(vcpu->kvm, gpa, seg_desc, 8);
 }
 }
 
 
 static u32 get_tss_base_addr(struct kvm_vcpu *vcpu,
 static u32 get_tss_base_addr(struct kvm_vcpu *vcpu,
@@ -3258,55 +3268,7 @@ static u32 get_tss_base_addr(struct kvm_vcpu *vcpu,
 	base_addr |= (seg_desc->base1 << 16);
 	base_addr |= (seg_desc->base1 << 16);
 	base_addr |= (seg_desc->base2 << 24);
 	base_addr |= (seg_desc->base2 << 24);
 
 
-	return base_addr;
-}
-
-static int load_tss_segment32(struct kvm_vcpu *vcpu,
-			      struct desc_struct *seg_desc,
-			      struct tss_segment_32 *tss)
-{
-	u32 base_addr;
-
-	base_addr = get_tss_base_addr(vcpu, seg_desc);
-
-	return kvm_read_guest(vcpu->kvm, base_addr, tss,
-			      sizeof(struct tss_segment_32));
-}
-
-static int save_tss_segment32(struct kvm_vcpu *vcpu,
-			      struct desc_struct *seg_desc,
-			      struct tss_segment_32 *tss)
-{
-	u32 base_addr;
-
-	base_addr = get_tss_base_addr(vcpu, seg_desc);
-
-	return kvm_write_guest(vcpu->kvm, base_addr, tss,
-			       sizeof(struct tss_segment_32));
-}
-
-static int load_tss_segment16(struct kvm_vcpu *vcpu,
-			      struct desc_struct *seg_desc,
-			      struct tss_segment_16 *tss)
-{
-	u32 base_addr;
-
-	base_addr = get_tss_base_addr(vcpu, seg_desc);
-
-	return kvm_read_guest(vcpu->kvm, base_addr, tss,
-			      sizeof(struct tss_segment_16));
-}
-
-static int save_tss_segment16(struct kvm_vcpu *vcpu,
-			      struct desc_struct *seg_desc,
-			      struct tss_segment_16 *tss)
-{
-	u32 base_addr;
-
-	base_addr = get_tss_base_addr(vcpu, seg_desc);
-
-	return kvm_write_guest(vcpu->kvm, base_addr, tss,
-			       sizeof(struct tss_segment_16));
+	return vcpu->arch.mmu.gva_to_gpa(vcpu, base_addr);
 }
 }
 
 
 static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
 static u16 get_segment_selector(struct kvm_vcpu *vcpu, int seg)
@@ -3466,20 +3428,26 @@ static int load_state_from_tss16(struct kvm_vcpu *vcpu,
 }
 }
 
 
 static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
 static int kvm_task_switch_16(struct kvm_vcpu *vcpu, u16 tss_selector,
-		       struct desc_struct *cseg_desc,
+		       u32 old_tss_base,
 		       struct desc_struct *nseg_desc)
 		       struct desc_struct *nseg_desc)
 {
 {
 	struct tss_segment_16 tss_segment_16;
 	struct tss_segment_16 tss_segment_16;
 	int ret = 0;
 	int ret = 0;
 
 
-	if (load_tss_segment16(vcpu, cseg_desc, &tss_segment_16))
+	if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_16,
+			   sizeof tss_segment_16))
 		goto out;
 		goto out;
 
 
 	save_state_to_tss16(vcpu, &tss_segment_16);
 	save_state_to_tss16(vcpu, &tss_segment_16);
-	save_tss_segment16(vcpu, cseg_desc, &tss_segment_16);
 
 
-	if (load_tss_segment16(vcpu, nseg_desc, &tss_segment_16))
+	if (kvm_write_guest(vcpu->kvm, old_tss_base, &tss_segment_16,
+			    sizeof tss_segment_16))
 		goto out;
 		goto out;
+
+	if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc),
+			   &tss_segment_16, sizeof tss_segment_16))
+		goto out;
+
 	if (load_state_from_tss16(vcpu, &tss_segment_16))
 	if (load_state_from_tss16(vcpu, &tss_segment_16))
 		goto out;
 		goto out;
 
 
@@ -3489,20 +3457,26 @@ out:
 }
 }
 
 
 static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
 static int kvm_task_switch_32(struct kvm_vcpu *vcpu, u16 tss_selector,
-		       struct desc_struct *cseg_desc,
+		       u32 old_tss_base,
 		       struct desc_struct *nseg_desc)
 		       struct desc_struct *nseg_desc)
 {
 {
 	struct tss_segment_32 tss_segment_32;
 	struct tss_segment_32 tss_segment_32;
 	int ret = 0;
 	int ret = 0;
 
 
-	if (load_tss_segment32(vcpu, cseg_desc, &tss_segment_32))
+	if (kvm_read_guest(vcpu->kvm, old_tss_base, &tss_segment_32,
+			   sizeof tss_segment_32))
 		goto out;
 		goto out;
 
 
 	save_state_to_tss32(vcpu, &tss_segment_32);
 	save_state_to_tss32(vcpu, &tss_segment_32);
-	save_tss_segment32(vcpu, cseg_desc, &tss_segment_32);
 
 
-	if (load_tss_segment32(vcpu, nseg_desc, &tss_segment_32))
+	if (kvm_write_guest(vcpu->kvm, old_tss_base, &tss_segment_32,
+			    sizeof tss_segment_32))
+		goto out;
+
+	if (kvm_read_guest(vcpu->kvm, get_tss_base_addr(vcpu, nseg_desc),
+			   &tss_segment_32, sizeof tss_segment_32))
 		goto out;
 		goto out;
+
 	if (load_state_from_tss32(vcpu, &tss_segment_32))
 	if (load_state_from_tss32(vcpu, &tss_segment_32))
 		goto out;
 		goto out;
 
 
@@ -3517,16 +3491,20 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
 	struct desc_struct cseg_desc;
 	struct desc_struct cseg_desc;
 	struct desc_struct nseg_desc;
 	struct desc_struct nseg_desc;
 	int ret = 0;
 	int ret = 0;
+	u32 old_tss_base = get_segment_base(vcpu, VCPU_SREG_TR);
+	u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR);
 
 
-	kvm_get_segment(vcpu, &tr_seg, VCPU_SREG_TR);
+	old_tss_base = vcpu->arch.mmu.gva_to_gpa(vcpu, old_tss_base);
 
 
+	/* FIXME: Handle errors. Failure to read either TSS or their
+	 * descriptors should generate a pagefault.
+	 */
 	if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc))
 	if (load_guest_segment_descriptor(vcpu, tss_selector, &nseg_desc))
 		goto out;
 		goto out;
 
 
-	if (load_guest_segment_descriptor(vcpu, tr_seg.selector, &cseg_desc))
+	if (load_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc))
 		goto out;
 		goto out;
 
 
-
 	if (reason != TASK_SWITCH_IRET) {
 	if (reason != TASK_SWITCH_IRET) {
 		int cpl;
 		int cpl;
 
 
@@ -3544,8 +3522,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
 
 
 	if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
 	if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) {
 		cseg_desc.type &= ~(1 << 1); //clear the B flag
 		cseg_desc.type &= ~(1 << 1); //clear the B flag
-		save_guest_segment_descriptor(vcpu, tr_seg.selector,
-					      &cseg_desc);
+		save_guest_segment_descriptor(vcpu, old_tss_sel, &cseg_desc);
 	}
 	}
 
 
 	if (reason == TASK_SWITCH_IRET) {
 	if (reason == TASK_SWITCH_IRET) {
@@ -3557,10 +3534,10 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason)
 	kvm_x86_ops->cache_regs(vcpu);
 	kvm_x86_ops->cache_regs(vcpu);
 
 
 	if (nseg_desc.type & 8)
 	if (nseg_desc.type & 8)
-		ret = kvm_task_switch_32(vcpu, tss_selector, &cseg_desc,
+		ret = kvm_task_switch_32(vcpu, tss_selector, old_tss_base,
 					 &nseg_desc);
 					 &nseg_desc);
 	else
 	else
-		ret = kvm_task_switch_16(vcpu, tss_selector, &cseg_desc,
+		ret = kvm_task_switch_16(vcpu, tss_selector, old_tss_base,
 					 &nseg_desc);
 					 &nseg_desc);
 
 
 	if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {
 	if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) {

+ 34 - 15
drivers/crypto/talitos.c

@@ -99,6 +99,9 @@ struct talitos_private {
 	/* next channel to be assigned next incoming descriptor */
 	/* next channel to be assigned next incoming descriptor */
 	atomic_t last_chan;
 	atomic_t last_chan;
 
 
+	/* per-channel number of requests pending in channel h/w fifo */
+	atomic_t *submit_count;
+
 	/* per-channel request fifo */
 	/* per-channel request fifo */
 	struct talitos_request **fifo;
 	struct talitos_request **fifo;
 
 
@@ -263,15 +266,15 @@ static int talitos_submit(struct device *dev, struct talitos_desc *desc,
 
 
 	spin_lock_irqsave(&priv->head_lock[ch], flags);
 	spin_lock_irqsave(&priv->head_lock[ch], flags);
 
 
-	head = priv->head[ch];
-	request = &priv->fifo[ch][head];
-
-	if (request->desc) {
-		/* request queue is full */
+	if (!atomic_inc_not_zero(&priv->submit_count[ch])) {
+		/* h/w fifo is full */
 		spin_unlock_irqrestore(&priv->head_lock[ch], flags);
 		spin_unlock_irqrestore(&priv->head_lock[ch], flags);
 		return -EAGAIN;
 		return -EAGAIN;
 	}
 	}
 
 
+	head = priv->head[ch];
+	request = &priv->fifo[ch][head];
+
 	/* map descriptor and save caller data */
 	/* map descriptor and save caller data */
 	request->dma_desc = dma_map_single(dev, desc, sizeof(*desc),
 	request->dma_desc = dma_map_single(dev, desc, sizeof(*desc),
 					   DMA_BIDIRECTIONAL);
 					   DMA_BIDIRECTIONAL);
@@ -335,6 +338,9 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
 		priv->tail[ch] = (tail + 1) & (priv->fifo_len - 1);
 		priv->tail[ch] = (tail + 1) & (priv->fifo_len - 1);
 
 
 		spin_unlock_irqrestore(&priv->tail_lock[ch], flags);
 		spin_unlock_irqrestore(&priv->tail_lock[ch], flags);
+
+		atomic_dec(&priv->submit_count[ch]);
+
 		saved_req.callback(dev, saved_req.desc, saved_req.context,
 		saved_req.callback(dev, saved_req.desc, saved_req.context,
 				   status);
 				   status);
 		/* channel may resume processing in single desc error case */
 		/* channel may resume processing in single desc error case */
@@ -842,7 +848,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count,
 
 
 	/* adjust (decrease) last one (or two) entry's len to cryptlen */
 	/* adjust (decrease) last one (or two) entry's len to cryptlen */
 	link_tbl_ptr--;
 	link_tbl_ptr--;
-	while (link_tbl_ptr->len <= (-cryptlen)) {
+	while (be16_to_cpu(link_tbl_ptr->len) <= (-cryptlen)) {
 		/* Empty this entry, and move to previous one */
 		/* Empty this entry, and move to previous one */
 		cryptlen += be16_to_cpu(link_tbl_ptr->len);
 		cryptlen += be16_to_cpu(link_tbl_ptr->len);
 		link_tbl_ptr->len = 0;
 		link_tbl_ptr->len = 0;
@@ -874,7 +880,7 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
 	unsigned int cryptlen = areq->cryptlen;
 	unsigned int cryptlen = areq->cryptlen;
 	unsigned int authsize = ctx->authsize;
 	unsigned int authsize = ctx->authsize;
 	unsigned int ivsize;
 	unsigned int ivsize;
-	int sg_count;
+	int sg_count, ret;
 
 
 	/* hmac key */
 	/* hmac key */
 	map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key,
 	map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key,
@@ -978,7 +984,12 @@ static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
 	map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, 0,
 	map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, 0,
 			       DMA_FROM_DEVICE);
 			       DMA_FROM_DEVICE);
 
 
-	return talitos_submit(dev, desc, callback, areq);
+	ret = talitos_submit(dev, desc, callback, areq);
+	if (ret != -EINPROGRESS) {
+		ipsec_esp_unmap(dev, edesc, areq);
+		kfree(edesc);
+	}
+	return ret;
 }
 }
 
 
 
 
@@ -1009,6 +1020,8 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
 	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
 	struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
 	struct ipsec_esp_edesc *edesc;
 	struct ipsec_esp_edesc *edesc;
 	int src_nents, dst_nents, alloc_len, dma_len;
 	int src_nents, dst_nents, alloc_len, dma_len;
+	gfp_t flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
+		      GFP_ATOMIC;
 
 
 	if (areq->cryptlen + ctx->authsize > TALITOS_MAX_DATA_LEN) {
 	if (areq->cryptlen + ctx->authsize > TALITOS_MAX_DATA_LEN) {
 		dev_err(ctx->dev, "cryptlen exceeds h/w max limit\n");
 		dev_err(ctx->dev, "cryptlen exceeds h/w max limit\n");
@@ -1022,7 +1035,7 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
 		dst_nents = src_nents;
 		dst_nents = src_nents;
 	} else {
 	} else {
 		dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize);
 		dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize);
-		dst_nents = (dst_nents == 1) ? 0 : src_nents;
+		dst_nents = (dst_nents == 1) ? 0 : dst_nents;
 	}
 	}
 
 
 	/*
 	/*
@@ -1040,7 +1053,7 @@ static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
 		alloc_len += icv_stashing ? ctx->authsize : 0;
 		alloc_len += icv_stashing ? ctx->authsize : 0;
 	}
 	}
 
 
-	edesc = kmalloc(alloc_len, GFP_DMA);
+	edesc = kmalloc(alloc_len, GFP_DMA | flags);
 	if (!edesc) {
 	if (!edesc) {
 		dev_err(ctx->dev, "could not allocate edescriptor\n");
 		dev_err(ctx->dev, "could not allocate edescriptor\n");
 		return ERR_PTR(-ENOMEM);
 		return ERR_PTR(-ENOMEM);
@@ -1337,6 +1350,7 @@ static int __devexit talitos_remove(struct of_device *ofdev)
 	if (hw_supports(dev, DESC_HDR_SEL0_RNG))
 	if (hw_supports(dev, DESC_HDR_SEL0_RNG))
 		talitos_unregister_rng(dev);
 		talitos_unregister_rng(dev);
 
 
+	kfree(priv->submit_count);
 	kfree(priv->tail);
 	kfree(priv->tail);
 	kfree(priv->head);
 	kfree(priv->head);
 
 
@@ -1466,9 +1480,6 @@ static int talitos_probe(struct of_device *ofdev,
 		goto err_out;
 		goto err_out;
 	}
 	}
 
 
-	of_node_put(np);
-	np = NULL;
-
 	priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
 	priv->head_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
 				  GFP_KERNEL);
 				  GFP_KERNEL);
 	priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
 	priv->tail_lock = kmalloc(sizeof(spinlock_t) * priv->num_channels,
@@ -1504,6 +1515,16 @@ static int talitos_probe(struct of_device *ofdev,
 		}
 		}
 	}
 	}
 
 
+	priv->submit_count = kmalloc(sizeof(atomic_t) * priv->num_channels,
+				     GFP_KERNEL);
+	if (!priv->submit_count) {
+		dev_err(dev, "failed to allocate fifo submit count space\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+	for (i = 0; i < priv->num_channels; i++)
+		atomic_set(&priv->submit_count[i], -priv->chfifo_len);
+
 	priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
 	priv->head = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
 	priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
 	priv->tail = kzalloc(sizeof(int) * priv->num_channels, GFP_KERNEL);
 	if (!priv->head || !priv->tail) {
 	if (!priv->head || !priv->tail) {
@@ -1559,8 +1580,6 @@ static int talitos_probe(struct of_device *ofdev,
 
 
 err_out:
 err_out:
 	talitos_remove(ofdev);
 	talitos_remove(ofdev);
-	if (np)
-		of_node_put(np);
 
 
 	return err;
 	return err;
 }
 }

+ 7 - 2
drivers/firewire/Kconfig

@@ -16,8 +16,13 @@ config FIREWIRE
 	  enable the new stack.
 	  enable the new stack.
 
 
 	  To compile this driver as a module, say M here: the module will be
 	  To compile this driver as a module, say M here: the module will be
-	  called firewire-core.  It functionally replaces ieee1394, raw1394,
-	  and video1394.
+	  called firewire-core.
+
+	  This module functionally replaces ieee1394, raw1394, and video1394.
+	  To access it from application programs, you generally need at least
+	  libraw1394 version 2.  IIDC/DCAM applications also need libdc1394
+	  version 2.  No libraries are required to access storage devices
+	  through the firewire-sbp2 driver.
 
 
 config FIREWIRE_OHCI
 config FIREWIRE_OHCI
 	tristate "OHCI-1394 controllers"
 	tristate "OHCI-1394 controllers"

+ 1 - 1
drivers/firewire/fw-card.c

@@ -539,7 +539,7 @@ fw_core_remove_card(struct fw_card *card)
 	wait_for_completion(&card->done);
 	wait_for_completion(&card->done);
 
 
 	cancel_delayed_work_sync(&card->work);
 	cancel_delayed_work_sync(&card->work);
-	fw_flush_transactions(card);
+	WARN_ON(!list_empty(&card->transaction_list));
 	del_timer_sync(&card->flush_timer);
 	del_timer_sync(&card->flush_timer);
 }
 }
 EXPORT_SYMBOL(fw_core_remove_card);
 EXPORT_SYMBOL(fw_core_remove_card);

+ 3 - 3
drivers/firewire/fw-cdev.c

@@ -382,9 +382,9 @@ complete_transaction(struct fw_card *card, int rcode,
 
 
 	response->response.type   = FW_CDEV_EVENT_RESPONSE;
 	response->response.type   = FW_CDEV_EVENT_RESPONSE;
 	response->response.rcode  = rcode;
 	response->response.rcode  = rcode;
-	queue_event(client, &response->event,
-		    &response->response, sizeof(response->response),
-		    response->response.data, response->response.length);
+	queue_event(client, &response->event, &response->response,
+		    sizeof(response->response) + response->response.length,
+		    NULL, 0);
 }
 }
 
 
 static int ioctl_send_request(struct client *client, void *buffer)
 static int ioctl_send_request(struct client *client, void *buffer)

+ 24 - 13
drivers/firewire/fw-ohci.c

@@ -171,7 +171,6 @@ struct iso_context {
 struct fw_ohci {
 struct fw_ohci {
 	struct fw_card card;
 	struct fw_card card;
 
 
-	u32 version;
 	__iomem char *registers;
 	__iomem char *registers;
 	dma_addr_t self_id_bus;
 	dma_addr_t self_id_bus;
 	__le32 *self_id_cpu;
 	__le32 *self_id_cpu;
@@ -180,6 +179,8 @@ struct fw_ohci {
 	int generation;
 	int generation;
 	int request_generation;	/* for timestamping incoming requests */
 	int request_generation;	/* for timestamping incoming requests */
 	u32 bus_seconds;
 	u32 bus_seconds;
+
+	bool use_dualbuffer;
 	bool old_uninorth;
 	bool old_uninorth;
 	bool bus_reset_packet_quirk;
 	bool bus_reset_packet_quirk;
 
 
@@ -1885,7 +1886,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
 	} else {
 	} else {
 		mask = &ohci->ir_context_mask;
 		mask = &ohci->ir_context_mask;
 		list = ohci->ir_context_list;
 		list = ohci->ir_context_list;
-		if (ohci->version >= OHCI_VERSION_1_1)
+		if (ohci->use_dualbuffer)
 			callback = handle_ir_dualbuffer_packet;
 			callback = handle_ir_dualbuffer_packet;
 		else
 		else
 			callback = handle_ir_packet_per_buffer;
 			callback = handle_ir_packet_per_buffer;
@@ -1949,7 +1950,7 @@ static int ohci_start_iso(struct fw_iso_context *base,
 	} else {
 	} else {
 		index = ctx - ohci->ir_context_list;
 		index = ctx - ohci->ir_context_list;
 		control = IR_CONTEXT_ISOCH_HEADER;
 		control = IR_CONTEXT_ISOCH_HEADER;
-		if (ohci->version >= OHCI_VERSION_1_1)
+		if (ohci->use_dualbuffer)
 			control |= IR_CONTEXT_DUAL_BUFFER_MODE;
 			control |= IR_CONTEXT_DUAL_BUFFER_MODE;
 		match = (tags << 28) | (sync << 8) | ctx->base.channel;
 		match = (tags << 28) | (sync << 8) | ctx->base.channel;
 		if (cycle >= 0) {
 		if (cycle >= 0) {
@@ -2279,7 +2280,7 @@ ohci_queue_iso(struct fw_iso_context *base,
 	spin_lock_irqsave(&ctx->context.ohci->lock, flags);
 	spin_lock_irqsave(&ctx->context.ohci->lock, flags);
 	if (base->type == FW_ISO_CONTEXT_TRANSMIT)
 	if (base->type == FW_ISO_CONTEXT_TRANSMIT)
 		retval = ohci_queue_iso_transmit(base, packet, buffer, payload);
 		retval = ohci_queue_iso_transmit(base, packet, buffer, payload);
-	else if (ctx->context.ohci->version >= OHCI_VERSION_1_1)
+	else if (ctx->context.ohci->use_dualbuffer)
 		retval = ohci_queue_iso_receive_dualbuffer(base, packet,
 		retval = ohci_queue_iso_receive_dualbuffer(base, packet,
 							 buffer, payload);
 							 buffer, payload);
 	else
 	else
@@ -2341,7 +2342,7 @@ static int __devinit
 pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 {
 {
 	struct fw_ohci *ohci;
 	struct fw_ohci *ohci;
-	u32 bus_options, max_receive, link_speed;
+	u32 bus_options, max_receive, link_speed, version;
 	u64 guid;
 	u64 guid;
 	int err;
 	int err;
 	size_t size;
 	size_t size;
@@ -2366,12 +2367,6 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 	pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
 	pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
 	pci_set_drvdata(dev, ohci);
 	pci_set_drvdata(dev, ohci);
 
 
-#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
-	ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
-			     dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
-#endif
-	ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
-
 	spin_lock_init(&ohci->lock);
 	spin_lock_init(&ohci->lock);
 
 
 	tasklet_init(&ohci->bus_reset_tasklet,
 	tasklet_init(&ohci->bus_reset_tasklet,
@@ -2390,6 +2385,23 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 		goto fail_iomem;
 		goto fail_iomem;
 	}
 	}
 
 
+	version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
+	ohci->use_dualbuffer = version >= OHCI_VERSION_1_1;
+
+/* x86-32 currently doesn't use highmem for dma_alloc_coherent */
+#if !defined(CONFIG_X86_32)
+	/* dual-buffer mode is broken with descriptor addresses above 2G */
+	if (dev->vendor == PCI_VENDOR_ID_TI &&
+	    dev->device == PCI_DEVICE_ID_TI_TSB43AB22)
+		ohci->use_dualbuffer = false;
+#endif
+
+#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32)
+	ohci->old_uninorth = dev->vendor == PCI_VENDOR_ID_APPLE &&
+			     dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW;
+#endif
+	ohci->bus_reset_packet_quirk = dev->vendor == PCI_VENDOR_ID_TI;
+
 	ar_context_init(&ohci->ar_request_ctx, ohci,
 	ar_context_init(&ohci->ar_request_ctx, ohci,
 			OHCI1394_AsReqRcvContextControlSet);
 			OHCI1394_AsReqRcvContextControlSet);
 
 
@@ -2441,9 +2453,8 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 	if (err < 0)
 	if (err < 0)
 		goto fail_self_id;
 		goto fail_self_id;
 
 
-	ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
 	fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
 	fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
-		  dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff);
+		  dev->dev.bus_id, version >> 16, version & 0xff);
 	return 0;
 	return 0;
 
 
  fail_self_id:
  fail_self_id:

+ 0 - 2
drivers/firewire/fw-topology.c

@@ -510,8 +510,6 @@ fw_core_handle_bus_reset(struct fw_card *card,
 	struct fw_node *local_node;
 	struct fw_node *local_node;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	fw_flush_transactions(card);
-
 	spin_lock_irqsave(&card->lock, flags);
 	spin_lock_irqsave(&card->lock, flags);
 
 
 	/*
 	/*

+ 30 - 49
drivers/firewire/fw-transaction.c

@@ -22,6 +22,7 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/kref.h>
 #include <linux/kref.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/pci.h>
@@ -151,7 +152,7 @@ transmit_complete_callback(struct fw_packet *packet,
 
 
 static void
 static void
 fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
 fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
-		int node_id, int source_id, int generation, int speed,
+		int destination_id, int source_id, int generation, int speed,
 		unsigned long long offset, void *payload, size_t length)
 		unsigned long long offset, void *payload, size_t length)
 {
 {
 	int ext_tcode;
 	int ext_tcode;
@@ -166,7 +167,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
 		HEADER_RETRY(RETRY_X) |
 		HEADER_RETRY(RETRY_X) |
 		HEADER_TLABEL(tlabel) |
 		HEADER_TLABEL(tlabel) |
 		HEADER_TCODE(tcode) |
 		HEADER_TCODE(tcode) |
-		HEADER_DESTINATION(node_id);
+		HEADER_DESTINATION(destination_id);
 	packet->header[1] =
 	packet->header[1] =
 		HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
 		HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
 	packet->header[2] =
 	packet->header[2] =
@@ -252,7 +253,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
 		fw_transaction_callback_t callback, void *callback_data)
 		fw_transaction_callback_t callback, void *callback_data)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
-	int tlabel, source;
+	int tlabel;
 
 
 	/*
 	/*
 	 * Bump the flush timer up 100ms first of all so we
 	 * Bump the flush timer up 100ms first of all so we
@@ -268,7 +269,6 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
 
 
 	spin_lock_irqsave(&card->lock, flags);
 	spin_lock_irqsave(&card->lock, flags);
 
 
-	source = card->node_id;
 	tlabel = card->current_tlabel;
 	tlabel = card->current_tlabel;
 	if (card->tlabel_mask & (1 << tlabel)) {
 	if (card->tlabel_mask & (1 << tlabel)) {
 		spin_unlock_irqrestore(&card->lock, flags);
 		spin_unlock_irqrestore(&card->lock, flags);
@@ -279,77 +279,58 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
 	card->current_tlabel = (card->current_tlabel + 1) & 0x1f;
 	card->current_tlabel = (card->current_tlabel + 1) & 0x1f;
 	card->tlabel_mask |= (1 << tlabel);
 	card->tlabel_mask |= (1 << tlabel);
 
 
-	list_add_tail(&t->link, &card->transaction_list);
-
-	spin_unlock_irqrestore(&card->lock, flags);
-
-	/* Initialize rest of transaction, fill out packet and send it. */
 	t->node_id = node_id;
 	t->node_id = node_id;
 	t->tlabel = tlabel;
 	t->tlabel = tlabel;
 	t->callback = callback;
 	t->callback = callback;
 	t->callback_data = callback_data;
 	t->callback_data = callback_data;
 
 
-	fw_fill_request(&t->packet, tcode, t->tlabel,
-			node_id, source, generation,
-			speed, offset, payload, length);
+	fw_fill_request(&t->packet, tcode, t->tlabel, node_id, card->node_id,
+			generation, speed, offset, payload, length);
 	t->packet.callback = transmit_complete_callback;
 	t->packet.callback = transmit_complete_callback;
 
 
+	list_add_tail(&t->link, &card->transaction_list);
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
 	card->driver->send_request(card, &t->packet);
 	card->driver->send_request(card, &t->packet);
 }
 }
 EXPORT_SYMBOL(fw_send_request);
 EXPORT_SYMBOL(fw_send_request);
 
 
-struct fw_phy_packet {
-	struct fw_packet packet;
-	struct completion done;
-	struct kref kref;
-};
-
-static void phy_packet_release(struct kref *kref)
-{
-	struct fw_phy_packet *p =
-			container_of(kref, struct fw_phy_packet, kref);
-	kfree(p);
-}
+static DEFINE_MUTEX(phy_config_mutex);
+static DECLARE_COMPLETION(phy_config_done);
 
 
 static void transmit_phy_packet_callback(struct fw_packet *packet,
 static void transmit_phy_packet_callback(struct fw_packet *packet,
 					 struct fw_card *card, int status)
 					 struct fw_card *card, int status)
 {
 {
-	struct fw_phy_packet *p =
-			container_of(packet, struct fw_phy_packet, packet);
-
-	complete(&p->done);
-	kref_put(&p->kref, phy_packet_release);
+	complete(&phy_config_done);
 }
 }
 
 
+static struct fw_packet phy_config_packet = {
+	.header_length	= 8,
+	.payload_length	= 0,
+	.speed		= SCODE_100,
+	.callback	= transmit_phy_packet_callback,
+};
+
 void fw_send_phy_config(struct fw_card *card,
 void fw_send_phy_config(struct fw_card *card,
 			int node_id, int generation, int gap_count)
 			int node_id, int generation, int gap_count)
 {
 {
-	struct fw_phy_packet *p;
 	long timeout = DIV_ROUND_UP(HZ, 10);
 	long timeout = DIV_ROUND_UP(HZ, 10);
 	u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
 	u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
 		   PHY_CONFIG_ROOT_ID(node_id) |
 		   PHY_CONFIG_ROOT_ID(node_id) |
 		   PHY_CONFIG_GAP_COUNT(gap_count);
 		   PHY_CONFIG_GAP_COUNT(gap_count);
 
 
-	p = kmalloc(sizeof(*p), GFP_KERNEL);
-	if (p == NULL)
-		return;
+	mutex_lock(&phy_config_mutex);
+
+	phy_config_packet.header[0] = data;
+	phy_config_packet.header[1] = ~data;
+	phy_config_packet.generation = generation;
+	INIT_COMPLETION(phy_config_done);
+
+	card->driver->send_request(card, &phy_config_packet);
+	wait_for_completion_timeout(&phy_config_done, timeout);
 
 
-	p->packet.header[0] = data;
-	p->packet.header[1] = ~data;
-	p->packet.header_length = 8;
-	p->packet.payload_length = 0;
-	p->packet.speed = SCODE_100;
-	p->packet.generation = generation;
-	p->packet.callback = transmit_phy_packet_callback;
-	init_completion(&p->done);
-	kref_set(&p->kref, 2);
-
-	card->driver->send_request(card, &p->packet);
-	timeout = wait_for_completion_timeout(&p->done, timeout);
-	kref_put(&p->kref, phy_packet_release);
-
-	/* will leak p if the callback is never executed */
-	WARN_ON(timeout == 0);
+	mutex_unlock(&phy_config_mutex);
 }
 }
 
 
 void fw_flush_transactions(struct fw_card *card)
 void fw_flush_transactions(struct fw_card *card)

+ 1 - 0
drivers/isdn/hardware/mISDN/Kconfig

@@ -7,6 +7,7 @@ config MISDN_HFCPCI
 	tristate "Support for HFC PCI cards"
 	tristate "Support for HFC PCI cards"
 	depends on MISDN
 	depends on MISDN
 	depends on PCI
 	depends on PCI
+	depends on VIRT_TO_BUS
 	help
 	help
 	  Enable support for cards with Cologne Chip AG's
 	  Enable support for cards with Cologne Chip AG's
           HFC PCI chip.
           HFC PCI chip.

+ 1 - 1
drivers/isdn/mISDN/layer2.c

@@ -2030,7 +2030,7 @@ release_l2(struct layer2 *l2)
 	skb_queue_purge(&l2->down_queue);
 	skb_queue_purge(&l2->down_queue);
 	ReleaseWin(l2);
 	ReleaseWin(l2);
 	if (test_bit(FLG_LAPD, &l2->flag)) {
 	if (test_bit(FLG_LAPD, &l2->flag)) {
-		release_tei(l2);
+		TEIrelease(l2);
 		if (l2->ch.st)
 		if (l2->ch.st)
 			l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D,
 			l2->ch.st->dev->D.ctrl(&l2->ch.st->dev->D,
 			    CLOSE_CHANNEL, NULL);
 			    CLOSE_CHANNEL, NULL);

+ 1 - 1
drivers/isdn/mISDN/layer2.h

@@ -96,7 +96,7 @@ extern int		tei_l2(struct layer2 *, u_int, u_long arg);
 
 
 /* from tei.c */
 /* from tei.c */
 extern int 		l2_tei(struct layer2 *, u_int, u_long arg);
 extern int 		l2_tei(struct layer2 *, u_int, u_long arg);
-extern void 		release_tei(struct layer2 *);
+extern void 		TEIrelease(struct layer2 *);
 extern int 		TEIInit(u_int *);
 extern int 		TEIInit(u_int *);
 extern void 		TEIFree(void);
 extern void 		TEIFree(void);
 
 

+ 1 - 1
drivers/isdn/mISDN/tei.c

@@ -945,7 +945,7 @@ l2_tei(struct layer2 *l2, u_int cmd, u_long arg)
 }
 }
 
 
 void
 void
-release_tei(struct layer2 *l2)
+TEIrelease(struct layer2 *l2)
 {
 {
 	struct teimgr	*tm = l2->tm;
 	struct teimgr	*tm = l2->tm;
 	u_long		flags;
 	u_long		flags;

+ 13 - 0
drivers/md/dm-mpath.c

@@ -147,9 +147,12 @@ static struct priority_group *alloc_priority_group(void)
 static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
 static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
 {
 {
 	struct pgpath *pgpath, *tmp;
 	struct pgpath *pgpath, *tmp;
+	struct multipath *m = ti->private;
 
 
 	list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
 	list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
 		list_del(&pgpath->list);
 		list_del(&pgpath->list);
+		if (m->hw_handler_name)
+			scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
 		dm_put_device(ti, pgpath->path.dev);
 		dm_put_device(ti, pgpath->path.dev);
 		free_pgpath(pgpath);
 		free_pgpath(pgpath);
 	}
 	}
@@ -548,6 +551,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
 {
 {
 	int r;
 	int r;
 	struct pgpath *p;
 	struct pgpath *p;
+	struct multipath *m = ti->private;
 
 
 	/* we need at least a path arg */
 	/* we need at least a path arg */
 	if (as->argc < 1) {
 	if (as->argc < 1) {
@@ -566,6 +570,15 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
 		goto bad;
 		goto bad;
 	}
 	}
 
 
+	if (m->hw_handler_name) {
+		r = scsi_dh_attach(bdev_get_queue(p->path.dev->bdev),
+				   m->hw_handler_name);
+		if (r < 0) {
+			dm_put_device(ti, p->path.dev);
+			goto bad;
+		}
+	}
+
 	r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error);
 	r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error);
 	if (r) {
 	if (r) {
 		dm_put_device(ti, p->path.dev);
 		dm_put_device(ti, p->path.dev);

+ 12 - 12
drivers/message/fusion/mptbase.c

@@ -273,12 +273,12 @@ mpt_fault_reset_work(struct work_struct *work)
 	ioc_raw_state = mpt_GetIocState(ioc, 0);
 	ioc_raw_state = mpt_GetIocState(ioc, 0);
 	if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
 	if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
 		printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
 		printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n",
-		    ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+		       ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
 		printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
 		printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n",
-		    ioc->name, __FUNCTION__);
+		       ioc->name, __func__);
 		rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
 		rc = mpt_HardResetHandler(ioc, CAN_SLEEP);
 		printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
 		printk(MYIOC_s_WARN_FMT "%s: HardReset: %s\n", ioc->name,
-		    __FUNCTION__, (rc == 0) ? "success" : "failed");
+		       __func__, (rc == 0) ? "success" : "failed");
 		ioc_raw_state = mpt_GetIocState(ioc, 0);
 		ioc_raw_state = mpt_GetIocState(ioc, 0);
 		if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
 		if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT)
 			printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
 			printk(MYIOC_s_WARN_FMT "IOC is in FAULT state after "
@@ -356,7 +356,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
 	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
 	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
 		MptCallbacks[cb_idx] == NULL) {
 		MptCallbacks[cb_idx] == NULL) {
 		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
 		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
-				__FUNCTION__, ioc->name, cb_idx);
+				__func__, ioc->name, cb_idx);
 		goto out;
 		goto out;
 	}
 	}
 
 
@@ -420,7 +420,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
 	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
 	if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
 		MptCallbacks[cb_idx] == NULL) {
 		MptCallbacks[cb_idx] == NULL) {
 		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
 		printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
-				__FUNCTION__, ioc->name, cb_idx);
+				__func__, ioc->name, cb_idx);
 		freeme = 0;
 		freeme = 0;
 		goto out;
 		goto out;
 	}
 	}
@@ -2434,7 +2434,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
 
 
 	if (ioc->cached_fw != NULL) {
 	if (ioc->cached_fw != NULL) {
 		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
 		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
-		    "adapter\n", __FUNCTION__, ioc->name));
+		    "adapter\n", __func__, ioc->name));
 		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
 		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
 		    ioc->cached_fw, CAN_SLEEP)) < 0) {
 		    ioc->cached_fw, CAN_SLEEP)) < 0) {
 			printk(MYIOC_s_WARN_FMT
 			printk(MYIOC_s_WARN_FMT
@@ -3693,7 +3693,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
 
 
 	if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
 	if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
 		drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
 		drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
-			"address=%p\n",  ioc->name, __FUNCTION__,
+			"address=%p\n",  ioc->name, __func__,
 			&ioc->chip->Doorbell, &ioc->chip->Reset_1078));
 			&ioc->chip->Doorbell, &ioc->chip->Reset_1078));
 		CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
 		CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
 		if (sleepFlag == CAN_SLEEP)
 		if (sleepFlag == CAN_SLEEP)
@@ -4742,12 +4742,12 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
 		break;
 		break;
 	}
 	}
 
 
-	printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode);
+	printk("%s: persist_opcode=%x\n",__func__, persist_opcode);
 
 
 	/* Get a MF for this command.
 	/* Get a MF for this command.
 	 */
 	 */
 	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
 	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
-		printk("%s: no msg frames!\n",__FUNCTION__);
+		printk("%s: no msg frames!\n",__func__);
 		return -1;
 		return -1;
         }
         }
 
 
@@ -4771,13 +4771,13 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
 	    (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
 	    (SasIoUnitControlReply_t *)ioc->persist_reply_frame;
 	if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
 	if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) {
 		printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
 		printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
-		    __FUNCTION__,
+		    __func__,
 		    sasIoUnitCntrReply->IOCStatus,
 		    sasIoUnitCntrReply->IOCStatus,
 		    sasIoUnitCntrReply->IOCLogInfo);
 		    sasIoUnitCntrReply->IOCLogInfo);
 		return -1;
 		return -1;
 	}
 	}
 
 
-	printk("%s: success\n",__FUNCTION__);
+	printk("%s: success\n",__func__);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -5784,7 +5784,7 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
 
 
 	if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
 	if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
-		    ioc->name,__FUNCTION__));
+		    ioc->name,__func__));
 		return -1;
 		return -1;
 	}
 	}
 
 

+ 2 - 2
drivers/message/fusion/mptctl.c

@@ -505,7 +505,7 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 	event = le32_to_cpu(pEvReply->Event) & 0xFF;
 	event = le32_to_cpu(pEvReply->Event) & 0xFF;
 
 
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n",
 	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n",
-	    ioc->name, __FUNCTION__));
+	    ioc->name, __func__));
 	if(async_queue == NULL)
 	if(async_queue == NULL)
 		return 1;
 		return 1;
 
 
@@ -2482,7 +2482,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
 	 */
 	 */
 	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
 	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
-		    ioc->name,__FUNCTION__));
+		    ioc->name,__func__));
 		goto out;
 		goto out;
 	}
 	}
 
 

+ 4 - 4
drivers/message/fusion/mptfc.c

@@ -231,28 +231,28 @@ static int
 mptfc_abort(struct scsi_cmnd *SCpnt)
 mptfc_abort(struct scsi_cmnd *SCpnt)
 {
 {
 	return
 	return
-	    mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
+	    mptfc_block_error_handler(SCpnt, mptscsih_abort, __func__);
 }
 }
 
 
 static int
 static int
 mptfc_dev_reset(struct scsi_cmnd *SCpnt)
 mptfc_dev_reset(struct scsi_cmnd *SCpnt)
 {
 {
 	return
 	return
-	    mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
+	    mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __func__);
 }
 }
 
 
 static int
 static int
 mptfc_bus_reset(struct scsi_cmnd *SCpnt)
 mptfc_bus_reset(struct scsi_cmnd *SCpnt)
 {
 {
 	return
 	return
-	    mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
+	    mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __func__);
 }
 }
 
 
 static int
 static int
 mptfc_host_reset(struct scsi_cmnd *SCpnt)
 mptfc_host_reset(struct scsi_cmnd *SCpnt)
 {
 {
 	return
 	return
-	    mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
+	    mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __func__);
 }
 }
 
 
 static void
 static void

+ 13 - 13
drivers/message/fusion/mptlan.c

@@ -610,7 +610,7 @@ mpt_lan_send_turbo(struct net_device *dev, u32 tmsg)
 
 
 	dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
 	dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
 			IOC_AND_NETDEV_NAMES_s_s(dev),
 			IOC_AND_NETDEV_NAMES_s_s(dev),
-			__FUNCTION__, sent));
+			__func__, sent));
 
 
 	priv->SendCtl[ctx].skb = NULL;
 	priv->SendCtl[ctx].skb = NULL;
 	pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
 	pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
@@ -676,7 +676,7 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
 
 
 		dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
 		dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
 				IOC_AND_NETDEV_NAMES_s_s(dev),
 				IOC_AND_NETDEV_NAMES_s_s(dev),
-				__FUNCTION__, sent));
+				__func__, sent));
 
 
 		priv->SendCtl[ctx].skb = NULL;
 		priv->SendCtl[ctx].skb = NULL;
 		pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
 		pci_unmap_single(mpt_dev->pcidev, priv->SendCtl[ctx].dma,
@@ -715,7 +715,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 	u16 cur_naa = 0x1000;
 	u16 cur_naa = 0x1000;
 
 
 	dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
 	dioprintk((KERN_INFO MYNAM ": %s called, skb_addr = %p\n",
-			__FUNCTION__, skb));
+			__func__, skb));
 
 
 	spin_lock_irqsave(&priv->txfidx_lock, flags);
 	spin_lock_irqsave(&priv->txfidx_lock, flags);
 	if (priv->mpt_txfidx_tail < 0) {
 	if (priv->mpt_txfidx_tail < 0) {
@@ -723,7 +723,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
 		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
 
 
 		printk (KERN_ERR "%s: no tx context available: %u\n",
 		printk (KERN_ERR "%s: no tx context available: %u\n",
-			__FUNCTION__, priv->mpt_txfidx_tail);
+			__func__, priv->mpt_txfidx_tail);
 		return 1;
 		return 1;
 	}
 	}
 
 
@@ -733,7 +733,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
 		spin_unlock_irqrestore(&priv->txfidx_lock, flags);
 
 
 		printk (KERN_ERR "%s: Unable to alloc request frame\n",
 		printk (KERN_ERR "%s: Unable to alloc request frame\n",
-			__FUNCTION__);
+			__func__);
 		return 1;
 		return 1;
 	}
 	}
 
 
@@ -1208,7 +1208,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 
 
 	dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
 	dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, Start_buckets = %u, buckets_out = %u\n",
 			IOC_AND_NETDEV_NAMES_s_s(dev),
 			IOC_AND_NETDEV_NAMES_s_s(dev),
-			__FUNCTION__, buckets, curr));
+			__func__, buckets, curr));
 
 
 	max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
 	max = (mpt_dev->req_sz - MPT_LAN_RECEIVE_POST_REQUEST_SIZE) /
 			(MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
 			(MPT_LAN_TRANSACTION32_SIZE + sizeof(SGESimple64_t));
@@ -1217,9 +1217,9 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 		mf = mpt_get_msg_frame(LanCtx, mpt_dev);
 		mf = mpt_get_msg_frame(LanCtx, mpt_dev);
 		if (mf == NULL) {
 		if (mf == NULL) {
 			printk (KERN_ERR "%s: Unable to alloc request frame\n",
 			printk (KERN_ERR "%s: Unable to alloc request frame\n",
-				__FUNCTION__);
+				__func__);
 			dioprintk((KERN_ERR "%s: %u buckets remaining\n",
 			dioprintk((KERN_ERR "%s: %u buckets remaining\n",
-				 __FUNCTION__, buckets));
+				 __func__, buckets));
 			goto out;
 			goto out;
 		}
 		}
 		pRecvReq = (LANReceivePostRequest_t *) mf;
 		pRecvReq = (LANReceivePostRequest_t *) mf;
@@ -1244,7 +1244,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 			spin_lock_irqsave(&priv->rxfidx_lock, flags);
 			spin_lock_irqsave(&priv->rxfidx_lock, flags);
 			if (priv->mpt_rxfidx_tail < 0) {
 			if (priv->mpt_rxfidx_tail < 0) {
 				printk (KERN_ERR "%s: Can't alloc context\n",
 				printk (KERN_ERR "%s: Can't alloc context\n",
-					__FUNCTION__);
+					__func__);
 				spin_unlock_irqrestore(&priv->rxfidx_lock,
 				spin_unlock_irqrestore(&priv->rxfidx_lock,
 						       flags);
 						       flags);
 				break;
 				break;
@@ -1267,7 +1267,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 				if (skb == NULL) {
 				if (skb == NULL) {
 					printk (KERN_WARNING
 					printk (KERN_WARNING
 						MYNAM "/%s: Can't alloc skb\n",
 						MYNAM "/%s: Can't alloc skb\n",
-						__FUNCTION__);
+						__func__);
 					priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
 					priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx;
 					spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
 					spin_unlock_irqrestore(&priv->rxfidx_lock, flags);
 					break;
 					break;
@@ -1305,7 +1305,7 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 
 
 		if (pSimple == NULL) {
 		if (pSimple == NULL) {
 /**/			printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
 /**/			printk (KERN_WARNING MYNAM "/%s: No buckets posted\n",
-/**/				__FUNCTION__);
+/**/				__func__);
 			mpt_free_msg_frame(mpt_dev, mf);
 			mpt_free_msg_frame(mpt_dev, mf);
 			goto out;
 			goto out;
 		}
 		}
@@ -1329,9 +1329,9 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
 
 
 out:
 out:
 	dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
 	dioprintk((KERN_INFO MYNAM "/%s: End_buckets = %u, priv->buckets_out = %u\n",
-		  __FUNCTION__, buckets, atomic_read(&priv->buckets_out)));
+		  __func__, buckets, atomic_read(&priv->buckets_out)));
 	dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
 	dioprintk((KERN_INFO MYNAM "/%s: Posted %u buckets and received %u back\n",
-	__FUNCTION__, priv->total_posted, priv->total_received));
+	__func__, priv->total_posted, priv->total_received));
 
 
 	clear_bit(0, &priv->post_buckets_active);
 	clear_bit(0, &priv->post_buckets_active);
 }
 }

+ 27 - 27
drivers/message/fusion/mptsas.c

@@ -300,7 +300,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai
 	phy_info = port_info->phy_info;
 	phy_info = port_info->phy_info;
 
 
 	dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
 	dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
-	    "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
+	    "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
 	    port_details->num_phys, (unsigned long long)
 	    port_details->num_phys, (unsigned long long)
 	    port_details->phy_bitmask));
 	    port_details->phy_bitmask));
 
 
@@ -411,7 +411,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
 		 */
 		 */
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		    "%s: [%p]: deleting phy = %d\n",
 		    "%s: [%p]: deleting phy = %d\n",
-		    ioc->name, __FUNCTION__, port_details, i));
+		    ioc->name, __func__, port_details, i));
 		port_details->num_phys--;
 		port_details->num_phys--;
 		port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
 		port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
 		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
 		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
@@ -497,7 +497,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
 			continue;
 			continue;
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		    "%s: [%p]: phy_id=%02d num_phys=%02d "
 		    "%s: [%p]: phy_id=%02d num_phys=%02d "
-		    "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
+		    "bitmask=0x%016llX\n", ioc->name, __func__,
 		    port_details, i, port_details->num_phys,
 		    port_details, i, port_details->num_phys,
 		    (unsigned long long)port_details->phy_bitmask));
 		    (unsigned long long)port_details->phy_bitmask));
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
@@ -553,7 +553,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
 
 
 	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
 	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
-		    ioc->name,__FUNCTION__, __LINE__));
+		    ioc->name,__func__, __LINE__));
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -606,7 +606,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
 	    GFP_ATOMIC);
 	    GFP_ATOMIC);
 	if (!target_reset_list) {
 	if (!target_reset_list) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
-		    ioc->name,__FUNCTION__, __LINE__));
+		    ioc->name,__func__, __LINE__));
 		return;
 		return;
 	}
 	}
 
 
@@ -673,7 +673,7 @@ mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
 	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
 	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
 	if (!ev) {
 	if (!ev) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
-		    ioc->name,__FUNCTION__, __LINE__));
+		    ioc->name,__func__, __LINE__));
 		return;
 		return;
 	}
 	}
 
 
@@ -1183,7 +1183,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
 	reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
 	reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
 	if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
 	if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
 		printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
 		printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
-		    ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo);
+		    ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
 		error = -ENXIO;
 		error = -ENXIO;
 		goto out_unlock;
 		goto out_unlock;
 	}
 	}
@@ -1270,14 +1270,14 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
 
 	if (!rsp) {
 	if (!rsp) {
 		printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
 		printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
-		    ioc->name, __FUNCTION__);
+		    ioc->name, __func__);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	/* do we need to support multiple segments? */
 	/* do we need to support multiple segments? */
 	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
 	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
 		printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
 		printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
-		    ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+		    ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
 		    rsp->bio->bi_vcnt, rsp->data_len);
 		    rsp->bio->bi_vcnt, rsp->data_len);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -1343,7 +1343,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
 
 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
 	if (!timeleft) {
 	if (!timeleft) {
-		printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__);
+		printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
 		/* On timeout reset the board */
 		/* On timeout reset the board */
 		mpt_HardResetHandler(ioc, CAN_SLEEP);
 		mpt_HardResetHandler(ioc, CAN_SLEEP);
 		ret = -ETIMEDOUT;
 		ret = -ETIMEDOUT;
@@ -1361,7 +1361,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 		rsp->data_len -= smprep->ResponseDataLength;
 		rsp->data_len -= smprep->ResponseDataLength;
 	} else {
 	} else {
 		printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
 		printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
-		    ioc->name, __FUNCTION__);
+		    ioc->name, __func__);
 		ret = -ENXIO;
 		ret = -ENXIO;
 	}
 	}
 unmap:
 unmap:
@@ -2006,7 +2006,7 @@ static int mptsas_probe_one_phy(struct device *dev,
 			if (error) {
 			if (error) {
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					"%s: exit at line=%d\n", ioc->name,
-					__FUNCTION__, __LINE__));
+					__func__, __LINE__));
 				goto out;
 				goto out;
 			}
 			}
 			mptsas_set_port(ioc, phy_info, port);
 			mptsas_set_port(ioc, phy_info, port);
@@ -2076,7 +2076,7 @@ static int mptsas_probe_one_phy(struct device *dev,
 		if (!rphy) {
 		if (!rphy) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-				__FUNCTION__, __LINE__));
+				__func__, __LINE__));
 			goto out;
 			goto out;
 		}
 		}
 
 
@@ -2085,7 +2085,7 @@ static int mptsas_probe_one_phy(struct device *dev,
 		if (error) {
 		if (error) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-				__FUNCTION__, __LINE__));
+				__func__, __LINE__));
 			sas_rphy_free(rphy);
 			sas_rphy_free(rphy);
 			goto out;
 			goto out;
 		}
 		}
@@ -2613,7 +2613,7 @@ mptsas_hotplug_work(struct work_struct *work)
 				    (ev->channel << 8) + ev->id)) {
 				    (ev->channel << 8) + ev->id)) {
 					dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					"%s: exit at line=%d\n", ioc->name,
-						__FUNCTION__, __LINE__));
+						__func__, __LINE__));
 					break;
 					break;
 				}
 				}
 				phy_info = mptsas_find_phyinfo_by_sas_address(
 				phy_info = mptsas_find_phyinfo_by_sas_address(
@@ -2633,20 +2633,20 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (!phy_info){
 		if (!phy_info){
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-				__FUNCTION__, __LINE__));
+				__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 		if (!phy_info->port_details) {
 		if (!phy_info->port_details) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 		rphy = mptsas_get_rphy(phy_info);
 		rphy = mptsas_get_rphy(phy_info);
 		if (!rphy) {
 		if (!rphy) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 
 
@@ -2654,7 +2654,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (!port) {
 		if (!port) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 
 
@@ -2665,7 +2665,7 @@ mptsas_hotplug_work(struct work_struct *work)
 			if (!vtarget) {
 			if (!vtarget) {
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					"%s: exit at line=%d\n", ioc->name,
-					__FUNCTION__, __LINE__));
+					__func__, __LINE__));
 				break;
 				break;
 			}
 			}
 
 
@@ -2720,7 +2720,7 @@ mptsas_hotplug_work(struct work_struct *work)
 			(ev->channel << 8) + ev->id)) {
 			(ev->channel << 8) + ev->id)) {
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					"%s: exit at line=%d\n", ioc->name,
-					__FUNCTION__, __LINE__));
+					__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 
 
@@ -2732,7 +2732,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (!phy_info || !phy_info->port_details) {
 		if (!phy_info || !phy_info->port_details) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 
 
@@ -2744,7 +2744,7 @@ mptsas_hotplug_work(struct work_struct *work)
 			if (!vtarget) {
 			if (!vtarget) {
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				    "%s: exit at line=%d\n", ioc->name,
 				    "%s: exit at line=%d\n", ioc->name,
-				    __FUNCTION__, __LINE__));
+				    __func__, __LINE__));
 				break;
 				break;
 			}
 			}
 			/*
 			/*
@@ -2767,7 +2767,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (mptsas_get_rphy(phy_info)) {
 		if (mptsas_get_rphy(phy_info)) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			if (ev->channel) printk("%d\n", __LINE__);
 			if (ev->channel) printk("%d\n", __LINE__);
 			break;
 			break;
 		}
 		}
@@ -2776,7 +2776,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (!port) {
 		if (!port) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break;
 			break;
 		}
 		}
 		memcpy(&phy_info->attached, &sas_device,
 		memcpy(&phy_info->attached, &sas_device,
@@ -2801,7 +2801,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (!rphy) {
 		if (!rphy) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			break; /* non-fatal: an rphy can be added later */
 			break; /* non-fatal: an rphy can be added later */
 		}
 		}
 
 
@@ -2809,7 +2809,7 @@ mptsas_hotplug_work(struct work_struct *work)
 		if (sas_rphy_add(rphy)) {
 		if (sas_rphy_add(rphy)) {
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				"%s: exit at line=%d\n", ioc->name,
-			       	__FUNCTION__, __LINE__));
+			       	__func__, __LINE__));
 			sas_rphy_free(rphy);
 			sas_rphy_free(rphy);
 			break;
 			break;
 		}
 		}

+ 2 - 2
drivers/message/fusion/mptscsih.c

@@ -461,7 +461,7 @@ mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
 
 
 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
-		    ioc->name,__FUNCTION__));
+		    ioc->name,__func__));
 		return;
 		return;
 	}
 	}
 
 
@@ -2187,7 +2187,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
 				(ioc->debug_level & MPT_DEBUG_TM ))
 				(ioc->debug_level & MPT_DEBUG_TM ))
 		printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
 		printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
 			"iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
 			"iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
-			"term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
+			"term_cmnds=%d\n", __func__, ioc->id, pScsiTmReply->Bus,
 			 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
 			 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
 			le16_to_cpu(pScsiTmReply->IOCStatus),
 			le16_to_cpu(pScsiTmReply->IOCStatus),
 			le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
 			le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,

+ 1 - 1
drivers/misc/Kconfig

@@ -360,7 +360,7 @@ config THINKPAD_ACPI_VIDEO
 	  If you are not sure, say Y here.
 	  If you are not sure, say Y here.
 
 
 config THINKPAD_ACPI_HOTKEY_POLL
 config THINKPAD_ACPI_HOTKEY_POLL
-	bool "Suport NVRAM polling for hot keys"
+	bool "Support NVRAM polling for hot keys"
 	depends on THINKPAD_ACPI
 	depends on THINKPAD_ACPI
 	default y
 	default y
 	---help---
 	---help---

+ 0 - 1
drivers/misc/atmel-ssc.c

@@ -13,7 +13,6 @@
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/io.h>
-#include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/atmel-ssc.h>
 #include <linux/atmel-ssc.h>
 
 

+ 9 - 8
drivers/mmc/host/atmel-mci.c

@@ -11,6 +11,8 @@
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/ioport.h>
@@ -27,7 +29,6 @@
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 
 
 #include <asm/arch/board.h>
 #include <asm/arch/board.h>
-#include <asm/arch/gpio.h>
 
 
 #include "atmel-mci-regs.h"
 #include "atmel-mci-regs.h"
 
 
@@ -573,7 +574,7 @@ static int atmci_get_ro(struct mmc_host *mmc)
 	int			read_only = 0;
 	int			read_only = 0;
 	struct atmel_mci	*host = mmc_priv(mmc);
 	struct atmel_mci	*host = mmc_priv(mmc);
 
 
-	if (host->wp_pin >= 0) {
+	if (gpio_is_valid(host->wp_pin)) {
 		read_only = gpio_get_value(host->wp_pin);
 		read_only = gpio_get_value(host->wp_pin);
 		dev_dbg(&mmc->class_dev, "card is %s\n",
 		dev_dbg(&mmc->class_dev, "card is %s\n",
 				read_only ? "read-only" : "read-write");
 				read_only ? "read-only" : "read-write");
@@ -635,7 +636,7 @@ static void atmci_detect_change(unsigned long data)
 	 * been freed.
 	 * been freed.
 	 */
 	 */
 	smp_rmb();
 	smp_rmb();
-	if (host->detect_pin < 0)
+	if (!gpio_is_valid(host->detect_pin))
 		return;
 		return;
 
 
 	enable_irq(gpio_to_irq(host->detect_pin));
 	enable_irq(gpio_to_irq(host->detect_pin));
@@ -1050,7 +1051,7 @@ static int __init atmci_probe(struct platform_device *pdev)
 
 
 	/* Assume card is present if we don't have a detect pin */
 	/* Assume card is present if we don't have a detect pin */
 	host->present = 1;
 	host->present = 1;
-	if (host->detect_pin >= 0) {
+	if (gpio_is_valid(host->detect_pin)) {
 		if (gpio_request(host->detect_pin, "mmc_detect")) {
 		if (gpio_request(host->detect_pin, "mmc_detect")) {
 			dev_dbg(&mmc->class_dev, "no detect pin available\n");
 			dev_dbg(&mmc->class_dev, "no detect pin available\n");
 			host->detect_pin = -1;
 			host->detect_pin = -1;
@@ -1058,7 +1059,7 @@ static int __init atmci_probe(struct platform_device *pdev)
 			host->present = !gpio_get_value(host->detect_pin);
 			host->present = !gpio_get_value(host->detect_pin);
 		}
 		}
 	}
 	}
-	if (host->wp_pin >= 0) {
+	if (gpio_is_valid(host->wp_pin)) {
 		if (gpio_request(host->wp_pin, "mmc_wp")) {
 		if (gpio_request(host->wp_pin, "mmc_wp")) {
 			dev_dbg(&mmc->class_dev, "no WP pin available\n");
 			dev_dbg(&mmc->class_dev, "no WP pin available\n");
 			host->wp_pin = -1;
 			host->wp_pin = -1;
@@ -1069,7 +1070,7 @@ static int __init atmci_probe(struct platform_device *pdev)
 
 
 	mmc_add_host(mmc);
 	mmc_add_host(mmc);
 
 
-	if (host->detect_pin >= 0) {
+	if (gpio_is_valid(host->detect_pin)) {
 		setup_timer(&host->detect_timer, atmci_detect_change,
 		setup_timer(&host->detect_timer, atmci_detect_change,
 				(unsigned long)host);
 				(unsigned long)host);
 
 
@@ -1112,7 +1113,7 @@ static int __exit atmci_remove(struct platform_device *pdev)
 	if (host) {
 	if (host) {
 		/* Debugfs stuff is cleaned up by mmc core */
 		/* Debugfs stuff is cleaned up by mmc core */
 
 
-		if (host->detect_pin >= 0) {
+		if (gpio_is_valid(host->detect_pin)) {
 			int pin = host->detect_pin;
 			int pin = host->detect_pin;
 
 
 			/* Make sure the timer doesn't enable the interrupt */
 			/* Make sure the timer doesn't enable the interrupt */
@@ -1132,7 +1133,7 @@ static int __exit atmci_remove(struct platform_device *pdev)
 		mci_readl(host, SR);
 		mci_readl(host, SR);
 		clk_disable(host->mck);
 		clk_disable(host->mck);
 
 
-		if (host->wp_pin >= 0)
+		if (gpio_is_valid(host->wp_pin))
 			gpio_free(host->wp_pin);
 			gpio_free(host->wp_pin);
 
 
 		free_irq(platform_get_irq(pdev, 0), host->mmc);
 		free_irq(platform_get_irq(pdev, 0), host->mmc);

+ 1 - 1
drivers/s390/kvm/Makefile

@@ -6,4 +6,4 @@
 # it under the terms of the GNU General Public License (version 2 only)
 # it under the terms of the GNU General Public License (version 2 only)
 # as published by the Free Software Foundation.
 # as published by the Free Software Foundation.
 
 
-obj-$(CONFIG_VIRTIO) += kvm_virtio.o
+obj-$(CONFIG_S390_GUEST) += kvm_virtio.o

+ 30 - 10
drivers/scsi/3w-9xxx.c

@@ -4,7 +4,7 @@
    Written By: Adam Radford <linuxraid@amcc.com>
    Written By: Adam Radford <linuxraid@amcc.com>
    Modifications By: Tom Couch <linuxraid@amcc.com>
    Modifications By: Tom Couch <linuxraid@amcc.com>
 
 
-   Copyright (C) 2004-2007 Applied Micro Circuits Corporation.
+   Copyright (C) 2004-2008 Applied Micro Circuits Corporation.
 
 
    This program is free software; you can redistribute it and/or modify
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    it under the terms of the GNU General Public License as published by
@@ -71,6 +71,10 @@
                  Add support for 9650SE controllers.
                  Add support for 9650SE controllers.
    2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
    2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
    2.26.02.010 - Add support for 9690SA controllers.
    2.26.02.010 - Add support for 9690SA controllers.
+   2.26.02.011 - Increase max AENs drained to 256.
+                 Add MSI support and "use_msi" module parameter.
+                 Fix bug in twa_get_param() on 4GB+.
+                 Use pci_resource_len() for ioremap().
 */
 */
 
 
 #include <linux/module.h>
 #include <linux/module.h>
@@ -95,7 +99,7 @@
 #include "3w-9xxx.h"
 #include "3w-9xxx.h"
 
 
 /* Globals */
 /* Globals */
-#define TW_DRIVER_VERSION "2.26.02.010"
+#define TW_DRIVER_VERSION "2.26.02.011"
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static unsigned int twa_device_extension_count;
 static unsigned int twa_device_extension_count;
 static int twa_major = -1;
 static int twa_major = -1;
@@ -107,6 +111,10 @@ MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(TW_DRIVER_VERSION);
 MODULE_VERSION(TW_DRIVER_VERSION);
 
 
+static int use_msi = 0;
+module_param(use_msi, int, S_IRUGO);
+MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts.  Default: 0");
+
 /* Function prototypes */
 /* Function prototypes */
 static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
 static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
 static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
 static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
@@ -1038,7 +1046,6 @@ static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int tabl
 	TW_Command_Full *full_command_packet;
 	TW_Command_Full *full_command_packet;
 	TW_Command *command_packet;
 	TW_Command *command_packet;
 	TW_Param_Apache *param;
 	TW_Param_Apache *param;
-	unsigned long param_value;
 	void *retval = NULL;
 	void *retval = NULL;
 
 
 	/* Setup the command packet */
 	/* Setup the command packet */
@@ -1057,9 +1064,8 @@ static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int tabl
 	param->table_id = cpu_to_le16(table_id | 0x8000);
 	param->table_id = cpu_to_le16(table_id | 0x8000);
 	param->parameter_id = cpu_to_le16(parameter_id);
 	param->parameter_id = cpu_to_le16(parameter_id);
 	param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
 	param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes);
-	param_value = tw_dev->generic_buffer_phys[request_id];
 
 
-	command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(param_value);
+	command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
 	command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
 	command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE);
 
 
 	/* Post the command packet to the board */
 	/* Post the command packet to the board */
@@ -2000,7 +2006,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 {
 {
 	struct Scsi_Host *host = NULL;
 	struct Scsi_Host *host = NULL;
 	TW_Device_Extension *tw_dev;
 	TW_Device_Extension *tw_dev;
-	u32 mem_addr;
+	unsigned long mem_addr, mem_len;
 	int retval = -ENODEV;
 	int retval = -ENODEV;
 
 
 	retval = pci_enable_device(pdev);
 	retval = pci_enable_device(pdev);
@@ -2045,13 +2051,16 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 		goto out_free_device_extension;
 		goto out_free_device_extension;
 	}
 	}
 
 
-	if (pdev->device == PCI_DEVICE_ID_3WARE_9000)
+	if (pdev->device == PCI_DEVICE_ID_3WARE_9000) {
 		mem_addr = pci_resource_start(pdev, 1);
 		mem_addr = pci_resource_start(pdev, 1);
-	else
+		mem_len = pci_resource_len(pdev, 1);
+	} else {
 		mem_addr = pci_resource_start(pdev, 2);
 		mem_addr = pci_resource_start(pdev, 2);
+		mem_len = pci_resource_len(pdev, 2);
+	}
 
 
 	/* Save base address */
 	/* Save base address */
-	tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE);
+	tw_dev->base_addr = ioremap(mem_addr, mem_len);
 	if (!tw_dev->base_addr) {
 	if (!tw_dev->base_addr) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
 		goto out_release_mem_region;
 		goto out_release_mem_region;
@@ -2086,7 +2095,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 
 
 	pci_set_drvdata(pdev, host);
 	pci_set_drvdata(pdev, host);
 
 
-	printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%x, IRQ: %d.\n",
+	printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%lx, IRQ: %d.\n",
 	       host->host_no, mem_addr, pdev->irq);
 	       host->host_no, mem_addr, pdev->irq);
 	printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
 	printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
 	       host->host_no,
 	       host->host_no,
@@ -2097,6 +2106,11 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 	       le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
 	       le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
 				     TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
 				     TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
 
 
+	/* Try to enable MSI */
+	if (use_msi && (pdev->device != PCI_DEVICE_ID_3WARE_9000) &&
+	    !pci_enable_msi(pdev))
+		set_bit(TW_USING_MSI, &tw_dev->flags);
+
 	/* Now setup the interrupt handler */
 	/* Now setup the interrupt handler */
 	retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
 	retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
 	if (retval) {
 	if (retval) {
@@ -2120,6 +2134,8 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 	return 0;
 	return 0;
 
 
 out_remove_host:
 out_remove_host:
+	if (test_bit(TW_USING_MSI, &tw_dev->flags))
+		pci_disable_msi(pdev);
 	scsi_remove_host(host);
 	scsi_remove_host(host);
 out_iounmap:
 out_iounmap:
 	iounmap(tw_dev->base_addr);
 	iounmap(tw_dev->base_addr);
@@ -2151,6 +2167,10 @@ static void twa_remove(struct pci_dev *pdev)
 	/* Shutdown the card */
 	/* Shutdown the card */
 	__twa_shutdown(tw_dev);
 	__twa_shutdown(tw_dev);
 
 
+	/* Disable MSI if enabled */
+	if (test_bit(TW_USING_MSI, &tw_dev->flags))
+		pci_disable_msi(pdev);
+
 	/* Free IO remapping */
 	/* Free IO remapping */
 	iounmap(tw_dev->base_addr);
 	iounmap(tw_dev->base_addr);
 
 

+ 5 - 4
drivers/scsi/3w-9xxx.h

@@ -4,7 +4,7 @@
    Written By: Adam Radford <linuxraid@amcc.com>
    Written By: Adam Radford <linuxraid@amcc.com>
    Modifications By: Tom Couch <linuxraid@amcc.com>
    Modifications By: Tom Couch <linuxraid@amcc.com>
 
 
-   Copyright (C) 2004-2007 Applied Micro Circuits Corporation.
+   Copyright (C) 2004-2008 Applied Micro Circuits Corporation.
 
 
    This program is free software; you can redistribute it and/or modify
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    it under the terms of the GNU General Public License as published by
@@ -319,8 +319,8 @@ static twa_message_type twa_error_table[] = {
 
 
 /* Compatibility defines */
 /* Compatibility defines */
 #define TW_9000_ARCH_ID 0x5
 #define TW_9000_ARCH_ID 0x5
-#define TW_CURRENT_DRIVER_SRL 30
-#define TW_CURRENT_DRIVER_BUILD 80
+#define TW_CURRENT_DRIVER_SRL 35
+#define TW_CURRENT_DRIVER_BUILD 0
 #define TW_CURRENT_DRIVER_BRANCH 0
 #define TW_CURRENT_DRIVER_BRANCH 0
 
 
 /* Phase defines */
 /* Phase defines */
@@ -352,8 +352,9 @@ static twa_message_type twa_error_table[] = {
 #define TW_MAX_RESET_TRIES		      2
 #define TW_MAX_RESET_TRIES		      2
 #define TW_MAX_CMDS_PER_LUN		      254
 #define TW_MAX_CMDS_PER_LUN		      254
 #define TW_MAX_RESPONSE_DRAIN		      256
 #define TW_MAX_RESPONSE_DRAIN		      256
-#define TW_MAX_AEN_DRAIN		      40
+#define TW_MAX_AEN_DRAIN		      255
 #define TW_IN_RESET                           2
 #define TW_IN_RESET                           2
+#define TW_USING_MSI			      3
 #define TW_IN_ATTENTION_LOOP		      4
 #define TW_IN_ATTENTION_LOOP		      4
 #define TW_MAX_SECTORS                        256
 #define TW_MAX_SECTORS                        256
 #define TW_AEN_WAIT_TIME                      1000
 #define TW_AEN_WAIT_TIME                      1000

+ 1 - 0
drivers/scsi/Kconfig

@@ -63,6 +63,7 @@ comment "SCSI support type (disk, tape, CD-ROM)"
 config BLK_DEV_SD
 config BLK_DEV_SD
 	tristate "SCSI disk support"
 	tristate "SCSI disk support"
 	depends on SCSI
 	depends on SCSI
+	select CRC_T10DIF
 	---help---
 	---help---
 	  If you want to use SCSI hard disks, Fibre Channel disks,
 	  If you want to use SCSI hard disks, Fibre Channel disks,
 	  Serial ATA (SATA) or Parallel ATA (PATA) hard disks,
 	  Serial ATA (SATA) or Parallel ATA (PATA) hard disks,

+ 2 - 0
drivers/scsi/Makefile

@@ -151,6 +151,8 @@ scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
 scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_if.o
 scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_if.o
 
 
 sd_mod-objs	:= sd.o
 sd_mod-objs	:= sd.o
+sd_mod-$(CONFIG_BLK_DEV_INTEGRITY) += sd_dif.o
+
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
 ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
 		:= -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \
 		:= -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \

+ 1 - 1
drivers/scsi/advansys.c

@@ -2278,7 +2278,7 @@ do { \
 #define ASC_DBG(lvl, format, arg...) {					\
 #define ASC_DBG(lvl, format, arg...) {					\
 	if (asc_dbglvl >= (lvl))					\
 	if (asc_dbglvl >= (lvl))					\
 		printk(KERN_DEBUG "%s: %s: " format, DRV_NAME,		\
 		printk(KERN_DEBUG "%s: %s: " format, DRV_NAME,		\
-			__FUNCTION__ , ## arg);				\
+			__func__ , ## arg);				\
 }
 }
 
 
 #define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
 #define ASC_DBG_PRT_SCSI_HOST(lvl, s) \

+ 6 - 6
drivers/scsi/aha152x.c

@@ -288,20 +288,20 @@ static LIST_HEAD(aha152x_host_list);
 #define DO_LOCK(flags)	\
 #define DO_LOCK(flags)	\
 	do { \
 	do { \
 		if(spin_is_locked(&QLOCK)) { \
 		if(spin_is_locked(&QLOCK)) { \
-			DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+			DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \
 		} \
 		} \
-		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
 		spin_lock_irqsave(&QLOCK,flags); \
 		spin_lock_irqsave(&QLOCK,flags); \
-		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
-		QLOCKER=__FUNCTION__; \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
+		QLOCKER=__func__; \
 		QLOCKERL=__LINE__; \
 		QLOCKERL=__LINE__; \
 	} while(0)
 	} while(0)
 
 
 #define DO_UNLOCK(flags)	\
 #define DO_UNLOCK(flags)	\
 	do { \
 	do { \
-		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \
 		spin_unlock_irqrestore(&QLOCK,flags); \
 		spin_unlock_irqrestore(&QLOCK,flags); \
-		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
 		QLOCKER="(not locked)"; \
 		QLOCKER="(not locked)"; \
 		QLOCKERL=0; \
 		QLOCKERL=0; \
 	} while(0)
 	} while(0)

+ 2 - 2
drivers/scsi/aic94xx/aic94xx.h

@@ -39,9 +39,9 @@
 
 
 #ifdef ASD_ENTER_EXIT
 #ifdef ASD_ENTER_EXIT
 #define ENTER  printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
 #define ENTER  printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
-		__FUNCTION__)
+		__func__)
 #define EXIT   printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
 #define EXIT   printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
-		__FUNCTION__)
+		__func__)
 #else
 #else
 #define ENTER
 #define ENTER
 #define EXIT
 #define EXIT

+ 1 - 1
drivers/scsi/aic94xx/aic94xx_hwi.c

@@ -1359,7 +1359,7 @@ int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask)
 	struct asd_ascb *ascb_list;
 	struct asd_ascb *ascb_list;
 
 
 	if (!phy_mask) {
 	if (!phy_mask) {
-		asd_printk("%s called with phy_mask of 0!?\n", __FUNCTION__);
+		asd_printk("%s called with phy_mask of 0!?\n", __func__);
 		return 0;
 		return 0;
 	}
 	}
 
 

+ 23 - 23
drivers/scsi/aic94xx/aic94xx_scb.c

@@ -211,7 +211,7 @@ static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
 		phy->asd_port = port;
 		phy->asd_port = port;
 	}
 	}
 	ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n",
 	ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n",
-		    __FUNCTION__, phy->asd_port->phy_mask, sas_phy->id);
+		    __func__, phy->asd_port->phy_mask, sas_phy->id);
 	asd_update_port_links(asd_ha, phy);
 	asd_update_port_links(asd_ha, phy);
 	spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
 	spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
 }
 }
@@ -294,7 +294,7 @@ static void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
 		struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num,
 		struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num,
 							  GFP_ATOMIC);
 							  GFP_ATOMIC);
 		if (!cp) {
 		if (!cp) {
-			asd_printk("%s: out of memory\n", __FUNCTION__);
+			asd_printk("%s: out of memory\n", __func__);
 			goto out;
 			goto out;
 		}
 		}
 		ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n",
 		ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n",
@@ -446,7 +446,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 		struct domain_device *failed_dev = NULL;
 		struct domain_device *failed_dev = NULL;
 
 
 		ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
 		ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n",
-			    __FUNCTION__, dl->status_block[3]);
+			    __func__, dl->status_block[3]);
 
 
 		/*
 		/*
 		 * Find the task that caused the abort and abort it first.
 		 * Find the task that caused the abort and abort it first.
@@ -474,7 +474,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 
 
 		if (!failed_dev) {
 		if (!failed_dev) {
 			ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n",
 			ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n",
-				    __FUNCTION__, tc_abort);
+				    __func__, tc_abort);
 			goto out;
 			goto out;
 		}
 		}
 
 
@@ -502,7 +502,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 		conn_handle = *((u16*)(&dl->status_block[1]));
 		conn_handle = *((u16*)(&dl->status_block[1]));
 		conn_handle = le16_to_cpu(conn_handle);
 		conn_handle = le16_to_cpu(conn_handle);
 
 
-		ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __FUNCTION__,
+		ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __func__,
 			    dl->status_block[3]);
 			    dl->status_block[3]);
 
 
 		/* Find the last pending task for the device... */
 		/* Find the last pending task for the device... */
@@ -522,7 +522,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 
 
 		if (!last_dev_task) {
 		if (!last_dev_task) {
 			ASD_DPRINTK("%s: Device reset for idle device %d?\n",
 			ASD_DPRINTK("%s: Device reset for idle device %d?\n",
-				    __FUNCTION__, conn_handle);
+				    __func__, conn_handle);
 			goto out;
 			goto out;
 		}
 		}
 
 
@@ -549,10 +549,10 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 		goto out;
 		goto out;
 	}
 	}
 	case SIGNAL_NCQ_ERROR:
 	case SIGNAL_NCQ_ERROR:
-		ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __FUNCTION__);
+		ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __func__);
 		goto out;
 		goto out;
 	case CLEAR_NCQ_ERROR:
 	case CLEAR_NCQ_ERROR:
-		ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __FUNCTION__);
+		ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __func__);
 		goto out;
 		goto out;
 	}
 	}
 
 
@@ -560,26 +560,26 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 
 
 	switch (sb_opcode) {
 	switch (sb_opcode) {
 	case BYTES_DMAED:
 	case BYTES_DMAED:
-		ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __FUNCTION__, phy_id);
+		ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __func__, phy_id);
 		asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
 		asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
 		break;
 		break;
 	case PRIMITIVE_RECVD:
 	case PRIMITIVE_RECVD:
-		ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __FUNCTION__,
+		ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __func__,
 			    phy_id);
 			    phy_id);
 		asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
 		asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
 		break;
 		break;
 	case PHY_EVENT:
 	case PHY_EVENT:
-		ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __FUNCTION__, phy_id);
+		ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __func__, phy_id);
 		asd_phy_event_tasklet(ascb, dl);
 		asd_phy_event_tasklet(ascb, dl);
 		break;
 		break;
 	case LINK_RESET_ERROR:
 	case LINK_RESET_ERROR:
-		ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __FUNCTION__,
+		ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __func__,
 			    phy_id);
 			    phy_id);
 		asd_link_reset_err_tasklet(ascb, dl, phy_id);
 		asd_link_reset_err_tasklet(ascb, dl, phy_id);
 		break;
 		break;
 	case TIMER_EVENT:
 	case TIMER_EVENT:
 		ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
 		ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
-			    __FUNCTION__, phy_id);
+			    __func__, phy_id);
 		asd_turn_led(asd_ha, phy_id, 0);
 		asd_turn_led(asd_ha, phy_id, 0);
 		/* the device is gone */
 		/* the device is gone */
 		sas_phy_disconnected(sas_phy);
 		sas_phy_disconnected(sas_phy);
@@ -587,7 +587,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
 		sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
 		sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
 		break;
 		break;
 	default:
 	default:
-		ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
+		ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __func__,
 			    phy_id, sb_opcode);
 			    phy_id, sb_opcode);
 		ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
 		ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
 			    edb, dl->opcode);
 			    edb, dl->opcode);
@@ -654,7 +654,7 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
 
 
 	if (status != 0) {
 	if (status != 0) {
 		ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n",
 		ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n",
-			    __FUNCTION__, phy_id, status);
+			    __func__, phy_id, status);
 		goto out;
 		goto out;
 	}
 	}
 
 
@@ -663,7 +663,7 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
 		asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id);
 		asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id);
 		asd_turn_led(asd_ha, phy_id, 0);
 		asd_turn_led(asd_ha, phy_id, 0);
 		asd_control_led(asd_ha, phy_id, 0);
 		asd_control_led(asd_ha, phy_id, 0);
-		ASD_DPRINTK("%s: disable phy%d\n", __FUNCTION__, phy_id);
+		ASD_DPRINTK("%s: disable phy%d\n", __func__, phy_id);
 		break;
 		break;
 
 
 	case ENABLE_PHY:
 	case ENABLE_PHY:
@@ -673,40 +673,40 @@ static void control_phy_tasklet_complete(struct asd_ascb *ascb,
 			get_lrate_mode(phy, oob_mode);
 			get_lrate_mode(phy, oob_mode);
 			asd_turn_led(asd_ha, phy_id, 1);
 			asd_turn_led(asd_ha, phy_id, 1);
 			ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n",
 			ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n",
-				    __FUNCTION__, phy_id,phy->sas_phy.linkrate,
+				    __func__, phy_id,phy->sas_phy.linkrate,
 				    phy->sas_phy.iproto);
 				    phy->sas_phy.iproto);
 		} else if (oob_status & CURRENT_SPINUP_HOLD) {
 		} else if (oob_status & CURRENT_SPINUP_HOLD) {
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_turn_led(asd_ha, phy_id, 1);
 			asd_turn_led(asd_ha, phy_id, 1);
-			ASD_DPRINTK("%s: phy%d, spinup hold\n", __FUNCTION__,
+			ASD_DPRINTK("%s: phy%d, spinup hold\n", __func__,
 				    phy_id);
 				    phy_id);
 		} else if (oob_status & CURRENT_ERR_MASK) {
 		} else if (oob_status & CURRENT_ERR_MASK) {
 			asd_turn_led(asd_ha, phy_id, 0);
 			asd_turn_led(asd_ha, phy_id, 0);
 			ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n",
 			ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n",
-				    __FUNCTION__, phy_id, oob_status);
+				    __func__, phy_id, oob_status);
 		} else if (oob_status & (CURRENT_HOT_PLUG_CNCT
 		} else if (oob_status & (CURRENT_HOT_PLUG_CNCT
 					 | CURRENT_DEVICE_PRESENT))  {
 					 | CURRENT_DEVICE_PRESENT))  {
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_turn_led(asd_ha, phy_id, 1);
 			asd_turn_led(asd_ha, phy_id, 1);
 			ASD_DPRINTK("%s: phy%d: hot plug or device present\n",
 			ASD_DPRINTK("%s: phy%d: hot plug or device present\n",
-				    __FUNCTION__, phy_id);
+				    __func__, phy_id);
 		} else {
 		} else {
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
 			asd_turn_led(asd_ha, phy_id, 0);
 			asd_turn_led(asd_ha, phy_id, 0);
 			ASD_DPRINTK("%s: phy%d: no device present: "
 			ASD_DPRINTK("%s: phy%d: no device present: "
 				    "oob_status:0x%x\n",
 				    "oob_status:0x%x\n",
-				    __FUNCTION__, phy_id, oob_status);
+				    __func__, phy_id, oob_status);
 		}
 		}
 		break;
 		break;
 	case RELEASE_SPINUP_HOLD:
 	case RELEASE_SPINUP_HOLD:
 	case PHY_NO_OP:
 	case PHY_NO_OP:
 	case EXECUTE_HARD_RESET:
 	case EXECUTE_HARD_RESET:
-		ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __FUNCTION__,
+		ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __func__,
 			    phy_id, control_phy->sub_func);
 			    phy_id, control_phy->sub_func);
 		/* XXX finish */
 		/* XXX finish */
 		break;
 		break;
 	default:
 	default:
-		ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __FUNCTION__,
+		ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __func__,
 			    phy_id, control_phy->sub_func);
 			    phy_id, control_phy->sub_func);
 		break;
 		break;
 	}
 	}

+ 1 - 1
drivers/scsi/aic94xx/aic94xx_task.c

@@ -320,7 +320,7 @@ Again:
 	case TC_RESUME:
 	case TC_RESUME:
 	case TC_PARTIAL_SG_LIST:
 	case TC_PARTIAL_SG_LIST:
 	default:
 	default:
-		ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __FUNCTION__, opcode);
+		ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __func__, opcode);
 		break;
 		break;
 	}
 	}
 
 

+ 9 - 9
drivers/scsi/aic94xx/aic94xx_tmf.c

@@ -75,12 +75,12 @@ static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
 					     struct done_list_struct *dl)
 					     struct done_list_struct *dl)
 {
 {
 	struct tasklet_completion_status *tcs = ascb->uldd_task;
 	struct tasklet_completion_status *tcs = ascb->uldd_task;
-	ASD_DPRINTK("%s: here\n", __FUNCTION__);
+	ASD_DPRINTK("%s: here\n", __func__);
 	if (!del_timer(&ascb->timer)) {
 	if (!del_timer(&ascb->timer)) {
-		ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__);
+		ASD_DPRINTK("%s: couldn't delete timer\n", __func__);
 		return;
 		return;
 	}
 	}
-	ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode);
+	ASD_DPRINTK("%s: opcode: 0x%x\n", __func__, dl->opcode);
 	tcs->dl_opcode = dl->opcode;
 	tcs->dl_opcode = dl->opcode;
 	complete(ascb->completion);
 	complete(ascb->completion);
 	asd_ascb_free(ascb);
 	asd_ascb_free(ascb);
@@ -91,7 +91,7 @@ static void asd_clear_nexus_timedout(unsigned long data)
 	struct asd_ascb *ascb = (void *)data;
 	struct asd_ascb *ascb = (void *)data;
 	struct tasklet_completion_status *tcs = ascb->uldd_task;
 	struct tasklet_completion_status *tcs = ascb->uldd_task;
 
 
-	ASD_DPRINTK("%s: here\n", __FUNCTION__);
+	ASD_DPRINTK("%s: here\n", __func__);
 	tcs->dl_opcode = TMF_RESP_FUNC_FAILED;
 	tcs->dl_opcode = TMF_RESP_FUNC_FAILED;
 	complete(ascb->completion);
 	complete(ascb->completion);
 }
 }
@@ -103,7 +103,7 @@ static void asd_clear_nexus_timedout(unsigned long data)
 	DECLARE_COMPLETION_ONSTACK(completion); \
 	DECLARE_COMPLETION_ONSTACK(completion); \
 	DECLARE_TCS(tcs); \
 	DECLARE_TCS(tcs); \
 		\
 		\
-	ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \
+	ASD_DPRINTK("%s: PRE\n", __func__); \
         res = 1;                \
         res = 1;                \
 	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
 	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
 	if (!ascb)              \
 	if (!ascb)              \
@@ -115,12 +115,12 @@ static void asd_clear_nexus_timedout(unsigned long data)
 	scb->header.opcode = CLEAR_NEXUS
 	scb->header.opcode = CLEAR_NEXUS
 
 
 #define CLEAR_NEXUS_POST        \
 #define CLEAR_NEXUS_POST        \
-	ASD_DPRINTK("%s: POST\n", __FUNCTION__); \
+	ASD_DPRINTK("%s: POST\n", __func__); \
 	res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
 	res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
 				   asd_clear_nexus_timedout);              \
 				   asd_clear_nexus_timedout);              \
 	if (res)                \
 	if (res)                \
 		goto out_err;   \
 		goto out_err;   \
-	ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \
+	ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __func__); \
 	wait_for_completion(&completion); \
 	wait_for_completion(&completion); \
 	res = tcs.dl_opcode; \
 	res = tcs.dl_opcode; \
 	if (res == TC_NO_ERROR) \
 	if (res == TC_NO_ERROR) \
@@ -417,7 +417,7 @@ int asd_abort_task(struct sas_task *task)
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		res = TMF_RESP_FUNC_COMPLETE;
 		res = TMF_RESP_FUNC_COMPLETE;
-		ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
+		ASD_DPRINTK("%s: task 0x%p done\n", __func__, task);
 		goto out_done;
 		goto out_done;
 	}
 	}
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
@@ -481,7 +481,7 @@ int asd_abort_task(struct sas_task *task)
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		res = TMF_RESP_FUNC_COMPLETE;
 		res = TMF_RESP_FUNC_COMPLETE;
-		ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
+		ASD_DPRINTK("%s: task 0x%p done\n", __func__, task);
 		goto out_done;
 		goto out_done;
 	}
 	}
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 	spin_unlock_irqrestore(&task->task_state_lock, flags);

+ 2 - 2
drivers/scsi/arm/fas216.c

@@ -240,7 +240,7 @@ static void __fas216_checkmagic(FAS216_Info *info, const char *func)
 		panic("scsi memory space corrupted in %s", func);
 		panic("scsi memory space corrupted in %s", func);
 	}
 	}
 }
 }
-#define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__)
+#define fas216_checkmagic(info) __fas216_checkmagic((info), __func__)
 #else
 #else
 #define fas216_checkmagic(info)
 #define fas216_checkmagic(info)
 #endif
 #endif
@@ -2658,7 +2658,7 @@ int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
 	fas216_checkmagic(info);
 	fas216_checkmagic(info);
 
 
 	printk("scsi%d.%c: %s: resetting host\n",
 	printk("scsi%d.%c: %s: resetting host\n",
-		info->host->host_no, '0' + SCpnt->device->id, __FUNCTION__);
+		info->host->host_no, '0' + SCpnt->device->id, __func__);
 
 
 	/*
 	/*
 	 * Reset the SCSI chip.
 	 * Reset the SCSI chip.

+ 1 - 0
drivers/scsi/ch.c

@@ -930,6 +930,7 @@ static int ch_probe(struct device *dev)
 	if (init)
 	if (init)
 		ch_init_elem(ch);
 		ch_init_elem(ch);
 
 
+	dev_set_drvdata(dev, ch);
 	sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
 	sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
 
 
 	return 0;
 	return 0;

+ 8 - 0
drivers/scsi/device_handler/Kconfig

@@ -30,3 +30,11 @@ config SCSI_DH_EMC
 	depends on SCSI_DH
 	depends on SCSI_DH
 	help
 	help
 	If you have a EMC CLARiiON select y. Otherwise, say N.
 	If you have a EMC CLARiiON select y. Otherwise, say N.
+
+config SCSI_DH_ALUA
+	tristate "SPC-3 ALUA Device Handler (EXPERIMENTAL)"
+	depends on SCSI_DH && EXPERIMENTAL
+	help
+	  SCSI Device handler for generic SPC-3 Asymmetric Logical Unit
+	  Access (ALUA).
+

+ 1 - 0
drivers/scsi/device_handler/Makefile

@@ -5,3 +5,4 @@ obj-$(CONFIG_SCSI_DH)		+= scsi_dh.o
 obj-$(CONFIG_SCSI_DH_RDAC)	+= scsi_dh_rdac.o
 obj-$(CONFIG_SCSI_DH_RDAC)	+= scsi_dh_rdac.o
 obj-$(CONFIG_SCSI_DH_HP_SW)	+= scsi_dh_hp_sw.o
 obj-$(CONFIG_SCSI_DH_HP_SW)	+= scsi_dh_hp_sw.o
 obj-$(CONFIG_SCSI_DH_EMC)	+= scsi_dh_emc.o
 obj-$(CONFIG_SCSI_DH_EMC)	+= scsi_dh_emc.o
+obj-$(CONFIG_SCSI_DH_ALUA)	+= scsi_dh_alua.o

+ 415 - 31
drivers/scsi/device_handler/scsi_dh.c

@@ -24,8 +24,16 @@
 #include <scsi/scsi_dh.h>
 #include <scsi/scsi_dh.h>
 #include "../scsi_priv.h"
 #include "../scsi_priv.h"
 
 
+struct scsi_dh_devinfo_list {
+	struct list_head node;
+	char vendor[9];
+	char model[17];
+	struct scsi_device_handler *handler;
+};
+
 static DEFINE_SPINLOCK(list_lock);
 static DEFINE_SPINLOCK(list_lock);
 static LIST_HEAD(scsi_dh_list);
 static LIST_HEAD(scsi_dh_list);
+static LIST_HEAD(scsi_dh_dev_list);
 
 
 static struct scsi_device_handler *get_device_handler(const char *name)
 static struct scsi_device_handler *get_device_handler(const char *name)
 {
 {
@@ -33,7 +41,7 @@ static struct scsi_device_handler *get_device_handler(const char *name)
 
 
 	spin_lock(&list_lock);
 	spin_lock(&list_lock);
 	list_for_each_entry(tmp, &scsi_dh_list, list) {
 	list_for_each_entry(tmp, &scsi_dh_list, list) {
-		if (!strcmp(tmp->name, name)) {
+		if (!strncmp(tmp->name, name, strlen(tmp->name))) {
 			found = tmp;
 			found = tmp;
 			break;
 			break;
 		}
 		}
@@ -42,11 +50,307 @@ static struct scsi_device_handler *get_device_handler(const char *name)
 	return found;
 	return found;
 }
 }
 
 
+
+static struct scsi_device_handler *
+scsi_dh_cache_lookup(struct scsi_device *sdev)
+{
+	struct scsi_dh_devinfo_list *tmp;
+	struct scsi_device_handler *found_dh = NULL;
+
+	spin_lock(&list_lock);
+	list_for_each_entry(tmp, &scsi_dh_dev_list, node) {
+		if (!strncmp(sdev->vendor, tmp->vendor, strlen(tmp->vendor)) &&
+		    !strncmp(sdev->model, tmp->model, strlen(tmp->model))) {
+			found_dh = tmp->handler;
+			break;
+		}
+	}
+	spin_unlock(&list_lock);
+
+	return found_dh;
+}
+
+static int scsi_dh_handler_lookup(struct scsi_device_handler *scsi_dh,
+				  struct scsi_device *sdev)
+{
+	int i, found = 0;
+
+	for(i = 0; scsi_dh->devlist[i].vendor; i++) {
+		if (!strncmp(sdev->vendor, scsi_dh->devlist[i].vendor,
+			     strlen(scsi_dh->devlist[i].vendor)) &&
+		    !strncmp(sdev->model, scsi_dh->devlist[i].model,
+			     strlen(scsi_dh->devlist[i].model))) {
+			found = 1;
+			break;
+		}
+	}
+	return found;
+}
+
+/*
+ * device_handler_match - Attach a device handler to a device
+ * @scsi_dh - The device handler to match against or NULL
+ * @sdev - SCSI device to be tested against @scsi_dh
+ *
+ * Tests @sdev against the device handler @scsi_dh or against
+ * all registered device_handler if @scsi_dh == NULL.
+ * Returns the found device handler or NULL if not found.
+ */
+static struct scsi_device_handler *
+device_handler_match(struct scsi_device_handler *scsi_dh,
+		     struct scsi_device *sdev)
+{
+	struct scsi_device_handler *found_dh = NULL;
+	struct scsi_dh_devinfo_list *tmp;
+
+	found_dh = scsi_dh_cache_lookup(sdev);
+	if (found_dh)
+		return found_dh;
+
+	if (scsi_dh) {
+		if (scsi_dh_handler_lookup(scsi_dh, sdev))
+			found_dh = scsi_dh;
+	} else {
+		struct scsi_device_handler *tmp_dh;
+
+		spin_lock(&list_lock);
+		list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
+			if (scsi_dh_handler_lookup(tmp_dh, sdev))
+				found_dh = tmp_dh;
+		}
+		spin_unlock(&list_lock);
+	}
+
+	if (found_dh) { /* If device is found, add it to the cache */
+		tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+		if (tmp) {
+			strncpy(tmp->vendor, sdev->vendor, 8);
+			strncpy(tmp->model, sdev->model, 16);
+			tmp->vendor[8] = '\0';
+			tmp->model[16] = '\0';
+			tmp->handler = found_dh;
+			spin_lock(&list_lock);
+			list_add(&tmp->node, &scsi_dh_dev_list);
+			spin_unlock(&list_lock);
+		} else {
+			found_dh = NULL;
+		}
+	}
+
+	return found_dh;
+}
+
+/*
+ * scsi_dh_handler_attach - Attach a device handler to a device
+ * @sdev - SCSI device the device handler should attach to
+ * @scsi_dh - The device handler to attach
+ */
+static int scsi_dh_handler_attach(struct scsi_device *sdev,
+				  struct scsi_device_handler *scsi_dh)
+{
+	int err = 0;
+
+	if (sdev->scsi_dh_data) {
+		if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
+			err = -EBUSY;
+	} else if (scsi_dh->attach)
+		err = scsi_dh->attach(sdev);
+
+	return err;
+}
+
+/*
+ * scsi_dh_handler_detach - Detach a device handler from a device
+ * @sdev - SCSI device the device handler should be detached from
+ * @scsi_dh - Device handler to be detached
+ *
+ * Detach from a device handler. If a device handler is specified,
+ * only detach if the currently attached handler matches @scsi_dh.
+ */
+static void scsi_dh_handler_detach(struct scsi_device *sdev,
+				   struct scsi_device_handler *scsi_dh)
+{
+	if (!sdev->scsi_dh_data)
+		return;
+
+	if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh)
+		return;
+
+	if (!scsi_dh)
+		scsi_dh = sdev->scsi_dh_data->scsi_dh;
+
+	if (scsi_dh && scsi_dh->detach)
+		scsi_dh->detach(sdev);
+}
+
+/*
+ * Functions for sysfs attribute 'dh_state'
+ */
+static ssize_t
+store_dh_state(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct scsi_device_handler *scsi_dh;
+	int err = -EINVAL;
+
+	if (!sdev->scsi_dh_data) {
+		/*
+		 * Attach to a device handler
+		 */
+		if (!(scsi_dh = get_device_handler(buf)))
+			return err;
+		err = scsi_dh_handler_attach(sdev, scsi_dh);
+	} else {
+		scsi_dh = sdev->scsi_dh_data->scsi_dh;
+		if (!strncmp(buf, "detach", 6)) {
+			/*
+			 * Detach from a device handler
+			 */
+			scsi_dh_handler_detach(sdev, scsi_dh);
+			err = 0;
+		} else if (!strncmp(buf, "activate", 8)) {
+			/*
+			 * Activate a device handler
+			 */
+			if (scsi_dh->activate)
+				err = scsi_dh->activate(sdev);
+			else
+				err = 0;
+		}
+	}
+
+	return err<0?err:count;
+}
+
+static ssize_t
+show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+
+	if (!sdev->scsi_dh_data)
+		return snprintf(buf, 20, "detached\n");
+
+	return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name);
+}
+
+static struct device_attribute scsi_dh_state_attr =
+	__ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
+	       store_dh_state);
+
+/*
+ * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh
+ */
+static int scsi_dh_sysfs_attr_add(struct device *dev, void *data)
+{
+	struct scsi_device *sdev;
+	int err;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+
+	err = device_create_file(&sdev->sdev_gendev,
+				 &scsi_dh_state_attr);
+
+	return 0;
+}
+
+/*
+ * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh
+ */
+static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data)
+{
+	struct scsi_device *sdev;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+
+	device_remove_file(&sdev->sdev_gendev,
+			   &scsi_dh_state_attr);
+
+	return 0;
+}
+
+/*
+ * scsi_dh_notifier - notifier chain callback
+ */
+static int scsi_dh_notifier(struct notifier_block *nb,
+			    unsigned long action, void *data)
+{
+	struct device *dev = data;
+	struct scsi_device *sdev;
+	int err = 0;
+	struct scsi_device_handler *devinfo = NULL;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+
+	if (action == BUS_NOTIFY_ADD_DEVICE) {
+		devinfo = device_handler_match(NULL, sdev);
+		if (!devinfo)
+			goto out;
+
+		err = scsi_dh_handler_attach(sdev, devinfo);
+		if (!err)
+			err = device_create_file(dev, &scsi_dh_state_attr);
+	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
+		device_remove_file(dev, &scsi_dh_state_attr);
+		scsi_dh_handler_detach(sdev, NULL);
+	}
+out:
+	return err;
+}
+
+/*
+ * scsi_dh_notifier_add - Callback for scsi_register_device_handler
+ */
 static int scsi_dh_notifier_add(struct device *dev, void *data)
 static int scsi_dh_notifier_add(struct device *dev, void *data)
 {
 {
 	struct scsi_device_handler *scsi_dh = data;
 	struct scsi_device_handler *scsi_dh = data;
+	struct scsi_device *sdev;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	if (!get_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+
+	if (device_handler_match(scsi_dh, sdev))
+		scsi_dh_handler_attach(sdev, scsi_dh);
+
+	put_device(dev);
+
+	return 0;
+}
+
+/*
+ * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler
+ */
+static int scsi_dh_notifier_remove(struct device *dev, void *data)
+{
+	struct scsi_device_handler *scsi_dh = data;
+	struct scsi_device *sdev;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	if (!get_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+
+	scsi_dh_handler_detach(sdev, scsi_dh);
+
+	put_device(dev);
 
 
-	scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_ADD_DEVICE, dev);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -59,33 +363,19 @@ static int scsi_dh_notifier_add(struct device *dev, void *data)
  */
  */
 int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
 int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
 {
 {
-	int ret = -EBUSY;
-	struct scsi_device_handler *tmp;
+	if (get_device_handler(scsi_dh->name))
+		return -EBUSY;
 
 
-	tmp = get_device_handler(scsi_dh->name);
-	if (tmp)
-		goto done;
-
-	ret = bus_register_notifier(&scsi_bus_type, &scsi_dh->nb);
-
-	bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
 	spin_lock(&list_lock);
 	spin_lock(&list_lock);
 	list_add(&scsi_dh->list, &scsi_dh_list);
 	list_add(&scsi_dh->list, &scsi_dh_list);
 	spin_unlock(&list_lock);
 	spin_unlock(&list_lock);
+	bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
+	printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
 
 
-done:
-	return ret;
+	return SCSI_DH_OK;
 }
 }
 EXPORT_SYMBOL_GPL(scsi_register_device_handler);
 EXPORT_SYMBOL_GPL(scsi_register_device_handler);
 
 
-static int scsi_dh_notifier_remove(struct device *dev, void *data)
-{
-	struct scsi_device_handler *scsi_dh = data;
-
-	scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_DEL_DEVICE, dev);
-	return 0;
-}
-
 /*
 /*
  * scsi_unregister_device_handler - register a device handler personality
  * scsi_unregister_device_handler - register a device handler personality
  *      module.
  *      module.
@@ -95,23 +385,26 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data)
  */
  */
 int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
 int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
 {
 {
-	int ret = -ENODEV;
-	struct scsi_device_handler *tmp;
-
-	tmp = get_device_handler(scsi_dh->name);
-	if (!tmp)
-		goto done;
+	struct scsi_dh_devinfo_list *tmp, *pos;
 
 
-	ret = bus_unregister_notifier(&scsi_bus_type, &scsi_dh->nb);
+	if (!get_device_handler(scsi_dh->name))
+		return -ENODEV;
 
 
 	bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
 	bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
-					scsi_dh_notifier_remove);
+			 scsi_dh_notifier_remove);
+
 	spin_lock(&list_lock);
 	spin_lock(&list_lock);
 	list_del(&scsi_dh->list);
 	list_del(&scsi_dh->list);
+	list_for_each_entry_safe(pos, tmp, &scsi_dh_dev_list, node) {
+		if (pos->handler == scsi_dh) {
+			list_del(&pos->node);
+			kfree(pos);
+		}
+	}
 	spin_unlock(&list_lock);
 	spin_unlock(&list_lock);
+	printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
 
 
-done:
-	return ret;
+	return SCSI_DH_OK;
 }
 }
 EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
 EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
 
 
@@ -157,6 +450,97 @@ int scsi_dh_handler_exist(const char *name)
 }
 }
 EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
 EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
 
 
+/*
+ * scsi_dh_handler_attach - Attach device handler
+ * @sdev - sdev the handler should be attached to
+ * @name - name of the handler to attach
+ */
+int scsi_dh_attach(struct request_queue *q, const char *name)
+{
+	unsigned long flags;
+	struct scsi_device *sdev;
+	struct scsi_device_handler *scsi_dh;
+	int err = 0;
+
+	scsi_dh = get_device_handler(name);
+	if (!scsi_dh)
+		return -EINVAL;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	sdev = q->queuedata;
+	if (!sdev || !get_device(&sdev->sdev_gendev))
+		err = -ENODEV;
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	if (!err) {
+		err = scsi_dh_handler_attach(sdev, scsi_dh);
+
+		put_device(&sdev->sdev_gendev);
+	}
+	return err;
+}
+EXPORT_SYMBOL_GPL(scsi_dh_attach);
+
+/*
+ * scsi_dh_handler_detach - Detach device handler
+ * @sdev - sdev the handler should be detached from
+ *
+ * This function will detach the device handler only
+ * if the sdev is not part of the internal list, ie
+ * if it has been attached manually.
+ */
+void scsi_dh_detach(struct request_queue *q)
+{
+	unsigned long flags;
+	struct scsi_device *sdev;
+	struct scsi_device_handler *scsi_dh = NULL;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	sdev = q->queuedata;
+	if (!sdev || !get_device(&sdev->sdev_gendev))
+		sdev = NULL;
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	if (!sdev)
+		return;
+
+	if (sdev->scsi_dh_data) {
+		/* if sdev is not on internal list, detach */
+		scsi_dh = sdev->scsi_dh_data->scsi_dh;
+		if (!device_handler_match(scsi_dh, sdev))
+			scsi_dh_handler_detach(sdev, scsi_dh);
+	}
+	put_device(&sdev->sdev_gendev);
+}
+EXPORT_SYMBOL_GPL(scsi_dh_detach);
+
+static struct notifier_block scsi_dh_nb = {
+	.notifier_call = scsi_dh_notifier
+};
+
+static int __init scsi_dh_init(void)
+{
+	int r;
+
+	r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);
+
+	if (!r)
+		bus_for_each_dev(&scsi_bus_type, NULL, NULL,
+				 scsi_dh_sysfs_attr_add);
+
+	return r;
+}
+
+static void __exit scsi_dh_exit(void)
+{
+	bus_for_each_dev(&scsi_bus_type, NULL, NULL,
+			 scsi_dh_sysfs_attr_remove);
+	bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
+}
+
+module_init(scsi_dh_init);
+module_exit(scsi_dh_exit);
+
 MODULE_DESCRIPTION("SCSI device handler");
 MODULE_DESCRIPTION("SCSI device handler");
 MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
 MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 802 - 0
drivers/scsi/device_handler/scsi_dh_alua.c

@@ -0,0 +1,802 @@
+/*
+ * Generic SCSI-3 ALUA SCSI Device Handler
+ *
+ * Copyright (C) 2007, 2008 Hannes Reinecke, SUSE Linux Products GmbH.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_dh.h>
+
+#define ALUA_DH_NAME "alua"
+#define ALUA_DH_VER "1.2"
+
+#define TPGS_STATE_OPTIMIZED		0x0
+#define TPGS_STATE_NONOPTIMIZED		0x1
+#define TPGS_STATE_STANDBY		0x2
+#define TPGS_STATE_UNAVAILABLE		0x3
+#define TPGS_STATE_OFFLINE		0xe
+#define TPGS_STATE_TRANSITIONING	0xf
+
+#define TPGS_SUPPORT_NONE		0x00
+#define TPGS_SUPPORT_OPTIMIZED		0x01
+#define TPGS_SUPPORT_NONOPTIMIZED	0x02
+#define TPGS_SUPPORT_STANDBY		0x04
+#define TPGS_SUPPORT_UNAVAILABLE	0x08
+#define TPGS_SUPPORT_OFFLINE		0x40
+#define TPGS_SUPPORT_TRANSITION		0x80
+
+#define TPGS_MODE_UNINITIALIZED		 -1
+#define TPGS_MODE_NONE			0x0
+#define TPGS_MODE_IMPLICIT		0x1
+#define TPGS_MODE_EXPLICIT		0x2
+
+#define ALUA_INQUIRY_SIZE		36
+#define ALUA_FAILOVER_TIMEOUT		(60 * HZ)
+#define ALUA_FAILOVER_RETRIES		5
+
+struct alua_dh_data {
+	int			group_id;
+	int			rel_port;
+	int			tpgs;
+	int			state;
+	unsigned char		inq[ALUA_INQUIRY_SIZE];
+	unsigned char		*buff;
+	int			bufflen;
+	unsigned char		sense[SCSI_SENSE_BUFFERSIZE];
+	int			senselen;
+};
+
+#define ALUA_POLICY_SWITCH_CURRENT	0
+#define ALUA_POLICY_SWITCH_ALL		1
+
+static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev)
+{
+	struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
+	BUG_ON(scsi_dh_data == NULL);
+	return ((struct alua_dh_data *) scsi_dh_data->buf);
+}
+
+static int realloc_buffer(struct alua_dh_data *h, unsigned len)
+{
+	if (h->buff && h->buff != h->inq)
+		kfree(h->buff);
+
+	h->buff = kmalloc(len, GFP_NOIO);
+	if (!h->buff) {
+		h->buff = h->inq;
+		h->bufflen = ALUA_INQUIRY_SIZE;
+		return 1;
+	}
+	h->bufflen = len;
+	return 0;
+}
+
+static struct request *get_alua_req(struct scsi_device *sdev,
+				    void *buffer, unsigned buflen, int rw)
+{
+	struct request *rq;
+	struct request_queue *q = sdev->request_queue;
+
+	rq = blk_get_request(q, rw, GFP_NOIO);
+
+	if (!rq) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: blk_get_request failed\n", __func__);
+		return NULL;
+	}
+
+	if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
+		blk_put_request(rq);
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: blk_rq_map_kern failed\n", __func__);
+		return NULL;
+	}
+
+	rq->cmd_type = REQ_TYPE_BLOCK_PC;
+	rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
+	rq->retries = ALUA_FAILOVER_RETRIES;
+	rq->timeout = ALUA_FAILOVER_TIMEOUT;
+
+	return rq;
+}
+
+/*
+ * submit_std_inquiry - Issue a standard INQUIRY command
+ * @sdev: sdev the command should be send to
+ */
+static int submit_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	struct request *rq;
+	int err = SCSI_DH_RES_TEMP_UNAVAIL;
+
+	rq = get_alua_req(sdev, h->inq, ALUA_INQUIRY_SIZE, READ);
+	if (!rq)
+		goto done;
+
+	/* Prepare the command. */
+	rq->cmd[0] = INQUIRY;
+	rq->cmd[1] = 0;
+	rq->cmd[2] = 0;
+	rq->cmd[4] = ALUA_INQUIRY_SIZE;
+	rq->cmd_len = COMMAND_SIZE(INQUIRY);
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = h->senselen = 0;
+
+	err = blk_execute_rq(rq->q, NULL, rq, 1);
+	if (err == -EIO) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: std inquiry failed with %x\n",
+			    ALUA_DH_NAME, rq->errors);
+		h->senselen = rq->sense_len;
+		err = SCSI_DH_IO;
+	}
+	blk_put_request(rq);
+done:
+	return err;
+}
+
+/*
+ * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command
+ * @sdev: sdev the command should be sent to
+ */
+static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	struct request *rq;
+	int err = SCSI_DH_RES_TEMP_UNAVAIL;
+
+	rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
+	if (!rq)
+		goto done;
+
+	/* Prepare the command. */
+	rq->cmd[0] = INQUIRY;
+	rq->cmd[1] = 1;
+	rq->cmd[2] = 0x83;
+	rq->cmd[4] = h->bufflen;
+	rq->cmd_len = COMMAND_SIZE(INQUIRY);
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = h->senselen = 0;
+
+	err = blk_execute_rq(rq->q, NULL, rq, 1);
+	if (err == -EIO) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: evpd inquiry failed with %x\n",
+			    ALUA_DH_NAME, rq->errors);
+		h->senselen = rq->sense_len;
+		err = SCSI_DH_IO;
+	}
+	blk_put_request(rq);
+done:
+	return err;
+}
+
+/*
+ * submit_rtpg - Issue a REPORT TARGET GROUP STATES command
+ * @sdev: sdev the command should be sent to
+ */
+static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	struct request *rq;
+	int err = SCSI_DH_RES_TEMP_UNAVAIL;
+
+	rq = get_alua_req(sdev, h->buff, h->bufflen, READ);
+	if (!rq)
+		goto done;
+
+	/* Prepare the command. */
+	rq->cmd[0] = MAINTENANCE_IN;
+	rq->cmd[1] = MI_REPORT_TARGET_PGS;
+	rq->cmd[6] = (h->bufflen >> 24) & 0xff;
+	rq->cmd[7] = (h->bufflen >> 16) & 0xff;
+	rq->cmd[8] = (h->bufflen >>  8) & 0xff;
+	rq->cmd[9] = h->bufflen & 0xff;
+	rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN);
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = h->senselen = 0;
+
+	err = blk_execute_rq(rq->q, NULL, rq, 1);
+	if (err == -EIO) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: rtpg failed with %x\n",
+			    ALUA_DH_NAME, rq->errors);
+		h->senselen = rq->sense_len;
+		err = SCSI_DH_IO;
+	}
+	blk_put_request(rq);
+done:
+	return err;
+}
+
+/*
+ * submit_stpg - Issue a SET TARGET GROUP STATES command
+ * @sdev: sdev the command should be sent to
+ *
+ * Currently we're only setting the current target port group state
+ * to 'active/optimized' and let the array firmware figure out
+ * the states of the remaining groups.
+ */
+static unsigned submit_stpg(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	struct request *rq;
+	int err = SCSI_DH_RES_TEMP_UNAVAIL;
+	int stpg_len = 8;
+
+	/* Prepare the data buffer */
+	memset(h->buff, 0, stpg_len);
+	h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f;
+	h->buff[6] = (h->group_id >> 8) & 0x0f;
+	h->buff[7] = h->group_id & 0x0f;
+
+	rq = get_alua_req(sdev, h->buff, stpg_len, WRITE);
+	if (!rq)
+		goto done;
+
+	/* Prepare the command. */
+	rq->cmd[0] = MAINTENANCE_OUT;
+	rq->cmd[1] = MO_SET_TARGET_PGS;
+	rq->cmd[6] = (stpg_len >> 24) & 0xff;
+	rq->cmd[7] = (stpg_len >> 16) & 0xff;
+	rq->cmd[8] = (stpg_len >>  8) & 0xff;
+	rq->cmd[9] = stpg_len & 0xff;
+	rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT);
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = h->senselen = 0;
+
+	err = blk_execute_rq(rq->q, NULL, rq, 1);
+	if (err == -EIO) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: stpg failed with %x\n",
+			    ALUA_DH_NAME, rq->errors);
+		h->senselen = rq->sense_len;
+		err = SCSI_DH_IO;
+	}
+	blk_put_request(rq);
+done:
+	return err;
+}
+
+/*
+ * alua_std_inquiry - Evaluate standard INQUIRY command
+ * @sdev: device to be checked
+ *
+ * Just extract the TPGS setting to find out if ALUA
+ * is supported.
+ */
+static int alua_std_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	int err;
+
+	err = submit_std_inquiry(sdev, h);
+
+	if (err != SCSI_DH_OK)
+		return err;
+
+	/* Check TPGS setting */
+	h->tpgs = (h->inq[5] >> 4) & 0x3;
+	switch (h->tpgs) {
+	case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT:
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: supports implicit and explicit TPGS\n",
+			    ALUA_DH_NAME);
+		break;
+	case TPGS_MODE_EXPLICIT:
+		sdev_printk(KERN_INFO, sdev, "%s: supports explicit TPGS\n",
+			    ALUA_DH_NAME);
+		break;
+	case TPGS_MODE_IMPLICIT:
+		sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n",
+			    ALUA_DH_NAME);
+		break;
+	default:
+		h->tpgs = TPGS_MODE_NONE;
+		sdev_printk(KERN_INFO, sdev, "%s: not supported\n",
+			    ALUA_DH_NAME);
+		err = SCSI_DH_DEV_UNSUPP;
+		break;
+	}
+
+	return err;
+}
+
+/*
+ * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83
+ * @sdev: device to be checked
+ *
+ * Extract the relative target port and the target port group
+ * descriptor from the list of identificators.
+ */
+static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	int len;
+	unsigned err;
+	unsigned char *d;
+
+ retry:
+	err = submit_vpd_inquiry(sdev, h);
+
+	if (err != SCSI_DH_OK)
+		return err;
+
+	/* Check if vpd page exceeds initial buffer */
+	len = (h->buff[2] << 8) + h->buff[3] + 4;
+	if (len > h->bufflen) {
+		/* Resubmit with the correct length */
+		if (realloc_buffer(h, len)) {
+			sdev_printk(KERN_WARNING, sdev,
+				    "%s: kmalloc buffer failed\n",
+				    ALUA_DH_NAME);
+			/* Temporary failure, bypass */
+			return SCSI_DH_DEV_TEMP_BUSY;
+		}
+		goto retry;
+	}
+
+	/*
+	 * Now look for the correct descriptor.
+	 */
+	d = h->buff + 4;
+	while (d < h->buff + len) {
+		switch (d[1] & 0xf) {
+		case 0x4:
+			/* Relative target port */
+			h->rel_port = (d[6] << 8) + d[7];
+			break;
+		case 0x5:
+			/* Target port group */
+			h->group_id = (d[6] << 8) + d[7];
+			break;
+		default:
+			break;
+		}
+		d += d[3] + 4;
+	}
+
+	if (h->group_id == -1) {
+		/*
+		 * Internal error; TPGS supported but required
+		 * VPD identification descriptors not present.
+		 * Disable ALUA support
+		 */
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: No target port descriptors found\n",
+			    ALUA_DH_NAME);
+		h->state = TPGS_STATE_OPTIMIZED;
+		h->tpgs = TPGS_MODE_NONE;
+		err = SCSI_DH_DEV_UNSUPP;
+	} else {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: port group %02x rel port %02x\n",
+			    ALUA_DH_NAME, h->group_id, h->rel_port);
+	}
+
+	return err;
+}
+
+static char print_alua_state(int state)
+{
+	switch (state) {
+	case TPGS_STATE_OPTIMIZED:
+		return 'A';
+	case TPGS_STATE_NONOPTIMIZED:
+		return 'N';
+	case TPGS_STATE_STANDBY:
+		return 'S';
+	case TPGS_STATE_UNAVAILABLE:
+		return 'U';
+	case TPGS_STATE_OFFLINE:
+		return 'O';
+	case TPGS_STATE_TRANSITIONING:
+		return 'T';
+	default:
+		return 'X';
+	}
+}
+
+static int alua_check_sense(struct scsi_device *sdev,
+			    struct scsi_sense_hdr *sense_hdr)
+{
+	switch (sense_hdr->sense_key) {
+	case NOT_READY:
+		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a)
+			/*
+			 * LUN Not Accessible - ALUA state transition
+			 */
+			return NEEDS_RETRY;
+		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b)
+			/*
+			 * LUN Not Accessible -- Target port in standby state
+			 */
+			return SUCCESS;
+		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c)
+			/*
+			 * LUN Not Accessible -- Target port in unavailable state
+			 */
+			return SUCCESS;
+		if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12)
+			/*
+			 * LUN Not Ready -- Offline
+			 */
+			return SUCCESS;
+		break;
+	case UNIT_ATTENTION:
+		if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
+			/*
+			 * Power On, Reset, or Bus Device Reset, just retry.
+			 */
+			return NEEDS_RETRY;
+		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) {
+			/*
+			 * ALUA state changed
+			 */
+			return NEEDS_RETRY;
+		}
+		if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) {
+			/*
+			 * Implicit ALUA state transition failed
+			 */
+			return NEEDS_RETRY;
+		}
+		break;
+	}
+
+	return SCSI_RETURN_NOT_HANDLED;
+}
+
+/*
+ * alua_stpg - Evaluate SET TARGET GROUP STATES
+ * @sdev: the device to be evaluated
+ * @state: the new target group state
+ *
+ * Send a SET TARGET GROUP STATES command to the device.
+ * We only have to test here if we should resubmit the command;
+ * any other error is assumed as a failure.
+ */
+static int alua_stpg(struct scsi_device *sdev, int state,
+		     struct alua_dh_data *h)
+{
+	struct scsi_sense_hdr sense_hdr;
+	unsigned err;
+	int retry = ALUA_FAILOVER_RETRIES;
+
+ retry:
+	err = submit_stpg(sdev, h);
+	if (err == SCSI_DH_IO && h->senselen > 0) {
+		err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+					   &sense_hdr);
+		if (!err)
+			return SCSI_DH_IO;
+		err = alua_check_sense(sdev, &sense_hdr);
+		if (retry > 0 && err == NEEDS_RETRY) {
+			retry--;
+			goto retry;
+		}
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: stpg sense code: %02x/%02x/%02x\n",
+			    ALUA_DH_NAME, sense_hdr.sense_key,
+			    sense_hdr.asc, sense_hdr.ascq);
+		err = SCSI_DH_IO;
+	}
+	if (err == SCSI_DH_OK) {
+		h->state = state;
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: port group %02x switched to state %c\n",
+			    ALUA_DH_NAME, h->group_id,
+			    print_alua_state(h->state) );
+	}
+	return err;
+}
+
+/*
+ * alua_rtpg - Evaluate REPORT TARGET GROUP STATES
+ * @sdev: the device to be evaluated.
+ *
+ * Evaluate the Target Port Group State.
+ * Returns SCSI_DH_DEV_OFFLINED if the path is
+ * found to be unuseable.
+ */
+static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	struct scsi_sense_hdr sense_hdr;
+	int len, k, off, valid_states = 0;
+	char *ucp;
+	unsigned err;
+
+ retry:
+	err = submit_rtpg(sdev, h);
+
+	if (err == SCSI_DH_IO && h->senselen > 0) {
+		err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
+					   &sense_hdr);
+		if (!err)
+			return SCSI_DH_IO;
+
+		err = alua_check_sense(sdev, &sense_hdr);
+		if (err == NEEDS_RETRY)
+			goto retry;
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: rtpg sense code %02x/%02x/%02x\n",
+			    ALUA_DH_NAME, sense_hdr.sense_key,
+			    sense_hdr.asc, sense_hdr.ascq);
+		err = SCSI_DH_IO;
+	}
+	if (err != SCSI_DH_OK)
+		return err;
+
+	len = (h->buff[0] << 24) + (h->buff[1] << 16) +
+		(h->buff[2] << 8) + h->buff[3] + 4;
+
+	if (len > h->bufflen) {
+		/* Resubmit with the correct length */
+		if (realloc_buffer(h, len)) {
+			sdev_printk(KERN_WARNING, sdev,
+				    "%s: kmalloc buffer failed\n",__func__);
+			/* Temporary failure, bypass */
+			return SCSI_DH_DEV_TEMP_BUSY;
+		}
+		goto retry;
+	}
+
+	for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) {
+		if (h->group_id == (ucp[2] << 8) + ucp[3]) {
+			h->state = ucp[0] & 0x0f;
+			valid_states = ucp[1];
+		}
+		off = 8 + (ucp[7] * 4);
+	}
+
+	sdev_printk(KERN_INFO, sdev,
+		    "%s: port group %02x state %c supports %c%c%c%c%c%c\n",
+		    ALUA_DH_NAME, h->group_id, print_alua_state(h->state),
+		    valid_states&TPGS_SUPPORT_TRANSITION?'T':'t',
+		    valid_states&TPGS_SUPPORT_OFFLINE?'O':'o',
+		    valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u',
+		    valid_states&TPGS_SUPPORT_STANDBY?'S':'s',
+		    valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n',
+		    valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a');
+
+	if (h->tpgs & TPGS_MODE_EXPLICIT) {
+		switch (h->state) {
+		case TPGS_STATE_TRANSITIONING:
+			/* State transition, retry */
+			goto retry;
+			break;
+		case TPGS_STATE_OFFLINE:
+			/* Path is offline, fail */
+			err = SCSI_DH_DEV_OFFLINED;
+			break;
+		default:
+			break;
+		}
+	} else {
+		/* Only Implicit ALUA support */
+		if (h->state == TPGS_STATE_OPTIMIZED ||
+		    h->state == TPGS_STATE_NONOPTIMIZED ||
+		    h->state == TPGS_STATE_STANDBY)
+			/* Useable path if active */
+			err = SCSI_DH_OK;
+		else
+			/* Path unuseable for unavailable/offline */
+			err = SCSI_DH_DEV_OFFLINED;
+	}
+	return err;
+}
+
+/*
+ * alua_initialize - Initialize ALUA state
+ * @sdev: the device to be initialized
+ *
+ * For the prep_fn to work correctly we have
+ * to initialize the ALUA state for the device.
+ */
+static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h)
+{
+	int err;
+
+	err = alua_std_inquiry(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto out;
+
+	err = alua_vpd_inquiry(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto out;
+
+	err = alua_rtpg(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto out;
+
+out:
+	return err;
+}
+
+/*
+ * alua_activate - activate a path
+ * @sdev: device on the path to be activated
+ *
+ * We're currently switching the port group to be activated only and
+ * let the array figure out the rest.
+ * There may be other arrays which require us to switch all port groups
+ * based on a certain policy. But until we actually encounter them it
+ * should be okay.
+ */
+static int alua_activate(struct scsi_device *sdev)
+{
+	struct alua_dh_data *h = get_alua_data(sdev);
+	int err = SCSI_DH_OK;
+
+	if (h->group_id != -1) {
+		err = alua_rtpg(sdev, h);
+		if (err != SCSI_DH_OK)
+			goto out;
+	}
+
+	if (h->tpgs == TPGS_MODE_EXPLICIT && h->state != TPGS_STATE_OPTIMIZED)
+		err = alua_stpg(sdev, TPGS_STATE_OPTIMIZED, h);
+
+out:
+	return err;
+}
+
+/*
+ * alua_prep_fn - request callback
+ *
+ * Fail I/O to all paths not in state
+ * active/optimized or active/non-optimized.
+ */
+static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
+{
+	struct alua_dh_data *h = get_alua_data(sdev);
+	int ret = BLKPREP_OK;
+
+	if (h->state != TPGS_STATE_OPTIMIZED &&
+	    h->state != TPGS_STATE_NONOPTIMIZED) {
+		ret = BLKPREP_KILL;
+		req->cmd_flags |= REQ_QUIET;
+	}
+	return ret;
+
+}
+
+const struct scsi_dh_devlist alua_dev_list[] = {
+	{"HP", "MSA VOLUME" },
+	{"HP", "HSV101" },
+	{"HP", "HSV111" },
+	{"HP", "HSV200" },
+	{"HP", "HSV210" },
+	{"HP", "HSV300" },
+	{"IBM", "2107900" },
+	{"IBM", "2145" },
+	{"Pillar", "Axiom" },
+	{NULL, NULL}
+};
+
+static int alua_bus_attach(struct scsi_device *sdev);
+static void alua_bus_detach(struct scsi_device *sdev);
+
+static struct scsi_device_handler alua_dh = {
+	.name = ALUA_DH_NAME,
+	.module = THIS_MODULE,
+	.devlist = alua_dev_list,
+	.attach = alua_bus_attach,
+	.detach = alua_bus_detach,
+	.prep_fn = alua_prep_fn,
+	.check_sense = alua_check_sense,
+	.activate = alua_activate,
+};
+
+/*
+ * alua_bus_attach - Attach device handler
+ * @sdev: device to be attached to
+ */
+static int alua_bus_attach(struct scsi_device *sdev)
+{
+	struct scsi_dh_data *scsi_dh_data;
+	struct alua_dh_data *h;
+	unsigned long flags;
+	int err = SCSI_DH_OK;
+
+	scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+			       + sizeof(*h) , GFP_KERNEL);
+	if (!scsi_dh_data) {
+		sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
+			    ALUA_DH_NAME);
+		return -ENOMEM;
+	}
+
+	scsi_dh_data->scsi_dh = &alua_dh;
+	h = (struct alua_dh_data *) scsi_dh_data->buf;
+	h->tpgs = TPGS_MODE_UNINITIALIZED;
+	h->state = TPGS_STATE_OPTIMIZED;
+	h->group_id = -1;
+	h->rel_port = -1;
+	h->buff = h->inq;
+	h->bufflen = ALUA_INQUIRY_SIZE;
+
+	err = alua_initialize(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto failed;
+
+	if (!try_module_get(THIS_MODULE))
+		goto failed;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	sdev->scsi_dh_data = scsi_dh_data;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+	return 0;
+
+failed:
+	kfree(scsi_dh_data);
+	sdev_printk(KERN_ERR, sdev, "%s: not attached\n", ALUA_DH_NAME);
+	return -EINVAL;
+}
+
+/*
+ * alua_bus_detach - Detach device handler
+ * @sdev: device to be detached from
+ */
+static void alua_bus_detach(struct scsi_device *sdev)
+{
+	struct scsi_dh_data *scsi_dh_data;
+	struct alua_dh_data *h;
+	unsigned long flags;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	scsi_dh_data = sdev->scsi_dh_data;
+	sdev->scsi_dh_data = NULL;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+	h = (struct alua_dh_data *) scsi_dh_data->buf;
+	if (h->buff && h->inq != h->buff)
+		kfree(h->buff);
+	kfree(scsi_dh_data);
+	module_put(THIS_MODULE);
+	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", ALUA_DH_NAME);
+}
+
+static int __init alua_init(void)
+{
+	int r;
+
+	r = scsi_register_device_handler(&alua_dh);
+	if (r != 0)
+		printk(KERN_ERR "%s: Failed to register scsi device handler",
+			ALUA_DH_NAME);
+	return r;
+}
+
+static void __exit alua_exit(void)
+{
+	scsi_unregister_device_handler(&alua_dh);
+}
+
+module_init(alua_init);
+module_exit(alua_exit);
+
+MODULE_DESCRIPTION("DM Multipath ALUA support");
+MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ALUA_DH_VER);

+ 409 - 235
drivers/scsi/device_handler/scsi_dh_emc.c

@@ -25,28 +25,31 @@
 #include <scsi/scsi_dh.h>
 #include <scsi/scsi_dh.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_device.h>
 
 
-#define CLARIION_NAME			"emc_clariion"
+#define CLARIION_NAME			"emc"
 
 
 #define CLARIION_TRESPASS_PAGE		0x22
 #define CLARIION_TRESPASS_PAGE		0x22
-#define CLARIION_BUFFER_SIZE		0x80
+#define CLARIION_BUFFER_SIZE		0xFC
 #define CLARIION_TIMEOUT		(60 * HZ)
 #define CLARIION_TIMEOUT		(60 * HZ)
 #define CLARIION_RETRIES		3
 #define CLARIION_RETRIES		3
 #define CLARIION_UNBOUND_LU		-1
 #define CLARIION_UNBOUND_LU		-1
+#define CLARIION_SP_A			0
+#define CLARIION_SP_B			1
 
 
-static unsigned char long_trespass[] = {
-	0, 0, 0, 0,
-	CLARIION_TRESPASS_PAGE,	/* Page code */
-	0x09,			/* Page length - 2 */
-	0x81,			/* Trespass code + Honor reservation bit */
-	0xff, 0xff,		/* Trespass target */
-	0, 0, 0, 0, 0, 0	/* Reserved bytes / unknown */
-};
+/* Flags */
+#define CLARIION_SHORT_TRESPASS		1
+#define CLARIION_HONOR_RESERVATIONS	2
 
 
-static unsigned char long_trespass_hr[] = {
-	0, 0, 0, 0,
+/* LUN states */
+#define CLARIION_LUN_UNINITIALIZED	-1
+#define CLARIION_LUN_UNBOUND		0
+#define CLARIION_LUN_BOUND		1
+#define CLARIION_LUN_OWNED		2
+
+static unsigned char long_trespass[] = {
+	0, 0, 0, 0, 0, 0, 0, 0,
 	CLARIION_TRESPASS_PAGE,	/* Page code */
 	CLARIION_TRESPASS_PAGE,	/* Page code */
 	0x09,			/* Page length - 2 */
 	0x09,			/* Page length - 2 */
-	0x01,			/* Trespass code + Honor reservation bit */
+	0x01,			/* Trespass code */
 	0xff, 0xff,		/* Trespass target */
 	0xff, 0xff,		/* Trespass target */
 	0, 0, 0, 0, 0, 0	/* Reserved bytes / unknown */
 	0, 0, 0, 0, 0, 0	/* Reserved bytes / unknown */
 };
 };
@@ -55,39 +58,56 @@ static unsigned char short_trespass[] = {
 	0, 0, 0, 0,
 	0, 0, 0, 0,
 	CLARIION_TRESPASS_PAGE,	/* Page code */
 	CLARIION_TRESPASS_PAGE,	/* Page code */
 	0x02,			/* Page length - 2 */
 	0x02,			/* Page length - 2 */
-	0x81,			/* Trespass code + Honor reservation bit */
+	0x01,			/* Trespass code */
 	0xff,			/* Trespass target */
 	0xff,			/* Trespass target */
 };
 };
 
 
-static unsigned char short_trespass_hr[] = {
-	0, 0, 0, 0,
-	CLARIION_TRESPASS_PAGE,	/* Page code */
-	0x02,			/* Page length - 2 */
-	0x01,			/* Trespass code + Honor reservation bit */
-	0xff,			/* Trespass target */
+static const char * lun_state[] =
+{
+    "not bound",
+    "bound",
+    "owned",
 };
 };
 
 
 struct clariion_dh_data {
 struct clariion_dh_data {
 	/*
 	/*
+	 * Flags:
+	 *  CLARIION_SHORT_TRESPASS
 	 * Use short trespass command (FC-series) or the long version
 	 * Use short trespass command (FC-series) or the long version
 	 * (default for AX/CX CLARiiON arrays).
 	 * (default for AX/CX CLARiiON arrays).
-	 */
-	unsigned short_trespass;
-	/*
+	 *
+	 *  CLARIION_HONOR_RESERVATIONS
 	 * Whether or not (default) to honor SCSI reservations when
 	 * Whether or not (default) to honor SCSI reservations when
 	 * initiating a switch-over.
 	 * initiating a switch-over.
 	 */
 	 */
-	unsigned hr;
-	/* I/O buffer for both MODE_SELECT and INQUIRY commands. */
+	unsigned flags;
+	/*
+	 * I/O buffer for both MODE_SELECT and INQUIRY commands.
+	 */
 	char buffer[CLARIION_BUFFER_SIZE];
 	char buffer[CLARIION_BUFFER_SIZE];
 	/*
 	/*
 	 * SCSI sense buffer for commands -- assumes serial issuance
 	 * SCSI sense buffer for commands -- assumes serial issuance
 	 * and completion sequence of all commands for same multipath.
 	 * and completion sequence of all commands for same multipath.
 	 */
 	 */
 	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
 	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
-	/* which SP (A=0,B=1,UNBOUND=-1) is dflt SP for path's mapped dev */
+	unsigned int senselen;
+	/*
+	 * LUN state
+	 */
+	int lun_state;
+	/*
+	 * SP Port number
+	 */
+	int port;
+	/*
+	 * which SP (A=0,B=1,UNBOUND=-1) is the default SP for this
+	 * path's mapped LUN
+	 */
 	int default_sp;
 	int default_sp;
-	/* which SP (A=0,B=1,UNBOUND=-1) is active for path's mapped dev */
+	/*
+	 * which SP (A=0,B=1,UNBOUND=-1) is the active SP for this
+	 * path's mapped LUN
+	 */
 	int current_sp;
 	int current_sp;
 };
 };
 
 
@@ -102,19 +122,16 @@ static inline struct clariion_dh_data
 /*
 /*
  * Parse MODE_SELECT cmd reply.
  * Parse MODE_SELECT cmd reply.
  */
  */
-static int trespass_endio(struct scsi_device *sdev, int result)
+static int trespass_endio(struct scsi_device *sdev, char *sense)
 {
 {
-	int err = SCSI_DH_OK;
+	int err = SCSI_DH_IO;
 	struct scsi_sense_hdr sshdr;
 	struct scsi_sense_hdr sshdr;
-	struct clariion_dh_data *csdev = get_clariion_data(sdev);
-	char *sense = csdev->sense;
 
 
-	if (status_byte(result) == CHECK_CONDITION &&
-	    scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
-		sdev_printk(KERN_ERR, sdev, "Found valid sense data 0x%2x, "
+	if (!scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) {
+		sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, "
 			    "0x%2x, 0x%2x while sending CLARiiON trespass "
 			    "0x%2x, 0x%2x while sending CLARiiON trespass "
-			    "command.\n", sshdr.sense_key, sshdr.asc,
-			     sshdr.ascq);
+			    "command.\n", CLARIION_NAME, sshdr.sense_key,
+			    sshdr.asc, sshdr.ascq);
 
 
 		if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) &&
 		if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) &&
 		     (sshdr.ascq == 0x00)) {
 		     (sshdr.ascq == 0x00)) {
@@ -122,9 +139,9 @@ static int trespass_endio(struct scsi_device *sdev, int result)
 			 * Array based copy in progress -- do not send
 			 * Array based copy in progress -- do not send
 			 * mode_select or copy will be aborted mid-stream.
 			 * mode_select or copy will be aborted mid-stream.
 			 */
 			 */
-			sdev_printk(KERN_INFO, sdev, "Array Based Copy in "
+			sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in "
 				    "progress while sending CLARiiON trespass "
 				    "progress while sending CLARiiON trespass "
-				    "command.\n");
+				    "command.\n", CLARIION_NAME);
 			err = SCSI_DH_DEV_TEMP_BUSY;
 			err = SCSI_DH_DEV_TEMP_BUSY;
 		} else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) &&
 		} else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) &&
 			    (sshdr.ascq == 0x03)) {
 			    (sshdr.ascq == 0x03)) {
@@ -132,160 +149,153 @@ static int trespass_endio(struct scsi_device *sdev, int result)
 			 * LUN Not Ready - Manual Intervention Required
 			 * LUN Not Ready - Manual Intervention Required
 			 * indicates in-progress ucode upgrade (NDU).
 			 * indicates in-progress ucode upgrade (NDU).
 			 */
 			 */
-			sdev_printk(KERN_INFO, sdev, "Detected in-progress "
+			sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress "
 				    "ucode upgrade NDU operation while sending "
 				    "ucode upgrade NDU operation while sending "
-				    "CLARiiON trespass command.\n");
+				    "CLARiiON trespass command.\n", CLARIION_NAME);
 			err = SCSI_DH_DEV_TEMP_BUSY;
 			err = SCSI_DH_DEV_TEMP_BUSY;
 		} else
 		} else
 			err = SCSI_DH_DEV_FAILED;
 			err = SCSI_DH_DEV_FAILED;
-	} else if (result) {
-		sdev_printk(KERN_ERR, sdev, "Error 0x%x while sending "
-			    "CLARiiON trespass command.\n", result);
-		err = SCSI_DH_IO;
+	} else {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: failed to send MODE SELECT, no sense available\n",
+			    CLARIION_NAME);
 	}
 	}
-
 	return err;
 	return err;
 }
 }
 
 
-static int parse_sp_info_reply(struct scsi_device *sdev, int result,
-		int *default_sp, int *current_sp, int *new_current_sp)
+static int parse_sp_info_reply(struct scsi_device *sdev,
+			       struct clariion_dh_data *csdev)
 {
 {
 	int err = SCSI_DH_OK;
 	int err = SCSI_DH_OK;
-	struct clariion_dh_data *csdev = get_clariion_data(sdev);
 
 
-	if (result == 0) {
-		/* check for in-progress ucode upgrade (NDU) */
-		if (csdev->buffer[48] != 0) {
-			sdev_printk(KERN_NOTICE, sdev, "Detected in-progress "
-			       "ucode upgrade NDU operation while finding "
-			       "current active SP.");
-			err = SCSI_DH_DEV_TEMP_BUSY;
-		} else {
-			*default_sp = csdev->buffer[5];
-
-			if (csdev->buffer[4] == 2)
-				/* SP for path is current */
-				*current_sp = csdev->buffer[8];
-			else {
-				if (csdev->buffer[4] == 1)
-					/* SP for this path is NOT current */
-					if (csdev->buffer[8] == 0)
-						*current_sp = 1;
-					else
-						*current_sp = 0;
-				else
-					/* unbound LU or LUNZ */
-					*current_sp = CLARIION_UNBOUND_LU;
-			}
-			*new_current_sp =  csdev->buffer[8];
-		}
-	} else {
-		struct scsi_sense_hdr sshdr;
-
-		err = SCSI_DH_IO;
-
-		if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
-							   &sshdr))
-			sdev_printk(KERN_ERR, sdev, "Found valid sense data "
-			      "0x%2x, 0x%2x, 0x%2x while finding current "
-			      "active SP.", sshdr.sense_key, sshdr.asc,
-			      sshdr.ascq);
-		else
-			sdev_printk(KERN_ERR, sdev, "Error 0x%x finding "
-			      "current active SP.", result);
+	/* check for in-progress ucode upgrade (NDU) */
+	if (csdev->buffer[48] != 0) {
+		sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress "
+			    "ucode upgrade NDU operation while finding "
+			    "current active SP.", CLARIION_NAME);
+		err = SCSI_DH_DEV_TEMP_BUSY;
+		goto out;
+	}
+	if (csdev->buffer[4] < 0 || csdev->buffer[4] > 2) {
+		/* Invalid buffer format */
+		sdev_printk(KERN_NOTICE, sdev,
+			    "%s: invalid VPD page 0xC0 format\n",
+			    CLARIION_NAME);
+		err = SCSI_DH_NOSYS;
+		goto out;
+	}
+	switch (csdev->buffer[28] & 0x0f) {
+	case 6:
+		sdev_printk(KERN_NOTICE, sdev,
+			    "%s: ALUA failover mode detected\n",
+			    CLARIION_NAME);
+		break;
+	case 4:
+		/* Linux failover */
+		break;
+	default:
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: Invalid failover mode %d\n",
+			    CLARIION_NAME, csdev->buffer[28] & 0x0f);
+		err = SCSI_DH_NOSYS;
+		goto out;
 	}
 	}
 
 
+	csdev->default_sp = csdev->buffer[5];
+	csdev->lun_state = csdev->buffer[4];
+	csdev->current_sp = csdev->buffer[8];
+	csdev->port = csdev->buffer[7];
+
+out:
 	return err;
 	return err;
 }
 }
 
 
-static int sp_info_endio(struct scsi_device *sdev, int result,
-					int mode_select_sent, int *done)
+#define emc_default_str "FC (Legacy)"
+
+static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer)
 {
 {
-	struct clariion_dh_data *csdev = get_clariion_data(sdev);
-	int err_flags, default_sp, current_sp, new_current_sp;
+	unsigned char len = buffer[4] + 5;
+	char *sp_model = NULL;
+	unsigned char sp_len, serial_len;
+
+	if (len < 160) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: Invalid information section length %d\n",
+			    CLARIION_NAME, len);
+		/* Check for old FC arrays */
+		if (!strncmp(buffer + 8, "DGC", 3)) {
+			/* Old FC array, not supporting extended information */
+			sp_model = emc_default_str;
+		}
+		goto out;
+	}
 
 
-	err_flags = parse_sp_info_reply(sdev, result, &default_sp,
-					     &current_sp, &new_current_sp);
+	/*
+	 * Parse extended information for SP model number
+	 */
+	serial_len = buffer[160];
+	if (serial_len == 0 || serial_len + 161 > len) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: Invalid array serial number length %d\n",
+			    CLARIION_NAME, serial_len);
+		goto out;
+	}
+	sp_len = buffer[99];
+	if (sp_len == 0 || serial_len + sp_len + 161 > len) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: Invalid model number length %d\n",
+			    CLARIION_NAME, sp_len);
+		goto out;
+	}
+	sp_model = &buffer[serial_len + 161];
+	/* Strip whitespace at the end */
+	while (sp_len > 1 && sp_model[sp_len - 1] == ' ')
+		sp_len--;
 
 
-	if (err_flags != SCSI_DH_OK)
-		goto done;
+	sp_model[sp_len] = '\0';
 
 
-	if (mode_select_sent) {
-		csdev->default_sp = default_sp;
-		csdev->current_sp = current_sp;
-	} else {
-		/*
-		 * Issue the actual module_selec request IFF either
-		 * (1) we do not know the identity of the current SP OR
-		 * (2) what we think we know is actually correct.
-		 */
-		if ((current_sp != CLARIION_UNBOUND_LU) &&
-		    (new_current_sp != current_sp)) {
-
-			csdev->default_sp = default_sp;
-			csdev->current_sp = current_sp;
-
-			sdev_printk(KERN_INFO, sdev, "Ignoring path group "
-			       "switch-over command for CLARiiON SP%s since "
-			       " mapped device is already initialized.",
-			       current_sp ? "B" : "A");
-			if (done)
-				*done = 1; /* as good as doing it */
-		}
-	}
-done:
-	return err_flags;
+out:
+	return sp_model;
 }
 }
 
 
 /*
 /*
-* Get block request for REQ_BLOCK_PC command issued to path.  Currently
-* limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
-*
-* Uses data and sense buffers in hardware handler context structure and
-* assumes serial servicing of commands, both issuance and completion.
-*/
-static struct request *get_req(struct scsi_device *sdev, int cmd)
+ * Get block request for REQ_BLOCK_PC command issued to path.  Currently
+ * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
+ *
+ * Uses data and sense buffers in hardware handler context structure and
+ * assumes serial servicing of commands, both issuance and completion.
+ */
+static struct request *get_req(struct scsi_device *sdev, int cmd,
+				unsigned char *buffer)
 {
 {
-	struct clariion_dh_data *csdev = get_clariion_data(sdev);
 	struct request *rq;
 	struct request *rq;
-	unsigned char *page22;
 	int len = 0;
 	int len = 0;
 
 
 	rq = blk_get_request(sdev->request_queue,
 	rq = blk_get_request(sdev->request_queue,
-			(cmd == MODE_SELECT) ? WRITE : READ, GFP_ATOMIC);
+			(cmd == MODE_SELECT) ? WRITE : READ, GFP_NOIO);
 	if (!rq) {
 	if (!rq) {
 		sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
 		sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	memset(&rq->cmd, 0, BLK_MAX_CDB);
+	memset(rq->cmd, 0, BLK_MAX_CDB);
+	rq->cmd_len = COMMAND_SIZE(cmd);
 	rq->cmd[0] = cmd;
 	rq->cmd[0] = cmd;
-	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case MODE_SELECT:
 	case MODE_SELECT:
-		if (csdev->short_trespass) {
-			page22 = csdev->hr ? short_trespass_hr : short_trespass;
-			len = sizeof(short_trespass);
-		} else {
-			page22 = csdev->hr ? long_trespass_hr : long_trespass;
-			len = sizeof(long_trespass);
-		}
-		/*
-		 * Can't DMA from kernel BSS -- must copy selected trespass
-		 * command mode page contents to context buffer which is
-		 * allocated by kmalloc.
-		 */
-		BUG_ON((len > CLARIION_BUFFER_SIZE));
-		memcpy(csdev->buffer, page22, len);
+		len = sizeof(short_trespass);
+		rq->cmd_flags |= REQ_RW;
+		rq->cmd[1] = 0x10;
+		break;
+	case MODE_SELECT_10:
+		len = sizeof(long_trespass);
 		rq->cmd_flags |= REQ_RW;
 		rq->cmd_flags |= REQ_RW;
 		rq->cmd[1] = 0x10;
 		rq->cmd[1] = 0x10;
 		break;
 		break;
 	case INQUIRY:
 	case INQUIRY:
-		rq->cmd[1] = 0x1;
-		rq->cmd[2] = 0xC0;
 		len = CLARIION_BUFFER_SIZE;
 		len = CLARIION_BUFFER_SIZE;
-		memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE);
+		memset(buffer, 0, len);
 		break;
 		break;
 	default:
 	default:
 		BUG_ON(1);
 		BUG_ON(1);
@@ -298,47 +308,94 @@ static struct request *get_req(struct scsi_device *sdev, int cmd)
 	rq->timeout = CLARIION_TIMEOUT;
 	rq->timeout = CLARIION_TIMEOUT;
 	rq->retries = CLARIION_RETRIES;
 	rq->retries = CLARIION_RETRIES;
 
 
-	rq->sense = csdev->sense;
-	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-	rq->sense_len = 0;
-
-	if (blk_rq_map_kern(sdev->request_queue, rq, csdev->buffer,
-							len, GFP_ATOMIC)) {
-		__blk_put_request(rq->q, rq);
+	if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) {
+		blk_put_request(rq);
 		return NULL;
 		return NULL;
 	}
 	}
 
 
 	return rq;
 	return rq;
 }
 }
 
 
-static int send_cmd(struct scsi_device *sdev, int cmd)
+static int send_inquiry_cmd(struct scsi_device *sdev, int page,
+			    struct clariion_dh_data *csdev)
 {
 {
-	struct request *rq = get_req(sdev, cmd);
+	struct request *rq = get_req(sdev, INQUIRY, csdev->buffer);
+	int err;
 
 
 	if (!rq)
 	if (!rq)
 		return SCSI_DH_RES_TEMP_UNAVAIL;
 		return SCSI_DH_RES_TEMP_UNAVAIL;
 
 
-	return blk_execute_rq(sdev->request_queue, NULL, rq, 1);
+	rq->sense = csdev->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = csdev->senselen = 0;
+
+	rq->cmd[0] = INQUIRY;
+	if (page != 0) {
+		rq->cmd[1] = 1;
+		rq->cmd[2] = page;
+	}
+	err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
+	if (err == -EIO) {
+		sdev_printk(KERN_INFO, sdev,
+			    "%s: failed to send %s INQUIRY: %x\n",
+			    CLARIION_NAME, page?"EVPD":"standard",
+			    rq->errors);
+		csdev->senselen = rq->sense_len;
+		err = SCSI_DH_IO;
+	}
+
+	blk_put_request(rq);
+
+	return err;
 }
 }
 
 
-static int clariion_activate(struct scsi_device *sdev)
+static int send_trespass_cmd(struct scsi_device *sdev,
+			    struct clariion_dh_data *csdev)
 {
 {
-	int result, done = 0;
+	struct request *rq;
+	unsigned char *page22;
+	int err, len, cmd;
+
+	if (csdev->flags & CLARIION_SHORT_TRESPASS) {
+		page22 = short_trespass;
+		if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
+			/* Set Honor Reservations bit */
+			page22[6] |= 0x80;
+		len = sizeof(short_trespass);
+		cmd = MODE_SELECT;
+	} else {
+		page22 = long_trespass;
+		if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
+			/* Set Honor Reservations bit */
+			page22[10] |= 0x80;
+		len = sizeof(long_trespass);
+		cmd = MODE_SELECT_10;
+	}
+	BUG_ON((len > CLARIION_BUFFER_SIZE));
+	memcpy(csdev->buffer, page22, len);
 
 
-	result = send_cmd(sdev, INQUIRY);
-	result = sp_info_endio(sdev, result, 0, &done);
-	if (result || done)
-		goto done;
+	rq = get_req(sdev, cmd, csdev->buffer);
+	if (!rq)
+		return SCSI_DH_RES_TEMP_UNAVAIL;
 
 
-	result = send_cmd(sdev, MODE_SELECT);
-	result = trespass_endio(sdev, result);
-	if (result)
-		goto done;
+	rq->sense = csdev->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = csdev->senselen = 0;
 
 
-	result = send_cmd(sdev, INQUIRY);
-	result = sp_info_endio(sdev, result, 1, NULL);
-done:
-	return result;
+	err = blk_execute_rq(sdev->request_queue, NULL, rq, 1);
+	if (err == -EIO) {
+		if (rq->sense_len) {
+			err = trespass_endio(sdev, csdev->sense);
+		} else {
+			sdev_printk(KERN_INFO, sdev,
+				    "%s: failed to send MODE SELECT: %x\n",
+				    CLARIION_NAME, rq->errors);
+		}
+	}
+
+	blk_put_request(rq);
+
+	return err;
 }
 }
 
 
 static int clariion_check_sense(struct scsi_device *sdev,
 static int clariion_check_sense(struct scsi_device *sdev,
@@ -386,99 +443,215 @@ static int clariion_check_sense(struct scsi_device *sdev,
 		break;
 		break;
 	}
 	}
 
 
-	/* success just means we do not care what scsi-ml does */
-	return SUCCESS;
+	return SCSI_RETURN_NOT_HANDLED;
+}
+
+static int clariion_prep_fn(struct scsi_device *sdev, struct request *req)
+{
+	struct clariion_dh_data *h = get_clariion_data(sdev);
+	int ret = BLKPREP_OK;
+
+	if (h->lun_state != CLARIION_LUN_OWNED) {
+		ret = BLKPREP_KILL;
+		req->cmd_flags |= REQ_QUIET;
+	}
+	return ret;
+
+}
+
+static int clariion_std_inquiry(struct scsi_device *sdev,
+				struct clariion_dh_data *csdev)
+{
+	int err;
+	char *sp_model;
+
+	err = send_inquiry_cmd(sdev, 0, csdev);
+	if (err != SCSI_DH_OK && csdev->senselen) {
+		struct scsi_sense_hdr sshdr;
+
+		if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
+					 &sshdr)) {
+			sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
+				    "%02x/%02x/%02x\n", CLARIION_NAME,
+				    sshdr.sense_key, sshdr.asc, sshdr.ascq);
+		}
+		err = SCSI_DH_IO;
+		goto out;
+	}
+
+	sp_model = parse_sp_model(sdev, csdev->buffer);
+	if (!sp_model) {
+		err = SCSI_DH_DEV_UNSUPP;
+		goto out;
+	}
+
+	/*
+	 * FC Series arrays do not support long trespass
+	 */
+	if (!strlen(sp_model) || !strncmp(sp_model, "FC",2))
+		csdev->flags |= CLARIION_SHORT_TRESPASS;
+
+	sdev_printk(KERN_INFO, sdev,
+		    "%s: detected Clariion %s, flags %x\n",
+		    CLARIION_NAME, sp_model, csdev->flags);
+out:
+	return err;
 }
 }
 
 
-static const struct {
-	char *vendor;
-	char *model;
-} clariion_dev_list[] = {
+static int clariion_send_inquiry(struct scsi_device *sdev,
+				 struct clariion_dh_data *csdev)
+{
+	int err, retry = CLARIION_RETRIES;
+
+retry:
+	err = send_inquiry_cmd(sdev, 0xC0, csdev);
+	if (err != SCSI_DH_OK && csdev->senselen) {
+		struct scsi_sense_hdr sshdr;
+
+		err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE,
+					   &sshdr);
+		if (!err)
+			return SCSI_DH_IO;
+
+		err = clariion_check_sense(sdev, &sshdr);
+		if (retry > 0 && err == NEEDS_RETRY) {
+			retry--;
+			goto retry;
+		}
+		sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code "
+			    "%02x/%02x/%02x\n", CLARIION_NAME,
+			      sshdr.sense_key, sshdr.asc, sshdr.ascq);
+		err = SCSI_DH_IO;
+	} else {
+		err = parse_sp_info_reply(sdev, csdev);
+	}
+	return err;
+}
+
+static int clariion_activate(struct scsi_device *sdev)
+{
+	struct clariion_dh_data *csdev = get_clariion_data(sdev);
+	int result;
+
+	result = clariion_send_inquiry(sdev, csdev);
+	if (result != SCSI_DH_OK)
+		goto done;
+
+	if (csdev->lun_state == CLARIION_LUN_OWNED)
+		goto done;
+
+	result = send_trespass_cmd(sdev, csdev);
+	if (result != SCSI_DH_OK)
+		goto done;
+	sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n",
+		    CLARIION_NAME,
+		    csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" );
+
+	/* Update status */
+	result = clariion_send_inquiry(sdev, csdev);
+	if (result != SCSI_DH_OK)
+		goto done;
+
+done:
+	sdev_printk(KERN_INFO, sdev,
+		    "%s: at SP %c Port %d (%s, default SP %c)\n",
+		    CLARIION_NAME, csdev->current_sp + 'A',
+		    csdev->port, lun_state[csdev->lun_state],
+		    csdev->default_sp + 'A');
+
+	return result;
+}
+
+const struct scsi_dh_devlist clariion_dev_list[] = {
 	{"DGC", "RAID"},
 	{"DGC", "RAID"},
 	{"DGC", "DISK"},
 	{"DGC", "DISK"},
+	{"DGC", "VRAID"},
 	{NULL, NULL},
 	{NULL, NULL},
 };
 };
 
 
-static int clariion_bus_notify(struct notifier_block *, unsigned long, void *);
+static int clariion_bus_attach(struct scsi_device *sdev);
+static void clariion_bus_detach(struct scsi_device *sdev);
 
 
 static struct scsi_device_handler clariion_dh = {
 static struct scsi_device_handler clariion_dh = {
 	.name		= CLARIION_NAME,
 	.name		= CLARIION_NAME,
 	.module		= THIS_MODULE,
 	.module		= THIS_MODULE,
-	.nb.notifier_call = clariion_bus_notify,
+	.devlist	= clariion_dev_list,
+	.attach		= clariion_bus_attach,
+	.detach		= clariion_bus_detach,
 	.check_sense	= clariion_check_sense,
 	.check_sense	= clariion_check_sense,
 	.activate	= clariion_activate,
 	.activate	= clariion_activate,
+	.prep_fn	= clariion_prep_fn,
 };
 };
 
 
 /*
 /*
  * TODO: need some interface so we can set trespass values
  * TODO: need some interface so we can set trespass values
  */
  */
-static int clariion_bus_notify(struct notifier_block *nb,
-				unsigned long action, void *data)
+static int clariion_bus_attach(struct scsi_device *sdev)
 {
 {
-	struct device *dev = data;
-	struct scsi_device *sdev;
 	struct scsi_dh_data *scsi_dh_data;
 	struct scsi_dh_data *scsi_dh_data;
 	struct clariion_dh_data *h;
 	struct clariion_dh_data *h;
-	int i, found = 0;
 	unsigned long flags;
 	unsigned long flags;
+	int err;
 
 
-	if (!scsi_is_sdev_device(dev))
-		return 0;
+	scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+			       + sizeof(*h) , GFP_KERNEL);
+	if (!scsi_dh_data) {
+		sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
+			    CLARIION_NAME);
+		return -ENOMEM;
+	}
 
 
-	sdev = to_scsi_device(dev);
+	scsi_dh_data->scsi_dh = &clariion_dh;
+	h = (struct clariion_dh_data *) scsi_dh_data->buf;
+	h->lun_state = CLARIION_LUN_UNINITIALIZED;
+	h->default_sp = CLARIION_UNBOUND_LU;
+	h->current_sp = CLARIION_UNBOUND_LU;
 
 
-	if (action == BUS_NOTIFY_ADD_DEVICE) {
-		for (i = 0; clariion_dev_list[i].vendor; i++) {
-			if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor,
-				     strlen(clariion_dev_list[i].vendor)) &&
-			    !strncmp(sdev->model, clariion_dev_list[i].model,
-				     strlen(clariion_dev_list[i].model))) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			goto out;
-
-		scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
-				+ sizeof(*h) , GFP_KERNEL);
-		if (!scsi_dh_data) {
-			sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
-				    CLARIION_NAME);
-			goto out;
-		}
+	err = clariion_std_inquiry(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto failed;
 
 
-		scsi_dh_data->scsi_dh = &clariion_dh;
-		h = (struct clariion_dh_data *) scsi_dh_data->buf;
-		h->default_sp = CLARIION_UNBOUND_LU;
-		h->current_sp = CLARIION_UNBOUND_LU;
+	err = clariion_send_inquiry(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto failed;
 
 
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		sdev->scsi_dh_data = scsi_dh_data;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+	if (!try_module_get(THIS_MODULE))
+		goto failed;
 
 
-		sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME);
-		try_module_get(THIS_MODULE);
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	sdev->scsi_dh_data = scsi_dh_data;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
 
 
-	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
-		if (sdev->scsi_dh_data == NULL ||
-				sdev->scsi_dh_data->scsi_dh != &clariion_dh)
-			goto out;
+	sdev_printk(KERN_INFO, sdev,
+		    "%s: connected to SP %c Port %d (%s, default SP %c)\n",
+		    CLARIION_NAME, h->current_sp + 'A',
+		    h->port, lun_state[h->lun_state],
+		    h->default_sp + 'A');
 
 
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		scsi_dh_data = sdev->scsi_dh_data;
-		sdev->scsi_dh_data = NULL;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+	return 0;
 
 
-		sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n",
-			    CLARIION_NAME);
+failed:
+	kfree(scsi_dh_data);
+	sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
+		    CLARIION_NAME);
+	return -EINVAL;
+}
 
 
-		kfree(scsi_dh_data);
-		module_put(THIS_MODULE);
-	}
+static void clariion_bus_detach(struct scsi_device *sdev)
+{
+	struct scsi_dh_data *scsi_dh_data;
+	unsigned long flags;
 
 
-out:
-	return 0;
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	scsi_dh_data = sdev->scsi_dh_data;
+	sdev->scsi_dh_data = NULL;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n",
+		    CLARIION_NAME);
+
+	kfree(scsi_dh_data);
+	module_put(THIS_MODULE);
 }
 }
 
 
 static int __init clariion_init(void)
 static int __init clariion_init(void)
@@ -487,7 +660,8 @@ static int __init clariion_init(void)
 
 
 	r = scsi_register_device_handler(&clariion_dh);
 	r = scsi_register_device_handler(&clariion_dh);
 	if (r != 0)
 	if (r != 0)
-		printk(KERN_ERR "Failed to register scsi device handler.");
+		printk(KERN_ERR "%s: Failed to register scsi device handler.",
+			CLARIION_NAME);
 	return r;
 	return r;
 }
 }
 
 

+ 261 - 87
drivers/scsi/device_handler/scsi_dh_hp_sw.c

@@ -4,6 +4,7 @@
  *
  *
  * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
  * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
  * Copyright (C) 2006 Mike Christie
  * Copyright (C) 2006 Mike Christie
+ * Copyright (C) 2008 Hannes Reinecke <hare@suse.de>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * it under the terms of the GNU General Public License as published by
@@ -25,13 +26,18 @@
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_dh.h>
 #include <scsi/scsi_dh.h>
 
 
-#define HP_SW_NAME	"hp_sw"
+#define HP_SW_NAME			"hp_sw"
 
 
-#define HP_SW_TIMEOUT (60 * HZ)
-#define HP_SW_RETRIES 3
+#define HP_SW_TIMEOUT			(60 * HZ)
+#define HP_SW_RETRIES			3
+
+#define HP_SW_PATH_UNINITIALIZED	-1
+#define HP_SW_PATH_ACTIVE		0
+#define HP_SW_PATH_PASSIVE		1
 
 
 struct hp_sw_dh_data {
 struct hp_sw_dh_data {
 	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
 	unsigned char sense[SCSI_SENSE_BUFFERSIZE];
+	int path_state;
 	int retries;
 	int retries;
 };
 };
 
 
@@ -42,51 +48,161 @@ static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
 	return ((struct hp_sw_dh_data *) scsi_dh_data->buf);
 	return ((struct hp_sw_dh_data *) scsi_dh_data->buf);
 }
 }
 
 
-static int hp_sw_done(struct scsi_device *sdev)
+/*
+ * tur_done - Handle TEST UNIT READY return status
+ * @sdev: sdev the command has been sent to
+ * @errors: blk error code
+ *
+ * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path
+ */
+static int tur_done(struct scsi_device *sdev, unsigned char *sense)
 {
 {
-	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
 	struct scsi_sense_hdr sshdr;
 	struct scsi_sense_hdr sshdr;
-	int rc;
-
-	sdev_printk(KERN_INFO, sdev, "hp_sw_done\n");
+	int ret;
 
 
-	rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
-	if (!rc)
+	ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
+	if (!ret) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: sending tur failed, no sense available\n",
+			    HP_SW_NAME);
+		ret = SCSI_DH_IO;
 		goto done;
 		goto done;
+	}
 	switch (sshdr.sense_key) {
 	switch (sshdr.sense_key) {
+	case UNIT_ATTENTION:
+		ret = SCSI_DH_IMM_RETRY;
+		break;
 	case NOT_READY:
 	case NOT_READY:
-		if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
-			rc = SCSI_DH_RETRY;
-			h->retries++;
+		if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) {
+			/*
+			 * LUN not ready - Initialization command required
+			 *
+			 * This is the passive path
+			 */
+			ret = SCSI_DH_DEV_OFFLINED;
 			break;
 			break;
 		}
 		}
-		/* fall through */
+		/* Fallthrough */
 	default:
 	default:
-		h->retries++;
-		rc = SCSI_DH_IMM_RETRY;
+		sdev_printk(KERN_WARNING, sdev,
+			   "%s: sending tur failed, sense %x/%x/%x\n",
+			   HP_SW_NAME, sshdr.sense_key, sshdr.asc,
+			   sshdr.ascq);
+		break;
 	}
 	}
 
 
 done:
 done:
-	if (rc == SCSI_DH_OK || rc == SCSI_DH_IO)
-		h->retries = 0;
-	else if (h->retries > HP_SW_RETRIES) {
-		h->retries = 0;
+	return ret;
+}
+
+/*
+ * hp_sw_tur - Send TEST UNIT READY
+ * @sdev: sdev command should be sent to
+ *
+ * Use the TEST UNIT READY command to determine
+ * the path state.
+ */
+static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
+{
+	struct request *req;
+	int ret;
+
+	req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
+	if (!req)
+		return SCSI_DH_RES_TEMP_UNAVAIL;
+
+	req->cmd_type = REQ_TYPE_BLOCK_PC;
+	req->cmd_flags |= REQ_FAILFAST;
+	req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY);
+	memset(req->cmd, 0, MAX_COMMAND_SIZE);
+	req->cmd[0] = TEST_UNIT_READY;
+	req->timeout = HP_SW_TIMEOUT;
+	req->sense = h->sense;
+	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	req->sense_len = 0;
+
+retry:
+	ret = blk_execute_rq(req->q, NULL, req, 1);
+	if (ret == -EIO) {
+		if (req->sense_len > 0) {
+			ret = tur_done(sdev, h->sense);
+		} else {
+			sdev_printk(KERN_WARNING, sdev,
+				    "%s: sending tur failed with %x\n",
+				    HP_SW_NAME, req->errors);
+			ret = SCSI_DH_IO;
+		}
+	} else {
+		h->path_state = HP_SW_PATH_ACTIVE;
+		ret = SCSI_DH_OK;
+	}
+	if (ret == SCSI_DH_IMM_RETRY)
+		goto retry;
+	if (ret == SCSI_DH_DEV_OFFLINED) {
+		h->path_state = HP_SW_PATH_PASSIVE;
+		ret = SCSI_DH_OK;
+	}
+
+	blk_put_request(req);
+
+	return ret;
+}
+
+/*
+ * start_done - Handle START STOP UNIT return status
+ * @sdev: sdev the command has been sent to
+ * @errors: blk error code
+ */
+static int start_done(struct scsi_device *sdev, unsigned char *sense)
+{
+	struct scsi_sense_hdr sshdr;
+	int rc;
+
+	rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
+	if (!rc) {
+		sdev_printk(KERN_WARNING, sdev,
+			    "%s: sending start_stop_unit failed, "
+			    "no sense available\n",
+			    HP_SW_NAME);
+		return SCSI_DH_IO;
+	}
+	switch (sshdr.sense_key) {
+	case NOT_READY:
+		if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
+			/*
+			 * LUN not ready - manual intervention required
+			 *
+			 * Switch-over in progress, retry.
+			 */
+			rc = SCSI_DH_RETRY;
+			break;
+		}
+		/* fall through */
+	default:
+		sdev_printk(KERN_WARNING, sdev,
+			   "%s: sending start_stop_unit failed, sense %x/%x/%x\n",
+			   HP_SW_NAME, sshdr.sense_key, sshdr.asc,
+			   sshdr.ascq);
 		rc = SCSI_DH_IO;
 		rc = SCSI_DH_IO;
 	}
 	}
+
 	return rc;
 	return rc;
 }
 }
 
 
-static int hp_sw_activate(struct scsi_device *sdev)
+/*
+ * hp_sw_start_stop - Send START STOP UNIT command
+ * @sdev: sdev command should be sent to
+ *
+ * Sending START STOP UNIT activates the SP.
+ */
+static int hp_sw_start_stop(struct scsi_device *sdev, struct hp_sw_dh_data *h)
 {
 {
-	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
 	struct request *req;
 	struct request *req;
-	int ret = SCSI_DH_RES_TEMP_UNAVAIL;
+	int ret, retry;
 
 
-	req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC);
+	req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
 	if (!req)
 	if (!req)
-		goto done;
-
-	sdev_printk(KERN_INFO, sdev, "sending START_STOP.");
+		return SCSI_DH_RES_TEMP_UNAVAIL;
 
 
 	req->cmd_type = REQ_TYPE_BLOCK_PC;
 	req->cmd_type = REQ_TYPE_BLOCK_PC;
 	req->cmd_flags |= REQ_FAILFAST;
 	req->cmd_flags |= REQ_FAILFAST;
@@ -98,95 +214,153 @@ static int hp_sw_activate(struct scsi_device *sdev)
 	req->sense = h->sense;
 	req->sense = h->sense;
 	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
 	memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
 	req->sense_len = 0;
 	req->sense_len = 0;
+	retry = h->retries;
 
 
+retry:
 	ret = blk_execute_rq(req->q, NULL, req, 1);
 	ret = blk_execute_rq(req->q, NULL, req, 1);
-	if (!ret) /* SUCCESS */
-		ret = hp_sw_done(sdev);
-	else
+	if (ret == -EIO) {
+		if (req->sense_len > 0) {
+			ret = start_done(sdev, h->sense);
+		} else {
+			sdev_printk(KERN_WARNING, sdev,
+				    "%s: sending start_stop_unit failed with %x\n",
+				    HP_SW_NAME, req->errors);
+			ret = SCSI_DH_IO;
+		}
+	} else
+		ret = SCSI_DH_OK;
+
+	if (ret == SCSI_DH_RETRY) {
+		if (--retry)
+			goto retry;
 		ret = SCSI_DH_IO;
 		ret = SCSI_DH_IO;
-done:
+	}
+
+	blk_put_request(req);
+
+	return ret;
+}
+
+static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
+{
+	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
+	int ret = BLKPREP_OK;
+
+	if (h->path_state != HP_SW_PATH_ACTIVE) {
+		ret = BLKPREP_KILL;
+		req->cmd_flags |= REQ_QUIET;
+	}
+	return ret;
+
+}
+
+/*
+ * hp_sw_activate - Activate a path
+ * @sdev: sdev on the path to be activated
+ *
+ * The HP Active/Passive firmware is pretty simple;
+ * the passive path reports NOT READY with sense codes
+ * 0x04/0x02; a START STOP UNIT command will then
+ * activate the passive path (and deactivate the
+ * previously active one).
+ */
+static int hp_sw_activate(struct scsi_device *sdev)
+{
+	int ret = SCSI_DH_OK;
+	struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
+
+	ret = hp_sw_tur(sdev, h);
+
+	if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) {
+		ret = hp_sw_start_stop(sdev, h);
+		if (ret == SCSI_DH_OK)
+			sdev_printk(KERN_INFO, sdev,
+				    "%s: activated path\n",
+				    HP_SW_NAME);
+	}
+
 	return ret;
 	return ret;
 }
 }
 
 
-static const struct {
-	char *vendor;
-	char *model;
-} hp_sw_dh_data_list[] = {
-	{"COMPAQ", "MSA"},
-	{"HP", "HSV"},
+const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
+	{"COMPAQ", "MSA1000 VOLUME"},
+	{"COMPAQ", "HSV110"},
+	{"HP", "HSV100"},
 	{"DEC", "HSG80"},
 	{"DEC", "HSG80"},
 	{NULL, NULL},
 	{NULL, NULL},
 };
 };
 
 
-static int hp_sw_bus_notify(struct notifier_block *, unsigned long, void *);
+static int hp_sw_bus_attach(struct scsi_device *sdev);
+static void hp_sw_bus_detach(struct scsi_device *sdev);
 
 
 static struct scsi_device_handler hp_sw_dh = {
 static struct scsi_device_handler hp_sw_dh = {
 	.name		= HP_SW_NAME,
 	.name		= HP_SW_NAME,
 	.module		= THIS_MODULE,
 	.module		= THIS_MODULE,
-	.nb.notifier_call = hp_sw_bus_notify,
+	.devlist	= hp_sw_dh_data_list,
+	.attach		= hp_sw_bus_attach,
+	.detach		= hp_sw_bus_detach,
 	.activate	= hp_sw_activate,
 	.activate	= hp_sw_activate,
+	.prep_fn	= hp_sw_prep_fn,
 };
 };
 
 
-static int hp_sw_bus_notify(struct notifier_block *nb,
-			    unsigned long action, void *data)
+static int hp_sw_bus_attach(struct scsi_device *sdev)
 {
 {
-	struct device *dev = data;
-	struct scsi_device *sdev;
 	struct scsi_dh_data *scsi_dh_data;
 	struct scsi_dh_data *scsi_dh_data;
-	int i, found = 0;
+	struct hp_sw_dh_data *h;
 	unsigned long flags;
 	unsigned long flags;
+	int ret;
 
 
-	if (!scsi_is_sdev_device(dev))
+	scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+			       + sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
+	if (!scsi_dh_data) {
+		sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n",
+			    HP_SW_NAME);
 		return 0;
 		return 0;
+	}
 
 
-	sdev = to_scsi_device(dev);
-
-	if (action == BUS_NOTIFY_ADD_DEVICE) {
-		for (i = 0; hp_sw_dh_data_list[i].vendor; i++) {
-			if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor,
-				     strlen(hp_sw_dh_data_list[i].vendor)) &&
-			    !strncmp(sdev->model, hp_sw_dh_data_list[i].model,
-				     strlen(hp_sw_dh_data_list[i].model))) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			goto out;
+	scsi_dh_data->scsi_dh = &hp_sw_dh;
+	h = (struct hp_sw_dh_data *) scsi_dh_data->buf;
+	h->path_state = HP_SW_PATH_UNINITIALIZED;
+	h->retries = HP_SW_RETRIES;
 
 
-		scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
-				+ sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
-		if (!scsi_dh_data) {
-			sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n",
-				    HP_SW_NAME);
-			goto out;
-		}
+	ret = hp_sw_tur(sdev, h);
+	if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED)
+		goto failed;
 
 
-		scsi_dh_data->scsi_dh = &hp_sw_dh;
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		sdev->scsi_dh_data = scsi_dh_data;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-		try_module_get(THIS_MODULE);
+	if (!try_module_get(THIS_MODULE))
+		goto failed;
 
 
-		sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME);
-	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
-		if (sdev->scsi_dh_data == NULL ||
-				sdev->scsi_dh_data->scsi_dh != &hp_sw_dh)
-			goto out;
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	sdev->scsi_dh_data = scsi_dh_data;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
 
 
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		scsi_dh_data = sdev->scsi_dh_data;
-		sdev->scsi_dh_data = NULL;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-		module_put(THIS_MODULE);
+	sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
+		    HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
+		    "active":"passive");
 
 
-		sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", HP_SW_NAME);
+	return 0;
 
 
-		kfree(scsi_dh_data);
-	}
+failed:
+	kfree(scsi_dh_data);
+	sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
+		    HP_SW_NAME);
+	return -EINVAL;
+}
 
 
-out:
-	return 0;
+static void hp_sw_bus_detach( struct scsi_device *sdev )
+{
+	struct scsi_dh_data *scsi_dh_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	scsi_dh_data = sdev->scsi_dh_data;
+	sdev->scsi_dh_data = NULL;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+	module_put(THIS_MODULE);
+
+	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", HP_SW_NAME);
+
+	kfree(scsi_dh_data);
 }
 }
 
 
 static int __init hp_sw_init(void)
 static int __init hp_sw_init(void)
@@ -202,6 +376,6 @@ static void __exit hp_sw_exit(void)
 module_init(hp_sw_init);
 module_init(hp_sw_init);
 module_exit(hp_sw_exit);
 module_exit(hp_sw_exit);
 
 
-MODULE_DESCRIPTION("HP MSA 1000");
+MODULE_DESCRIPTION("HP Active/Passive driver");
 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 132 - 130
drivers/scsi/device_handler/scsi_dh_rdac.c

@@ -173,6 +173,11 @@ struct rdac_dh_data {
 #define RDAC_STATE_ACTIVE	0
 #define RDAC_STATE_ACTIVE	0
 #define RDAC_STATE_PASSIVE	1
 #define RDAC_STATE_PASSIVE	1
 	unsigned char		state;
 	unsigned char		state;
+
+#define RDAC_LUN_UNOWNED	0
+#define RDAC_LUN_OWNED		1
+#define RDAC_LUN_AVT		2
+	char			lun_state;
 	unsigned char		sense[SCSI_SENSE_BUFFERSIZE];
 	unsigned char		sense[SCSI_SENSE_BUFFERSIZE];
 	union			{
 	union			{
 		struct c2_inquiry c2;
 		struct c2_inquiry c2;
@@ -182,6 +187,13 @@ struct rdac_dh_data {
 	} inq;
 	} inq;
 };
 };
 
 
+static const char *lun_state[] =
+{
+	"unowned",
+	"owned",
+	"owned (AVT mode)",
+};
+
 static LIST_HEAD(ctlr_list);
 static LIST_HEAD(ctlr_list);
 static DEFINE_SPINLOCK(list_lock);
 static DEFINE_SPINLOCK(list_lock);
 
 
@@ -197,9 +209,8 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
 {
 {
 	struct request *rq;
 	struct request *rq;
 	struct request_queue *q = sdev->request_queue;
 	struct request_queue *q = sdev->request_queue;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
-	rq = blk_get_request(q, rw, GFP_KERNEL);
+	rq = blk_get_request(q, rw, GFP_NOIO);
 
 
 	if (!rq) {
 	if (!rq) {
 		sdev_printk(KERN_INFO, sdev,
 		sdev_printk(KERN_INFO, sdev,
@@ -207,17 +218,14 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) {
+	if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
 		blk_put_request(rq);
 		blk_put_request(rq);
 		sdev_printk(KERN_INFO, sdev,
 		sdev_printk(KERN_INFO, sdev,
 				"get_rdac_req: blk_rq_map_kern failed.\n");
 				"get_rdac_req: blk_rq_map_kern failed.\n");
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	memset(&rq->cmd, 0, BLK_MAX_CDB);
-	rq->sense = h->sense;
-	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
-	rq->sense_len = 0;
+	memset(rq->cmd, 0, BLK_MAX_CDB);
 
 
 	rq->cmd_type = REQ_TYPE_BLOCK_PC;
 	rq->cmd_type = REQ_TYPE_BLOCK_PC;
 	rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
 	rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
@@ -227,12 +235,12 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
 	return rq;
 	return rq;
 }
 }
 
 
-static struct request *rdac_failover_get(struct scsi_device *sdev)
+static struct request *rdac_failover_get(struct scsi_device *sdev,
+					 struct rdac_dh_data *h)
 {
 {
 	struct request *rq;
 	struct request *rq;
 	struct rdac_mode_common *common;
 	struct rdac_mode_common *common;
 	unsigned data_size;
 	unsigned data_size;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
 	if (h->ctlr->use_ms10) {
 	if (h->ctlr->use_ms10) {
 		struct rdac_pg_expanded *rdac_pg;
 		struct rdac_pg_expanded *rdac_pg;
@@ -277,6 +285,10 @@ static struct request *rdac_failover_get(struct scsi_device *sdev)
 	}
 	}
 	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
 	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
 
 
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = 0;
+
 	return rq;
 	return rq;
 }
 }
 
 
@@ -321,11 +333,10 @@ done:
 }
 }
 
 
 static int submit_inquiry(struct scsi_device *sdev, int page_code,
 static int submit_inquiry(struct scsi_device *sdev, int page_code,
-		unsigned int len)
+			  unsigned int len, struct rdac_dh_data *h)
 {
 {
 	struct request *rq;
 	struct request *rq;
 	struct request_queue *q = sdev->request_queue;
 	struct request_queue *q = sdev->request_queue;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 	int err = SCSI_DH_RES_TEMP_UNAVAIL;
 	int err = SCSI_DH_RES_TEMP_UNAVAIL;
 
 
 	rq = get_rdac_req(sdev, &h->inq, len, READ);
 	rq = get_rdac_req(sdev, &h->inq, len, READ);
@@ -338,59 +349,68 @@ static int submit_inquiry(struct scsi_device *sdev, int page_code,
 	rq->cmd[2] = page_code;
 	rq->cmd[2] = page_code;
 	rq->cmd[4] = len;
 	rq->cmd[4] = len;
 	rq->cmd_len = COMMAND_SIZE(INQUIRY);
 	rq->cmd_len = COMMAND_SIZE(INQUIRY);
+
+	rq->sense = h->sense;
+	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+	rq->sense_len = 0;
+
 	err = blk_execute_rq(q, NULL, rq, 1);
 	err = blk_execute_rq(q, NULL, rq, 1);
 	if (err == -EIO)
 	if (err == -EIO)
 		err = SCSI_DH_IO;
 		err = SCSI_DH_IO;
+
+	blk_put_request(rq);
 done:
 done:
 	return err;
 	return err;
 }
 }
 
 
-static int get_lun(struct scsi_device *sdev)
+static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
 {
 	int err;
 	int err;
 	struct c8_inquiry *inqp;
 	struct c8_inquiry *inqp;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
-	err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry));
+	err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h);
 	if (err == SCSI_DH_OK) {
 	if (err == SCSI_DH_OK) {
 		inqp = &h->inq.c8;
 		inqp = &h->inq.c8;
-		h->lun = inqp->lun[7]; /* currently it uses only one byte */
+		if (inqp->page_code != 0xc8)
+			return SCSI_DH_NOSYS;
+		if (inqp->page_id[0] != 'e' || inqp->page_id[1] != 'd' ||
+		    inqp->page_id[2] != 'i' || inqp->page_id[3] != 'd')
+			return SCSI_DH_NOSYS;
+		h->lun = scsilun_to_int((struct scsi_lun *)inqp->lun);
 	}
 	}
 	return err;
 	return err;
 }
 }
 
 
-#define RDAC_OWNED	0
-#define RDAC_UNOWNED	1
-#define RDAC_FAILED	2
-static int check_ownership(struct scsi_device *sdev)
+static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
 {
 	int err;
 	int err;
 	struct c9_inquiry *inqp;
 	struct c9_inquiry *inqp;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
-	err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry));
+	err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h);
 	if (err == SCSI_DH_OK) {
 	if (err == SCSI_DH_OK) {
-		err = RDAC_UNOWNED;
 		inqp = &h->inq.c9;
 		inqp = &h->inq.c9;
-		/*
-		 * If in AVT mode or if the path already owns the LUN,
-		 * return RDAC_OWNED;
-		 */
-		if (((inqp->avte_cvp >> 7) == 0x1) ||
-				 ((inqp->avte_cvp & 0x1) != 0))
-			err = RDAC_OWNED;
-	} else
-		err = RDAC_FAILED;
+		if ((inqp->avte_cvp >> 7) == 0x1) {
+			/* LUN in AVT mode */
+			sdev_printk(KERN_NOTICE, sdev,
+				    "%s: AVT mode detected\n",
+				    RDAC_NAME);
+			h->lun_state = RDAC_LUN_AVT;
+		} else if ((inqp->avte_cvp & 0x1) != 0) {
+			/* LUN was owned by the controller */
+			h->lun_state = RDAC_LUN_OWNED;
+		}
+	}
+
 	return err;
 	return err;
 }
 }
 
 
-static int initialize_controller(struct scsi_device *sdev)
+static int initialize_controller(struct scsi_device *sdev,
+				 struct rdac_dh_data *h)
 {
 {
 	int err;
 	int err;
 	struct c4_inquiry *inqp;
 	struct c4_inquiry *inqp;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
-	err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry));
+	err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h);
 	if (err == SCSI_DH_OK) {
 	if (err == SCSI_DH_OK) {
 		inqp = &h->inq.c4;
 		inqp = &h->inq.c4;
 		h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id);
 		h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id);
@@ -400,13 +420,12 @@ static int initialize_controller(struct scsi_device *sdev)
 	return err;
 	return err;
 }
 }
 
 
-static int set_mode_select(struct scsi_device *sdev)
+static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
 {
 	int err;
 	int err;
 	struct c2_inquiry *inqp;
 	struct c2_inquiry *inqp;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 
 
-	err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry));
+	err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry), h);
 	if (err == SCSI_DH_OK) {
 	if (err == SCSI_DH_OK) {
 		inqp = &h->inq.c2;
 		inqp = &h->inq.c2;
 		/*
 		/*
@@ -421,13 +440,13 @@ static int set_mode_select(struct scsi_device *sdev)
 	return err;
 	return err;
 }
 }
 
 
-static int mode_select_handle_sense(struct scsi_device *sdev)
+static int mode_select_handle_sense(struct scsi_device *sdev,
+				    unsigned char *sensebuf)
 {
 {
 	struct scsi_sense_hdr sense_hdr;
 	struct scsi_sense_hdr sense_hdr;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 	int sense, err = SCSI_DH_IO, ret;
 	int sense, err = SCSI_DH_IO, ret;
 
 
-	ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
+	ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
 	if (!ret)
 	if (!ret)
 		goto done;
 		goto done;
 
 
@@ -451,14 +470,13 @@ done:
 	return err;
 	return err;
 }
 }
 
 
-static int send_mode_select(struct scsi_device *sdev)
+static int send_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
 {
 {
 	struct request *rq;
 	struct request *rq;
 	struct request_queue *q = sdev->request_queue;
 	struct request_queue *q = sdev->request_queue;
-	struct rdac_dh_data *h = get_rdac_data(sdev);
 	int err = SCSI_DH_RES_TEMP_UNAVAIL;
 	int err = SCSI_DH_RES_TEMP_UNAVAIL;
 
 
-	rq = rdac_failover_get(sdev);
+	rq = rdac_failover_get(sdev, h);
 	if (!rq)
 	if (!rq)
 		goto done;
 		goto done;
 
 
@@ -466,9 +484,11 @@ static int send_mode_select(struct scsi_device *sdev)
 
 
 	err = blk_execute_rq(q, NULL, rq, 1);
 	err = blk_execute_rq(q, NULL, rq, 1);
 	if (err != SCSI_DH_OK)
 	if (err != SCSI_DH_OK)
-		err = mode_select_handle_sense(sdev);
+		err = mode_select_handle_sense(sdev, h->sense);
 	if (err == SCSI_DH_OK)
 	if (err == SCSI_DH_OK)
 		h->state = RDAC_STATE_ACTIVE;
 		h->state = RDAC_STATE_ACTIVE;
+
+	blk_put_request(rq);
 done:
 done:
 	return err;
 	return err;
 }
 }
@@ -478,38 +498,23 @@ static int rdac_activate(struct scsi_device *sdev)
 	struct rdac_dh_data *h = get_rdac_data(sdev);
 	struct rdac_dh_data *h = get_rdac_data(sdev);
 	int err = SCSI_DH_OK;
 	int err = SCSI_DH_OK;
 
 
-	if (h->lun == UNINITIALIZED_LUN) {
-		err = get_lun(sdev);
-		if (err != SCSI_DH_OK)
-			goto done;
-	}
-
-	err = check_ownership(sdev);
-	switch (err) {
-	case RDAC_UNOWNED:
-		break;
-	case RDAC_OWNED:
-		err = SCSI_DH_OK;
-		goto done;
-	case RDAC_FAILED:
-	default:
-		err = SCSI_DH_IO;
+	err = check_ownership(sdev, h);
+	if (err != SCSI_DH_OK)
 		goto done;
 		goto done;
-	}
 
 
 	if (!h->ctlr) {
 	if (!h->ctlr) {
-		err = initialize_controller(sdev);
+		err = initialize_controller(sdev, h);
 		if (err != SCSI_DH_OK)
 		if (err != SCSI_DH_OK)
 			goto done;
 			goto done;
 	}
 	}
 
 
 	if (h->ctlr->use_ms10 == -1) {
 	if (h->ctlr->use_ms10 == -1) {
-		err = set_mode_select(sdev);
+		err = set_mode_select(sdev, h);
 		if (err != SCSI_DH_OK)
 		if (err != SCSI_DH_OK)
 			goto done;
 			goto done;
 	}
 	}
-
-	err = send_mode_select(sdev);
+	if (h->lun_state == RDAC_LUN_UNOWNED)
+		err = send_mode_select(sdev, h);
 done:
 done:
 	return err;
 	return err;
 }
 }
@@ -569,10 +574,7 @@ static int rdac_check_sense(struct scsi_device *sdev,
 	return SCSI_RETURN_NOT_HANDLED;
 	return SCSI_RETURN_NOT_HANDLED;
 }
 }
 
 
-static const struct {
-	char *vendor;
-	char *model;
-} rdac_dev_list[] = {
+const struct scsi_dh_devlist rdac_dev_list[] = {
 	{"IBM", "1722"},
 	{"IBM", "1722"},
 	{"IBM", "1724"},
 	{"IBM", "1724"},
 	{"IBM", "1726"},
 	{"IBM", "1726"},
@@ -590,89 +592,89 @@ static const struct {
 	{NULL, NULL},
 	{NULL, NULL},
 };
 };
 
 
-static int rdac_bus_notify(struct notifier_block *, unsigned long, void *);
+static int rdac_bus_attach(struct scsi_device *sdev);
+static void rdac_bus_detach(struct scsi_device *sdev);
 
 
 static struct scsi_device_handler rdac_dh = {
 static struct scsi_device_handler rdac_dh = {
 	.name = RDAC_NAME,
 	.name = RDAC_NAME,
 	.module = THIS_MODULE,
 	.module = THIS_MODULE,
-	.nb.notifier_call = rdac_bus_notify,
+	.devlist = rdac_dev_list,
 	.prep_fn = rdac_prep_fn,
 	.prep_fn = rdac_prep_fn,
 	.check_sense = rdac_check_sense,
 	.check_sense = rdac_check_sense,
+	.attach = rdac_bus_attach,
+	.detach = rdac_bus_detach,
 	.activate = rdac_activate,
 	.activate = rdac_activate,
 };
 };
 
 
-/*
- * TODO: need some interface so we can set trespass values
- */
-static int rdac_bus_notify(struct notifier_block *nb,
-			    unsigned long action, void *data)
+static int rdac_bus_attach(struct scsi_device *sdev)
 {
 {
-	struct device *dev = data;
-	struct scsi_device *sdev;
 	struct scsi_dh_data *scsi_dh_data;
 	struct scsi_dh_data *scsi_dh_data;
 	struct rdac_dh_data *h;
 	struct rdac_dh_data *h;
-	int i, found = 0;
 	unsigned long flags;
 	unsigned long flags;
+	int err;
 
 
-	if (!scsi_is_sdev_device(dev))
+	scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+			       + sizeof(*h) , GFP_KERNEL);
+	if (!scsi_dh_data) {
+		sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
+			    RDAC_NAME);
 		return 0;
 		return 0;
+	}
 
 
-	sdev = to_scsi_device(dev);
-
-	if (action == BUS_NOTIFY_ADD_DEVICE) {
-		for (i = 0; rdac_dev_list[i].vendor; i++) {
-			if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor,
-				     strlen(rdac_dev_list[i].vendor)) &&
-			    !strncmp(sdev->model, rdac_dev_list[i].model,
-				     strlen(rdac_dev_list[i].model))) {
-				found = 1;
-				break;
-			}
-		}
-		if (!found)
-			goto out;
+	scsi_dh_data->scsi_dh = &rdac_dh;
+	h = (struct rdac_dh_data *) scsi_dh_data->buf;
+	h->lun = UNINITIALIZED_LUN;
+	h->state = RDAC_STATE_ACTIVE;
 
 
-		scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
-				+ sizeof(*h) , GFP_KERNEL);
-		if (!scsi_dh_data) {
-			sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
-				    RDAC_NAME);
-			goto out;
-		}
+	err = get_lun(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto failed;
 
 
-		scsi_dh_data->scsi_dh = &rdac_dh;
-		h = (struct rdac_dh_data *) scsi_dh_data->buf;
-		h->lun = UNINITIALIZED_LUN;
-		h->state = RDAC_STATE_ACTIVE;
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		sdev->scsi_dh_data = scsi_dh_data;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-		try_module_get(THIS_MODULE);
-
-		sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", RDAC_NAME);
-
-	} else if (action == BUS_NOTIFY_DEL_DEVICE) {
-		if (sdev->scsi_dh_data == NULL ||
-				sdev->scsi_dh_data->scsi_dh != &rdac_dh)
-			goto out;
-
-		spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-		scsi_dh_data = sdev->scsi_dh_data;
-		sdev->scsi_dh_data = NULL;
-		spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-
-		h = (struct rdac_dh_data *) scsi_dh_data->buf;
-		if (h->ctlr)
-			kref_put(&h->ctlr->kref, release_controller);
-		kfree(scsi_dh_data);
-		module_put(THIS_MODULE);
-		sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", RDAC_NAME);
-	}
+	err = check_ownership(sdev, h);
+	if (err != SCSI_DH_OK)
+		goto failed;
+
+	if (!try_module_get(THIS_MODULE))
+		goto failed;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	sdev->scsi_dh_data = scsi_dh_data;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+	sdev_printk(KERN_NOTICE, sdev,
+		    "%s: LUN %d (%s)\n",
+		    RDAC_NAME, h->lun, lun_state[(int)h->lun_state]);
 
 
-out:
 	return 0;
 	return 0;
+
+failed:
+	kfree(scsi_dh_data);
+	sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
+		    RDAC_NAME);
+	return -EINVAL;
+}
+
+static void rdac_bus_detach( struct scsi_device *sdev )
+{
+	struct scsi_dh_data *scsi_dh_data;
+	struct rdac_dh_data *h;
+	unsigned long flags;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+	scsi_dh_data = sdev->scsi_dh_data;
+	sdev->scsi_dh_data = NULL;
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+
+	h = (struct rdac_dh_data *) scsi_dh_data->buf;
+	if (h->ctlr)
+		kref_put(&h->ctlr->kref, release_controller);
+	kfree(scsi_dh_data);
+	module_put(THIS_MODULE);
+	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", RDAC_NAME);
 }
 }
 
 
+
+
 static int __init rdac_init(void)
 static int __init rdac_init(void)
 {
 {
 	int r;
 	int r;

+ 177 - 27
drivers/scsi/ibmvscsi/ibmvfc.c

@@ -521,9 +521,10 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
 static void ibmvfc_reinit_host(struct ibmvfc_host *vhost)
 static void ibmvfc_reinit_host(struct ibmvfc_host *vhost)
 {
 {
 	if (vhost->action == IBMVFC_HOST_ACTION_NONE) {
 	if (vhost->action == IBMVFC_HOST_ACTION_NONE) {
-		scsi_block_requests(vhost->host);
-		ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING);
-		ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
+		if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) {
+			scsi_block_requests(vhost->host);
+			ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
+		}
 	} else
 	} else
 		vhost->reinit = 1;
 		vhost->reinit = 1;
 
 
@@ -854,39 +855,41 @@ static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost)
 }
 }
 
 
 /**
 /**
- * __ibmvfc_find_target - Find the specified scsi_target (no locking)
+ * __ibmvfc_get_target - Find the specified scsi_target (no locking)
  * @starget:	scsi target struct
  * @starget:	scsi target struct
  *
  *
  * Return value:
  * Return value:
  *	ibmvfc_target struct / NULL if not found
  *	ibmvfc_target struct / NULL if not found
  **/
  **/
-static struct ibmvfc_target *__ibmvfc_find_target(struct scsi_target *starget)
+static struct ibmvfc_target *__ibmvfc_get_target(struct scsi_target *starget)
 {
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct ibmvfc_host *vhost = shost_priv(shost);
 	struct ibmvfc_host *vhost = shost_priv(shost);
 	struct ibmvfc_target *tgt;
 	struct ibmvfc_target *tgt;
 
 
 	list_for_each_entry(tgt, &vhost->targets, queue)
 	list_for_each_entry(tgt, &vhost->targets, queue)
-		if (tgt->target_id == starget->id)
+		if (tgt->target_id == starget->id) {
+			kref_get(&tgt->kref);
 			return tgt;
 			return tgt;
+		}
 	return NULL;
 	return NULL;
 }
 }
 
 
 /**
 /**
- * ibmvfc_find_target - Find the specified scsi_target
+ * ibmvfc_get_target - Find the specified scsi_target
  * @starget:	scsi target struct
  * @starget:	scsi target struct
  *
  *
  * Return value:
  * Return value:
  *	ibmvfc_target struct / NULL if not found
  *	ibmvfc_target struct / NULL if not found
  **/
  **/
-static struct ibmvfc_target *ibmvfc_find_target(struct scsi_target *starget)
+static struct ibmvfc_target *ibmvfc_get_target(struct scsi_target *starget)
 {
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct ibmvfc_target *tgt;
 	struct ibmvfc_target *tgt;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(shost->host_lock, flags);
 	spin_lock_irqsave(shost->host_lock, flags);
-	tgt = __ibmvfc_find_target(starget);
+	tgt = __ibmvfc_get_target(starget);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	return tgt;
 	return tgt;
 }
 }
@@ -963,6 +966,9 @@ static void ibmvfc_get_host_port_state(struct Scsi_Host *shost)
 	case IBMVFC_HALTED:
 	case IBMVFC_HALTED:
 		fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED;
 		fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED;
 		break;
 		break;
+	case IBMVFC_NO_CRQ:
+		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
+		break;
 	default:
 	default:
 		ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state);
 		ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state);
 		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
 		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
@@ -987,6 +993,17 @@ static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
 		rport->dev_loss_tmo = 1;
 		rport->dev_loss_tmo = 1;
 }
 }
 
 
+/**
+ * ibmvfc_release_tgt - Free memory allocated for a target
+ * @kref:		kref struct
+ *
+ **/
+static void ibmvfc_release_tgt(struct kref *kref)
+{
+	struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref);
+	kfree(tgt);
+}
+
 /**
 /**
  * ibmvfc_get_starget_node_name - Get SCSI target's node name
  * ibmvfc_get_starget_node_name - Get SCSI target's node name
  * @starget:	scsi target struct
  * @starget:	scsi target struct
@@ -996,8 +1013,10 @@ static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
  **/
  **/
 static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
 static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
 {
 {
-	struct ibmvfc_target *tgt = ibmvfc_find_target(starget);
+	struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
 	fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0;
 	fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0;
+	if (tgt)
+		kref_put(&tgt->kref, ibmvfc_release_tgt);
 }
 }
 
 
 /**
 /**
@@ -1009,8 +1028,10 @@ static void ibmvfc_get_starget_node_name(struct scsi_target *starget)
  **/
  **/
 static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
 static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
 {
 {
-	struct ibmvfc_target *tgt = ibmvfc_find_target(starget);
+	struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
 	fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0;
 	fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0;
+	if (tgt)
+		kref_put(&tgt->kref, ibmvfc_release_tgt);
 }
 }
 
 
 /**
 /**
@@ -1022,8 +1043,10 @@ static void ibmvfc_get_starget_port_name(struct scsi_target *starget)
  **/
  **/
 static void ibmvfc_get_starget_port_id(struct scsi_target *starget)
 static void ibmvfc_get_starget_port_id(struct scsi_target *starget)
 {
 {
-	struct ibmvfc_target *tgt = ibmvfc_find_target(starget);
+	struct ibmvfc_target *tgt = ibmvfc_get_target(starget);
 	fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1;
 	fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1;
+	if (tgt)
+		kref_put(&tgt->kref, ibmvfc_release_tgt);
 }
 }
 
 
 /**
 /**
@@ -1113,7 +1136,7 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
 	login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ;
 	login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ;
 	login_info->capabilities = IBMVFC_CAN_MIGRATE;
 	login_info->capabilities = IBMVFC_CAN_MIGRATE;
 	login_info->async.va = vhost->async_crq.msg_token;
 	login_info->async.va = vhost->async_crq.msg_token;
-	login_info->async.len = vhost->async_crq.size;
+	login_info->async.len = vhost->async_crq.size * sizeof(*vhost->async_crq.msgs);
 	strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME);
 	strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME);
 	strncpy(login_info->device_name,
 	strncpy(login_info->device_name,
 		vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME);
 		vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME);
@@ -1404,7 +1427,7 @@ static void ibmvfc_log_error(struct ibmvfc_event *evt)
 		err = cmd_status[index].name;
 		err = cmd_status[index].name;
 	}
 	}
 
 
-	if (!logerr && (vhost->log_level <= IBMVFC_DEFAULT_LOG_LEVEL))
+	if (!logerr && (vhost->log_level <= (IBMVFC_DEFAULT_LOG_LEVEL + 1)))
 		return;
 		return;
 
 
 	if (rsp->flags & FCP_RSP_LEN_VALID)
 	if (rsp->flags & FCP_RSP_LEN_VALID)
@@ -2054,7 +2077,7 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
 {
 {
 	const char *desc = ibmvfc_get_ae_desc(crq->event);
 	const char *desc = ibmvfc_get_ae_desc(crq->event);
 
 
-	ibmvfc_log(vhost, 2, "%s event received\n", desc);
+	ibmvfc_log(vhost, 3, "%s event received\n", desc);
 
 
 	switch (crq->event) {
 	switch (crq->event) {
 	case IBMVFC_AE_LINK_UP:
 	case IBMVFC_AE_LINK_UP:
@@ -2647,17 +2670,6 @@ static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt,
 		ibmvfc_init_tgt(tgt, job_step);
 		ibmvfc_init_tgt(tgt, job_step);
 }
 }
 
 
-/**
- * ibmvfc_release_tgt - Free memory allocated for a target
- * @kref:		kref struct
- *
- **/
-static void ibmvfc_release_tgt(struct kref *kref)
-{
-	struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref);
-	kfree(tgt);
-}
-
 /**
 /**
  * ibmvfc_tgt_prli_done - Completion handler for Process Login
  * ibmvfc_tgt_prli_done - Completion handler for Process Login
  * @evt:	ibmvfc event struct
  * @evt:	ibmvfc event struct
@@ -2901,6 +2913,139 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
 		tgt_dbg(tgt, "Sent Implicit Logout\n");
 		tgt_dbg(tgt, "Sent Implicit Logout\n");
 }
 }
 
 
+/**
+ * ibmvfc_adisc_needs_plogi - Does device need PLOGI?
+ * @mad:	ibmvfc passthru mad struct
+ * @tgt:	ibmvfc target struct
+ *
+ * Returns:
+ *	1 if PLOGI needed / 0 if PLOGI not needed
+ **/
+static int ibmvfc_adisc_needs_plogi(struct ibmvfc_passthru_mad *mad,
+				    struct ibmvfc_target *tgt)
+{
+	if (memcmp(&mad->fc_iu.response[2], &tgt->ids.port_name,
+		   sizeof(tgt->ids.port_name)))
+		return 1;
+	if (memcmp(&mad->fc_iu.response[4], &tgt->ids.node_name,
+		   sizeof(tgt->ids.node_name)))
+		return 1;
+	if (mad->fc_iu.response[6] != tgt->scsi_id)
+		return 1;
+	return 0;
+}
+
+/**
+ * ibmvfc_tgt_adisc_done - Completion handler for ADISC
+ * @evt:	ibmvfc event struct
+ *
+ **/
+static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt)
+{
+	struct ibmvfc_target *tgt = evt->tgt;
+	struct ibmvfc_host *vhost = evt->vhost;
+	struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru;
+	u32 status = mad->common.status;
+	u8 fc_reason, fc_explain;
+
+	vhost->discovery_threads--;
+	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
+
+	switch (status) {
+	case IBMVFC_MAD_SUCCESS:
+		tgt_dbg(tgt, "ADISC succeeded\n");
+		if (ibmvfc_adisc_needs_plogi(mad, tgt))
+			tgt->need_login = 1;
+		break;
+	case IBMVFC_MAD_DRIVER_FAILED:
+		break;
+	case IBMVFC_MAD_FAILED:
+	default:
+		tgt->need_login = 1;
+		fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16;
+		fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8;
+		tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n",
+			 ibmvfc_get_cmd_error(mad->iu.status, mad->iu.error),
+			 mad->iu.status, mad->iu.error,
+			 ibmvfc_get_fc_type(fc_reason), fc_reason,
+			 ibmvfc_get_ls_explain(fc_explain), fc_explain, status);
+		break;
+	};
+
+	kref_put(&tgt->kref, ibmvfc_release_tgt);
+	ibmvfc_free_event(evt);
+	wake_up(&vhost->work_wait_q);
+}
+
+/**
+ * ibmvfc_init_passthru - Initialize an event struct for FC passthru
+ * @evt:		ibmvfc event struct
+ *
+ **/
+static void ibmvfc_init_passthru(struct ibmvfc_event *evt)
+{
+	struct ibmvfc_passthru_mad *mad = &evt->iu.passthru;
+
+	memset(mad, 0, sizeof(*mad));
+	mad->common.version = 1;
+	mad->common.opcode = IBMVFC_PASSTHRU;
+	mad->common.length = sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu);
+	mad->cmd_ioba.va = (u64)evt->crq.ioba +
+		offsetof(struct ibmvfc_passthru_mad, iu);
+	mad->cmd_ioba.len = sizeof(mad->iu);
+	mad->iu.cmd_len = sizeof(mad->fc_iu.payload);
+	mad->iu.rsp_len = sizeof(mad->fc_iu.response);
+	mad->iu.cmd.va = (u64)evt->crq.ioba +
+		offsetof(struct ibmvfc_passthru_mad, fc_iu) +
+		offsetof(struct ibmvfc_passthru_fc_iu, payload);
+	mad->iu.cmd.len = sizeof(mad->fc_iu.payload);
+	mad->iu.rsp.va = (u64)evt->crq.ioba +
+		offsetof(struct ibmvfc_passthru_mad, fc_iu) +
+		offsetof(struct ibmvfc_passthru_fc_iu, response);
+	mad->iu.rsp.len = sizeof(mad->fc_iu.response);
+}
+
+/**
+ * ibmvfc_tgt_adisc - Initiate an ADISC for specified target
+ * @tgt:		ibmvfc target struct
+ *
+ **/
+static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt)
+{
+	struct ibmvfc_passthru_mad *mad;
+	struct ibmvfc_host *vhost = tgt->vhost;
+	struct ibmvfc_event *evt;
+
+	if (vhost->discovery_threads >= disc_threads)
+		return;
+
+	kref_get(&tgt->kref);
+	evt = ibmvfc_get_event(vhost);
+	vhost->discovery_threads++;
+	ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT);
+	evt->tgt = tgt;
+
+	ibmvfc_init_passthru(evt);
+	mad = &evt->iu.passthru;
+	mad->iu.flags = IBMVFC_FC_ELS;
+	mad->iu.scsi_id = tgt->scsi_id;
+
+	mad->fc_iu.payload[0] = IBMVFC_ADISC;
+	memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name,
+	       sizeof(vhost->login_buf->resp.port_name));
+	memcpy(&mad->fc_iu.payload[4], &vhost->login_buf->resp.node_name,
+	       sizeof(vhost->login_buf->resp.node_name));
+	mad->fc_iu.payload[6] = vhost->login_buf->resp.scsi_id & 0x00ffffff;
+
+	ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
+	if (ibmvfc_send_event(evt, vhost, default_timeout)) {
+		vhost->discovery_threads--;
+		ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
+		kref_put(&tgt->kref, ibmvfc_release_tgt);
+	} else
+		tgt_dbg(tgt, "Sent ADISC\n");
+}
+
 /**
 /**
  * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD
  * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD
  * @evt:	ibmvfc event struct
  * @evt:	ibmvfc event struct
@@ -2921,6 +3066,8 @@ static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt)
 		tgt->new_scsi_id = rsp->scsi_id;
 		tgt->new_scsi_id = rsp->scsi_id;
 		if (rsp->scsi_id != tgt->scsi_id)
 		if (rsp->scsi_id != tgt->scsi_id)
 			ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout);
 			ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout);
+		else
+			ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc);
 		break;
 		break;
 	case IBMVFC_MAD_DRIVER_FAILED:
 	case IBMVFC_MAD_DRIVER_FAILED:
 		break;
 		break;
@@ -3336,6 +3483,7 @@ static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
 		tgt_dbg(tgt, "rport add succeeded\n");
 		tgt_dbg(tgt, "rport add succeeded\n");
 		rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff;
 		rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff;
 		rport->supported_classes = 0;
 		rport->supported_classes = 0;
+		tgt->target_id = rport->scsi_target_id;
 		if (tgt->service_parms.class1_parms[0] & 0x80000000)
 		if (tgt->service_parms.class1_parms[0] & 0x80000000)
 			rport->supported_classes |= FC_COS_CLASS1;
 			rport->supported_classes |= FC_COS_CLASS1;
 		if (tgt->service_parms.class2_parms[0] & 0x80000000)
 		if (tgt->service_parms.class2_parms[0] & 0x80000000)
@@ -3800,10 +3948,12 @@ static int ibmvfc_remove(struct vio_dev *vdev)
 
 
 	ENTER;
 	ENTER;
 	ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr);
 	ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr);
+	ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE);
+	ibmvfc_wait_while_resetting(vhost);
+	ibmvfc_release_crq_queue(vhost);
 	kthread_stop(vhost->work_thread);
 	kthread_stop(vhost->work_thread);
 	fc_remove_host(vhost->host);
 	fc_remove_host(vhost->host);
 	scsi_remove_host(vhost->host);
 	scsi_remove_host(vhost->host);
-	ibmvfc_release_crq_queue(vhost);
 
 
 	spin_lock_irqsave(vhost->host->host_lock, flags);
 	spin_lock_irqsave(vhost->host->host_lock, flags);
 	ibmvfc_purge_requests(vhost, DID_ERROR);
 	ibmvfc_purge_requests(vhost, DID_ERROR);

+ 40 - 4
drivers/scsi/ibmvscsi/ibmvfc.h

@@ -29,8 +29,8 @@
 #include "viosrp.h"
 #include "viosrp.h"
 
 
 #define IBMVFC_NAME	"ibmvfc"
 #define IBMVFC_NAME	"ibmvfc"
-#define IBMVFC_DRIVER_VERSION		"1.0.0"
-#define IBMVFC_DRIVER_DATE		"(July 1, 2008)"
+#define IBMVFC_DRIVER_VERSION		"1.0.1"
+#define IBMVFC_DRIVER_DATE		"(July 11, 2008)"
 
 
 #define IBMVFC_DEFAULT_TIMEOUT	15
 #define IBMVFC_DEFAULT_TIMEOUT	15
 #define IBMVFC_INIT_TIMEOUT		30
 #define IBMVFC_INIT_TIMEOUT		30
@@ -119,6 +119,7 @@ enum ibmvfc_mad_types {
 	IBMVFC_PROCESS_LOGIN	= 0x0008,
 	IBMVFC_PROCESS_LOGIN	= 0x0008,
 	IBMVFC_QUERY_TARGET	= 0x0010,
 	IBMVFC_QUERY_TARGET	= 0x0010,
 	IBMVFC_IMPLICIT_LOGOUT	= 0x0040,
 	IBMVFC_IMPLICIT_LOGOUT	= 0x0040,
+	IBMVFC_PASSTHRU		= 0x0200,
 	IBMVFC_TMF_MAD		= 0x0100,
 	IBMVFC_TMF_MAD		= 0x0100,
 };
 };
 
 
@@ -439,6 +440,37 @@ struct ibmvfc_cmd {
 	struct ibmvfc_fcp_rsp rsp;
 	struct ibmvfc_fcp_rsp rsp;
 }__attribute__((packed, aligned (8)));
 }__attribute__((packed, aligned (8)));
 
 
+struct ibmvfc_passthru_fc_iu {
+	u32 payload[7];
+#define IBMVFC_ADISC	0x52000000
+	u32 response[7];
+};
+
+struct ibmvfc_passthru_iu {
+	u64 task_tag;
+	u32 cmd_len;
+	u32 rsp_len;
+	u16 status;
+	u16 error;
+	u32 flags;
+#define IBMVFC_FC_ELS		0x01
+	u32 cancel_key;
+	u32 reserved;
+	struct srp_direct_buf cmd;
+	struct srp_direct_buf rsp;
+	u64 correlation;
+	u64 scsi_id;
+	u64 tag;
+	u64 reserved2[2];
+}__attribute__((packed, aligned (8)));
+
+struct ibmvfc_passthru_mad {
+	struct ibmvfc_mad_common common;
+	struct srp_direct_buf cmd_ioba;
+	struct ibmvfc_passthru_iu iu;
+	struct ibmvfc_passthru_fc_iu fc_iu;
+}__attribute__((packed, aligned (8)));
+
 struct ibmvfc_trace_start_entry {
 struct ibmvfc_trace_start_entry {
 	u32 xfer_len;
 	u32 xfer_len;
 }__attribute__((packed));
 }__attribute__((packed));
@@ -531,6 +563,7 @@ union ibmvfc_iu {
 	struct ibmvfc_implicit_logout implicit_logout;
 	struct ibmvfc_implicit_logout implicit_logout;
 	struct ibmvfc_tmf tmf;
 	struct ibmvfc_tmf tmf;
 	struct ibmvfc_cmd cmd;
 	struct ibmvfc_cmd cmd;
+	struct ibmvfc_passthru_mad passthru;
 }__attribute__((packed, aligned (8)));
 }__attribute__((packed, aligned (8)));
 
 
 enum ibmvfc_target_action {
 enum ibmvfc_target_action {
@@ -656,6 +689,9 @@ struct ibmvfc_host {
 #define tgt_dbg(t, fmt, ...)			\
 #define tgt_dbg(t, fmt, ...)			\
 	DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__))
 	DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__))
 
 
+#define tgt_info(t, fmt, ...)		\
+	dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
+
 #define tgt_err(t, fmt, ...)		\
 #define tgt_err(t, fmt, ...)		\
 	dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
 	dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
 
 
@@ -668,8 +704,8 @@ struct ibmvfc_host {
 			dev_err((vhost)->dev, ##__VA_ARGS__); \
 			dev_err((vhost)->dev, ##__VA_ARGS__); \
 	} while (0)
 	} while (0)
 
 
-#define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __FUNCTION__))
-#define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __FUNCTION__))
+#define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __func__))
+#define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __func__))
 
 
 #ifdef CONFIG_SCSI_IBMVFC_TRACE
 #ifdef CONFIG_SCSI_IBMVFC_TRACE
 #define ibmvfc_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr)
 #define ibmvfc_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr)

+ 1 - 1
drivers/scsi/ibmvscsi/ibmvstgt.c

@@ -55,7 +55,7 @@
 /* tmp - will replace with SCSI logging stuff */
 /* tmp - will replace with SCSI logging stuff */
 #define eprintk(fmt, args...)					\
 #define eprintk(fmt, args...)					\
 do {								\
 do {								\
-	printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);	\
+	printk("%s(%d) " fmt, __func__, __LINE__, ##args);	\
 } while (0)
 } while (0)
 /* #define dprintk eprintk */
 /* #define dprintk eprintk */
 #define dprintk(fmt, args...)
 #define dprintk(fmt, args...)

+ 1 - 1
drivers/scsi/imm.c

@@ -163,7 +163,7 @@ static int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start,
 
 
 #if IMM_DEBUG > 0
 #if IMM_DEBUG > 0
 #define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\
 #define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\
-	   y, __FUNCTION__, __LINE__); imm_fail_func(x,y);
+	   y, __func__, __LINE__); imm_fail_func(x,y);
 static inline void
 static inline void
 imm_fail_func(imm_struct *dev, int error_code)
 imm_fail_func(imm_struct *dev, int error_code)
 #else
 #else

+ 3 - 3
drivers/scsi/ipr.h

@@ -1403,10 +1403,10 @@ struct ipr_ucode_image_header {
 }
 }
 
 
 #define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
 #define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
-	__FILE__, __FUNCTION__, __LINE__)
+	__FILE__, __func__, __LINE__)
 
 
-#define ENTER IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Entering %s\n", __FUNCTION__))
-#define LEAVE IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Leaving %s\n", __FUNCTION__))
+#define ENTER IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Entering %s\n", __func__))
+#define LEAVE IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Leaving %s\n", __func__))
 
 
 #define ipr_err_separator \
 #define ipr_err_separator \
 ipr_err("----------------------------------------------------------\n")
 ipr_err("----------------------------------------------------------\n")

+ 8 - 8
drivers/scsi/libsas/sas_ata.c

@@ -74,7 +74,7 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts)
 		case SAS_OPEN_TO:
 		case SAS_OPEN_TO:
 		case SAS_OPEN_REJECT:
 		case SAS_OPEN_REJECT:
 			SAS_DPRINTK("%s: Saw error %d.  What to do?\n",
 			SAS_DPRINTK("%s: Saw error %d.  What to do?\n",
-				    __FUNCTION__, ts->stat);
+				    __func__, ts->stat);
 			return AC_ERR_OTHER;
 			return AC_ERR_OTHER;
 
 
 		case SAS_ABORTED_TASK:
 		case SAS_ABORTED_TASK:
@@ -115,7 +115,7 @@ static void sas_ata_task_done(struct sas_task *task)
 	} else if (stat->stat != SAM_STAT_GOOD) {
 	} else if (stat->stat != SAM_STAT_GOOD) {
 		ac = sas_to_ata_err(stat);
 		ac = sas_to_ata_err(stat);
 		if (ac) {
 		if (ac) {
-			SAS_DPRINTK("%s: SAS error %x\n", __FUNCTION__,
+			SAS_DPRINTK("%s: SAS error %x\n", __func__,
 				    stat->stat);
 				    stat->stat);
 			/* We saw a SAS error. Send a vague error. */
 			/* We saw a SAS error. Send a vague error. */
 			qc->err_mask = ac;
 			qc->err_mask = ac;
@@ -244,20 +244,20 @@ static void sas_ata_phy_reset(struct ata_port *ap)
 		res = i->dft->lldd_I_T_nexus_reset(dev);
 		res = i->dft->lldd_I_T_nexus_reset(dev);
 
 
 	if (res != TMF_RESP_FUNC_COMPLETE)
 	if (res != TMF_RESP_FUNC_COMPLETE)
-		SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__);
+		SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__);
 
 
 	switch (dev->sata_dev.command_set) {
 	switch (dev->sata_dev.command_set) {
 		case ATA_COMMAND_SET:
 		case ATA_COMMAND_SET:
-			SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__);
+			SAS_DPRINTK("%s: Found ATA device.\n", __func__);
 			ap->link.device[0].class = ATA_DEV_ATA;
 			ap->link.device[0].class = ATA_DEV_ATA;
 			break;
 			break;
 		case ATAPI_COMMAND_SET:
 		case ATAPI_COMMAND_SET:
-			SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__);
+			SAS_DPRINTK("%s: Found ATAPI device.\n", __func__);
 			ap->link.device[0].class = ATA_DEV_ATAPI;
 			ap->link.device[0].class = ATA_DEV_ATAPI;
 			break;
 			break;
 		default:
 		default:
 			SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
 			SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
-				    __FUNCTION__,
+				    __func__,
 				    dev->sata_dev.command_set);
 				    dev->sata_dev.command_set);
 			ap->link.device[0].class = ATA_DEV_UNKNOWN;
 			ap->link.device[0].class = ATA_DEV_UNKNOWN;
 			break;
 			break;
@@ -299,7 +299,7 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
 {
 {
 	struct domain_device *dev = ap->private_data;
 	struct domain_device *dev = ap->private_data;
 
 
-	SAS_DPRINTK("STUB %s\n", __FUNCTION__);
+	SAS_DPRINTK("STUB %s\n", __func__);
 	switch (sc_reg_in) {
 	switch (sc_reg_in) {
 		case SCR_STATUS:
 		case SCR_STATUS:
 			dev->sata_dev.sstatus = val;
 			dev->sata_dev.sstatus = val;
@@ -324,7 +324,7 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
 {
 {
 	struct domain_device *dev = ap->private_data;
 	struct domain_device *dev = ap->private_data;
 
 
-	SAS_DPRINTK("STUB %s\n", __FUNCTION__);
+	SAS_DPRINTK("STUB %s\n", __func__);
 	switch (sc_reg_in) {
 	switch (sc_reg_in) {
 		case SCR_STATUS:
 		case SCR_STATUS:
 			*val = dev->sata_dev.sstatus;
 			*val = dev->sata_dev.sstatus;

+ 6 - 6
drivers/scsi/libsas/sas_expander.c

@@ -121,7 +121,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
 			break;
 			break;
 		} else {
 		} else {
 			SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
 			SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
-				    "status 0x%x\n", __FUNCTION__,
+				    "status 0x%x\n", __func__,
 				    SAS_ADDR(dev->sas_addr),
 				    SAS_ADDR(dev->sas_addr),
 				    task->task_status.resp,
 				    task->task_status.resp,
 				    task->task_status.stat);
 				    task->task_status.stat);
@@ -1279,7 +1279,7 @@ static int sas_configure_present(struct domain_device *dev, int phy_id,
 			goto out;
 			goto out;
 		} else if (res != SMP_RESP_FUNC_ACC) {
 		} else if (res != SMP_RESP_FUNC_ACC) {
 			SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x "
 			SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x "
-				    "result 0x%x\n", __FUNCTION__,
+				    "result 0x%x\n", __func__,
 				    SAS_ADDR(dev->sas_addr), phy_id, i, res);
 				    SAS_ADDR(dev->sas_addr), phy_id, i, res);
 			goto out;
 			goto out;
 		}
 		}
@@ -1901,7 +1901,7 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
 
 	if (!rsp) {
 	if (!rsp) {
 		printk("%s: space for a smp response is missing\n",
 		printk("%s: space for a smp response is missing\n",
-		       __FUNCTION__);
+		       __func__);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
@@ -1914,20 +1914,20 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 	if (type != SAS_EDGE_EXPANDER_DEVICE &&
 	if (type != SAS_EDGE_EXPANDER_DEVICE &&
 	    type != SAS_FANOUT_EXPANDER_DEVICE) {
 	    type != SAS_FANOUT_EXPANDER_DEVICE) {
 		printk("%s: can we send a smp request to a device?\n",
 		printk("%s: can we send a smp request to a device?\n",
-		       __FUNCTION__);
+		       __func__);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	dev = sas_find_dev_by_rphy(rphy);
 	dev = sas_find_dev_by_rphy(rphy);
 	if (!dev) {
 	if (!dev) {
-		printk("%s: fail to find a domain_device?\n", __FUNCTION__);
+		printk("%s: fail to find a domain_device?\n", __func__);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
 	/* do we need to support multiple segments? */
 	/* do we need to support multiple segments? */
 	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
 	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
 		printk("%s: multiple segments req %u %u, rsp %u %u\n",
 		printk("%s: multiple segments req %u %u, rsp %u %u\n",
-		       __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+		       __func__, req->bio->bi_vcnt, req->data_len,
 		       rsp->bio->bi_vcnt, rsp->data_len);
 		       rsp->bio->bi_vcnt, rsp->data_len);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}

+ 2 - 2
drivers/scsi/libsas/sas_port.c

@@ -50,7 +50,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
 			sas_deform_port(phy);
 			sas_deform_port(phy);
 		else {
 		else {
 			SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
 			SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
-				    __FUNCTION__, phy->id, phy->port->id,
+				    __func__, phy->id, phy->port->id,
 				    phy->port->num_phys);
 				    phy->port->num_phys);
 			return;
 			return;
 		}
 		}
@@ -78,7 +78,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
 
 
 	if (i >= sas_ha->num_phys) {
 	if (i >= sas_ha->num_phys) {
 		printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
 		printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
-		       __FUNCTION__);
+		       __func__);
 		spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
 		spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
 		return;
 		return;
 	}
 	}

+ 15 - 15
drivers/scsi/libsas/sas_scsi_host.c

@@ -343,7 +343,7 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
 						       flags);
 						       flags);
 				SAS_DPRINTK("%s: task 0x%p aborted from "
 				SAS_DPRINTK("%s: task 0x%p aborted from "
 					    "task_queue\n",
 					    "task_queue\n",
-					    __FUNCTION__, task);
+					    __func__, task);
 				return TASK_IS_ABORTED;
 				return TASK_IS_ABORTED;
 			}
 			}
 		}
 		}
@@ -351,13 +351,13 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
 	}
 	}
 
 
 	for (i = 0; i < 5; i++) {
 	for (i = 0; i < 5; i++) {
-		SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
+		SAS_DPRINTK("%s: aborting task 0x%p\n", __func__, task);
 		res = si->dft->lldd_abort_task(task);
 		res = si->dft->lldd_abort_task(task);
 
 
 		spin_lock_irqsave(&task->task_state_lock, flags);
 		spin_lock_irqsave(&task->task_state_lock, flags);
 		if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 			spin_unlock_irqrestore(&task->task_state_lock, flags);
 			spin_unlock_irqrestore(&task->task_state_lock, flags);
-			SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+			SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
 				    task);
 				    task);
 			return TASK_IS_DONE;
 			return TASK_IS_DONE;
 		}
 		}
@@ -365,24 +365,24 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task)
 
 
 		if (res == TMF_RESP_FUNC_COMPLETE) {
 		if (res == TMF_RESP_FUNC_COMPLETE) {
 			SAS_DPRINTK("%s: task 0x%p is aborted\n",
 			SAS_DPRINTK("%s: task 0x%p is aborted\n",
-				    __FUNCTION__, task);
+				    __func__, task);
 			return TASK_IS_ABORTED;
 			return TASK_IS_ABORTED;
 		} else if (si->dft->lldd_query_task) {
 		} else if (si->dft->lldd_query_task) {
 			SAS_DPRINTK("%s: querying task 0x%p\n",
 			SAS_DPRINTK("%s: querying task 0x%p\n",
-				    __FUNCTION__, task);
+				    __func__, task);
 			res = si->dft->lldd_query_task(task);
 			res = si->dft->lldd_query_task(task);
 			switch (res) {
 			switch (res) {
 			case TMF_RESP_FUNC_SUCC:
 			case TMF_RESP_FUNC_SUCC:
 				SAS_DPRINTK("%s: task 0x%p at LU\n",
 				SAS_DPRINTK("%s: task 0x%p at LU\n",
-					    __FUNCTION__, task);
+					    __func__, task);
 				return TASK_IS_AT_LU;
 				return TASK_IS_AT_LU;
 			case TMF_RESP_FUNC_COMPLETE:
 			case TMF_RESP_FUNC_COMPLETE:
 				SAS_DPRINTK("%s: task 0x%p not at LU\n",
 				SAS_DPRINTK("%s: task 0x%p not at LU\n",
-					    __FUNCTION__, task);
+					    __func__, task);
 				return TASK_IS_NOT_AT_LU;
 				return TASK_IS_NOT_AT_LU;
 			case TMF_RESP_FUNC_FAILED:
 			case TMF_RESP_FUNC_FAILED:
                                 SAS_DPRINTK("%s: task 0x%p failed to abort\n",
                                 SAS_DPRINTK("%s: task 0x%p failed to abort\n",
-                                                __FUNCTION__, task);
+                                                __func__, task);
                                 return TASK_ABORT_FAILED;
                                 return TASK_ABORT_FAILED;
                         }
                         }
 
 
@@ -545,7 +545,7 @@ Again:
 
 
 		if (need_reset) {
 		if (need_reset) {
 			SAS_DPRINTK("%s: task 0x%p requests reset\n",
 			SAS_DPRINTK("%s: task 0x%p requests reset\n",
-				    __FUNCTION__, task);
+				    __func__, task);
 			goto reset;
 			goto reset;
 		}
 		}
 
 
@@ -556,13 +556,13 @@ Again:
 
 
 		switch (res) {
 		switch (res) {
 		case TASK_IS_DONE:
 		case TASK_IS_DONE:
-			SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+			SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
 				    task);
 				    task);
 			sas_eh_finish_cmd(cmd);
 			sas_eh_finish_cmd(cmd);
 			continue;
 			continue;
 		case TASK_IS_ABORTED:
 		case TASK_IS_ABORTED:
 			SAS_DPRINTK("%s: task 0x%p is aborted\n",
 			SAS_DPRINTK("%s: task 0x%p is aborted\n",
-				    __FUNCTION__, task);
+				    __func__, task);
 			sas_eh_finish_cmd(cmd);
 			sas_eh_finish_cmd(cmd);
 			continue;
 			continue;
 		case TASK_IS_AT_LU:
 		case TASK_IS_AT_LU:
@@ -633,7 +633,7 @@ Again:
 	}
 	}
 	return list_empty(work_q);
 	return list_empty(work_q);
 clear_q:
 clear_q:
-	SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
+	SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__);
 	list_for_each_entry_safe(cmd, n, work_q, eh_entry)
 	list_for_each_entry_safe(cmd, n, work_q, eh_entry)
 		sas_eh_finish_cmd(cmd);
 		sas_eh_finish_cmd(cmd);
 
 
@@ -650,7 +650,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
 	list_splice_init(&shost->eh_cmd_q, &eh_work_q);
 	list_splice_init(&shost->eh_cmd_q, &eh_work_q);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
 
-	SAS_DPRINTK("Enter %s\n", __FUNCTION__);
+	SAS_DPRINTK("Enter %s\n", __func__);
 	/*
 	/*
 	 * Deal with commands that still have SAS tasks (i.e. they didn't
 	 * Deal with commands that still have SAS tasks (i.e. they didn't
 	 * complete via the normal sas_task completion mechanism)
 	 * complete via the normal sas_task completion mechanism)
@@ -669,7 +669,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
 
 
 out:
 out:
 	scsi_eh_flush_done_q(&ha->eh_done_q);
 	scsi_eh_flush_done_q(&ha->eh_done_q);
-	SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
+	SAS_DPRINTK("--- Exit %s\n", __func__);
 	return;
 	return;
 }
 }
 
 
@@ -990,7 +990,7 @@ int __sas_task_abort(struct sas_task *task)
 	if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
 	if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
 	    task->task_state_flags & SAS_TASK_STATE_DONE) {
 	    task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__,
+		SAS_DPRINTK("%s: Task %p already finished.\n", __func__,
 			    task);
 			    task);
 		return 0;
 		return 0;
 	}
 	}

+ 1 - 1
drivers/scsi/libsrp.c

@@ -39,7 +39,7 @@ enum srp_task_attributes {
 /* tmp - will replace with SCSI logging stuff */
 /* tmp - will replace with SCSI logging stuff */
 #define eprintk(fmt, args...)					\
 #define eprintk(fmt, args...)					\
 do {								\
 do {								\
-	printk("%s(%d) " fmt, __FUNCTION__, __LINE__, ##args);	\
+	printk("%s(%d) " fmt, __func__, __LINE__, ##args);	\
 } while (0)
 } while (0)
 /* #define dprintk eprintk */
 /* #define dprintk eprintk */
 #define dprintk(fmt, args...)
 #define dprintk(fmt, args...)

+ 2 - 2
drivers/scsi/lpfc/lpfc_init.c

@@ -2083,7 +2083,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 		if (iocbq_entry == NULL) {
 		if (iocbq_entry == NULL) {
 			printk(KERN_ERR "%s: only allocated %d iocbs of "
 			printk(KERN_ERR "%s: only allocated %d iocbs of "
 				"expected %d count. Unloading driver.\n",
 				"expected %d count. Unloading driver.\n",
-				__FUNCTION__, i, LPFC_IOCB_LIST_CNT);
+				__func__, i, LPFC_IOCB_LIST_CNT);
 			error = -ENOMEM;
 			error = -ENOMEM;
 			goto out_free_iocbq;
 			goto out_free_iocbq;
 		}
 		}
@@ -2093,7 +2093,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 			kfree (iocbq_entry);
 			kfree (iocbq_entry);
 			printk(KERN_ERR "%s: failed to allocate IOTAG. "
 			printk(KERN_ERR "%s: failed to allocate IOTAG. "
 			       "Unloading driver.\n",
 			       "Unloading driver.\n",
-				__FUNCTION__);
+				__func__);
 			error = -ENOMEM;
 			error = -ENOMEM;
 			goto out_free_iocbq;
 			goto out_free_iocbq;
 		}
 		}

+ 1 - 1
drivers/scsi/lpfc/lpfc_scsi.c

@@ -341,7 +341,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
 		if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
 		if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
 			printk(KERN_ERR "%s: Too many sg segments from "
 			printk(KERN_ERR "%s: Too many sg segments from "
 			       "dma_map_sg.  Config %d, seg_cnt %d",
 			       "dma_map_sg.  Config %d, seg_cnt %d",
-			       __FUNCTION__, phba->cfg_sg_seg_cnt,
+			       __func__, phba->cfg_sg_seg_cnt,
 			       lpfc_cmd->seg_cnt);
 			       lpfc_cmd->seg_cnt);
 			scsi_dma_unmap(scsi_cmnd);
 			scsi_dma_unmap(scsi_cmnd);
 			return 1;
 			return 1;

+ 3 - 3
drivers/scsi/lpfc/lpfc_sli.c

@@ -219,7 +219,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
 	case CMD_IOCB_LOGENTRY_CN:
 	case CMD_IOCB_LOGENTRY_CN:
 	case CMD_IOCB_LOGENTRY_ASYNC_CN:
 	case CMD_IOCB_LOGENTRY_ASYNC_CN:
 		printk("%s - Unhandled SLI-3 Command x%x\n",
 		printk("%s - Unhandled SLI-3 Command x%x\n",
-				__FUNCTION__, iocb_cmnd);
+				__func__, iocb_cmnd);
 		type = LPFC_UNKNOWN_IOCB;
 		type = LPFC_UNKNOWN_IOCB;
 		break;
 		break;
 	default:
 	default:
@@ -1715,7 +1715,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 		rspiocbp = __lpfc_sli_get_iocbq(phba);
 		rspiocbp = __lpfc_sli_get_iocbq(phba);
 		if (rspiocbp == NULL) {
 		if (rspiocbp == NULL) {
 			printk(KERN_ERR "%s: out of buffers! Failing "
 			printk(KERN_ERR "%s: out of buffers! Failing "
-			       "completion.\n", __FUNCTION__);
+			       "completion.\n", __func__);
 			break;
 			break;
 		}
 		}
 
 
@@ -3793,7 +3793,7 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport,
 		break;
 		break;
 	default:
 	default:
 		printk(KERN_ERR "%s: Unknown context cmd type, value %d\n",
 		printk(KERN_ERR "%s: Unknown context cmd type, value %d\n",
-			__FUNCTION__, ctx_cmd);
+			__func__, ctx_cmd);
 		break;
 		break;
 	}
 	}
 
 

+ 1 - 1
drivers/scsi/megaraid/mega_common.h

@@ -265,7 +265,7 @@ typedef struct {
 #define ASSERT(expression)						\
 #define ASSERT(expression)						\
 	if (!(expression)) {						\
 	if (!(expression)) {						\
 	ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n",	\
 	ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n",	\
-			#expression, __FILE__, __LINE__, __FUNCTION__);	\
+			#expression, __FILE__, __LINE__, __func__);	\
 	}
 	}
 #else
 #else
 #define ASSERT(expression)
 #define ASSERT(expression)

+ 8 - 8
drivers/scsi/megaraid/megaraid_mbox.c

@@ -458,7 +458,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 
 	if (adapter == NULL) {
 	if (adapter == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-		"megaraid: out of memory, %s %d.\n", __FUNCTION__, __LINE__));
+		"megaraid: out of memory, %s %d.\n", __func__, __LINE__));
 
 
 		goto out_probe_one;
 		goto out_probe_one;
 	}
 	}
@@ -1002,7 +1002,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
 
 
 	if (!raid_dev->una_mbox64) {
 	if (!raid_dev->una_mbox64) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 		return -1;
 		return -1;
 	}
 	}
@@ -1030,7 +1030,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
 	if (!adapter->ibuf) {
 	if (!adapter->ibuf) {
 
 
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 
 
 		goto out_free_common_mbox;
 		goto out_free_common_mbox;
@@ -1052,7 +1052,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
 
 
 	if (adapter->kscb_list == NULL) {
 	if (adapter->kscb_list == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 		goto out_free_ibuf;
 		goto out_free_ibuf;
 	}
 	}
@@ -1060,7 +1060,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
 	// memory allocation for our command packets
 	// memory allocation for our command packets
 	if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
 	if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 		goto out_free_scb_list;
 		goto out_free_scb_list;
 	}
 	}
@@ -2981,7 +2981,7 @@ megaraid_mbox_product_info(adapter_t *adapter)
 
 
 	if (pinfo == NULL) {
 	if (pinfo == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 
 
 		return -1;
 		return -1;
@@ -3508,7 +3508,7 @@ megaraid_cmm_register(adapter_t *adapter)
 
 
 	if (adapter->uscb_list == NULL) {
 	if (adapter->uscb_list == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 		return -1;
 		return -1;
 	}
 	}
@@ -3879,7 +3879,7 @@ megaraid_sysfs_alloc_resources(adapter_t *adapter)
 		!raid_dev->sysfs_buffer) {
 		!raid_dev->sysfs_buffer) {
 
 
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 
 
 		rval = -ENOMEM;
 		rval = -ENOMEM;

+ 2 - 2
drivers/scsi/megaraid/megaraid_mm.c

@@ -929,7 +929,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
 			!adapter->pthru_dma_pool) {
 			!adapter->pthru_dma_pool) {
 
 
 		con_log(CL_ANN, (KERN_WARNING
 		con_log(CL_ANN, (KERN_WARNING
-			"megaraid cmm: out of memory, %s %d\n", __FUNCTION__,
+			"megaraid cmm: out of memory, %s %d\n", __func__,
 			__LINE__));
 			__LINE__));
 
 
 		rval = (-ENOMEM);
 		rval = (-ENOMEM);
@@ -957,7 +957,7 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
 
 
 			con_log(CL_ANN, (KERN_WARNING
 			con_log(CL_ANN, (KERN_WARNING
 				"megaraid cmm: out of memory, %s %d\n",
 				"megaraid cmm: out of memory, %s %d\n",
-					__FUNCTION__, __LINE__));
+					__func__, __LINE__));
 
 
 			rval = (-ENOMEM);
 			rval = (-ENOMEM);
 
 

+ 2 - 2
drivers/scsi/nsp32.c

@@ -299,9 +299,9 @@ static struct scsi_host_template nsp32_template = {
 #else
 #else
 # define NSP32_DEBUG_MASK	      0xffffff
 # define NSP32_DEBUG_MASK	      0xffffff
 # define nsp32_msg(type, args...) \
 # define nsp32_msg(type, args...) \
-	nsp32_message (__FUNCTION__, __LINE__, (type), args)
+	nsp32_message (__func__, __LINE__, (type), args)
 # define nsp32_dbg(mask, args...) \
 # define nsp32_dbg(mask, args...) \
-	nsp32_dmessage(__FUNCTION__, __LINE__, (mask), args)
+	nsp32_dmessage(__func__, __LINE__, (mask), args)
 #endif
 #endif
 
 
 #define NSP32_DEBUG_QUEUECOMMAND	BIT(0)
 #define NSP32_DEBUG_QUEUECOMMAND	BIT(0)

+ 1 - 1
drivers/scsi/nsp32_debug.c

@@ -88,7 +88,7 @@ static void print_commandk (unsigned char *command)
 	int i,s;
 	int i,s;
 //	printk(KERN_DEBUG);
 //	printk(KERN_DEBUG);
 	print_opcodek(command[0]);
 	print_opcodek(command[0]);
-	/*printk(KERN_DEBUG "%s ", __FUNCTION__);*/
+	/*printk(KERN_DEBUG "%s ", __func__);*/
 	if ((command[0] >> 5) == 6 ||
 	if ((command[0] >> 5) == 6 ||
 	    (command[0] >> 5) == 7 ) {
 	    (command[0] >> 5) == 7 ) {
 		s = 12; /* vender specific */
 		s = 12; /* vender specific */

+ 2 - 2
drivers/scsi/pcmcia/nsp_cs.c

@@ -107,9 +107,9 @@ static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
 #else
 #else
 # define NSP_DEBUG_MASK		0xffffff
 # define NSP_DEBUG_MASK		0xffffff
 # define nsp_msg(type, args...) \
 # define nsp_msg(type, args...) \
-	nsp_cs_message (__FUNCTION__, __LINE__, (type), args)
+	nsp_cs_message (__func__, __LINE__, (type), args)
 # define nsp_dbg(mask, args...) \
 # define nsp_dbg(mask, args...) \
-	nsp_cs_dmessage(__FUNCTION__, __LINE__, (mask), args)
+	nsp_cs_dmessage(__func__, __LINE__, (mask), args)
 #endif
 #endif
 
 
 #define NSP_DEBUG_QUEUECOMMAND		BIT(0)
 #define NSP_DEBUG_QUEUECOMMAND		BIT(0)

+ 1 - 1
drivers/scsi/pcmcia/nsp_debug.c

@@ -90,7 +90,7 @@ static void print_commandk (unsigned char *command)
 	int i, s;
 	int i, s;
 	printk(KERN_DEBUG);
 	printk(KERN_DEBUG);
 	print_opcodek(command[0]);
 	print_opcodek(command[0]);
-	/*printk(KERN_DEBUG "%s ", __FUNCTION__);*/
+	/*printk(KERN_DEBUG "%s ", __func__);*/
 	if ((command[0] >> 5) == 6 ||
 	if ((command[0] >> 5) == 6 ||
 	    (command[0] >> 5) == 7 ) {
 	    (command[0] >> 5) == 7 ) {
 		s = 12; /* vender specific */
 		s = 12; /* vender specific */

+ 1 - 1
drivers/scsi/ppa.c

@@ -171,7 +171,7 @@ static int device_check(ppa_struct *dev);
 
 
 #if PPA_DEBUG > 0
 #if PPA_DEBUG > 0
 #define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
 #define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
-	   y, __FUNCTION__, __LINE__); ppa_fail_func(x,y);
+	   y, __func__, __LINE__); ppa_fail_func(x,y);
 static inline void ppa_fail_func(ppa_struct *dev, int error_code)
 static inline void ppa_fail_func(ppa_struct *dev, int error_code)
 #else
 #else
 static inline void ppa_fail(ppa_struct *dev, int error_code)
 static inline void ppa_fail(ppa_struct *dev, int error_code)

+ 6 - 6
drivers/scsi/qla1280.c

@@ -1695,7 +1695,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
 	risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen;
 	risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen;
 
 
 	dprintk(1, "%s: DMA RISC code (%i) words\n",
 	dprintk(1, "%s: DMA RISC code (%i) words\n",
-			__FUNCTION__, risc_code_size);
+			__func__, risc_code_size);
 
 
 	num = 0;
 	num = 0;
 	while (risc_code_size > 0) {
 	while (risc_code_size > 0) {
@@ -1721,7 +1721,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
 		mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff;
 		mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff;
 		mb[6] = pci_dma_hi32(ha->request_dma) >> 16;
 		mb[6] = pci_dma_hi32(ha->request_dma) >> 16;
 		dprintk(2, "%s: op=%d  0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n",
 		dprintk(2, "%s: op=%d  0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n",
-				__FUNCTION__, mb[0],
+				__func__, mb[0],
 				(void *)(long)ha->request_dma,
 				(void *)(long)ha->request_dma,
 				mb[6], mb[7], mb[2], mb[3]);
 				mb[6], mb[7], mb[2], mb[3]);
 		err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
 		err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
@@ -1753,10 +1753,10 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha)
 			if (tbuf[i] != sp[i] && warn++ < 10) {
 			if (tbuf[i] != sp[i] && warn++ < 10) {
 				printk(KERN_ERR "%s: FW compare error @ "
 				printk(KERN_ERR "%s: FW compare error @ "
 						"byte(0x%x) loop#=%x\n",
 						"byte(0x%x) loop#=%x\n",
-						__FUNCTION__, i, num);
+						__func__, i, num);
 				printk(KERN_ERR "%s: FWbyte=%x  "
 				printk(KERN_ERR "%s: FWbyte=%x  "
 						"FWfromChip=%x\n",
 						"FWfromChip=%x\n",
-						__FUNCTION__, sp[i], tbuf[i]);
+						__func__, sp[i], tbuf[i]);
 				/*break; */
 				/*break; */
 			}
 			}
 		}
 		}
@@ -1781,7 +1781,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha)
 	int err;
 	int err;
 
 
 	dprintk(1, "%s: Verifying checksum of loaded RISC code.\n",
 	dprintk(1, "%s: Verifying checksum of loaded RISC code.\n",
-			__FUNCTION__);
+			__func__);
 
 
 	/* Verify checksum of loaded RISC code. */
 	/* Verify checksum of loaded RISC code. */
 	mb[0] = MBC_VERIFY_CHECKSUM;
 	mb[0] = MBC_VERIFY_CHECKSUM;
@@ -1794,7 +1794,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha)
 	}
 	}
 
 
 	/* Start firmware execution. */
 	/* Start firmware execution. */
-	dprintk(1, "%s: start firmware running.\n", __FUNCTION__);
+	dprintk(1, "%s: start firmware running.\n", __func__);
 	mb[0] = MBC_EXECUTE_FIRMWARE;
 	mb[0] = MBC_EXECUTE_FIRMWARE;
 	mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
 	mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
 	err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
 	err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);

+ 61 - 57
drivers/scsi/qla2xxx/qla_attr.c

@@ -20,18 +20,12 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
 {
 {
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	    struct device, kobj)));
 	    struct device, kobj)));
-	char *rbuf = (char *)ha->fw_dump;
 
 
 	if (ha->fw_dump_reading == 0)
 	if (ha->fw_dump_reading == 0)
 		return 0;
 		return 0;
-	if (off > ha->fw_dump_len)
-                return 0;
-	if (off + count > ha->fw_dump_len)
-		count = ha->fw_dump_len - off;
 
 
-	memcpy(buf, &rbuf[off], count);
-
-	return (count);
+	return memory_read_from_buffer(buf, count, &off, ha->fw_dump,
+					ha->fw_dump_len);
 }
 }
 
 
 static ssize_t
 static ssize_t
@@ -94,20 +88,13 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj,
 {
 {
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	    struct device, kobj)));
 	    struct device, kobj)));
-	int		size = ha->nvram_size;
-	char		*nvram_cache = ha->nvram;
 
 
-	if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
+	if (!capable(CAP_SYS_ADMIN))
 		return 0;
 		return 0;
-	if (off + count > size) {
-		size -= off;
-		count = size;
-	}
 
 
 	/* Read NVRAM data from cache. */
 	/* Read NVRAM data from cache. */
-	memcpy(buf, &nvram_cache[off], count);
-
-	return count;
+	return memory_read_from_buffer(buf, count, &off, ha->nvram,
+					ha->nvram_size);
 }
 }
 
 
 static ssize_t
 static ssize_t
@@ -175,14 +162,9 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj,
 
 
 	if (ha->optrom_state != QLA_SREADING)
 	if (ha->optrom_state != QLA_SREADING)
 		return 0;
 		return 0;
-	if (off > ha->optrom_region_size)
-		return 0;
-	if (off + count > ha->optrom_region_size)
-		count = ha->optrom_region_size - off;
-
-	memcpy(buf, &ha->optrom_buffer[off], count);
 
 
-	return count;
+	return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
+					ha->optrom_region_size);
 }
 }
 
 
 static ssize_t
 static ssize_t
@@ -374,20 +356,12 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj,
 {
 {
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
 	    struct device, kobj)));
 	    struct device, kobj)));
-	int           size = ha->vpd_size;
-	char          *vpd_cache = ha->vpd;
 
 
-	if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
+	if (!capable(CAP_SYS_ADMIN))
 		return 0;
 		return 0;
-	if (off + count > size) {
-		size -= off;
-		count = size;
-	}
 
 
 	/* Read NVRAM data from cache. */
 	/* Read NVRAM data from cache. */
-	memcpy(buf, &vpd_cache[off], count);
-
-	return count;
+	return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
 }
 }
 
 
 static ssize_t
 static ssize_t
@@ -557,8 +531,10 @@ qla2x00_serial_num_show(struct device *dev, struct device_attribute *attr,
 	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
 	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
 	uint32_t sn;
 	uint32_t sn;
 
 
-	if (IS_FWI2_CAPABLE(ha))
-		return snprintf(buf, PAGE_SIZE, "\n");
+	if (IS_FWI2_CAPABLE(ha)) {
+		qla2xxx_get_vpd_field(ha, "SN", buf, PAGE_SIZE);
+		return snprintf(buf, PAGE_SIZE, "%s\n", buf);
+	}
 
 
 	sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
 	sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
 	return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
 	return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
@@ -809,6 +785,16 @@ qla2x00_optrom_fw_version_show(struct device *dev,
 	    ha->fw_revision[3]);
 	    ha->fw_revision[3]);
 }
 }
 
 
+static ssize_t
+qla2x00_total_isp_aborts_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+	    ha->qla_stats.total_isp_aborts);
+}
+
 static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
 static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
 static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
 static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
 static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
 static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -831,6 +817,8 @@ static DEVICE_ATTR(optrom_fcode_version, S_IRUGO,
 		   qla2x00_optrom_fcode_version_show, NULL);
 		   qla2x00_optrom_fcode_version_show, NULL);
 static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
 static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
 		   NULL);
 		   NULL);
+static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
+		   NULL);
 
 
 struct device_attribute *qla2x00_host_attrs[] = {
 struct device_attribute *qla2x00_host_attrs[] = {
 	&dev_attr_driver_version,
 	&dev_attr_driver_version,
@@ -849,6 +837,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
 	&dev_attr_optrom_efi_version,
 	&dev_attr_optrom_efi_version,
 	&dev_attr_optrom_fcode_version,
 	&dev_attr_optrom_fcode_version,
 	&dev_attr_optrom_fw_version,
 	&dev_attr_optrom_fw_version,
+	&dev_attr_total_isp_aborts,
 	NULL,
 	NULL,
 };
 };
 
 
@@ -972,26 +961,39 @@ qla2x00_get_starget_port_id(struct scsi_target *starget)
 }
 }
 
 
 static void
 static void
-qla2x00_get_rport_loss_tmo(struct fc_rport *rport)
+qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
 {
 {
-	struct Scsi_Host *host = rport_to_shost(rport);
-	scsi_qla_host_t *ha = shost_priv(host);
-
-	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
+	if (timeout)
+		rport->dev_loss_tmo = timeout;
+	else
+		rport->dev_loss_tmo = 1;
 }
 }
 
 
 static void
 static void
-qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
 {
 {
 	struct Scsi_Host *host = rport_to_shost(rport);
 	struct Scsi_Host *host = rport_to_shost(rport);
-	scsi_qla_host_t *ha = shost_priv(host);
+	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
+
+	qla2x00_abort_fcport_cmds(fcport);
+
+	/*
+	 * Transport has effectively 'deleted' the rport, clear
+	 * all local references.
+	 */
+	spin_lock_irq(host->host_lock);
+	fcport->rport = NULL;
+	*((fc_port_t **)rport->dd_data) = NULL;
+	spin_unlock_irq(host->host_lock);
+}
 
 
-	if (timeout)
-		ha->port_down_retry_count = timeout;
-	else
-		ha->port_down_retry_count = 1;
+static void
+qla2x00_terminate_rport_io(struct fc_rport *rport)
+{
+	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
 
 
-	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
+	qla2x00_abort_fcport_cmds(fcport);
+	scsi_target_unblock(&rport->dev);
 }
 }
 
 
 static int
 static int
@@ -1045,6 +1047,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
 	pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
 	pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
 	pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
 	pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
 	if (IS_FWI2_CAPABLE(ha)) {
 	if (IS_FWI2_CAPABLE(ha)) {
+		pfc_host_stat->lip_count = stats->lip_cnt;
 		pfc_host_stat->tx_frames = stats->tx_frames;
 		pfc_host_stat->tx_frames = stats->tx_frames;
 		pfc_host_stat->rx_frames = stats->rx_frames;
 		pfc_host_stat->rx_frames = stats->rx_frames;
 		pfc_host_stat->dumped_frames = stats->dumped_frames;
 		pfc_host_stat->dumped_frames = stats->dumped_frames;
@@ -1173,17 +1176,16 @@ vport_create_failed_2:
 static int
 static int
 qla24xx_vport_delete(struct fc_vport *fc_vport)
 qla24xx_vport_delete(struct fc_vport *fc_vport)
 {
 {
-	scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
 	scsi_qla_host_t *vha = fc_vport->dd_data;
 	scsi_qla_host_t *vha = fc_vport->dd_data;
+	scsi_qla_host_t *pha = to_qla_parent(vha);
+
+	while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags) ||
+	    test_bit(FCPORT_UPDATE_NEEDED, &pha->dpc_flags))
+		msleep(1000);
 
 
 	qla24xx_disable_vp(vha);
 	qla24xx_disable_vp(vha);
 	qla24xx_deallocate_vp_id(vha);
 	qla24xx_deallocate_vp_id(vha);
 
 
-	mutex_lock(&ha->vport_lock);
-	ha->cur_vport_count--;
-	clear_bit(vha->vp_idx, ha->vp_idx_map);
-	mutex_unlock(&ha->vport_lock);
-
 	kfree(vha->node_name);
 	kfree(vha->node_name);
 	kfree(vha->port_name);
 	kfree(vha->port_name);
 
 
@@ -1248,11 +1250,12 @@ struct fc_function_template qla2xxx_transport_functions = {
 	.get_starget_port_id  = qla2x00_get_starget_port_id,
 	.get_starget_port_id  = qla2x00_get_starget_port_id,
 	.show_starget_port_id = 1,
 	.show_starget_port_id = 1,
 
 
-	.get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
 	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
 	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
 	.show_rport_dev_loss_tmo = 1,
 	.show_rport_dev_loss_tmo = 1,
 
 
 	.issue_fc_host_lip = qla2x00_issue_lip,
 	.issue_fc_host_lip = qla2x00_issue_lip,
+	.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
+	.terminate_rport_io = qla2x00_terminate_rport_io,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
 
 
 	.vport_create = qla24xx_vport_create,
 	.vport_create = qla24xx_vport_create,
@@ -1291,11 +1294,12 @@ struct fc_function_template qla2xxx_transport_vport_functions = {
 	.get_starget_port_id  = qla2x00_get_starget_port_id,
 	.get_starget_port_id  = qla2x00_get_starget_port_id,
 	.show_starget_port_id = 1,
 	.show_starget_port_id = 1,
 
 
-	.get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
 	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
 	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
 	.show_rport_dev_loss_tmo = 1,
 	.show_rport_dev_loss_tmo = 1,
 
 
 	.issue_fc_host_lip = qla2x00_issue_lip,
 	.issue_fc_host_lip = qla2x00_issue_lip,
+	.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
+	.terminate_rport_io = qla2x00_terminate_rport_io,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
 };
 };
 
 

+ 1 - 1
drivers/scsi/qla2xxx/qla_dbg.c

@@ -216,7 +216,7 @@ qla24xx_soft_reset(scsi_qla_host_t *ha)
 
 
 static int
 static int
 qla2xxx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint16_t *ram,
 qla2xxx_dump_ram(scsi_qla_host_t *ha, uint32_t addr, uint16_t *ram,
-    uint16_t ram_words, void **nxt)
+    uint32_t ram_words, void **nxt)
 {
 {
 	int rval;
 	int rval;
 	uint32_t cnt, stat, timer, words, idx;
 	uint32_t cnt, stat, timer, words, idx;

+ 8 - 4
drivers/scsi/qla2xxx/qla_def.h

@@ -864,7 +864,8 @@ struct link_statistics {
 	uint32_t prim_seq_err_cnt;
 	uint32_t prim_seq_err_cnt;
 	uint32_t inval_xmit_word_cnt;
 	uint32_t inval_xmit_word_cnt;
 	uint32_t inval_crc_cnt;
 	uint32_t inval_crc_cnt;
-	uint32_t unused1[0x1b];
+	uint32_t lip_cnt;
+	uint32_t unused1[0x1a];
 	uint32_t tx_frames;
 	uint32_t tx_frames;
 	uint32_t rx_frames;
 	uint32_t rx_frames;
 	uint32_t dumped_frames;
 	uint32_t dumped_frames;
@@ -1544,7 +1545,6 @@ typedef struct fc_port {
 	int login_retry;
 	int login_retry;
 	atomic_t port_down_timer;
 	atomic_t port_down_timer;
 
 
-	spinlock_t rport_lock;
 	struct fc_rport *rport, *drport;
 	struct fc_rport *rport, *drport;
 	u32 supported_classes;
 	u32 supported_classes;
 
 
@@ -2155,6 +2155,10 @@ struct qla_chip_state_84xx {
 	uint32_t gold_fw_version;
 	uint32_t gold_fw_version;
 };
 };
 
 
+struct qla_statistics {
+	uint32_t total_isp_aborts;
+};
+
 /*
 /*
  * Linux Host Adapter structure
  * Linux Host Adapter structure
  */
  */
@@ -2166,7 +2170,6 @@ typedef struct scsi_qla_host {
 	struct pci_dev	*pdev;
 	struct pci_dev	*pdev;
 
 
 	unsigned long	host_no;
 	unsigned long	host_no;
-	unsigned long	instance;
 
 
 	volatile struct {
 	volatile struct {
 		uint32_t	init_done		:1;
 		uint32_t	init_done		:1;
@@ -2515,7 +2518,7 @@ typedef struct scsi_qla_host {
 
 
 	uint8_t		model_number[16+1];
 	uint8_t		model_number[16+1];
 #define BINZERO		"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 #define BINZERO		"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
-	char		*model_desc;
+	char		model_desc[80];
 	uint8_t		adapter_id[16+1];
 	uint8_t		adapter_id[16+1];
 
 
 	uint8_t		*node_name;
 	uint8_t		*node_name;
@@ -2596,6 +2599,7 @@ typedef struct scsi_qla_host {
 	int		cur_vport_count;
 	int		cur_vport_count;
 
 
 	struct qla_chip_state_84xx *cs84xx;
 	struct qla_chip_state_84xx *cs84xx;
+	struct qla_statistics qla_stats;
 } scsi_qla_host_t;
 } scsi_qla_host_t;
 
 
 
 

+ 4 - 1
drivers/scsi/qla2xxx/qla_gbl.h

@@ -62,7 +62,7 @@ extern int ql2xfdmienable;
 extern int ql2xallocfwdump;
 extern int ql2xallocfwdump;
 extern int ql2xextended_error_logging;
 extern int ql2xextended_error_logging;
 extern int ql2xqfullrampup;
 extern int ql2xqfullrampup;
-extern int num_hosts;
+extern int ql2xiidmaenable;
 
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
@@ -71,6 +71,8 @@ extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum
 extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t,
 extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t,
     uint16_t, uint16_t);
     uint16_t, uint16_t);
 
 
+extern void qla2x00_abort_fcport_cmds(fc_port_t *);
+
 /*
 /*
  * Global Functions in qla_mid.c source file.
  * Global Functions in qla_mid.c source file.
  */
  */
@@ -312,6 +314,7 @@ extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t,
     uint16_t, uint16_t);
     uint16_t, uint16_t);
 
 
 extern void qla2xxx_get_flash_info(scsi_qla_host_t *);
 extern void qla2xxx_get_flash_info(scsi_qla_host_t *);
+extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
 
 
 /*
 /*
  * Global Function Prototypes in qla_dbg.c source file.
  * Global Function Prototypes in qla_dbg.c source file.

+ 6 - 0
drivers/scsi/qla2xxx/qla_gs.c

@@ -1661,6 +1661,12 @@ qla2x00_fdmi_register(scsi_qla_host_t *ha)
 {
 {
 	int rval;
 	int rval;
 
 
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		DEBUG2(printk("scsi(%ld): FDMI unsupported on "
+		    "ISP2100/ISP2200.\n", ha->host_no));
+		return QLA_SUCCESS;
+	}
+
 	rval = qla2x00_mgmt_svr_login(ha);
 	rval = qla2x00_mgmt_svr_login(ha);
 	if (rval)
 	if (rval)
 		return rval;
 		return rval;

+ 73 - 60
drivers/scsi/qla2xxx/qla_init.c

@@ -334,6 +334,8 @@ static int
 qla2x00_isp_firmware(scsi_qla_host_t *ha)
 qla2x00_isp_firmware(scsi_qla_host_t *ha)
 {
 {
 	int  rval;
 	int  rval;
+	uint16_t loop_id, topo, sw_cap;
+	uint8_t domain, area, al_pa;
 
 
 	/* Assume loading risc code */
 	/* Assume loading risc code */
 	rval = QLA_FUNCTION_FAILED;
 	rval = QLA_FUNCTION_FAILED;
@@ -345,6 +347,11 @@ qla2x00_isp_firmware(scsi_qla_host_t *ha)
 
 
 		/* Verify checksum of loaded RISC code. */
 		/* Verify checksum of loaded RISC code. */
 		rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address);
 		rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address);
+		if (rval == QLA_SUCCESS) {
+			/* And, verify we are not in ROM code. */
+			rval = qla2x00_get_adapter_id(ha, &loop_id, &al_pa,
+			    &area, &domain, &topo, &sw_cap);
+		}
 	}
 	}
 
 
 	if (rval) {
 	if (rval) {
@@ -722,7 +729,7 @@ qla24xx_chip_diag(scsi_qla_host_t *ha)
 	/* Perform RISC reset. */
 	/* Perform RISC reset. */
 	qla24xx_reset_risc(ha);
 	qla24xx_reset_risc(ha);
 
 
-	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
+	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * ha->request_q_length;
 
 
 	rval = qla2x00_mbx_reg_test(ha);
 	rval = qla2x00_mbx_reg_test(ha);
 	if (rval) {
 	if (rval) {
@@ -768,42 +775,16 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 		mem_size = (ha->fw_memory_size - 0x100000 + 1) *
 		mem_size = (ha->fw_memory_size - 0x100000 + 1) *
 		    sizeof(uint32_t);
 		    sizeof(uint32_t);
 
 
-		/* Allocate memory for Extended Trace Buffer. */
-		tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
-		    GFP_KERNEL);
-		if (!tc) {
-			qla_printk(KERN_WARNING, ha, "Unable to allocate "
-			    "(%d KB) for EFT.\n", EFT_SIZE / 1024);
-			goto cont_alloc;
-		}
-
-		memset(tc, 0, EFT_SIZE);
-		rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS);
-		if (rval) {
-			qla_printk(KERN_WARNING, ha, "Unable to initialize "
-			    "EFT (%d).\n", rval);
-			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
-			    tc_dma);
-			goto cont_alloc;
-		}
-
-		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
-		    EFT_SIZE / 1024);
-
-		eft_size = EFT_SIZE;
-		ha->eft_dma = tc_dma;
-		ha->eft = tc;
-
 		/* Allocate memory for Fibre Channel Event Buffer. */
 		/* Allocate memory for Fibre Channel Event Buffer. */
 		if (!IS_QLA25XX(ha))
 		if (!IS_QLA25XX(ha))
-			goto cont_alloc;
+			goto try_eft;
 
 
 		tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
 		tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
 		    GFP_KERNEL);
 		    GFP_KERNEL);
 		if (!tc) {
 		if (!tc) {
 			qla_printk(KERN_WARNING, ha, "Unable to allocate "
 			qla_printk(KERN_WARNING, ha, "Unable to allocate "
 			    "(%d KB) for FCE.\n", FCE_SIZE / 1024);
 			    "(%d KB) for FCE.\n", FCE_SIZE / 1024);
-			goto cont_alloc;
+			goto try_eft;
 		}
 		}
 
 
 		memset(tc, 0, FCE_SIZE);
 		memset(tc, 0, FCE_SIZE);
@@ -815,7 +796,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 			dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
 			dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
 			    tc_dma);
 			    tc_dma);
 			ha->flags.fce_enabled = 0;
 			ha->flags.fce_enabled = 0;
-			goto cont_alloc;
+			goto try_eft;
 		}
 		}
 
 
 		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
 		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
@@ -825,6 +806,32 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 		ha->flags.fce_enabled = 1;
 		ha->flags.fce_enabled = 1;
 		ha->fce_dma = tc_dma;
 		ha->fce_dma = tc_dma;
 		ha->fce = tc;
 		ha->fce = tc;
+try_eft:
+		/* Allocate memory for Extended Trace Buffer. */
+		tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
+		    GFP_KERNEL);
+		if (!tc) {
+			qla_printk(KERN_WARNING, ha, "Unable to allocate "
+			    "(%d KB) for EFT.\n", EFT_SIZE / 1024);
+			goto cont_alloc;
+		}
+
+		memset(tc, 0, EFT_SIZE);
+		rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS);
+		if (rval) {
+			qla_printk(KERN_WARNING, ha, "Unable to initialize "
+			    "EFT (%d).\n", rval);
+			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
+			    tc_dma);
+			goto cont_alloc;
+		}
+
+		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
+		    EFT_SIZE / 1024);
+
+		eft_size = EFT_SIZE;
+		ha->eft_dma = tc_dma;
+		ha->eft = tc;
 	}
 	}
 cont_alloc:
 cont_alloc:
 	req_q_size = ha->request_q_length * sizeof(request_t);
 	req_q_size = ha->request_q_length * sizeof(request_t);
@@ -1501,18 +1508,25 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de
 		index = (ha->pdev->subsystem_device & 0xff);
 		index = (ha->pdev->subsystem_device & 0xff);
 		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		    index < QLA_MODEL_NAMES)
 		    index < QLA_MODEL_NAMES)
-			ha->model_desc = qla2x00_model_name[index * 2 + 1];
+			strncpy(ha->model_desc,
+			    qla2x00_model_name[index * 2 + 1],
+			    sizeof(ha->model_desc) - 1);
 	} else {
 	} else {
 		index = (ha->pdev->subsystem_device & 0xff);
 		index = (ha->pdev->subsystem_device & 0xff);
 		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
 		    index < QLA_MODEL_NAMES) {
 		    index < QLA_MODEL_NAMES) {
 			strcpy(ha->model_number,
 			strcpy(ha->model_number,
 			    qla2x00_model_name[index * 2]);
 			    qla2x00_model_name[index * 2]);
-			ha->model_desc = qla2x00_model_name[index * 2 + 1];
+			strncpy(ha->model_desc,
+			    qla2x00_model_name[index * 2 + 1],
+			    sizeof(ha->model_desc) - 1);
 		} else {
 		} else {
 			strcpy(ha->model_number, def);
 			strcpy(ha->model_number, def);
 		}
 		}
 	}
 	}
+	if (IS_FWI2_CAPABLE(ha))
+		qla2xxx_get_vpd_field(ha, "\x82", ha->model_desc,
+		    sizeof(ha->model_desc));
 }
 }
 
 
 /* On sparc systems, obtain port and node WWN from firmware
 /* On sparc systems, obtain port and node WWN from firmware
@@ -1864,12 +1878,11 @@ qla2x00_rport_del(void *data)
 {
 {
 	fc_port_t *fcport = data;
 	fc_port_t *fcport = data;
 	struct fc_rport *rport;
 	struct fc_rport *rport;
-	unsigned long flags;
 
 
-	spin_lock_irqsave(&fcport->rport_lock, flags);
+	spin_lock_irq(fcport->ha->host->host_lock);
 	rport = fcport->drport;
 	rport = fcport->drport;
 	fcport->drport = NULL;
 	fcport->drport = NULL;
-	spin_unlock_irqrestore(&fcport->rport_lock, flags);
+	spin_unlock_irq(fcport->ha->host->host_lock);
 	if (rport)
 	if (rport)
 		fc_remote_port_delete(rport);
 		fc_remote_port_delete(rport);
 }
 }
@@ -1898,7 +1911,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
 	atomic_set(&fcport->state, FCS_UNCONFIGURED);
 	atomic_set(&fcport->state, FCS_UNCONFIGURED);
 	fcport->flags = FCF_RLC_SUPPORT;
 	fcport->flags = FCF_RLC_SUPPORT;
 	fcport->supported_classes = FC_COS_UNSPECIFIED;
 	fcport->supported_classes = FC_COS_UNSPECIFIED;
-	spin_lock_init(&fcport->rport_lock);
 
 
 	return fcport;
 	return fcport;
 }
 }
@@ -2007,8 +2019,10 @@ qla2x00_configure_loop(scsi_qla_host_t *ha)
 	if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
 	if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
 		if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
 		if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
 			set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
 			set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
-		if (test_bit(RSCN_UPDATE, &save_flags))
+		if (test_bit(RSCN_UPDATE, &save_flags)) {
+			ha->flags.rscn_queue_overflow = 1;
 			set_bit(RSCN_UPDATE, &ha->dpc_flags);
 			set_bit(RSCN_UPDATE, &ha->dpc_flags);
+		}
 	}
 	}
 
 
 	return (rval);
 	return (rval);
@@ -2243,28 +2257,24 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
 {
 	struct fc_rport_identifiers rport_ids;
 	struct fc_rport_identifiers rport_ids;
 	struct fc_rport *rport;
 	struct fc_rport *rport;
-	unsigned long flags;
 
 
 	if (fcport->drport)
 	if (fcport->drport)
 		qla2x00_rport_del(fcport);
 		qla2x00_rport_del(fcport);
-	if (fcport->rport)
-		return;
 
 
 	rport_ids.node_name = wwn_to_u64(fcport->node_name);
 	rport_ids.node_name = wwn_to_u64(fcport->node_name);
 	rport_ids.port_name = wwn_to_u64(fcport->port_name);
 	rport_ids.port_name = wwn_to_u64(fcport->port_name);
 	rport_ids.port_id = fcport->d_id.b.domain << 16 |
 	rport_ids.port_id = fcport->d_id.b.domain << 16 |
 	    fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
 	    fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
 	rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
 	rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
-	rport = fc_remote_port_add(ha->host, 0, &rport_ids);
+	fcport->rport = rport = fc_remote_port_add(ha->host, 0, &rport_ids);
 	if (!rport) {
 	if (!rport) {
 		qla_printk(KERN_WARNING, ha,
 		qla_printk(KERN_WARNING, ha,
 		    "Unable to allocate fc remote port!\n");
 		    "Unable to allocate fc remote port!\n");
 		return;
 		return;
 	}
 	}
-	spin_lock_irqsave(&fcport->rport_lock, flags);
-	fcport->rport = rport;
+	spin_lock_irq(fcport->ha->host->host_lock);
 	*((fc_port_t **)rport->dd_data) = fcport;
 	*((fc_port_t **)rport->dd_data) = fcport;
-	spin_unlock_irqrestore(&fcport->rport_lock, flags);
+	spin_unlock_irq(fcport->ha->host->host_lock);
 
 
 	rport->supported_classes = fcport->supported_classes;
 	rport->supported_classes = fcport->supported_classes;
 
 
@@ -2565,7 +2575,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
 		} else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
 		} else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
 			kfree(swl);
 			kfree(swl);
 			swl = NULL;
 			swl = NULL;
-		} else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
+		} else if (ql2xiidmaenable &&
+		    qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
 			qla2x00_gpsc(ha, swl);
 			qla2x00_gpsc(ha, swl);
 		}
 		}
 	}
 	}
@@ -3220,7 +3231,8 @@ qla2x00_update_fcports(scsi_qla_host_t *ha)
 
 
 	/* Go with deferred removal of rport references. */
 	/* Go with deferred removal of rport references. */
 	list_for_each_entry(fcport, &ha->fcports, list)
 	list_for_each_entry(fcport, &ha->fcports, list)
-		if (fcport->drport)
+		if (fcport->drport &&
+		    atomic_read(&fcport->state) != FCS_UNCONFIGURED)
 			qla2x00_rport_del(fcport);
 			qla2x00_rport_del(fcport);
 }
 }
 
 
@@ -3243,6 +3255,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 	if (ha->flags.online) {
 	if (ha->flags.online) {
 		ha->flags.online = 0;
 		ha->flags.online = 0;
 		clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
 		clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		ha->qla_stats.total_isp_aborts++;
 
 
 		qla_printk(KERN_INFO, ha,
 		qla_printk(KERN_INFO, ha,
 		    "Performing ISP error recovery - ha= %p.\n", ha);
 		    "Performing ISP error recovery - ha= %p.\n", ha);
@@ -3283,17 +3296,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 			ha->isp_abort_cnt = 0;
 			ha->isp_abort_cnt = 0;
 			clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
 			clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
 
 
-			if (ha->eft) {
-				memset(ha->eft, 0, EFT_SIZE);
-				rval = qla2x00_enable_eft_trace(ha,
-				    ha->eft_dma, EFT_NUM_BUFFERS);
-				if (rval) {
-					qla_printk(KERN_WARNING, ha,
-					    "Unable to reinitialize EFT "
-					    "(%d).\n", rval);
-				}
-			}
-
 			if (ha->fce) {
 			if (ha->fce) {
 				ha->flags.fce_enabled = 1;
 				ha->flags.fce_enabled = 1;
 				memset(ha->fce, 0,
 				memset(ha->fce, 0,
@@ -3308,6 +3310,17 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 					ha->flags.fce_enabled = 0;
 					ha->flags.fce_enabled = 0;
 				}
 				}
 			}
 			}
+
+			if (ha->eft) {
+				memset(ha->eft, 0, EFT_SIZE);
+				rval = qla2x00_enable_eft_trace(ha,
+				    ha->eft_dma, EFT_NUM_BUFFERS);
+				if (rval) {
+					qla_printk(KERN_WARNING, ha,
+					    "Unable to reinitialize EFT "
+					    "(%d).\n", rval);
+				}
+			}
 		} else {	/* failed the ISP abort */
 		} else {	/* failed the ISP abort */
 			ha->flags.online = 1;
 			ha->flags.online = 1;
 			if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
 			if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
@@ -4026,8 +4039,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
 	ret = qla2x00_stop_firmware(ha);
 	ret = qla2x00_stop_firmware(ha);
 	for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
 	for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
 	    retries ; retries--) {
 	    retries ; retries--) {
-		qla2x00_reset_chip(ha);
-		if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
+		ha->isp_ops->reset_chip(ha);
+		if (ha->isp_ops->chip_diag(ha) != QLA_SUCCESS)
 			continue;
 			continue;
 		if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
 		if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
 			continue;
 			continue;
@@ -4049,7 +4062,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha)
 	rval = qla2x00_fw_ready(ha->parent);
 	rval = qla2x00_fw_ready(ha->parent);
 	if (rval == QLA_SUCCESS) {
 	if (rval == QLA_SUCCESS) {
 		clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
 		clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
-		qla2x00_marker(ha->parent, 0, 0, MK_SYNC_ALL);
+		qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
 	}
 	}
 
 
 	ha->flags.management_server_logged_in = 0;
 	ha->flags.management_server_logged_in = 0;

+ 8 - 6
drivers/scsi/qla2xxx/qla_iocb.c

@@ -454,10 +454,11 @@ qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
 {
 {
 	int ret;
 	int ret;
 	unsigned long flags = 0;
 	unsigned long flags = 0;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&pha->hardware_lock, flags);
 	ret = __qla2x00_marker(ha, loop_id, lun, type);
 	ret = __qla2x00_marker(ha, loop_id, lun, type);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
 
 
 	return (ret);
 	return (ret);
 }
 }
@@ -672,7 +673,7 @@ qla24xx_start_scsi(srb_t *sp)
 {
 {
 	int		ret, nseg;
 	int		ret, nseg;
 	unsigned long   flags;
 	unsigned long   flags;
-	scsi_qla_host_t	*ha;
+	scsi_qla_host_t	*ha, *pha;
 	struct scsi_cmnd *cmd;
 	struct scsi_cmnd *cmd;
 	uint32_t	*clr_ptr;
 	uint32_t	*clr_ptr;
 	uint32_t        index;
 	uint32_t        index;
@@ -686,6 +687,7 @@ qla24xx_start_scsi(srb_t *sp)
 	/* Setup device pointers. */
 	/* Setup device pointers. */
 	ret = 0;
 	ret = 0;
 	ha = sp->ha;
 	ha = sp->ha;
+	pha = to_qla_parent(ha);
 	reg = &ha->iobase->isp24;
 	reg = &ha->iobase->isp24;
 	cmd = sp->cmd;
 	cmd = sp->cmd;
 	/* So we know we haven't pci_map'ed anything yet */
 	/* So we know we haven't pci_map'ed anything yet */
@@ -700,7 +702,7 @@ qla24xx_start_scsi(srb_t *sp)
 	}
 	}
 
 
 	/* Acquire ring specific lock */
 	/* Acquire ring specific lock */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&pha->hardware_lock, flags);
 
 
 	/* Check for room in outstanding command list. */
 	/* Check for room in outstanding command list. */
 	handle = ha->current_outstanding_cmd;
 	handle = ha->current_outstanding_cmd;
@@ -795,14 +797,14 @@ qla24xx_start_scsi(srb_t *sp)
 	    ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
 	    ha->response_ring_ptr->signature != RESPONSE_PROCESSED)
 		qla24xx_process_response_queue(ha);
 		qla24xx_process_response_queue(ha);
 
 
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
 	return QLA_SUCCESS;
 	return QLA_SUCCESS;
 
 
 queuing_error:
 queuing_error:
 	if (tot_dsds)
 	if (tot_dsds)
 		scsi_dma_unmap(cmd);
 		scsi_dma_unmap(cmd);
 
 
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
 
 
 	return QLA_FUNCTION_FAILED;
 	return QLA_FUNCTION_FAILED;
 }
 }

+ 0 - 4
drivers/scsi/qla2xxx/qla_isr.c

@@ -542,10 +542,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
 		break;
 		break;
 
 
 	case MBA_PORT_UPDATE:		/* Port database update */
 	case MBA_PORT_UPDATE:		/* Port database update */
-		/* Only handle SCNs for our Vport index. */
-		if (ha->parent && ha->vp_idx != (mb[3] & 0xff))
-			break;
-
 		/*
 		/*
 		 * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
 		 * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
 		 * event etc. earlier indicating loop is down) then process
 		 * event etc. earlier indicating loop is down) then process

+ 6 - 3
drivers/scsi/qla2xxx/qla_mbx.c

@@ -918,6 +918,8 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
 	rval = qla2x00_mailbox_command(ha, mcp);
 	rval = qla2x00_mailbox_command(ha, mcp);
 	if (mcp->mb[0] == MBS_COMMAND_ERROR)
 	if (mcp->mb[0] == MBS_COMMAND_ERROR)
 		rval = QLA_COMMAND_ERROR;
 		rval = QLA_COMMAND_ERROR;
+	else if (mcp->mb[0] == MBS_INVALID_COMMAND)
+		rval = QLA_INVALID_COMMAND;
 
 
 	/* Return data. */
 	/* Return data. */
 	*id = mcp->mb[1];
 	*id = mcp->mb[1];
@@ -2161,17 +2163,18 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
 	struct abort_entry_24xx *abt;
 	struct abort_entry_24xx *abt;
 	dma_addr_t	abt_dma;
 	dma_addr_t	abt_dma;
 	uint32_t	handle;
 	uint32_t	handle;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
 
 	fcport = sp->fcport;
 	fcport = sp->fcport;
 
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&pha->hardware_lock, flags);
 	for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
 	for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
-		if (ha->outstanding_cmds[handle] == sp)
+		if (pha->outstanding_cmds[handle] == sp)
 			break;
 			break;
 	}
 	}
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
 	if (handle == MAX_OUTSTANDING_COMMANDS) {
 	if (handle == MAX_OUTSTANDING_COMMANDS) {
 		/* Command not found. */
 		/* Command not found. */
 		return QLA_FUNCTION_FAILED;
 		return QLA_FUNCTION_FAILED;

+ 6 - 10
drivers/scsi/qla2xxx/qla_mid.c

@@ -43,6 +43,7 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
 
 
 	set_bit(vp_id, ha->vp_idx_map);
 	set_bit(vp_id, ha->vp_idx_map);
 	ha->num_vhosts++;
 	ha->num_vhosts++;
+	ha->cur_vport_count++;
 	vha->vp_idx = vp_id;
 	vha->vp_idx = vp_id;
 	list_add_tail(&vha->vp_list, &ha->vp_list);
 	list_add_tail(&vha->vp_list, &ha->vp_list);
 	mutex_unlock(&ha->vport_lock);
 	mutex_unlock(&ha->vport_lock);
@@ -58,6 +59,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
 	mutex_lock(&ha->vport_lock);
 	mutex_lock(&ha->vport_lock);
 	vp_id = vha->vp_idx;
 	vp_id = vha->vp_idx;
 	ha->num_vhosts--;
 	ha->num_vhosts--;
+	ha->cur_vport_count--;
 	clear_bit(vp_id, ha->vp_idx_map);
 	clear_bit(vp_id, ha->vp_idx_map);
 	list_del(&vha->vp_list);
 	list_del(&vha->vp_list);
 	mutex_unlock(&ha->vport_lock);
 	mutex_unlock(&ha->vport_lock);
@@ -103,8 +105,8 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
 		    "loop_id=0x%04x :%x\n",
 		    "loop_id=0x%04x :%x\n",
 		    vha->host_no, fcport->loop_id, fcport->vp_idx));
 		    vha->host_no, fcport->loop_id, fcport->vp_idx));
 
 
-		atomic_set(&fcport->state, FCS_DEVICE_DEAD);
 		qla2x00_mark_device_lost(vha, fcport, 0, 0);
 		qla2x00_mark_device_lost(vha, fcport, 0, 0);
+		atomic_set(&fcport->state, FCS_UNCONFIGURED);
 	}
 	}
 }
 }
 
 
@@ -276,7 +278,8 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
 		clear_bit(RESET_ACTIVE, &vha->dpc_flags);
 		clear_bit(RESET_ACTIVE, &vha->dpc_flags);
 	}
 	}
 
 
-	if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
+	if (atomic_read(&vha->vp_state) == VP_ACTIVE &&
+	    test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
 		if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
 		if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
 			qla2x00_loop_resync(vha);
 			qla2x00_loop_resync(vha);
 			clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
 			clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
@@ -390,7 +393,6 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 	vha->parent = ha;
 	vha->parent = ha;
 	vha->fc_vport = fc_vport;
 	vha->fc_vport = fc_vport;
 	vha->device_flags = 0;
 	vha->device_flags = 0;
-	vha->instance = num_hosts;
 	vha->vp_idx = qla24xx_allocate_vp_id(vha);
 	vha->vp_idx = qla24xx_allocate_vp_id(vha);
 	if (vha->vp_idx > ha->max_npiv_vports) {
 	if (vha->vp_idx > ha->max_npiv_vports) {
 		DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
 		DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
@@ -428,7 +430,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 	host->max_cmd_len = MAX_CMDSZ;
 	host->max_cmd_len = MAX_CMDSZ;
 	host->max_channel = MAX_BUSES - 1;
 	host->max_channel = MAX_BUSES - 1;
 	host->max_lun = MAX_LUNS;
 	host->max_lun = MAX_LUNS;
-	host->unique_id = vha->instance;
+	host->unique_id = host->host_no;
 	host->max_id = MAX_TARGETS_2200;
 	host->max_id = MAX_TARGETS_2200;
 	host->transportt = qla2xxx_transport_vport_template;
 	host->transportt = qla2xxx_transport_vport_template;
 
 
@@ -436,12 +438,6 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 	    vha->host_no, vha));
 	    vha->host_no, vha));
 
 
 	vha->flags.init_done = 1;
 	vha->flags.init_done = 1;
-	num_hosts++;
-
-	mutex_lock(&ha->vport_lock);
-	set_bit(vha->vp_idx, ha->vp_idx_map);
-	ha->cur_vport_count++;
-	mutex_unlock(&ha->vport_lock);
 
 
 	return vha;
 	return vha;
 
 

+ 59 - 35
drivers/scsi/qla2xxx/qla_os.c

@@ -27,7 +27,6 @@ char qla2x00_version_str[40];
  */
  */
 static struct kmem_cache *srb_cachep;
 static struct kmem_cache *srb_cachep;
 
 
-int num_hosts;
 int ql2xlogintimeout = 20;
 int ql2xlogintimeout = 20;
 module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xlogintimeout,
 MODULE_PARM_DESC(ql2xlogintimeout,
@@ -87,6 +86,13 @@ MODULE_PARM_DESC(ql2xqfullrampup,
 		"depth for a device after a queue-full condition has been "
 		"depth for a device after a queue-full condition has been "
 		"detected.  Default is 120 seconds.");
 		"detected.  Default is 120 seconds.");
 
 
+int ql2xiidmaenable=1;
+module_param(ql2xiidmaenable, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xiidmaenable,
+		"Enables iIDMA settings "
+		"Default is 1 - perform iIDMA. 0 - no iIDMA.");
+
+
 /*
 /*
  * SCSI host template entry points
  * SCSI host template entry points
  */
  */
@@ -388,7 +394,7 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 	}
 	}
 
 
 	/* Close window on fcport/rport state-transitioning. */
 	/* Close window on fcport/rport state-transitioning. */
-	if (!*(fc_port_t **)rport->dd_data) {
+	if (fcport->drport) {
 		cmd->result = DID_IMM_RETRY << 16;
 		cmd->result = DID_IMM_RETRY << 16;
 		goto qc_fail_command;
 		goto qc_fail_command;
 	}
 	}
@@ -443,7 +449,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 	int rval;
 	int rval;
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
-	if (unlikely(pci_channel_offline(ha->pdev))) {
+	if (unlikely(pci_channel_offline(pha->pdev))) {
 		cmd->result = DID_REQUEUE << 16;
 		cmd->result = DID_REQUEUE << 16;
 		goto qc24_fail_command;
 		goto qc24_fail_command;
 	}
 	}
@@ -455,7 +461,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 	}
 	}
 
 
 	/* Close window on fcport/rport state-transitioning. */
 	/* Close window on fcport/rport state-transitioning. */
-	if (!*(fc_port_t **)rport->dd_data) {
+	if (fcport->drport) {
 		cmd->result = DID_IMM_RETRY << 16;
 		cmd->result = DID_IMM_RETRY << 16;
 		goto qc24_fail_command;
 		goto qc24_fail_command;
 	}
 	}
@@ -617,6 +623,40 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
 	return (return_status);
 	return (return_status);
 }
 }
 
 
+void
+qla2x00_abort_fcport_cmds(fc_port_t *fcport)
+{
+	int cnt;
+	unsigned long flags;
+	srb_t *sp;
+	scsi_qla_host_t *ha = fcport->ha;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
+
+	spin_lock_irqsave(&pha->hardware_lock, flags);
+	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+		sp = pha->outstanding_cmds[cnt];
+		if (!sp)
+			continue;
+		if (sp->fcport != fcport)
+			continue;
+
+		spin_unlock_irqrestore(&pha->hardware_lock, flags);
+		if (ha->isp_ops->abort_command(ha, sp)) {
+			DEBUG2(qla_printk(KERN_WARNING, ha,
+			    "Abort failed --  %lx\n", sp->cmd->serial_number));
+		} else {
+			if (qla2x00_eh_wait_on_command(ha, sp->cmd) !=
+			    QLA_SUCCESS)
+				DEBUG2(qla_printk(KERN_WARNING, ha,
+				    "Abort failed while waiting --  %lx\n",
+				    sp->cmd->serial_number));
+
+		}
+		spin_lock_irqsave(&pha->hardware_lock, flags);
+	}
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
+}
+
 static void
 static void
 qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
 qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
 {
 {
@@ -1073,7 +1113,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
 	else
 	else
 		scsi_deactivate_tcq(sdev, ha->max_q_depth);
 		scsi_deactivate_tcq(sdev, ha->max_q_depth);
 
 
-	rport->dev_loss_tmo = ha->port_down_retry_count + 5;
+	rport->dev_loss_tmo = ha->port_down_retry_count;
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1629,9 +1669,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	}
 	}
 	host->can_queue = ha->request_q_length + 128;
 	host->can_queue = ha->request_q_length + 128;
 
 
-	/* load the F/W, read paramaters, and init the H/W */
-	ha->instance = num_hosts;
-
 	mutex_init(&ha->vport_lock);
 	mutex_init(&ha->vport_lock);
 	init_completion(&ha->mbx_cmd_comp);
 	init_completion(&ha->mbx_cmd_comp);
 	complete(&ha->mbx_cmd_comp);
 	complete(&ha->mbx_cmd_comp);
@@ -1679,7 +1716,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 
 	host->this_id = 255;
 	host->this_id = 255;
 	host->cmd_per_lun = 3;
 	host->cmd_per_lun = 3;
-	host->unique_id = ha->instance;
+	host->unique_id = host->host_no;
 	host->max_cmd_len = MAX_CMDSZ;
 	host->max_cmd_len = MAX_CMDSZ;
 	host->max_channel = MAX_BUSES - 1;
 	host->max_channel = MAX_BUSES - 1;
 	host->max_lun = MAX_LUNS;
 	host->max_lun = MAX_LUNS;
@@ -1700,8 +1737,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	ha->flags.init_done = 1;
 	ha->flags.init_done = 1;
 	ha->flags.online = 1;
 	ha->flags.online = 1;
 
 
-	num_hosts++;
-
 	ret = scsi_add_host(host, &pdev->dev);
 	ret = scsi_add_host(host, &pdev->dev);
 	if (ret)
 	if (ret)
 		goto probe_failed;
 		goto probe_failed;
@@ -1813,27 +1848,21 @@ static inline void
 qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
 qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
     int defer)
     int defer)
 {
 {
-	unsigned long flags;
 	struct fc_rport *rport;
 	struct fc_rport *rport;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
 	if (!fcport->rport)
 	if (!fcport->rport)
 		return;
 		return;
 
 
 	rport = fcport->rport;
 	rport = fcport->rport;
 	if (defer) {
 	if (defer) {
-		spin_lock_irqsave(&fcport->rport_lock, flags);
+		spin_lock_irq(ha->host->host_lock);
 		fcport->drport = rport;
 		fcport->drport = rport;
-		fcport->rport = NULL;
-		*(fc_port_t **)rport->dd_data = NULL;
-		spin_unlock_irqrestore(&fcport->rport_lock, flags);
-		set_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags);
-	} else {
-		spin_lock_irqsave(&fcport->rport_lock, flags);
-		fcport->rport = NULL;
-		*(fc_port_t **)rport->dd_data = NULL;
-		spin_unlock_irqrestore(&fcport->rport_lock, flags);
+		spin_unlock_irq(ha->host->host_lock);
+		set_bit(FCPORT_UPDATE_NEEDED, &pha->dpc_flags);
+		qla2xxx_wake_dpc(pha);
+	} else
 		fc_remote_port_delete(rport);
 		fc_remote_port_delete(rport);
-	}
 }
 }
 
 
 /*
 /*
@@ -1903,7 +1932,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
 	list_for_each_entry(fcport, &pha->fcports, list) {
 	list_for_each_entry(fcport, &pha->fcports, list) {
-		if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
+		if (ha->vp_idx != fcport->vp_idx)
 			continue;
 			continue;
 		/*
 		/*
 		 * No point in marking the device as lost, if the device is
 		 * No point in marking the device as lost, if the device is
@@ -1911,17 +1940,10 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 		 */
 		 */
 		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
 		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
 			continue;
 			continue;
-		if (atomic_read(&fcport->state) == FCS_ONLINE) {
-			if (defer)
-				qla2x00_schedule_rport_del(ha, fcport, defer);
-			else if (ha->vp_idx == fcport->vp_idx)
-				qla2x00_schedule_rport_del(ha, fcport, defer);
-		}
+		if (atomic_read(&fcport->state) == FCS_ONLINE)
+			qla2x00_schedule_rport_del(ha, fcport, defer);
 		atomic_set(&fcport->state, FCS_DEVICE_LOST);
 		atomic_set(&fcport->state, FCS_DEVICE_LOST);
 	}
 	}
-
-	if (defer)
-		qla2xxx_wake_dpc(ha);
 }
 }
 
 
 /*
 /*
@@ -2156,7 +2178,7 @@ qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
 static int
 static int
 qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
 qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
 {
 {
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 
 	if (!locked)
 	if (!locked)
@@ -2313,8 +2335,10 @@ qla2x00_do_dpc(void *data)
 			    ha->host_no));
 			    ha->host_no));
 		}
 		}
 
 
-		if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags))
+		if (test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags)) {
 			qla2x00_update_fcports(ha);
 			qla2x00_update_fcports(ha);
+			clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags);
+		}
 
 
 		if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) &&
 		if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) &&
 		    (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) {
 		    (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) {

+ 45 - 3
drivers/scsi/qla2xxx/qla_sup.c

@@ -869,11 +869,9 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
 	uint32_t i;
 	uint32_t i;
 	uint32_t *dwptr;
 	uint32_t *dwptr;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-	unsigned long flags;
 
 
 	ret = QLA_SUCCESS;
 	ret = QLA_SUCCESS;
 
 
-	spin_lock_irqsave(&ha->hardware_lock, flags);
 	/* Enable flash write. */
 	/* Enable flash write. */
 	WRT_REG_DWORD(&reg->ctrl_status,
 	WRT_REG_DWORD(&reg->ctrl_status,
 	    RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
 	    RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
@@ -907,7 +905,6 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
 	WRT_REG_DWORD(&reg->ctrl_status,
 	WRT_REG_DWORD(&reg->ctrl_status,
 	    RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
 	    RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
 	RD_REG_DWORD(&reg->ctrl_status);	/* PCI Posting. */
 	RD_REG_DWORD(&reg->ctrl_status);	/* PCI Posting. */
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -2305,6 +2302,51 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf)
 	return ret;
 	return ret;
 }
 }
 
 
+static int
+qla2xxx_is_vpd_valid(uint8_t *pos, uint8_t *end)
+{
+	if (pos >= end || *pos != 0x82)
+		return 0;
+
+	pos += 3 + pos[1];
+	if (pos >= end || *pos != 0x90)
+		return 0;
+
+	pos += 3 + pos[1];
+	if (pos >= end || *pos != 0x78)
+		return 0;
+
+	return 1;
+}
+
+int
+qla2xxx_get_vpd_field(scsi_qla_host_t *ha, char *key, char *str, size_t size)
+{
+	uint8_t *pos = ha->vpd;
+	uint8_t *end = pos + ha->vpd_size;
+	int len = 0;
+
+	if (!IS_FWI2_CAPABLE(ha) || !qla2xxx_is_vpd_valid(pos, end))
+		return 0;
+
+	while (pos < end && *pos != 0x78) {
+		len = (*pos == 0x82) ? pos[1] : pos[2];
+
+		if (!strncmp(pos, key, strlen(key)))
+			break;
+
+		if (*pos != 0x90 && *pos != 0x91)
+			pos += len;
+
+		pos += 3;
+	}
+
+	if (pos < end - len && *pos != 0x78)
+		return snprintf(str, size, "%.*s", len, pos + 3);
+
+	return 0;
+}
+
 static int
 static int
 qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata)
 qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata)
 {
 {

+ 1 - 1
drivers/scsi/qla2xxx/qla_version.h

@@ -7,7 +7,7 @@
 /*
 /*
  * Driver version
  * Driver version
  */
  */
-#define QLA2XXX_VERSION      "8.02.01-k4"
+#define QLA2XXX_VERSION      "8.02.01-k6"
 
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	2
 #define QLA_DRIVER_MINOR_VER	2

+ 3 - 1
drivers/scsi/qla4xxx/ql4_os.c

@@ -46,6 +46,8 @@ MODULE_PARM_DESC(ql4xextended_error_logging,
 
 
 int ql4_mod_unload = 0;
 int ql4_mod_unload = 0;
 
 
+#define QL4_DEF_QDEPTH 32
+
 /*
 /*
  * SCSI host template entry points
  * SCSI host template entry points
  */
  */
@@ -1387,7 +1389,7 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev)
 
 
 	sdev->hostdata = ddb;
 	sdev->hostdata = ddb;
 	sdev->tagged_supported = 1;
 	sdev->tagged_supported = 1;
-	scsi_activate_tcq(sdev, sdev->host->can_queue);
+	scsi_activate_tcq(sdev, QL4_DEF_QDEPTH);
 	return 0;
 	return 0;
 }
 }
 
 

+ 48 - 7
drivers/scsi/scsi.c

@@ -197,10 +197,42 @@ static void
 scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
 scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
 			 struct scsi_cmnd *cmd)
 			 struct scsi_cmnd *cmd)
 {
 {
+	if (cmd->prot_sdb)
+		kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
+
 	kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
 	kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
 	kmem_cache_free(pool->cmd_slab, cmd);
 	kmem_cache_free(pool->cmd_slab, cmd);
 }
 }
 
 
+/**
+ * scsi_host_alloc_command - internal function to allocate command
+ * @shost:	SCSI host whose pool to allocate from
+ * @gfp_mask:	mask for the allocation
+ *
+ * Returns a fully allocated command with sense buffer and protection
+ * data buffer (where applicable) or NULL on failure
+ */
+static struct scsi_cmnd *
+scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
+{
+	struct scsi_cmnd *cmd;
+
+	cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+	if (!cmd)
+		return NULL;
+
+	if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
+		cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask);
+
+		if (!cmd->prot_sdb) {
+			scsi_pool_free_command(shost->cmd_pool, cmd);
+			return NULL;
+		}
+	}
+
+	return cmd;
+}
+
 /**
 /**
  * __scsi_get_command - Allocate a struct scsi_cmnd
  * __scsi_get_command - Allocate a struct scsi_cmnd
  * @shost: host to transmit command
  * @shost: host to transmit command
@@ -214,7 +246,7 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
 	struct scsi_cmnd *cmd;
 	struct scsi_cmnd *cmd;
 	unsigned char *buf;
 	unsigned char *buf;
 
 
-	cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+	cmd = scsi_host_alloc_command(shost, gfp_mask);
 
 
 	if (unlikely(!cmd)) {
 	if (unlikely(!cmd)) {
 		unsigned long flags;
 		unsigned long flags;
@@ -457,7 +489,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
 	/*
 	/*
 	 * Get one backup command for this host.
 	 * Get one backup command for this host.
 	 */
 	 */
-	cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+	cmd = scsi_host_alloc_command(shost, gfp_mask);
 	if (!cmd) {
 	if (!cmd) {
 		scsi_put_host_cmd_pool(gfp_mask);
 		scsi_put_host_cmd_pool(gfp_mask);
 		shost->cmd_pool = NULL;
 		shost->cmd_pool = NULL;
@@ -902,11 +934,20 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
 
 
 	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
 	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
 
 
-	/* Check to see if the queue is managed by the block layer.
-	 * If it is, and we fail to adjust the depth, exit. */
-	if (blk_queue_tagged(sdev->request_queue) &&
-	    blk_queue_resize_tags(sdev->request_queue, tags) != 0)
-		goto out;
+	/*
+	 * Check to see if the queue is managed by the block layer.
+	 * If it is, and we fail to adjust the depth, exit.
+	 *
+	 * Do not resize the tag map if it is a host wide share bqt,
+	 * because the size should be the hosts's can_queue. If there
+	 * is more IO than the LLD's can_queue (so there are not enuogh
+	 * tags) request_fn's host queue ready check will handle it.
+	 */
+	if (!sdev->host->bqt) {
+		if (blk_queue_tagged(sdev->request_queue) &&
+		    blk_queue_resize_tags(sdev->request_queue, tags) != 0)
+			goto out;
+	}
 
 
 	sdev->queue_depth = tags;
 	sdev->queue_depth = tags;
 	switch (tagged) {
 	switch (tagged) {

Some files were not shown because too many files changed in this diff