Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3483

kernel-2.6.18-194.11.1.el5.src.rpm

From: Rob Evers <revers@redhat.com>
Date: Thu, 25 Jun 2009 15:28:03 -0400
Subject: [scsi] lpfc: update to version 8.2.0.46
Message-id: 20090625192352.15255.13183.sendpatchset@localhost.localdomain
O-Subject: [RHEL5.4 PATCH 1/1] lpfc: Update from version 8.2.0.45 to version 8.2.0.46
Bugzilla: 506792
RH-Acked-by: Tomas Henzl <thenzl@redhat.com>

https://bugzilla.redhat.com/show_bug.cgi?id=506792

Description:

    Update lpfc from 8.2.0.45 to 8.2.0.46

    * Changed version number to 8.2.0.46
    * Remove always true conditional in lpfc_sli_read_serdes_param()
    * Update resume_rpi mailbox data structure to match spec
    * Rework/cleanup EH entry points to be consistent with upstream
      implementation
    * Fixed lpfcdfc_host leak when lpfc_pci_remove_one_s4 called or init error
      occurs
    * Use PCI config space register to determine SLI rev of HBA
    * Fixed crash when sending CT commands from libdfc
    * Fixed mailbox timeout during HBA reset
    * Fixed SLI4 HBAs not accessible from /dev/lpfcdfc
    * Show persistent link down state in link_state sysfs attribute
    * Fix for firmware dump failure (CR 90533)

Upstream Status:

    Mostly bug fixes.
    One section is synchronizing with upstream for EH entry points.

Testing:

    Brew-built across all architectures
    Loaded driver on ia64 (this testing helped resolve bz506968).
    Currently running overnight dt testing on an FC lpfc adapter.

--

diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 37bae16..6e62128 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -344,7 +344,12 @@ lpfc_state_show(struct class_device *cdev, char *buf)
 	case LPFC_INIT_MBX_CMDS:
 	case LPFC_LINK_DOWN:
 	case LPFC_HBA_ERROR:
-		len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n");
+		if (phba->hba_flag & LINK_DISABLED)
+			len += snprintf(buf + len, PAGE_SIZE-len,
+				"Link Down - User disabled\n");
+		else
+			len += snprintf(buf + len, PAGE_SIZE-len,
+				"Link Down\n");
 		break;
 	case LPFC_LINK_UP:
 	case LPFC_CLEAR_LA:
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 4dae439..1cb37e0 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -54,6 +54,31 @@ struct dma_address {
 	uint32_t addr_hi;
 };
 
+#define LPFC_SLIREV_CONF_WORD	0x58
+struct lpfc_sli_intf {
+	uint32_t word0;
+#define lpfc_sli_intf_iftype_MASK 	0x00000007
+#define lpfc_sli_intf_iftype_SHIFT	0
+#define lpfc_sli_intf_iftype_WORD	word0
+#define lpfc_sli_intf_rev_MASK 		0x0000000f
+#define lpfc_sli_intf_rev_SHIFT		4
+#define lpfc_sli_intf_rev_WORD		word0
+#define LPFC_SLIREV_CONF_SLI4	4
+#define lpfc_sli_intf_family_MASK 	0x000000ff
+#define lpfc_sli_intf_family_SHIFT	8
+#define lpfc_sli_intf_family_WORD	word0
+#define lpfc_sli_intf_feat1_MASK 	0x000000ff
+#define lpfc_sli_intf_feat1_SHIFT	16
+#define lpfc_sli_intf_feat1_WORD	word0
+#define lpfc_sli_intf_feat2_MASK 	0x0000001f
+#define lpfc_sli_intf_feat2_SHIFT	24
+#define lpfc_sli_intf_feat2_WORD	word0
+#define lpfc_sli_intf_valid_MASK 	0x00000007
+#define lpfc_sli_intf_valid_SHIFT	29
+#define lpfc_sli_intf_valid_WORD	word0
+#define LPFC_SLI_INTF_VALID		6
+};
+
 #define LPFC_SLI4_BAR0		1
 #define LPFC_SLI4_BAR1		2
 #define LPFC_SLI4_BAR2		4
@@ -1413,20 +1438,17 @@ struct lpfc_mbx_unreg_vfi {
 
 struct lpfc_mbx_resume_rpi {
 	uint32_t word1;
-#define lpfc_resume_rpi_rpi_SHIFT	0
-#define lpfc_resume_rpi_rpi_MASK	0x0000FFFF
-#define lpfc_resume_rpi_rpi_WORD	word1
+#define lpfc_resume_rpi_index_SHIFT	0
+#define lpfc_resume_rpi_index_MASK	0x0000FFFF
+#define lpfc_resume_rpi_index_WORD	word1
+#define lpfc_resume_rpi_ii_SHIFT	30
+#define lpfc_resume_rpi_ii_MASK		0x00000003
+#define lpfc_resume_rpi_ii_WORD		word1
+#define RESUME_INDEX_RPI		0
+#define RESUME_INDEX_VPI		1
+#define RESUME_INDEX_VFI		2
+#define RESUME_INDEX_FCFI		3
 	uint32_t event_tag;
-	uint32_t word3_rsvd;
-	uint32_t word4_rsvd;
-	uint32_t word5_rsvd;
-	uint32_t word6;
-#define lpfc_resume_rpi_vpi_SHIFT	0
-#define lpfc_resume_rpi_vpi_MASK	0x0000FFFF
-#define lpfc_resume_rpi_vpi_WORD	word6
-#define lpfc_resume_rpi_vfi_SHIFT	16
-#define lpfc_resume_rpi_vfi_MASK	0x0000FFFF
-#define lpfc_resume_rpi_vfi_WORD	word6
 };
 
 #define REG_FCF_INVALID_QID	0xFFFF
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 6d598ec..abfac84 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -461,6 +461,9 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 
 	phba->lmt = mb->un.varRdConfig.lmt;
 
+	/* Check if the port is disabled */
+	lpfc_sli_read_serdes_param(phba);
+
 	/* Get the default values for Model Name and Description */
 	lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc);
 
@@ -564,9 +567,6 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 		}
 	}
 
-	/* Check if the port is disabled */
-	lpfc_sli_read_serdes_param(phba);
-
 	if (phba->hba_flag & LINK_DISABLED) {
 		lpfc_printf_log(phba,
 			KERN_ERR, LOG_INIT,
@@ -6873,7 +6873,8 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
 
 	/* Confiugre sysfs attributes */
 	vport = phba->pport;
-	phba->dfc_host = lpfcdfc_host_add(pdev, lpfc_shost_from_vport(vport), phba);
+	phba->dfc_host = lpfcdfc_host_add(pdev, lpfc_shost_from_vport(vport),
+					phba);
 	if (!phba->dfc_host) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
 				"1201 Failed to allocate dfc_host \n");
@@ -6884,7 +6885,7 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
 	if (lpfc_alloc_sysfs_attr(vport)) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"1476 Failed to allocate sysfs attr\n");
-		goto out_destroy_shost;
+		goto out_destroy_lpfcdfc_host;
 	}
 
 	/* Now, trying to enable interrupt and bring up the device */
@@ -6942,6 +6943,8 @@ out_remove_device:
 	lpfc_unset_hba(phba);
 out_free_sysfs_attr:
 	lpfc_free_sysfs_attr(vport);
+out_destroy_lpfcdfc_host:
+	lpfcdfc_host_del(phba->dfc_host);
 out_destroy_shost:
 	lpfc_destroy_shost(phba);
 out_unset_driver_resource:
@@ -7432,11 +7435,19 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
 
 	/* Configure sysfs attributes */
 	vport = phba->pport;
+	phba->dfc_host = lpfcdfc_host_add(pdev, lpfc_shost_from_vport(vport),
+		 phba);
+	if (!phba->dfc_host) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
+				"1262 Failed to allocate dfc_host \n");
+		error = -ENOMEM;
+		goto out_destroy_shost;
+	}
 	error = lpfc_alloc_sysfs_attr(vport);
 	if (error) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"1416 Failed to allocate sysfs attr\n");
-		goto out_destroy_shost;
+		goto out_destroy_lpfcdfc_host;
 	}
 
 	/* Now, trying to enable interrupt and bring up the device */
