Browse Source

Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (182 commits)
  [SCSI] aacraid: add an ifdef'd device delete case instead of taking the device offline
  [SCSI] aacraid: prohibit access to array container space
  [SCSI] aacraid: add support for handling ATA pass-through commands.
  [SCSI] aacraid: expose physical devices for models with newer firmware
  [SCSI] aacraid: respond automatically to volumes added by config tool
  [SCSI] fcoe: fix fcoe module ref counting
  [SCSI] libfcoe: FIP Keep-Alive messages for VPorts are sent with incorrect port_id and wwn
  [SCSI] libfcoe: Fix incorrect MAC address clearing
  [SCSI] fcoe: fix a circular locking issue with rtnl and sysfs mutex
  [SCSI] libfc: Move the port_id into lport
  [SCSI] fcoe: move link speed checking into its own routine
  [SCSI] libfc: Remove extra pointer check
  [SCSI] libfc: Remove unused fc_get_host_port_type
  [SCSI] fcoe: fixes wrong error exit in fcoe_create
  [SCSI] libfc: set seq_id for incoming sequence
  [SCSI] qla2xxx: Updates to ISP82xx support.
  [SCSI] qla2xxx: Optionally disable target reset.
  [SCSI] qla2xxx: ensure flash operation and host reset via sg_reset are mutually exclusive
  [SCSI] qla2xxx: Silence bogus warning by gcc for wrap and did.
  [SCSI] qla2xxx: T10 DIF support added.
  ...
Linus Torvalds 15 năm trước cách đây
mục cha
commit
33cf23b0a5
100 tập tin đã thay đổi với 3574 bổ sung1988 xóa
  1. 12 11
      MAINTAINERS
  2. 174 3
      drivers/message/fusion/mptbase.c
  3. 3 2
      drivers/message/fusion/mptbase.h
  4. 105 76
      drivers/message/fusion/mptctl.c
  5. 21 1
      drivers/message/fusion/mptfc.c
  6. 38 17
      drivers/message/fusion/mptsas.c
  7. 1 1
      drivers/message/fusion/mptsas.h
  8. 18 9
      drivers/message/fusion/mptscsih.c
  9. 10 0
      drivers/message/fusion/mptspi.c
  10. 6 1
      drivers/s390/scsi/zfcp_aux.c
  11. 2 17
      drivers/s390/scsi/zfcp_def.h
  12. 1 1
      drivers/s390/scsi/zfcp_erp.c
  13. 3 3
      drivers/s390/scsi/zfcp_ext.h
  14. 2 2
      drivers/s390/scsi/zfcp_fc.c
  15. 85 161
      drivers/s390/scsi/zfcp_fsf.c
  16. 8 3
      drivers/s390/scsi/zfcp_fsf.h
  17. 61 47
      drivers/s390/scsi/zfcp_qdio.c
  18. 104 0
      drivers/s390/scsi/zfcp_qdio.h
  19. 16 7
      drivers/s390/scsi/zfcp_scsi.c
  20. 18 6
      drivers/scsi/3w-9xxx.c
  21. 5 4
      drivers/scsi/3w-9xxx.h
  22. 17 6
      drivers/scsi/3w-xxxx.c
  23. 4 4
      drivers/scsi/3w-xxxx.h
  24. 1 0
      drivers/scsi/Makefile
  25. 157 152
      drivers/scsi/a2091.c
  26. 21 21
      drivers/scsi/a2091.h
  27. 143 142
      drivers/scsi/a3000.c
  28. 23 23
      drivers/scsi/a3000.h
  29. 65 2
      drivers/scsi/aacraid/aachba.c
  30. 3 1
      drivers/scsi/aacraid/aacraid.h
  31. 18 0
      drivers/scsi/aacraid/commsup.c
  32. 0 29
      drivers/scsi/bfa/bfa_cb_ioim_macros.h
  33. 17 5
      drivers/scsi/bfa/bfa_ioim.c
  34. 19 4
      drivers/scsi/bfa/bfa_os_inc.h
  35. 7 14
      drivers/scsi/bfa/bfad.c
  36. 201 0
      drivers/scsi/bfa/bfad_attr.c
  37. 2 2
      drivers/scsi/bfa/bfad_drv.h
  38. 36 31
      drivers/scsi/bfa/bfad_im.c
  39. 5 1
      drivers/scsi/bfa/bfad_im.h
  40. 1 1
      drivers/scsi/bnx2i/bnx2i_hwi.c
  41. 6 5
      drivers/scsi/bnx2i/bnx2i_init.c
  42. 3 1
      drivers/scsi/cxgb3i/cxgb3i_init.c
  43. 0 2
      drivers/scsi/device_handler/scsi_dh_emc.c
  44. 128 66
      drivers/scsi/fcoe/fcoe.c
  45. 53 58
      drivers/scsi/fcoe/libfcoe.c
  46. 2 2
      drivers/scsi/fnic/fnic.h
  47. 1 1
      drivers/scsi/fnic/fnic_fcs.c
  48. 1 1
      drivers/scsi/fnic/fnic_main.c
  49. 1 1
      drivers/scsi/gdth.c
  50. 283 282
      drivers/scsi/gvp11.c
  51. 18 18
      drivers/scsi/gvp11.h
  52. 0 8
      drivers/scsi/hpsa.c
  53. 0 15
      drivers/scsi/hpsa_cmd.h
  54. 7 1
      drivers/scsi/ibmvscsi/ibmvfc.c
  55. 1 0
      drivers/scsi/ibmvscsi/ibmvfc.h
  56. 4 2
      drivers/scsi/iscsi_tcp.c
  57. 0 1
      drivers/scsi/iscsi_tcp.h
  58. 4 4
      drivers/scsi/libfc/fc_disc.c
  59. 1 1
      drivers/scsi/libfc/fc_elsct.c
  60. 17 34
      drivers/scsi/libfc/fc_exch.c
  61. 64 39
      drivers/scsi/libfc/fc_fcp.c
  62. 4 4
      drivers/scsi/libfc/fc_libfc.h
  63. 29 29
      drivers/scsi/libfc/fc_lport.c
  64. 5 2
      drivers/scsi/libfc/fc_npiv.c
  65. 87 108
      drivers/scsi/libfc/fc_rport.c
  66. 1 1
      drivers/scsi/libiscsi_tcp.c
  67. 3 2
      drivers/scsi/libsas/sas_ata.c
  68. 8 8
      drivers/scsi/libsas/sas_scsi_host.c
  69. 4 0
      drivers/scsi/lpfc/lpfc.h
  70. 13 7
      drivers/scsi/lpfc/lpfc_attr.c
  71. 421 77
      drivers/scsi/lpfc/lpfc_bsg.c
  72. 2 1
      drivers/scsi/lpfc/lpfc_bsg.h
  73. 1 0
      drivers/scsi/lpfc/lpfc_crtn.h
  74. 1 0
      drivers/scsi/lpfc/lpfc_disc.h
  75. 17 7
      drivers/scsi/lpfc/lpfc_els.c
  76. 73 6
      drivers/scsi/lpfc/lpfc_hbadisc.c
  77. 100 90
      drivers/scsi/lpfc/lpfc_hw.h
  78. 58 2
      drivers/scsi/lpfc/lpfc_hw4.h
  79. 135 78
      drivers/scsi/lpfc/lpfc_init.c
  80. 42 27
      drivers/scsi/lpfc/lpfc_mbox.c
  81. 94 5
      drivers/scsi/lpfc/lpfc_nportdisc.c
  82. 100 49
      drivers/scsi/lpfc/lpfc_scsi.c
  83. 219 50
      drivers/scsi/lpfc/lpfc_sli.c
  84. 4 0
      drivers/scsi/lpfc/lpfc_sli.h
  85. 3 2
      drivers/scsi/lpfc/lpfc_sli4.h
  86. 1 1
      drivers/scsi/lpfc/lpfc_version.h
  87. 3 1
      drivers/scsi/lpfc/lpfc_vport.c
  88. 1 1
      drivers/scsi/mpt2sas/Kconfig
  89. 1 1
      drivers/scsi/mpt2sas/mpi/mpi2.h
  90. 1 1
      drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
  91. 1 1
      drivers/scsi/mpt2sas/mpi/mpi2_history.txt
  92. 1 1
      drivers/scsi/mpt2sas/mpi/mpi2_init.h
  93. 1 1
      drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
  94. 1 1
      drivers/scsi/mpt2sas/mpi/mpi2_tool.h
  95. 66 24
      drivers/scsi/mpt2sas/mpt2sas_base.c
  96. 14 22
      drivers/scsi/mpt2sas/mpt2sas_base.h
  97. 4 4
      drivers/scsi/mpt2sas/mpt2sas_config.c
  98. 26 20
      drivers/scsi/mpt2sas/mpt2sas_ctl.c
  99. 1 1
      drivers/scsi/mpt2sas/mpt2sas_ctl.h
  100. 1 1
      drivers/scsi/mpt2sas/mpt2sas_debug.h

+ 12 - 11
MAINTAINERS

@@ -131,19 +131,12 @@ L:	netdev@vger.kernel.org
 S:	Maintained
 F:	drivers/net/typhoon*
 
-3W-9XXX SATA-RAID CONTROLLER DRIVER
-M:	Adam Radford <linuxraid@amcc.com>
+3WARE SAS/SATA-RAID SCSI DRIVERS (3W-XXXX, 3W-9XXX, 3W-SAS)
+M:	Adam Radford <linuxraid@lsi.com>
 L:	linux-scsi@vger.kernel.org
-W:	http://www.amcc.com
+W:	http://www.lsi.com
 S:	Supported
-F:	drivers/scsi/3w-9xxx*
-
-3W-XXXX ATA-RAID CONTROLLER DRIVER
-M:	Adam Radford <linuxraid@amcc.com>
-L:	linux-scsi@vger.kernel.org
-W:	http://www.amcc.com
-S:	Supported
-F:	drivers/scsi/3w-xxxx*
+F:	drivers/scsi/3w-*
 
 53C700 AND 53C700-66 SCSI DRIVER
 M:	"James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
@@ -4621,6 +4614,14 @@ S:	Supported
 F:	Documentation/scsi/LICENSE.qla2xxx
 F:	drivers/scsi/qla2xxx/
 
+QLOGIC QLA4XXX iSCSI DRIVER
+M:	Ravi Anand <ravi.anand@qlogic.com>
+M:	Vikas Chaudhary <vikas.chaudhary@qlogic.com>
+M:	iscsi-driver@qlogic.com
+L:	linux-scsi@vger.kernel.org
+S:	Supported
+F:	drivers/scsi/qla4xxx/
+
 QLOGIC QLA3XXX NETWORK DRIVER
 M:	Ron Mercer <ron.mercer@qlogic.com>
 M:	linux-driver@qlogic.com

+ 174 - 3
drivers/message/fusion/mptbase.c

@@ -5064,7 +5064,7 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode)
 		if (!timeleft) {
 			printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n",
 			    ioc->name, __func__);
-			mpt_HardResetHandler(ioc, CAN_SLEEP);
+			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 			mpt_free_msg_frame(ioc, mf);
 		}
 		goto out;
@@ -6456,10 +6456,15 @@ out:
 		issue_hard_reset = 0;
 		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
 		    ioc->name, __func__);
-		mpt_HardResetHandler(ioc, CAN_SLEEP);
+		if (retry_count == 0) {
+			if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0)
+				retry_count++;
+		} else
+			mpt_HardResetHandler(ioc, CAN_SLEEP);
+
 		mpt_free_msg_frame(ioc, mf);
 		/* attempt one retry for a timed out command */
-		if (!retry_count) {
+		if (retry_count < 2) {
 			printk(MYIOC_s_INFO_FMT
 			    "Attempting Retry Config request"
 			    " type 0x%x, page 0x%x,"
@@ -6904,6 +6909,172 @@ mpt_halt_firmware(MPT_ADAPTER *ioc)
 }
 EXPORT_SYMBOL(mpt_halt_firmware);
 
+/**
+ *	mpt_SoftResetHandler - Issues a less expensive reset
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@sleepFlag: Indicates if sleep or schedule must be called.
+
+ *
+ *	Returns 0 for SUCCESS or -1 if FAILED.
+ *
+ *	Message Unit Reset - instructs the IOC to reset the Reply Post and
+ *	Free FIFO's. All the Message Frames on Reply Free FIFO are discarded.
+ *	All posted buffers are freed, and event notification is turned off.
+ *	IOC doesnt reply to any outstanding request. This will transfer IOC
+ *	to READY state.
+ **/
+int
+mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
+{
+	int		 rc;
+	int		 ii;
+	u8		 cb_idx;
+	unsigned long	 flags;
+	u32		 ioc_state;
+	unsigned long	 time_count;
+
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SoftResetHandler Entered!\n",
+		ioc->name));
+
+	ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
+
+	if (mpt_fwfault_debug)
+		mpt_halt_firmware(ioc);
+
+	if (ioc_state == MPI_IOC_STATE_FAULT ||
+	    ioc_state == MPI_IOC_STATE_RESET) {
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "skipping, either in FAULT or RESET state!\n", ioc->name));
+		return -1;
+	}
+
+	if (ioc->bus_type == FC) {
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "skipping, because the bus type is FC!\n", ioc->name));
+		return -1;
+	}
+
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	if (ioc->ioc_reset_in_progress) {
+		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+		return -1;
+	}
+	ioc->ioc_reset_in_progress = 1;
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+	rc = -1;
+
+	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+		if (MptResetHandlers[cb_idx])
+			mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
+	}
+
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	if (ioc->taskmgmt_in_progress) {
+		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+		return -1;
+	}
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+	/* Disable reply interrupts (also blocks FreeQ) */
+	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
+	ioc->active = 0;
+	time_count = jiffies;
+
+	rc = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag);
+
+	for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+		if (MptResetHandlers[cb_idx])
+			mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
+	}
+
+	if (rc)
+		goto out;
+
+	ioc_state = mpt_GetIocState(ioc, 0) & MPI_IOC_STATE_MASK;
+	if (ioc_state != MPI_IOC_STATE_READY)
+		goto out;
+
+	for (ii = 0; ii < 5; ii++) {
+		/* Get IOC facts! Allow 5 retries */
+		rc = GetIocFacts(ioc, sleepFlag,
+			MPT_HOSTEVENT_IOC_RECOVER);
+		if (rc == 0)
+			break;
+		if (sleepFlag == CAN_SLEEP)
+			msleep(100);
+		else
+			mdelay(100);
+	}
+	if (ii == 5)
+		goto out;
+
+	rc = PrimeIocFifos(ioc);
+	if (rc != 0)
+		goto out;
+
+	rc = SendIocInit(ioc, sleepFlag);
+	if (rc != 0)
+		goto out;
+
+	rc = SendEventNotification(ioc, 1, sleepFlag);
+	if (rc != 0)
+		goto out;
+
+	if (ioc->hard_resets < -1)
+		ioc->hard_resets++;
+
+	/*
+	 * At this point, we know soft reset succeeded.
+	 */
+
+	ioc->active = 1;
+	CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
+
+ out:
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	ioc->ioc_reset_in_progress = 0;
+	ioc->taskmgmt_quiesce_io = 0;
+	ioc->taskmgmt_in_progress = 0;
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+	if (ioc->active) {	/* otherwise, hard reset coming */
+		for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+			if (MptResetHandlers[cb_idx])
+				mpt_signal_reset(cb_idx, ioc,
+					MPT_IOC_POST_RESET);
+		}
+	}
+
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		"SoftResetHandler: completed (%d seconds): %s\n",
+		ioc->name, jiffies_to_msecs(jiffies - time_count)/1000,
+		((rc == 0) ? "SUCCESS" : "FAILED")));
+
+	return rc;
+}
+
+/**
+ *	mpt_Soft_Hard_ResetHandler - Try less expensive reset
+ *	@ioc: Pointer to MPT_ADAPTER structure
+ *	@sleepFlag: Indicates if sleep or schedule must be called.
+
+ *
+ *	Returns 0 for SUCCESS or -1 if FAILED.
+ *	Try for softreset first, only if it fails go for expensive
+ *	HardReset.
+ **/
+int
+mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag) {
+	int ret = -1;
+
+	ret = mpt_SoftResetHandler(ioc, sleepFlag);
+	if (ret == 0)
+		return ret;
+	ret = mpt_HardResetHandler(ioc, sleepFlag);
+	return ret;
+}
+EXPORT_SYMBOL(mpt_Soft_Hard_ResetHandler);
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *	Reset Handling

+ 3 - 2
drivers/message/fusion/mptbase.h

@@ -76,8 +76,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2008 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.04.14"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.04.14"
+#define MPT_LINUX_VERSION_COMMON	"3.04.15"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.04.15"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -940,6 +940,7 @@ extern int	 mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
 extern u32	 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
 extern void	 mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
 extern int	 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
+extern int	 mpt_Soft_Hard_ResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
 extern int	 mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
 extern int	 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
 extern void	 mpt_free_fw_memory(MPT_ADAPTER *ioc);

+ 105 - 76
drivers/message/fusion/mptctl.c

@@ -128,7 +128,6 @@ static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags
 		struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
 static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
 		struct buflist *buflist, MPT_ADAPTER *ioc);
-static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function);
 
 /*
  * Reset Handler cleanup function
@@ -275,45 +274,6 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
 	return 1;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* mptctl_timeout_expired
- *
- * Expecting an interrupt, however timed out.
- *
- */
-static void
-mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
-{
-	unsigned long flags;
-
-	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
-		ioc->name, __func__));
-
-	if (mpt_fwfault_debug)
-		mpt_halt_firmware(ioc);
-
-	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
-	if (ioc->ioc_reset_in_progress) {
-		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
-		CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
-		mpt_free_msg_frame(ioc, mf);
-		return;
-	}
-	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
-
-
-	if (!mptctl_bus_reset(ioc, mf->u.hdr.Function))
-		return;
-
-	/* Issue a reset for this device.
-	 * The IOC is not responding.
-	 */
-	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
-		 ioc->name));
-	CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
-	mpt_HardResetHandler(ioc, CAN_SLEEP);
-	mpt_free_msg_frame(ioc, mf);
-}
 
 static int
 mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
@@ -343,12 +303,8 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
 	return 0;
 }
 
-/* mptctl_bus_reset
- *
- * Bus reset code.
- *
- */
-static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
+static int
+mptctl_do_taskmgmt(MPT_ADAPTER *ioc, u8 tm_type, u8 bus_id, u8 target_id)
 {
 	MPT_FRAME_HDR	*mf;
 	SCSITaskMgmt_t	*pScsiTm;
@@ -359,13 +315,6 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 	unsigned long	 time_count;
 	u16		 iocstatus;
 
-	/* bus reset is only good for SCSI IO, RAID PASSTHRU */
-	if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
-		function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
-		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-			"TaskMgmt, not SCSI_IO!!\n", ioc->name));
-		return -EPERM;
-	}
 
 	mutex_lock(&ioc->taskmgmt_cmds.mutex);
 	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
@@ -375,15 +324,14 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 
 	retval = 0;
 
-	/* Send request
-	 */
 	mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc);
 	if (mf == NULL) {
-		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-			"TaskMgmt, no msg frames!!\n", ioc->name));
+		dtmprintk(ioc,
+			printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
+			ioc->name));
 		mpt_clear_taskmgmt_in_progress_flag(ioc);
 		retval = -ENOMEM;
-		goto mptctl_bus_reset_done;
+		goto tm_done;
 	}
 
 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
@@ -392,10 +340,13 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 	pScsiTm = (SCSITaskMgmt_t *) mf;
 	memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
-	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
-	pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
-	pScsiTm->TargetID = 0;
-	pScsiTm->Bus = 0;
+	pScsiTm->TaskType = tm_type;
+	if ((tm_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) &&
+		(ioc->bus_type == FC))
+		pScsiTm->MsgFlags =
+				MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+	pScsiTm->TargetID = target_id;
+	pScsiTm->Bus = bus_id;
 	pScsiTm->ChainOffset = 0;
 	pScsiTm->Reserved = 0;
 	pScsiTm->Reserved1 = 0;
@@ -413,17 +364,16 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 		timeout = 30;
 		break;
 	case SPI:
-	default:
-		timeout = 2;
+		default:
+		timeout = 10;
 		break;
 	}
 
-	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-		"TaskMgmt type=%d timeout=%ld\n",
-		ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
+	dtmprintk(ioc,
+		printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
+		ioc->name, tm_type, timeout));
 
 	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
-	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
 	time_count = jiffies;
 	if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
 	    (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
@@ -432,17 +382,20 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 		retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
 		    sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP);
 		if (retval != 0) {
-			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+			dfailprintk(ioc,
+				printk(MYIOC_s_ERR_FMT
 				"TaskMgmt send_handshake FAILED!"
 				" (ioc %p, mf %p, rc=%d) \n", ioc->name,
 				ioc, mf, retval));
+			mpt_free_msg_frame(ioc, mf);
 			mpt_clear_taskmgmt_in_progress_flag(ioc);
-			goto mptctl_bus_reset_done;
+			goto tm_done;
 		}
 	}
 
 	/* Now wait for the command to complete */
 	ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+
 	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		    "TaskMgmt failed\n", ioc->name));
@@ -452,14 +405,14 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 			retval = 0;
 		else
 			retval = -1; /* return failure */
-		goto mptctl_bus_reset_done;
+		goto tm_done;
 	}
 
 	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		    "TaskMgmt failed\n", ioc->name));
 		retval = -1; /* return failure */
-		goto mptctl_bus_reset_done;
+		goto tm_done;
 	}
 
 	pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
@@ -467,7 +420,7 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 	    "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "
 	    "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "
 	    "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus,
-	    pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+	    pScsiTmReply->TargetID, tm_type,
 	    le16_to_cpu(pScsiTmReply->IOCStatus),
 	    le32_to_cpu(pScsiTmReply->IOCLogInfo),
 	    pScsiTmReply->ResponseCode,
@@ -485,13 +438,71 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 		retval = -1; /* return failure */
 	}
 
-
- mptctl_bus_reset_done:
+ tm_done:
 	mutex_unlock(&ioc->taskmgmt_cmds.mutex);
 	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
 	return retval;
 }
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_timeout_expired
+ *
+ * Expecting an interrupt, however timed out.
+ *
+ */
+static void
+mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+{
+	unsigned long flags;
+	int ret_val = -1;
+	SCSIIORequest_t *scsi_req = (SCSIIORequest_t *) mf;
+	u8 function = mf->u.hdr.Function;
+
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
+		ioc->name, __func__));
+
+	if (mpt_fwfault_debug)
+		mpt_halt_firmware(ioc);
+
+	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+	if (ioc->ioc_reset_in_progress) {
+		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+		CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+		mpt_free_msg_frame(ioc, mf);
+		return;
+	}
+	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+
+	CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+
+	if (ioc->bus_type == SAS) {
+		if (function == MPI_FUNCTION_SCSI_IO_REQUEST)
+			ret_val = mptctl_do_taskmgmt(ioc,
+				MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+				scsi_req->Bus, scsi_req->TargetID);
+		else if (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
+			ret_val = mptctl_do_taskmgmt(ioc,
+				MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+				scsi_req->Bus, 0);
+		if (!ret_val)
+			return;
+	} else {
+		if ((function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+			(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH))
+			ret_val = mptctl_do_taskmgmt(ioc,
+				MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+				scsi_req->Bus, 0);
+		if (!ret_val)
+			return;
+	}
+
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling Reset! \n",
+		 ioc->name));
+	mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
+	mpt_free_msg_frame(ioc, mf);
+}
+
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* mptctl_ioc_reset
@@ -1318,6 +1329,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
 	if (ioc->sh) {
 		shost_for_each_device(sdev, ioc->sh) {
 			vdevice = sdev->hostdata;
+			if (vdevice == NULL || vdevice->vtarget == NULL)
+				continue;
 			if (vdevice->vtarget->tflags &
 			    MPT_TARGET_FLAGS_RAID_COMPONENT)
 				continue;
@@ -1439,6 +1452,8 @@ mptctl_gettargetinfo (unsigned long arg)
 			if (!maxWordsLeft)
 				continue;
 			vdevice = sdev->hostdata;
+			if (vdevice == NULL || vdevice->vtarget == NULL)
+				continue;
 			if (vdevice->vtarget->tflags &
 			    MPT_TARGET_FLAGS_RAID_COMPONENT)
 				continue;
@@ -1967,6 +1982,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
 				struct scsi_target *starget = scsi_target(sdev);
 				VirtTarget *vtarget = starget->hostdata;
 
+				if (vtarget == NULL)
+					continue;
+
 				if ((pScsiReq->TargetID == vtarget->id) &&
 				    (pScsiReq->Bus == vtarget->channel) &&
 				    (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
@@ -2991,6 +3009,14 @@ static int __init mptctl_init(void)
 	}
 
 	mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
+	if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) {
+		printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
+		mpt_deregister(mptctl_id);
+		misc_deregister(&mptctl_miscdev);
+		err = -EBUSY;
+		goto out_fail;
+	}
+
 	mpt_reset_register(mptctl_id, mptctl_ioc_reset);
 	mpt_event_register(mptctl_id, mptctl_event_process);
 
@@ -3010,12 +3036,15 @@ static void mptctl_exit(void)
 	printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",
 			 mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
 
+	/* De-register event handler from base module */
+	mpt_event_deregister(mptctl_id);
+
 	/* De-register reset handler from base module */
 	mpt_reset_deregister(mptctl_id);
 
 	/* De-register callback handler from base module */
+	mpt_deregister(mptctl_taskmgmt_id);
 	mpt_deregister(mptctl_id);
-	mpt_reset_deregister(mptctl_taskmgmt_id);
 
         mpt_device_driver_deregister(MPTCTL_DRIVER);
 

+ 21 - 1
drivers/message/fusion/mptfc.c

@@ -482,6 +482,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
 				if (vtarget) {
 					vtarget->id = pg0->CurrentTargetID;
 					vtarget->channel = pg0->CurrentBus;
+					vtarget->deleted = 0;
 				}
 			}
 			*((struct mptfc_rport_info **)rport->dd_data) = ri;
@@ -1092,6 +1093,8 @@ mptfc_setup_reset(struct work_struct *work)
 		container_of(work, MPT_ADAPTER, fc_setup_reset_work);
 	u64			pn;
 	struct mptfc_rport_info *ri;
+	struct scsi_target      *starget;
+	VirtTarget              *vtarget;
 
 	/* reset about to happen, delete (block) all rports */
 	list_for_each_entry(ri, &ioc->fc_rports, list) {
@@ -1099,6 +1102,12 @@ mptfc_setup_reset(struct work_struct *work)
 			ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
 			fc_remote_port_delete(ri->rport);	/* won't sleep */
 			ri->rport = NULL;
+			starget = ri->starget;
+			if (starget) {
+				vtarget = starget->hostdata;
+				if (vtarget)
+					vtarget->deleted = 1;
+			}
 
 			pn = (u64)ri->pg0.WWPN.High << 32 |
 			     (u64)ri->pg0.WWPN.Low;
@@ -1119,6 +1128,8 @@ mptfc_rescan_devices(struct work_struct *work)
 	int			ii;
 	u64			pn;
 	struct mptfc_rport_info *ri;
+	struct scsi_target      *starget;
+	VirtTarget              *vtarget;
 
 	/* start by tagging all ports as missing */
 	list_for_each_entry(ri, &ioc->fc_rports, list) {
@@ -1146,6 +1157,12 @@ mptfc_rescan_devices(struct work_struct *work)
 				       MPT_RPORT_INFO_FLAGS_MISSING);
 			fc_remote_port_delete(ri->rport);	/* won't sleep */
 			ri->rport = NULL;
+			starget = ri->starget;
+			if (starget) {
+				vtarget = starget->hostdata;
+				if (vtarget)
+					vtarget->deleted = 1;
+			}
 
 			pn = (u64)ri->pg0.WWPN.High << 32 |
 			     (u64)ri->pg0.WWPN.Low;
@@ -1358,6 +1375,9 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 	unsigned long flags;
 	int rc=1;
 
+	if (ioc->bus_type != FC)
+		return 0;
+
 	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
 			ioc->name, event));
 
@@ -1396,7 +1416,7 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 	unsigned long	flags;
 
 	rc = mptscsih_ioc_reset(ioc,reset_phase);
-	if (rc == 0)
+	if ((ioc->bus_type != FC) || (!rc))
 		return rc;
 
 

+ 38 - 17
drivers/message/fusion/mptsas.c

@@ -1894,7 +1894,7 @@ static struct scsi_host_template mptsas_driver_template = {
 	.module				= THIS_MODULE,
 	.proc_name			= "mptsas",
 	.proc_info			= mptscsih_proc_info,
-	.name				= "MPT SPI Host",
+	.name				= "MPT SAS Host",
 	.info				= mptscsih_info,
 	.queuecommand			= mptsas_qcmd,
 	.target_alloc			= mptsas_target_alloc,
@@ -2038,11 +2038,13 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
 
 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
 			10 * HZ);
-	if (!timeleft) {
-		/* On timeout reset the board */
+	if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		error = -ETIME;
 		mpt_free_msg_frame(ioc, mf);
-		mpt_HardResetHandler(ioc, CAN_SLEEP);
-		error = -ETIMEDOUT;
+		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
+			goto out_unlock;
+		if (!timeleft)
+			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 		goto out_unlock;
 	}
 
@@ -2223,11 +2225,14 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 	mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
 
 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
-	if (!timeleft) {
-		printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
-		/* On timeout reset the board */
-		mpt_HardResetHandler(ioc, CAN_SLEEP);
-		ret = -ETIMEDOUT;
+	if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
+		ret = -ETIME;
+		mpt_free_msg_frame(ioc, mf);
+		mf = NULL;
+		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
+			goto unmap;
+		if (!timeleft)
+			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 		goto unmap;
 	}
 	mf = NULL;
@@ -2518,6 +2523,12 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 
 	error = mpt_config(ioc, &cfg);
+
+	if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
+		error = -ENODEV;
+		goto out_free_consistent;
+	}
+
 	if (error)
 		goto out_free_consistent;
 
@@ -2594,14 +2605,14 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 
 	error = mpt_config(ioc, &cfg);
-	if (error)
-		goto out_free_consistent;
-
-	if (!buffer->NumPhys) {
+	if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
 		error = -ENODEV;
 		goto out_free_consistent;
 	}
 
+	if (error)
+		goto out_free_consistent;
+
 	/* save config data */
 	port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
 	port_info->phy_info = kcalloc(port_info->num_phys,
@@ -2677,7 +2688,7 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
 
 	if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
 		error = -ENODEV;
-		goto out;
+		goto out_free_consistent;
 	}
 
 	if (error)
@@ -2833,7 +2844,7 @@ mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
 		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
 			goto out_free;
 		if (!timeleft)
-			mpt_HardResetHandler(ioc, CAN_SLEEP);
+			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 		goto out_free;
 	}
 
@@ -4098,6 +4109,7 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
 	cfg.pageAddr = (channel << 8) + id;
 	cfg.cfghdr.hdr = &hdr;
 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
 
 	if (mpt_config(ioc, &cfg) != 0)
 		goto out;
@@ -4717,7 +4729,7 @@ mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
 	if (issue_reset) {
 		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
 		    ioc->name, __func__);
-		mpt_HardResetHandler(ioc, CAN_SLEEP);
+		mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 	}
 	mptsas_free_fw_event(ioc, fw_event);
 }
@@ -4779,6 +4791,9 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
 	struct fw_event_work *fw_event;
 	unsigned long delay;
 
+	if (ioc->bus_type != SAS)
+		return 0;
+
 	/* events turned off due to host reset or driver unloading */
 	if (ioc->fw_events_off)
 		return 0;
@@ -5073,6 +5088,12 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
 	struct mptsas_portinfo *p, *n;
 	int i;
 
+	if (!ioc->sh) {
+		printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
+		mpt_detach(pdev);
+		return;
+	}
+
 	mptsas_shutdown(pdev);
 
 	mptsas_del_device_components(ioc);

+ 1 - 1
drivers/message/fusion/mptsas.h

@@ -110,7 +110,7 @@ struct fw_event_work {
 	MPT_ADAPTER	*ioc;
 	u32			event;
 	u8			retries;
-	u8			event_data[1];
+	u8			__attribute__((aligned(4))) event_data[1];
 };
 
 struct mptsas_discovery_event {

+ 18 - 9
drivers/message/fusion/mptscsih.c

@@ -1149,11 +1149,6 @@ mptscsih_remove(struct pci_dev *pdev)
 	MPT_SCSI_HOST		*hd;
 	int sz1;
 
-	if(!host) {
-		mpt_detach(pdev);
-		return;
-	}
-
 	scsi_remove_host(host);
 
 	if((hd = shost_priv(host)) == NULL)
@@ -1711,7 +1706,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun,
 	if (issue_hard_reset) {
 		printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
 			ioc->name, __func__);
-		retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+		retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 		mpt_free_msg_frame(ioc, mf);
 	}
 
@@ -1728,6 +1723,7 @@ mptscsih_get_tm_timeout(MPT_ADAPTER *ioc)
 	case FC:
 		return 40;
 	case SAS:
+		return 30;
 	case SPI:
 	default:
 		return 10;
@@ -1777,7 +1773,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
 		    ioc->name, SCpnt));
 		SCpnt->result = DID_NO_CONNECT << 16;
 		SCpnt->scsi_done(SCpnt);
-		retval = 0;
+		retval = SUCCESS;
 		goto out;
 	}
 
@@ -1792,6 +1788,17 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
 		goto out;
 	}
 
+	/* Task aborts are not supported for volumes.
+	 */
+	if (vdevice->vtarget->raidVolume) {
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "task abort: raid volume (sc=%p)\n",
+		    ioc->name, SCpnt));
+		SCpnt->result = DID_RESET << 16;
+		retval = FAILED;
+		goto out;
+	}
+
 	/* Find this command
 	 */
 	if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
@@ -1991,7 +1998,7 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
 	/*  If our attempts to reset the host failed, then return a failed
 	 *  status.  The host will be taken off line by the SCSI mid-layer.
 	 */
-    retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+    retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 	if (retval < 0)
 		status = FAILED;
 	else
@@ -2344,6 +2351,8 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
 	starget = scsi_target(sdev);
 	vtarget = starget->hostdata;
 	vdevice = sdev->hostdata;
+	if (!vdevice)
+		return;
 
 	mptscsih_search_running_cmds(hd, vdevice);
 	vtarget->num_luns--;
@@ -3040,7 +3049,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
 		if (!timeleft) {
 			printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
 			    ioc->name, __func__);
-			mpt_HardResetHandler(ioc, CAN_SLEEP);
+			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
 			mpt_free_msg_frame(ioc, mf);
 		}
 		goto out;

+ 10 - 0
drivers/message/fusion/mptspi.c

@@ -210,6 +210,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
 	target->maxOffset = offset;
 	target->maxWidth = width;
 
+	spi_min_period(scsi_target(sdev)) = factor;
+	spi_max_offset(scsi_target(sdev)) = offset;
+	spi_max_width(scsi_target(sdev)) = width;
+
 	target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO;
 
 	/* Disable unused features.
@@ -558,6 +562,7 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 	cfg.dir = 0;
 	cfg.pageAddr = starget->id;
+	cfg.timeout = 60;
 
 	if (mpt_config(ioc, &cfg)) {
 		starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
@@ -1152,6 +1157,9 @@ mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
 	struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
 
+	if (ioc->bus_type != SPI)
+		return 0;
+
 	if (hd && event ==  MPI_EVENT_INTEGRATED_RAID) {
 		int reason
 			= (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16;
@@ -1283,6 +1291,8 @@ mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 	int rc;
 
 	rc = mptscsih_ioc_reset(ioc, reset_phase);
+	if ((ioc->bus_type != SPI) || (!rc))
+		return rc;
 
 	/* only try to do a renegotiation if we're properly set up
 	 * if we get an ioc fault on bringup, ioc->sh will be NULL */

+ 6 - 1
drivers/s390/scsi/zfcp_aux.c

@@ -425,7 +425,8 @@ int zfcp_status_read_refill(struct zfcp_adapter *adapter)
 {
 	while (atomic_read(&adapter->stat_miss) > 0)
 		if (zfcp_fsf_status_read(adapter->qdio)) {
-			if (atomic_read(&adapter->stat_miss) >= 16) {
+			if (atomic_read(&adapter->stat_miss) >=
+			    adapter->stat_read_buf_num) {
 				zfcp_erp_adapter_reopen(adapter, 0, "axsref1",
 							NULL);
 				return 1;
@@ -545,6 +546,10 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
 			       &zfcp_sysfs_adapter_attrs))
 		goto failed;
 
+	/* report size limit per scatter-gather segment */
+	adapter->dma_parms.max_segment_size = ZFCP_QDIO_SBALE_LEN;
+	adapter->ccw_device->dev.dma_parms = &adapter->dma_parms;
+
 	if (!zfcp_adapter_scsi_register(adapter))
 		return adapter;
 

+ 2 - 17
drivers/s390/scsi/zfcp_def.h

@@ -44,23 +44,6 @@ struct zfcp_reqlist;
 /********************* SCSI SPECIFIC DEFINES *********************************/
 #define ZFCP_SCSI_ER_TIMEOUT                    (10*HZ)
 
-/********************* CIO/QDIO SPECIFIC DEFINES *****************************/
-
-/* DMQ bug workaround: don't use last SBALE */
-#define ZFCP_MAX_SBALES_PER_SBAL	(QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
-
-/* index of last SBALE (with respect to DMQ bug workaround) */
-#define ZFCP_LAST_SBALE_PER_SBAL	(ZFCP_MAX_SBALES_PER_SBAL - 1)
-
-/* max. number of (data buffer) SBALEs in largest SBAL chain */
-#define ZFCP_MAX_SBALES_PER_REQ		\
-	(FSF_MAX_SBALS_PER_REQ * ZFCP_MAX_SBALES_PER_SBAL - 2)
-        /* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */
-
-#define ZFCP_MAX_SECTORS (ZFCP_MAX_SBALES_PER_REQ * 8)
-        /* max. number of (data buffer) SBALEs in largest SBAL chain
-           multiplied with number of sectors per 4k block */
-
 /********************* FSF SPECIFIC DEFINES *********************************/
 
 /* ATTENTION: value must not be used by hardware */
@@ -181,6 +164,7 @@ struct zfcp_adapter {
 						      stack abort/command
 						      completion races */
 	atomic_t		stat_miss;	   /* # missing status reads*/
+	unsigned int		stat_read_buf_num;
 	struct work_struct	stat_work;
 	atomic_t		status;	           /* status of this adapter */
 	struct list_head	erp_ready_head;	   /* error recovery for this
@@ -205,6 +189,7 @@ struct zfcp_adapter {
 	struct work_struct	scan_work;
 	struct service_level	service_level;
 	struct workqueue_struct	*work_queue;
+	struct device_dma_parameters dma_parms;
 };
 
 struct zfcp_port {

+ 1 - 1
drivers/s390/scsi/zfcp_erp.c

@@ -714,7 +714,7 @@ static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *act)
 	if (zfcp_erp_adapter_strategy_open_fsf_xport(act) == ZFCP_ERP_FAILED)
 		return ZFCP_ERP_FAILED;
 
-	atomic_set(&act->adapter->stat_miss, 16);
+	atomic_set(&act->adapter->stat_miss, act->adapter->stat_read_buf_num);
 	if (zfcp_status_read_refill(act->adapter))
 		return ZFCP_ERP_FAILED;
 

+ 3 - 3
drivers/s390/scsi/zfcp_ext.h

@@ -3,7 +3,7 @@
  *
  * External function declarations.
  *
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
  */
 
 #ifndef ZFCP_EXT_H
@@ -143,9 +143,9 @@ extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int);
 /* zfcp_qdio.c */
 extern int zfcp_qdio_setup(struct zfcp_adapter *);
 extern void zfcp_qdio_destroy(struct zfcp_qdio *);
+extern int zfcp_qdio_sbal_get(struct zfcp_qdio *);
 extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *);
-extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *,
-				   struct zfcp_qdio_req *, unsigned long,
+extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
 				   struct scatterlist *, int);
 extern int zfcp_qdio_open(struct zfcp_qdio *);
 extern void zfcp_qdio_close(struct zfcp_qdio *);

+ 2 - 2
drivers/s390/scsi/zfcp_fc.c

@@ -400,7 +400,7 @@ static int zfcp_fc_adisc(struct zfcp_port *port)
 	struct zfcp_adapter *adapter = port->adapter;
 	int ret;
 
-	adisc = kmem_cache_alloc(zfcp_data.adisc_cache, GFP_ATOMIC);
+	adisc = kmem_cache_zalloc(zfcp_data.adisc_cache, GFP_ATOMIC);
 	if (!adisc)
 		return -ENOMEM;
 
@@ -493,7 +493,7 @@ static struct zfcp_fc_gpn_ft *zfcp_alloc_sg_env(int buf_num)
 	if (!gpn_ft)
 		return NULL;
 
-	req = kmem_cache_alloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);
+	req = kmem_cache_zalloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);
 	if (!req) {
 		kfree(gpn_ft);
 		gpn_ft = NULL;

+ 85 - 161
drivers/s390/scsi/zfcp_fsf.c

@@ -496,6 +496,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
 
 	adapter->hydra_version = bottom->adapter_type;
 	adapter->timer_ticks = bottom->timer_interval;
+	adapter->stat_read_buf_num = max(bottom->status_read_buf_num, (u16)16);
 
 	if (fc_host_permanent_port_name(shost) == -1)
 		fc_host_permanent_port_name(shost) = fc_host_port_name(shost);
@@ -640,37 +641,6 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
 	}
 }
 
-static int zfcp_fsf_sbal_check(struct zfcp_qdio *qdio)
-{
-	struct zfcp_qdio_queue *req_q = &qdio->req_q;
-
-	spin_lock_bh(&qdio->req_q_lock);
-	if (atomic_read(&req_q->count))
-		return 1;
-	spin_unlock_bh(&qdio->req_q_lock);
-	return 0;
-}
-
-static int zfcp_fsf_req_sbal_get(struct zfcp_qdio *qdio)
-{
-	struct zfcp_adapter *adapter = qdio->adapter;
-	long ret;
-
-	spin_unlock_bh(&qdio->req_q_lock);
-	ret = wait_event_interruptible_timeout(qdio->req_q_wq,
-			       zfcp_fsf_sbal_check(qdio), 5 * HZ);
-	if (ret > 0)
-		return 0;
-	if (!ret) {
-		atomic_inc(&qdio->req_q_full);
-		/* assume hanging outbound queue, try queue recovery */
-		zfcp_erp_adapter_reopen(adapter, 0, "fsrsg_1", NULL);
-	}
-
-	spin_lock_bh(&qdio->req_q_lock);
-	return -EIO;
-}
-
 static struct zfcp_fsf_req *zfcp_fsf_alloc(mempool_t *pool)
 {
 	struct zfcp_fsf_req *req;
@@ -705,10 +675,9 @@ static struct fsf_qtcb *zfcp_qtcb_alloc(mempool_t *pool)
 }
 
 static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
-						u32 fsf_cmd, mempool_t *pool)
+						u32 fsf_cmd, u32 sbtype,
+						mempool_t *pool)
 {
-	struct qdio_buffer_element *sbale;
-	struct zfcp_qdio_queue *req_q = &qdio->req_q;
 	struct zfcp_adapter *adapter = qdio->adapter;
 	struct zfcp_fsf_req *req = zfcp_fsf_alloc(pool);
 
@@ -725,14 +694,6 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
 	req->adapter = adapter;
 	req->fsf_command = fsf_cmd;
 	req->req_id = adapter->req_no;
-	req->qdio_req.sbal_number = 1;
-	req->qdio_req.sbal_first = req_q->first;
-	req->qdio_req.sbal_last = req_q->first;
-	req->qdio_req.sbale_curr = 1;
-
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].addr = (void *) req->req_id;
-	sbale[0].flags |= SBAL_FLAGS0_COMMAND;
 
 	if (likely(fsf_cmd != FSF_QTCB_UNSOLICITED_STATUS)) {
 		if (likely(pool))
@@ -753,10 +714,11 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_qdio *qdio,
 		req->qtcb->prefix.qtcb_version = FSF_QTCB_CURRENT_VERSION;
 		req->qtcb->header.req_handle = req->req_id;
 		req->qtcb->header.fsf_command = req->fsf_command;
-		sbale[1].addr = (void *) req->qtcb;
-		sbale[1].length = sizeof(struct fsf_qtcb);
 	}
 
+	zfcp_qdio_req_init(adapter->qdio, &req->qdio_req, req->req_id, sbtype,
+			   req->qtcb, sizeof(struct fsf_qtcb));
+
 	if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) {
 		zfcp_fsf_req_free(req);
 		return ERR_PTR(-EIO);
@@ -803,24 +765,19 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
 	struct zfcp_adapter *adapter = qdio->adapter;
 	struct zfcp_fsf_req *req;
 	struct fsf_status_read_buffer *sr_buf;
-	struct qdio_buffer_element *sbale;
 	int retval = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
-	req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS,
+	req = zfcp_fsf_req_create(qdio, FSF_QTCB_UNSOLICITED_STATUS, 0,
 				  adapter->pool.status_read_req);
 	if (IS_ERR(req)) {
 		retval = PTR_ERR(req);
 		goto out;
 	}
 
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[2].flags |= SBAL_FLAGS_LAST_ENTRY;
-	req->qdio_req.sbale_curr = 2;
-
 	sr_buf = mempool_alloc(adapter->pool.status_read_data, GFP_ATOMIC);
 	if (!sr_buf) {
 		retval = -ENOMEM;
@@ -828,9 +785,9 @@ int zfcp_fsf_status_read(struct zfcp_qdio *qdio)
 	}
 	memset(sr_buf, 0, sizeof(*sr_buf));
 	req->data = sr_buf;
-	sbale = zfcp_qdio_sbale_curr(qdio, &req->qdio_req);
-	sbale->addr = (void *) sr_buf;
-	sbale->length = sizeof(*sr_buf);
+
+	zfcp_qdio_fill_next(qdio, &req->qdio_req, sr_buf, sizeof(*sr_buf));
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	retval = zfcp_fsf_req_send(req);
 	if (retval)
@@ -907,14 +864,14 @@ static void zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *req)
 struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
 						struct zfcp_unit *unit)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req = NULL;
 	struct zfcp_qdio *qdio = unit->port->adapter->qdio;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_ABORT_FCP_CMND,
+				  SBAL_FLAGS0_TYPE_READ,
 				  qdio->adapter->pool.scsi_abort);
 	if (IS_ERR(req)) {
 		req = NULL;
@@ -925,9 +882,7 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
 		       ZFCP_STATUS_COMMON_UNBLOCKED)))
 		goto out_error_free;
 
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->data = unit;
 	req->handler = zfcp_fsf_abort_fcp_command_handler;
@@ -996,21 +951,14 @@ skip_fsfstatus:
 		ct->handler(ct->handler_data);
 }
 
-static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale,
+static void zfcp_fsf_setup_ct_els_unchained(struct zfcp_qdio *qdio,
+					    struct zfcp_qdio_req *q_req,
 					    struct scatterlist *sg_req,
 					    struct scatterlist *sg_resp)
 {
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
-	sbale[2].addr   = sg_virt(sg_req);
-	sbale[2].length = sg_req->length;
-	sbale[3].addr   = sg_virt(sg_resp);
-	sbale[3].length = sg_resp->length;
-	sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
-}
-
-static int zfcp_fsf_one_sbal(struct scatterlist *sg)
-{
-	return sg_is_last(sg) && sg->length <= PAGE_SIZE;
+	zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_req), sg_req->length);
+	zfcp_qdio_fill_next(qdio, q_req, sg_virt(sg_resp), sg_resp->length);
+	zfcp_qdio_set_sbale_last(qdio, q_req);
 }
 
 static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
@@ -1019,35 +967,34 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
 				       int max_sbals)
 {
 	struct zfcp_adapter *adapter = req->adapter;
-	struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(adapter->qdio,
-							       &req->qdio_req);
 	u32 feat = adapter->adapter_features;
 	int bytes;
 
 	if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
-		if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp))
+		if (!zfcp_qdio_sg_one_sbale(sg_req) ||
+		    !zfcp_qdio_sg_one_sbale(sg_resp))
 			return -EOPNOTSUPP;
 
-		zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
+		zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req,
+						sg_req, sg_resp);
 		return 0;
 	}
 
 	/* use single, unchained SBAL if it can hold the request */
-	if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) {
-		zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp);
+	if (zfcp_qdio_sg_one_sbale(sg_req) || zfcp_qdio_sg_one_sbale(sg_resp)) {
+		zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req,
+						sg_req, sg_resp);
 		return 0;
 	}
 
 	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
-					SBAL_FLAGS0_TYPE_WRITE_READ,
 					sg_req, max_sbals);
 	if (bytes <= 0)
 		return -EIO;
 	req->qtcb->bottom.support.req_buf_length = bytes;
-	req->qdio_req.sbale_curr = ZFCP_LAST_SBALE_PER_SBAL;
+	zfcp_qdio_skip_to_last_sbale(&req->qdio_req);
 
 	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
-					SBAL_FLAGS0_TYPE_WRITE_READ,
 					sg_resp, max_sbals);
 	req->qtcb->bottom.support.resp_buf_length = bytes;
 	if (bytes <= 0)
@@ -1091,10 +1038,11 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
 	int ret = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
-	req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC, pool);
+	req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_GENERIC,
+				  SBAL_FLAGS0_TYPE_WRITE_READ, pool);
 
 	if (IS_ERR(req)) {
 		ret = PTR_ERR(req);
@@ -1103,7 +1051,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port,
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
 	ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
-				    FSF_MAX_SBALS_PER_REQ, timeout);
+				    ZFCP_FSF_MAX_SBALS_PER_REQ, timeout);
 	if (ret)
 		goto failed_send;
 
@@ -1187,10 +1135,11 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
 	int ret = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
-	req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS, NULL);
+	req = zfcp_fsf_req_create(qdio, FSF_QTCB_SEND_ELS,
+				  SBAL_FLAGS0_TYPE_WRITE_READ, NULL);
 
 	if (IS_ERR(req)) {
 		ret = PTR_ERR(req);
@@ -1224,16 +1173,16 @@ out:
 
 int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req;
 	struct zfcp_qdio *qdio = erp_action->adapter->qdio;
 	int retval = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
+				  SBAL_FLAGS0_TYPE_READ,
 				  qdio->adapter->pool.erp_req);
 
 	if (IS_ERR(req)) {
@@ -1242,9 +1191,7 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->qtcb->bottom.config.feature_selection =
 			FSF_FEATURE_CFDC |
@@ -1269,24 +1216,22 @@ out:
 int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio,
 				       struct fsf_qtcb_bottom_config *data)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req = NULL;
 	int retval = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out_unlock;
 
-	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA, NULL);
+	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_CONFIG_DATA,
+				  SBAL_FLAGS0_TYPE_READ, NULL);
 
 	if (IS_ERR(req)) {
 		retval = PTR_ERR(req);
 		goto out_unlock;
 	}
 
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 	req->handler = zfcp_fsf_exchange_config_data_handler;
 
 	req->qtcb->bottom.config.feature_selection =
@@ -1320,7 +1265,6 @@ out_unlock:
 int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
 {
 	struct zfcp_qdio *qdio = erp_action->adapter->qdio;
-	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
@@ -1328,10 +1272,11 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
 		return -EOPNOTSUPP;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
+				  SBAL_FLAGS0_TYPE_READ,
 				  qdio->adapter->pool.erp_req);
 
 	if (IS_ERR(req)) {
@@ -1340,9 +1285,7 @@ int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->handler = zfcp_fsf_exchange_port_data_handler;
 	req->erp_action = erp_action;
@@ -1368,7 +1311,6 @@ out:
 int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
 				     struct fsf_qtcb_bottom_port *data)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req = NULL;
 	int retval = -EIO;
 
@@ -1376,10 +1318,11 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
 		return -EOPNOTSUPP;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out_unlock;
 
-	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA, NULL);
+	req = zfcp_fsf_req_create(qdio, FSF_QTCB_EXCHANGE_PORT_DATA,
+				  SBAL_FLAGS0_TYPE_READ, NULL);
 
 	if (IS_ERR(req)) {
 		retval = PTR_ERR(req);
@@ -1389,9 +1332,7 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio,
 	if (data)
 		req->data = data;
 
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->handler = zfcp_fsf_exchange_port_data_handler;
 	zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
@@ -1485,17 +1426,17 @@ out:
  */
 int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_qdio *qdio = erp_action->adapter->qdio;
 	struct zfcp_port *port = erp_action->port;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
+				  SBAL_FLAGS0_TYPE_READ,
 				  qdio->adapter->pool.erp_req);
 
 	if (IS_ERR(req)) {
@@ -1504,9 +1445,7 @@ int zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->handler = zfcp_fsf_open_port_handler;
 	hton24(req->qtcb->bottom.support.d_id, port->d_id);
@@ -1556,16 +1495,16 @@ static void zfcp_fsf_close_port_handler(struct zfcp_fsf_req *req)
  */
 int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_qdio *qdio = erp_action->adapter->qdio;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
+				  SBAL_FLAGS0_TYPE_READ,
 				  qdio->adapter->pool.erp_req);
 
 	if (IS_ERR(req)) {
@@ -1574,9 +1513,7 @@ int zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->handler = zfcp_fsf_close_port_handler;
 	req->data = erp_action->port;
@@ -1633,16 +1570,16 @@ out:
  */
 int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_qdio *qdio = wka_port->adapter->qdio;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_PORT_WITH_DID,
+				  SBAL_FLAGS0_TYPE_READ,
 				  qdio->adapter->pool.erp_req);
 
 	if (unlikely(IS_ERR(req))) {
@@ -1651,9 +1588,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port)
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->handler = zfcp_fsf_open_wka_port_handler;
 	hton24(req->qtcb->bottom.support.d_id, wka_port->d_id);
@@ -1688,16 +1623,16 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req)
  */
 int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_qdio *qdio = wka_port->adapter->qdio;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PORT,
+				  SBAL_FLAGS0_TYPE_READ,
 				  qdio->adapter->pool.erp_req);
 
 	if (unlikely(IS_ERR(req))) {
@@ -1706,9 +1641,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port)
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->handler = zfcp_fsf_close_wka_port_handler;
 	req->data = wka_port;
@@ -1782,16 +1715,16 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req)
  */
 int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_qdio *qdio = erp_action->adapter->qdio;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_PHYSICAL_PORT,
+				  SBAL_FLAGS0_TYPE_READ,
 				  qdio->adapter->pool.erp_req);
 
 	if (IS_ERR(req)) {
@@ -1800,9 +1733,7 @@ int zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->data = erp_action->port;
 	req->qtcb->header.port_handle = erp_action->port->handle;
@@ -1954,17 +1885,17 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req)
  */
 int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 	struct zfcp_qdio *qdio = adapter->qdio;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_OPEN_LUN,
+				  SBAL_FLAGS0_TYPE_READ,
 				  adapter->pool.erp_req);
 
 	if (IS_ERR(req)) {
@@ -1973,9 +1904,7 @@ int zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-        sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-        sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->qtcb->header.port_handle = erp_action->port->handle;
 	req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
@@ -2041,16 +1970,16 @@ static void zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *req)
  */
 int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_qdio *qdio = erp_action->adapter->qdio;
 	struct zfcp_fsf_req *req;
 	int retval = -EIO;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_CLOSE_LUN,
+				  SBAL_FLAGS0_TYPE_READ,
 				  qdio->adapter->pool.erp_req);
 
 	if (IS_ERR(req)) {
@@ -2059,9 +1988,7 @@ int zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	req->qtcb->header.port_handle = erp_action->port->handle;
 	req->qtcb->header.lun_handle = erp_action->unit->handle;
@@ -2289,8 +2216,11 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
 		goto out;
 	}
 
+	if (scsi_cmnd->sc_data_direction == DMA_TO_DEVICE)
+		sbtype = SBAL_FLAGS0_TYPE_WRITE;
+
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
-				  adapter->pool.scsi_req);
+				  sbtype, adapter->pool.scsi_req);
 
 	if (IS_ERR(req)) {
 		retval = PTR_ERR(req);
@@ -2298,7 +2228,6 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
 	}
 
 	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
-	get_device(&unit->dev);
 	req->unit = unit;
 	req->data = scsi_cmnd;
 	req->handler = zfcp_fsf_send_fcp_command_handler;
@@ -2323,20 +2252,21 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
 		break;
 	case DMA_TO_DEVICE:
 		req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
-		sbtype = SBAL_FLAGS0_TYPE_WRITE;
 		break;
 	case DMA_BIDIRECTIONAL:
 		goto failed_scsi_cmnd;
 	}
 
+	get_device(&unit->dev);
+
 	fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
 	zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
 
-	real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sbtype,
+	real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
 					     scsi_sglist(scsi_cmnd),
-					     FSF_MAX_SBALS_PER_REQ);
+					     ZFCP_FSF_MAX_SBALS_PER_REQ);
 	if (unlikely(real_bytes < 0)) {
-		if (req->qdio_req.sbal_number >= FSF_MAX_SBALS_PER_REQ) {
+		if (req->qdio_req.sbal_number >= ZFCP_FSF_MAX_SBALS_PER_REQ) {
 			dev_err(&adapter->ccw_device->dev,
 				"Oversize data package, unit 0x%016Lx "
 				"on port 0x%016Lx closed\n",
@@ -2371,7 +2301,6 @@ out:
  */
 struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_fsf_req *req = NULL;
 	struct fcp_cmnd *fcp_cmnd;
 	struct zfcp_qdio *qdio = unit->port->adapter->qdio;
@@ -2381,10 +2310,11 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
 		return NULL;
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
 	req = zfcp_fsf_req_create(qdio, FSF_QTCB_FCP_CMND,
+				  SBAL_FLAGS0_TYPE_WRITE,
 				  qdio->adapter->pool.scsi_req);
 
 	if (IS_ERR(req)) {
@@ -2401,9 +2331,7 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_unit *unit, u8 tm_flags)
 	req->qtcb->bottom.io.service_class = FSF_CLASS_3;
 	req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
 
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE;
-	sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+	zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
 
 	fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
 	zfcp_fc_fcp_tm(fcp_cmnd, unit->device, tm_flags);
@@ -2432,7 +2360,6 @@ static void zfcp_fsf_control_file_handler(struct zfcp_fsf_req *req)
 struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
 					   struct zfcp_fsf_cfdc *fsf_cfdc)
 {
-	struct qdio_buffer_element *sbale;
 	struct zfcp_qdio *qdio = adapter->qdio;
 	struct zfcp_fsf_req *req = NULL;
 	struct fsf_qtcb_bottom_support *bottom;
@@ -2453,10 +2380,10 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
 	}
 
 	spin_lock_bh(&qdio->req_q_lock);
-	if (zfcp_fsf_req_sbal_get(qdio))
+	if (zfcp_qdio_sbal_get(qdio))
 		goto out;
 
-	req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, NULL);
+	req = zfcp_fsf_req_create(qdio, fsf_cfdc->command, direction, NULL);
 	if (IS_ERR(req)) {
 		retval = -EPERM;
 		goto out;
@@ -2464,16 +2391,13 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
 
 	req->handler = zfcp_fsf_control_file_handler;
 
-	sbale = zfcp_qdio_sbale_req(qdio, &req->qdio_req);
-	sbale[0].flags |= direction;
-
 	bottom = &req->qtcb->bottom.support;
 	bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
 	bottom->option = fsf_cfdc->option;
 
 	bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
-					direction, fsf_cfdc->sg,
-					FSF_MAX_SBALS_PER_REQ);
+					fsf_cfdc->sg,
+					ZFCP_FSF_MAX_SBALS_PER_REQ);
 	if (bytes != ZFCP_CFDC_MAX_SIZE) {
 		zfcp_fsf_req_free(req);
 		goto out;

+ 8 - 3
drivers/s390/scsi/zfcp_fsf.h

@@ -3,7 +3,7 @@
  *
  * Interface to the FSF support functions.
  *
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
  */
 
 #ifndef FSF_H
@@ -152,7 +152,12 @@
 #define FSF_CLASS_3				0x00000003
 
 /* SBAL chaining */
-#define FSF_MAX_SBALS_PER_REQ			36
+#define ZFCP_FSF_MAX_SBALS_PER_REQ		36
+
+/* max. number of (data buffer) SBALEs in largest SBAL chain
+ * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain   */
+#define ZFCP_FSF_MAX_SBALES_PER_REQ	\
+	(ZFCP_FSF_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
 
 /* logging space behind QTCB */
 #define FSF_QTCB_LOG_SIZE			1024
@@ -361,7 +366,7 @@ struct fsf_qtcb_bottom_config {
 	u32 adapter_type;
 	u8 res0;
 	u8 peer_d_id[3];
-	u8 res1[2];
+	u16 status_read_buf_num;
 	u16 timer_interval;
 	u8 res2[9];
 	u8 s_id[3];

+ 61 - 47
drivers/s390/scsi/zfcp_qdio.c

@@ -3,7 +3,7 @@
  *
  * Setup and helper functions to access QDIO.
  *
- * Copyright IBM Corporation 2002, 2009
+ * Copyright IBM Corporation 2002, 2010
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -151,8 +151,7 @@ static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
 }
 
 static struct qdio_buffer_element *
-zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
-		     unsigned long sbtype)
+zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
 	struct qdio_buffer_element *sbale;
 
@@ -180,17 +179,16 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
 
 	/* set storage-block type for new SBAL */
 	sbale = zfcp_qdio_sbale_curr(qdio, q_req);
-	sbale->flags |= sbtype;
+	sbale->flags |= q_req->sbtype;
 
 	return sbale;
 }
 
 static struct qdio_buffer_element *
-zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
-		     unsigned int sbtype)
+zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
-	if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
-		return zfcp_qdio_sbal_chain(qdio, q_req, sbtype);
+	if (q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL)
+		return zfcp_qdio_sbal_chain(qdio, q_req);
 	q_req->sbale_curr++;
 	return zfcp_qdio_sbale_curr(qdio, q_req);
 }
@@ -206,62 +204,38 @@ static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
 	zfcp_qdio_zero_sbals(sbal, first, count);
 }
 
-static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio,
-				struct zfcp_qdio_req *q_req,
-				unsigned int sbtype, void *start_addr,
-				unsigned int total_length)
-{
-	struct qdio_buffer_element *sbale;
-	unsigned long remaining, length;
-	void *addr;
-
-	/* split segment up */
-	for (addr = start_addr, remaining = total_length; remaining > 0;
-	     addr += length, remaining -= length) {
-		sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype);
-		if (!sbale) {
-			atomic_inc(&qdio->req_q_full);
-			zfcp_qdio_undo_sbals(qdio, q_req);
-			return -EINVAL;
-		}
-
-		/* new piece must not exceed next page boundary */
-		length = min(remaining,
-			     (PAGE_SIZE - ((unsigned long)addr &
-					   (PAGE_SIZE - 1))));
-		sbale->addr = addr;
-		sbale->length = length;
-	}
-	return 0;
-}
-
 /**
  * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
- * @fsf_req: request to be processed
- * @sbtype: SBALE flags
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: pointer to struct zfcp_qdio_req
  * @sg: scatter-gather list
  * @max_sbals: upper bound for number of SBALs to be used
  * Returns: number of bytes, or error (negativ)
  */
 int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
-			    unsigned long sbtype, struct scatterlist *sg,
-			    int max_sbals)
+			    struct scatterlist *sg, int max_sbals)
 {
 	struct qdio_buffer_element *sbale;
-	int retval, bytes = 0;
+	int bytes = 0;
 
 	/* figure out last allowed SBAL */
 	zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);
 
 	/* set storage-block type for this request */
 	sbale = zfcp_qdio_sbale_req(qdio, q_req);
-	sbale->flags |= sbtype;
+	sbale->flags |= q_req->sbtype;
 
 	for (; sg; sg = sg_next(sg)) {
-		retval = zfcp_qdio_fill_sbals(qdio, q_req, sbtype,
-					      sg_virt(sg), sg->length);
-		if (retval < 0)
-			return retval;
+		sbale = zfcp_qdio_sbale_next(qdio, q_req);
+		if (!sbale) {
+			atomic_inc(&qdio->req_q_full);
+			zfcp_qdio_undo_sbals(qdio, q_req);
+			return -EINVAL;
+		}
+
+		sbale->addr = sg_virt(sg);
+		sbale->length = sg->length;
+
 		bytes += sg->length;
 	}
 
@@ -272,6 +246,46 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
 	return bytes;
 }
 
+static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
+{
+	struct zfcp_qdio_queue *req_q = &qdio->req_q;
+
+	spin_lock_bh(&qdio->req_q_lock);
+	if (atomic_read(&req_q->count))
+		return 1;
+	spin_unlock_bh(&qdio->req_q_lock);
+	return 0;
+}
+
+/**
+ * zfcp_qdio_sbal_get - get free sbal in request queue, wait if necessary
+ * @qdio: pointer to struct zfcp_qdio
+ *
+ * The req_q_lock must be held by the caller of this function, and
+ * this function may only be called from process context; it will
+ * sleep when waiting for a free sbal.
+ *
+ * Returns: 0 on success, -EIO if there is no free sbal after waiting.
+ */
+int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
+{
+	long ret;
+
+	spin_unlock_bh(&qdio->req_q_lock);
+	ret = wait_event_interruptible_timeout(qdio->req_q_wq,
+			       zfcp_qdio_sbal_check(qdio), 5 * HZ);
+	if (ret > 0)
+		return 0;
+	if (!ret) {
+		atomic_inc(&qdio->req_q_full);
+		/* assume hanging outbound queue, try queue recovery */
+		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1", NULL);
+	}
+
+	spin_lock_bh(&qdio->req_q_lock);
+	return -EIO;
+}
+
 /**
  * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO
  * @qdio: pointer to struct zfcp_qdio

+ 104 - 0
drivers/s390/scsi/zfcp_qdio.h

@@ -11,6 +11,14 @@
 
 #include <asm/qdio.h>
 
+#define ZFCP_QDIO_SBALE_LEN	PAGE_SIZE
+
+/* DMQ bug workaround: don't use last SBALE */
+#define ZFCP_QDIO_MAX_SBALES_PER_SBAL	(QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
+
+/* index of last SBALE (with respect to DMQ bug workaround) */
+#define ZFCP_QDIO_LAST_SBALE_PER_SBAL	(ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1)
+
 /**
  * struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count
  * @sbal: qdio buffers
@@ -49,6 +57,7 @@ struct zfcp_qdio {
 
 /**
  * struct zfcp_qdio_req - qdio queue related values for a request
+ * @sbtype: sbal type flags for sbale 0
  * @sbal_number: number of free sbals
  * @sbal_first: first sbal for this request
  * @sbal_last: last sbal for this request
@@ -59,6 +68,7 @@ struct zfcp_qdio {
  * @qdio_inb_usage: usage of inbound queue
  */
 struct zfcp_qdio_req {
+	u32	sbtype;
 	u8	sbal_number;
 	u8	sbal_first;
 	u8	sbal_last;
@@ -106,4 +116,98 @@ zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 			       q_req->sbale_curr);
 }
 
+/**
+ * zfcp_qdio_req_init - initialize qdio request
+ * @qdio: request queue where to start putting the request
+ * @q_req: the qdio request to start
+ * @req_id: The request id
+ * @sbtype: type flags to set for all sbals
+ * @data: First data block
+ * @len: Length of first data block
+ *
+ * This is the start of putting the request into the queue, the last
+ * step is passing the request to zfcp_qdio_send. The request queue
+ * lock must be held during the whole process from init to send.
+ */
+static inline
+void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
+			unsigned long req_id, u32 sbtype, void *data, u32 len)
+{
+	struct qdio_buffer_element *sbale;
+
+	q_req->sbal_first = q_req->sbal_last = qdio->req_q.first;
+	q_req->sbal_number = 1;
+	q_req->sbtype = sbtype;
+
+	sbale = zfcp_qdio_sbale_req(qdio, q_req);
+	sbale->addr = (void *) req_id;
+	sbale->flags |= SBAL_FLAGS0_COMMAND;
+	sbale->flags |= sbtype;
+
+	q_req->sbale_curr = 1;
+	sbale++;
+	sbale->addr = data;
+	if (likely(data))
+		sbale->length = len;
+}
+
+/**
+ * zfcp_qdio_fill_next - Fill next sbale, only for single sbal requests
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: pointer to struct zfcp_queue_req
+ *
+ * This is only required for single sbal requests, calling it when
+ * wrapping around to the next sbal is a bug.
+ */
+static inline
+void zfcp_qdio_fill_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
+			 void *data, u32 len)
+{
+	struct qdio_buffer_element *sbale;
+
+	BUG_ON(q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL);
+	q_req->sbale_curr++;
+	sbale = zfcp_qdio_sbale_curr(qdio, q_req);
+	sbale->addr = data;
+	sbale->length = len;
+}
+
+/**
+ * zfcp_qdio_set_sbale_last - set last entry flag in current sbale
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: pointer to struct zfcp_queue_req
+ */
+static inline
+void zfcp_qdio_set_sbale_last(struct zfcp_qdio *qdio,
+			      struct zfcp_qdio_req *q_req)
+{
+	struct qdio_buffer_element *sbale;
+
+	sbale = zfcp_qdio_sbale_curr(qdio, q_req);
+	sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
+}
+
+/**
+ * zfcp_qdio_sg_one_sbal - check if one sbale is enough for sg data
+ * @sg: The scatterlist where to check the data size
+ *
+ * Returns: 1 when one sbale is enough for the data in the scatterlist,
+ *	    0 if not.
+ */
+static inline
+int zfcp_qdio_sg_one_sbale(struct scatterlist *sg)
+{
+	return sg_is_last(sg) && sg->length <= ZFCP_QDIO_SBALE_LEN;
+}
+
+/**
+ * zfcp_qdio_skip_to_last_sbale - skip to last sbale in sbal
+ * @q_req: The current zfcp_qdio_req
+ */
+static inline
+void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio_req *q_req)
+{
+	q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL;
+}
+
 #endif /* ZFCP_QDIO_H */

+ 16 - 7
drivers/s390/scsi/zfcp_scsi.c

@@ -175,7 +175,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 	struct zfcp_fsf_req *old_req, *abrt_req;
 	unsigned long flags;
 	unsigned long old_reqid = (unsigned long) scpnt->host_scribble;
-	int retval = SUCCESS;
+	int retval = SUCCESS, ret;
 	int retry = 3;
 	char *dbf_tag;
 
@@ -200,7 +200,9 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 			break;
 
 		zfcp_erp_wait(adapter);
-		fc_block_scsi_eh(scpnt);
+		ret = fc_block_scsi_eh(scpnt);
+		if (ret)
+			return ret;
 		if (!(atomic_read(&adapter->status) &
 		      ZFCP_STATUS_COMMON_RUNNING)) {
 			zfcp_dbf_scsi_abort("nres", adapter->dbf, scpnt, NULL,
@@ -231,7 +233,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
 	struct zfcp_unit *unit = scpnt->device->hostdata;
 	struct zfcp_adapter *adapter = unit->port->adapter;
 	struct zfcp_fsf_req *fsf_req = NULL;
-	int retval = SUCCESS;
+	int retval = SUCCESS, ret;
 	int retry = 3;
 
 	while (retry--) {
@@ -240,7 +242,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
 			break;
 
 		zfcp_erp_wait(adapter);
-		fc_block_scsi_eh(scpnt);
+		ret = fc_block_scsi_eh(scpnt);
+		if (ret)
+			return ret;
+
 		if (!(atomic_read(&adapter->status) &
 		      ZFCP_STATUS_COMMON_RUNNING)) {
 			zfcp_dbf_scsi_devreset("nres", tm_flags, unit, scpnt);
@@ -276,10 +281,13 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 {
 	struct zfcp_unit *unit = scpnt->device->hostdata;
 	struct zfcp_adapter *adapter = unit->port->adapter;
+	int ret;
 
 	zfcp_erp_adapter_reopen(adapter, 0, "schrh_1", scpnt);
 	zfcp_erp_wait(adapter);
-	fc_block_scsi_eh(scpnt);
+	ret = fc_block_scsi_eh(scpnt);
+	if (ret)
+		return ret;
 
 	return SUCCESS;
 }
@@ -669,11 +677,12 @@ struct zfcp_data zfcp_data = {
 		.eh_host_reset_handler	 = zfcp_scsi_eh_host_reset_handler,
 		.can_queue		 = 4096,
 		.this_id		 = -1,
-		.sg_tablesize		 = ZFCP_MAX_SBALES_PER_REQ,
+		.sg_tablesize		 = ZFCP_FSF_MAX_SBALES_PER_REQ,
 		.cmd_per_lun		 = 1,
 		.use_clustering		 = 1,
 		.sdev_attrs		 = zfcp_sysfs_sdev_attrs,
-		.max_sectors		 = (ZFCP_MAX_SBALES_PER_REQ * 8),
+		.max_sectors		 = (ZFCP_FSF_MAX_SBALES_PER_REQ * 8),
+		.dma_boundary		 = ZFCP_QDIO_SBALE_LEN - 1,
 		.shost_attrs		 = zfcp_sysfs_shost_attrs,
 	},
 };

+ 18 - 6
drivers/scsi/3w-9xxx.c

@@ -1,10 +1,11 @@
 /*
    3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
 
-   Written By: Adam Radford <linuxraid@amcc.com>
-   Modifications By: Tom Couch <linuxraid@amcc.com>
+   Written By: Adam Radford <linuxraid@lsi.com>
+   Modifications By: Tom Couch <linuxraid@lsi.com>
 
    Copyright (C) 2004-2009 Applied Micro Circuits Corporation.
+   Copyright (C) 2010 LSI Corporation.
 
    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
@@ -40,10 +41,10 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
    Bugs/Comments/Suggestions should be mailed to:
-   linuxraid@amcc.com
+   linuxraid@lsi.com
 
    For more information, goto:
-   http://www.amcc.com
+   http://www.lsi.com
 
    Note: This version of the driver does not contain a bundled firmware
          image.
@@ -77,6 +78,7 @@
                  Use pci_resource_len() for ioremap().
    2.26.02.012 - Add power management support.
    2.26.02.013 - Fix bug in twa_load_sgl().
+   2.26.02.014 - Force 60 second timeout default.
 */
 
 #include <linux/module.h>
@@ -102,14 +104,14 @@
 #include "3w-9xxx.h"
 
 /* Globals */
-#define TW_DRIVER_VERSION "2.26.02.013"
+#define TW_DRIVER_VERSION "2.26.02.014"
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static unsigned int twa_device_extension_count;
 static int twa_major = -1;
 extern struct timezone sys_tz;
 
 /* Module parameters */
-MODULE_AUTHOR ("AMCC");
+MODULE_AUTHOR ("LSI");
 MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(TW_DRIVER_VERSION);
@@ -1990,6 +1992,15 @@ static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
 		scsi_dma_unmap(cmd);
 } /* End twa_unmap_scsi_data() */
 
+/* This function gets called when a disk is coming on-line */
+static int twa_slave_configure(struct scsi_device *sdev)
+{
+	/* Force 60 second timeout */
+	blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
+
+	return 0;
+} /* End twa_slave_configure() */
+
 /* scsi_host_template initializer */
 static struct scsi_host_template driver_template = {
 	.module			= THIS_MODULE,
@@ -1999,6 +2010,7 @@ static struct scsi_host_template driver_template = {
 	.bios_param		= twa_scsi_biosparam,
 	.change_queue_depth	= twa_change_queue_depth,
 	.can_queue		= TW_Q_LENGTH-2,
+	.slave_configure	= twa_slave_configure,
 	.this_id		= -1,
 	.sg_tablesize		= TW_APACHE_MAX_SGL_LENGTH,
 	.max_sectors		= TW_MAX_SECTORS,

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

@@ -1,10 +1,11 @@
 /*
    3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux.
 
-   Written By: Adam Radford <linuxraid@amcc.com>
-   Modifications By: Tom Couch <linuxraid@amcc.com>
+   Written By: Adam Radford <linuxraid@lsi.com>
+   Modifications By: Tom Couch <linuxraid@lsi.com>
 
    Copyright (C) 2004-2009 Applied Micro Circuits Corporation.
+   Copyright (C) 2010 LSI Corporation.
 
    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
@@ -40,10 +41,10 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
    Bugs/Comments/Suggestions should be mailed to:
-   linuxraid@amcc.com
+   linuxraid@lsi.com
 
    For more information, goto:
-   http://www.amcc.com
+   http://www.lsi.com
 */
 
 #ifndef _3W_9XXX_H

+ 17 - 6
drivers/scsi/3w-xxxx.c

@@ -1,12 +1,12 @@
 /* 
    3w-xxxx.c -- 3ware Storage Controller device driver for Linux.
 
-   Written By: Adam Radford <linuxraid@amcc.com>
+   Written By: Adam Radford <linuxraid@lsi.com>
    Modifications By: Joel Jacobson <linux@3ware.com>
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2009 3ware Inc.
+   Copyright (C) 1999-2010 3ware Inc.
 
    Kernel compatibility By: 	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -47,10 +47,10 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
    Bugs/Comments/Suggestions should be mailed to:                            
-   linuxraid@amcc.com
+   linuxraid@lsi.com
 
    For more information, goto:
-   http://www.amcc.com
+   http://www.lsi.com
 
    History
    -------
@@ -194,6 +194,7 @@
    1.26.02.002 - Free irq handler in __tw_shutdown().
                  Turn on RCD bit for caching mode page.
                  Serialize reset code.
+   1.26.02.003 - Force 60 second timeout default.
 */
 
 #include <linux/module.h>
@@ -219,13 +220,13 @@
 #include "3w-xxxx.h"
 
 /* Globals */
-#define TW_DRIVER_VERSION "1.26.02.002"
+#define TW_DRIVER_VERSION "1.26.02.003"
 static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 static int tw_device_extension_count = 0;
 static int twe_major = -1;
 
 /* Module parameters */
-MODULE_AUTHOR("AMCC");
+MODULE_AUTHOR("LSI");
 MODULE_DESCRIPTION("3ware Storage Controller Linux Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(TW_DRIVER_VERSION);
@@ -2245,6 +2246,15 @@ static void tw_shutdown(struct pci_dev *pdev)
 	__tw_shutdown(tw_dev);
 } /* End tw_shutdown() */
 
+/* This function gets called when a disk is coming online */
+static int tw_slave_configure(struct scsi_device *sdev)
+{
+	/* Force 60 second timeout */
+	blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
+
+	return 0;
+} /* End tw_slave_configure() */
+
 static struct scsi_host_template driver_template = {
 	.module			= THIS_MODULE,
 	.name			= "3ware Storage Controller",
@@ -2253,6 +2263,7 @@ static struct scsi_host_template driver_template = {
 	.bios_param		= tw_scsi_biosparam,
 	.change_queue_depth	= tw_change_queue_depth,
 	.can_queue		= TW_Q_LENGTH-2,
+	.slave_configure	= tw_slave_configure,
 	.this_id		= -1,
 	.sg_tablesize		= TW_MAX_SGL_LENGTH,
 	.max_sectors		= TW_MAX_SECTORS,

+ 4 - 4
drivers/scsi/3w-xxxx.h

@@ -1,12 +1,12 @@
 /* 
    3w-xxxx.h -- 3ware Storage Controller device driver for Linux.
    
-   Written By: Adam Radford <linuxraid@amcc.com>
+   Written By: Adam Radford <linuxraid@lsi.com>
    Modifications By: Joel Jacobson <linux@3ware.com>
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
                      Brad Strand <linux@3ware.com>
 
-   Copyright (C) 1999-2009 3ware Inc.
+   Copyright (C) 1999-2010 3ware Inc.
 
    Kernel compatiblity By:	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -45,10 +45,10 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
    Bugs/Comments/Suggestions should be mailed to:                            
-   linuxraid@amcc.com
+   linuxraid@lsi.com
    
    For more information, goto:
-   http://www.amcc.com
+   http://www.lsi.com
 */
 
 #ifndef _3W_XXXX_H

+ 1 - 0
drivers/scsi/Makefile

@@ -162,6 +162,7 @@ scsi_mod-y			+= scsi_scan.o scsi_sysfs.o scsi_devinfo.o
 scsi_mod-$(CONFIG_SCSI_NETLINK)	+= scsi_netlink.o
 scsi_mod-$(CONFIG_SYSCTL)	+= scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
+scsi_mod-y			+= scsi_trace.o
 
 scsi_tgt-y			+= scsi_tgt_lib.o scsi_tgt_if.o
 

+ 157 - 152
drivers/scsi/a2091.c

@@ -19,186 +19,190 @@
 #include "wd33c93.h"
 #include "a2091.h"
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
-#define DMA(ptr) ((a2091_scsiregs *)((ptr)->base))
-#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
 
 static int a2091_release(struct Scsi_Host *instance);
 
-static irqreturn_t a2091_intr (int irq, void *_instance)
+static irqreturn_t a2091_intr(int irq, void *data)
 {
-    unsigned long flags;
-    unsigned int status;
-    struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
-
-    status = DMA(instance)->ISTR;
-    if (!(status & (ISTR_INT_F|ISTR_INT_P)) || !(status & ISTR_INTS))
-	return IRQ_NONE;
-
-    spin_lock_irqsave(instance->host_lock, flags);
-    wd33c93_intr(instance);
-    spin_unlock_irqrestore(instance->host_lock, flags);
-    return IRQ_HANDLED;
+	struct Scsi_Host *instance = data;
+	a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+	unsigned int status = regs->ISTR;
+	unsigned long flags;
+
+	if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS))
+		return IRQ_NONE;
+
+	spin_lock_irqsave(instance->host_lock, flags);
+	wd33c93_intr(instance);
+	spin_unlock_irqrestore(instance->host_lock, flags);
+	return IRQ_HANDLED;
 }
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
-    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
-    struct Scsi_Host *instance = cmd->device->host;
-
-    /* don't allow DMA if the physical address is bad */
-    if (addr & A2091_XFER_MASK)
-    {
-	HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
-	    & ~0x1ff;
-	HDATA(instance)->dma_bounce_buffer =
-	    kmalloc (HDATA(instance)->dma_bounce_len, GFP_KERNEL);
-	
-	/* can't allocate memory; use PIO */
-	if (!HDATA(instance)->dma_bounce_buffer) {
-	    HDATA(instance)->dma_bounce_len = 0;
-	    return 1;
-	}
-
-	/* get the physical address of the bounce buffer */
-	addr = virt_to_bus(HDATA(instance)->dma_bounce_buffer);
+	struct Scsi_Host *instance = cmd->device->host;
+	struct WD33C93_hostdata *hdata = shost_priv(instance);
+	a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+	unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
+	unsigned long addr = virt_to_bus(cmd->SCp.ptr);
 
-	/* the bounce buffer may not be in the first 16M of physmem */
+	/* don't allow DMA if the physical address is bad */
 	if (addr & A2091_XFER_MASK) {
-	    /* we could use chipmem... maybe later */
-	    kfree (HDATA(instance)->dma_bounce_buffer);
-	    HDATA(instance)->dma_bounce_buffer = NULL;
-	    HDATA(instance)->dma_bounce_len = 0;
-	    return 1;
+		hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+		hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
+						   GFP_KERNEL);
+
+		/* can't allocate memory; use PIO */
+		if (!hdata->dma_bounce_buffer) {
+			hdata->dma_bounce_len = 0;
+			return 1;
+		}
+
+		/* get the physical address of the bounce buffer */
+		addr = virt_to_bus(hdata->dma_bounce_buffer);
+
+		/* the bounce buffer may not be in the first 16M of physmem */
+		if (addr & A2091_XFER_MASK) {
+			/* we could use chipmem... maybe later */
+			kfree(hdata->dma_bounce_buffer);
+			hdata->dma_bounce_buffer = NULL;
+			hdata->dma_bounce_len = 0;
+			return 1;
+		}
+
+		if (!dir_in) {
+			/* copy to bounce buffer for a write */
+			memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+			       cmd->SCp.this_residual);
+		}
 	}
 
-	if (!dir_in) {
-		/* copy to bounce buffer for a write */
-		memcpy (HDATA(instance)->dma_bounce_buffer,
-			cmd->SCp.ptr, cmd->SCp.this_residual);
-	}
-    }
+	/* setup dma direction */
+	if (!dir_in)
+		cntr |= CNTR_DDIR;
 
-    /* setup dma direction */
-    if (!dir_in)
-	cntr |= CNTR_DDIR;
+	/* remember direction */
+	hdata->dma_dir = dir_in;
 
-    /* remember direction */
-    HDATA(cmd->device->host)->dma_dir = dir_in;
+	regs->CNTR = cntr;
 
-    DMA(cmd->device->host)->CNTR = cntr;
+	/* setup DMA *physical* address */
+	regs->ACR = addr;
 
-    /* setup DMA *physical* address */
-    DMA(cmd->device->host)->ACR = addr;
-
-    if (dir_in){
-	/* invalidate any cache */
-	cache_clear (addr, cmd->SCp.this_residual);
-    }else{
-	/* push any dirty cache */
-	cache_push (addr, cmd->SCp.this_residual);
-      }
-    /* start DMA */
-    DMA(cmd->device->host)->ST_DMA = 1;
+	if (dir_in) {
+		/* invalidate any cache */
+		cache_clear(addr, cmd->SCp.this_residual);
+	} else {
+		/* push any dirty cache */
+		cache_push(addr, cmd->SCp.this_residual);
+	}
+	/* start DMA */
+	regs->ST_DMA = 1;
 
-    /* return success */
-    return 0;
+	/* return success */
+	return 0;
 }
 
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
-		      int status)
+		     int status)
 {
-    /* disable SCSI interrupts */
-    unsigned short cntr = CNTR_PDMD;
-
-    if (!HDATA(instance)->dma_dir)
-	    cntr |= CNTR_DDIR;
-
-    /* disable SCSI interrupts */
-    DMA(instance)->CNTR = cntr;
-
-    /* flush if we were reading */
-    if (HDATA(instance)->dma_dir) {
-	DMA(instance)->FLUSH = 1;
-	while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
-	    ;
-    }
-
-    /* clear a possible interrupt */
-    DMA(instance)->CINT = 1;
-
-    /* stop DMA */
-    DMA(instance)->SP_DMA = 1;
-
-    /* restore the CONTROL bits (minus the direction flag) */
-    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
-
-    /* copy from a bounce buffer, if necessary */
-    if (status && HDATA(instance)->dma_bounce_buffer) {
-	if( HDATA(instance)->dma_dir )
-		memcpy (SCpnt->SCp.ptr, 
-			HDATA(instance)->dma_bounce_buffer,
-			SCpnt->SCp.this_residual);
-	kfree (HDATA(instance)->dma_bounce_buffer);
-	HDATA(instance)->dma_bounce_buffer = NULL;
-	HDATA(instance)->dma_bounce_len = 0;
-    }
+	struct WD33C93_hostdata *hdata = shost_priv(instance);
+	a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+
+	/* disable SCSI interrupts */
+	unsigned short cntr = CNTR_PDMD;
+
+	if (!hdata->dma_dir)
+		cntr |= CNTR_DDIR;
+
+	/* disable SCSI interrupts */
+	regs->CNTR = cntr;
+
+	/* flush if we were reading */
+	if (hdata->dma_dir) {
+		regs->FLUSH = 1;
+		while (!(regs->ISTR & ISTR_FE_FLG))
+			;
+	}
+
+	/* clear a possible interrupt */
+	regs->CINT = 1;
+
+	/* stop DMA */
+	regs->SP_DMA = 1;
+
+	/* restore the CONTROL bits (minus the direction flag) */
+	regs->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+	/* copy from a bounce buffer, if necessary */
+	if (status && hdata->dma_bounce_buffer) {
+		if (hdata->dma_dir)
+			memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
+			       SCpnt->SCp.this_residual);
+		kfree(hdata->dma_bounce_buffer);
+		hdata->dma_bounce_buffer = NULL;
+		hdata->dma_bounce_len = 0;
+	}
 }
 
 static int __init a2091_detect(struct scsi_host_template *tpnt)
 {
-    static unsigned char called = 0;
-    struct Scsi_Host *instance;
-    unsigned long address;
-    struct zorro_dev *z = NULL;
-    wd33c93_regs regs;
-    int num_a2091 = 0;
-
-    if (!MACH_IS_AMIGA || called)
-	return 0;
-    called = 1;
-
-    tpnt->proc_name = "A2091";
-    tpnt->proc_info = &wd33c93_proc_info;
-
-    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-	if (z->id != ZORRO_PROD_CBM_A590_A2091_1 &&
-	    z->id != ZORRO_PROD_CBM_A590_A2091_2)
-	    continue;
-	address = z->resource.start;
-	if (!request_mem_region(address, 256, "wd33c93"))
-	    continue;
-
-	instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
-	if (instance == NULL)
-	    goto release;
-	instance->base = ZTWO_VADDR(address);
-	instance->irq = IRQ_AMIGA_PORTS;
-	instance->unique_id = z->slotaddr;
-	DMA(instance)->DAWR = DAWR_A2091;
-	regs.SASR = &(DMA(instance)->SASR);
-	regs.SCMD = &(DMA(instance)->SCMD);
-	HDATA(instance)->no_sync = 0xff;
-	HDATA(instance)->fast = 0;
-	HDATA(instance)->dma_mode = CTRL_DMA;
-	wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
-	if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI",
-			instance))
-	    goto unregister;
-	DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
-	num_a2091++;
-	continue;
+	static unsigned char called = 0;
+	struct Scsi_Host *instance;
+	unsigned long address;
+	struct zorro_dev *z = NULL;
+	wd33c93_regs wdregs;
+	a2091_scsiregs *regs;
+	struct WD33C93_hostdata *hdata;
+	int num_a2091 = 0;
+
+	if (!MACH_IS_AMIGA || called)
+		return 0;
+	called = 1;
+
+	tpnt->proc_name = "A2091";
+	tpnt->proc_info = &wd33c93_proc_info;
+
+	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+		if (z->id != ZORRO_PROD_CBM_A590_A2091_1 &&
+		    z->id != ZORRO_PROD_CBM_A590_A2091_2)
+			continue;
+		address = z->resource.start;
+		if (!request_mem_region(address, 256, "wd33c93"))
+			continue;
+
+		instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
+		if (instance == NULL)
+			goto release;
+		instance->base = ZTWO_VADDR(address);
+		instance->irq = IRQ_AMIGA_PORTS;
+		instance->unique_id = z->slotaddr;
+		regs = (a2091_scsiregs *)(instance->base);
+		regs->DAWR = DAWR_A2091;
+		wdregs.SASR = &regs->SASR;
+		wdregs.SCMD = &regs->SCMD;
+		hdata = shost_priv(instance);
+		hdata->no_sync = 0xff;
+		hdata->fast = 0;
+		hdata->dma_mode = CTRL_DMA;
+		wd33c93_init(instance, wdregs, dma_setup, dma_stop,
+			     WD33C93_FS_8_10);
+		if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED,
+				"A2091 SCSI", instance))
+			goto unregister;
+		regs->CNTR = CNTR_PDMD | CNTR_INTEN;
+		num_a2091++;
+		continue;
 
 unregister:
-	scsi_unregister(instance);
-	wd33c93_release();
+		scsi_unregister(instance);
 release:
-	release_mem_region(address, 256);
-    }
+		release_mem_region(address, 256);
+	}
 
-    return num_a2091;
+	return num_a2091;
 }
 
 static int a2091_bus_reset(struct scsi_cmnd *cmd)
@@ -239,10 +243,11 @@ static struct scsi_host_template driver_template = {
 static int a2091_release(struct Scsi_Host *instance)
 {
 #ifdef MODULE
-	DMA(instance)->CNTR = 0;
+	a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+
+	regs->CNTR = 0;
 	release_mem_region(ZTWO_PADDR(instance->base), 256);
 	free_irq(IRQ_AMIGA_PORTS, instance);
-	wd33c93_release();
 #endif
 	return 1;
 }

+ 21 - 21
drivers/scsi/a2091.h

@@ -12,38 +12,38 @@
 #include <linux/types.h>
 
 #ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
+#define CMD_PER_LUN		2
 #endif
 
 #ifndef CAN_QUEUE
-#define CAN_QUEUE 16
+#define CAN_QUEUE		16
 #endif
 
 /*
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
  */
-#define A2091_XFER_MASK  (0xff000001)
+#define A2091_XFER_MASK		(0xff000001)
 
 typedef struct {
-             unsigned char      pad1[64];
-    volatile unsigned short     ISTR;
-    volatile unsigned short     CNTR;
-             unsigned char      pad2[60];
-    volatile unsigned int       WTC;
-    volatile unsigned long      ACR;
-             unsigned char      pad3[6];
-    volatile unsigned short     DAWR;
-             unsigned char      pad4;
-    volatile unsigned char      SASR;
-             unsigned char      pad5;
-    volatile unsigned char      SCMD;
-             unsigned char      pad6[76];
-    volatile unsigned short     ST_DMA;
-    volatile unsigned short     SP_DMA;
-    volatile unsigned short     CINT;
-             unsigned char      pad7[2];
-    volatile unsigned short     FLUSH;
+		 unsigned char	pad1[64];
+	volatile unsigned short	ISTR;
+	volatile unsigned short	CNTR;
+		 unsigned char	pad2[60];
+	volatile unsigned int	WTC;
+	volatile unsigned long	ACR;
+		 unsigned char	pad3[6];
+	volatile unsigned short	DAWR;
+		 unsigned char	pad4;
+	volatile unsigned char	SASR;
+		 unsigned char	pad5;
+	volatile unsigned char	SCMD;
+		 unsigned char	pad6[76];
+	volatile unsigned short	ST_DMA;
+	volatile unsigned short	SP_DMA;
+	volatile unsigned short	CINT;
+		 unsigned char	pad7[2];
+	volatile unsigned short	FLUSH;
 } a2091_scsiregs;
 
 #define DAWR_A2091		(3)

+ 143 - 142
drivers/scsi/a3000.c

@@ -19,26 +19,25 @@
 #include "wd33c93.h"
 #include "a3000.h"
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
-#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
-#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+#define DMA(ptr)	((a3000_scsiregs *)((ptr)->base))
 
 static struct Scsi_Host *a3000_host = NULL;
 
 static int a3000_release(struct Scsi_Host *instance);
 
-static irqreturn_t a3000_intr (int irq, void *dummy)
+static irqreturn_t a3000_intr(int irq, void *dummy)
 {
 	unsigned long flags;
 	unsigned int status = DMA(a3000_host)->ISTR;
 
 	if (!(status & ISTR_INT_P))
 		return IRQ_NONE;
-	if (status & ISTR_INTS)
-	{
+	if (status & ISTR_INTS) {
 		spin_lock_irqsave(a3000_host->host_lock, flags);
-		wd33c93_intr (a3000_host);
+		wd33c93_intr(a3000_host);
 		spin_unlock_irqrestore(a3000_host->host_lock, flags);
 		return IRQ_HANDLED;
 	}
@@ -48,162 +47,165 @@ static irqreturn_t a3000_intr (int irq, void *dummy)
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
-    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
-
-    /*
-     * if the physical address has the wrong alignment, or if
-     * physical address is bad, or if it is a write and at the
-     * end of a physical memory chunk, then allocate a bounce
-     * buffer
-     */
-    if (addr & A3000_XFER_MASK)
-    {
-	HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
-	    & ~0x1ff;
-	HDATA(a3000_host)->dma_bounce_buffer =
-	    kmalloc (HDATA(a3000_host)->dma_bounce_len, GFP_KERNEL);
-	
-	/* can't allocate memory; use PIO */
-	if (!HDATA(a3000_host)->dma_bounce_buffer) {
-	    HDATA(a3000_host)->dma_bounce_len = 0;
-	    return 1;
-	}
-
-	if (!dir_in) {
-	    /* copy to bounce buffer for a write */
-	    memcpy (HDATA(a3000_host)->dma_bounce_buffer,
-		cmd->SCp.ptr, cmd->SCp.this_residual);
+	struct WD33C93_hostdata *hdata = shost_priv(a3000_host);
+	unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
+	unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+
+	/*
+	 * if the physical address has the wrong alignment, or if
+	 * physical address is bad, or if it is a write and at the
+	 * end of a physical memory chunk, then allocate a bounce
+	 * buffer
+	 */
+	if (addr & A3000_XFER_MASK) {
+		hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+		hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
+						   GFP_KERNEL);
+
+		/* can't allocate memory; use PIO */
+		if (!hdata->dma_bounce_buffer) {
+			hdata->dma_bounce_len = 0;
+			return 1;
+		}
+
+		if (!dir_in) {
+			/* copy to bounce buffer for a write */
+			memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+			       cmd->SCp.this_residual);
+		}
+
+		addr = virt_to_bus(hdata->dma_bounce_buffer);
 	}
 
-	addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
-    }
+	/* setup dma direction */
+	if (!dir_in)
+		cntr |= CNTR_DDIR;
 
-    /* setup dma direction */
-    if (!dir_in)
-	cntr |= CNTR_DDIR;
+	/* remember direction */
+	hdata->dma_dir = dir_in;
 
-    /* remember direction */
-    HDATA(a3000_host)->dma_dir = dir_in;
+	DMA(a3000_host)->CNTR = cntr;
 
-    DMA(a3000_host)->CNTR = cntr;
+	/* setup DMA *physical* address */
+	DMA(a3000_host)->ACR = addr;
 
-    /* setup DMA *physical* address */
-    DMA(a3000_host)->ACR = addr;
-
-    if (dir_in)
-  	/* invalidate any cache */
-	cache_clear (addr, cmd->SCp.this_residual);
-    else
-	/* push any dirty cache */
-	cache_push (addr, cmd->SCp.this_residual);
+	if (dir_in) {
+		/* invalidate any cache */
+		cache_clear(addr, cmd->SCp.this_residual);
+	} else {
+		/* push any dirty cache */
+		cache_push(addr, cmd->SCp.this_residual);
+	}
 
-    /* start DMA */
-    mb();			/* make sure setup is completed */
-    DMA(a3000_host)->ST_DMA = 1;
-    mb();			/* make sure DMA has started before next IO */
+	/* start DMA */
+	mb();			/* make sure setup is completed */
+	DMA(a3000_host)->ST_DMA = 1;
+	mb();			/* make sure DMA has started before next IO */
 
-    /* return success */
-    return 0;
+	/* return success */
+	return 0;
 }
 
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 		     int status)
 {
-    /* disable SCSI interrupts */
-    unsigned short cntr = CNTR_PDMD;
-
-    if (!HDATA(instance)->dma_dir)
-	cntr |= CNTR_DDIR;
-
-    DMA(instance)->CNTR = cntr;
-    mb();			/* make sure CNTR is updated before next IO */
-
-    /* flush if we were reading */
-    if (HDATA(instance)->dma_dir) {
-	DMA(instance)->FLUSH = 1;
-	mb();			/* don't allow prefetch */
-	while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
-	    barrier();
-	mb();			/* no IO until FLUSH is done */
-    }
-
-    /* clear a possible interrupt */
-    /* I think that this CINT is only necessary if you are
-     * using the terminal count features.   HM 7 Mar 1994
-     */
-    DMA(instance)->CINT = 1;
-
-    /* stop DMA */
-    DMA(instance)->SP_DMA = 1;
-    mb();			/* make sure DMA is stopped before next IO */
-
-    /* restore the CONTROL bits (minus the direction flag) */
-    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
-    mb();			/* make sure CNTR is updated before next IO */
-
-    /* copy from a bounce buffer, if necessary */
-    if (status && HDATA(instance)->dma_bounce_buffer) {
-	if (SCpnt) {
-	    if (HDATA(instance)->dma_dir && SCpnt)
-		memcpy (SCpnt->SCp.ptr,
-			HDATA(instance)->dma_bounce_buffer,
-			SCpnt->SCp.this_residual);
-	    kfree (HDATA(instance)->dma_bounce_buffer);
-	    HDATA(instance)->dma_bounce_buffer = NULL;
-	    HDATA(instance)->dma_bounce_len = 0;
-	} else {
-	    kfree (HDATA(instance)->dma_bounce_buffer);
-	    HDATA(instance)->dma_bounce_buffer = NULL;
-	    HDATA(instance)->dma_bounce_len = 0;
+	struct WD33C93_hostdata *hdata = shost_priv(instance);
+
+	/* disable SCSI interrupts */
+	unsigned short cntr = CNTR_PDMD;
+
+	if (!hdata->dma_dir)
+		cntr |= CNTR_DDIR;
+
+	DMA(instance)->CNTR = cntr;
+	mb();			/* make sure CNTR is updated before next IO */
+
+	/* flush if we were reading */
+	if (hdata->dma_dir) {
+		DMA(instance)->FLUSH = 1;
+		mb();		/* don't allow prefetch */
+		while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
+			barrier();
+		mb();		/* no IO until FLUSH is done */
+	}
+
+	/* clear a possible interrupt */
+	/* I think that this CINT is only necessary if you are
+	 * using the terminal count features.   HM 7 Mar 1994
+	 */
+	DMA(instance)->CINT = 1;
+
+	/* stop DMA */
+	DMA(instance)->SP_DMA = 1;
+	mb();			/* make sure DMA is stopped before next IO */
+
+	/* restore the CONTROL bits (minus the direction flag) */
+	DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+	mb();			/* make sure CNTR is updated before next IO */
+
+	/* copy from a bounce buffer, if necessary */
+	if (status && hdata->dma_bounce_buffer) {
+		if (SCpnt) {
+			if (hdata->dma_dir && SCpnt)
+				memcpy(SCpnt->SCp.ptr,
+				       hdata->dma_bounce_buffer,
+				       SCpnt->SCp.this_residual);
+			kfree(hdata->dma_bounce_buffer);
+			hdata->dma_bounce_buffer = NULL;
+			hdata->dma_bounce_len = 0;
+		} else {
+			kfree(hdata->dma_bounce_buffer);
+			hdata->dma_bounce_buffer = NULL;
+			hdata->dma_bounce_len = 0;
+		}
 	}
-    }
 }
 
 static int __init a3000_detect(struct scsi_host_template *tpnt)
 {
-    wd33c93_regs regs;
-
-    if  (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
-	return 0;
-    if (!request_mem_region(0xDD0000, 256, "wd33c93"))
-	return 0;
-
-    tpnt->proc_name = "A3000";
-    tpnt->proc_info = &wd33c93_proc_info;
-
-    a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
-    if (a3000_host == NULL)
-	goto fail_register;
-
-    a3000_host->base = ZTWO_VADDR(0xDD0000);
-    a3000_host->irq = IRQ_AMIGA_PORTS;
-    DMA(a3000_host)->DAWR = DAWR_A3000;
-    regs.SASR = &(DMA(a3000_host)->SASR);
-    regs.SCMD = &(DMA(a3000_host)->SCMD);
-    HDATA(a3000_host)->no_sync = 0xff;
-    HDATA(a3000_host)->fast = 0;
-    HDATA(a3000_host)->dma_mode = CTRL_DMA;
-    wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
-    if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
-		    a3000_intr))
-        goto fail_irq;
-    DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
-
-    return 1;
+	wd33c93_regs regs;
+	struct WD33C93_hostdata *hdata;
+
+	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
+		return 0;
+	if (!request_mem_region(0xDD0000, 256, "wd33c93"))
+		return 0;
+
+	tpnt->proc_name = "A3000";
+	tpnt->proc_info = &wd33c93_proc_info;
+
+	a3000_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
+	if (a3000_host == NULL)
+		goto fail_register;
+
+	a3000_host->base = ZTWO_VADDR(0xDD0000);
+	a3000_host->irq = IRQ_AMIGA_PORTS;
+	DMA(a3000_host)->DAWR = DAWR_A3000;
+	regs.SASR = &(DMA(a3000_host)->SASR);
+	regs.SCMD = &(DMA(a3000_host)->SCMD);
+	hdata = shost_priv(a3000_host);
+	hdata->no_sync = 0xff;
+	hdata->fast = 0;
+	hdata->dma_mode = CTRL_DMA;
+	wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
+	if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
+			a3000_intr))
+		goto fail_irq;
+	DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+	return 1;
 
 fail_irq:
-    wd33c93_release();
-    scsi_unregister(a3000_host);
+	scsi_unregister(a3000_host);
 fail_register:
-    release_mem_region(0xDD0000, 256);
-    return 0;
+	release_mem_region(0xDD0000, 256);
+	return 0;
 }
 
 static int a3000_bus_reset(struct scsi_cmnd *cmd)
 {
 	/* FIXME perform bus-specific reset */
-	
+
 	/* FIXME 2: kill this entire function, which should
 	   cause mid-layer to call wd33c93_host_reset anyway? */
 
@@ -237,11 +239,10 @@ static struct scsi_host_template driver_template = {
 
 static int a3000_release(struct Scsi_Host *instance)
 {
-    wd33c93_release();
-    DMA(instance)->CNTR = 0;
-    release_mem_region(0xDD0000, 256);
-    free_irq(IRQ_AMIGA_PORTS, a3000_intr);
-    return 1;
+	DMA(instance)->CNTR = 0;
+	release_mem_region(0xDD0000, 256);
+	free_irq(IRQ_AMIGA_PORTS, a3000_intr);
+	return 1;
 }
 
 MODULE_LICENSE("GPL");

+ 23 - 23
drivers/scsi/a3000.h

@@ -12,40 +12,40 @@
 #include <linux/types.h>
 
 #ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
+#define CMD_PER_LUN		2
 #endif
 
 #ifndef CAN_QUEUE
-#define CAN_QUEUE 16
+#define CAN_QUEUE		16
 #endif
 
 /*
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
  */
-#define A3000_XFER_MASK  (0x00000003)
+#define A3000_XFER_MASK		(0x00000003)
 
 typedef struct {
-             unsigned char      pad1[2];
-    volatile unsigned short     DAWR;
-    volatile unsigned int       WTC;
-             unsigned char      pad2[2];
-    volatile unsigned short     CNTR;
-    volatile unsigned long      ACR;
-             unsigned char      pad3[2];
-    volatile unsigned short     ST_DMA;
-             unsigned char      pad4[2];
-    volatile unsigned short     FLUSH;
-             unsigned char      pad5[2];
-    volatile unsigned short     CINT;
-             unsigned char      pad6[2];
-    volatile unsigned short     ISTR;
-	     unsigned char      pad7[30];
-    volatile unsigned short     SP_DMA;
-             unsigned char      pad8;
-    volatile unsigned char      SASR;
-             unsigned char      pad9;
-    volatile unsigned char      SCMD;
+		 unsigned char	pad1[2];
+	volatile unsigned short	DAWR;
+	volatile unsigned int	WTC;
+		 unsigned char	pad2[2];
+	volatile unsigned short	CNTR;
+	volatile unsigned long	ACR;
+		 unsigned char	pad3[2];
+	volatile unsigned short	ST_DMA;
+		 unsigned char	pad4[2];
+	volatile unsigned short	FLUSH;
+		 unsigned char	pad5[2];
+	volatile unsigned short	CINT;
+		 unsigned char	pad6[2];
+	volatile unsigned short	ISTR;
+		 unsigned char	pad7[30];
+	volatile unsigned short	SP_DMA;
+		 unsigned char	pad8;
+	volatile unsigned char	SASR;
+		 unsigned char	pad9;
+	volatile unsigned char	SCMD;
 } a3000_scsiregs;
 
 #define DAWR_A3000		(3)

+ 65 - 2
drivers/scsi/aacraid/aachba.c

@@ -328,6 +328,16 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
 	return status;
 }
 
+static void aac_expose_phy_device(struct scsi_cmnd *scsicmd)
+{
+	char inq_data;
+	scsi_sg_copy_to_buffer(scsicmd,  &inq_data, sizeof(inq_data));
+	if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) {
+		inq_data &= 0xdf;
+		scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
+	}
+}
+
 /**
  *	aac_get_containers	-	list containers
  *	@common: adapter to probe
@@ -1598,6 +1608,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
 	int status;
 	struct aac_dev *dev;
 	struct fib * cmd_fibcontext;
+	int cid;
 
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	/*
@@ -1647,6 +1658,22 @@ static int aac_read(struct scsi_cmnd * scsicmd)
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 		break;
 	}
+
+	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
+		cid = scmd_id(scsicmd);
+		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+			SAM_STAT_CHECK_CONDITION;
+		set_sense(&dev->fsa_dev[cid].sense_data,
+			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+			     SCSI_SENSE_BUFFERSIZE));
+		scsicmd->scsi_done(scsicmd);
+		return 1;
+	}
+
 	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
 	  smp_processor_id(), (unsigned long long)lba, jiffies));
 	if (aac_adapter_bounds(dev,scsicmd,lba))
@@ -1688,6 +1715,7 @@ static int aac_write(struct scsi_cmnd * scsicmd)
 	int status;
 	struct aac_dev *dev;
 	struct fib * cmd_fibcontext;
+	int cid;
 
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	/*
@@ -1727,6 +1755,22 @@ static int aac_write(struct scsi_cmnd * scsicmd)
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 		fua = scsicmd->cmnd[1] & 0x8;
 	}
+
+	if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) {
+		cid = scmd_id(scsicmd);
+		dprintk((KERN_DEBUG "aacraid: Illegal lba\n"));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+			SAM_STAT_CHECK_CONDITION;
+		set_sense(&dev->fsa_dev[cid].sense_data,
+			  HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
+			  ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+			     SCSI_SENSE_BUFFERSIZE));
+		scsicmd->scsi_done(scsicmd);
+		return 1;
+	}
+
 	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
 	  smp_processor_id(), (unsigned long long)lba, jiffies));
 	if (aac_adapter_bounds(dev,scsicmd,lba))
@@ -2573,6 +2617,11 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 
 	scsi_dma_unmap(scsicmd);
 
+	/* expose physical device if expose_physicald flag is on */
+	if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
+	  && expose_physicals > 0)
+		aac_expose_phy_device(scsicmd);
+
 	/*
 	 * First check the fib status
 	 */
@@ -2678,8 +2727,22 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 			scsicmd->cmnd[0],
 			le32_to_cpu(srbreply->scsi_status));
 #endif
-		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
-		break;
+		if ((scsicmd->cmnd[0] == ATA_12)
+		  || (scsicmd->cmnd[0] == ATA_16)) {
+			if (scsicmd->cmnd[2] & (0x01 << 5)) {
+				scsicmd->result = DID_OK << 16
+						| COMMAND_COMPLETE << 8;
+				break;
+			} else {
+				scsicmd->result = DID_ERROR << 16
+						| COMMAND_COMPLETE << 8;
+				break;
+			}
+		} else {
+			scsicmd->result = DID_ERROR << 16
+					| COMMAND_COMPLETE << 8;
+			break;
+		}
 	}
 	if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {
 		int len;

+ 3 - 1
drivers/scsi/aacraid/aacraid.h

@@ -12,7 +12,7 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 24702
+# define AAC_DRIVER_BUILD 26400
 # define AAC_DRIVER_BRANCH "-ms"
 #endif
 #define MAXIMUM_NUM_CONTAINERS	32
@@ -26,6 +26,8 @@
 #define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff)
 #define AAC_MAX_32BIT_SGBCOUNT	((unsigned short)256)
 
+#define AAC_DEBUG_INSTRUMENT_AIF_DELETE
+
 /*
  * These macros convert from physical channels to virtual channels
  */

+ 18 - 0
drivers/scsi/aacraid/commsup.c

@@ -966,6 +966,16 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 			device_config_needed =
 			  (((__le32 *)aifcmd->data)[0] ==
 			    cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE;
+			if (device_config_needed == ADD) {
+				device = scsi_device_lookup(dev->scsi_host_ptr,
+					channel,
+					id,
+					lun);
+				if (device) {
+					scsi_remove_device(device);
+					scsi_device_put(device);
+				}
+			}
 			break;
 
 		case AifEnEnclosureManagement:
@@ -1123,6 +1133,9 @@ retry_next:
 	if (device) {
 		switch (device_config_needed) {
 		case DELETE:
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE))
+			scsi_remove_device(device);
+#else
 			if (scsi_device_online(device)) {
 				scsi_device_set_state(device, SDEV_OFFLINE);
 				sdev_printk(KERN_INFO, device,
@@ -1131,6 +1144,7 @@ retry_next:
 						"array deleted" :
 						"enclosure services event");
 			}
+#endif
 			break;
 		case ADD:
 			if (!scsi_device_online(device)) {
@@ -1145,12 +1159,16 @@ retry_next:
 		case CHANGE:
 			if ((channel == CONTAINER_CHANNEL)
 			 && (!dev->fsa_dev[container].valid)) {
+#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE))
+				scsi_remove_device(device);
+#else
 				if (!scsi_device_online(device))
 					break;
 				scsi_device_set_state(device, SDEV_OFFLINE);
 				sdev_printk(KERN_INFO, device,
 					"Device offlined - %s\n",
 					"array failed");
+#endif
 				break;
 			}
 			scsi_rescan_device(&device->sdev_gendev);

+ 0 - 29
drivers/scsi/bfa/bfa_cb_ioim_macros.h

@@ -116,35 +116,6 @@ bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio)
 	return 0;
 }
 
-/**
- * Get SG element for the I/O request given the SG element index
- */
-static inline union bfi_addr_u
-bfa_cb_ioim_get_sgaddr(struct bfad_ioim_s *dio, int sgeid)
-{
-	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
-	struct scatterlist *sge;
-	u64        addr;
-
-	sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
-	addr = (u64) sg_dma_address(sge);
-
-	return *((union bfi_addr_u *) &addr);
-}
-
-static inline u32
-bfa_cb_ioim_get_sglen(struct bfad_ioim_s *dio, int sgeid)
-{
-	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
-	struct scatterlist *sge;
-	u32        len;
-
-	sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
-	len = sg_dma_len(sge);
-
-	return len;
-}
-
 /**
  * Get Command Reference Number for the I/O request. 0 if none.
  */

+ 17 - 5
drivers/scsi/bfa/bfa_ioim.c

@@ -731,6 +731,9 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
 	static struct fcp_cmnd_s cmnd_z0 = { 0 };
 	struct bfi_sge_s      *sge;
 	u32        pgdlen = 0;
+	u64 addr;
+	struct scatterlist *sg;
+	struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
 
 	/**
 	 * check for room in queue to send request now
@@ -754,8 +757,10 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
 	 */
 	sge = &m->sges[0];
 	if (ioim->nsges) {
-		sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, 0);
-		pgdlen = bfa_cb_ioim_get_sglen(ioim->dio, 0);
+		sg = (struct scatterlist *)scsi_sglist(cmnd);
+		addr = bfa_os_sgaddr(sg_dma_address(sg));
+		sge->sga = *(union bfi_addr_u *) &addr;
+		pgdlen = sg_dma_len(sg);
 		sge->sg_len = pgdlen;
 		sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?
 					BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST;
@@ -868,10 +873,16 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
 	struct bfi_sge_s      *sge;
 	struct bfa_sgpg_s *sgpg;
 	u32        pgcumsz;
+	u64        addr;
+	struct scatterlist *sg;
+	struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio;
 
 	sgeid = BFI_SGE_INLINE;
 	ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q);
 
+	sg = scsi_sglist(cmnd);
+	sg = sg_next(sg);
+
 	do {
 		sge = sgpg->sgpg->sges;
 		nsges = ioim->nsges - sgeid;
@@ -879,9 +890,10 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
 			nsges = BFI_SGPG_DATA_SGES;
 
 		pgcumsz = 0;
-		for (i = 0; i < nsges; i++, sge++, sgeid++) {
-			sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, sgeid);
-			sge->sg_len = bfa_cb_ioim_get_sglen(ioim->dio, sgeid);
+		for (i = 0; i < nsges; i++, sge++, sgeid++, sg = sg_next(sg)) {
+			addr = bfa_os_sgaddr(sg_dma_address(sg));
+			sge->sga = *(union bfi_addr_u *) &addr;
+			sge->sg_len = sg_dma_len(sg);
 			pgcumsz += sge->sg_len;
 
 			/**

+ 19 - 4
drivers/scsi/bfa/bfa_os_inc.h

@@ -50,6 +50,10 @@
 #include <scsi/scsi_transport_fc.h>
 #include <scsi/scsi_transport.h>
 
+#ifdef __BIG_ENDIAN
+#define __BIGENDIAN
+#endif
+
 #define BFA_ERR			KERN_ERR
 #define BFA_WARNING		KERN_WARNING
 #define BFA_NOTICE		KERN_NOTICE
@@ -123,6 +127,15 @@ int bfa_os_MWB(void *);
 	(((_x) & 0x00ff0000) >> 8)	|	\
 	(((_x) & 0xff000000) >> 24))
 
+#define bfa_os_swap_sgaddr(_x)	((u64)(					\
+	(((u64)(_x) & (u64)0x00000000000000ffull) << 32)	|	\
+	(((u64)(_x) & (u64)0x000000000000ff00ull) << 32)	|	\
+	(((u64)(_x) & (u64)0x0000000000ff0000ull) << 32)	|	\
+	(((u64)(_x) & (u64)0x00000000ff000000ull) << 32)	|	\
+	(((u64)(_x) & (u64)0x000000ff00000000ull) >> 32)	|	\
+	(((u64)(_x) & (u64)0x0000ff0000000000ull) >> 32)	|	\
+	(((u64)(_x) & (u64)0x00ff000000000000ull) >> 32)	|	\
+	(((u64)(_x) & (u64)0xff00000000000000ull) >> 32)))
 
 #ifndef __BIGENDIAN
 #define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \
@@ -133,6 +146,7 @@ int bfa_os_MWB(void *);
 #define bfa_os_hton3b(_x)	bfa_swap_3b(_x)
 
 #define bfa_os_wtole(_x)   (_x)
+#define bfa_os_sgaddr(_x)  (_x)
 
 #else
 
@@ -141,6 +155,7 @@ int bfa_os_MWB(void *);
 #define bfa_os_hton3b(_x)  (_x)
 #define bfa_os_htonll(_x)  (_x)
 #define bfa_os_wtole(_x)   bfa_os_swap32(_x)
+#define bfa_os_sgaddr(_x)  bfa_os_swap_sgaddr(_x)
 
 #endif
 
@@ -161,12 +176,12 @@ int bfa_os_MWB(void *);
 #define bfa_os_addr_t char __iomem *
 #define bfa_os_panic()
 
-#define bfa_os_reg_read(_raddr) bfa_os_wtole(readl(_raddr))
-#define bfa_os_reg_write(_raddr, _val) writel(bfa_os_wtole((_val)), (_raddr))
+#define bfa_os_reg_read(_raddr) readl(_raddr)
+#define bfa_os_reg_write(_raddr, _val) writel((_val), (_raddr))
 #define bfa_os_mem_read(_raddr, _off)                                   \
-	bfa_os_ntohl(readl(((_raddr) + (_off))))
+	bfa_os_swap32(readl(((_raddr) + (_off))))
 #define bfa_os_mem_write(_raddr, _off, _val)                            \
-	writel(bfa_os_htonl((_val)), ((_raddr) + (_off)))
+	writel(bfa_os_swap32((_val)), ((_raddr) + (_off)))
 
 #define BFA_TRC_TS(_trcm)						\
 			({						\

+ 7 - 14
drivers/scsi/bfa/bfad.c

@@ -33,7 +33,7 @@
 #include <fcb/bfa_fcb.h>
 
 BFA_TRC_FILE(LDRV, BFAD);
-static DEFINE_MUTEX(bfad_mutex);
+DEFINE_MUTEX(bfad_mutex);
 LIST_HEAD(bfad_list);
 static int      bfad_inst;
 int bfad_supported_fc4s;
@@ -299,8 +299,6 @@ bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv)
 		complete(vport_drv->comp_del);
 		return;
 	}
-
-	kfree(vport_drv);
 }
 
 /**
@@ -483,7 +481,7 @@ ext:
  */
 bfa_status_t
 bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
-		  struct bfa_port_cfg_s *port_cfg)
+		  struct bfa_port_cfg_s *port_cfg, struct device *dev)
 {
 	struct bfad_vport_s *vport;
 	int             rc = BFA_STATUS_OK;
@@ -506,7 +504,8 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
 		goto ext_free_vport;
 
 	if (port_cfg->roles & BFA_PORT_ROLE_FCP_IM) {
-		rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port);
+		rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port,
+							dev);
 		if (rc != BFA_STATUS_OK)
 			goto ext_free_fcs_vport;
 	}
@@ -591,7 +590,6 @@ bfad_init_timer(struct bfad_s *bfad)
 int
 bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
 {
-	unsigned long   bar0_len;
 	int             rc = -ENODEV;
 
 	if (pci_enable_device(pdev)) {
@@ -611,9 +609,7 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
 			goto out_release_region;
 		}
 
-	bfad->pci_bar0_map = pci_resource_start(pdev, 0);
-	bar0_len = pci_resource_len(pdev, 0);
-	bfad->pci_bar0_kva = ioremap(bfad->pci_bar0_map, bar0_len);
+	bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
 
 	if (bfad->pci_bar0_kva == NULL) {
 		BFA_PRINTF(BFA_ERR, "Fail to map bar0\n");
@@ -646,11 +642,7 @@ out:
 void
 bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad)
 {
-#if defined(__ia64__)
 	pci_iounmap(pdev, bfad->pci_bar0_kva);
-#else
-	iounmap(bfad->pci_bar0_kva);
-#endif
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
@@ -848,7 +840,8 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role)
 			goto out;
 		}
 
-		rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port);
+		rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port,
+						&bfad->pcidev->dev);
 		if (rc != BFA_STATUS_OK)
 			goto out;
 

+ 201 - 0
drivers/scsi/bfa/bfad_attr.c

@@ -364,6 +364,152 @@ bfad_im_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
 
 }
 
+static int
+bfad_im_vport_create(struct fc_vport *fc_vport, bool disable)
+{
+	char *vname = fc_vport->symbolic_name;
+	struct Scsi_Host *shost = fc_vport->shost;
+	struct bfad_im_port_s *im_port =
+		(struct bfad_im_port_s *) shost->hostdata[0];
+	struct bfad_s *bfad = im_port->bfad;
+	struct bfa_port_cfg_s port_cfg;
+	int status = 0, rc;
+	unsigned long flags;
+
+	memset(&port_cfg, 0, sizeof(port_cfg));
+
+	port_cfg.pwwn = wwn_to_u64((u8 *) &fc_vport->port_name);
+	port_cfg.nwwn = wwn_to_u64((u8 *) &fc_vport->node_name);
+
+	if (strlen(vname) > 0)
+		strcpy((char *)&port_cfg.sym_name, vname);
+
+	port_cfg.roles = BFA_PORT_ROLE_FCP_IM;
+	rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev);
+
+	if (rc == BFA_STATUS_OK) {
+		struct bfad_vport_s   *vport;
+		struct bfa_fcs_vport_s *fcs_vport;
+		struct Scsi_Host *vshost;
+
+		spin_lock_irqsave(&bfad->bfad_lock, flags);
+		fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0,
+					port_cfg.pwwn);
+		if (fcs_vport == NULL) {
+			spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+			return VPCERR_BAD_WWN;
+		}
+
+		fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
+		if (disable) {
+			bfa_fcs_vport_stop(fcs_vport);
+			fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
+		}
+		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+		vport = fcs_vport->vport_drv;
+		vshost = vport->drv_port.im_port->shost;
+		fc_host_node_name(vshost) = wwn_to_u64((u8 *) &port_cfg.nwwn);
+		fc_host_port_name(vshost) = wwn_to_u64((u8 *) &port_cfg.pwwn);
+		fc_vport->dd_data = vport;
+		vport->drv_port.im_port->fc_vport = fc_vport;
+
+	} else if (rc == BFA_STATUS_INVALID_WWN)
+		return VPCERR_BAD_WWN;
+	else if (rc == BFA_STATUS_VPORT_EXISTS)
+		return VPCERR_BAD_WWN;
+	else if (rc == BFA_STATUS_VPORT_MAX)
+		return VPCERR_NO_FABRIC_SUPP;
+	else if (rc == BFA_STATUS_VPORT_WWN_BP)
+		return VPCERR_BAD_WWN;
+	 else
+		return FC_VPORT_FAILED;
+
+	return status;
+}
+
+static int
+bfad_im_vport_delete(struct fc_vport *fc_vport)
+{
+	struct bfad_vport_s *vport = (struct bfad_vport_s *)fc_vport->dd_data;
+	struct bfad_im_port_s *im_port =
+			(struct bfad_im_port_s *) vport->drv_port.im_port;
+	struct bfad_s *bfad = im_port->bfad;
+	struct bfad_port_s *port;
+	struct bfa_fcs_vport_s *fcs_vport;
+	struct Scsi_Host *vshost;
+	wwn_t   pwwn;
+	int rc;
+	unsigned long flags;
+	struct completion fcomp;
+
+	if (im_port->flags & BFAD_PORT_DELETE)
+		goto free_scsi_host;
+
+	port = im_port->port;
+
+	vshost = vport->drv_port.im_port->shost;
+	pwwn = wwn_to_u64((u8 *) &fc_host_port_name(vshost));
+
+	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn);
+	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+	if (fcs_vport == NULL)
+		return VPCERR_BAD_WWN;
+
+	vport->drv_port.flags |= BFAD_PORT_DELETE;
+
+	vport->comp_del = &fcomp;
+	init_completion(vport->comp_del);
+
+	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	rc = bfa_fcs_vport_delete(&vport->fcs_vport);
+	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+	wait_for_completion(vport->comp_del);
+
+free_scsi_host:
+	bfad_os_scsi_host_free(bfad, im_port);
+
+	kfree(vport);
+
+	return 0;
+}
+
+static int
+bfad_im_vport_disable(struct fc_vport *fc_vport, bool disable)
+{
+	struct bfad_vport_s *vport;
+	struct bfad_s *bfad;
+	struct bfa_fcs_vport_s *fcs_vport;
+	struct Scsi_Host *vshost;
+	wwn_t   pwwn;
+	unsigned long flags;
+
+	vport = (struct bfad_vport_s *)fc_vport->dd_data;
+	bfad = vport->drv_port.bfad;
+	vshost = vport->drv_port.im_port->shost;
+	pwwn = wwn_to_u64((u8 *) &fc_vport->port_name);
+
+	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn);
+	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+	if (fcs_vport == NULL)
+		return VPCERR_BAD_WWN;
+
+	if (disable) {
+		bfa_fcs_vport_stop(fcs_vport);
+		fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
+	} else {
+		bfa_fcs_vport_start(fcs_vport);
+		fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
+	}
+
+	return 0;
+}
+
 struct fc_function_template bfad_im_fc_function_template = {
 
 	/* Target dynamic attributes */
@@ -413,6 +559,61 @@ struct fc_function_template bfad_im_fc_function_template = {
 	.show_rport_dev_loss_tmo = 1,
 	.get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo,
 	.set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
+
+	.vport_create = bfad_im_vport_create,
+	.vport_delete = bfad_im_vport_delete,
+	.vport_disable = bfad_im_vport_disable,
+};
+
+struct fc_function_template bfad_im_vport_fc_function_template = {
+
+	/* Target dynamic attributes */
+	.get_starget_port_id = bfad_im_get_starget_port_id,
+	.show_starget_port_id = 1,
+	.get_starget_node_name = bfad_im_get_starget_node_name,
+	.show_starget_node_name = 1,
+	.get_starget_port_name = bfad_im_get_starget_port_name,
+	.show_starget_port_name = 1,
+
+	/* Host dynamic attribute */
+	.get_host_port_id = bfad_im_get_host_port_id,
+	.show_host_port_id = 1,
+
+	/* Host fixed attributes */
+	.show_host_node_name = 1,
+	.show_host_port_name = 1,
+	.show_host_supported_classes = 1,
+	.show_host_supported_fc4s = 1,
+	.show_host_supported_speeds = 1,
+	.show_host_maxframe_size = 1,
+
+	/* More host dynamic attributes */
+	.show_host_port_type = 1,
+	.get_host_port_type = bfad_im_get_host_port_type,
+	.show_host_port_state = 1,
+	.get_host_port_state = bfad_im_get_host_port_state,
+	.show_host_active_fc4s = 1,
+	.get_host_active_fc4s = bfad_im_get_host_active_fc4s,
+	.show_host_speed = 1,
+	.get_host_speed = bfad_im_get_host_speed,
+	.show_host_fabric_name = 1,
+	.get_host_fabric_name = bfad_im_get_host_fabric_name,
+
+	.show_host_symbolic_name = 1,
+
+	/* Statistics */
+	.get_fc_host_stats = bfad_im_get_stats,
+	.reset_fc_host_stats = bfad_im_reset_stats,
+
+	/* Allocation length for host specific data */
+	.dd_fcrport_size = sizeof(struct bfad_itnim_data_s *),
+
+	/* Remote port fixed attributes */
+	.show_rport_maxframe_size = 1,
+	.show_rport_supported_classes = 1,
+	.show_rport_dev_loss_tmo = 1,
+	.get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo,
+	.set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
 };
 
 /**

+ 2 - 2
drivers/scsi/bfa/bfad_drv.h

@@ -162,7 +162,6 @@ struct bfad_s {
 	const char *pci_name;
 	struct bfa_pcidev_s hal_pcidev;
 	struct bfa_ioc_pci_attr_s pci_attr;
-	unsigned long   pci_bar0_map;
 	void __iomem   *pci_bar0_kva;
 	struct completion comp;
 	struct completion suspend;
@@ -254,7 +253,7 @@ do {                                            	\
 
 
 bfa_status_t    bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
-				  struct bfa_port_cfg_s *port_cfg);
+			  struct bfa_port_cfg_s *port_cfg, struct device *dev);
 bfa_status_t    bfad_vf_create(struct bfad_s *bfad, u16 vf_id,
 			       struct bfa_port_cfg_s *port_cfg);
 bfa_status_t    bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role);
@@ -294,5 +293,6 @@ extern struct list_head bfad_list;
 extern int bfa_lun_queue_depth;
 extern int bfad_supported_fc4s;
 extern int bfa_linkup_delay;
+extern struct mutex bfad_mutex;
 
 #endif /* __BFAD_DRV_H__ */

+ 36 - 31
drivers/scsi/bfa/bfad_im.c

@@ -30,6 +30,7 @@ BFA_TRC_FILE(LDRV, IM);
 
 DEFINE_IDR(bfad_im_port_index);
 struct scsi_transport_template *bfad_im_scsi_transport_template;
+struct scsi_transport_template *bfad_im_scsi_vport_transport_template;
 static void bfad_im_itnim_work_handler(struct work_struct *work);
 static int bfad_im_queuecommand(struct scsi_cmnd *cmnd,
 		void (*done)(struct scsi_cmnd *));
@@ -252,7 +253,6 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
 	struct bfa_itnim_s *bfa_itnim;
 	bfa_status_t    rc = BFA_STATUS_OK;
 
-	bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
 	tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
 	if (!tskim) {
 		BFA_DEV_PRINTF(bfad, BFA_ERR,
@@ -513,11 +513,14 @@ void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim)
  * Allocate a Scsi_Host for a port.
  */
 int
-bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
+bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
+				struct device *dev)
 {
 	int error = 1;
 
+	mutex_lock(&bfad_mutex);
 	if (!idr_pre_get(&bfad_im_port_index, GFP_KERNEL)) {
+		mutex_unlock(&bfad_mutex);
 		printk(KERN_WARNING "idr_pre_get failure\n");
 		goto out;
 	}
@@ -525,10 +528,13 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
 	error = idr_get_new(&bfad_im_port_index, im_port,
 					 &im_port->idr_id);
 	if (error) {
+		mutex_unlock(&bfad_mutex);
 		printk(KERN_WARNING "idr_get_new failure\n");
 		goto out;
 	}
 
+	mutex_unlock(&bfad_mutex);
+
 	im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad);
 	if (!im_port->shost) {
 		error = 1;
@@ -542,12 +548,15 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
 	im_port->shost->max_lun = MAX_FCP_LUN;
 	im_port->shost->max_cmd_len = 16;
 	im_port->shost->can_queue = bfad->cfg_data.ioc_queue_depth;
-	im_port->shost->transportt = bfad_im_scsi_transport_template;
+	if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
+		im_port->shost->transportt = bfad_im_scsi_transport_template;
+	else
+		im_port->shost->transportt =
+				bfad_im_scsi_vport_transport_template;
 
-	error = bfad_os_scsi_add_host(im_port->shost, im_port, bfad);
+	error = scsi_add_host(im_port->shost, dev);
 	if (error) {
-		printk(KERN_WARNING "bfad_os_scsi_add_host failure %d\n",
-							error);
+		printk(KERN_WARNING "scsi_add_host failure %d\n", error);
 		goto out_fc_rel;
 	}
 
@@ -559,7 +568,9 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
 out_fc_rel:
 	scsi_host_put(im_port->shost);
 out_free_idr:
+	mutex_lock(&bfad_mutex);
 	idr_remove(&bfad_im_port_index, im_port->idr_id);
+	mutex_unlock(&bfad_mutex);
 out:
 	return error;
 }
@@ -567,8 +578,6 @@ out:
 void
 bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
 {
-	unsigned long flags;
-
 	bfa_trc(bfad, bfad->inst_no);
 	bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_HOST_FREE,
 			im_port->shost->host_no);
@@ -578,9 +587,9 @@ bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
 	scsi_remove_host(im_port->shost);
 	scsi_host_put(im_port->shost);
 
-	spin_lock_irqsave(&bfad->bfad_lock, flags);
+	mutex_lock(&bfad_mutex);
 	idr_remove(&bfad_im_port_index, im_port->idr_id);
-	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+	mutex_unlock(&bfad_mutex);
 }
 
 static void
@@ -589,9 +598,11 @@ bfad_im_port_delete_handler(struct work_struct *work)
 	struct bfad_im_port_s *im_port =
 		container_of(work, struct bfad_im_port_s, port_delete_work);
 
-	bfad_im_scsi_host_free(im_port->bfad, im_port);
-	bfad_im_port_clean(im_port);
-	kfree(im_port);
+	if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
+		im_port->flags |= BFAD_PORT_DELETE;
+		fc_vport_terminate(im_port->fc_vport);
+	}
+
 }
 
 bfa_status_t
@@ -690,23 +701,6 @@ bfad_im_probe_undo(struct bfad_s *bfad)
 	}
 }
 
-
-
-
-int
-bfad_os_scsi_add_host(struct Scsi_Host *shost, struct bfad_im_port_s *im_port,
-			struct bfad_s *bfad)
-{
-    struct device *dev;
-
-    if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
-		dev = &bfad->pcidev->dev;
-    else
-		dev = &bfad->pport.im_port->shost->shost_gendev;
-
-    return scsi_add_host(shost, dev);
-}
-
 struct Scsi_Host *
 bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
 {
@@ -725,7 +719,8 @@ bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
 void
 bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
 {
-	flush_workqueue(bfad->im->drv_workq);
+	if (!(im_port->flags & BFAD_PORT_DELETE))
+		flush_workqueue(bfad->im->drv_workq);
 	bfad_im_scsi_host_free(im_port->bfad, im_port);
 	bfad_im_port_clean(im_port);
 	kfree(im_port);
@@ -830,6 +825,13 @@ bfad_im_module_init(void)
 	if (!bfad_im_scsi_transport_template)
 		return BFA_STATUS_ENOMEM;
 
+	bfad_im_scsi_vport_transport_template =
+		fc_attach_transport(&bfad_im_vport_fc_function_template);
+	if (!bfad_im_scsi_vport_transport_template) {
+		fc_release_transport(bfad_im_scsi_transport_template);
+		return BFA_STATUS_ENOMEM;
+	}
+
 	return BFA_STATUS_OK;
 }
 
@@ -838,6 +840,8 @@ bfad_im_module_exit(void)
 {
 	if (bfad_im_scsi_transport_template)
 		fc_release_transport(bfad_im_scsi_transport_template);
+	if (bfad_im_scsi_vport_transport_template)
+		fc_release_transport(bfad_im_scsi_vport_transport_template);
 }
 
 void
@@ -938,6 +942,7 @@ bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
 		bfa_os_htonll((bfa_fcs_port_get_nwwn(port->fcs_port)));
 	fc_host_port_name(host) =
 		bfa_os_htonll((bfa_fcs_port_get_pwwn(port->fcs_port)));
+	fc_host_max_npiv_vports(host) = bfa_lps_get_max_vport(&bfad->bfa);
 
 	fc_host_supported_classes(host) = FC_COS_CLASS3;
 

+ 5 - 1
drivers/scsi/bfa/bfad_im.h

@@ -34,7 +34,7 @@ void bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port);
 void bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port);
 void bfad_im_port_clean(struct bfad_im_port_s *im_port);
 int  bfad_im_scsi_host_alloc(struct bfad_s *bfad,
-				struct bfad_im_port_s *im_port);
+		struct bfad_im_port_s *im_port, struct device *dev);
 void bfad_im_scsi_host_free(struct bfad_s *bfad,
 				struct bfad_im_port_s *im_port);
 
@@ -64,9 +64,11 @@ struct bfad_im_port_s {
 	struct work_struct port_delete_work;
 	int             idr_id;
 	u16        cur_scsi_id;
+	u16	   flags;
 	struct list_head binding_list;
 	struct Scsi_Host *shost;
 	struct list_head itnim_mapped_list;
+	struct fc_vport *fc_vport;
 };
 
 enum bfad_itnim_state {
@@ -140,6 +142,8 @@ void bfad_im_itnim_unmap(struct bfad_im_port_s  *im_port,
 extern struct scsi_host_template bfad_im_scsi_host_template;
 extern struct scsi_host_template bfad_im_vport_template;
 extern struct fc_function_template bfad_im_fc_function_template;
+extern struct fc_function_template bfad_im_vport_fc_function_template;
 extern struct scsi_transport_template *bfad_im_scsi_transport_template;
+extern struct scsi_transport_template *bfad_im_scsi_vport_transport_template;
 
 #endif

+ 1 - 1
drivers/scsi/bnx2i/bnx2i_hwi.c

@@ -347,6 +347,7 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
 
 	login_wqe->cmd_sn = be32_to_cpu(login_hdr->cmdsn);
 	login_wqe->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn);
+	login_wqe->flags = ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN;
 
 	login_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma;
 	login_wqe->resp_bd_list_addr_hi =
@@ -356,7 +357,6 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn,
 		 (bnx2i_conn->gen_pdu.resp_buf_size <<
 		  ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT));
 	login_wqe->resp_buffer = dword;
-	login_wqe->flags = 0;
 	login_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma;
 	login_wqe->bd_list_addr_hi =
 		(u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32);

+ 6 - 5
drivers/scsi/bnx2i/bnx2i_init.c

@@ -17,8 +17,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list);
 static u32 adapter_count;
 
 #define DRV_MODULE_NAME		"bnx2i"
-#define DRV_MODULE_VERSION	"2.1.0"
-#define DRV_MODULE_RELDATE	"Dec 06, 2009"
+#define DRV_MODULE_VERSION	"2.1.1"
+#define DRV_MODULE_RELDATE	"Mar 24, 2010"
 
 static char version[] __devinitdata =
 		"Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@@ -26,7 +26,8 @@ static char version[] __devinitdata =
 
 
 MODULE_AUTHOR("Anil Veerabhadrappa <anilgv@broadcom.com>");
-MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 iSCSI Driver");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711"
+		   " iSCSI Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
@@ -289,6 +290,7 @@ static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic)
 	int rc;
 
 	mutex_lock(&bnx2i_dev_lock);
+	hba->cnic = cnic;
 	rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
 	if (!rc) {
 		hba->age++;
@@ -335,8 +337,7 @@ void bnx2i_ulp_init(struct cnic_dev *dev)
 	if (bnx2i_init_one(hba, dev)) {
 		printk(KERN_ERR "bnx2i - hba %p init failed\n", hba);
 		bnx2i_free_hba(hba);
-	} else
-		hba->cnic = dev;
+	}
 }
 
 

+ 3 - 1
drivers/scsi/cxgb3i/cxgb3i_init.c

@@ -104,8 +104,10 @@ static int __init cxgb3i_init_module(void)
 		return err;
 
 	err = cxgb3i_pdu_init();
-	if (err < 0)
+	if (err < 0) {
+		cxgb3i_iscsi_cleanup();
 		return err;
+	}
 
 	cxgb3_register_client(&t3c_client);
 

+ 0 - 2
drivers/scsi/device_handler/scsi_dh_emc.c

@@ -285,13 +285,11 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
 	switch (cmd) {
 	case MODE_SELECT:
 		len = sizeof(short_trespass);
-		rq->cmd_flags |= REQ_RW;
 		rq->cmd[1] = 0x10;
 		rq->cmd[4] = len;
 		break;
 	case MODE_SELECT_10:
 		len = sizeof(long_trespass);
-		rq->cmd_flags |= REQ_RW;
 		rq->cmd[1] = 0x10;
 		rq->cmd[8] = len;
 		break;

+ 128 - 66
drivers/scsi/fcoe/fcoe.c

@@ -74,6 +74,7 @@ static int fcoe_rcv(struct sk_buff *, struct net_device *,
 static int fcoe_percpu_receive_thread(void *);
 static void fcoe_clean_pending_queue(struct fc_lport *);
 static void fcoe_percpu_clean(struct fc_lport *);
+static int fcoe_link_speed_update(struct fc_lport *);
 static int fcoe_link_ok(struct fc_lport *);
 
 static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *);
@@ -146,6 +147,7 @@ static int fcoe_vport_destroy(struct fc_vport *);
 static int fcoe_vport_create(struct fc_vport *, bool disabled);
 static int fcoe_vport_disable(struct fc_vport *, bool disable);
 static void fcoe_set_vport_symbolic_name(struct fc_vport *);
+static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *);
 
 static struct libfc_function_template fcoe_libfc_fcn_templ = {
 	.frame_send = fcoe_xmit,
@@ -153,6 +155,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {
 	.ddp_done = fcoe_ddp_done,
 	.elsct_send = fcoe_elsct_send,
 	.get_lesb = fcoe_get_lesb,
+	.lport_set_port_id = fcoe_set_port_id,
 };
 
 struct fc_function_template fcoe_transport_function = {
@@ -629,6 +632,8 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
 	port->fcoe_pending_queue_active = 0;
 	setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport);
 
+	fcoe_link_speed_update(lport);
+
 	if (!lport->vport) {
 		/*
 		 * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN:
@@ -653,15 +658,13 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
 /**
  * fcoe_shost_config() - Set up the SCSI host associated with a local port
  * @lport: The local port
- * @shost: The SCSI host to associate with the local port
  * @dev:   The device associated with the SCSI host
  *
  * Must be called after fcoe_lport_config() and fcoe_netdev_config()
  *
  * Returns: 0 for success
  */
-static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost,
-			     struct device *dev)
+static int fcoe_shost_config(struct fc_lport *lport, struct device *dev)
 {
 	int rc = 0;
 
@@ -669,6 +672,8 @@ static int fcoe_shost_config(struct fc_lport *lport, struct Scsi_Host *shost,
 	lport->host->max_lun = FCOE_MAX_LUN;
 	lport->host->max_id = FCOE_MAX_FCP_TARGET;
 	lport->host->max_channel = 0;
+	lport->host->max_cmd_len = FCOE_MAX_CMD_LEN;
+
 	if (lport->vport)
 		lport->host->transportt = fcoe_vport_transport_template;
 	else
@@ -796,6 +801,12 @@ skip_oem:
 /**
  * fcoe_if_destroy() - Tear down a SW FCoE instance
  * @lport: The local port to be destroyed
+ *
+ * Locking: must be called with the RTNL mutex held and RTNL mutex
+ * needed to be dropped by this function since not dropping RTNL
+ * would cause circular locking warning on synchronous fip worker
+ * cancelling thru fcoe_interface_put invoked by this function.
+ *
  */
 static void fcoe_if_destroy(struct fc_lport *lport)
 {
@@ -818,7 +829,6 @@ static void fcoe_if_destroy(struct fc_lport *lport)
 	/* Free existing transmit skbs */
 	fcoe_clean_pending_queue(lport);
 
-	rtnl_lock();
 	if (!is_zero_ether_addr(port->data_src_addr))
 		dev_uc_del(netdev, port->data_src_addr);
 	rtnl_unlock();
@@ -841,6 +851,7 @@ static void fcoe_if_destroy(struct fc_lport *lport)
 
 	/* Release the Scsi_Host */
 	scsi_host_put(lport->host);
+	module_put(THIS_MODULE);
 }
 
 /**
@@ -897,7 +908,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
 	struct net_device *netdev = fcoe->netdev;
 	struct fc_lport *lport = NULL;
 	struct fcoe_port *port;
-	struct Scsi_Host *shost;
 	int rc;
 	/*
 	 * parent is only a vport if npiv is 1,
@@ -919,7 +929,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
 		rc = -ENOMEM;
 		goto out;
 	}
-	shost = lport->host;
 	port = lport_priv(lport);
 	port->lport = lport;
 	port->fcoe = fcoe;
@@ -934,7 +943,8 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
 	}
 
 	if (npiv) {
-		FCOE_NETDEV_DBG(netdev, "Setting vport names, 0x%llX 0x%llX\n",
+		FCOE_NETDEV_DBG(netdev, "Setting vport names, "
+				"%16.16llx %16.16llx\n",
 				vport->node_name, vport->port_name);
 		fc_set_wwnn(lport, vport->node_name);
 		fc_set_wwpn(lport, vport->port_name);
@@ -949,7 +959,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
 	}
 
 	/* configure lport scsi host properties */
-	rc = fcoe_shost_config(lport, shost, parent);
+	rc = fcoe_shost_config(lport, parent);
 	if (rc) {
 		FCOE_NETDEV_DBG(netdev, "Could not configure shost for the "
 				"interface\n");
@@ -1073,7 +1083,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)
 	struct sk_buff *skb;
 #ifdef CONFIG_SMP
 	struct fcoe_percpu_s *p0;
-	unsigned targ_cpu = smp_processor_id();
+	unsigned targ_cpu = get_cpu();
 #endif /* CONFIG_SMP */
 
 	FCOE_DBG("Destroying receive thread for CPU %d\n", cpu);
@@ -1129,6 +1139,7 @@ static void fcoe_percpu_thread_destroy(unsigned int cpu)
 			kfree_skb(skb);
 		spin_unlock_bh(&p->fcoe_rx_list.lock);
 	}
+	put_cpu();
 #else
 	/*
 	 * This a non-SMP scenario where the singular Rx thread is
@@ -1297,8 +1308,8 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
 
 	return 0;
 err:
-	fc_lport_get_stats(lport)->ErrorFrames++;
-
+	per_cpu_ptr(lport->dev_stats, get_cpu())->ErrorFrames++;
+	put_cpu();
 err2:
 	kfree_skb(skb);
 	return -1;
@@ -1444,7 +1455,7 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
 		return 0;
 	}
 
-	if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) &&
+	if (unlikely(fh->fh_type == FC_TYPE_ELS) &&
 	    fcoe_ctlr_els_send(&fcoe->ctlr, lport, skb))
 		return 0;
 
@@ -1527,9 +1538,10 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
 		skb_shinfo(skb)->gso_size = 0;
 	}
 	/* update tx stats: regardless if LLD fails */
-	stats = fc_lport_get_stats(lport);
+	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
 	stats->TxFrames++;
 	stats->TxWords += wlen;
+	put_cpu();
 
 	/* send down to lld */
 	fr_dev(fp) = lport;
@@ -1563,7 +1575,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)
 	struct fc_frame_header *fh;
 	struct fcoe_crc_eof crc_eof;
 	struct fc_frame *fp;
-	u8 *mac = NULL;
 	struct fcoe_port *port;
 	struct fcoe_hdr *hp;
 
@@ -1583,13 +1594,9 @@ static void fcoe_recv_frame(struct sk_buff *skb)
 			skb_end_pointer(skb), skb->csum,
 			skb->dev ? skb->dev->name : "<NULL>");
 
-	/*
-	 * Save source MAC address before discarding header.
-	 */
 	port = lport_priv(lport);
 	if (skb_is_nonlinear(skb))
 		skb_linearize(skb);	/* not ideal */
-	mac = eth_hdr(skb)->h_source;
 
 	/*
 	 * Frame length checks and setting up the header pointers
@@ -1598,7 +1605,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)
 	hp = (struct fcoe_hdr *) skb_network_header(skb);
 	fh = (struct fc_frame_header *) skb_transport_header(skb);
 
-	stats = fc_lport_get_stats(lport);
+	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
 	if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
 		if (stats->ErrorFrames < 5)
 			printk(KERN_WARNING "fcoe: FCoE version "
@@ -1607,9 +1614,7 @@ static void fcoe_recv_frame(struct sk_buff *skb)
 			       "initiator supports version "
 			       "%x\n", FC_FCOE_DECAPS_VER(hp),
 			       FC_FCOE_VER);
-		stats->ErrorFrames++;
-		kfree_skb(skb);
-		return;
+		goto drop;
 	}
 
 	skb_pull(skb, sizeof(struct fcoe_hdr));
@@ -1624,16 +1629,12 @@ static void fcoe_recv_frame(struct sk_buff *skb)
 	fr_sof(fp) = hp->fcoe_sof;
 
 	/* Copy out the CRC and EOF trailer for access */
-	if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
-		kfree_skb(skb);
-		return;
-	}
+	if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof)))
+		goto drop;
 	fr_eof(fp) = crc_eof.fcoe_eof;
 	fr_crc(fp) = crc_eof.fcoe_crc32;
-	if (pskb_trim(skb, fr_len)) {
-		kfree_skb(skb);
-		return;
-	}
+	if (pskb_trim(skb, fr_len))
+		goto drop;
 
 	/*
 	 * We only check CRC if no offload is available and if it is
@@ -1647,25 +1648,27 @@ static void fcoe_recv_frame(struct sk_buff *skb)
 		fr_flags(fp) |= FCPHF_CRC_UNCHECKED;
 
 	fh = fc_frame_header_get(fp);
-	if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
-	    fh->fh_type == FC_TYPE_FCP) {
-		fc_exch_recv(lport, fp);
-		return;
-	}
-	if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
+	if ((fh->fh_r_ctl != FC_RCTL_DD_SOL_DATA ||
+	    fh->fh_type != FC_TYPE_FCP) &&
+	    (fr_flags(fp) & FCPHF_CRC_UNCHECKED)) {
 		if (le32_to_cpu(fr_crc(fp)) !=
 		    ~crc32(~0, skb->data, fr_len)) {
 			if (stats->InvalidCRCCount < 5)
 				printk(KERN_WARNING "fcoe: dropping "
 				       "frame with CRC error\n");
 			stats->InvalidCRCCount++;
-			stats->ErrorFrames++;
-			fc_frame_free(fp);
-			return;
+			goto drop;
 		}
 		fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED;
 	}
+	put_cpu();
 	fc_exch_recv(lport, fp);
+	return;
+
+drop:
+	stats->ErrorFrames++;
+	put_cpu();
+	kfree_skb(skb);
 }
 
 /**
@@ -1835,11 +1838,15 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 		FCOE_NETDEV_DBG(netdev, "Unknown event %ld "
 				"from netdev netlink\n", event);
 	}
+
+	fcoe_link_speed_update(lport);
+
 	if (link_possible && !fcoe_link_ok(lport))
 		fcoe_ctlr_link_up(&fcoe->ctlr);
 	else if (fcoe_ctlr_link_down(&fcoe->ctlr)) {
-		stats = fc_lport_get_stats(lport);
+		stats = per_cpu_ptr(lport->dev_stats, get_cpu());
 		stats->LinkFailureCount++;
+		put_cpu();
 		fcoe_clean_pending_queue(lport);
 	}
 out:
@@ -1901,13 +1908,19 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp)
 		goto out_nodev;
 	}
 
-	rtnl_lock();
+	if (!rtnl_trylock()) {
+		dev_put(netdev);
+		mutex_unlock(&fcoe_config_mutex);
+		return restart_syscall();
+	}
+
 	fcoe = fcoe_hostlist_lookup_port(netdev);
 	rtnl_unlock();
 
-	if (fcoe)
+	if (fcoe) {
 		fc_fabric_logoff(fcoe->ctlr.lp);
-	else
+		fcoe_ctlr_link_down(&fcoe->ctlr);
+	} else
 		rc = -ENODEV;
 
 	dev_put(netdev);
@@ -1950,13 +1963,20 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp)
 		goto out_nodev;
 	}
 
-	rtnl_lock();
+	if (!rtnl_trylock()) {
+		dev_put(netdev);
+		mutex_unlock(&fcoe_config_mutex);
+		return restart_syscall();
+	}
+
 	fcoe = fcoe_hostlist_lookup_port(netdev);
 	rtnl_unlock();
 
-	if (fcoe)
+	if (fcoe) {
+		if (!fcoe_link_ok(fcoe->ctlr.lp))
+			fcoe_ctlr_link_up(&fcoe->ctlr);
 		rc = fc_fabric_login(fcoe->ctlr.lp);
-	else
+	} else
 		rc = -ENODEV;
 
 	dev_put(netdev);
@@ -1999,7 +2019,12 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
 		goto out_nodev;
 	}
 
-	rtnl_lock();
+	if (!rtnl_trylock()) {
+		dev_put(netdev);
+		mutex_unlock(&fcoe_config_mutex);
+		return restart_syscall();
+	}
+
 	fcoe = fcoe_hostlist_lookup_port(netdev);
 	if (!fcoe) {
 		rtnl_unlock();
@@ -2008,9 +2033,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
 	}
 	list_del(&fcoe->list);
 	fcoe_interface_cleanup(fcoe);
-	rtnl_unlock();
+	/* RTNL mutex is dropped by fcoe_if_destroy */
 	fcoe_if_destroy(fcoe->ctlr.lp);
-	module_put(THIS_MODULE);
 
 out_putdev:
 	dev_put(netdev);
@@ -2029,6 +2053,8 @@ static void fcoe_destroy_work(struct work_struct *work)
 
 	port = container_of(work, struct fcoe_port, destroy_work);
 	mutex_lock(&fcoe_config_mutex);
+	rtnl_lock();
+	/* RTNL mutex is dropped by fcoe_if_destroy */
 	fcoe_if_destroy(port->lport);
 	mutex_unlock(&fcoe_config_mutex);
 }
@@ -2050,6 +2076,12 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
 	struct net_device *netdev;
 
 	mutex_lock(&fcoe_config_mutex);
+
+	if (!rtnl_trylock()) {
+		mutex_unlock(&fcoe_config_mutex);
+		return restart_syscall();
+	}
+
 #ifdef CONFIG_FCOE_MODULE
 	/*
 	 * Make sure the module has been initialized, and is not about to be
@@ -2058,7 +2090,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
 	 */
 	if (THIS_MODULE->state != MODULE_STATE_LIVE) {
 		rc = -ENODEV;
-		goto out_nodev;
+		goto out_nomod;
 	}
 #endif
 
@@ -2067,7 +2099,6 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
 		goto out_nomod;
 	}
 
-	rtnl_lock();
 	netdev = fcoe_if_to_netdev(buffer);
 	if (!netdev) {
 		rc = -ENODEV;
@@ -2122,35 +2153,27 @@ out_free:
 out_putdev:
 	dev_put(netdev);
 out_nodev:
-	rtnl_unlock();
 	module_put(THIS_MODULE);
 out_nomod:
+	rtnl_unlock();
 	mutex_unlock(&fcoe_config_mutex);
 	return rc;
 }
 
 /**
- * fcoe_link_ok() - Check if the link is OK for a local port
- * @lport: The local port to check link on
- *
- * Any permanently-disqualifying conditions have been previously checked.
- * This also updates the speed setting, which may change with link for 100/1000.
- *
- * This function should probably be checking for PAUSE support at some point
- * in the future. Currently Per-priority-pause is not determinable using
- * ethtool, so we shouldn't be restrictive until that problem is resolved.
- *
- * Returns: 0 if link is OK for use by FCoE.
+ * fcoe_link_speed_update() - Update the supported and actual link speeds
+ * @lport: The local port to update speeds for
  *
+ * Returns: 0 if the ethtool query was successful
+ *          -1 if the ethtool query failed
  */
-int fcoe_link_ok(struct fc_lport *lport)
+int fcoe_link_speed_update(struct fc_lport *lport)
 {
 	struct fcoe_port *port = lport_priv(lport);
 	struct net_device *netdev = port->fcoe->netdev;
 	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
 
-	if ((netdev->flags & IFF_UP) && netif_carrier_ok(netdev) &&
-	    (!dev_ethtool_get_settings(netdev, &ecmd))) {
+	if (!dev_ethtool_get_settings(netdev, &ecmd)) {
 		lport->link_supported_speeds &=
 			~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
 		if (ecmd.supported & (SUPPORTED_1000baseT_Half |
@@ -2169,6 +2192,23 @@ int fcoe_link_ok(struct fc_lport *lport)
 	return -1;
 }
 
+/**
+ * fcoe_link_ok() - Check if the link is OK for a local port
+ * @lport: The local port to check link on
+ *
+ * Returns: 0 if link is UP and OK, -1 if not
+ *
+ */
+int fcoe_link_ok(struct fc_lport *lport)
+{
+	struct fcoe_port *port = lport_priv(lport);
+	struct net_device *netdev = port->fcoe->netdev;
+
+	if (netif_oper_up(netdev))
+		return 0;
+	return -1;
+}
+
 /**
  * fcoe_percpu_clean() - Clear all pending skbs for an local port
  * @lport: The local port whose skbs are to be cleared
@@ -2631,3 +2671,25 @@ static void fcoe_get_lesb(struct fc_lport *lport,
 	lesb->lesb_miss_fka = htonl(mdac);
 	lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors);
 }
+
+/**
+ * fcoe_set_port_id() - Callback from libfc when Port_ID is set.
+ * @lport: the local port
+ * @port_id: the port ID
+ * @fp: the received frame, if any, that caused the port_id to be set.
+ *
+ * This routine handles the case where we received a FLOGI and are
+ * entering point-to-point mode.  We need to call fcoe_ctlr_recv_flogi()
+ * so it can set the non-mapped mode and gateway address.
+ *
+ * The FLOGI LS_ACC is handled by fcoe_flogi_resp().
+ */
+static void fcoe_set_port_id(struct fc_lport *lport,
+			     u32 port_id, struct fc_frame *fp)
+{
+	struct fcoe_port *port = lport_priv(lport);
+	struct fcoe_interface *fcoe = port->fcoe;
+
+	if (fp && fc_frame_payload_op(fp) == ELS_FLOGI)
+		fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp);
+}

+ 53 - 58
drivers/scsi/fcoe/libfcoe.c

@@ -51,7 +51,7 @@ MODULE_LICENSE("GPL v2");
 #define	FCOE_CTLR_DEF_FKA	FIP_DEF_FKA	/* default keep alive (mS) */
 
 static void fcoe_ctlr_timeout(unsigned long);
-static void fcoe_ctlr_link_work(struct work_struct *);
+static void fcoe_ctlr_timer_work(struct work_struct *);
 static void fcoe_ctlr_recv_work(struct work_struct *);
 
 static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS;
@@ -116,7 +116,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip)
 	spin_lock_init(&fip->lock);
 	fip->flogi_oxid = FC_XID_UNKNOWN;
 	setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
-	INIT_WORK(&fip->link_work, fcoe_ctlr_link_work);
+	INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
 	INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work);
 	skb_queue_head_init(&fip->fip_recv_list);
 }
@@ -164,7 +164,7 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
 	fcoe_ctlr_reset_fcfs(fip);
 	spin_unlock_bh(&fip->lock);
 	del_timer_sync(&fip->timer);
-	cancel_work_sync(&fip->link_work);
+	cancel_work_sync(&fip->timer_work);
 }
 EXPORT_SYMBOL(fcoe_ctlr_destroy);
 
@@ -257,14 +257,10 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
 {
 	spin_lock_bh(&fip->lock);
 	if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) {
-		fip->last_link = 1;
-		fip->link = 1;
 		spin_unlock_bh(&fip->lock);
 		fc_linkup(fip->lp);
 	} else if (fip->state == FIP_ST_LINK_WAIT) {
 		fip->state = fip->mode;
-		fip->last_link = 1;
-		fip->link = 1;
 		spin_unlock_bh(&fip->lock);
 		if (fip->state == FIP_ST_AUTO)
 			LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
@@ -306,9 +302,7 @@ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip)
 	LIBFCOE_FIP_DBG(fip, "link down.\n");
 	spin_lock_bh(&fip->lock);
 	fcoe_ctlr_reset(fip);
-	link_dropped = fip->link;
-	fip->link = 0;
-	fip->last_link = 0;
+	link_dropped = fip->state != FIP_ST_LINK_WAIT;
 	fip->state = FIP_ST_LINK_WAIT;
 	spin_unlock_bh(&fip->lock);
 
@@ -349,7 +343,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
 
 	fcf = fip->sel_fcf;
 	lp = fip->lp;
-	if (!fcf || !fc_host_port_id(lp->host))
+	if (!fcf || !lp->port_id)
 		return;
 
 	len = sizeof(*kal) + ports * sizeof(*vn);
@@ -380,8 +374,8 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
 		vn->fd_desc.fip_dtype = FIP_DT_VN_ID;
 		vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW;
 		memcpy(vn->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
-		hton24(vn->fd_fc_id, fc_host_port_id(lp->host));
-		put_unaligned_be64(lp->wwpn, &vn->fd_wwpn);
+		hton24(vn->fd_fc_id, lport->port_id);
+		put_unaligned_be64(lport->wwpn, &vn->fd_wwpn);
 	}
 	skb_put(skb, len);
 	skb->protocol = htons(ETH_P_FIP);
@@ -445,13 +439,18 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
 	cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
 
 	mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
-	memset(mac, 0, sizeof(mac));
+	memset(mac, 0, sizeof(*mac));
 	mac->fd_desc.fip_dtype = FIP_DT_MAC;
 	mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
-	if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC)
+	if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
 		memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
-	else if (fip->spma)
+	} else if (fip_flags & FIP_FL_SPMA) {
+		LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
 		memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
+	} else {
+		LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
+		/* FPMA only FLOGI must leave the MAC desc set to all 0s */
+	}
 
 	skb->protocol = htons(ETH_P_FIP);
 	skb_reset_mac_header(skb);
@@ -556,7 +555,7 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send);
  * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller
  * @fip: The FCoE controller to free FCFs on
  *
- * Called with lock held.
+ * Called with lock held and preemption disabled.
  *
  * An FCF is considered old if we have missed three advertisements.
  * That is, there have been no valid advertisement from it for three
@@ -573,17 +572,20 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
 	struct fcoe_fcf *next;
 	unsigned long sel_time = 0;
 	unsigned long mda_time = 0;
+	struct fcoe_dev_stats *stats;
 
 	list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
 		mda_time = fcf->fka_period + (fcf->fka_period >> 1);
 		if ((fip->sel_fcf == fcf) &&
 		    (time_after(jiffies, fcf->time + mda_time))) {
 			mod_timer(&fip->timer, jiffies + mda_time);
-			fc_lport_get_stats(fip->lp)->MissDiscAdvCount++;
+			stats = per_cpu_ptr(fip->lp->dev_stats,
+					    smp_processor_id());
+			stats->MissDiscAdvCount++;
 			printk(KERN_INFO "libfcoe: host%d: Missing Discovery "
-			       "Advertisement for fab %llx count %lld\n",
+			       "Advertisement for fab %16.16llx count %lld\n",
 			       fip->lp->host->host_no, fcf->fabric_name,
-			       fc_lport_get_stats(fip->lp)->MissDiscAdvCount);
+			       stats->MissDiscAdvCount);
 		}
 		if (time_after(jiffies, fcf->time + fcf->fka_period * 3 +
 			       msecs_to_jiffies(FIP_FCF_FUZZ * 3))) {
@@ -593,7 +595,9 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
 			WARN_ON(!fip->fcf_count);
 			fip->fcf_count--;
 			kfree(fcf);
-			fc_lport_get_stats(fip->lp)->VLinkFailureCount++;
+			stats = per_cpu_ptr(fip->lp->dev_stats,
+					    smp_processor_id());
+			stats->VLinkFailureCount++;
 		} else if (fcoe_ctlr_mtu_valid(fcf) &&
 			   (!sel_time || time_before(sel_time, fcf->time))) {
 			sel_time = fcf->time;
@@ -776,7 +780,8 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
 	mtu_valid = fcoe_ctlr_mtu_valid(fcf);
 	fcf->time = jiffies;
 	if (!found) {
-		LIBFCOE_FIP_DBG(fip, "New FCF for fab %llx map %x val %d\n",
+		LIBFCOE_FIP_DBG(fip, "New FCF for fab %16.16llx "
+				"map %x val %d\n",
 				fcf->fabric_name, fcf->fc_map, mtu_valid);
 	}
 
@@ -906,9 +911,10 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
 	fr_eof(fp) = FC_EOF_T;
 	fr_dev(fp) = lport;
 
-	stats = fc_lport_get_stats(lport);
+	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
 	stats->RxFrames++;
 	stats->RxWords += skb->len / FIP_BPW;
+	put_cpu();
 
 	fc_exch_recv(lport, fp);
 	return;
@@ -942,9 +948,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
 	u32	desc_mask;
 
 	LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
-	if (!fcf)
-		return;
-	if (!fcf || !fc_host_port_id(lport->host))
+
+	if (!fcf || !lport->port_id)
 		return;
 
 	/*
@@ -982,8 +987,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
 			if (compare_ether_addr(vp->fd_mac,
 					       fip->get_src_addr(lport)) == 0 &&
 			    get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn &&
-			    ntoh24(vp->fd_fc_id) ==
-			    fc_host_port_id(lport->host))
+			    ntoh24(vp->fd_fc_id) == lport->port_id)
 				desc_mask &= ~BIT(FIP_DT_VN_ID);
 			break;
 		default:
@@ -1006,7 +1010,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
 		LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
 
 		spin_lock_bh(&fip->lock);
-		fc_lport_get_stats(lport)->VLinkFailureCount++;
+		per_cpu_ptr(lport->dev_stats,
+			    smp_processor_id())->VLinkFailureCount++;
 		fcoe_ctlr_reset(fip);
 		spin_unlock_bh(&fip->lock);
 
@@ -1102,15 +1107,17 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
 	struct fcoe_fcf *best = NULL;
 
 	list_for_each_entry(fcf, &fip->fcfs, list) {
-		LIBFCOE_FIP_DBG(fip, "consider FCF for fab %llx VFID %d map %x "
-				"val %d\n", fcf->fabric_name, fcf->vfid,
+		LIBFCOE_FIP_DBG(fip, "consider FCF for fab %16.16llx "
+				"VFID %d map %x val %d\n",
+				fcf->fabric_name, fcf->vfid,
 				fcf->fc_map, fcoe_ctlr_mtu_valid(fcf));
 		if (!fcoe_ctlr_fcf_usable(fcf)) {
-			LIBFCOE_FIP_DBG(fip, "FCF for fab %llx map %x %svalid "
-					"%savailable\n", fcf->fabric_name,
-					fcf->fc_map, (fcf->flags & FIP_FL_SOL)
-					? "" : "in", (fcf->flags & FIP_FL_AVAIL)
-					? "" : "un");
+			LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx "
+					"map %x %svalid %savailable\n",
+					fcf->fabric_name, fcf->fc_map,
+					(fcf->flags & FIP_FL_SOL) ? "" : "in",
+					(fcf->flags & FIP_FL_AVAIL) ?
+					"" : "un");
 			continue;
 		}
 		if (!best) {
@@ -1175,7 +1182,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
 			       "Starting FCF discovery.\n",
 			       fip->lp->host->host_no);
 			fip->reset_req = 1;
-			schedule_work(&fip->link_work);
+			schedule_work(&fip->timer_work);
 		}
 	}
 
@@ -1201,43 +1208,31 @@ static void fcoe_ctlr_timeout(unsigned long arg)
 		mod_timer(&fip->timer, next_timer);
 	}
 	if (fip->send_ctlr_ka || fip->send_port_ka)
-		schedule_work(&fip->link_work);
+		schedule_work(&fip->timer_work);
 	spin_unlock_bh(&fip->lock);
 }
 
 /**
- * fcoe_ctlr_link_work() - Worker thread function for link changes
+ * fcoe_ctlr_timer_work() - Worker thread function for timer work
  * @work: Handle to a FCoE controller
  *
- * See if the link status has changed and if so, report it.
- *
- * This is here because fc_linkup() and fc_linkdown() must not
+ * Sends keep-alives and resets which must not
  * be called from the timer directly, since they use a mutex.
  */
-static void fcoe_ctlr_link_work(struct work_struct *work)
+static void fcoe_ctlr_timer_work(struct work_struct *work)
 {
 	struct fcoe_ctlr *fip;
 	struct fc_lport *vport;
 	u8 *mac;
-	int link;
-	int last_link;
 	int reset;
 
-	fip = container_of(work, struct fcoe_ctlr, link_work);
+	fip = container_of(work, struct fcoe_ctlr, timer_work);
 	spin_lock_bh(&fip->lock);
-	last_link = fip->last_link;
-	link = fip->link;
-	fip->last_link = link;
 	reset = fip->reset_req;
 	fip->reset_req = 0;
 	spin_unlock_bh(&fip->lock);
 
-	if (last_link != link) {
-		if (link)
-			fc_linkup(fip->lp);
-		else
-			fc_linkdown(fip->lp);
-	} else if (reset && link)
+	if (reset)
 		fc_lport_reset(fip->lp);
 
 	if (fip->send_ctlr_ka) {
@@ -1334,9 +1329,9 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
 		if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) {
 			memcpy(fip->dest_addr, sa, ETH_ALEN);
 			fip->map_dest = 0;
-			if (fip->state == FIP_ST_NON_FIP)
-				LIBFCOE_FIP_DBG(fip, "received FLOGI REQ, "
-						"using non-FIP mode\n");
+			if (fip->state == FIP_ST_AUTO)
+				LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. "
+						"Setting non-FIP mode\n");
 			fip->state = FIP_ST_NON_FIP;
 		}
 		spin_unlock_bh(&fip->lock);

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

@@ -36,7 +36,7 @@
 
 #define DRV_NAME		"fnic"
 #define DRV_DESCRIPTION		"Cisco FCoE HBA Driver"
-#define DRV_VERSION		"1.4.0.98"
+#define DRV_VERSION		"1.4.0.145"
 #define PFX			DRV_NAME ": "
 #define DFX                     DRV_NAME "%d: "
 
@@ -45,7 +45,7 @@
 #define	FNIC_IO_LOCKS		64 /* IO locks: power of 2 */
 #define FNIC_DFLT_QUEUE_DEPTH	32
 #define	FNIC_STATS_RATE_LIMIT	4 /* limit rate at which stats are pulled up */
-#define FNIC_MAX_CMD_LEN        16 /* Supported CDB length */
+
 /*
  * Tag bits used for special requests.
  */

+ 1 - 1
drivers/scsi/fnic/fnic_fcs.c

@@ -617,7 +617,7 @@ void fnic_flush_tx(struct fnic *fnic)
 	struct sk_buff *skb;
 	struct fc_frame *fp;
 
-	while ((skb = skb_dequeue(&fnic->frame_queue))) {
+	while ((skb = skb_dequeue(&fnic->tx_queue))) {
 		fp = (struct fc_frame *)skb;
 		fnic_send_frame(fnic, fp);
 	}

+ 1 - 1
drivers/scsi/fnic/fnic_main.c

@@ -556,7 +556,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
 	}
 	host->max_lun = fnic->config.luns_per_tgt;
 	host->max_id = FNIC_MAX_FCP_TARGET;
-	host->max_cmd_len = FNIC_MAX_CMD_LEN;
+	host->max_cmd_len = FCOE_MAX_CMD_LEN;
 
 	fnic_get_res_counts(fnic);
 

+ 1 - 1
drivers/scsi/gdth.c

@@ -3842,7 +3842,7 @@ int __init option_setup(char *str)
 
     TRACE2(("option_setup() str %s\n", str ? str:"NULL")); 
 
-    while (cur && isdigit(*cur) && i <= MAXHA) {
+    while (cur && isdigit(*cur) && i < MAXHA) {
         ints[i++] = simple_strtoul(cur, NULL, 0);
         if ((cur = strchr(cur, ',')) != NULL) cur++;
     }

+ 283 - 282
drivers/scsi/gvp11.c

@@ -19,332 +19,334 @@
 #include "wd33c93.h"
 #include "gvp11.h"
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
-#define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base))
-#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
 
-static irqreturn_t gvp11_intr (int irq, void *_instance)
+#define DMA(ptr)	((gvp11_scsiregs *)((ptr)->base))
+
+static irqreturn_t gvp11_intr(int irq, void *_instance)
 {
-    unsigned long flags;
-    unsigned int status;
-    struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
-
-    status = DMA(instance)->CNTR;
-    if (!(status & GVP11_DMAC_INT_PENDING))
-	return IRQ_NONE;
-
-    spin_lock_irqsave(instance->host_lock, flags);
-    wd33c93_intr(instance);
-    spin_unlock_irqrestore(instance->host_lock, flags);
-    return IRQ_HANDLED;
+	unsigned long flags;
+	unsigned int status;
+	struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
+
+	status = DMA(instance)->CNTR;
+	if (!(status & GVP11_DMAC_INT_PENDING))
+		return IRQ_NONE;
+
+	spin_lock_irqsave(instance->host_lock, flags);
+	wd33c93_intr(instance);
+	spin_unlock_irqrestore(instance->host_lock, flags);
+	return IRQ_HANDLED;
 }
 
 static int gvp11_xfer_mask = 0;
 
-void gvp11_setup (char *str, int *ints)
+void gvp11_setup(char *str, int *ints)
 {
-    gvp11_xfer_mask = ints[1];
+	gvp11_xfer_mask = ints[1];
 }
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-    unsigned short cntr = GVP11_DMAC_INT_ENABLE;
-    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
-    int bank_mask;
-    static int scsi_alloc_out_of_range = 0;
-
-    /* use bounce buffer if the physical address is bad */
-    if (addr & HDATA(cmd->device->host)->dma_xfer_mask)
-    {
-	HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
-	    & ~0x1ff;
-
- 	if( !scsi_alloc_out_of_range ) {
-	    HDATA(cmd->device->host)->dma_bounce_buffer =
-		kmalloc (HDATA(cmd->device->host)->dma_bounce_len, GFP_KERNEL);
-	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_SCSI_ALLOCED;
-	}
+	struct Scsi_Host *instance = cmd->device->host;
+	struct WD33C93_hostdata *hdata = shost_priv(instance);
+	unsigned short cntr = GVP11_DMAC_INT_ENABLE;
+	unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+	int bank_mask;
+	static int scsi_alloc_out_of_range = 0;
+
+	/* use bounce buffer if the physical address is bad */
+	if (addr & hdata->dma_xfer_mask) {
+		hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+
+		if (!scsi_alloc_out_of_range) {
+			hdata->dma_bounce_buffer =
+				kmalloc(hdata->dma_bounce_len, GFP_KERNEL);
+			hdata->dma_buffer_pool = BUF_SCSI_ALLOCED;
+		}
 
-	if (scsi_alloc_out_of_range ||
-	    !HDATA(cmd->device->host)->dma_bounce_buffer) {
-	    HDATA(cmd->device->host)->dma_bounce_buffer =
-		amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
-				       "GVP II SCSI Bounce Buffer");
+		if (scsi_alloc_out_of_range ||
+		    !hdata->dma_bounce_buffer) {
+			hdata->dma_bounce_buffer =
+				amiga_chip_alloc(hdata->dma_bounce_len,
+						 "GVP II SCSI Bounce Buffer");
 
-	    if(!HDATA(cmd->device->host)->dma_bounce_buffer)
-	    {
-		HDATA(cmd->device->host)->dma_bounce_len = 0;
-		return 1;
-	    }
+			if (!hdata->dma_bounce_buffer) {
+				hdata->dma_bounce_len = 0;
+				return 1;
+			}
 
-	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
-	}
+			hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
+		}
 
-	/* check if the address of the bounce buffer is OK */
-	addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
-
-	if (addr & HDATA(cmd->device->host)->dma_xfer_mask) {
-	    /* fall back to Chip RAM if address out of range */
-	    if( HDATA(cmd->device->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) {
-		kfree (HDATA(cmd->device->host)->dma_bounce_buffer);
-		scsi_alloc_out_of_range = 1;
-	    } else {
-		amiga_chip_free (HDATA(cmd->device->host)->dma_bounce_buffer);
-            }
-		
-	    HDATA(cmd->device->host)->dma_bounce_buffer =
-		amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
-				       "GVP II SCSI Bounce Buffer");
-
-	    if(!HDATA(cmd->device->host)->dma_bounce_buffer)
-	    {
-		HDATA(cmd->device->host)->dma_bounce_len = 0;
-		return 1;
-	    }
-
-	    addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
-	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
-	}
-	    
-	if (!dir_in) {
-	    /* copy to bounce buffer for a write */
-	    memcpy (HDATA(cmd->device->host)->dma_bounce_buffer,
-		    cmd->SCp.ptr, cmd->SCp.this_residual);
+		/* check if the address of the bounce buffer is OK */
+		addr = virt_to_bus(hdata->dma_bounce_buffer);
+
+		if (addr & hdata->dma_xfer_mask) {
+			/* fall back to Chip RAM if address out of range */
+			if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED) {
+				kfree(hdata->dma_bounce_buffer);
+				scsi_alloc_out_of_range = 1;
+			} else {
+				amiga_chip_free(hdata->dma_bounce_buffer);
+			}
+
+			hdata->dma_bounce_buffer =
+				amiga_chip_alloc(hdata->dma_bounce_len,
+						 "GVP II SCSI Bounce Buffer");
+
+			if (!hdata->dma_bounce_buffer) {
+				hdata->dma_bounce_len = 0;
+				return 1;
+			}
+
+			addr = virt_to_bus(hdata->dma_bounce_buffer);
+			hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
+		}
+
+		if (!dir_in) {
+			/* copy to bounce buffer for a write */
+			memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+			       cmd->SCp.this_residual);
+		}
 	}
-    }
 
-    /* setup dma direction */
-    if (!dir_in)
-	cntr |= GVP11_DMAC_DIR_WRITE;
+	/* setup dma direction */
+	if (!dir_in)
+		cntr |= GVP11_DMAC_DIR_WRITE;
 
-    HDATA(cmd->device->host)->dma_dir = dir_in;
-    DMA(cmd->device->host)->CNTR = cntr;
+	hdata->dma_dir = dir_in;
+	DMA(cmd->device->host)->CNTR = cntr;
 
-    /* setup DMA *physical* address */
-    DMA(cmd->device->host)->ACR = addr;
+	/* setup DMA *physical* address */
+	DMA(cmd->device->host)->ACR = addr;
 
-    if (dir_in)
-	/* invalidate any cache */
-	cache_clear (addr, cmd->SCp.this_residual);
-    else
-	/* push any dirty cache */
-	cache_push (addr, cmd->SCp.this_residual);
+	if (dir_in) {
+		/* invalidate any cache */
+		cache_clear(addr, cmd->SCp.this_residual);
+	} else {
+		/* push any dirty cache */
+		cache_push(addr, cmd->SCp.this_residual);
+	}
 
-    if ((bank_mask = (~HDATA(cmd->device->host)->dma_xfer_mask >> 18) & 0x01c0))
-	    DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
+	bank_mask = (~hdata->dma_xfer_mask >> 18) & 0x01c0;
+	if (bank_mask)
+		DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
 
-    /* start DMA */
-    DMA(cmd->device->host)->ST_DMA = 1;
+	/* start DMA */
+	DMA(cmd->device->host)->ST_DMA = 1;
 
-    /* return success */
-    return 0;
+	/* return success */
+	return 0;
 }
 
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 		     int status)
 {
-    /* stop DMA */
-    DMA(instance)->SP_DMA = 1;
-    /* remove write bit from CONTROL bits */
-    DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
-
-    /* copy from a bounce buffer, if necessary */
-    if (status && HDATA(instance)->dma_bounce_buffer) {
-	if (HDATA(instance)->dma_dir && SCpnt)
-	    memcpy (SCpnt->SCp.ptr, 
-		    HDATA(instance)->dma_bounce_buffer,
-		    SCpnt->SCp.this_residual);
-	
-	if (HDATA(instance)->dma_buffer_pool == BUF_SCSI_ALLOCED)
-	    kfree (HDATA(instance)->dma_bounce_buffer);
-	else
-	    amiga_chip_free(HDATA(instance)->dma_bounce_buffer);
-	
-	HDATA(instance)->dma_bounce_buffer = NULL;
-	HDATA(instance)->dma_bounce_len = 0;
-    }
+	struct WD33C93_hostdata *hdata = shost_priv(instance);
+
+	/* stop DMA */
+	DMA(instance)->SP_DMA = 1;
+	/* remove write bit from CONTROL bits */
+	DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+
+	/* copy from a bounce buffer, if necessary */
+	if (status && hdata->dma_bounce_buffer) {
+		if (hdata->dma_dir && SCpnt)
+			memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
+			       SCpnt->SCp.this_residual);
+
+		if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED)
+			kfree(hdata->dma_bounce_buffer);
+		else
+			amiga_chip_free(hdata->dma_bounce_buffer);
+
+		hdata->dma_bounce_buffer = NULL;
+		hdata->dma_bounce_len = 0;
+	}
 }
 
 #define CHECK_WD33C93
 
 int __init gvp11_detect(struct scsi_host_template *tpnt)
 {
-    static unsigned char called = 0;
-    struct Scsi_Host *instance;
-    unsigned long address;
-    unsigned int epc;
-    struct zorro_dev *z = NULL;
-    unsigned int default_dma_xfer_mask;
-    wd33c93_regs regs;
-    int num_gvp11 = 0;
+	static unsigned char called = 0;
+	struct Scsi_Host *instance;
+	unsigned long address;
+	unsigned int epc;
+	struct zorro_dev *z = NULL;
+	unsigned int default_dma_xfer_mask;
+	struct WD33C93_hostdata *hdata;
+	wd33c93_regs regs;
+	int num_gvp11 = 0;
 #ifdef CHECK_WD33C93
-    volatile unsigned char *sasr_3393, *scmd_3393;
-    unsigned char save_sasr;
-    unsigned char q, qq;
+	volatile unsigned char *sasr_3393, *scmd_3393;
+	unsigned char save_sasr;
+	unsigned char q, qq;
 #endif
 
-    if (!MACH_IS_AMIGA || called)
-	return 0;
-    called = 1;
-
-    tpnt->proc_name = "GVP11";
-    tpnt->proc_info = &wd33c93_proc_info;
-
-    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-	/* 
-	 * This should (hopefully) be the correct way to identify
-	 * all the different GVP SCSI controllers (except for the
-	 * SERIES I though).
-	 */
-
-	if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI ||
-	    z->id == ZORRO_PROD_GVP_SERIES_II)
-	    default_dma_xfer_mask = ~0x00ffffff;
-	else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI ||
-		 z->id == ZORRO_PROD_GVP_A530_SCSI ||
-		 z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI)
-	    default_dma_xfer_mask = ~0x01ffffff;
-	else if (z->id == ZORRO_PROD_GVP_A1291 ||
-		 z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1)
-	    default_dma_xfer_mask = ~0x07ffffff;
-	else
-	    continue;
-
-	/*
-	 * Rumors state that some GVP ram boards use the same product
-	 * code as the SCSI controllers. Therefore if the board-size
-	 * is not 64KB we asume it is a ram board and bail out.
-	 */
-	if (z->resource.end-z->resource.start != 0xffff)
-		continue;
-
-	address = z->resource.start;
-	if (!request_mem_region(address, 256, "wd33c93"))
-	    continue;
+	if (!MACH_IS_AMIGA || called)
+		return 0;
+	called = 1;
+
+	tpnt->proc_name = "GVP11";
+	tpnt->proc_info = &wd33c93_proc_info;
+
+	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+		/*
+		 * This should (hopefully) be the correct way to identify
+		 * all the different GVP SCSI controllers (except for the
+		 * SERIES I though).
+		 */
+
+		if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI ||
+		    z->id == ZORRO_PROD_GVP_SERIES_II)
+			default_dma_xfer_mask = ~0x00ffffff;
+		else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI ||
+			 z->id == ZORRO_PROD_GVP_A530_SCSI ||
+			 z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI)
+			default_dma_xfer_mask = ~0x01ffffff;
+		else if (z->id == ZORRO_PROD_GVP_A1291 ||
+			 z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1)
+			default_dma_xfer_mask = ~0x07ffffff;
+		else
+			continue;
+
+		/*
+		 * Rumors state that some GVP ram boards use the same product
+		 * code as the SCSI controllers. Therefore if the board-size
+		 * is not 64KB we asume it is a ram board and bail out.
+		 */
+		if (z->resource.end - z->resource.start != 0xffff)
+			continue;
+
+		address = z->resource.start;
+		if (!request_mem_region(address, 256, "wd33c93"))
+			continue;
 
 #ifdef CHECK_WD33C93
 
-	/*
-	 * These darn GVP boards are a problem - it can be tough to tell
-	 * whether or not they include a SCSI controller. This is the
-	 * ultimate Yet-Another-GVP-Detection-Hack in that it actually
-	 * probes for a WD33c93 chip: If we find one, it's extremely
-	 * likely that this card supports SCSI, regardless of Product_
-	 * Code, Board_Size, etc. 
-	 */
-
-    /* Get pointers to the presumed register locations and save contents */
-
-	sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
-	scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
-	save_sasr = *sasr_3393;
-
-    /* First test the AuxStatus Reg */
-
-	q = *sasr_3393;		/* read it */
-	if (q & 0x08)		/* bit 3 should always be clear */
-		goto release;
-	*sasr_3393 = WD_AUXILIARY_STATUS;	 /* setup indirect address */
-	if (*sasr_3393 == WD_AUXILIARY_STATUS) { /* shouldn't retain the write */
-		*sasr_3393 = save_sasr;	/* Oops - restore this byte */
-		goto release;
+		/*
+		 * These darn GVP boards are a problem - it can be tough to tell
+		 * whether or not they include a SCSI controller. This is the
+		 * ultimate Yet-Another-GVP-Detection-Hack in that it actually
+		 * probes for a WD33c93 chip: If we find one, it's extremely
+		 * likely that this card supports SCSI, regardless of Product_
+		 * Code, Board_Size, etc.
+		 */
+
+		/* Get pointers to the presumed register locations and save contents */
+
+		sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
+		scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
+		save_sasr = *sasr_3393;
+
+		/* First test the AuxStatus Reg */
+
+		q = *sasr_3393;	/* read it */
+		if (q & 0x08)	/* bit 3 should always be clear */
+			goto release;
+		*sasr_3393 = WD_AUXILIARY_STATUS;	/* setup indirect address */
+		if (*sasr_3393 == WD_AUXILIARY_STATUS) {	/* shouldn't retain the write */
+			*sasr_3393 = save_sasr;	/* Oops - restore this byte */
+			goto release;
 		}
-	if (*sasr_3393 != q) {	/* should still read the same */
-		*sasr_3393 = save_sasr;	/* Oops - restore this byte */
-		goto release;
+		if (*sasr_3393 != q) {	/* should still read the same */
+			*sasr_3393 = save_sasr;	/* Oops - restore this byte */
+			goto release;
 		}
-	if (*scmd_3393 != q)	/* and so should the image at 0x1f */
-		goto release;
-
-
-    /* Ok, we probably have a wd33c93, but let's check a few other places
-     * for good measure. Make sure that this works for both 'A and 'B    
-     * chip versions.
-     */
-
-	*sasr_3393 = WD_SCSI_STATUS;
-	q = *scmd_3393;
-	*sasr_3393 = WD_SCSI_STATUS;
-	*scmd_3393 = ~q;
-	*sasr_3393 = WD_SCSI_STATUS;
-	qq = *scmd_3393;
-	*sasr_3393 = WD_SCSI_STATUS;
-	*scmd_3393 = q;
-	if (qq != q)			/* should be read only */
-		goto release;
-	*sasr_3393 = 0x1e;	/* this register is unimplemented */
-	q = *scmd_3393;
-	*sasr_3393 = 0x1e;
-	*scmd_3393 = ~q;
-	*sasr_3393 = 0x1e;
-	qq = *scmd_3393;
-	*sasr_3393 = 0x1e;
-	*scmd_3393 = q;
-	if (qq != q || qq != 0xff)	/* should be read only, all 1's */
-		goto release;
-	*sasr_3393 = WD_TIMEOUT_PERIOD;
-	q = *scmd_3393;
-	*sasr_3393 = WD_TIMEOUT_PERIOD;
-	*scmd_3393 = ~q;
-	*sasr_3393 = WD_TIMEOUT_PERIOD;
-	qq = *scmd_3393;
-	*sasr_3393 = WD_TIMEOUT_PERIOD;
-	*scmd_3393 = q;
-	if (qq != (~q & 0xff))		/* should be read/write */
-		goto release;
+		if (*scmd_3393 != q)	/* and so should the image at 0x1f */
+			goto release;
+
+		/*
+		 * Ok, we probably have a wd33c93, but let's check a few other places
+		 * for good measure. Make sure that this works for both 'A and 'B
+		 * chip versions.
+		 */
+
+		*sasr_3393 = WD_SCSI_STATUS;
+		q = *scmd_3393;
+		*sasr_3393 = WD_SCSI_STATUS;
+		*scmd_3393 = ~q;
+		*sasr_3393 = WD_SCSI_STATUS;
+		qq = *scmd_3393;
+		*sasr_3393 = WD_SCSI_STATUS;
+		*scmd_3393 = q;
+		if (qq != q)	/* should be read only */
+			goto release;
+		*sasr_3393 = 0x1e;	/* this register is unimplemented */
+		q = *scmd_3393;
+		*sasr_3393 = 0x1e;
+		*scmd_3393 = ~q;
+		*sasr_3393 = 0x1e;
+		qq = *scmd_3393;
+		*sasr_3393 = 0x1e;
+		*scmd_3393 = q;
+		if (qq != q || qq != 0xff)	/* should be read only, all 1's */
+			goto release;
+		*sasr_3393 = WD_TIMEOUT_PERIOD;
+		q = *scmd_3393;
+		*sasr_3393 = WD_TIMEOUT_PERIOD;
+		*scmd_3393 = ~q;
+		*sasr_3393 = WD_TIMEOUT_PERIOD;
+		qq = *scmd_3393;
+		*sasr_3393 = WD_TIMEOUT_PERIOD;
+		*scmd_3393 = q;
+		if (qq != (~q & 0xff))	/* should be read/write */
+			goto release;
 #endif
 
-	instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
-	if(instance == NULL)
-		goto release;
-	instance->base = ZTWO_VADDR(address);
-	instance->irq = IRQ_AMIGA_PORTS;
-	instance->unique_id = z->slotaddr;
-
-	if (gvp11_xfer_mask)
-		HDATA(instance)->dma_xfer_mask = gvp11_xfer_mask;
-	else
-		HDATA(instance)->dma_xfer_mask = default_dma_xfer_mask;
-
-
-	DMA(instance)->secret2 = 1;
-	DMA(instance)->secret1 = 0;
-	DMA(instance)->secret3 = 15;
-	while (DMA(instance)->CNTR & GVP11_DMAC_BUSY) ;
-	DMA(instance)->CNTR = 0;
-
-	DMA(instance)->BANK = 0;
-
-	epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
-
-	/*
-	 * Check for 14MHz SCSI clock
-	 */
-	regs.SASR = &(DMA(instance)->SASR);
-	regs.SCMD = &(DMA(instance)->SCMD);
-	HDATA(instance)->no_sync = 0xff;
-	HDATA(instance)->fast = 0;
-	HDATA(instance)->dma_mode = CTRL_DMA;
-	wd33c93_init(instance, regs, dma_setup, dma_stop,
-		     (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
-					     : WD33C93_FS_12_15);
-
-	if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, "GVP11 SCSI",
-			instance))
-		goto unregister;
-	DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
-	num_gvp11++;
-	continue;
+		instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
+		if (instance == NULL)
+			goto release;
+		instance->base = ZTWO_VADDR(address);
+		instance->irq = IRQ_AMIGA_PORTS;
+		instance->unique_id = z->slotaddr;
+
+		hdata = shost_priv(instance);
+		if (gvp11_xfer_mask)
+			hdata->dma_xfer_mask = gvp11_xfer_mask;
+		else
+			hdata->dma_xfer_mask = default_dma_xfer_mask;
+
+		DMA(instance)->secret2 = 1;
+		DMA(instance)->secret1 = 0;
+		DMA(instance)->secret3 = 15;
+		while (DMA(instance)->CNTR & GVP11_DMAC_BUSY)
+			;
+		DMA(instance)->CNTR = 0;
+
+		DMA(instance)->BANK = 0;
+
+		epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
+
+		/*
+		 * Check for 14MHz SCSI clock
+		 */
+		regs.SASR = &(DMA(instance)->SASR);
+		regs.SCMD = &(DMA(instance)->SCMD);
+		hdata->no_sync = 0xff;
+		hdata->fast = 0;
+		hdata->dma_mode = CTRL_DMA;
+		wd33c93_init(instance, regs, dma_setup, dma_stop,
+			     (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
+						     : WD33C93_FS_12_15);
+
+		if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED,
+				"GVP11 SCSI", instance))
+			goto unregister;
+		DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+		num_gvp11++;
+		continue;
 
 unregister:
-	scsi_unregister(instance);
-	wd33c93_release();
+		scsi_unregister(instance);
 release:
-	release_mem_region(address, 256);
-    }
+		release_mem_region(address, 256);
+	}
 
-    return num_gvp11;
+	return num_gvp11;
 }
 
 static int gvp11_bus_reset(struct scsi_cmnd *cmd)
@@ -389,12 +391,11 @@ static struct scsi_host_template driver_template = {
 int gvp11_release(struct Scsi_Host *instance)
 {
 #ifdef MODULE
-    DMA(instance)->CNTR = 0;
-    release_mem_region(ZTWO_PADDR(instance->base), 256);
-    free_irq(IRQ_AMIGA_PORTS, instance);
-    wd33c93_release();
+	DMA(instance)->CNTR = 0;
+	release_mem_region(ZTWO_PADDR(instance->base), 256);
+	free_irq(IRQ_AMIGA_PORTS, instance);
 #endif
-    return 1;
+	return 1;
 }
 
 MODULE_LICENSE("GPL");

+ 18 - 18
drivers/scsi/gvp11.h

@@ -15,11 +15,11 @@ int gvp11_detect(struct scsi_host_template *);
 int gvp11_release(struct Scsi_Host *);
 
 #ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
+#define CMD_PER_LUN		2
 #endif
 
 #ifndef CAN_QUEUE
-#define CAN_QUEUE 16
+#define CAN_QUEUE		16
 #endif
 
 #ifndef HOSTS_C
@@ -28,24 +28,24 @@ int gvp11_release(struct Scsi_Host *);
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
  */
-#define GVP11_XFER_MASK  (0xff000001)
+#define GVP11_XFER_MASK		(0xff000001)
 
 typedef struct {
-             unsigned char      pad1[64];
-    volatile unsigned short     CNTR;
-             unsigned char      pad2[31];
-    volatile unsigned char      SASR;
-             unsigned char      pad3;
-    volatile unsigned char      SCMD;
-             unsigned char      pad4[4];
-    volatile unsigned short     BANK;
-             unsigned char      pad5[6];
-    volatile unsigned long      ACR;
-    volatile unsigned short     secret1; /* store 0 here */
-    volatile unsigned short     ST_DMA;
-    volatile unsigned short     SP_DMA;
-    volatile unsigned short     secret2; /* store 1 here */
-    volatile unsigned short     secret3; /* store 15 here */
+		 unsigned char	pad1[64];
+	volatile unsigned short	CNTR;
+		 unsigned char	pad2[31];
+	volatile unsigned char	SASR;
+		 unsigned char	pad3;
+	volatile unsigned char	SCMD;
+		 unsigned char	pad4[4];
+	volatile unsigned short	BANK;
+		 unsigned char	pad5[6];
+	volatile unsigned long	ACR;
+	volatile unsigned short	secret1; /* store 0 here */
+	volatile unsigned short	ST_DMA;
+	volatile unsigned short	SP_DMA;
+	volatile unsigned short	secret2; /* store 1 here */
+	volatile unsigned short	secret3; /* store 15 here */
 } gvp11_scsiregs;
 
 /* bits in CNTR */

+ 0 - 8
drivers/scsi/hpsa.c

@@ -2708,14 +2708,6 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
 			c->Request.CDB[8] = (size >> 8) & 0xFF;
 			c->Request.CDB[9] = size & 0xFF;
 			break;
-
-		case HPSA_READ_CAPACITY:
-			c->Request.CDBLen = 10;
-			c->Request.Type.Attribute = ATTR_SIMPLE;
-			c->Request.Type.Direction = XFER_READ;
-			c->Request.Timeout = 0;
-			c->Request.CDB[0] = cmd;
-			break;
 		case HPSA_CACHE_FLUSH:
 			c->Request.CDBLen = 12;
 			c->Request.Type.Attribute = ATTR_SIMPLE;

+ 0 - 15
drivers/scsi/hpsa_cmd.h

@@ -152,21 +152,6 @@ struct SenseSubsystem_info {
 	u8 reserved1[1108];
 };
 
-#define HPSA_READ_CAPACITY 0x25 /* Read Capacity */
-struct ReadCapdata {
-	u8 total_size[4];	/* Total size in blocks */
-	u8 block_size[4];	/* Size of blocks in bytes */
-};
-
-#if 0
-/* 12 byte commands not implemented in firmware yet. */
-#define HPSA_READ 	0xa8
-#define HPSA_WRITE	0xaa
-#endif
-
-#define HPSA_READ   0x28    /* Read(10) */
-#define HPSA_WRITE  0x2a    /* Write(10) */
-
 /* BMIC commands */
 #define BMIC_READ 0x26
 #define BMIC_WRITE 0x27

+ 7 - 1
drivers/scsi/ibmvscsi/ibmvfc.c

@@ -2245,7 +2245,7 @@ static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device,
 	DECLARE_COMPLETION_ONSTACK(comp);
 	int wait;
 	unsigned long flags;
-	signed long timeout = init_timeout * HZ;
+	signed long timeout = IBMVFC_ABORT_WAIT_TIMEOUT * HZ;
 
 	ENTER;
 	do {
@@ -3013,6 +3013,7 @@ static struct ibmvfc_async_crq *ibmvfc_next_async_crq(struct ibmvfc_host *vhost)
 	if (crq->valid & 0x80) {
 		if (++async_crq->cur == async_crq->size)
 			async_crq->cur = 0;
+		rmb();
 	} else
 		crq = NULL;
 
@@ -3035,6 +3036,7 @@ static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost)
 	if (crq->valid & 0x80) {
 		if (++queue->cur == queue->size)
 			queue->cur = 0;
+		rmb();
 	} else
 		crq = NULL;
 
@@ -3083,12 +3085,14 @@ static void ibmvfc_tasklet(void *data)
 		while ((async = ibmvfc_next_async_crq(vhost)) != NULL) {
 			ibmvfc_handle_async(async, vhost);
 			async->valid = 0;
+			wmb();
 		}
 
 		/* Pull all the valid messages off the CRQ */
 		while ((crq = ibmvfc_next_crq(vhost)) != NULL) {
 			ibmvfc_handle_crq(crq, vhost);
 			crq->valid = 0;
+			wmb();
 		}
 
 		vio_enable_interrupts(vdev);
@@ -3096,10 +3100,12 @@ static void ibmvfc_tasklet(void *data)
 			vio_disable_interrupts(vdev);
 			ibmvfc_handle_async(async, vhost);
 			async->valid = 0;
+			wmb();
 		} else if ((crq = ibmvfc_next_crq(vhost)) != NULL) {
 			vio_disable_interrupts(vdev);
 			ibmvfc_handle_crq(crq, vhost);
 			crq->valid = 0;
+			wmb();
 		} else
 			done = 1;
 	}

+ 1 - 0
drivers/scsi/ibmvscsi/ibmvfc.h

@@ -38,6 +38,7 @@
 #define IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT	\
 		(IBMVFC_ADISC_TIMEOUT + IBMVFC_ADISC_CANCEL_TIMEOUT)
 #define IBMVFC_INIT_TIMEOUT		120
+#define IBMVFC_ABORT_WAIT_TIMEOUT	40
 #define IBMVFC_MAX_REQUESTS_DEFAULT	100
 
 #define IBMVFC_DEBUG			0

+ 4 - 2
drivers/scsi/iscsi_tcp.c

@@ -206,8 +206,10 @@ static void iscsi_sw_tcp_conn_set_callbacks(struct iscsi_conn *conn)
 }
 
 static void
-iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_sw_tcp_conn *tcp_sw_conn)
+iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn)
 {
+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+	struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
 	struct sock *sk = tcp_sw_conn->sock->sk;
 
 	/* restore socket callbacks, see also: iscsi_conn_set_callbacks() */
@@ -555,7 +557,7 @@ static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn)
 		return;
 
 	sock_hold(sock->sk);
-	iscsi_sw_tcp_conn_restore_callbacks(tcp_sw_conn);
+	iscsi_sw_tcp_conn_restore_callbacks(conn);
 	sock_put(sock->sk);
 
 	spin_lock_bh(&session->lock);

+ 0 - 1
drivers/scsi/iscsi_tcp.h

@@ -36,7 +36,6 @@ struct iscsi_sw_tcp_send {
 };
 
 struct iscsi_sw_tcp_conn {
-	struct iscsi_conn	*iscsi_conn;
 	struct socket		*sock;
 
 	struct iscsi_sw_tcp_send out;

+ 4 - 4
drivers/scsi/libfc/fc_disc.c

@@ -132,7 +132,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
 		switch (fmt) {
 		case ELS_ADDR_FMT_PORT:
 			FC_DISC_DBG(disc, "Port address format for port "
-				    "(%6x)\n", ntoh24(pp->rscn_fid));
+				    "(%6.6x)\n", ntoh24(pp->rscn_fid));
 			dp = kzalloc(sizeof(*dp), GFP_KERNEL);
 			if (!dp) {
 				redisc = 1;
@@ -440,7 +440,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
 		ids.port_id = ntoh24(np->fp_fid);
 		ids.port_name = ntohll(np->fp_wwpn);
 
-		if (ids.port_id != fc_host_port_id(lport->host) &&
+		if (ids.port_id != lport->port_id &&
 		    ids.port_name != lport->wwpn) {
 			rdata = lport->tt.rport_create(lport, ids.port_id);
 			if (rdata) {
@@ -449,7 +449,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
 			} else {
 				printk(KERN_WARNING "libfc: Failed to allocate "
 				       "memory for the newly discovered port "
-				       "(%6x)\n", ids.port_id);
+				       "(%6.6x)\n", ids.port_id);
 				error = -ENOMEM;
 			}
 		}
@@ -607,7 +607,7 @@ static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,
 			rdata->ids.port_name = port_name;
 		else if (rdata->ids.port_name != port_name) {
 			FC_DISC_DBG(disc, "GPN_ID accepted.  WWPN changed. "
-				    "Port-id %x wwpn %llx\n",
+				    "Port-id %6.6x wwpn %16.16llx\n",
 				    rdata->ids.port_id, port_name);
 			lport->tt.rport_logoff(rdata);
 

+ 1 - 1
drivers/scsi/libfc/fc_elsct.c

@@ -63,7 +63,7 @@ struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did,
 		return NULL;
 	}
 
-	fc_fill_fc_hdr(fp, r_ctl, did, fc_host_port_id(lport->host), fh_type,
+	fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type,
 		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
 	return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec);

+ 17 - 34
drivers/scsi/libfc/fc_exch.c

@@ -488,7 +488,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
 	 */
 	spin_lock_bh(&ep->ex_lock);
 	ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ;	/* not first seq */
-	if (f_ctl & (FC_FC_END_SEQ | FC_FC_SEQ_INIT))
+	if (f_ctl & FC_FC_SEQ_INIT)
 		ep->esb_stat &= ~ESB_ST_SEQ_INIT;
 	spin_unlock_bh(&ep->ex_lock);
 	return error;
@@ -676,9 +676,10 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,
 	}
 	memset(ep, 0, sizeof(*ep));
 
-	cpu = smp_processor_id();
+	cpu = get_cpu();
 	pool = per_cpu_ptr(mp->pool, cpu);
 	spin_lock_bh(&pool->lock);
+	put_cpu();
 	index = pool->next_index;
 	/* allocate new exch from pool */
 	while (fc_exch_ptr_get(pool, index)) {
@@ -734,19 +735,14 @@ err:
  * EM is selected when a NULL match function pointer is encountered
  * or when a call to a match function returns true.
  */
-static struct fc_exch *fc_exch_alloc(struct fc_lport *lport,
-				     struct fc_frame *fp)
+static inline struct fc_exch *fc_exch_alloc(struct fc_lport *lport,
+					    struct fc_frame *fp)
 {
 	struct fc_exch_mgr_anchor *ema;
-	struct fc_exch *ep;
 
-	list_for_each_entry(ema, &lport->ema_list, ema_list) {
-		if (!ema->match || ema->match(fp)) {
-			ep = fc_exch_em_alloc(lport, ema->mp);
-			if (ep)
-				return ep;
-		}
-	}
+	list_for_each_entry(ema, &lport->ema_list, ema_list)
+		if (!ema->match || ema->match(fp))
+			return fc_exch_em_alloc(lport, ema->mp);
 	return NULL;
 }
 
@@ -920,13 +916,9 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport,
 	 * Find or create the sequence.
 	 */
 	if (fc_sof_is_init(fr_sof(fp))) {
-		sp = fc_seq_start_next(&ep->seq);
-		if (!sp) {
-			reject = FC_RJT_SEQ_XS;	/* exchange shortage */
-			goto rel;
-		}
-		sp->id = fh->fh_seq_id;
+		sp = &ep->seq;
 		sp->ssb_stat |= SSB_ST_RESP;
+		sp->id = fh->fh_seq_id;
 	} else {
 		sp = &ep->seq;
 		if (sp->id != fh->fh_seq_id) {
@@ -1250,9 +1242,6 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
 	struct fc_frame_header *fh = fc_frame_header_get(fp);
 	struct fc_seq *sp = NULL;
 	struct fc_exch *ep = NULL;
-	enum fc_sof sof;
-	enum fc_eof eof;
-	u32 f_ctl;
 	enum fc_pf_rjt_reason reject;
 
 	/* We can have the wrong fc_lport at this point with NPIV, which is a
@@ -1269,9 +1258,6 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
 	if (reject == FC_RJT_NONE) {
 		sp = fr_seq(fp);	/* sequence will be held */
 		ep = fc_seq_exch(sp);
-		sof = fr_sof(fp);
-		eof = fr_eof(fp);
-		f_ctl = ntoh24(fh->fh_f_ctl);
 		fc_seq_send_ack(sp, fp);
 
 		/*
@@ -1336,17 +1322,15 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)
 		goto rel;
 	}
 	sof = fr_sof(fp);
+	sp = &ep->seq;
 	if (fc_sof_is_init(sof)) {
-		sp = fc_seq_start_next(&ep->seq);
-		sp->id = fh->fh_seq_id;
 		sp->ssb_stat |= SSB_ST_RESP;
-	} else {
-		sp = &ep->seq;
-		if (sp->id != fh->fh_seq_id) {
-			atomic_inc(&mp->stats.seq_not_found);
-			goto rel;
-		}
+		sp->id = fh->fh_seq_id;
+	} else if (sp->id != fh->fh_seq_id) {
+		atomic_inc(&mp->stats.seq_not_found);
+		goto rel;
 	}
+
 	f_ctl = ntoh24(fh->fh_f_ctl);
 	fr_seq(fp) = sp;
 	if (f_ctl & FC_FC_SEQ_INIT)
@@ -1763,7 +1747,6 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
 		fc_exch_done(sp);
 		goto out;
 	}
-	sp = fc_seq_start_next(sp);
 	acc = fc_frame_payload_get(fp, sizeof(*acc));
 	memset(acc, 0, sizeof(*acc));
 	acc->reca_cmd = ELS_LS_ACC;
@@ -1944,7 +1927,7 @@ static void fc_exch_rrq(struct fc_exch *ep)
 		did = ep->sid;
 
 	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, did,
-		       fc_host_port_id(lport->host), FC_TYPE_ELS,
+		       lport->port_id, FC_TYPE_ELS,
 		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
 	if (fc_exch_seq_send(lport, fp, fc_exch_rrq_resp, NULL, ep,

+ 64 - 39
drivers/scsi/libfc/fc_fcp.c

@@ -97,7 +97,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *);
 static void fc_fcp_complete_locked(struct fc_fcp_pkt *);
 static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *);
 static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *);
-static void fc_timeout_error(struct fc_fcp_pkt *);
+static void fc_fcp_recovery(struct fc_fcp_pkt *);
 static void fc_fcp_timeout(unsigned long);
 static void fc_fcp_rec(struct fc_fcp_pkt *);
 static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *);
@@ -121,7 +121,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *);
 #define FC_DATA_UNDRUN		7
 #define FC_ERROR		8
 #define FC_HRD_ERROR		9
-#define FC_CMD_TIME_OUT		10
+#define FC_CMD_RECOVERY		10
 
 /*
  * Error recovery timeout values.
@@ -446,9 +446,16 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 	len = fr_len(fp) - sizeof(*fh);
 	buf = fc_frame_payload_get(fp, 0);
 
-	/* if this I/O is ddped, update xfer len */
-	fc_fcp_ddp_done(fsp);
-
+	/*
+	 * if this I/O is ddped then clear it
+	 * and initiate recovery since data
+	 * frames are expected to be placed
+	 * directly in that case.
+	 */
+	if (fsp->xfer_ddp != FC_XID_UNKNOWN) {
+		fc_fcp_ddp_done(fsp);
+		goto err;
+	}
 	if (offset + len > fsp->data_len) {
 		/* this should never happen */
 		if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) &&
@@ -456,8 +463,7 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 			goto crc_err;
 		FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx "
 			   "data_len %x\n", len, offset, fsp->data_len);
-		fc_fcp_retry_cmd(fsp);
-		return;
+		goto err;
 	}
 	if (offset != fsp->xfer_len)
 		fsp->state |= FC_SRB_DISCONTIG;
@@ -478,13 +484,14 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 
 		if (~crc != le32_to_cpu(fr_crc(fp))) {
 crc_err:
-			stats = fc_lport_get_stats(lport);
+			stats = per_cpu_ptr(lport->dev_stats, get_cpu());
 			stats->ErrorFrames++;
-			/* FIXME - per cpu count, not total count! */
+			/* per cpu count, not total count, but OK for limit */
 			if (stats->InvalidCRCCount++ < 5)
 				printk(KERN_WARNING "libfc: CRC error on data "
-				       "frame for port (%6x)\n",
-				       fc_host_port_id(lport->host));
+				       "frame for port (%6.6x)\n",
+				       lport->port_id);
+			put_cpu();
 			/*
 			 * Assume the frame is total garbage.
 			 * We may have copied it over the good part
@@ -493,7 +500,7 @@ crc_err:
 			 * Otherwise, ignore it.
 			 */
 			if (fsp->state & FC_SRB_DISCONTIG)
-				fc_fcp_retry_cmd(fsp);
+				goto err;
 			return;
 		}
 	}
@@ -509,6 +516,9 @@ crc_err:
 	if (unlikely(fsp->state & FC_SRB_RCV_STATUS) &&
 	    fsp->xfer_len == fsp->data_len - fsp->scsi_resid)
 		fc_fcp_complete_locked(fsp);
+	return;
+err:
+	fc_fcp_recovery(fsp);
 }
 
 /**
@@ -834,8 +844,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 					 * exit here
 					 */
 					return;
-				} else
-					goto err;
+				}
 			}
 			if (flags & FCP_SNS_LEN_VAL) {
 				snsl = ntohl(rp_ex->fr_sns_len);
@@ -885,7 +894,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 			return;
 		}
 		fsp->status_code = FC_DATA_OVRRUN;
-		FC_FCP_DBG(fsp, "tgt %6x xfer len %zx greater than expected, "
+		FC_FCP_DBG(fsp, "tgt %6.6x xfer len %zx greater than expected, "
 			   "len %x, data len %x\n",
 			   fsp->rport->port_id,
 			   fsp->xfer_len, expected_len, fsp->data_len);
@@ -1100,7 +1109,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
 	rpriv = rport->dd_data;
 
 	fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id,
-		       fc_host_port_id(rpriv->local_port->host), FC_TYPE_FCP,
+		       rpriv->local_port->port_id, FC_TYPE_FCP,
 		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
 	seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy,
@@ -1341,7 +1350,7 @@ static void fc_fcp_timeout(unsigned long data)
 	else if (fsp->state & FC_SRB_RCV_STATUS)
 		fc_fcp_complete_locked(fsp);
 	else
-		fc_timeout_error(fsp);
+		fc_fcp_recovery(fsp);
 	fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO;
 unlock:
 	fc_fcp_unlock_pkt(fsp);
@@ -1373,7 +1382,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
 
 	fr_seq(fp) = fsp->seq_ptr;
 	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id,
-		       fc_host_port_id(rpriv->local_port->host), FC_TYPE_ELS,
+		       rpriv->local_port->port_id, FC_TYPE_ELS,
 		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 	if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC,
 				 fc_fcp_rec_resp, fsp,
@@ -1385,7 +1394,7 @@ retry:
 	if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
 		fc_fcp_timer_set(fsp, FC_SCSI_REC_TOV);
 	else
-		fc_timeout_error(fsp);
+		fc_fcp_recovery(fsp);
 }
 
 /**
@@ -1454,7 +1463,7 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
 				fc_fcp_retry_cmd(fsp);
 				break;
 			}
-			fc_timeout_error(fsp);
+			fc_fcp_recovery(fsp);
 			break;
 		}
 	} else if (opcode == ELS_LS_ACC) {
@@ -1553,7 +1562,7 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 		break;
 
 	default:
-		FC_FCP_DBG(fsp, "REC %p fid %x error unexpected error %d\n",
+		FC_FCP_DBG(fsp, "REC %p fid %6.6x error unexpected error %d\n",
 			   fsp, fsp->rport->port_id, error);
 		fsp->status_code = FC_CMD_PLOGO;
 		/* fall through */
@@ -1563,13 +1572,13 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 		 * Assume REC or LS_ACC was lost.
 		 * The exchange manager will have aborted REC, so retry.
 		 */
-		FC_FCP_DBG(fsp, "REC fid %x error error %d retry %d/%d\n",
+		FC_FCP_DBG(fsp, "REC fid %6.6x error error %d retry %d/%d\n",
 			   fsp->rport->port_id, error, fsp->recov_retry,
 			   FC_MAX_RECOV_RETRY);
 		if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
 			fc_fcp_rec(fsp);
 		else
-			fc_timeout_error(fsp);
+			fc_fcp_recovery(fsp);
 		break;
 	}
 	fc_fcp_unlock_pkt(fsp);
@@ -1578,12 +1587,12 @@ out:
 }
 
 /**
- * fc_timeout_error() - Handler for fcp_pkt timeouts
- * @fsp: The FCP packt that has timed out
+ * fc_fcp_recovery() - Handler for fcp_pkt recovery
+ * @fsp: The FCP pkt that needs to be aborted
  */
-static void fc_timeout_error(struct fc_fcp_pkt *fsp)
+static void fc_fcp_recovery(struct fc_fcp_pkt *fsp)
 {
-	fsp->status_code = FC_CMD_TIME_OUT;
+	fsp->status_code = FC_CMD_RECOVERY;
 	fsp->cdb_status = 0;
 	fsp->io_status = 0;
 	/*
@@ -1631,7 +1640,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
 	srr->srr_rel_off = htonl(offset);
 
 	fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id,
-		       fc_host_port_id(rpriv->local_port->host), FC_TYPE_FCP,
+		       rpriv->local_port->port_id, FC_TYPE_FCP,
 		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
 
 	seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL,
@@ -1689,7 +1698,7 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
 		break;
 	case ELS_LS_RJT:
 	default:
-		fc_timeout_error(fsp);
+		fc_fcp_recovery(fsp);
 		break;
 	}
 	fc_fcp_unlock_pkt(fsp);
@@ -1715,7 +1724,7 @@ static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
 		if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY)
 			fc_fcp_rec(fsp);
 		else
-			fc_timeout_error(fsp);
+			fc_fcp_recovery(fsp);
 		break;
 	case -FC_EX_CLOSED:			/* e.g., link failure */
 		/* fall through */
@@ -1810,7 +1819,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
 	/*
 	 * setup the data direction
 	 */
-	stats = fc_lport_get_stats(lport);
+	stats = per_cpu_ptr(lport->dev_stats, get_cpu());
 	if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
 		fsp->req_flags = FC_SRB_READ;
 		stats->InputRequests++;
@@ -1823,6 +1832,7 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
 		fsp->req_flags = 0;
 		stats->ControlRequests++;
 	}
+	put_cpu();
 
 	fsp->tgt_flags = rpriv->flags;
 
@@ -1907,6 +1917,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
 		}
 		break;
 	case FC_ERROR:
+		FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
+			   "due to FC_ERROR\n");
 		sc_cmd->result = DID_ERROR << 16;
 		break;
 	case FC_DATA_UNDRUN:
@@ -1915,12 +1927,19 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
 			 * scsi status is good but transport level
 			 * underrun.
 			 */
-			sc_cmd->result = (fsp->state & FC_SRB_RCV_STATUS ?
-					  DID_OK : DID_ERROR) << 16;
+			if (fsp->state & FC_SRB_RCV_STATUS) {
+				sc_cmd->result = DID_OK << 16;
+			} else {
+				FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml"
+					   " due to FC_DATA_UNDRUN (trans)\n");
+				sc_cmd->result = DID_ERROR << 16;
+			}
 		} else {
 			/*
 			 * scsi got underrun, this is an error
 			 */
+			FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
+				   "due to FC_DATA_UNDRUN (scsi)\n");
 			CMD_RESID_LEN(sc_cmd) = fsp->scsi_resid;
 			sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status;
 		}
@@ -1929,12 +1948,16 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
 		/*
 		 * overrun is an error
 		 */
+		FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
+			   "due to FC_DATA_OVRRUN\n");
 		sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status;
 		break;
 	case FC_CMD_ABORTED:
+		FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
+			   "due to FC_CMD_ABORTED\n");
 		sc_cmd->result = (DID_ERROR << 16) | fsp->io_status;
 		break;
-	case FC_CMD_TIME_OUT:
+	case FC_CMD_RECOVERY:
 		sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status;
 		break;
 	case FC_CMD_RESET:
@@ -1944,6 +1967,8 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
 		sc_cmd->result = (DID_NO_CONNECT << 16);
 		break;
 	default:
+		FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml "
+			   "due to unknown error\n");
 		sc_cmd->result = (DID_ERROR << 16);
 		break;
 	}
@@ -2028,7 +2053,7 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
 	if (lport->state != LPORT_ST_READY)
 		return rc;
 
-	FC_SCSI_DBG(lport, "Resetting rport (%6x)\n", rport->port_id);
+	FC_SCSI_DBG(lport, "Resetting rport (%6.6x)\n", rport->port_id);
 
 	fsp = fc_fcp_pkt_alloc(lport, GFP_NOIO);
 	if (fsp == NULL) {
@@ -2076,12 +2101,12 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd)
 
 	if (fc_fcp_lport_queue_ready(lport)) {
 		shost_printk(KERN_INFO, shost, "libfc: Host reset succeeded "
-			     "on port (%6x)\n", fc_host_port_id(lport->host));
+			     "on port (%6.6x)\n", lport->port_id);
 		return SUCCESS;
 	} else {
 		shost_printk(KERN_INFO, shost, "libfc: Host reset failed, "
-			     "port (%6x) is not ready.\n",
-			     fc_host_port_id(lport->host));
+			     "port (%6.6x) is not ready.\n",
+			     lport->port_id);
 		return FAILED;
 	}
 }
@@ -2166,7 +2191,7 @@ void fc_fcp_destroy(struct fc_lport *lport)
 
 	if (!list_empty(&si->scsi_pkt_queue))
 		printk(KERN_ERR "libfc: Leaked SCSI packets when destroying "
-		       "port (%6x)\n", fc_host_port_id(lport->host));
+		       "port (%6.6x)\n", lport->port_id);
 
 	mempool_destroy(si->scsi_pkt_pool);
 	kfree(si);

+ 4 - 4
drivers/scsi/libfc/fc_libfc.h

@@ -45,9 +45,9 @@ extern unsigned int fc_debug_logging;
 
 #define FC_LPORT_DBG(lport, fmt, args...)				\
 	FC_CHECK_LOGGING(FC_LPORT_LOGGING,				\
-			 printk(KERN_INFO "host%u: lport %6x: " fmt,	\
+			 printk(KERN_INFO "host%u: lport %6.6x: " fmt,	\
 				(lport)->host->host_no,			\
-				fc_host_port_id((lport)->host), ##args))
+				(lport)->port_id, ##args))
 
 #define FC_DISC_DBG(disc, fmt, args...)				\
 	FC_CHECK_LOGGING(FC_DISC_LOGGING,			\
@@ -57,7 +57,7 @@ extern unsigned int fc_debug_logging;
 
 #define FC_RPORT_ID_DBG(lport, port_id, fmt, args...)			\
 	FC_CHECK_LOGGING(FC_RPORT_LOGGING,				\
-			 printk(KERN_INFO "host%u: rport %6x: " fmt,	\
+			 printk(KERN_INFO "host%u: rport %6.6x: " fmt,	\
 				(lport)->host->host_no,			\
 				(port_id), ##args))
 
@@ -66,7 +66,7 @@ extern unsigned int fc_debug_logging;
 
 #define FC_FCP_DBG(pkt, fmt, args...)					\
 	FC_CHECK_LOGGING(FC_FCP_LOGGING,				\
-			 printk(KERN_INFO "host%u: fcp: %6x: " fmt,	\
+			 printk(KERN_INFO "host%u: fcp: %6.6x: " fmt,	\
 				(pkt)->lp->host->host_no,		\
 				pkt->rport->port_id, ##args))
 

+ 29 - 29
drivers/scsi/libfc/fc_lport.c

@@ -172,7 +172,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
 				    struct fc_rport_priv *rdata,
 				    enum fc_rport_event event)
 {
-	FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event,
+	FC_LPORT_DBG(lport, "Received a %d event for port (%6.6x)\n", event,
 		     rdata->ids.port_id);
 
 	mutex_lock(&lport->lp_mutex);
@@ -183,7 +183,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,
 			fc_lport_enter_ns(lport, LPORT_ST_RNN_ID);
 		} else {
 			FC_LPORT_DBG(lport, "Received an READY event "
-				     "on port (%6x) for the directory "
+				     "on port (%6.6x) for the directory "
 				     "server, but the lport is not "
 				     "in the DNS state, it's in the "
 				     "%d state", rdata->ids.port_id,
@@ -228,9 +228,12 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
 			       u64 remote_wwnn)
 {
 	mutex_lock(&lport->disc.disc_mutex);
-	if (lport->ptp_rdata)
+	if (lport->ptp_rdata) {
 		lport->tt.rport_logoff(lport->ptp_rdata);
+		kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy);
+	}
 	lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid);
+	kref_get(&lport->ptp_rdata->kref);
 	lport->ptp_rdata->ids.port_name = remote_wwpn;
 	lport->ptp_rdata->ids.node_name = remote_wwnn;
 	mutex_unlock(&lport->disc.disc_mutex);
@@ -240,17 +243,6 @@ static void fc_lport_ptp_setup(struct fc_lport *lport,
 	fc_lport_enter_ready(lport);
 }
 
-/**
- * fc_get_host_port_type() - Return the port type of the given Scsi_Host
- * @shost: The SCSI host whose port type is to be determined
- */
-void fc_get_host_port_type(struct Scsi_Host *shost)
-{
-	/* TODO - currently just NPORT */
-	fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
-}
-EXPORT_SYMBOL(fc_get_host_port_type);
-
 /**
  * fc_get_host_port_state() - Return the port state of the given Scsi_Host
  * @shost:  The SCSI host whose port state is to be determined
@@ -572,8 +564,8 @@ void __fc_linkup(struct fc_lport *lport)
  */
 void fc_linkup(struct fc_lport *lport)
 {
-	printk(KERN_INFO "host%d: libfc: Link up on port (%6x)\n",
-	       lport->host->host_no, fc_host_port_id(lport->host));
+	printk(KERN_INFO "host%d: libfc: Link up on port (%6.6x)\n",
+	       lport->host->host_no, lport->port_id);
 
 	mutex_lock(&lport->lp_mutex);
 	__fc_linkup(lport);
@@ -602,8 +594,8 @@ void __fc_linkdown(struct fc_lport *lport)
  */
 void fc_linkdown(struct fc_lport *lport)
 {
-	printk(KERN_INFO "host%d: libfc: Link down on port (%6x)\n",
-	       lport->host->host_no, fc_host_port_id(lport->host));
+	printk(KERN_INFO "host%d: libfc: Link down on port (%6.6x)\n",
+	       lport->host->host_no, lport->port_id);
 
 	mutex_lock(&lport->lp_mutex);
 	__fc_linkdown(lport);
@@ -704,8 +696,8 @@ void fc_lport_disc_callback(struct fc_lport *lport, enum fc_disc_event event)
 		break;
 	case DISC_EV_FAILED:
 		printk(KERN_ERR "host%d: libfc: "
-		       "Discovery failed for port (%6x)\n",
-		       lport->host->host_no, fc_host_port_id(lport->host));
+		       "Discovery failed for port (%6.6x)\n",
+		       lport->host->host_no, lport->port_id);
 		mutex_lock(&lport->lp_mutex);
 		fc_lport_enter_reset(lport);
 		mutex_unlock(&lport->lp_mutex);
@@ -750,10 +742,14 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id,
 				 struct fc_frame *fp)
 {
 	if (port_id)
-		printk(KERN_INFO "host%d: Assigned Port ID %6x\n",
+		printk(KERN_INFO "host%d: Assigned Port ID %6.6x\n",
 		       lport->host->host_no, port_id);
 
+	lport->port_id = port_id;
+
+	/* Update the fc_host */
 	fc_host_port_id(lport->host) = port_id;
+
 	if (lport->tt.lport_set_port_id)
 		lport->tt.lport_set_port_id(lport, port_id, fp);
 }
@@ -797,11 +793,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 	remote_wwpn = get_unaligned_be64(&flp->fl_wwpn);
 	if (remote_wwpn == lport->wwpn) {
 		printk(KERN_WARNING "host%d: libfc: Received FLOGI from port "
-		       "with same WWPN %llx\n",
+		       "with same WWPN %16.16llx\n",
 		       lport->host->host_no, remote_wwpn);
 		goto out;
 	}
-	FC_LPORT_DBG(lport, "FLOGI from port WWPN %llx\n", remote_wwpn);
+	FC_LPORT_DBG(lport, "FLOGI from port WWPN %16.16llx\n", remote_wwpn);
 
 	/*
 	 * XXX what is the right thing to do for FIDs?
@@ -832,7 +828,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 		 */
 		f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
 		ep = fc_seq_exch(sp);
-		fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
+		fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, remote_fid, local_fid,
 			       FC_TYPE_ELS, f_ctl, 0);
 		lport->tt.seq_send(lport, sp, fp);
 
@@ -947,14 +943,18 @@ static void fc_lport_reset_locked(struct fc_lport *lport)
 	if (lport->dns_rdata)
 		lport->tt.rport_logoff(lport->dns_rdata);
 
-	lport->ptp_rdata = NULL;
+	if (lport->ptp_rdata) {
+		lport->tt.rport_logoff(lport->ptp_rdata);
+		kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy);
+		lport->ptp_rdata = NULL;
+	}
 
 	lport->tt.disc_stop(lport);
 
 	lport->tt.exch_mgr_reset(lport, 0, 0);
 	fc_host_fabric_name(lport->host) = 0;
 
-	if (fc_host_port_id(lport->host))
+	if (lport->port_id)
 		fc_lport_set_port_id(lport, 0, NULL);
 }
 
@@ -1492,7 +1492,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 				lport->r_a_tov = 2 * e_d_tov;
 				fc_lport_set_port_id(lport, did, fp);
 				printk(KERN_INFO "host%d: libfc: "
-				       "Port (%6x) entered "
+				       "Port (%6.6x) entered "
 				       "point-to-point mode\n",
 				       lport->host->host_no, did);
 				fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id),
@@ -1699,7 +1699,7 @@ static int fc_lport_els_request(struct fc_bsg_job *job,
 	fh = fc_frame_header_get(fp);
 	fh->fh_r_ctl = FC_RCTL_ELS_REQ;
 	hton24(fh->fh_d_id, did);
-	hton24(fh->fh_s_id, fc_host_port_id(lport->host));
+	hton24(fh->fh_s_id, lport->port_id);
 	fh->fh_type = FC_TYPE_ELS;
 	hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
 	       FC_FC_END_SEQ | FC_FC_SEQ_INIT);
@@ -1759,7 +1759,7 @@ static int fc_lport_ct_request(struct fc_bsg_job *job,
 	fh = fc_frame_header_get(fp);
 	fh->fh_r_ctl = FC_RCTL_DD_UNSOL_CTL;
 	hton24(fh->fh_d_id, did);
-	hton24(fh->fh_s_id, fc_host_port_id(lport->host));
+	hton24(fh->fh_s_id, lport->port_id);
 	fh->fh_type = FC_TYPE_CT;
 	hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
 	       FC_FC_END_SEQ | FC_FC_SEQ_INIT);

+ 5 - 2
drivers/scsi/libfc/fc_npiv.c

@@ -69,12 +69,15 @@ struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id)
 	struct fc_lport *lport = NULL;
 	struct fc_lport *vn_port;
 
-	if (fc_host_port_id(n_port->host) == port_id)
+	if (n_port->port_id == port_id)
 		return n_port;
 
+	if (port_id == FC_FID_FLOGI)
+		return n_port;		/* for point-to-point */
+
 	mutex_lock(&n_port->lp_mutex);
 	list_for_each_entry(vn_port, &n_port->vports, list) {
-		if (fc_host_port_id(vn_port->host) == port_id) {
+		if (vn_port->port_id == port_id) {
 			lport = vn_port;
 			break;
 		}

+ 87 - 108
drivers/scsi/libfc/fc_rport.c

@@ -1442,136 +1442,115 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
 	struct fc_els_spp *spp;	/* response spp */
 	unsigned int len;
 	unsigned int plen;
-	enum fc_els_rjt_reason reason = ELS_RJT_UNAB;
-	enum fc_els_rjt_explan explan = ELS_EXPL_NONE;
 	enum fc_els_spp_resp resp;
 	struct fc_seq_els_data rjt_data;
 	u32 f_ctl;
 	u32 fcp_parm;
 	u32 roles = FC_RPORT_ROLE_UNKNOWN;
-	rjt_data.fp = NULL;
 
+	rjt_data.fp = NULL;
 	fh = fc_frame_header_get(rx_fp);
 
 	FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
 		     fc_rport_state(rdata));
 
-	switch (rdata->rp_state) {
-	case RPORT_ST_PRLI:
-	case RPORT_ST_RTV:
-	case RPORT_ST_READY:
-	case RPORT_ST_ADISC:
-		reason = ELS_RJT_NONE;
-		break;
-	default:
-		fc_frame_free(rx_fp);
-		return;
-		break;
-	}
 	len = fr_len(rx_fp) - sizeof(*fh);
 	pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
-	if (pp == NULL) {
-		reason = ELS_RJT_PROT;
-		explan = ELS_EXPL_INV_LEN;
-	} else {
-		plen = ntohs(pp->prli.prli_len);
-		if ((plen % 4) != 0 || plen > len) {
-			reason = ELS_RJT_PROT;
-			explan = ELS_EXPL_INV_LEN;
-		} else if (plen < len) {
-			len = plen;
-		}
-		plen = pp->prli.prli_spp_len;
-		if ((plen % 4) != 0 || plen < sizeof(*spp) ||
-		    plen > len || len < sizeof(*pp)) {
-			reason = ELS_RJT_PROT;
-			explan = ELS_EXPL_INV_LEN;
-		}
-		rspp = &pp->spp;
+	if (!pp)
+		goto reject_len;
+	plen = ntohs(pp->prli.prli_len);
+	if ((plen % 4) != 0 || plen > len || plen < 16)
+		goto reject_len;
+	if (plen < len)
+		len = plen;
+	plen = pp->prli.prli_spp_len;
+	if ((plen % 4) != 0 || plen < sizeof(*spp) ||
+	    plen > len || len < sizeof(*pp) || plen < 12)
+		goto reject_len;
+	rspp = &pp->spp;
+
+	fp = fc_frame_alloc(lport, len);
+	if (!fp) {
+		rjt_data.reason = ELS_RJT_UNAB;
+		rjt_data.explan = ELS_EXPL_INSUF_RES;
+		goto reject;
 	}
-	if (reason != ELS_RJT_NONE ||
-	    (fp = fc_frame_alloc(lport, len)) == NULL) {
-		rjt_data.reason = reason;
-		rjt_data.explan = explan;
-		lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
-	} else {
-		sp = lport->tt.seq_start_next(sp);
-		WARN_ON(!sp);
-		pp = fc_frame_payload_get(fp, len);
-		WARN_ON(!pp);
-		memset(pp, 0, len);
-		pp->prli.prli_cmd = ELS_LS_ACC;
-		pp->prli.prli_spp_len = plen;
-		pp->prli.prli_len = htons(len);
-		len -= sizeof(struct fc_els_prli);
-
-		/* reinitialize remote port roles */
-		rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
-
-		/*
-		 * Go through all the service parameter pages and build
-		 * response.  If plen indicates longer SPP than standard,
-		 * use that.  The entire response has been pre-cleared above.
-		 */
-		spp = &pp->spp;
-		while (len >= plen) {
-			spp->spp_type = rspp->spp_type;
-			spp->spp_type_ext = rspp->spp_type_ext;
-			spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
-			resp = FC_SPP_RESP_ACK;
-			if (rspp->spp_flags & FC_SPP_RPA_VAL)
-				resp = FC_SPP_RESP_NO_PA;
-			switch (rspp->spp_type) {
-			case 0:	/* common to all FC-4 types */
-				break;
-			case FC_TYPE_FCP:
-				fcp_parm = ntohl(rspp->spp_params);
-				if (fcp_parm & FCP_SPPF_RETRY)
-					rdata->flags |= FC_RP_FLAGS_RETRY;
-				rdata->supported_classes = FC_COS_CLASS3;
-				if (fcp_parm & FCP_SPPF_INIT_FCN)
-					roles |= FC_RPORT_ROLE_FCP_INITIATOR;
-				if (fcp_parm & FCP_SPPF_TARG_FCN)
-					roles |= FC_RPORT_ROLE_FCP_TARGET;
-				rdata->ids.roles = roles;
-
-				spp->spp_params =
-					htonl(lport->service_params);
-				break;
-			default:
-				resp = FC_SPP_RESP_INVL;
-				break;
-			}
-			spp->spp_flags |= resp;
-			len -= plen;
-			rspp = (struct fc_els_spp *)((char *)rspp + plen);
-			spp = (struct fc_els_spp *)((char *)spp + plen);
-		}
+	sp = lport->tt.seq_start_next(sp);
+	WARN_ON(!sp);
+	pp = fc_frame_payload_get(fp, len);
+	WARN_ON(!pp);
+	memset(pp, 0, len);
+	pp->prli.prli_cmd = ELS_LS_ACC;
+	pp->prli.prli_spp_len = plen;
+	pp->prli.prli_len = htons(len);
+	len -= sizeof(struct fc_els_prli);
 
-		/*
-		 * Send LS_ACC.	 If this fails, the originator should retry.
-		 */
-		f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
-		f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
-		ep = fc_seq_exch(sp);
-		fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
-			       FC_TYPE_ELS, f_ctl, 0);
-		lport->tt.seq_send(lport, sp, fp);
+	/* reinitialize remote port roles */
+	rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
 
-		/*
-		 * Get lock and re-check state.
-		 */
-		switch (rdata->rp_state) {
-		case RPORT_ST_PRLI:
-			fc_rport_enter_ready(rdata);
+	/*
+	 * Go through all the service parameter pages and build
+	 * response.  If plen indicates longer SPP than standard,
+	 * use that.  The entire response has been pre-cleared above.
+	 */
+	spp = &pp->spp;
+	while (len >= plen) {
+		spp->spp_type = rspp->spp_type;
+		spp->spp_type_ext = rspp->spp_type_ext;
+		spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
+		resp = FC_SPP_RESP_ACK;
+
+		switch (rspp->spp_type) {
+		case 0:	/* common to all FC-4 types */
 			break;
-		case RPORT_ST_READY:
-		case RPORT_ST_ADISC:
+		case FC_TYPE_FCP:
+			fcp_parm = ntohl(rspp->spp_params);
+			if (fcp_parm & FCP_SPPF_RETRY)
+				rdata->flags |= FC_RP_FLAGS_RETRY;
+			rdata->supported_classes = FC_COS_CLASS3;
+			if (fcp_parm & FCP_SPPF_INIT_FCN)
+				roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+			if (fcp_parm & FCP_SPPF_TARG_FCN)
+				roles |= FC_RPORT_ROLE_FCP_TARGET;
+			rdata->ids.roles = roles;
+
+			spp->spp_params = htonl(lport->service_params);
 			break;
 		default:
+			resp = FC_SPP_RESP_INVL;
 			break;
 		}
+		spp->spp_flags |= resp;
+		len -= plen;
+		rspp = (struct fc_els_spp *)((char *)rspp + plen);
+		spp = (struct fc_els_spp *)((char *)spp + plen);
+	}
+
+	/*
+	 * Send LS_ACC.	 If this fails, the originator should retry.
+	 */
+	f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
+	f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
+	ep = fc_seq_exch(sp);
+	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
+		       FC_TYPE_ELS, f_ctl, 0);
+	lport->tt.seq_send(lport, sp, fp);
+
+	switch (rdata->rp_state) {
+	case RPORT_ST_PRLI:
+		fc_rport_enter_ready(rdata);
+		break;
+	default:
+		break;
 	}
+	goto drop;
+
+reject_len:
+	rjt_data.reason = ELS_RJT_PROT;
+	rjt_data.explan = ELS_EXPL_INV_LEN;
+reject:
+	lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+drop:
 	fc_frame_free(rx_fp);
 }
 

+ 1 - 1
drivers/scsi/libiscsi_tcp.c

@@ -421,7 +421,7 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
 	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
 	struct hash_desc *rx_hash = NULL;
 
-	if (conn->datadgst_en &
+	if (conn->datadgst_en &&
 	    !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
 		rx_hash = tcp_conn->rx_hash;
 

+ 3 - 2
drivers/scsi/libsas/sas_ata.c

@@ -395,12 +395,13 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev,
 void sas_ata_task_abort(struct sas_task *task)
 {
 	struct ata_queued_cmd *qc = task->uldd_task;
-	struct request_queue *q = qc->scsicmd->device->request_queue;
 	struct completion *waiting;
-	unsigned long flags;
 
 	/* Bounce SCSI-initiated commands to the SCSI EH */
 	if (qc->scsicmd) {
+		struct request_queue *q = qc->scsicmd->device->request_queue;
+		unsigned long flags;
+
 		spin_lock_irqsave(q->queue_lock, flags);
 		blk_abort_request(qc->scsicmd->request);
 		spin_unlock_irqrestore(q->queue_lock, flags);

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

@@ -1030,8 +1030,6 @@ int __sas_task_abort(struct sas_task *task)
 void sas_task_abort(struct sas_task *task)
 {
 	struct scsi_cmnd *sc = task->uldd_task;
-	struct request_queue *q = sc->device->request_queue;
-	unsigned long flags;
 
 	/* Escape for libsas internal commands */
 	if (!sc) {
@@ -1043,13 +1041,15 @@ void sas_task_abort(struct sas_task *task)
 
 	if (dev_is_sata(task->dev)) {
 		sas_ata_task_abort(task);
-		return;
-	}
+	} else {
+		struct request_queue *q = sc->device->request_queue;
+		unsigned long flags;
 
-	spin_lock_irqsave(q->queue_lock, flags);
-	blk_abort_request(sc->request);
-	spin_unlock_irqrestore(q->queue_lock, flags);
-	scsi_schedule_eh(sc->device->host);
+		spin_lock_irqsave(q->queue_lock, flags);
+		blk_abort_request(sc->request);
+		spin_unlock_irqrestore(q->queue_lock, flags);
+		scsi_schedule_eh(sc->device->host);
+	}
 }
 
 int sas_slave_alloc(struct scsi_device *scsi_dev)

+ 4 - 0
drivers/scsi/lpfc/lpfc.h

@@ -310,7 +310,9 @@ struct lpfc_vport {
 #define FC_NLP_MORE             0x40	 /* More node to process in node tbl */
 #define FC_OFFLINE_MODE         0x80	 /* Interface is offline for diag */
 #define FC_FABRIC               0x100	 /* We are fabric attached */
+#define FC_VPORT_LOGO_RCVD      0x200    /* LOGO received on vport */
 #define FC_RSCN_DISCOVERY       0x400	 /* Auth all devices after RSCN */
+#define FC_LOGO_RCVD_DID_CHNG   0x800    /* FDISC on phys port detect DID chng*/
 #define FC_SCSI_SCAN_TMO        0x4000	 /* scsi scan timer running */
 #define FC_ABORT_DISCOVERY      0x8000	 /* we want to abort discovery */
 #define FC_NDISC_ACTIVE         0x10000	 /* NPort discovery active */
@@ -554,6 +556,7 @@ struct lpfc_hba {
 	struct lpfc_dmabuf slim2p;
 
 	MAILBOX_t *mbox;
+	uint32_t *mbox_ext;
 	uint32_t *inb_ha_copy;
 	uint32_t *inb_counter;
 	uint32_t inb_last_counter;
@@ -622,6 +625,7 @@ struct lpfc_hba {
 	uint32_t cfg_enable_hba_reset;
 	uint32_t cfg_enable_hba_heartbeat;
 	uint32_t cfg_enable_bg;
+	uint32_t cfg_hostmem_hgp;
 	uint32_t cfg_log_verbose;
 	uint32_t cfg_aer_support;
 	uint32_t cfg_suppress_link_up;

+ 13 - 7
drivers/scsi/lpfc/lpfc_attr.c

@@ -869,6 +869,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
 	LPFC_MBOXQ_t *pmboxq;
 	MAILBOX_t *pmb;
 	int rc = 0;
+	uint32_t max_vpi;
 
 	/*
 	 * prevent udev from issuing mailbox commands until the port is
@@ -916,11 +917,17 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
 		if (axri)
 			*axri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config) -
 					phba->sli4_hba.max_cfg_param.xri_used;
+
+		/* Account for differences with SLI-3.  Get vpi count from
+		 * mailbox data and subtract one for max vpi value.
+		 */
+		max_vpi = (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) > 0) ?
+			(bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - 1) : 0;
+
 		if (mvpi)
-			*mvpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config);
+			*mvpi = max_vpi;
 		if (avpi)
-			*avpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) -
-					phba->sli4_hba.max_cfg_param.vpi_used;
+			*avpi = max_vpi - phba->sli4_hba.max_cfg_param.vpi_used;
 	} else {
 		if (mrpi)
 			*mrpi = pmb->un.varRdConfig.max_rpi;
@@ -1925,13 +1932,12 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
 		 " 2 - select SLI-2 even on SLI-3 capable HBAs,"
 		 " 3 - select SLI-3");
 
-int lpfc_enable_npiv = 0;
+int lpfc_enable_npiv = 1;
 module_param(lpfc_enable_npiv, int, 0);
 MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");
 lpfc_param_show(enable_npiv);
-lpfc_param_init(enable_npiv, 0, 0, 1);
-static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
-			 lpfc_enable_npiv_show, NULL);
+lpfc_param_init(enable_npiv, 1, 0, 1);
+static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
 
 /*
 # lpfc_suppress_link_up:  Bring link up at initialization

+ 421 - 77
drivers/scsi/lpfc/lpfc_bsg.c

@@ -79,6 +79,12 @@ struct lpfc_bsg_iocb {
 struct lpfc_bsg_mbox {
 	LPFC_MBOXQ_t *pmboxq;
 	MAILBOX_t *mb;
+	struct lpfc_dmabuf *rxbmp; /* for BIU diags */
+	struct lpfc_dmabufext *dmp; /* for BIU diags */
+	uint8_t *ext; /* extended mailbox data */
+	uint32_t mbOffset; /* from app */
+	uint32_t inExtWLen; /* from app */
+	uint32_t outExtWLen; /* from app */
 
 	/* job waiting for this mbox command to finish */
 	struct fc_bsg_job *set_job;
@@ -1708,21 +1714,26 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
 	dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
 	if (dmabuf) {
 		dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys);
-		INIT_LIST_HEAD(&dmabuf->list);
-		bpl = (struct ulp_bde64 *) dmabuf->virt;
-		memset(bpl, 0, sizeof(*bpl));
-		ctreq = (struct lpfc_sli_ct_request *)(bpl + 1);
-		bpl->addrHigh =
-			le32_to_cpu(putPaddrHigh(dmabuf->phys + sizeof(*bpl)));
-		bpl->addrLow =
-			le32_to_cpu(putPaddrLow(dmabuf->phys + sizeof(*bpl)));
-		bpl->tus.f.bdeFlags = 0;
-		bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ;
-		bpl->tus.w = le32_to_cpu(bpl->tus.w);
+		if (dmabuf->virt) {
+			INIT_LIST_HEAD(&dmabuf->list);
+			bpl = (struct ulp_bde64 *) dmabuf->virt;
+			memset(bpl, 0, sizeof(*bpl));
+			ctreq = (struct lpfc_sli_ct_request *)(bpl + 1);
+			bpl->addrHigh =
+				le32_to_cpu(putPaddrHigh(dmabuf->phys +
+					sizeof(*bpl)));
+			bpl->addrLow =
+				le32_to_cpu(putPaddrLow(dmabuf->phys +
+					sizeof(*bpl)));
+			bpl->tus.f.bdeFlags = 0;
+			bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ;
+			bpl->tus.w = le32_to_cpu(bpl->tus.w);
+		}
 	}
 
 	if (cmdiocbq == NULL || rspiocbq == NULL ||
-	    dmabuf == NULL || bpl == NULL || ctreq == NULL) {
+	    dmabuf == NULL || bpl == NULL || ctreq == NULL ||
+		dmabuf->virt == NULL) {
 		ret_val = ENOMEM;
 		goto err_get_xri_exit;
 	}
@@ -1918,9 +1929,11 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,
 	rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
 	if (rxbmp != NULL) {
 		rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
-		INIT_LIST_HEAD(&rxbmp->list);
-		rxbpl = (struct ulp_bde64 *) rxbmp->virt;
-		rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0);
+		if (rxbmp->virt) {
+			INIT_LIST_HEAD(&rxbmp->list);
+			rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+			rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0);
+		}
 	}
 
 	if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) {
@@ -2174,14 +2187,16 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job)
 
 	if (txbmp) {
 		txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys);
-		INIT_LIST_HEAD(&txbmp->list);
-		txbpl = (struct ulp_bde64 *) txbmp->virt;
-		if (txbpl)
+		if (txbmp->virt) {
+			INIT_LIST_HEAD(&txbmp->list);
+			txbpl = (struct ulp_bde64 *) txbmp->virt;
 			txbuffer = diag_cmd_data_alloc(phba,
 							txbpl, full_size, 0);
+		}
 	}
 
-	if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer) {
+	if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer ||
+		!txbmp->virt) {
 		rc = -ENOMEM;
 		goto err_loopback_test_exit;
 	}
@@ -2377,35 +2392,90 @@ void
 lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
 {
 	struct bsg_job_data *dd_data;
-	MAILBOX_t *pmb;
-	MAILBOX_t *mb;
 	struct fc_bsg_job *job;
 	uint32_t size;
 	unsigned long flags;
+	uint8_t *to;
+	uint8_t *from;
 
 	spin_lock_irqsave(&phba->ct_ev_lock, flags);
 	dd_data = pmboxq->context1;
+	/* job already timed out? */
 	if (!dd_data) {
 		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
 		return;
 	}
 
-	pmb = &dd_data->context_un.mbox.pmboxq->u.mb;
-	mb = dd_data->context_un.mbox.mb;
+	/* build the outgoing buffer to do an sg copy
+	 * the format is the response mailbox followed by any extended
+	 * mailbox data
+	 */
+	from = (uint8_t *)&pmboxq->u.mb;
+	to = (uint8_t *)dd_data->context_un.mbox.mb;
+	memcpy(to, from, sizeof(MAILBOX_t));
+	if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS) {
+		/* copy the extended data if any, count is in words */
+		if (dd_data->context_un.mbox.outExtWLen) {
+			from = (uint8_t *)dd_data->context_un.mbox.ext;
+			to += sizeof(MAILBOX_t);
+			size = dd_data->context_un.mbox.outExtWLen *
+					sizeof(uint32_t);
+			memcpy(to, from, size);
+		} else if (pmboxq->u.mb.mbxCommand == MBX_RUN_BIU_DIAG64) {
+			from = (uint8_t *)dd_data->context_un.mbox.
+						dmp->dma.virt;
+			to += sizeof(MAILBOX_t);
+			size = dd_data->context_un.mbox.dmp->size;
+			memcpy(to, from, size);
+		} else if ((phba->sli_rev == LPFC_SLI_REV4) &&
+			(pmboxq->u.mb.mbxCommand == MBX_DUMP_MEMORY)) {
+			from = (uint8_t *)dd_data->context_un.mbox.dmp->dma.
+						virt;
+			to += sizeof(MAILBOX_t);
+			size = pmboxq->u.mb.un.varWords[5];
+			memcpy(to, from, size);
+		} else if (pmboxq->u.mb.mbxCommand == MBX_READ_EVENT_LOG) {
+			from = (uint8_t *)dd_data->context_un.
+						mbox.dmp->dma.virt;
+			to += sizeof(MAILBOX_t);
+			size = dd_data->context_un.mbox.dmp->size;
+			memcpy(to, from, size);
+		}
+	}
+
+	from = (uint8_t *)dd_data->context_un.mbox.mb;
 	job = dd_data->context_un.mbox.set_job;
-	memcpy(mb, pmb, sizeof(*pmb));
-	size = job->request_payload.payload_len;
+	size = job->reply_payload.payload_len;
 	job->reply->reply_payload_rcv_len =
 		sg_copy_from_buffer(job->reply_payload.sg_list,
 				job->reply_payload.sg_cnt,
-				mb, size);
+				from, size);
 	job->reply->result = 0;
+
 	dd_data->context_un.mbox.set_job = NULL;
 	job->dd_data = NULL;
 	job->job_done(job);
+	/* need to hold the lock until we call job done to hold off
+	 * the timeout handler returning to the midlayer while
+	 * we are stillprocessing the job
+	 */
 	spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+	kfree(dd_data->context_un.mbox.mb);
 	mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool);
-	kfree(mb);
+	kfree(dd_data->context_un.mbox.ext);
+	if (dd_data->context_un.mbox.dmp) {
+		dma_free_coherent(&phba->pcidev->dev,
+			dd_data->context_un.mbox.dmp->size,
+			dd_data->context_un.mbox.dmp->dma.virt,
+			dd_data->context_un.mbox.dmp->dma.phys);
+		kfree(dd_data->context_un.mbox.dmp);
+	}
+	if (dd_data->context_un.mbox.rxbmp) {
+		lpfc_mbuf_free(phba, dd_data->context_un.mbox.rxbmp->virt,
+			dd_data->context_un.mbox.rxbmp->phys);
+		kfree(dd_data->context_un.mbox.rxbmp);
+	}
 	kfree(dd_data);
 	return;
 }
@@ -2464,10 +2534,12 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
 	case MBX_SET_DEBUG:
 	case MBX_WRITE_WWN:
 	case MBX_SLI4_CONFIG:
+	case MBX_READ_EVENT_LOG:
 	case MBX_READ_EVENT_LOG_STATUS:
 	case MBX_WRITE_EVENT_LOG:
 	case MBX_PORT_CAPABILITIES:
 	case MBX_PORT_IOV_CONTROL:
+	case MBX_RUN_BIU_DIAG64:
 		break;
 	case MBX_SET_VARIABLE:
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
@@ -2482,8 +2554,6 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba,
 			phba->fc_topology = TOPOLOGY_PT_PT;
 		}
 		break;
-	case MBX_RUN_BIU_DIAG64:
-	case MBX_READ_EVENT_LOG:
 	case MBX_READ_SPARM64:
 	case MBX_READ_LA:
 	case MBX_READ_LA64:
@@ -2518,97 +2588,365 @@ static uint32_t
 lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
 	struct lpfc_vport *vport)
 {
-	LPFC_MBOXQ_t *pmboxq;
-	MAILBOX_t *pmb;
-	MAILBOX_t *mb;
-	struct bsg_job_data *dd_data;
+	LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */
+	MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */
+	/* a 4k buffer to hold the mb and extended data from/to the bsg */
+	MAILBOX_t *mb = NULL;
+	struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */
 	uint32_t size;
+	struct lpfc_dmabuf *rxbmp = NULL; /* for biu diag */
+	struct lpfc_dmabufext *dmp = NULL; /* for biu diag */
+	struct ulp_bde64 *rxbpl = NULL;
+	struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *)
+		job->request->rqst_data.h_vendor.vendor_cmd;
+	uint8_t *ext = NULL;
 	int rc = 0;
+	uint8_t *from;
+
+	/* in case no data is transferred */
+	job->reply->reply_payload_rcv_len = 0;
+
+	/* check if requested extended data lengths are valid */
+	if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) ||
+		(mbox_req->outExtWLen > MAILBOX_EXT_SIZE)) {
+		rc = -ERANGE;
+		goto job_done;
+	}
 
 	/* allocate our bsg tracking structure */
 	dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
 	if (!dd_data) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
 				"2727 Failed allocation of dd_data\n");
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto job_done;
 	}
 
-	mb = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	mb = kzalloc(BSG_MBOX_SIZE, GFP_KERNEL);
 	if (!mb) {
-		kfree(dd_data);
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto job_done;
 	}
 
 	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!pmboxq) {
-		kfree(dd_data);
-		kfree(mb);
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto job_done;
 	}
+	memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
 
 	size = job->request_payload.payload_len;
-	job->reply->reply_payload_rcv_len =
-		sg_copy_to_buffer(job->request_payload.sg_list,
-				job->request_payload.sg_cnt,
-				mb, size);
+	sg_copy_to_buffer(job->request_payload.sg_list,
+			job->request_payload.sg_cnt,
+			mb, size);
 
 	rc = lpfc_bsg_check_cmd_access(phba, mb, vport);
-	if (rc != 0) {
-		kfree(dd_data);
-		kfree(mb);
-		mempool_free(pmboxq, phba->mbox_mem_pool);
-		return rc; /* must be negative */
-	}
+	if (rc != 0)
+		goto job_done; /* must be negative */
 
-	memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
 	pmb = &pmboxq->u.mb;
 	memcpy(pmb, mb, sizeof(*pmb));
 	pmb->mbxOwner = OWN_HOST;
-	pmboxq->context1 = NULL;
 	pmboxq->vport = vport;
 
-	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-	    (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
-		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
-		if (rc != MBX_SUCCESS) {
-			if (rc != MBX_TIMEOUT) {
-				kfree(dd_data);
-				kfree(mb);
-				mempool_free(pmboxq, phba->mbox_mem_pool);
+	/* If HBA encountered an error attention, allow only DUMP
+	 * or RESTART mailbox commands until the HBA is restarted.
+	 */
+	if (phba->pport->stopped &&
+	    pmb->mbxCommand != MBX_DUMP_MEMORY &&
+	    pmb->mbxCommand != MBX_RESTART &&
+	    pmb->mbxCommand != MBX_WRITE_VPARMS &&
+	    pmb->mbxCommand != MBX_WRITE_WWN)
+		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+				"2797 mbox: Issued mailbox cmd "
+				"0x%x while in stopped state.\n",
+				pmb->mbxCommand);
+
+	/* Don't allow mailbox commands to be sent when blocked
+	 * or when in the middle of discovery
+	 */
+	if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
+		rc = -EAGAIN;
+		goto job_done;
+	}
+
+	/* extended mailbox commands will need an extended buffer */
+	if (mbox_req->inExtWLen || mbox_req->outExtWLen) {
+		ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL);
+		if (!ext) {
+			rc = -ENOMEM;
+			goto job_done;
+		}
+
+		/* any data for the device? */
+		if (mbox_req->inExtWLen) {
+			from = (uint8_t *)mb;
+			from += sizeof(MAILBOX_t);
+			memcpy((uint8_t *)ext, from,
+				mbox_req->inExtWLen * sizeof(uint32_t));
+		}
+
+		pmboxq->context2 = ext;
+		pmboxq->in_ext_byte_len =
+			mbox_req->inExtWLen *
+			sizeof(uint32_t);
+		pmboxq->out_ext_byte_len =
+			mbox_req->outExtWLen *
+			sizeof(uint32_t);
+		pmboxq->mbox_offset_word =
+			mbox_req->mbOffset;
+		pmboxq->context2 = ext;
+		pmboxq->in_ext_byte_len =
+			mbox_req->inExtWLen * sizeof(uint32_t);
+		pmboxq->out_ext_byte_len =
+			mbox_req->outExtWLen * sizeof(uint32_t);
+		pmboxq->mbox_offset_word = mbox_req->mbOffset;
+	}
+
+	/* biu diag will need a kernel buffer to transfer the data
+	 * allocate our own buffer and setup the mailbox command to
+	 * use ours
+	 */
+	if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) {
+		uint32_t transmit_length = pmb->un.varWords[1];
+		uint32_t receive_length = pmb->un.varWords[4];
+		/* transmit length cannot be greater than receive length or
+		 * mailbox extension size
+		 */
+		if ((transmit_length > receive_length) ||
+			(transmit_length > MAILBOX_EXT_SIZE)) {
+			rc = -ERANGE;
+			goto job_done;
+		}
+
+		rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+		if (!rxbmp) {
+			rc = -ENOMEM;
+			goto job_done;
+		}
+
+		rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
+		if (!rxbmp->virt) {
+			rc = -ENOMEM;
+			goto job_done;
+		}
+
+		INIT_LIST_HEAD(&rxbmp->list);
+		rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+		dmp = diag_cmd_data_alloc(phba, rxbpl, transmit_length, 0);
+		if (!dmp) {
+			rc = -ENOMEM;
+			goto job_done;
+		}
+
+		INIT_LIST_HEAD(&dmp->dma.list);
+		pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh =
+			putPaddrHigh(dmp->dma.phys);
+		pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow =
+			putPaddrLow(dmp->dma.phys);
+
+		pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh =
+			putPaddrHigh(dmp->dma.phys +
+				pmb->un.varBIUdiag.un.s2.
+					xmit_bde64.tus.f.bdeSize);
+		pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow =
+			putPaddrLow(dmp->dma.phys +
+				pmb->un.varBIUdiag.un.s2.
+					xmit_bde64.tus.f.bdeSize);
+
+		/* copy the transmit data found in the mailbox extension area */
+		from = (uint8_t *)mb;
+		from += sizeof(MAILBOX_t);
+		memcpy((uint8_t *)dmp->dma.virt, from, transmit_length);
+	} else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) {
+		struct READ_EVENT_LOG_VAR *rdEventLog =
+			&pmb->un.varRdEventLog ;
+		uint32_t receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize;
+		uint32_t mode =	 bf_get(lpfc_event_log, rdEventLog);
+
+		/* receive length cannot be greater than mailbox
+		 * extension size
+		 */
+		if (receive_length > MAILBOX_EXT_SIZE) {
+			rc = -ERANGE;
+			goto job_done;
+		}
+
+		/* mode zero uses a bde like biu diags command */
+		if (mode == 0) {
+
+			/* rebuild the command for sli4 using our own buffers
+			* like we do for biu diags
+			*/
+
+			rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+			if (!rxbmp) {
+				rc = -ENOMEM;
+				goto job_done;
 			}
-			return  (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
+
+			rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
+			rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+			if (rxbpl) {
+				INIT_LIST_HEAD(&rxbmp->list);
+				dmp = diag_cmd_data_alloc(phba, rxbpl,
+					receive_length, 0);
+			}
+
+			if (!dmp) {
+				rc = -ENOMEM;
+				goto job_done;
+			}
+
+			INIT_LIST_HEAD(&dmp->dma.list);
+			pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys);
+			pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys);
 		}
+	} else if (phba->sli_rev == LPFC_SLI_REV4) {
+		if (pmb->mbxCommand == MBX_DUMP_MEMORY) {
+			/* rebuild the command for sli4 using our own buffers
+			* like we do for biu diags
+			*/
+			uint32_t receive_length = pmb->un.varWords[2];
+			/* receive length cannot be greater than mailbox
+			 * extension size
+			 */
+			if ((receive_length == 0) ||
+				(receive_length > MAILBOX_EXT_SIZE)) {
+				rc = -ERANGE;
+				goto job_done;
+			}
 
-		memcpy(mb, pmb, sizeof(*pmb));
-		job->reply->reply_payload_rcv_len =
-			sg_copy_from_buffer(job->reply_payload.sg_list,
-					job->reply_payload.sg_cnt,
-					mb, size);
-		kfree(dd_data);
-		kfree(mb);
-		mempool_free(pmboxq, phba->mbox_mem_pool);
-		/* not waiting mbox already done */
-		return 0;
+			rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+			if (!rxbmp) {
+				rc = -ENOMEM;
+				goto job_done;
+			}
+
+			rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
+			if (!rxbmp->virt) {
+				rc = -ENOMEM;
+				goto job_done;
+			}
+
+			INIT_LIST_HEAD(&rxbmp->list);
+			rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+			dmp = diag_cmd_data_alloc(phba, rxbpl, receive_length,
+						0);
+			if (!dmp) {
+				rc = -ENOMEM;
+				goto job_done;
+			}
+
+			INIT_LIST_HEAD(&dmp->dma.list);
+			pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys);
+			pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys);
+		} else if ((pmb->mbxCommand == MBX_UPDATE_CFG) &&
+			pmb->un.varUpdateCfg.co) {
+			struct ulp_bde64 *bde =
+				(struct ulp_bde64 *)&pmb->un.varWords[4];
+
+			/* bde size cannot be greater than mailbox ext size */
+			if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) {
+				rc = -ERANGE;
+				goto job_done;
+			}
+
+			rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+			if (!rxbmp) {
+				rc = -ENOMEM;
+				goto job_done;
+			}
+
+			rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys);
+			if (!rxbmp->virt) {
+				rc = -ENOMEM;
+				goto job_done;
+			}
+
+			INIT_LIST_HEAD(&rxbmp->list);
+			rxbpl = (struct ulp_bde64 *) rxbmp->virt;
+			dmp = diag_cmd_data_alloc(phba, rxbpl,
+					bde->tus.f.bdeSize, 0);
+			if (!dmp) {
+				rc = -ENOMEM;
+				goto job_done;
+			}
+
+			INIT_LIST_HEAD(&dmp->dma.list);
+			bde->addrHigh = putPaddrHigh(dmp->dma.phys);
+			bde->addrLow = putPaddrLow(dmp->dma.phys);
+
+			/* copy the transmit data found in the mailbox
+			 * extension area
+			 */
+			from = (uint8_t *)mb;
+			from += sizeof(MAILBOX_t);
+			memcpy((uint8_t *)dmp->dma.virt, from,
+				bde->tus.f.bdeSize);
+		}
 	}
 
+	dd_data->context_un.mbox.rxbmp = rxbmp;
+	dd_data->context_un.mbox.dmp = dmp;
+
 	/* setup wake call as IOCB callback */
 	pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait;
+
 	/* setup context field to pass wait_queue pointer to wake function */
 	pmboxq->context1 = dd_data;
 	dd_data->type = TYPE_MBOX;
 	dd_data->context_un.mbox.pmboxq = pmboxq;
 	dd_data->context_un.mbox.mb = mb;
 	dd_data->context_un.mbox.set_job = job;
+	dd_data->context_un.mbox.ext = ext;
+	dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset;
+	dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen;
+	dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen;
 	job->dd_data = dd_data;
+
+	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+	    (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) {
+		rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+		if (rc != MBX_SUCCESS) {
+			rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
+			goto job_done;
+		}
+
+		/* job finished, copy the data */
+		memcpy(mb, pmb, sizeof(*pmb));
+		job->reply->reply_payload_rcv_len =
+			sg_copy_from_buffer(job->reply_payload.sg_list,
+					job->reply_payload.sg_cnt,
+					mb, size);
+		/* not waiting mbox already done */
+		rc = 0;
+		goto job_done;
+	}
+
 	rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
-	if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
-		kfree(dd_data);
-		kfree(mb);
+	if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY))
+		return 1; /* job started */
+
+job_done:
+	/* common exit for error or job completed inline */
+	kfree(mb);
+	if (pmboxq)
 		mempool_free(pmboxq, phba->mbox_mem_pool);
-		return -EIO;
+	kfree(ext);
+	if (dmp) {
+		dma_free_coherent(&phba->pcidev->dev,
+			dmp->size, dmp->dma.virt,
+				dmp->dma.phys);
+		kfree(dmp);
 	}
+	if (rxbmp) {
+		lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys);
+		kfree(rxbmp);
+	}
+	kfree(dd_data);
 
-	return 1;
+	return rc;
 }
 
 /**
@@ -2633,7 +2971,12 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job)
 		goto job_error;
 	}
 
-	if (job->request_payload.payload_len != PAGE_SIZE) {
+	if (job->request_payload.payload_len != BSG_MBOX_SIZE) {
+		rc = -EINVAL;
+		goto job_error;
+	}
+
+	if (job->reply_payload.payload_len != BSG_MBOX_SIZE) {
 		rc = -EINVAL;
 		goto job_error;
 	}
@@ -3094,6 +3437,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
 		job->dd_data = NULL;
 		job->reply->reply_payload_rcv_len = 0;
 		job->reply->result = -EAGAIN;
+		/* the mbox completion handler can now be run */
 		spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
 		job->job_done(job);
 		break;

+ 2 - 1
drivers/scsi/lpfc/lpfc_bsg.h

@@ -91,11 +91,12 @@ struct get_mgmt_rev_reply {
 	struct MgmtRevInfo info;
 };
 
+#define BSG_MBOX_SIZE 4096 /* mailbox command plus extended data */
 struct dfc_mbox_req {
 	uint32_t command;
+	uint32_t mbOffset;
 	uint32_t inExtWLen;
 	uint32_t outExtWLen;
-	uint8_t mbOffset;
 };
 
 /* Used for menlo command or menlo data. The xri is only used for menlo data */

+ 1 - 0
drivers/scsi/lpfc/lpfc_crtn.h

@@ -65,6 +65,7 @@ void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
 void lpfc_retry_pport_discovery(struct lpfc_hba *);
+void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
 
 void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);

+ 1 - 0
drivers/scsi/lpfc/lpfc_disc.h

@@ -38,6 +38,7 @@ enum lpfc_work_type {
 	LPFC_EVT_ELS_RETRY,
 	LPFC_EVT_DEV_LOSS,
 	LPFC_EVT_FASTPATH_MGMT_EVT,
+	LPFC_EVT_RESET_HBA,
 };
 
 /* structure used to queue event to the discovery tasklet */

+ 17 - 7
drivers/scsi/lpfc/lpfc_els.c

@@ -584,6 +584,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			spin_unlock_irq(shost->host_lock);
 			lpfc_unreg_rpi(vport, np);
 		}
+		lpfc_cleanup_pending_mbox(vport);
 		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
 			lpfc_mbx_unreg_vpi(vport);
 			spin_lock_irq(shost->host_lock);
@@ -864,6 +865,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	}
 	spin_lock_irq(shost->host_lock);
 	vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
+	vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;
 	spin_unlock_irq(shost->host_lock);
 
 	/*
@@ -893,11 +895,14 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
 		if (!rc) {
 			/* Mark the FCF discovery process done */
-			lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | LOG_ELS,
-					 "2769 FLOGI successful on FCF record: "
-					 "current_fcf_index:x%x, terminate FCF "
-					 "round robin failover process\n",
-					 phba->fcf.current_rec.fcf_indx);
+			if (phba->hba_flag & HBA_FIP_SUPPORT)
+				lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP |
+						LOG_ELS,
+						"2769 FLOGI successful on FCF "
+						"record: current_fcf_index:"
+						"x%x, terminate FCF round "
+						"robin failover process\n",
+						phba->fcf.current_rec.fcf_indx);
 			spin_lock_irq(&phba->hbalock);
 			phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
 			spin_unlock_irq(&phba->hbalock);
@@ -5366,7 +5371,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba,
 			sizeof(struct lpfc_name));
 		pcmd = (uint32_t *) (((struct lpfc_dmabuf *)
 			cmdiocbp->context2)->virt);
-		lsrjt_event.command = *pcmd;
+		lsrjt_event.command = (pcmd != NULL) ? *pcmd : 0;
 		stat.un.lsRjtError = be32_to_cpu(rspiocbp->iocb.un.ulpWord[4]);
 		lsrjt_event.reason_code = stat.un.b.lsRjtRsnCode;
 		lsrjt_event.explanation = stat.un.b.lsRjtRsnCodeExp;
@@ -6050,7 +6055,8 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
 			spin_unlock_irq(shost->host_lock);
-			if (vport->port_type == LPFC_PHYSICAL_PORT)
+			if (vport->port_type == LPFC_PHYSICAL_PORT
+				&& !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
 				lpfc_initial_flogi(vport);
 			else
 				lpfc_initial_fdisc(vport);
@@ -6286,6 +6292,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	}
 	spin_lock_irq(shost->host_lock);
 	vport->fc_flag &= ~FC_VPORT_CVL_RCVD;
+	vport->fc_flag &= ~FC_VPORT_LOGO_RCVD;
 	vport->fc_flag |= FC_FABRIC;
 	if (vport->phba->fc_topology == TOPOLOGY_LOOP)
 		vport->fc_flag |=  FC_PUBLIC_LOOP;
@@ -6310,11 +6317,14 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			spin_unlock_irq(shost->host_lock);
 			lpfc_unreg_rpi(vport, np);
 		}
+		lpfc_cleanup_pending_mbox(vport);
 		lpfc_mbx_unreg_vpi(vport);
 		spin_lock_irq(shost->host_lock);
 		vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
 		if (phba->sli_rev == LPFC_SLI_REV4)
 			vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
+		else
+			vport->fc_flag |= FC_LOGO_RCVD_DID_CHNG;
 		spin_unlock_irq(shost->host_lock);
 	}
 

+ 73 - 6
drivers/scsi/lpfc/lpfc_hbadisc.c

@@ -475,6 +475,10 @@ lpfc_work_list_done(struct lpfc_hba *phba)
 			lpfc_send_fastpath_evt(phba, evtp);
 			free_evt = 0;
 			break;
+		case LPFC_EVT_RESET_HBA:
+			if (!(phba->pport->load_flag & FC_UNLOADING))
+				lpfc_reset_hba(phba);
+			break;
 		}
 		if (free_evt)
 			kfree(evtp);
@@ -1531,7 +1535,37 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
 }
 
 /**
- * lpfc_sli4_fcf_rec_mbox_parse - parse non-embedded fcf record mailbox command
+ * lpfc_sli4_new_fcf_random_select - Randomly select an eligible new fcf record
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_cnt: number of eligible fcf record seen so far.
+ *
+ * This function makes an running random selection decision on FCF record to
+ * use through a sequence of @fcf_cnt eligible FCF records with equal
+ * probability. To perform integer manunipulation of random numbers with
+ * size unit32_t, the lower 16 bits of the 32-bit random number returned
+ * from random32() are taken as the random random number generated.
+ *
+ * Returns true when outcome is for the newly read FCF record should be
+ * chosen; otherwise, return false when outcome is for keeping the previously
+ * chosen FCF record.
+ **/
+static bool
+lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt)
+{
+	uint32_t rand_num;
+
+	/* Get 16-bit uniform random number */
+	rand_num = (0xFFFF & random32());
+
+	/* Decision with probability 1/fcf_cnt */
+	if ((fcf_cnt * rand_num) < 0xFFFF)
+		return true;
+	else
+		return false;
+}
+
+/**
+ * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox.
  * @phba: pointer to lpfc hba data structure.
  * @mboxq: pointer to mailbox object.
  * @next_fcf_index: pointer to holder of next fcf index.
@@ -1592,7 +1626,9 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
 	new_fcf_record = (struct fcf_record *)(virt_addr +
 			  sizeof(struct lpfc_mbx_read_fcf_tbl));
 	lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record,
-			      sizeof(struct fcf_record));
+				offsetof(struct fcf_record, vlan_bitmap));
+	new_fcf_record->word137 = le32_to_cpu(new_fcf_record->word137);
+	new_fcf_record->word138 = le32_to_cpu(new_fcf_record->word138);
 
 	return new_fcf_record;
 }
@@ -1679,6 +1715,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 	uint16_t fcf_index, next_fcf_index;
 	struct lpfc_fcf_rec *fcf_rec = NULL;
 	uint16_t vlan_id;
+	uint32_t seed;
+	bool select_new_fcf;
 	int rc;
 
 	/* If there is pending FCoE event restart FCF table scan */
@@ -1809,9 +1847,21 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 		 * than the driver FCF record, use the new record.
 		 */
 		if (new_fcf_record->fip_priority < fcf_rec->priority) {
-			/* Choose this FCF record */
+			/* Choose the new FCF record with lower priority */
 			__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
 					addr_mode, vlan_id, 0);
+			/* Reset running random FCF selection count */
+			phba->fcf.eligible_fcf_cnt = 1;
+		} else if (new_fcf_record->fip_priority == fcf_rec->priority) {
+			/* Update running random FCF selection count */
+			phba->fcf.eligible_fcf_cnt++;
+			select_new_fcf = lpfc_sli4_new_fcf_random_select(phba,
+						phba->fcf.eligible_fcf_cnt);
+			if (select_new_fcf)
+				/* Choose the new FCF by random selection */
+				__lpfc_update_fcf_record(phba, fcf_rec,
+							 new_fcf_record,
+							 addr_mode, vlan_id, 0);
 		}
 		spin_unlock_irq(&phba->hbalock);
 		goto read_next_fcf;
@@ -1825,6 +1875,11 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 					 addr_mode, vlan_id, (boot_flag ?
 					 BOOT_ENABLE : 0));
 		phba->fcf.fcf_flag |= FCF_AVAILABLE;
+		/* Setup initial running random FCF selection count */
+		phba->fcf.eligible_fcf_cnt = 1;
+		/* Seeding the random number generator for random selection */
+		seed = (uint32_t)(0xFFFFFFFF & jiffies);
+		srandom32(seed);
 	}
 	spin_unlock_irq(&phba->hbalock);
 	goto read_next_fcf;
@@ -2686,11 +2741,18 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	switch (mb->mbxStatus) {
 	case 0x0011:
 	case 0x0020:
-	case 0x9700:
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
 				 "0911 cmpl_unreg_vpi, mb status = 0x%x\n",
 				 mb->mbxStatus);
 		break;
+	/* If VPI is busy, reset the HBA */
+	case 0x9700:
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
+			"2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n",
+			vport->vpi, mb->mbxStatus);
+		if (!(phba->pport->load_flag & FC_UNLOADING))
+			lpfc_workq_post_event(phba, NULL, NULL,
+				LPFC_EVT_RESET_HBA);
 	}
 	spin_lock_irq(shost->host_lock);
 	vport->vpi_state &= ~LPFC_VPI_REGISTERED;
@@ -2965,7 +3027,12 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 
 	if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
-		lpfc_start_fdiscs(phba);
+		/* when physical port receive logo donot start
+		 * vport discovery */
+		if (!(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
+			lpfc_start_fdiscs(phba);
+		else
+			vport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG ;
 		lpfc_do_scr_ns_plogi(phba, vport);
 	}
 
@@ -3177,7 +3244,6 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
 	if (new_state == NLP_STE_UNMAPPED_NODE) {
-		ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
 		ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
 		ndlp->nlp_type |= NLP_FC_NODE;
 	}
@@ -4935,6 +5001,7 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba)
 			ndlp = lpfc_findnode_did(vports[i], Fabric_DID);
 			if (ndlp)
 				lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
+			lpfc_cleanup_pending_mbox(vports[i]);
 			lpfc_mbx_unreg_vpi(vports[i]);
 			shost = lpfc_shost_from_vport(vports[i]);
 			spin_lock_irq(shost->host_lock);

+ 100 - 90
drivers/scsi/lpfc/lpfc_hw.h

@@ -1565,95 +1565,83 @@ enum lpfc_protgrp_type {
 };
 
 /* PDE Descriptors */
-#define LPFC_PDE1_DESCRIPTOR		0x81
-#define LPFC_PDE2_DESCRIPTOR		0x82
-#define LPFC_PDE3_DESCRIPTOR		0x83
-
-/* BlockGuard Profiles */
-enum lpfc_bg_prof_codes {
-	LPFC_PROF_INVALID,
-	LPFC_PROF_A1	= 128,	/* Full Protection			      */
-	LPFC_PROF_A2,		/* Disabled Protection Checks:A2~A4           */
-	LPFC_PROF_A3,
-	LPFC_PROF_A4,
-	LPFC_PROF_B1,		/* Embedded DIFs: B1~B3	                      */
-	LPFC_PROF_B2,
-	LPFC_PROF_B3,
-	LPFC_PROF_C1,		/* Separate DIFs: C1~C3                       */
-	LPFC_PROF_C2,
-	LPFC_PROF_C3,
-	LPFC_PROF_D1,		/* Full Protection                            */
-	LPFC_PROF_D2,		/* Partial Protection & Check Disabling       */
-	LPFC_PROF_D3,
-	LPFC_PROF_E1,		/* E1~E4:out - check-only, in - update apptag */
-	LPFC_PROF_E2,
-	LPFC_PROF_E3,
-	LPFC_PROF_E4,
-	LPFC_PROF_F1,		/* Full Translation - F1 Prot Descriptor      */
-				/* F1 Translation BDE                         */
-	LPFC_PROF_ANT1,		/* TCP checksum, DIF inline with data buffers */
-	LPFC_PROF_AST1,		/* TCP checksum, DIF split from data buffer   */
-	LPFC_PROF_ANT2,
-	LPFC_PROF_AST2
+#define LPFC_PDE5_DESCRIPTOR		0x85
+#define LPFC_PDE6_DESCRIPTOR		0x86
+#define LPFC_PDE7_DESCRIPTOR		0x87
+
+/* BlockGuard Opcodes */
+#define BG_OP_IN_NODIF_OUT_CRC		0x0
+#define	BG_OP_IN_CRC_OUT_NODIF		0x1
+#define	BG_OP_IN_NODIF_OUT_CSUM		0x2
+#define	BG_OP_IN_CSUM_OUT_NODIF		0x3
+#define	BG_OP_IN_CRC_OUT_CRC		0x4
+#define	BG_OP_IN_CSUM_OUT_CSUM		0x5
+#define	BG_OP_IN_CRC_OUT_CSUM		0x6
+#define	BG_OP_IN_CSUM_OUT_CRC		0x7
+
+struct lpfc_pde5 {
+	uint32_t word0;
+#define pde5_type_SHIFT		24
+#define pde5_type_MASK		0x000000ff
+#define pde5_type_WORD		word0
+#define pde5_rsvd0_SHIFT	0
+#define pde5_rsvd0_MASK		0x00ffffff
+#define pde5_rsvd0_WORD		word0
+	uint32_t reftag;	/* Reference Tag Value			*/
+	uint32_t reftagtr;	/* Reference Tag Translation Value 	*/
 };
 
-/* BlockGuard error-control defines */
-#define BG_EC_STOP_ERR			0x00
-#define BG_EC_CONT_ERR			0x01
-#define BG_EC_IGN_UNINIT_STOP_ERR	0x10
-#define BG_EC_IGN_UNINIT_CONT_ERR	0x11
-
-/* PDE (Protection Descriptor Entry) word 0 bit masks and shifts */
-#define PDE_DESC_TYPE_MASK		0xff000000
-#define PDE_DESC_TYPE_SHIFT		24
-#define PDE_BG_PROFILE_MASK		0x00ff0000
-#define PDE_BG_PROFILE_SHIFT		16
-#define PDE_BLOCK_LEN_MASK		0x0000fffc
-#define PDE_BLOCK_LEN_SHIFT		2
-#define PDE_ERR_CTRL_MASK		0x00000003
-#define PDE_ERR_CTRL_SHIFT		0
-/* PDE word 1 bit masks and shifts */
-#define PDE_APPTAG_MASK_MASK		0xffff0000
-#define PDE_APPTAG_MASK_SHIFT		16
-#define PDE_APPTAG_VAL_MASK		0x0000ffff
-#define PDE_APPTAG_VAL_SHIFT		0
-struct lpfc_pde {
-	uint32_t parms;     /* bitfields of descriptor, prof, len, and ec */
-	uint32_t apptag;    /* bitfields of app tag maskand app tag value */
-	uint32_t reftag;    /* reference tag occupying all 32 bits        */
+struct lpfc_pde6 {
+	uint32_t word0;
+#define pde6_type_SHIFT		24
+#define pde6_type_MASK		0x000000ff
+#define pde6_type_WORD		word0
+#define pde6_rsvd0_SHIFT	0
+#define pde6_rsvd0_MASK		0x00ffffff
+#define pde6_rsvd0_WORD		word0
+	uint32_t word1;
+#define pde6_rsvd1_SHIFT	26
+#define pde6_rsvd1_MASK		0x0000003f
+#define pde6_rsvd1_WORD		word1
+#define pde6_na_SHIFT		25
+#define pde6_na_MASK		0x00000001
+#define pde6_na_WORD		word1
+#define pde6_rsvd2_SHIFT	16
+#define pde6_rsvd2_MASK		0x000001FF
+#define pde6_rsvd2_WORD		word1
+#define pde6_apptagtr_SHIFT	0
+#define pde6_apptagtr_MASK	0x0000ffff
+#define pde6_apptagtr_WORD	word1
+	uint32_t word2;
+#define pde6_optx_SHIFT		28
+#define pde6_optx_MASK		0x0000000f
+#define pde6_optx_WORD		word2
+#define pde6_oprx_SHIFT		24
+#define pde6_oprx_MASK		0x0000000f
+#define pde6_oprx_WORD		word2
+#define pde6_nr_SHIFT		23
+#define pde6_nr_MASK		0x00000001
+#define pde6_nr_WORD		word2
+#define pde6_ce_SHIFT		22
+#define pde6_ce_MASK		0x00000001
+#define pde6_ce_WORD		word2
+#define pde6_re_SHIFT		21
+#define pde6_re_MASK		0x00000001
+#define pde6_re_WORD		word2
+#define pde6_ae_SHIFT		20
+#define pde6_ae_MASK		0x00000001
+#define pde6_ae_WORD		word2
+#define pde6_ai_SHIFT		19
+#define pde6_ai_MASK		0x00000001
+#define pde6_ai_WORD		word2
+#define pde6_bs_SHIFT		16
+#define pde6_bs_MASK		0x00000007
+#define pde6_bs_WORD		word2
+#define pde6_apptagval_SHIFT	0
+#define pde6_apptagval_MASK	0x0000ffff
+#define pde6_apptagval_WORD	word2
 };
 
-/* inline function to set fields in parms of PDE */
-static inline void
-lpfc_pde_set_bg_parms(struct lpfc_pde *p, u8 desc, u8 prof, u16 len, u8 ec)
-{
-	uint32_t *wp = &p->parms;
-
-	/* spec indicates that adapter appends two 0's to length field */
-	len = len >> 2;
-
-	*wp &= 0;
-	*wp |= ((desc << PDE_DESC_TYPE_SHIFT) & PDE_DESC_TYPE_MASK);
-	*wp |= ((prof << PDE_BG_PROFILE_SHIFT) & PDE_BG_PROFILE_MASK);
-	*wp |= ((len << PDE_BLOCK_LEN_SHIFT) & PDE_BLOCK_LEN_MASK);
-	*wp |= ((ec << PDE_ERR_CTRL_SHIFT) & PDE_ERR_CTRL_MASK);
-	*wp = le32_to_cpu(*wp);
-}
-
-/* inline function to set apptag and reftag fields of PDE */
-static inline void
-lpfc_pde_set_dif_parms(struct lpfc_pde *p, u16 apptagmask, u16 apptagval,
-		u32 reftag)
-{
-	uint32_t *wp = &p->apptag;
-	*wp &= 0;
-	*wp |= ((apptagmask << PDE_APPTAG_MASK_SHIFT) & PDE_APPTAG_MASK_MASK);
-	*wp |= ((apptagval << PDE_APPTAG_VAL_SHIFT) & PDE_APPTAG_VAL_MASK);
-	*wp = le32_to_cpu(*wp);
-	wp = &p->reftag;
-	*wp = le32_to_cpu(reftag);
-}
-
 
 /* Structure for MB Command LOAD_SM and DOWN_LOAD */
 
@@ -1744,6 +1732,17 @@ typedef struct {
 	} un;
 } BIU_DIAG_VAR;
 
+/* Structure for MB command READ_EVENT_LOG (0x38) */
+struct READ_EVENT_LOG_VAR {
+	uint32_t word1;
+#define lpfc_event_log_SHIFT	29
+#define lpfc_event_log_MASK	0x00000001
+#define lpfc_event_log_WORD	word1
+#define USE_MAILBOX_RESPONSE	1
+	uint32_t offset;
+	struct ulp_bde64 rcv_bde64;
+};
+
 /* Structure for MB Command INIT_LINK (05) */
 
 typedef struct {
@@ -2487,8 +2486,8 @@ typedef struct {
 #define  DMP_VPORT_REGION_SIZE	 0x200
 #define  DMP_MBOX_OFFSET_WORD	 0x5
 
-#define  DMP_REGION_23	 	 0x17   /* fcoe param  and port state region */
-#define  DMP_RGN23_SIZE	 	 0x400
+#define  DMP_REGION_23		 0x17   /* fcoe param  and port state region */
+#define  DMP_RGN23_SIZE		 0x400
 
 #define  WAKE_UP_PARMS_REGION_ID    4
 #define  WAKE_UP_PARMS_WORD_SIZE   15
@@ -2503,9 +2502,9 @@ struct vport_rec {
 #define VPORT_INFO_REV 0x1
 #define MAX_STATIC_VPORT_COUNT 16
 struct static_vport_info {
-	uint32_t 		signature;
+	uint32_t		signature;
 	uint32_t		rev;
-	struct vport_rec 	vport_list[MAX_STATIC_VPORT_COUNT];
+	struct vport_rec	vport_list[MAX_STATIC_VPORT_COUNT];
 	uint32_t		resvd[66];
 };
 
@@ -2934,6 +2933,12 @@ typedef struct {
 /* Union of all Mailbox Command types */
 #define MAILBOX_CMD_WSIZE	32
 #define MAILBOX_CMD_SIZE	(MAILBOX_CMD_WSIZE * sizeof(uint32_t))
+/* ext_wsize times 4 bytes should not be greater than max xmit size */
+#define MAILBOX_EXT_WSIZE	512
+#define MAILBOX_EXT_SIZE	(MAILBOX_EXT_WSIZE * sizeof(uint32_t))
+#define MAILBOX_HBA_EXT_OFFSET  0x100
+/* max mbox xmit size is a page size for sysfs IO operations */
+#define MAILBOX_MAX_XMIT_SIZE   PAGE_SIZE
 
 typedef union {
 	uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/
@@ -2972,6 +2977,9 @@ typedef union {
 	REG_VPI_VAR varRegVpi;		/* cmd = 0x96 (REG_VPI) */
 	UNREG_VPI_VAR varUnregVpi;	/* cmd = 0x97 (UNREG_VPI) */
 	ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */
+	struct READ_EVENT_LOG_VAR varRdEventLog;	/* cmd = 0x38
+							 * (READ_EVENT_LOG)
+							 */
 	struct config_msi_var varCfgMSI;/* cmd = x30 (CONFIG_MSI)     */
 } MAILVARIANTS;
 
@@ -3652,7 +3660,8 @@ typedef struct _IOCB {	/* IOCB structure */
 /* Maximum IOCBs that will fit in SLI2 slim */
 #define MAX_SLI2_IOCB    498
 #define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \
-			    (sizeof(MAILBOX_t) + sizeof(PCB_t)))
+			    (sizeof(MAILBOX_t) + sizeof(PCB_t) + \
+			    sizeof(uint32_t) * MAILBOX_EXT_WSIZE))
 
 /* HBQ entries are 4 words each = 4k */
 #define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) *  \
@@ -3660,6 +3669,7 @@ typedef struct _IOCB {	/* IOCB structure */
 
 struct lpfc_sli2_slim {
 	MAILBOX_t mbx;
+	uint32_t  mbx_ext_words[MAILBOX_EXT_WSIZE];
 	PCB_t pcb;
 	IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE];
 };

+ 58 - 2
drivers/scsi/lpfc/lpfc_hw4.h

@@ -41,8 +41,14 @@
  * Or clear that bit field:
  *	bf_set(example_bit_field, &t1, 0);
  */
+#define bf_get_le32(name, ptr) \
+	((le32_to_cpu((ptr)->name##_WORD) >> name##_SHIFT) & name##_MASK)
 #define bf_get(name, ptr) \
 	(((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK)
+#define bf_set_le32(name, ptr, value) \
+	((ptr)->name##_WORD = cpu_to_le32(((((value) & \
+	name##_MASK) << name##_SHIFT) | (le32_to_cpu((ptr)->name##_WORD) & \
+	~(name##_MASK << name##_SHIFT)))))
 #define bf_set(name, ptr, value) \
 	((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \
 		 ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT))))
@@ -781,6 +787,7 @@ struct mbox_header {
 #define LPFC_MBOX_OPCODE_EQ_DESTROY		0x37
 #define LPFC_MBOX_OPCODE_QUERY_FW_CFG		0x3A
 #define LPFC_MBOX_OPCODE_FUNCTION_RESET		0x3D
+#define LPFC_MBOX_OPCODE_MQ_CREATE_EXT		0x5A
 
 /* FCoE Opcodes */
 #define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE			0x01
@@ -1102,6 +1109,39 @@ struct lpfc_mbx_mq_create {
 	} u;
 };
 
+struct lpfc_mbx_mq_create_ext {
+	struct mbox_header header;
+	union {
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_mq_create_ext_num_pages_SHIFT		0
+#define lpfc_mbx_mq_create_ext_num_pages_MASK		0x0000FFFF
+#define lpfc_mbx_mq_create_ext_num_pages_WORD		word0
+			uint32_t async_evt_bmap;
+#define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT	LPFC_TRAILER_CODE_LINK
+#define lpfc_mbx_mq_create_ext_async_evt_link_MASK	0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_link_WORD	async_evt_bmap
+#define lpfc_mbx_mq_create_ext_async_evt_fcfste_SHIFT	LPFC_TRAILER_CODE_FCOE
+#define lpfc_mbx_mq_create_ext_async_evt_fcfste_MASK	0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_fcfste_WORD	async_evt_bmap
+#define lpfc_mbx_mq_create_ext_async_evt_group5_SHIFT	LPFC_TRAILER_CODE_GRP5
+#define lpfc_mbx_mq_create_ext_async_evt_group5_MASK	0x00000001
+#define lpfc_mbx_mq_create_ext_async_evt_group5_WORD	async_evt_bmap
+			struct mq_context context;
+			struct dma_address page[LPFC_MAX_MQ_PAGE];
+		} request;
+		struct {
+			uint32_t word0;
+#define lpfc_mbx_mq_create_q_id_SHIFT	0
+#define lpfc_mbx_mq_create_q_id_MASK	0x0000FFFF
+#define lpfc_mbx_mq_create_q_id_WORD	word0
+		} response;
+	} u;
+#define LPFC_ASYNC_EVENT_LINK_STATE	0x2
+#define LPFC_ASYNC_EVENT_FCF_STATE	0x4
+#define LPFC_ASYNC_EVENT_GROUP5		0x20
+};
+
 struct lpfc_mbx_mq_destroy {
 	struct mbox_header header;
 	union {
@@ -1428,8 +1468,8 @@ struct lpfc_mbx_reg_vfi {
 #define lpfc_reg_vfi_fcfi_WORD		word2
 	uint32_t wwn[2];
 	struct ulp_bde64 bde;
-	uint32_t word8_rsvd;
-	uint32_t word9_rsvd;
+	uint32_t e_d_tov;
+	uint32_t r_a_tov;
 	uint32_t word10;
 #define lpfc_reg_vfi_nport_id_SHIFT		0
 #define lpfc_reg_vfi_nport_id_MASK		0x00FFFFFF
@@ -1940,6 +1980,7 @@ struct lpfc_mbx_sli4_params {
 #define rdma_MASK				0x00000001
 #define rdma_WORD				word3
 	uint32_t sge_supp_len;
+#define SLI4_PAGE_SIZE 4096
 	uint32_t word5;
 #define if_page_sz_SHIFT			0
 #define if_page_sz_MASK				0x0000ffff
@@ -2041,6 +2082,7 @@ struct lpfc_mqe {
 		struct lpfc_mbx_reg_fcfi reg_fcfi;
 		struct lpfc_mbx_unreg_fcfi unreg_fcfi;
 		struct lpfc_mbx_mq_create mq_create;
+		struct lpfc_mbx_mq_create_ext mq_create_ext;
 		struct lpfc_mbx_eq_create eq_create;
 		struct lpfc_mbx_cq_create cq_create;
 		struct lpfc_mbx_wq_create wq_create;
@@ -2099,6 +2141,7 @@ struct lpfc_mcqe {
 #define LPFC_TRAILER_CODE_LINK	0x1
 #define LPFC_TRAILER_CODE_FCOE	0x2
 #define LPFC_TRAILER_CODE_DCBX	0x3
+#define LPFC_TRAILER_CODE_GRP5	0x5
 };
 
 struct lpfc_acqe_link {
@@ -2168,6 +2211,19 @@ struct lpfc_acqe_dcbx {
 	uint32_t trailer;
 };
 
+struct lpfc_acqe_grp5 {
+	uint32_t word0;
+#define lpfc_acqe_grp5_pport_SHIFT	0
+#define lpfc_acqe_grp5_pport_MASK	0x000000FF
+#define lpfc_acqe_grp5_pport_WORD	word0
+	uint32_t word1;
+#define lpfc_acqe_grp5_llink_spd_SHIFT	16
+#define lpfc_acqe_grp5_llink_spd_MASK	0x0000FFFF
+#define lpfc_acqe_grp5_llink_spd_WORD	word1
+	uint32_t event_tag;
+	uint32_t trailer;
+};
+
 /*
  * Define the bootstrap mailbox (bmbx) region used to communicate
  * mailbox command between the host and port. The mailbox consists

+ 135 - 78
drivers/scsi/lpfc/lpfc_init.c

@@ -2566,7 +2566,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
 	shost->max_cmd_len = 16;
 	if (phba->sli_rev == LPFC_SLI_REV4) {
 		shost->dma_boundary =
-			phba->sli4_hba.pc_sli4_params.sge_supp_len;
+			phba->sli4_hba.pc_sli4_params.sge_supp_len-1;
 		shost->sg_tablesize = phba->cfg_sg_seg_cnt;
 	}
 
@@ -2600,15 +2600,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
 	init_timer(&vport->els_tmofunc);
 	vport->els_tmofunc.function = lpfc_els_timeout;
 	vport->els_tmofunc.data = (unsigned long)vport;
-	if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) {
-		phba->menlo_flag |= HBA_MENLO_SUPPORT;
-		/* check for menlo minimum sg count */
-		if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT) {
-			phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT;
-			shost->sg_tablesize = phba->cfg_sg_seg_cnt;
-		}
-	}
-
 	error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev);
 	if (error)
 		goto out_put_shost;
@@ -3236,12 +3227,26 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport)
 
 	if (!vport)
 		return NULL;
-	ndlp = lpfc_findnode_did(vport, Fabric_DID);
-	if (!ndlp)
-		return NULL;
 	phba = vport->phba;
 	if (!phba)
 		return NULL;
+	ndlp = lpfc_findnode_did(vport, Fabric_DID);
+	if (!ndlp) {
+		/* Cannot find existing Fabric ndlp, so allocate a new one */
+		ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+		if (!ndlp)
+			return 0;
+		lpfc_nlp_init(vport, ndlp, Fabric_DID);
+		/* Set the node type */
+		ndlp->nlp_type |= NLP_FABRIC;
+		/* Put ndlp onto node list */
+		lpfc_enqueue_node(vport, ndlp);
+	} else if (!NLP_CHK_NODE_ACT(ndlp)) {
+		/* re-setup ndlp without removing from node list */
+		ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE);
+		if (!ndlp)
+			return 0;
+	}
 	if (phba->pport->port_state <= LPFC_FLOGI)
 		return NULL;
 	/* If virtual link is not yet instantiated ignore CVL */
@@ -3304,11 +3309,20 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba,
 	switch (event_type) {
 	case LPFC_FCOE_EVENT_TYPE_NEW_FCF:
 	case LPFC_FCOE_EVENT_TYPE_FCF_PARAM_MOD:
-		lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
-			"2546 New FCF found/FCF parameter modified event: "
-			"evt_tag:x%x, fcf_index:x%x\n",
-			acqe_fcoe->event_tag, acqe_fcoe->index);
-
+		if (event_type == LPFC_FCOE_EVENT_TYPE_NEW_FCF)
+			lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
+					LOG_DISCOVERY,
+					"2546 New FCF found event: "
+					"evt_tag:x%x, fcf_index:x%x\n",
+					acqe_fcoe->event_tag,
+					acqe_fcoe->index);
+		else
+			lpfc_printf_log(phba, KERN_WARNING, LOG_FIP |
+					LOG_DISCOVERY,
+					"2788 FCF parameter modified event: "
+					"evt_tag:x%x, fcf_index:x%x\n",
+					acqe_fcoe->event_tag,
+					acqe_fcoe->index);
 		spin_lock_irq(&phba->hbalock);
 		if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) ||
 		    (phba->hba_flag & FCF_DISC_INPROGRESS)) {
@@ -3516,6 +3530,32 @@ lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba,
 			"handled yet\n");
 }
 
+/**
+ * lpfc_sli4_async_grp5_evt - Process the asynchronous group5 event
+ * @phba: pointer to lpfc hba data structure.
+ * @acqe_link: pointer to the async grp5 completion queue entry.
+ *
+ * This routine is to handle the SLI4 asynchronous grp5 event. A grp5 event
+ * is an asynchronous notified of a logical link speed change.  The Port
+ * reports the logical link speed in units of 10Mbps.
+ **/
+static void
+lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba,
+			 struct lpfc_acqe_grp5 *acqe_grp5)
+{
+	uint16_t prev_ll_spd;
+
+	phba->fc_eventTag = acqe_grp5->event_tag;
+	phba->fcoe_eventtag = acqe_grp5->event_tag;
+	prev_ll_spd = phba->sli4_hba.link_state.logical_speed;
+	phba->sli4_hba.link_state.logical_speed =
+		(bf_get(lpfc_acqe_grp5_llink_spd, acqe_grp5));
+	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+			"2789 GRP5 Async Event: Updating logical link speed "
+			"from %dMbps to %dMbps\n", (prev_ll_spd * 10),
+			(phba->sli4_hba.link_state.logical_speed*10));
+}
+
 /**
  * lpfc_sli4_async_event_proc - Process all the pending asynchronous event
  * @phba: pointer to lpfc hba data structure.
@@ -3552,6 +3592,10 @@ void lpfc_sli4_async_event_proc(struct lpfc_hba *phba)
 			lpfc_sli4_async_dcbx_evt(phba,
 						 &cq_event->cqe.acqe_dcbx);
 			break;
+		case LPFC_TRAILER_CODE_GRP5:
+			lpfc_sli4_async_grp5_evt(phba,
+						 &cq_event->cqe.acqe_grp5);
+			break;
 		default:
 			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 					"1804 Invalid asynchrous event code: "
@@ -3813,6 +3857,13 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba)
 
 	/* Get all the module params for configuring this host */
 	lpfc_get_cfgparam(phba);
+	if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) {
+		phba->menlo_flag |= HBA_MENLO_SUPPORT;
+		/* check for menlo minimum sg count */
+		if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT)
+			phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT;
+	}
+
 	/*
 	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
 	 * used to create the sg_dma_buf_pool must be dynamically calculated.
@@ -4030,6 +4081,43 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
 	if (unlikely(rc))
 		goto out_free_bsmbx;
 
+	mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+						       GFP_KERNEL);
+	if (!mboxq) {
+		rc = -ENOMEM;
+		goto out_free_bsmbx;
+	}
+
+	/* Get the Supported Pages. It is always available. */
+	lpfc_supported_pages(mboxq);
+	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
+	if (unlikely(rc)) {
+		rc = -EIO;
+		mempool_free(mboxq, phba->mbox_mem_pool);
+		goto out_free_bsmbx;
+	}
+
+	mqe = &mboxq->u.mqe;
+	memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3),
+	       LPFC_MAX_SUPPORTED_PAGES);
+	for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) {
+		switch (pn_page[i]) {
+		case LPFC_SLI4_PARAMETERS:
+			phba->sli4_hba.pc_sli4_params.supported = 1;
+			break;
+		default:
+			break;
+		}
+	}
+
+	/* Read the port's SLI4 Parameters capabilities if supported. */
+	if (phba->sli4_hba.pc_sli4_params.supported)
+		rc = lpfc_pc_sli4_params_get(phba, mboxq);
+	mempool_free(mboxq, phba->mbox_mem_pool);
+	if (rc) {
+		rc = -EIO;
+		goto out_free_bsmbx;
+	}
 	/* Create all the SLI4 queues */
 	rc = lpfc_sli4_queue_create(phba);
 	if (rc)
@@ -4090,43 +4178,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
 		goto out_free_fcp_eq_hdl;
 	}
 
-	mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
-						       GFP_KERNEL);
-	if (!mboxq) {
-		rc = -ENOMEM;
-		goto out_free_fcp_eq_hdl;
-	}
-
-	/* Get the Supported Pages. It is always available. */
-	lpfc_supported_pages(mboxq);
-	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL);
-	if (unlikely(rc)) {
-		rc = -EIO;
-		mempool_free(mboxq, phba->mbox_mem_pool);
-		goto out_free_fcp_eq_hdl;
-	}
-
-	mqe = &mboxq->u.mqe;
-	memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3),
-	       LPFC_MAX_SUPPORTED_PAGES);
-	for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) {
-		switch (pn_page[i]) {
-		case LPFC_SLI4_PARAMETERS:
-			phba->sli4_hba.pc_sli4_params.supported = 1;
-			break;
-		default:
-			break;
-		}
-	}
-
-	/* Read the port's SLI4 Parameters capabilities if supported. */
-	if (phba->sli4_hba.pc_sli4_params.supported)
-		rc = lpfc_pc_sli4_params_get(phba, mboxq);
-	mempool_free(mboxq, phba->mbox_mem_pool);
-	if (rc) {
-		rc = -EIO;
-		goto out_free_fcp_eq_hdl;
-	}
 	return rc;
 
 out_free_fcp_eq_hdl:
@@ -5050,6 +5101,8 @@ lpfc_sli_pci_mem_setup(struct lpfc_hba *phba)
 
 	memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE);
 	phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx);
+	phba->mbox_ext = (phba->slim2p.virt +
+		offsetof(struct lpfc_sli2_slim, mbx_ext_words));
 	phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb));
 	phba->IOCBs = (phba->slim2p.virt +
 		       offsetof(struct lpfc_sli2_slim, IOCBs));
@@ -7753,21 +7806,23 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)
  * @phba: pointer to lpfc hba data structure.
  *
  * This routine is called to prepare the SLI3 device for PCI slot recover. It
- * aborts and stops all the on-going I/Os on the pci device.
+ * aborts all the outstanding SCSI I/Os to the pci device.
  **/
 static void
 lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)
 {
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_sli_ring  *pring;
+
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"2723 PCI channel I/O abort preparing for recovery\n");
-	/* Prepare for bringing HBA offline */
-	lpfc_offline_prep(phba);
-	/* Clear sli active flag to prevent sysfs access to HBA */
-	spin_lock_irq(&phba->hbalock);
-	phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE;
-	spin_unlock_irq(&phba->hbalock);
-	/* Stop and flush all I/Os and bring HBA offline */
-	lpfc_offline(phba);
+
+	/*
+	 * There may be errored I/Os through HBA, abort all I/Os on txcmplq
+	 * and let the SCSI mid-layer to retry them to recover.
+	 */
+	pring = &psli->ring[psli->fcp_ring];
+	lpfc_sli_abort_iocb_ring(phba, pring);
 }
 
 /**
@@ -7781,21 +7836,20 @@ lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)
 static void
 lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
 {
-	struct lpfc_sli *psli = &phba->sli;
-	struct lpfc_sli_ring  *pring;
-
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"2710 PCI channel disable preparing for reset\n");
+
+	/* Block all SCSI devices' I/Os on the host */
+	lpfc_scsi_dev_block(phba);
+
+	/* stop all timers */
+	lpfc_stop_hba_timers(phba);
+
 	/* Disable interrupt and pci device */
 	lpfc_sli_disable_intr(phba);
 	pci_disable_device(phba->pcidev);
-	/*
-	 * There may be I/Os dropped by the firmware.
-	 * Error iocb (I/O) on txcmplq and let the SCSI layer
-	 * retry it after re-establishing link.
-	 */
-	pring = &psli->ring[psli->fcp_ring];
-	lpfc_sli_abort_iocb_ring(phba, pring);
+	/* Flush all driver's outstanding SCSI I/Os as we are to reset */
+	lpfc_sli_flush_fcp_rings(phba);
 }
 
 /**
@@ -7811,6 +7865,12 @@ lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba)
 {
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"2711 PCI channel permanent disable for failure\n");
+	/* Block all SCSI devices' I/Os on the host */
+	lpfc_scsi_dev_block(phba);
+
+	/* stop all timers */
+	lpfc_stop_hba_timers(phba);
+
 	/* Clean up all driver's outstanding SCSI I/Os */
 	lpfc_sli_flush_fcp_rings(phba);
 }
@@ -7839,9 +7899,6 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 
-	/* Block all SCSI devices' I/Os on the host */
-	lpfc_scsi_dev_block(phba);
-
 	switch (state) {
 	case pci_channel_io_normal:
 		/* Non-fatal error, prepare for recovery */
@@ -7948,7 +8005,7 @@ lpfc_io_resume_s3(struct pci_dev *pdev)
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 
-	/* Bring the device online */
+	/* Bring device online, it will be no-op for non-fatal error resume */
 	lpfc_online(phba);
 
 	/* Clean up Advanced Error Reporting (AER) if needed */

+ 42 - 27
drivers/scsi/lpfc/lpfc_mbox.c

@@ -1216,7 +1216,7 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	phba->pcb->feature = FEATURE_INITIAL_SLI2;
 
 	/* Setup Mailbox pointers */
-	phba->pcb->mailBoxSize = sizeof(MAILBOX_t);
+	phba->pcb->mailBoxSize = sizeof(MAILBOX_t) + MAILBOX_EXT_SIZE;
 	offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt;
 	pdma_addr = phba->slim2p.phys + offset;
 	phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr);
@@ -1272,28 +1272,41 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	 *
 	 */
 
-	if (phba->sli_rev == 3) {
-		phba->host_gp = &mb_slim->us.s3.host[0];
-		phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
-	} else {
-		phba->host_gp = &mb_slim->us.s2.host[0];
+	if (phba->cfg_hostmem_hgp && phba->sli_rev != 3) {
+		phba->host_gp = &phba->mbox->us.s2.host[0];
 		phba->hbq_put = NULL;
-	}
+		offset = (uint8_t *)&phba->mbox->us.s2.host -
+			(uint8_t *)phba->slim2p.virt;
+		pdma_addr = phba->slim2p.phys + offset;
+		phba->pcb->hgpAddrHigh = putPaddrHigh(pdma_addr);
+		phba->pcb->hgpAddrLow = putPaddrLow(pdma_addr);
+	} else {
+		/* Always Host Group Pointer is in SLIM */
+		mb->un.varCfgPort.hps = 1;
 
-	/* mask off BAR0's flag bits 0 - 3 */
-	phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
-		(void __iomem *)phba->host_gp -
-		(void __iomem *)phba->MBslimaddr;
-	if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
-		phba->pcb->hgpAddrHigh = bar_high;
-	else
-		phba->pcb->hgpAddrHigh = 0;
-	/* write HGP data to SLIM at the required longword offset */
-	memset(&hgp, 0, sizeof(struct lpfc_hgp));
+		if (phba->sli_rev == 3) {
+			phba->host_gp = &mb_slim->us.s3.host[0];
+			phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
+		} else {
+			phba->host_gp = &mb_slim->us.s2.host[0];
+			phba->hbq_put = NULL;
+		}
 
-	for (i=0; i < phba->sli.num_rings; i++) {
-		lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
+		/* mask off BAR0's flag bits 0 - 3 */
+		phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
+			(void __iomem *)phba->host_gp -
+			(void __iomem *)phba->MBslimaddr;
+		if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
+			phba->pcb->hgpAddrHigh = bar_high;
+		else
+			phba->pcb->hgpAddrHigh = 0;
+		/* write HGP data to SLIM at the required longword offset */
+		memset(&hgp, 0, sizeof(struct lpfc_hgp));
+
+		for (i = 0; i < phba->sli.num_rings; i++) {
+			lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
 				    sizeof(*phba->host_gp));
+		}
 	}
 
 	/* Setup Port Group offset */
@@ -1598,7 +1611,7 @@ lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
 	for (sgentry = 0; sgentry < sgecount; sgentry++) {
 		lpfc_sli4_mbx_sge_get(mbox, sgentry, &sge);
 		phyaddr = getPaddr(sge.pa_hi, sge.pa_lo);
-		dma_free_coherent(&phba->pcidev->dev, PAGE_SIZE,
+		dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE,
 				  mbox->sge_array->addr[sgentry], phyaddr);
 	}
 	/* Free the sge address array memory */
@@ -1656,7 +1669,7 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
 	}
 
 	/* Setup for the none-embedded mbox command */
-	pcount = (PAGE_ALIGN(length))/PAGE_SIZE;
+	pcount = (PAGE_ALIGN(length))/SLI4_PAGE_SIZE;
 	pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ?
 				LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount;
 	/* Allocate record for keeping SGE virtual addresses */
@@ -1671,24 +1684,24 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
 	for (pagen = 0, alloc_len = 0; pagen < pcount; pagen++) {
 		/* The DMA memory is always allocated in the length of a
 		 * page even though the last SGE might not fill up to a
-		 * page, this is used as a priori size of PAGE_SIZE for
+		 * page, this is used as a priori size of SLI4_PAGE_SIZE for
 		 * the later DMA memory free.
 		 */
-		viraddr = dma_alloc_coherent(&phba->pcidev->dev, PAGE_SIZE,
+		viraddr = dma_alloc_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE,
 					     &phyaddr, GFP_KERNEL);
 		/* In case of malloc fails, proceed with whatever we have */
 		if (!viraddr)
 			break;
-		memset(viraddr, 0, PAGE_SIZE);
+		memset(viraddr, 0, SLI4_PAGE_SIZE);
 		mbox->sge_array->addr[pagen] = viraddr;
 		/* Keep the first page for later sub-header construction */
 		if (pagen == 0)
 			cfg_shdr = (union lpfc_sli4_cfg_shdr *)viraddr;
 		resid_len = length - alloc_len;
-		if (resid_len > PAGE_SIZE) {
+		if (resid_len > SLI4_PAGE_SIZE) {
 			lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,
-					      PAGE_SIZE);
-			alloc_len += PAGE_SIZE;
+					      SLI4_PAGE_SIZE);
+			alloc_len += SLI4_PAGE_SIZE;
 		} else {
 			lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr,
 					      resid_len);
@@ -1886,6 +1899,8 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
 	memcpy(reg_vfi->wwn, &vport->fc_portname, sizeof(struct lpfc_name));
 	reg_vfi->wwn[0] = cpu_to_le32(reg_vfi->wwn[0]);
 	reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]);
+	reg_vfi->e_d_tov = vport->phba->fc_edtov;
+	reg_vfi->r_a_tov = vport->phba->fc_ratov;
 	reg_vfi->bde.addrHigh = putPaddrHigh(phys);
 	reg_vfi->bde.addrLow = putPaddrLow(phys);
 	reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);

+ 94 - 5
drivers/scsi/lpfc/lpfc_nportdisc.c

@@ -493,6 +493,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	      struct lpfc_iocbq *cmdiocb, uint32_t els_cmd)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+	struct lpfc_hba    *phba = vport->phba;
+	struct lpfc_vport **vports;
+	int i, active_vlink_present = 0 ;
 
 	/* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */
 	/* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
@@ -505,15 +508,44 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
 	else
 		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
-	if ((ndlp->nlp_DID == Fabric_DID) &&
-		vport->port_type == LPFC_NPIV_PORT) {
+	if (ndlp->nlp_DID == Fabric_DID) {
+		if (vport->port_state <= LPFC_FDISC)
+			goto out;
 		lpfc_linkdown_port(vport);
-		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
 		spin_lock_irq(shost->host_lock);
-		ndlp->nlp_flag |= NLP_DELAY_TMO;
+		vport->fc_flag |= FC_VPORT_LOGO_RCVD;
 		spin_unlock_irq(shost->host_lock);
+		vports = lpfc_create_vport_work_array(phba);
+		if (vports) {
+			for (i = 0; i <= phba->max_vports && vports[i] != NULL;
+					i++) {
+				if ((!(vports[i]->fc_flag &
+					FC_VPORT_LOGO_RCVD)) &&
+					(vports[i]->port_state > LPFC_FDISC)) {
+					active_vlink_present = 1;
+					break;
+				}
+			}
+			lpfc_destroy_vport_work_array(phba, vports);
+		}
 
-		ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
+		if (active_vlink_present) {
+			/*
+			 * If there are other active VLinks present,
+			 * re-instantiate the Vlink using FDISC.
+			 */
+			mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+			spin_lock_irq(shost->host_lock);
+			ndlp->nlp_flag |= NLP_DELAY_TMO;
+			spin_unlock_irq(shost->host_lock);
+			ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
+			vport->port_state = LPFC_FDISC;
+		} else {
+			spin_lock_irq(shost->host_lock);
+			phba->pport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG;
+			spin_unlock_irq(shost->host_lock);
+			lpfc_retry_pport_discovery(phba);
+		}
 	} else if ((!(ndlp->nlp_type & NLP_FABRIC) &&
 		((ndlp->nlp_type & NLP_FCP_TARGET) ||
 		!(ndlp->nlp_type & NLP_FCP_INITIATOR))) ||
@@ -526,6 +558,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
 		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
 	}
+out:
 	ndlp->nlp_prev_state = ndlp->nlp_state;
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 
@@ -604,11 +637,55 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 	lpfc_unreg_rpi(vport, ndlp);
 	return 0;
 }
+/**
+ * lpfc_release_rpi - Release a RPI by issueing unreg_login mailbox cmd.
+ * @phba : Pointer to lpfc_hba structure.
+ * @vport: Pointer to lpfc_vport structure.
+ * @rpi  : rpi to be release.
+ *
+ * This function will send a unreg_login mailbox command to the firmware
+ * to release a rpi.
+ **/
+void
+lpfc_release_rpi(struct lpfc_hba *phba,
+		struct lpfc_vport *vport,
+		uint16_t rpi)
+{
+	LPFC_MBOXQ_t *pmb;
+	int rc;
+
+	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+			GFP_KERNEL);
+	if (!pmb)
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+			"2796 mailbox memory allocation failed \n");
+	else {
+		lpfc_unreg_login(phba, vport->vpi, rpi, pmb);
+		pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+		if (rc == MBX_NOT_FINISHED)
+			mempool_free(pmb, phba->mbox_mem_pool);
+	}
+}
 
 static uint32_t
 lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		  void *arg, uint32_t evt)
 {
+	struct lpfc_hba *phba;
+	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
+	MAILBOX_t *mb;
+	uint16_t rpi;
+
+	phba = vport->phba;
+	/* Release the RPI if reglogin completing */
+	if (!(phba->pport->load_flag & FC_UNLOADING) &&
+		(evt == NLP_EVT_CMPL_REG_LOGIN) &&
+		(!pmb->u.mb.mbxStatus)) {
+		mb = &pmb->u.mb;
+		rpi = pmb->u.mb.un.varWords[0];
+		lpfc_release_rpi(phba, vport, rpi);
+	}
 	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
 			 "0271 Illegal State Transition: node x%x "
 			 "event x%x, state x%x Data: x%x x%x\n",
@@ -944,6 +1021,18 @@ static uint32_t
 lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
 	struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
 {
+	struct lpfc_hba *phba;
+	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
+	MAILBOX_t *mb = &pmb->u.mb;
+	uint16_t rpi;
+
+	phba = vport->phba;
+	/* Release the RPI */
+	if (!(phba->pport->load_flag & FC_UNLOADING) &&
+		!mb->mbxStatus) {
+		rpi = pmb->u.mb.un.varWords[0];
+		lpfc_release_rpi(phba, vport, rpi);
+	}
 	return ndlp->nlp_state;
 }
 

+ 100 - 49
drivers/scsi/lpfc/lpfc_scsi.c

@@ -1141,37 +1141,47 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
 }
 
 /*
- * Given a scsi cmnd, determine the BlockGuard profile to be used
- * with the cmd
+ * Given a scsi cmnd, determine the BlockGuard opcodes to be used with it
+ * @sc: The SCSI command to examine
+ * @txopt: (out) BlockGuard operation for transmitted data
+ * @rxopt: (out) BlockGuard operation for received data
+ *
+ * Returns: zero on success; non-zero if tx and/or rx op cannot be determined
+ *
  */
 static int
-lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
+lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
+		uint8_t *txop, uint8_t *rxop)
 {
 	uint8_t guard_type = scsi_host_get_guard(sc->device->host);
-	uint8_t ret_prof = LPFC_PROF_INVALID;
+	uint8_t ret = 0;
 
 	if (guard_type == SHOST_DIX_GUARD_IP) {
 		switch (scsi_get_prot_op(sc)) {
 		case SCSI_PROT_READ_INSERT:
 		case SCSI_PROT_WRITE_STRIP:
-			ret_prof = LPFC_PROF_AST2;
+			*txop = BG_OP_IN_CSUM_OUT_NODIF;
+			*rxop = BG_OP_IN_NODIF_OUT_CSUM;
 			break;
 
 		case SCSI_PROT_READ_STRIP:
 		case SCSI_PROT_WRITE_INSERT:
-			ret_prof = LPFC_PROF_A1;
+			*txop = BG_OP_IN_NODIF_OUT_CRC;
+			*rxop = BG_OP_IN_CRC_OUT_NODIF;
 			break;
 
 		case SCSI_PROT_READ_PASS:
 		case SCSI_PROT_WRITE_PASS:
-			ret_prof = LPFC_PROF_AST1;
+			*txop = BG_OP_IN_CSUM_OUT_CRC;
+			*rxop = BG_OP_IN_CRC_OUT_CSUM;
 			break;
 
 		case SCSI_PROT_NORMAL:
 		default:
 			lpfc_printf_log(phba, KERN_ERR, LOG_BG,
-				"9063 BLKGRD:Bad op/guard:%d/%d combination\n",
+				"9063 BLKGRD: Bad op/guard:%d/%d combination\n",
 					scsi_get_prot_op(sc), guard_type);
+			ret = 1;
 			break;
 
 		}
@@ -1179,12 +1189,14 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
 		switch (scsi_get_prot_op(sc)) {
 		case SCSI_PROT_READ_STRIP:
 		case SCSI_PROT_WRITE_INSERT:
-			ret_prof = LPFC_PROF_A1;
+			*txop = BG_OP_IN_NODIF_OUT_CRC;
+			*rxop = BG_OP_IN_CRC_OUT_NODIF;
 			break;
 
 		case SCSI_PROT_READ_PASS:
 		case SCSI_PROT_WRITE_PASS:
-			ret_prof = LPFC_PROF_C1;
+			*txop = BG_OP_IN_CRC_OUT_CRC;
+			*rxop = BG_OP_IN_CRC_OUT_CRC;
 			break;
 
 		case SCSI_PROT_READ_INSERT:
@@ -1194,6 +1206,7 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
 			lpfc_printf_log(phba, KERN_ERR, LOG_BG,
 				"9075 BLKGRD: Bad op/guard:%d/%d combination\n",
 					scsi_get_prot_op(sc), guard_type);
+			ret = 1;
 			break;
 		}
 	} else {
@@ -1201,7 +1214,7 @@ lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc)
 		BUG();
 	}
 
-	return ret_prof;
+	return ret;
 }
 
 struct scsi_dif_tuple {
@@ -1266,7 +1279,9 @@ lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask,
  * The buffer list consists of just one protection group described
  * below:
  *                                +-------------------------+
- *   start of prot group  -->     |          PDE_1          |
+ *   start of prot group  -->     |          PDE_5          |
+ *                                +-------------------------+
+ *                                |          PDE_6          |
  *                                +-------------------------+
  *                                |         Data BDE        |
  *                                +-------------------------+
@@ -1284,30 +1299,49 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 		struct ulp_bde64 *bpl, int datasegcnt)
 {
 	struct scatterlist *sgde = NULL; /* s/g data entry */
-	struct lpfc_pde *pde1 = NULL;
+	struct lpfc_pde5 *pde5 = NULL;
+	struct lpfc_pde6 *pde6 = NULL;
 	dma_addr_t physaddr;
-	int i = 0, num_bde = 0;
+	int i = 0, num_bde = 0, status;
 	int datadir = sc->sc_data_direction;
-	int prof = LPFC_PROF_INVALID;
 	unsigned blksize;
 	uint32_t reftag;
 	uint16_t apptagmask, apptagval;
+	uint8_t txop, rxop;
 
-	pde1 = (struct lpfc_pde *) bpl;
-	prof = lpfc_sc_to_sli_prof(phba, sc);
-
-	if (prof == LPFC_PROF_INVALID)
+	status  = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
+	if (status)
 		goto out;
 
-	/* extract some info from the scsi command for PDE1*/
+	/* extract some info from the scsi command for pde*/
 	blksize = lpfc_cmd_blksize(sc);
 	lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
 
-	/* setup PDE1 with what we have */
-	lpfc_pde_set_bg_parms(pde1, LPFC_PDE1_DESCRIPTOR, prof, blksize,
-			BG_EC_STOP_ERR);
-	lpfc_pde_set_dif_parms(pde1, apptagmask, apptagval, reftag);
+	/* setup PDE5 with what we have */
+	pde5 = (struct lpfc_pde5 *) bpl;
+	memset(pde5, 0, sizeof(struct lpfc_pde5));
+	bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
+	pde5->reftag = reftag;
 
+	/* advance bpl and increment bde count */
+	num_bde++;
+	bpl++;
+	pde6 = (struct lpfc_pde6 *) bpl;
+
+	/* setup PDE6 with the rest of the info */
+	memset(pde6, 0, sizeof(struct lpfc_pde6));
+	bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR);
+	bf_set(pde6_optx, pde6, txop);
+	bf_set(pde6_oprx, pde6, rxop);
+	if (datadir == DMA_FROM_DEVICE) {
+		bf_set(pde6_ce, pde6, 1);
+		bf_set(pde6_re, pde6, 1);
+		bf_set(pde6_ae, pde6, 1);
+	}
+	bf_set(pde6_ai, pde6, 1);
+	bf_set(pde6_apptagval, pde6, apptagval);
+
+	/* advance bpl and increment bde count */
 	num_bde++;
 	bpl++;
 
@@ -1342,15 +1376,17 @@ out:
  * The buffer list for this type consists of one or more of the
  * protection groups described below:
  *                                    +-------------------------+
- *   start of first prot group  -->   |          PDE_1          |
+ *   start of first prot group  -->   |          PDE_5          |
+ *                                    +-------------------------+
+ *                                    |          PDE_6          |
  *                                    +-------------------------+
- *                                    |      PDE_3 (Prot BDE)   |
+ *                                    |      PDE_7 (Prot BDE)   |
  *                                    +-------------------------+
  *                                    |        Data BDE         |
  *                                    +-------------------------+
  *                                    |more Data BDE's ... (opt)|
  *                                    +-------------------------+
- *   start of new  prot group  -->    |          PDE_1          |
+ *   start of new  prot group  -->    |          PDE_5          |
  *                                    +-------------------------+
  *                                    |          ...            |
  *                                    +-------------------------+
@@ -1369,19 +1405,21 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 {
 	struct scatterlist *sgde = NULL; /* s/g data entry */
 	struct scatterlist *sgpe = NULL; /* s/g prot entry */
-	struct lpfc_pde *pde1 = NULL;
+	struct lpfc_pde5 *pde5 = NULL;
+	struct lpfc_pde6 *pde6 = NULL;
 	struct ulp_bde64 *prot_bde = NULL;
 	dma_addr_t dataphysaddr, protphysaddr;
 	unsigned short curr_data = 0, curr_prot = 0;
 	unsigned int split_offset, protgroup_len;
 	unsigned int protgrp_blks, protgrp_bytes;
 	unsigned int remainder, subtotal;
-	int prof = LPFC_PROF_INVALID;
+	int status;
 	int datadir = sc->sc_data_direction;
 	unsigned char pgdone = 0, alldone = 0;
 	unsigned blksize;
 	uint32_t reftag;
 	uint16_t apptagmask, apptagval;
+	uint8_t txop, rxop;
 	int num_bde = 0;
 
 	sgpe = scsi_prot_sglist(sc);
@@ -1394,31 +1432,47 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 		return 0;
 	}
 
-	prof = lpfc_sc_to_sli_prof(phba, sc);
-	if (prof == LPFC_PROF_INVALID)
+	status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
+	if (status)
 		goto out;
 
-	/* extract some info from the scsi command for PDE1*/
+	/* extract some info from the scsi command */
 	blksize = lpfc_cmd_blksize(sc);
 	lpfc_get_cmd_dif_parms(sc, &apptagmask, &apptagval, &reftag);
 
 	split_offset = 0;
 	do {
-		/* setup the first PDE_1 */
-		pde1 = (struct lpfc_pde *) bpl;
-
-		lpfc_pde_set_bg_parms(pde1, LPFC_PDE1_DESCRIPTOR, prof, blksize,
-				BG_EC_STOP_ERR);
-		lpfc_pde_set_dif_parms(pde1, apptagmask, apptagval, reftag);
+		/* setup PDE5 with what we have */
+		pde5 = (struct lpfc_pde5 *) bpl;
+		memset(pde5, 0, sizeof(struct lpfc_pde5));
+		bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
+		pde5->reftag = reftag;
 
+		/* advance bpl and increment bde count */
+		num_bde++;
+		bpl++;
+		pde6 = (struct lpfc_pde6 *) bpl;
+
+		/* setup PDE6 with the rest of the info */
+		memset(pde6, 0, sizeof(struct lpfc_pde6));
+		bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR);
+		bf_set(pde6_optx, pde6, txop);
+		bf_set(pde6_oprx, pde6, rxop);
+		bf_set(pde6_ce, pde6, 1);
+		bf_set(pde6_re, pde6, 1);
+		bf_set(pde6_ae, pde6, 1);
+		bf_set(pde6_ai, pde6, 1);
+		bf_set(pde6_apptagval, pde6, apptagval);
+
+		/* advance bpl and increment bde count */
 		num_bde++;
 		bpl++;
 
 		/* setup the first BDE that points to protection buffer */
 		prot_bde = (struct ulp_bde64 *) bpl;
 		protphysaddr = sg_dma_address(sgpe);
-		prot_bde->addrLow = le32_to_cpu(putPaddrLow(protphysaddr));
-		prot_bde->addrHigh = le32_to_cpu(putPaddrHigh(protphysaddr));
+		prot_bde->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr));
+		prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
 		protgroup_len = sg_dma_len(sgpe);
 
 
@@ -1429,10 +1483,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 		protgrp_bytes = protgrp_blks * blksize;
 
 		prot_bde->tus.f.bdeSize = protgroup_len;
-		if (datadir == DMA_TO_DEVICE)
-			prot_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
-		else
-			prot_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
+		prot_bde->tus.f.bdeFlags = LPFC_PDE7_DESCRIPTOR;
 		prot_bde->tus.w = le32_to_cpu(bpl->tus.w);
 
 		curr_prot++;
@@ -1484,6 +1535,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
 			/* Move to the next s/g segment if possible */
 			sgde = sg_next(sgde);
+
 		}
 
 		/* are we done ? */
@@ -1506,7 +1558,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
 out:
 
-
 	return num_bde;
 }
 /*
@@ -1828,8 +1879,8 @@ out:
  * field of @lpfc_cmd for device with SLI-4 interface spec.
  *
  * Return codes:
- * 	1 - Error
- * 	0 - Success
+ *	1 - Error
+ *	0 - Success
  **/
 static int
 lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
@@ -1937,8 +1988,8 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
  * lpfc_hba struct.
  *
  * Return codes:
- * 	1 - Error
- * 	0 - Success
+ *	1 - Error
+ *	0 - Success
  **/
 static inline int
 lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)

+ 219 - 50
drivers/scsi/lpfc/lpfc_sli.c

@@ -212,7 +212,7 @@ lpfc_sli4_eq_get(struct lpfc_queue *q)
 	struct lpfc_eqe *eqe = q->qe[q->hba_index].eqe;
 
 	/* If the next EQE is not valid then we are done */
-	if (!bf_get(lpfc_eqe_valid, eqe))
+	if (!bf_get_le32(lpfc_eqe_valid, eqe))
 		return NULL;
 	/* If the host has not yet processed the next entry then we are done */
 	if (((q->hba_index + 1) % q->entry_count) == q->host_index)
@@ -247,7 +247,7 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm)
 	/* while there are valid entries */
 	while (q->hba_index != q->host_index) {
 		temp_eqe = q->qe[q->host_index].eqe;
-		bf_set(lpfc_eqe_valid, temp_eqe, 0);
+		bf_set_le32(lpfc_eqe_valid, temp_eqe, 0);
 		released++;
 		q->host_index = ((q->host_index + 1) % q->entry_count);
 	}
@@ -285,7 +285,7 @@ lpfc_sli4_cq_get(struct lpfc_queue *q)
 	struct lpfc_cqe *cqe;
 
 	/* If the next CQE is not valid then we are done */
-	if (!bf_get(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
+	if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe))
 		return NULL;
 	/* If the host has not yet processed the next entry then we are done */
 	if (((q->hba_index + 1) % q->entry_count) == q->host_index)
@@ -321,7 +321,7 @@ lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm)
 	/* while there are valid entries */
 	while (q->hba_index != q->host_index) {
 		temp_qe = q->qe[q->host_index].cqe;
-		bf_set(lpfc_cqe_valid, temp_qe, 0);
+		bf_set_le32(lpfc_cqe_valid, temp_qe, 0);
 		released++;
 		q->host_index = ((q->host_index + 1) % q->entry_count);
 	}
@@ -1659,6 +1659,8 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
 	case MBX_INIT_VPI:
 	case MBX_INIT_VFI:
 	case MBX_RESUME_RPI:
+	case MBX_READ_EVENT_LOG_STATUS:
+	case MBX_READ_EVENT_LOG:
 		ret = mbxCommand;
 		break;
 	default:
@@ -4296,7 +4298,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
 			"2570 Failed to read FCoE parameters\n");
 
 	/* Issue READ_REV to collect vpd and FW information. */
-	vpd_size = PAGE_SIZE;
+	vpd_size = SLI4_PAGE_SIZE;
 	vpd = kzalloc(vpd_size, GFP_KERNEL);
 	if (!vpd) {
 		rc = -ENOMEM;
@@ -4891,9 +4893,34 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
 	mb->mbxOwner = OWN_CHIP;
 
 	if (psli->sli_flag & LPFC_SLI_ACTIVE) {
-		/* First copy command data to host SLIM area */
+		/* Populate mbox extension offset word. */
+		if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) {
+			*(((uint32_t *)mb) + pmbox->mbox_offset_word)
+				= (uint8_t *)phba->mbox_ext
+				  - (uint8_t *)phba->mbox;
+		}
+
+		/* Copy the mailbox extension data */
+		if (pmbox->in_ext_byte_len && pmbox->context2) {
+			lpfc_sli_pcimem_bcopy(pmbox->context2,
+				(uint8_t *)phba->mbox_ext,
+				pmbox->in_ext_byte_len);
+		}
+		/* Copy command data to host SLIM area */
 		lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
 	} else {
+		/* Populate mbox extension offset word. */
+		if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len)
+			*(((uint32_t *)mb) + pmbox->mbox_offset_word)
+				= MAILBOX_HBA_EXT_OFFSET;
+
+		/* Copy the mailbox extension data */
+		if (pmbox->in_ext_byte_len && pmbox->context2) {
+			lpfc_memcpy_to_slim(phba->MBslimaddr +
+				MAILBOX_HBA_EXT_OFFSET,
+				pmbox->context2, pmbox->in_ext_byte_len);
+
+		}
 		if (mb->mbxCommand == MBX_CONFIG_PORT) {
 			/* copy command data into host mbox for cmpl */
 			lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE);
@@ -5003,15 +5030,22 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
 		if (psli->sli_flag & LPFC_SLI_ACTIVE) {
 			/* copy results back to user */
 			lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE);
+			/* Copy the mailbox extension data */
+			if (pmbox->out_ext_byte_len && pmbox->context2) {
+				lpfc_sli_pcimem_bcopy(phba->mbox_ext,
+						      pmbox->context2,
+						      pmbox->out_ext_byte_len);
+			}
 		} else {
 			/* First copy command data */
 			lpfc_memcpy_from_slim(mb, phba->MBslimaddr,
 							MAILBOX_CMD_SIZE);
-			if ((mb->mbxCommand == MBX_DUMP_MEMORY) &&
-				pmbox->context2) {
-				lpfc_memcpy_from_slim((void *)pmbox->context2,
-				      phba->MBslimaddr + DMP_RSP_OFFSET,
-						      mb->un.varDmp.word_cnt);
+			/* Copy the mailbox extension data */
+			if (pmbox->out_ext_byte_len && pmbox->context2) {
+				lpfc_memcpy_from_slim(pmbox->context2,
+					phba->MBslimaddr +
+					MAILBOX_HBA_EXT_OFFSET,
+					pmbox->out_ext_byte_len);
 			}
 		}
 
@@ -7104,13 +7138,11 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			 */
 			list_del_init(&abort_iocb->list);
 			pring->txcmplq_cnt--;
-			spin_unlock_irq(&phba->hbalock);
 
 			/* Firmware could still be in progress of DMAing
 			 * payload, so don't free data buffer till after
 			 * a hbeat.
 			 */
-			spin_lock_irq(&phba->hbalock);
 			abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;
 			abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
 			spin_unlock_irq(&phba->hbalock);
@@ -7118,7 +7150,8 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
 			abort_iocb->iocb.un.ulpWord[4] = IOERR_ABORT_REQUESTED;
 			(abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb);
-		}
+		} else
+			spin_unlock_irq(&phba->hbalock);
 	}
 
 	lpfc_sli_release_iocbq(phba, cmdiocb);
@@ -8133,6 +8166,12 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id)
 				if (pmb->mbox_cmpl) {
 					lpfc_sli_pcimem_bcopy(mbox, pmbox,
 							MAILBOX_CMD_SIZE);
+					if (pmb->out_ext_byte_len &&
+						pmb->context2)
+						lpfc_sli_pcimem_bcopy(
+						phba->mbox_ext,
+						pmb->context2,
+						pmb->out_ext_byte_len);
 				}
 				if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
 					pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
@@ -8983,17 +9022,17 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
 	int ecount = 0;
 	uint16_t cqid;
 
-	if (bf_get(lpfc_eqe_major_code, eqe) != 0) {
+	if (bf_get_le32(lpfc_eqe_major_code, eqe) != 0) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 				"0359 Not a valid slow-path completion "
 				"event: majorcode=x%x, minorcode=x%x\n",
-				bf_get(lpfc_eqe_major_code, eqe),
-				bf_get(lpfc_eqe_minor_code, eqe));
+				bf_get_le32(lpfc_eqe_major_code, eqe),
+				bf_get_le32(lpfc_eqe_minor_code, eqe));
 		return;
 	}
 
 	/* Get the reference to the corresponding CQ */
-	cqid = bf_get(lpfc_eqe_resource_id, eqe);
+	cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
 
 	/* Search for completion queue pointer matching this cqid */
 	speq = phba->sli4_hba.sp_eq;
@@ -9221,12 +9260,12 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
 	uint16_t cqid;
 	int ecount = 0;
 
-	if (unlikely(bf_get(lpfc_eqe_major_code, eqe) != 0)) {
+	if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 				"0366 Not a valid fast-path completion "
 				"event: majorcode=x%x, minorcode=x%x\n",
-				bf_get(lpfc_eqe_major_code, eqe),
-				bf_get(lpfc_eqe_minor_code, eqe));
+				bf_get_le32(lpfc_eqe_major_code, eqe),
+				bf_get_le32(lpfc_eqe_minor_code, eqe));
 		return;
 	}
 
@@ -9239,7 +9278,7 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
 	}
 
 	/* Get the reference to the corresponding CQ */
-	cqid = bf_get(lpfc_eqe_resource_id, eqe);
+	cqid = bf_get_le32(lpfc_eqe_resource_id, eqe);
 	if (unlikely(cqid != cq->queue_id)) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
 				"0368 Miss-matched fast-path completion "
@@ -9506,7 +9545,7 @@ lpfc_sli4_queue_free(struct lpfc_queue *queue)
 	while (!list_empty(&queue->page_list)) {
 		list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf,
 				 list);
-		dma_free_coherent(&queue->phba->pcidev->dev, PAGE_SIZE,
+		dma_free_coherent(&queue->phba->pcidev->dev, SLI4_PAGE_SIZE,
 				  dmabuf->virt, dmabuf->phys);
 		kfree(dmabuf);
 	}
@@ -9532,13 +9571,17 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,
 	struct lpfc_dmabuf *dmabuf;
 	int x, total_qe_count;
 	void *dma_pointer;
+	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
 
+	if (!phba->sli4_hba.pc_sli4_params.supported)
+		hw_page_size = SLI4_PAGE_SIZE;
 
 	queue = kzalloc(sizeof(struct lpfc_queue) +
 			(sizeof(union sli4_qe) * entry_count), GFP_KERNEL);
 	if (!queue)
 		return NULL;
-	queue->page_count = (PAGE_ALIGN(entry_size * entry_count))/PAGE_SIZE;
+	queue->page_count = (ALIGN(entry_size * entry_count,
+			hw_page_size))/hw_page_size;
 	INIT_LIST_HEAD(&queue->list);
 	INIT_LIST_HEAD(&queue->page_list);
 	INIT_LIST_HEAD(&queue->child_list);
@@ -9547,19 +9590,19 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,
 		if (!dmabuf)
 			goto out_fail;
 		dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev,
-						  PAGE_SIZE, &dmabuf->phys,
+						  hw_page_size, &dmabuf->phys,
 						  GFP_KERNEL);
 		if (!dmabuf->virt) {
 			kfree(dmabuf);
 			goto out_fail;
 		}
-		memset(dmabuf->virt, 0, PAGE_SIZE);
+		memset(dmabuf->virt, 0, hw_page_size);
 		dmabuf->buffer_tag = x;
 		list_add_tail(&dmabuf->list, &queue->page_list);
 		/* initialize queue's entry array */
 		dma_pointer = dmabuf->virt;
 		for (; total_qe_count < entry_count &&
-		     dma_pointer < (PAGE_SIZE + dmabuf->virt);
+		     dma_pointer < (hw_page_size + dmabuf->virt);
 		     total_qe_count++, dma_pointer += entry_size) {
 			queue->qe[total_qe_count].address = dma_pointer;
 		}
@@ -9604,6 +9647,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)
 	uint32_t shdr_status, shdr_add_status;
 	union lpfc_sli4_cfg_shdr *shdr;
 	uint16_t dmult;
+	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+
+	if (!phba->sli4_hba.pc_sli4_params.supported)
+		hw_page_size = SLI4_PAGE_SIZE;
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!mbox)
@@ -9653,6 +9700,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax)
 		break;
 	}
 	list_for_each_entry(dmabuf, &eq->page_list, list) {
+		memset(dmabuf->virt, 0, hw_page_size);
 		eq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
 					putPaddrLow(dmabuf->phys);
 		eq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
@@ -9715,6 +9763,11 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
 	int rc, length, status = 0;
 	uint32_t shdr_status, shdr_add_status;
 	union lpfc_sli4_cfg_shdr *shdr;
+	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+
+	if (!phba->sli4_hba.pc_sli4_params.supported)
+		hw_page_size = SLI4_PAGE_SIZE;
+
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!mbox)
@@ -9752,6 +9805,7 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq,
 		break;
 	}
 	list_for_each_entry(dmabuf, &cq->page_list, list) {
+		memset(dmabuf->virt, 0, hw_page_size);
 		cq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
 					putPaddrLow(dmabuf->phys);
 		cq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
@@ -9790,10 +9844,71 @@ out:
 	return status;
 }
 
+/**
+ * lpfc_mq_create_fb_init - Send MCC_CREATE without async events registration
+ * @phba: HBA structure that indicates port to create a queue on.
+ * @mq: The queue structure to use to create the mailbox queue.
+ * @mbox: An allocated pointer to type LPFC_MBOXQ_t
+ * @cq: The completion queue to associate with this cq.
+ *
+ * This function provides failback (fb) functionality when the
+ * mq_create_ext fails on older FW generations.  It's purpose is identical
+ * to mq_create_ext otherwise.
+ *
+ * This routine cannot fail as all attributes were previously accessed and
+ * initialized in mq_create_ext.
+ **/
+static void
+lpfc_mq_create_fb_init(struct lpfc_hba *phba, struct lpfc_queue *mq,
+		       LPFC_MBOXQ_t *mbox, struct lpfc_queue *cq)
+{
+	struct lpfc_mbx_mq_create *mq_create;
+	struct lpfc_dmabuf *dmabuf;
+	int length;
+
+	length = (sizeof(struct lpfc_mbx_mq_create) -
+		  sizeof(struct lpfc_sli4_cfg_mhdr));
+	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
+			 LPFC_MBOX_OPCODE_MQ_CREATE,
+			 length, LPFC_SLI4_MBX_EMBED);
+	mq_create = &mbox->u.mqe.un.mq_create;
+	bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request,
+	       mq->page_count);
+	bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context,
+	       cq->queue_id);
+	bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1);
+	switch (mq->entry_count) {
+	case 16:
+		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		       LPFC_MQ_CNT_16);
+		break;
+	case 32:
+		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		       LPFC_MQ_CNT_32);
+		break;
+	case 64:
+		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		       LPFC_MQ_CNT_64);
+		break;
+	case 128:
+		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		       LPFC_MQ_CNT_128);
+		break;
+	}
+	list_for_each_entry(dmabuf, &mq->page_list, list) {
+		mq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+			putPaddrLow(dmabuf->phys);
+		mq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+			putPaddrHigh(dmabuf->phys);
+	}
+}
+
 /**
  * lpfc_mq_create - Create a mailbox Queue on the HBA
  * @phba: HBA structure that indicates port to create a queue on.
  * @mq: The queue structure to use to create the mailbox queue.
+ * @cq: The completion queue to associate with this cq.
+ * @subtype: The queue's subtype.
  *
  * This function creates a mailbox queue, as detailed in @mq, on a port,
  * described by @phba by sending a MQ_CREATE mailbox command to the HBA.
@@ -9809,31 +9924,43 @@ out:
  * memory this function will return ENOMEM. If the queue create mailbox command
  * fails this function will return ENXIO.
  **/
-uint32_t
+int32_t
 lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
 	       struct lpfc_queue *cq, uint32_t subtype)
 {
 	struct lpfc_mbx_mq_create *mq_create;
+	struct lpfc_mbx_mq_create_ext *mq_create_ext;
 	struct lpfc_dmabuf *dmabuf;
 	LPFC_MBOXQ_t *mbox;
 	int rc, length, status = 0;
 	uint32_t shdr_status, shdr_add_status;
 	union lpfc_sli4_cfg_shdr *shdr;
+	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+
+	if (!phba->sli4_hba.pc_sli4_params.supported)
+		hw_page_size = SLI4_PAGE_SIZE;
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!mbox)
 		return -ENOMEM;
-	length = (sizeof(struct lpfc_mbx_mq_create) -
+	length = (sizeof(struct lpfc_mbx_mq_create_ext) -
 		  sizeof(struct lpfc_sli4_cfg_mhdr));
 	lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON,
-			 LPFC_MBOX_OPCODE_MQ_CREATE,
+			 LPFC_MBOX_OPCODE_MQ_CREATE_EXT,
 			 length, LPFC_SLI4_MBX_EMBED);
-	mq_create = &mbox->u.mqe.un.mq_create;
-	bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request,
+
+	mq_create_ext = &mbox->u.mqe.un.mq_create_ext;
+	bf_set(lpfc_mbx_mq_create_ext_num_pages, &mq_create_ext->u.request,
 		    mq->page_count);
-	bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context,
-		    cq->queue_id);
-	bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1);
+	bf_set(lpfc_mbx_mq_create_ext_async_evt_link, &mq_create_ext->u.request,
+	       1);
+	bf_set(lpfc_mbx_mq_create_ext_async_evt_fcfste,
+	       &mq_create_ext->u.request, 1);
+	bf_set(lpfc_mbx_mq_create_ext_async_evt_group5,
+	       &mq_create_ext->u.request, 1);
+	bf_set(lpfc_mq_context_cq_id, &mq_create_ext->u.request.context,
+	       cq->queue_id);
+	bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1);
 	switch (mq->entry_count) {
 	default:
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
@@ -9843,31 +9970,47 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
 			return -EINVAL;
 		/* otherwise default to smallest count (drop through) */
 	case 16:
-		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
 		       LPFC_MQ_CNT_16);
 		break;
 	case 32:
-		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
 		       LPFC_MQ_CNT_32);
 		break;
 	case 64:
-		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
 		       LPFC_MQ_CNT_64);
 		break;
 	case 128:
-		bf_set(lpfc_mq_context_count, &mq_create->u.request.context,
+		bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context,
 		       LPFC_MQ_CNT_128);
 		break;
 	}
 	list_for_each_entry(dmabuf, &mq->page_list, list) {
-		mq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
+		memset(dmabuf->virt, 0, hw_page_size);
+		mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_lo =
 					putPaddrLow(dmabuf->phys);
-		mq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
+		mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_hi =
 					putPaddrHigh(dmabuf->phys);
 	}
 	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	shdr = (union lpfc_sli4_cfg_shdr *) &mq_create_ext->header.cfg_shdr;
+	mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id,
+			      &mq_create_ext->u.response);
+	if (rc != MBX_SUCCESS) {
+		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"2795 MQ_CREATE_EXT failed with "
+				"status x%x. Failback to MQ_CREATE.\n",
+				rc);
+		lpfc_mq_create_fb_init(phba, mq, mbox, cq);
+		mq_create = &mbox->u.mqe.un.mq_create;
+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+		shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr;
+		mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id,
+				      &mq_create->u.response);
+	}
+
 	/* The IOCTL status is embedded in the mailbox subheader. */
-	shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr;
 	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
 	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
 	if (shdr_status || shdr_add_status || rc) {
@@ -9878,7 +10021,6 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq,
 		status = -ENXIO;
 		goto out;
 	}
-	mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, &mq_create->u.response);
 	if (mq->queue_id == 0xFFFF) {
 		status = -ENXIO;
 		goto out;
@@ -9927,6 +10069,10 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
 	int rc, length, status = 0;
 	uint32_t shdr_status, shdr_add_status;
 	union lpfc_sli4_cfg_shdr *shdr;
+	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+
+	if (!phba->sli4_hba.pc_sli4_params.supported)
+		hw_page_size = SLI4_PAGE_SIZE;
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!mbox)
@@ -9942,6 +10088,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
 	bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request,
 		    cq->queue_id);
 	list_for_each_entry(dmabuf, &wq->page_list, list) {
+		memset(dmabuf->virt, 0, hw_page_size);
 		wq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
 					putPaddrLow(dmabuf->phys);
 		wq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
@@ -10010,6 +10157,10 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 	int rc, length, status = 0;
 	uint32_t shdr_status, shdr_add_status;
 	union lpfc_sli4_cfg_shdr *shdr;
+	uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz;
+
+	if (!phba->sli4_hba.pc_sli4_params.supported)
+		hw_page_size = SLI4_PAGE_SIZE;
 
 	if (hrq->entry_count != drq->entry_count)
 		return -EINVAL;
@@ -10054,6 +10205,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
 	bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context,
 	       LPFC_HDR_BUF_SIZE);
 	list_for_each_entry(dmabuf, &hrq->page_list, list) {
+		memset(dmabuf->virt, 0, hw_page_size);
 		rq_create->u.request.page[dmabuf->buffer_tag].addr_lo =
 					putPaddrLow(dmabuf->phys);
 		rq_create->u.request.page[dmabuf->buffer_tag].addr_hi =
@@ -10626,7 +10778,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba)
 
 	reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) +
 		 sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
-	if (reqlen > PAGE_SIZE) {
+	if (reqlen > SLI4_PAGE_SIZE) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 				"2559 Block sgl registration required DMA "
 				"size (%d) great than a page\n", reqlen);
@@ -10732,7 +10884,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist,
 	/* Calculate the requested length of the dma memory */
 	reqlen = cnt * sizeof(struct sgl_page_pairs) +
 		 sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t);
-	if (reqlen > PAGE_SIZE) {
+	if (reqlen > SLI4_PAGE_SIZE) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 				"0217 Block sgl registration required DMA "
 				"size (%d) great than a page\n", reqlen);
@@ -11568,8 +11720,8 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba,
  *
  * This routine is invoked to post rpi header templates to the
  * HBA consistent with the SLI-4 interface spec.  This routine
- * posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers.
+ * posts a SLI4_PAGE_SIZE memory region to the port to hold up to
+ * SLI4_PAGE_SIZE modulo 64 rpi context headers.
  *
  * This routine does not require any locks.  It's usage is expected
  * to be driver load or reset recovery when the driver is
@@ -11672,8 +11824,8 @@ lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page)
  *
  * This routine is invoked to post rpi header templates to the
  * HBA consistent with the SLI-4 interface spec.  This routine
- * posts a PAGE_SIZE memory region to the port to hold up to
- * PAGE_SIZE modulo 64 rpi context headers.
+ * posts a SLI4_PAGE_SIZE memory region to the port to hold up to
+ * SLI4_PAGE_SIZE modulo 64 rpi context headers.
  *
  * Returns
  * 	A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful
@@ -12040,9 +12192,11 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index)
 		phba->hba_flag |= FCF_DISC_INPROGRESS;
 		spin_unlock_irq(&phba->hbalock);
 		/* Reset FCF round robin index bmask for new scan */
-		if (fcf_index == LPFC_FCOE_FCF_GET_FIRST)
+		if (fcf_index == LPFC_FCOE_FCF_GET_FIRST) {
 			memset(phba->fcf.fcf_rr_bmask, 0,
 			       sizeof(*phba->fcf.fcf_rr_bmask));
+			phba->fcf.eligible_fcf_cnt = 0;
+		}
 		error = 0;
 	}
 fail_fcf_scan:
@@ -12507,6 +12661,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
 	struct lpfc_hba *phba = vport->phba;
 	LPFC_MBOXQ_t *mb, *nextmb;
 	struct lpfc_dmabuf *mp;
+	struct lpfc_nodelist *ndlp;
 
 	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
@@ -12523,6 +12678,11 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
 				__lpfc_mbuf_free(phba, mp->virt, mp->phys);
 				kfree(mp);
 			}
+			ndlp = (struct lpfc_nodelist *) mb->context2;
+			if (ndlp) {
+				lpfc_nlp_put(ndlp);
+				mb->context2 = NULL;
+			}
 		}
 		list_del(&mb->list);
 		mempool_free(mb, phba->mbox_mem_pool);
@@ -12532,6 +12692,15 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
 		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) ||
 			(mb->u.mb.mbxCommand == MBX_REG_VPI))
 			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+		if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+			ndlp = (struct lpfc_nodelist *) mb->context2;
+			if (ndlp) {
+				lpfc_nlp_put(ndlp);
+				mb->context2 = NULL;
+			}
+			/* Unregister the RPI when mailbox complete */
+			mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
+		}
 	}
 	spin_unlock_irq(&phba->hbalock);
 }

+ 4 - 0
drivers/scsi/lpfc/lpfc_sli.h

@@ -36,6 +36,7 @@ struct lpfc_cq_event {
 		struct lpfc_acqe_link		acqe_link;
 		struct lpfc_acqe_fcoe		acqe_fcoe;
 		struct lpfc_acqe_dcbx		acqe_dcbx;
+		struct lpfc_acqe_grp5		acqe_grp5;
 		struct lpfc_rcqe		rcqe_cmpl;
 		struct sli4_wcqe_xri_aborted	wcqe_axri;
 		struct lpfc_wcqe_complete	wcqe_cmpl;
@@ -110,6 +111,9 @@ typedef struct lpfcMboxq {
 
 	void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
 	uint8_t mbox_flag;
+	uint16_t in_ext_byte_len;
+	uint16_t out_ext_byte_len;
+	uint8_t  mbox_offset_word;
 	struct lpfc_mcqe mcqe;
 	struct lpfc_mbx_nembed_sge_virt *sge_array;
 } LPFC_MBOXQ_t;

+ 3 - 2
drivers/scsi/lpfc/lpfc_sli4.h

@@ -162,6 +162,7 @@ struct lpfc_fcf {
 #define FCF_REDISC_FOV	0x200 /* Post FCF rediscovery fast failover */
 	uint32_t addr_mode;
 	uint16_t fcf_rr_init_indx;
+	uint32_t eligible_fcf_cnt;
 	struct lpfc_fcf_rec current_rec;
 	struct lpfc_fcf_rec failover_rec;
 	struct timer_list redisc_wait;
@@ -492,8 +493,8 @@ void lpfc_sli4_queue_free(struct lpfc_queue *);
 uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t);
 uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *,
 			struct lpfc_queue *, uint32_t, uint32_t);
-uint32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *,
-			struct lpfc_queue *, uint32_t);
+int32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *,
+		       struct lpfc_queue *, uint32_t);
 uint32_t lpfc_wq_create(struct lpfc_hba *, struct lpfc_queue *,
 			struct lpfc_queue *, uint32_t);
 uint32_t lpfc_rq_create(struct lpfc_hba *, struct lpfc_queue *,

+ 1 - 1
drivers/scsi/lpfc/lpfc_version.h

@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.10"
+#define LPFC_DRIVER_VERSION "8.3.12"
 #define LPFC_DRIVER_NAME		"lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME	"lpfc:sp"
 #define LPFC_FP_DRIVER_HANDLER_NAME	"lpfc:fp"

+ 3 - 1
drivers/scsi/lpfc/lpfc_vport.c

@@ -763,7 +763,9 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
 	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry(port_iterator, &phba->port_list, listentry) {
 		if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) {
-			lpfc_printf_vlog(port_iterator, KERN_WARNING, LOG_VPORT,
+			if (!(port_iterator->load_flag & FC_UNLOADING))
+				lpfc_printf_vlog(port_iterator, KERN_ERR,
+					 LOG_VPORT,
 					 "1801 Create vport work array FAILED: "
 					 "cannot do scsi_host_get\n");
 			continue;

+ 1 - 1
drivers/scsi/mpt2sas/Kconfig

@@ -2,7 +2,7 @@
 # Kernel configuration file for the MPT2SAS
 #
 # This code is based on drivers/scsi/mpt2sas/Kconfig
-# Copyright (C) 2007-2009  LSI Corporation
+# Copyright (C) 2007-2010  LSI Corporation
 #  (mailto:DL-MPTFusionLinux@lsi.com)
 
 # This program is free software; you can redistribute it and/or

+ 1 - 1
drivers/scsi/mpt2sas/mpi/mpi2.h

@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2010 LSI Corporation.
  *
  *
  *           Name:  mpi2.h

+ 1 - 1
drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h

@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2010 LSI Corporation.
  *
  *
  *           Name:  mpi2_cnfg.h

+ 1 - 1
drivers/scsi/mpt2sas/mpi/mpi2_history.txt

@@ -2,7 +2,7 @@
  Fusion-MPT MPI 2.0 Header File Change History
  ==============================
 
- Copyright (c) 2000-2009 LSI Corporation.
+ Copyright (c) 2000-2010 LSI Corporation.
 
  ---------------------------------------
  Header Set Release Version:    02.00.14

+ 1 - 1
drivers/scsi/mpt2sas/mpi/mpi2_init.h

@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2010 LSI Corporation.
  *
  *
  *           Name:  mpi2_init.h

+ 1 - 1
drivers/scsi/mpt2sas/mpi/mpi2_ioc.h

@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2010 LSI Corporation.
  *
  *
  *           Name:  mpi2_ioc.h

+ 1 - 1
drivers/scsi/mpt2sas/mpi/mpi2_tool.h

@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2009 LSI Corporation.
+ *  Copyright (c) 2000-2010 LSI Corporation.
  *
  *
  *           Name:  mpi2_tool.h

+ 66 - 24
drivers/scsi/mpt2sas/mpt2sas_base.c

@@ -3,7 +3,7 @@
  * for access to MPT (Message Passing Technology) firmware.
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -58,6 +58,7 @@
 #include <linux/sort.h>
 #include <linux/io.h>
 #include <linux/time.h>
+#include <linux/aer.h>
 
 #include "mpt2sas_base.h"
 
@@ -285,6 +286,9 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
 	    request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)
 		return;
 
+	if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+		return;
+
 	switch (ioc_status) {
 
 /****************************************************************************
@@ -517,8 +521,18 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
 		desc = "IR Operation Status";
 		break;
 	case MPI2_EVENT_SAS_DISCOVERY:
-		desc =  "Discovery";
-		break;
+	{
+		Mpi2EventDataSasDiscovery_t *event_data =
+		    (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData;
+		printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name,
+		    (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
+		    "start" : "stop");
+		if (event_data->DiscoveryStatus)
+			printk("discovery_status(0x%08x)",
+			    le32_to_cpu(event_data->DiscoveryStatus));
+			printk("\n");
+		return;
+	}
 	case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
 		desc = "SAS Broadcast Primitive";
 		break;
@@ -1243,6 +1257,9 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
 		goto out_fail;
 	}
 
+	/* AER (Advanced Error Reporting) hooks */
+	pci_enable_pcie_error_reporting(pdev);
+
 	pci_set_master(pdev);
 
 	if (_base_config_dma_addressing(ioc, pdev) != 0) {
@@ -1253,7 +1270,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
 	}
 
 	for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) {
-		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO) {
+		if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
 			if (pio_sz)
 				continue;
 			pio_chip = (u64)pci_resource_start(pdev, i);
@@ -1261,15 +1278,18 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
 		} else {
 			if (memap_sz)
 				continue;
-			ioc->chip_phys = pci_resource_start(pdev, i);
-			chip_phys = (u64)ioc->chip_phys;
-			memap_sz = pci_resource_len(pdev, i);
-			ioc->chip = ioremap(ioc->chip_phys, memap_sz);
-			if (ioc->chip == NULL) {
-				printk(MPT2SAS_ERR_FMT "unable to map adapter "
-				    "memory!\n", ioc->name);
-				r = -EINVAL;
-				goto out_fail;
+			/* verify memory resource is valid before using */
+			if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+				ioc->chip_phys = pci_resource_start(pdev, i);
+				chip_phys = (u64)ioc->chip_phys;
+				memap_sz = pci_resource_len(pdev, i);
+				ioc->chip = ioremap(ioc->chip_phys, memap_sz);
+				if (ioc->chip == NULL) {
+					printk(MPT2SAS_ERR_FMT "unable to map "
+					    "adapter memory!\n", ioc->name);
+					r = -EINVAL;
+					goto out_fail;
+				}
 			}
 		}
 	}
@@ -1295,6 +1315,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
 	ioc->chip_phys = 0;
 	ioc->pci_irq = -1;
 	pci_release_selected_regions(ioc->pdev, ioc->bars);
+	pci_disable_pcie_error_reporting(pdev);
 	pci_disable_device(pdev);
 	return r;
 }
@@ -1898,7 +1919,10 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 		    ioc->config_page, ioc->config_page_dma);
 	}
 
-	kfree(ioc->scsi_lookup);
+	if (ioc->scsi_lookup) {
+		free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages);
+		ioc->scsi_lookup = NULL;
+	}
 	kfree(ioc->hpr_lookup);
 	kfree(ioc->internal_lookup);
 }
@@ -2110,11 +2134,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
 	    ioc->name, (unsigned long long) ioc->request_dma));
 	total_sz += sz;
 
-	ioc->scsi_lookup = kcalloc(ioc->scsiio_depth,
-	    sizeof(struct request_tracker), GFP_KERNEL);
+	sz = ioc->scsiio_depth * sizeof(struct request_tracker);
+	ioc->scsi_lookup_pages = get_order(sz);
+	ioc->scsi_lookup = (struct request_tracker *)__get_free_pages(
+	    GFP_KERNEL, ioc->scsi_lookup_pages);
 	if (!ioc->scsi_lookup) {
-		printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n",
-		    ioc->name);
+		printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, "
+		    "sz(%d)\n", ioc->name, (int)sz);
 		goto out;
 	}
 
@@ -3006,8 +3032,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	 * since epoch ~ midnight January 1, 1970.
 	 */
 	do_gettimeofday(&current_time);
-	mpi_request.TimeStamp = (current_time.tv_sec * 1000) +
-	    (current_time.tv_usec >> 3);
+	mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 +
+	    (current_time.tv_usec / 1000));
 
 	if (ioc->logging_level & MPT_DEBUG_INIT) {
 		u32 *mfp;
@@ -3179,7 +3205,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	mpi_request->VP_ID = 0;
 	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
 		mpi_request->EventMasks[i] =
-		    le32_to_cpu(ioc->event_masks[i]);
+		    cpu_to_le32(ioc->event_masks[i]);
 	mpt2sas_base_put_smid_default(ioc, smid);
 	init_completion(&ioc->base_cmds.done);
 	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
@@ -3516,7 +3542,9 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
 	    __func__));
 
 	_base_mask_interrupts(ioc);
+	ioc->shost_recovery = 1;
 	_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
+	ioc->shost_recovery = 0;
 	if (ioc->pci_irq) {
 		synchronize_irq(pdev->irq);
 		free_irq(ioc->pci_irq, ioc);
@@ -3527,6 +3555,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
 	ioc->pci_irq = -1;
 	ioc->chip_phys = 0;
 	pci_release_selected_regions(ioc->pdev, ioc->bars);
+	pci_disable_pcie_error_reporting(pdev);
 	pci_disable_device(pdev);
 	return;
 }
@@ -3560,8 +3589,10 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
 
 	ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
 	    sizeof(Mpi2PortFactsReply_t), GFP_KERNEL);
-	if (!ioc->pfacts)
+	if (!ioc->pfacts) {
+		r = -ENOMEM;
 		goto out_free_resources;
+	}
 
 	for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
 		r = _base_get_port_facts(ioc, i, CAN_SLEEP);
@@ -3607,6 +3638,15 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
 	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
 	mutex_init(&ioc->ctl_cmds.mutex);
 
+	if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
+	    !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
+	    !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) {
+		r = -ENOMEM;
+		goto out_free_resources;
+	}
+
+	init_completion(&ioc->shost_recovery_done);
+
 	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
 		ioc->event_masks[i] = -1;
 
@@ -3639,6 +3679,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
 	pci_set_drvdata(ioc->pdev, NULL);
 	kfree(ioc->tm_cmds.reply);
 	kfree(ioc->transport_cmds.reply);
+	kfree(ioc->scsih_cmds.reply);
 	kfree(ioc->config_cmds.reply);
 	kfree(ioc->base_cmds.reply);
 	kfree(ioc->ctl_cmds.reply);
@@ -3646,6 +3687,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
 	ioc->ctl_cmds.reply = NULL;
 	ioc->base_cmds.reply = NULL;
 	ioc->tm_cmds.reply = NULL;
+	ioc->scsih_cmds.reply = NULL;
 	ioc->transport_cmds.reply = NULL;
 	ioc->config_cmds.reply = NULL;
 	ioc->pfacts = NULL;
@@ -3675,6 +3717,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
 	kfree(ioc->base_cmds.reply);
 	kfree(ioc->tm_cmds.reply);
 	kfree(ioc->transport_cmds.reply);
+	kfree(ioc->scsih_cmds.reply);
 	kfree(ioc->config_cmds.reply);
 }
 
@@ -3811,9 +3854,8 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
 
 	spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
 	ioc->shost_recovery = 0;
+	complete(&ioc->shost_recovery_done);
 	spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
 
-	if (!r)
-		_base_reset_handler(ioc, MPT2_IOC_RUNNING);
 	return r;
 }

+ 14 - 22
drivers/scsi/mpt2sas/mpt2sas_base.h

@@ -3,7 +3,7 @@
  * for access to MPT (Message Passing Technology) firmware.
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.h
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -69,11 +69,11 @@
 #define MPT2SAS_DRIVER_NAME		"mpt2sas"
 #define MPT2SAS_AUTHOR	"LSI Corporation <DL-MPTFusionLinux@lsi.com>"
 #define MPT2SAS_DESCRIPTION	"LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION		"04.100.01.00"
-#define MPT2SAS_MAJOR_VERSION		04
+#define MPT2SAS_DRIVER_VERSION		"05.100.00.02"
+#define MPT2SAS_MAJOR_VERSION		05
 #define MPT2SAS_MINOR_VERSION		100
-#define MPT2SAS_BUILD_VERSION		01
-#define MPT2SAS_RELEASE_VERSION		00
+#define MPT2SAS_BUILD_VERSION		00
+#define MPT2SAS_RELEASE_VERSION		02
 
 /*
  * Set MPT2SAS_SG_DEPTH value based on user input.
@@ -119,7 +119,6 @@
 #define MPT2_IOC_PRE_RESET		1 /* prior to host reset */
 #define MPT2_IOC_AFTER_RESET		2 /* just after host reset */
 #define MPT2_IOC_DONE_RESET		3 /* links re-initialized */
-#define MPT2_IOC_RUNNING		4 /* shost running */
 
 /*
  * logging format
@@ -260,16 +259,6 @@ struct _internal_cmd {
 	u16	smid;
 };
 
-/*
- * SAS Topology Structures
- */
-
-#define MPTSAS_STATE_TR_SEND		0x0001
-#define MPTSAS_STATE_TR_COMPLETE	0x0002
-#define MPTSAS_STATE_CNTRL_SEND		0x0004
-#define MPTSAS_STATE_CNTRL_COMPLETE	0x0008
-
-#define MPT2SAS_REQ_SAS_CNTRL		0x0010
 
 /**
  * struct _sas_device - attached device information
@@ -307,7 +296,6 @@ struct _sas_device {
 	u16	slot;
 	u8	hidden_raid_component;
 	u8	responding;
-	u16	state;
 };
 
 /**
@@ -378,6 +366,7 @@ struct _sas_port {
  * @phy_id: unique phy id
  * @handle: device handle for this phy
  * @attached_handle: device handle for attached device
+ * @phy_belongs_to_port: port has been created for this phy
  */
 struct _sas_phy {
 	struct list_head port_siblings;
@@ -387,6 +376,7 @@ struct _sas_phy {
 	u8	phy_id;
 	u16	handle;
 	u16	attached_handle;
+	u8	phy_belongs_to_port;
 };
 
 /**
@@ -603,7 +593,6 @@ struct MPT2SAS_ADAPTER {
 	/* fw event handler */
 	char		firmware_event_name[20];
 	struct workqueue_struct	*firmware_event_thread;
-	u8		fw_events_off;
 	spinlock_t	fw_event_lock;
 	struct list_head fw_event_list;
 
@@ -611,6 +600,7 @@ struct MPT2SAS_ADAPTER {
 	int		aen_event_read_flag;
 	u8		broadcast_aen_busy;
 	u8		shost_recovery;
+	struct completion	shost_recovery_done;
 	spinlock_t 	ioc_reset_in_progress_lock;
 	u8		ioc_link_reset_in_progress;
 	u8		ignore_loginfos;
@@ -688,7 +678,8 @@ struct MPT2SAS_ADAPTER {
 	dma_addr_t	request_dma;
 	u32		request_dma_sz;
 	struct request_tracker *scsi_lookup;
-	spinlock_t scsi_lookup_lock;
+	ulong		scsi_lookup_pages;
+	spinlock_t 	scsi_lookup_lock;
 	struct list_head free_list;
 	int		pending_io_count;
 	wait_queue_head_t reset_wq;
@@ -700,7 +691,7 @@ struct MPT2SAS_ADAPTER {
 	u16		max_sges_in_chain_message;
 	u16		chains_needed_per_io;
 	u16		chain_offset_value_for_main_message;
-	u16		chain_depth;
+	u32		chain_depth;
 
 	/* hi-priority queue */
 	u16		hi_priority_smid;
@@ -814,8 +805,9 @@ void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc);
 /* scsih shared API */
 u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
     u32 reply);
-void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
-    u8 type, u16 smid_task, ulong timeout);
+int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
+    uint channel, uint id, uint lun, u8 type, u16 smid_task,
+    ulong timeout, struct scsi_cmnd *scmd);
 void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
 void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
 struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,

+ 4 - 4
drivers/scsi/mpt2sas/mpt2sas_config.c

@@ -2,7 +2,7 @@
  * This module provides common API for accessing firmware configuration pages
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -1390,12 +1390,12 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
 		goto out;
 	for (i = 0; i < config_page->NumElements; i++) {
-		if ((config_page->ConfigElement[i].ElementFlags &
+		if ((le16_to_cpu(config_page->ConfigElement[i].ElementFlags) &
 		    MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) !=
 		    MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT)
 			continue;
-		if (config_page->ConfigElement[i].PhysDiskDevHandle ==
-		    pd_handle) {
+		if (le16_to_cpu(config_page->ConfigElement[i].
+		    PhysDiskDevHandle) == pd_handle) {
 			*volume_handle = le16_to_cpu(config_page->
 			    ConfigElement[i].VolDevHandle);
 			r = 0;

+ 26 - 20
drivers/scsi/mpt2sas/mpt2sas_ctl.c

@@ -3,7 +3,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -533,7 +533,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
 	if (!found) {
 		dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
 		    "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
-		    desc, tm_request->DevHandle, lun));
+		    desc, le16_to_cpu(tm_request->DevHandle), lun));
 		tm_reply = ioc->ctl_cmds.reply;
 		tm_reply->DevHandle = tm_request->DevHandle;
 		tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
@@ -551,7 +551,8 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
 
 	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
 	    "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,
-	    desc, tm_request->DevHandle, lun, tm_request->TaskMID));
+	    desc, le16_to_cpu(tm_request->DevHandle), lun,
+	     le16_to_cpu(tm_request->TaskMID)));
 	return 0;
 }
 
@@ -647,9 +648,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
 
 	if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
 	    mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
-		if (!mpi_request->FunctionDependent1 ||
-		    mpi_request->FunctionDependent1 >
-		    cpu_to_le16(ioc->facts.MaxDevHandle)) {
+		if (!le16_to_cpu(mpi_request->FunctionDependent1) ||
+		    le16_to_cpu(mpi_request->FunctionDependent1) >
+		    ioc->facts.MaxDevHandle) {
 			ret = -EINVAL;
 			mpt2sas_base_free_smid(ioc, smid);
 			goto out;
@@ -743,8 +744,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
 		    mpt2sas_base_get_sense_buffer_dma(ioc, smid);
 		priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
 		memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
-		mpt2sas_base_put_smid_scsi_io(ioc, smid,
-		    le16_to_cpu(mpi_request->FunctionDependent1));
+		if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
+			mpt2sas_base_put_smid_scsi_io(ioc, smid,
+			    le16_to_cpu(mpi_request->FunctionDependent1));
+		else
+			mpt2sas_base_put_smid_default(ioc, smid);
 		break;
 	}
 	case MPI2_FUNCTION_SCSI_TASK_MGMT:
@@ -752,6 +756,10 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
 		Mpi2SCSITaskManagementRequest_t *tm_request =
 		    (Mpi2SCSITaskManagementRequest_t *)mpi_request;
 
+		dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
+		    "handle(0x%04x), task_type(0x%02x)\n", ioc->name,
+		    le16_to_cpu(tm_request->DevHandle), tm_request->TaskType));
+
 		if (tm_request->TaskType ==
 		    MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||
 		    tm_request->TaskType ==
@@ -762,7 +770,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
 			}
 		}
 
-		mutex_lock(&ioc->tm_cmds.mutex);
 		mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(
 		    tm_request->DevHandle));
 		mpt2sas_base_put_smid_hi_priority(ioc, smid);
@@ -818,7 +825,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
 	if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
 		Mpi2SCSITaskManagementRequest_t *tm_request =
 		    (Mpi2SCSITaskManagementRequest_t *)mpi_request;
-		mutex_unlock(&ioc->tm_cmds.mutex);
 		mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu(
 		    tm_request->DevHandle));
 	} else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH ||
@@ -897,14 +903,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
 		    MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
 			printk(MPT2SAS_INFO_FMT "issue target reset: handle "
 			    "= (0x%04x)\n", ioc->name,
-			    mpi_request->FunctionDependent1);
+			    le16_to_cpu(mpi_request->FunctionDependent1));
 			mpt2sas_halt_firmware(ioc);
-			mutex_lock(&ioc->tm_cmds.mutex);
 			mpt2sas_scsih_issue_tm(ioc,
-			    mpi_request->FunctionDependent1, 0,
-			    MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10);
+			    le16_to_cpu(mpi_request->FunctionDependent1), 0, 0,
+			    0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10,
+			    NULL);
 			ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
-			mutex_unlock(&ioc->tm_cmds.mutex);
 		} else
 			mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
 			    FORCE_BIG_HAMMER);
@@ -1373,7 +1378,8 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
 
 	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "
 	    "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
-	    (unsigned long long)request_data_dma, mpi_request->BufferLength));
+	    (unsigned long long)request_data_dma,
+	    le32_to_cpu(mpi_request->BufferLength)));
 
 	for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
 		mpi_request->ProductSpecific[i] =
@@ -2334,8 +2340,8 @@ _ctl_version_nvdata_persistent_show(struct device *cdev,
 	struct Scsi_Host *shost = class_to_shost(cdev);
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
 
-	return snprintf(buf, PAGE_SIZE, "%02xh\n",
-	    le16_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
+	return snprintf(buf, PAGE_SIZE, "%08xh\n",
+	    le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
 }
 static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
     _ctl_version_nvdata_persistent_show, NULL);
@@ -2354,8 +2360,8 @@ _ctl_version_nvdata_default_show(struct device *cdev,
 	struct Scsi_Host *shost = class_to_shost(cdev);
 	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
 
-	return snprintf(buf, PAGE_SIZE, "%02xh\n",
-	    le16_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
+	return snprintf(buf, PAGE_SIZE, "%08xh\n",
+	    le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
 }
 static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
     _ctl_version_nvdata_default_show, NULL);

+ 1 - 1
drivers/scsi/mpt2sas/mpt2sas_ctl.h

@@ -3,7 +3,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or

+ 1 - 1
drivers/scsi/mpt2sas/mpt2sas_debug.h

@@ -2,7 +2,7 @@
  * Logging Support for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
- * Copyright (C) 2007-2009  LSI Corporation
+ * Copyright (C) 2007-2010  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác