return 0;
 }
+
 /**
  * lpfc_hba_down_post_s4 - Perform lpfc uninitialization after HBA reset
  * @phba: pointer to lpfc HBA data structure.
        return;
 }
 
+/**
+ * lpfc_sli4_xri_exchange_busy_wait - Wait for device XRI exchange busy
+ * @phba: Pointer to HBA context object.
+ *
+ * This function is called in the SLI4 code path to wait for completion
+ * of device's XRIs exchange busy. It will check the XRI exchange busy
+ * on outstanding FCP and ELS I/Os every 10ms for up to 10 seconds; after
+ * that, it will check the XRI exchange busy on outstanding FCP and ELS
+ * I/Os every 30 seconds, log error message, and wait forever. Only when
+ * all XRI exchange busy complete, the driver unload shall proceed with
+ * invoking the function reset ioctl mailbox command to the CNA and the
+ * the rest of the driver unload resource release.
+ **/
+static void
+lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba)
+{
+       int wait_time = 0;
+       int fcp_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_scsi_buf_list);
+       int els_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_els_sgl_list);
+
+       while (!fcp_xri_cmpl || !els_xri_cmpl) {
+               if (wait_time > LPFC_XRI_EXCH_BUSY_WAIT_TMO) {
+                       if (!fcp_xri_cmpl)
+                               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                               "2877 FCP XRI exchange busy "
+                                               "wait time: %d seconds.\n",
+                                               wait_time/1000);
+                       if (!els_xri_cmpl)
+                               lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+                                               "2878 ELS XRI exchange busy "
+                                               "wait time: %d seconds.\n",
+                                               wait_time/1000);
+                       msleep(LPFC_XRI_EXCH_BUSY_WAIT_T2);
+                       wait_time += LPFC_XRI_EXCH_BUSY_WAIT_T2;
+               } else {
+                       msleep(LPFC_XRI_EXCH_BUSY_WAIT_T1);
+                       wait_time += LPFC_XRI_EXCH_BUSY_WAIT_T1;
+               }
+               fcp_xri_cmpl =
+                       list_empty(&phba->sli4_hba.lpfc_abts_scsi_buf_list);
+               els_xri_cmpl =
+                       list_empty(&phba->sli4_hba.lpfc_abts_els_sgl_list);
+       }
+}
+
 /**
  * lpfc_sli4_hba_unset - Unset the fcoe hba
  * @phba: Pointer to HBA context object.
                spin_unlock_irq(&phba->hbalock);
        }
 
+       /* Abort all iocbs associated with the hba */
+       lpfc_sli_hba_iocb_abort(phba);
+
+       /* Wait for completion of device XRI exchange busy */
+       lpfc_sli4_xri_exchange_busy_wait(phba);
+
        /* Disable PCI subsystem interrupt */
        lpfc_sli4_disable_intr(phba);
 
 
        struct lpfc_vport  *vport = pmb->vport;
        struct lpfc_dmabuf *mp;
        struct lpfc_nodelist *ndlp;
+       struct Scsi_Host *shost;
        uint16_t rpi, vpi;
        int rc;
 
        }
 
        if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) &&
-           (phba->sli_rev == LPFC_SLI_REV4))
+           (phba->sli_rev == LPFC_SLI_REV4) &&
+           (pmb->u.mb.un.varUnregLogin.rsvd1 == 0x0))
                lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi);
 
        /*
                        return;
        }
 
-       /* Unreg VPI, if the REG_VPI succeed after VLink failure */
        if ((pmb->u.mb.mbxCommand == MBX_REG_VPI) &&
                !(phba->pport->load_flag & FC_UNLOADING) &&
                !pmb->u.mb.mbxStatus) {
-               lpfc_unreg_vpi(phba, pmb->u.mb.un.varRegVpi.vpi, pmb);
-               pmb->vport = vport;
-               pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-               rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
-               if (rc != MBX_NOT_FINISHED)
-                       return;
+               shost = lpfc_shost_from_vport(vport);
+               spin_lock_irq(shost->host_lock);
+               vport->vpi_state |= LPFC_VPI_REGISTERED;
+               vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+               spin_unlock_irq(shost->host_lock);
        }
 
        if (pmb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
 }
 
 /**
- * lpfc_sli_issue_abort_iotag - Abort function for a command iocb
+ * lpfc_sli_abort_iotag_issue - Issue abort for a command iocb
  * @phba: Pointer to HBA context object.
  * @pring: Pointer to driver SLI ring object.
  * @cmdiocb: Pointer to driver command iocb object.
  *
- * This function issues an abort iocb for the provided command
- * iocb. This function is called with hbalock held.
- * The function returns 0 when it fails due to memory allocation
- * failure or when the command iocb is an abort request.
+ * This function issues an abort iocb for the provided command iocb down to
+ * the port. Other than the case the outstanding command iocb is an abort
+ * request, this function issues abort out unconditionally. This function is
+ * called with hbalock held. The function returns 0 when it fails due to
+ * memory allocation failure or when the command iocb is an abort request.
  **/