@@ -7492,6 +7503,8 @@ out_disable_intr:
 	lpfc_sli4_disable_intr(phba);
 out_free_sysfs_attr:
 	lpfc_free_sysfs_attr(vport);
+out_destroy_lpfcdfc_host:
+	lpfcdfc_host_del(phba->dfc_host);
 out_destroy_shost:
 	lpfc_destroy_shost(phba);
 out_unset_driver_resource:
@@ -7527,6 +7540,9 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev)
 	struct lpfc_hba *phba = vport->phba;
 	int i;
 
+	lpfcdfc_host_del(phba->dfc_host);
+	phba->dfc_host = NULL;
+
 	/* Mark the device unloading flag */
 	spin_lock_irq(&phba->hbalock);
 	vport->load_flag |= FC_UNLOADING;
@@ -7775,7 +7791,7 @@ static int __devinit
 lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
 	int rc;
-	uint16_t dev_id;
+	struct lpfc_sli_intf intf;
 
 	/*
 	 * Check if FC controller is excluded from binding to lpfc driver.
@@ -7788,17 +7804,16 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 		return -EPERM;
 	}
 
-	if (pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id))
+	if (pci_read_config_dword(pdev, LPFC_SLIREV_CONF_WORD,
+		(uint32_t *) &intf))
 		return -ENODEV;
 
-	switch (dev_id) {
-	case PCI_DEVICE_ID_TIGERSHARK:
+	if ((bf_get(lpfc_sli_intf_valid, &intf) == LPFC_SLI_INTF_VALID) &&
+		(bf_get(lpfc_sli_intf_rev, &intf) == LPFC_SLIREV_CONF_SLI4))
 		rc = lpfc_pci_probe_one_s4(pdev, pid);
-		break;
-	default:
+	else
 		rc = lpfc_pci_probe_one_s3(pdev, pid);
-		break;
-	}
+
 	return rc;
 }
 
diff --git a/drivers/scsi/lpfc/lpfc_ioctl.c b/drivers/scsi/lpfc/lpfc_ioctl.c
index 289c918..76e216e 100644
--- a/drivers/scsi/lpfc/lpfc_ioctl.c
+++ b/drivers/scsi/lpfc/lpfc_ioctl.c
@@ -749,6 +749,7 @@ lpfc_ioctl_send_mgmt_cmd(struct lpfc_hba * phba,
 	cmdiocbq->vport = phba->pport;
 	cmdiocbq->context1 = NULL;
 	cmdiocbq->context2 = NULL;
+	cmdiocbq->context3 = bmp;
 	cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
 
 	if (cip->lpfc_flag == 0 )
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 5433762..9e222ef 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -2027,9 +2027,7 @@ lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp)
 	memset(mbox, 0, sizeof(*mbox));
 	resume_rpi = &mbox->u.mqe.un.resume_rpi;
 	bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_RESUME_RPI);
-	bf_set(lpfc_resume_rpi_rpi, resume_rpi, ndlp->nlp_rpi);
-	bf_set(lpfc_resume_rpi_vpi, resume_rpi,
-	       ndlp->vport->vpi + ndlp->vport->phba->vpi_base);
-	bf_set(lpfc_resume_rpi_vfi, resume_rpi,
-	       ndlp->vport->vfi + ndlp->vport->phba->vfi_base);
+	bf_set(lpfc_resume_rpi_index, resume_rpi, ndlp->nlp_rpi);
+	bf_set(lpfc_resume_rpi_ii, resume_rpi, RESUME_INDEX_RPI);
+	resume_rpi->event_tag = ndlp->phba->fc_eventTag;
 }
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 7d173dc..57fd297 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1914,72 +1914,6 @@ lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba,
 }
 
 /**
- * lpfc_scsi_tgt_reset - Target reset handler
- * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure
- * @vport: The virtual port for which this call is being executed.
- * @tgt_id: Target ID.
- * @lun: Lun number.
- * @rdata: Pointer to lpfc_rport_data.
- *
- * This routine issues a TARGET RESET iocb to reset a target with @tgt_id ID.
- *
- * Return Code:
- *   0x2003 - Error
- *   0x2002 - Success.
- **/
-static int
-lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport,
-		    unsigned  tgt_id, unsigned int lun,
-		    struct lpfc_rport_data *rdata)
-{
-	struct lpfc_hba   *phba = vport->phba;
-	struct lpfc_iocbq *iocbq;
-	struct lpfc_iocbq *iocbqrsp;
-	int ret;
-	int status;
-
-	if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode))
-		return FAILED;
-
-	lpfc_cmd->rdata = rdata;
-	status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun,
-					   FCP_TARGET_RESET);
-	if (!status)
-		return FAILED;
-
-	iocbq = &lpfc_cmd->cur_iocbq;
-	iocbqrsp = lpfc_sli_get_iocbq(phba);
-
-	if (!iocbqrsp)
-		return FAILED;
-
-	/* Issue Target Reset to TGT <num> */
-	lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
-			 "0702 Issue Target Reset to TGT %d Data: x%x x%x\n",
-			 tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
-	status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING,
-					  iocbq, iocbqrsp, lpfc_cmd->timeout);
-	if (status != IOCB_SUCCESS) {
-		if (status == IOCB_TIMEDOUT) {
-			iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
-			ret = TIMEOUT_ERROR;
-		} else
-			ret = FAILED;
-		lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
-	} else {
-		ret = SUCCESS;
-		lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4];
-		lpfc_cmd->status = iocbqrsp->iocb.ulpStatus;
-		if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT &&
-			(lpfc_cmd->result & IOERR_DRVR_MASK))
-				lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
-	}
-
-	lpfc_sli_release_iocbq(phba, iocbqrsp);
-	return ret;
-}
-
-/**
  * lpfc_info - Info entry point of scsi_host_template data structure
  * @host: The scsi host for which this call is being executed.
  *
@@ -2315,156 +2249,275 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 	return ret;
 }
 
+static char *
+lpfc_taskmgmt_name(uint8_t task_mgmt_cmd)
+{
+	switch (task_mgmt_cmd) {
+	case FCP_ABORT_TASK_SET:
+		return "ABORT_TASK_SET";
+	case FCP_CLEAR_TASK_SET:
+		return "FCP_CLEAR_TASK_SET";
+	case FCP_BUS_RESET:
+		return "FCP_BUS_RESET";
+	case FCP_LUN_RESET:
+		return "FCP_LUN_RESET";
+	case FCP_TARGET_RESET:
+		return "FCP_TARGET_RESET";
+	case FCP_CLEAR_ACA:
+		return "FCP_CLEAR_ACA";
+	case FCP_TERMINATE_TASK:
+		return "FCP_TERMINATE_TASK";
+	default:
+		return "unknown";
+	}
+}
+
 /**
- * lpfc_device_reset_handler - scsi_host_template eh_device_reset entry point
- * @cmnd: Pointer to scsi_cmnd data structure.
+ * lpfc_send_taskmgmt - Generic SCSI Task Mgmt Handler
+ * @vport: The virtual port for which this call is being executed.
+ * @rdata: Pointer to remote port local data
+ * @tgt_id: Target ID of remote device.
+ * @lun_id: Lun number for the TMF
+ * @task_mgmt_cmd: type of TMF to send
  *
- * This routine does a device reset by sending a TARGET_RESET task management
- * command.
+ * This routine builds and sends a TMF (SCSI Task Mgmt Function) to
+ * a remote port.
  *
- * Return code :
- *  0x2003 - Error
- *  0x2002 - Success
+ * Return Code:
+ *   0x2003 - Error
+ *   0x2002 - Success.
  **/
 static int
-lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
+lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
+		    unsigned  tgt_id, unsigned int lun_id,
+		    uint8_t task_mgmt_cmd)
 {
-	struct Scsi_Host  *shost = cmnd->device->host;
-	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
 	struct lpfc_scsi_buf *lpfc_cmd;
-	struct lpfc_iocbq *iocbq, *iocbqrsp;
-	struct lpfc_rport_data *rdata = cmnd->device->hostdata;
-	struct lpfc_nodelist *pnode = rdata->pnode;
-	unsigned long later;
-	int ret = SUCCESS;
+	struct lpfc_iocbq *iocbq;
+	struct lpfc_iocbq *iocbqrsp;
+	int ret;
 	int status;
-	int cnt;
-	struct lpfc_scsi_event_header scsi_event;
 
-	lpfc_block_error_handler(cmnd);
-	/*
-	 * If target is not in a MAPPED state, delay the reset until
-	 * target is rediscovered or devloss timeout expires.
-	 */
-	later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies;
-	while (time_after(later, jiffies)) {
-		if (!pnode || !NLP_CHK_NODE_ACT(pnode))
-			return FAILED;
-		if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
-			break;
-		schedule_timeout_uninterruptible(msecs_to_jiffies(500));
-		rdata = cmnd->device->hostdata;
-		if (!rdata)
-			break;
-		pnode = rdata->pnode;
-	}
-
-	scsi_event.event_type = FC_REG_SCSI_EVENT;
-	scsi_event.subcategory = LPFC_EVENT_TGTRESET;
-	scsi_event.lun = 0;
-	memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name));
-	memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name));
-
-	fc_host_post_vendor_event(shost,
-		fc_get_event_number(),
-		sizeof(scsi_event),
-		(char *)&scsi_event,
-		LPFC_NL_VENDOR_ID);
-
-	if (!rdata || pnode->nlp_state != NLP_STE_MAPPED_NODE) {
-		lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
-				 "0721 LUN Reset rport "
-				 "failure: msec x%x rdata x%p\n",
-				 jiffies_to_msecs(jiffies - later), rdata);
+	if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode))
 		return FAILED;