-int
-lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+static int
+lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                           struct lpfc_iocbq *cmdiocb)
 {
        struct lpfc_vport *vport = cmdiocb->vport;
        struct lpfc_iocbq *abtsiocbp;
        IOCB_t *icmd = NULL;
        IOCB_t *iabt = NULL;
-       int retval = IOCB_ERROR;
+       int retval;
 
        /*
         * There are certain command types we don't want to abort.  And we
            (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
                return 0;
 
-       /* If we're unloading, don't abort iocb on the ELS ring, but change the
-        * callback so that nothing happens when it finishes.
-        */
-       if ((vport->load_flag & FC_UNLOADING) &&
-           (pring->ringno == LPFC_ELS_RING)) {
-               if (cmdiocb->iocb_flag & LPFC_IO_FABRIC)
-                       cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
-               else
-                       cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl;
-               goto abort_iotag_exit;
-       }
-
        /* issue ABTS for this IOCB based on iotag */
        abtsiocbp = __lpfc_sli_get_iocbq(phba);
        if (abtsiocbp == NULL)
 
        if (retval)
                __lpfc_sli_release_iocbq(phba, abtsiocbp);
+
+       /*
+        * Caller to this routine should check for IOCB_ERROR
+        * and handle it properly.  This routine no longer removes
+        * iocb off txcmplq and call compl in case of IOCB_ERROR.
+        */
+       return retval;
+}
+
+/**
+ * lpfc_sli_issue_abort_iotag - Abort function for a command iocb
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ * @cmdiocb: Pointer to driver command iocb object.
+ *
+ * This function issues an abort iocb for the provided command iocb. In case
+ * of unloading, the abort iocb will not be issued to commands on the ELS
+ * ring. Instead, the callback function shall be changed to those commands
+ * so that nothing happens when them finishes. This function is called with
+ * hbalock held. The function returns 0 when the command iocb is an abort
+ * request.
+ **/
+int
+lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+                          struct lpfc_iocbq *cmdiocb)
+{
+       struct lpfc_vport *vport = cmdiocb->vport;
+       int retval = IOCB_ERROR;
+       IOCB_t *icmd = NULL;
+
+       /*
+        * There are certain command types we don't want to abort.  And we
+        * don't want to abort commands that are already in the process of
+        * being aborted.
+        */
+       icmd = &cmdiocb->iocb;
+       if (icmd->ulpCommand == CMD_ABORT_XRI_CN ||
+           icmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+           (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
+               return 0;
+
+       /*
+        * If we're unloading, don't abort iocb on the ELS ring, but change
+        * the callback so that nothing happens when it finishes.
+        */
+       if ((vport->load_flag & FC_UNLOADING) &&
+           (pring->ringno == LPFC_ELS_RING)) {
+               if (cmdiocb->iocb_flag & LPFC_IO_FABRIC)
+                       cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
+               else
+                       cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl;
+               goto abort_iotag_exit;
+       }
+
+       /* Now, we try to issue the abort to the cmdiocb out */
+       retval = lpfc_sli_abort_iotag_issue(phba, pring, cmdiocb);
+
 abort_iotag_exit:
        /*
         * Caller to this routine should check for IOCB_ERROR
        return retval;
 }
 
+/**
+ * lpfc_sli_iocb_ring_abort - Unconditionally abort all iocbs on an iocb ring
+ * @phba: Pointer to HBA context object.
+ * @pring: Pointer to driver SLI ring object.
+ *
+ * This function aborts all iocbs in the given ring and frees all the iocb
+ * objects in txq. This function issues abort iocbs unconditionally for all
+ * the iocb commands in txcmplq. The iocbs in the txcmplq is not guaranteed
+ * to complete before the return of this function. The caller is not required
+ * to hold any locks.
+ **/
+static void
+lpfc_sli_iocb_ring_abort(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+       LIST_HEAD(completions);
+       struct lpfc_iocbq *iocb, *next_iocb;
+
+       if (pring->ringno == LPFC_ELS_RING)
+               lpfc_fabric_abort_hba(phba);
+
+       spin_lock_irq(&phba->hbalock);
+
+       /* Take off all the iocbs on txq for cancelling */
+       list_splice_init(&pring->txq, &completions);
+       pring->txq_cnt = 0;
+
+       /* Next issue ABTS for everything on the txcmplq */
+       list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
+               lpfc_sli_abort_iotag_issue(phba, pring, iocb);
+
+       spin_unlock_irq(&phba->hbalock);
+
+       /* Cancel all the IOCBs from the completions list */
+       lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
+                             IOERR_SLI_ABORTED);
+}
+
+/**
+ * lpfc_sli_hba_iocb_abort - Abort all iocbs to an hba.
+ * @phba: pointer to lpfc HBA data structure.
+ *
+ * This routine will abort all pending and outstanding iocbs to an HBA.
+ **/
+void
+lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba)
+{
+       struct lpfc_sli *psli = &phba->sli;
+       struct lpfc_sli_ring *pring;
+       int i;
+
+       for (i = 0; i < psli->num_rings; i++) {
+               pring = &psli->ring[i];
+               lpfc_sli_iocb_ring_abort(phba, pring);
+       }
+}
+
 /**
  * lpfc_sli_validate_fcp_iocb - find commands associated with a vport or LUN
  * @iocbq: Pointer to driver iocb object.