-	}
+
 	lpfc_cmd = lpfc_get_scsi_buf(phba);
 	if (lpfc_cmd == NULL)
 		return FAILED;
 	lpfc_cmd->timeout = 60;
 	lpfc_cmd->rdata = rdata;
 
-	status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd,
-					      cmnd->device->lun,
-					      FCP_TARGET_RESET);
+	status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun_id,
+					   task_mgmt_cmd);
 	if (!status) {
 		lpfc_release_scsi_buf(phba, lpfc_cmd);
 		return FAILED;
 	}
-	iocbq = &lpfc_cmd->cur_iocbq;
 
-	/* get a buffer for this IOCB command response */
+	iocbq = &lpfc_cmd->cur_iocbq;
 	iocbqrsp = lpfc_sli_get_iocbq(phba);
 	if (iocbqrsp == NULL) {
 		lpfc_release_scsi_buf(phba, lpfc_cmd);
 		return FAILED;
 	}
+
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
-			 "0703 Issue target reset to TGT %d LUN %d "
-			 "rpi x%x nlp_flag x%x\n", cmnd->device->id,
-			 cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
+			 "0702 Issue %s to TGT %d LUN %d "
+			 "rpi x%x nlp_flag x%x\n",
+			 lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id,
+			 rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
+
 	status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING,
 					  iocbq, iocbqrsp, lpfc_cmd->timeout);
-	if (status == IOCB_TIMEDOUT) {
-		iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
-		ret = TIMEOUT_ERROR;
-	} else {
-		if (status != IOCB_SUCCESS)
+	if (status != IOCB_SUCCESS) {
+		if (status == IOCB_TIMEDOUT) {
+			iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
+			ret = TIMEOUT_ERROR;
+		} else
 			ret = FAILED;
-		lpfc_release_scsi_buf(phba, lpfc_cmd);
-	}
-	lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
-			 "0713 SCSI layer issued device reset (%d, %d) "
-			 "return x%x status x%x result x%x\n",
-			 cmnd->device->id, cmnd->device->lun, ret,
-			 iocbqrsp->iocb.ulpStatus,
+		lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+			 "0727 TMF %s to TGT %d LUN %d failed (%d, %d)\n",
+			 lpfc_taskmgmt_name(task_mgmt_cmd),
+			 tgt_id, lun_id, iocbqrsp->iocb.ulpStatus,
 			 iocbqrsp->iocb.un.ulpWord[4]);
+	} else
+		ret = SUCCESS;
+
 	lpfc_sli_release_iocbq(phba, iocbqrsp);
-	cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun,
-				LPFC_CTX_TGT);
+
+	if (ret != TIMEOUT_ERROR)
+		lpfc_release_scsi_buf(phba, lpfc_cmd);
+
+	return ret;
+}
+
+/**
+ * lpfc_chk_tgt_mapped -
+ * @vport: The virtual port to check on
+ * @cmnd: Pointer to scsi_cmnd data structure.
+ *
+ * This routine delays until the scsi target (aka rport) for the
+ * command exists (is present and logged in) or we declare it non-existent.
+ *
+ * Return code :
+ *  0x2003 - Error
+ *  0x2002 - Success
+ **/
+static int
+lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd)
+{
+	struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+	struct lpfc_nodelist *pnode = rdata->pnode;
+	unsigned long later;
+
+	/*
+	 * If target is not in a MAPPED state, delay until
+	 * target is rediscovered or devloss timeout expires.
+	 */
+	later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies;
+	while (time_after(later, jiffies)) {
+		if (!pnode || !NLP_CHK_NODE_ACT(pnode))
+			return FAILED;
+		if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
+			return SUCCESS;
+		schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+		rdata = cmnd->device->hostdata;
+		if (!rdata)
+			return FAILED;
+		pnode = rdata->pnode;
+	}
+	if (!pnode || !NLP_CHK_NODE_ACT(pnode) ||
+	    (pnode->nlp_state != NLP_STE_MAPPED_NODE))
+		return FAILED;
+	return SUCCESS;
+}
+
+/**
+ * lpfc_reset_flush_io_context -
+ * @vport: The virtual port (scsi_host) for the flush context
+ * @tgt_id: If aborting by Target contect - specifies the target id
+ * @lun_id: If aborting by Lun context - specifies the lun id
+ * @context: specifies the context level to flush at.
+ *
+ * After a reset condition via TMF, we need to flush orphaned i/o
+ * contexts from the adapter. This routine aborts any contexts
+ * outstanding, then waits for their completions. The wait is
+ * bounded by devloss_tmo though.
+ *
+ * Return code :
+ *  0x2003 - Error
+ *  0x2002 - Success
+ **/
+static int
+lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id,
+			uint64_t lun_id, lpfc_ctx_cmd context)
+{
+	struct lpfc_hba   *phba = vport->phba;
+	unsigned long later;
+	int cnt;
+
+	cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context);
 	if (cnt)
 		lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
-				    cmnd->device->id, cmnd->device->lun,
-				    LPFC_CTX_TGT);
+				    tgt_id, lun_id, context);
 	later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies;
 	while (time_after(later, jiffies) && cnt) {
 		schedule_timeout_uninterruptible(msecs_to_jiffies(20));
-		cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id,
-					cmnd->device->lun, LPFC_CTX_TGT);
+		cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context);
 	}
 	if (cnt) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
-				 "0719 device reset I/O flush failure: "
-				 "cnt x%x\n", cnt);
-		ret = FAILED;
+			"0724 I/O flush failure for context %s : cnt x%x\n",
+			((context == LPFC_CTX_LUN) ? "LUN" :
+			 ((context == LPFC_CTX_TGT) ? "TGT" :
+			  ((context == LPFC_CTX_HOST) ? "HOST" : "Unknown"))),
+			cnt);
+		return FAILED;
 	}
-	return ret;
+	return SUCCESS;
+}
+
+/**
+ * lpfc_device_reset_handler - scsi_host_template eh_device_reset entry point
+ * @cmnd: Pointer to scsi_cmnd data structure.
+ *
+ * This routine does a device reset by sending a LUN_RESET task management
+ * command.
+ *
+ * Return code :
+ *  0x2003 - Error
+ *  0x2002 - Success
+ **/
+static int
+lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
+{
+	struct Scsi_Host  *shost = cmnd->device->host;
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+	struct lpfc_rport_data *rdata = cmnd->device->hostdata;
+	struct lpfc_nodelist *pnode = rdata->pnode;
+	unsigned tgt_id = cmnd->device->id;
+	unsigned int lun_id = cmnd->device->lun;
+	struct lpfc_scsi_event_header scsi_event;
+	int status;
+
+	lpfc_block_error_handler(cmnd);
+
+	status = lpfc_chk_tgt_mapped(vport, cmnd);
+	if (status == FAILED) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+			"0721 Device Reset rport failure: rdata x%p\n", rdata);
+		return FAILED;
+	}
+
+	scsi_event.event_type = FC_REG_SCSI_EVENT;
+	scsi_event.subcategory = LPFC_EVENT_LUNRESET;
+	scsi_event.lun = lun_id;
+	memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name));
+	memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name));
+
+	fc_host_post_vendor_event(shost, fc_get_event_number(),
+		sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
+
+	status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id,
+						FCP_LUN_RESET);
+
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+			 "0713 SCSI layer issued Device Reset (%d, %d) "
+			 "return x%x\n", tgt_id, lun_id, status);
+
+	/*
+	 * We have to clean up i/o as : they may be orphaned by the TMF;
+	 * or if the TMF failed, they may be in an indeterminate state.
+	 * So, continue on.
+	 * We will report success if all the i/o aborts successfully.
+	 */
+	status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id,
+						LPFC_CTX_LUN);
+	return status;
 }
 
 /**
  * lpfc_bus_reset_handler - scsi_host_template eh_bus_reset_handler entry point
  * @cmnd: Pointer to scsi_cmnd data structure.
  *
- * This routine does target reset to all target on @cmnd->device->host.
+ * This routine does target reset to all targets on @cmnd->device->host.
+ * This emulates Parallel SCSI Bus Reset Semantics.
  *
- * Return Code:
- *   0x2003 - Error
- *   0x2002 - Success
+ * Return code :
+ *  0x2003 - Error
+ *  0x2002 - Success
  **/
 static int
 lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 {
 	struct Scsi_Host  *shost = cmnd->device->host;
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-	struct lpfc_hba   *phba = vport->phba;
 	struct lpfc_nodelist *ndlp = NULL;
+	struct lpfc_scsi_event_header scsi_event;
 	int match;
 	int ret = SUCCESS, status, i;
-	int cnt;
-	struct lpfc_scsi_buf * lpfc_cmd;
-	unsigned long later;
-	struct lpfc_scsi_event_header scsi_event;
 
 	scsi_event.event_type = FC_REG_SCSI_EVENT;
 	scsi_event.subcategory = LPFC_EVENT_BUSRESET;
@@ -2472,13 +2525,11 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 	memcpy(scsi_event.wwpn, &vport->fc_portname, sizeof(struct lpfc_name));
 	memcpy(scsi_event.wwnn, &vport->fc_nodename, sizeof(struct lpfc_name));
 
-	fc_host_post_vendor_event(shost,
-		fc_get_event_number(),
-		sizeof(scsi_event),
-		(char *)&scsi_event,
-		LPFC_NL_VENDOR_ID);
+	fc_host_post_vendor_event(shost, fc_get_event_number(),
+		sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID);
 
 	lpfc_block_error_handler(cmnd);
+
 	/*
 	 * Since the driver manages a single bus device, reset all
 	 * targets known to the driver.  Should any target reset
@@ -2501,16 +2552,11 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 		spin_unlock_irq(shost->host_lock);
 		if (!match)
 			continue;
-		lpfc_cmd = lpfc_get_scsi_buf(phba);
-		if (lpfc_cmd) {
-			lpfc_cmd->timeout = 60;
-			status = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i,
-						     cmnd->device->lun,
-						     ndlp->rport->dd_data);
-			if (status != TIMEOUT_ERROR)
-				lpfc_release_scsi_buf(phba, lpfc_cmd);
-		}
-		if (!lpfc_cmd || status != SUCCESS) {
+
+		status = lpfc_send_taskmgmt(vport, ndlp->rport->dd_data,
+					i, 0, FCP_TARGET_RESET);
+
+		if (status != SUCCESS) {
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
 					 "0700 Bus Reset on target %d failed\n",
 					 i);
@@ -2518,25 +2564,16 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
 		}
 	}
 	/*
-	 * All outstanding txcmplq I/Os should have been aborted by
-	 * the targets.  Unfortunately, some targets do not abide by
-	 * this forcing the driver to double check.
+	 * We have to clean up i/o as : they may be orphaned by the TMFs
+	 * above; or if any of the TMFs failed, they may be in an
+	 * indeterminate state.
+	 * We will report success if all the i/o aborts successfully.
 	 */
-	cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST);
-	if (cnt)
-		lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
-				    0, 0, LPFC_CTX_HOST);
-	later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies;
-	while (time_after(later, jiffies) && cnt) {
-		schedule_timeout_uninterruptible(msecs_to_jiffies(20));
-		cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST);
-	}
-	if (cnt) {
-		lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
-				 "0715 Bus Reset I/O flush failure: "
-				 "cnt x%x left x%x\n", cnt, i);
+
+	status = lpfc_reset_flush_io_context(vport, 0, 0, LPFC_CTX_HOST);
+	if (status != SUCCESS)
 		ret = FAILED;
-	}
+
 	lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
 			 "0714 SCSI layer issued Bus Reset Data: x%x\n", ret);
 	return ret;
@@ -2669,7 +2706,7 @@ struct scsi_host_template lpfc_template = {
 	.info			= lpfc_info,
 	.queuecommand		= lpfc_queuecommand,
 	.eh_abort_handler	= lpfc_abort_handler,
-	.eh_device_reset_handler= lpfc_device_reset_handler,
+	.eh_device_reset_handler = lpfc_device_reset_handler,
 	.eh_bus_reset_handler	= lpfc_bus_reset_handler,
 	.slave_alloc		= lpfc_slave_alloc,
 	.slave_configure	= lpfc_slave_configure,
@@ -2688,7 +2725,7 @@ struct scsi_host_template lpfc_vport_template = {
 	.info			= lpfc_info,
 	.queuecommand		= lpfc_queuecommand,
 	.eh_abort_handler	= lpfc_abort_handler,
-	.eh_device_reset_handler= lpfc_device_reset_handler,
+	.eh_device_reset_handler = lpfc_device_reset_handler,
 	.eh_bus_reset_handler	= lpfc_bus_reset_handler,
 	.slave_alloc		= lpfc_slave_alloc,
 	.slave_configure	= lpfc_slave_configure,
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 222858c..d15f2dc 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -4725,13 +4725,13 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox,
 
 	spin_lock_irqsave(&phba->hbalock, drvr_flag);
 	if (!pmbox) {
+		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
 		/* processing mbox queue from intr_handler */
 		if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) {
 			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 			return MBX_SUCCESS;
 		}
 		processing_queue = 1;
-		phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
 		pmbox = lpfc_mbox_get(phba);
 		if (!pmbox) {
 			spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
@@ -5828,6 +5828,8 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
 		 * have not been byteswapped yet so there is no
 		 * need to swap them back.
 		 */
+		if (!piocbq->context3)
+			return xritag;
 		bpl  = (struct ulp_bde64 *)
 			((struct lpfc_dmabuf *)piocbq->context3)->virt;
 
@@ -11681,7 +11683,6 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index)
  * decide if the used disaled the port. If the TLC indicates the
  * port is disabled, the hba_flag is set accordingly.
  **/
-
 void
 lpfc_sli_read_serdes_param(struct lpfc_hba *phba)
 {
@@ -11702,7 +11703,7 @@ lpfc_sli_read_serdes_param(struct lpfc_hba *phba)
 
 	lpfc_dump_serdes_param(phba, pmb);
 
-	rc = lpfc_sli_issue_mbox_wait(phba, pmb, LPFC_MBOX_TMO);
+	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
 
 	if ((rc != MBX_SUCCESS) || mb->mbxStatus) {
 		lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
@@ -11713,7 +11714,6 @@ lpfc_sli_read_serdes_param(struct lpfc_hba *phba)
 		goto out;
 	}
 
-
 	serdes_param = (uint8_t *)mb + DMP_RSP_OFFSET;
 
 	/* Swap the byte ordering to match with Firmware endianess */
@@ -11735,7 +11735,6 @@ lpfc_sli_read_serdes_param(struct lpfc_hba *phba)
 		break;
 	}
 out:
-	if (rc != MBX_TIMEOUT)
-		mempool_free(pmb, phba->mbox_mem_pool);
+	mempool_free(pmb, phba->mbox_mem_pool);
 	return;
 }
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 97f011b..d48d66b 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.2.0.45"
+#define LPFC_DRIVER_VERSION "8.2.0.46"
 
 #define LPFC_DRIVER_NAME		"lpfc"
 #define LPFC_SP_DRIVER_HANDLER_NAME	"lpfc:sp"