scsi: be2iscsi: Add TPE recovery feature
authorJitendra Bhivare <jitendra.bhivare@broadcom.com>
Fri, 19 Aug 2016 09:50:18 +0000 (15:20 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 24 Aug 2016 02:42:44 +0000 (22:42 -0400)
After UE is detected, check for recoverable error by reading
SLIPORT SEMAPHORE register. If transient parity error i.e. 0xExxx
then schedule recovery work on driver wq.

FLag this error to prevent any transactions for the duration of ue2rp to
restart polling. After that, if FW becomes ready then recover port.

Wake up processes in wq before going offline.
Wait for process to execute before cleaning up.

Signed-off-by: Jitendra Bhivare <jitendra.bhivare@broadcom.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/be2iscsi/be_cmds.c
drivers/scsi/be2iscsi/be_cmds.h
drivers/scsi/be2iscsi/be_iscsi.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/be2iscsi/be_main.h
drivers/scsi/be2iscsi/be_mgmt.c
drivers/scsi/be2iscsi/be_mgmt.h

index 6f3cd82c429564a7c6756be2c6d756982fdbda67..ad7405d6821f1cba1d86573eb00bd4fe78e2e7ce 100644 (file)
 #include "be.h"
 #include "be_mgmt.h"
 
+/* UE Status Low CSR */
+static const char * const desc_ue_status_low[] = {
+       "CEV",
+       "CTX",
+       "DBUF",
+       "ERX",
+       "Host",
+       "MPU",
+       "NDMA",
+       "PTC ",
+       "RDMA ",
+       "RXF ",
+       "RXIPS ",
+       "RXULP0 ",
+       "RXULP1 ",
+       "RXULP2 ",
+       "TIM ",
+       "TPOST ",
+       "TPRE ",
+       "TXIPS ",
+       "TXULP0 ",
+       "TXULP1 ",
+       "UC ",
+       "WDMA ",
+       "TXULP2 ",
+       "HOST1 ",
+       "P0_OB_LINK ",
+       "P1_OB_LINK ",
+       "HOST_GPIO ",
+       "MBOX ",
+       "AXGMAC0",
+       "AXGMAC1",
+       "JTAG",
+       "MPU_INTPEND"
+};
+
+/* UE Status High CSR */
+static const char * const desc_ue_status_hi[] = {
+       "LPCMEMHOST",
+       "MGMT_MAC",
+       "PCS0ONLINE",
+       "MPU_IRAM",
+       "PCS1ONLINE",
+       "PCTL0",
+       "PCTL1",
+       "PMEM",
+       "RR",
+       "TXPB",
+       "RXPP",
+       "XAUI",
+       "TXP",
+       "ARM",
+       "IPC",
+       "HOST2",
+       "HOST3",
+       "HOST4",
+       "HOST5",
+       "HOST6",
+       "HOST7",
+       "HOST8",
+       "HOST9",
+       "NETC",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown"
+};
+
 struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
                                 unsigned int *ref_tag)
 {
@@ -185,6 +257,16 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba,
                                              phba->ctrl.mcc_tag_status[tag],
                                              msecs_to_jiffies(
                                                BEISCSI_HOST_MBX_TIMEOUT));
+       /**
+        * Return EIO if port is being disabled. Associated DMA memory, if any,
+        * is freed by the caller. When port goes offline, MCCQ is cleaned up
+        * so does WRB.
+        */
+       if (!test_bit(BEISCSI_HBA_ONLINE, &phba->state)) {
+               clear_bit(MCC_TAG_STATE_RUNNING,
+                         &phba->ctrl.ptag_state[tag].tag_state);
+               return -EIO;
+       }
 
        /**
         * If MBOX cmd timeout expired, tag and resource allocated
@@ -538,7 +620,6 @@ static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl)
                        BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
                        "BC_%d : FW Timed Out\n");
        set_bit(BEISCSI_HBA_FW_TIMEOUT, &phba->state);
-       beiscsi_ue_detect(phba);
        return -EBUSY;
 }
 
@@ -1584,6 +1665,12 @@ int beiscsi_init_sliport(struct beiscsi_hba *phba)
        if (!status)
                return -EIO;
 
+       /* clear all error states after checking FW rdy */
+       phba->state &= ~BEISCSI_HBA_IN_ERR;
+
+       /* check again UER support */
+       phba->state &= ~BEISCSI_HBA_UER_SUPP;
+
        /*
         * SLI COMMON_FUNCTION_RESET completion is indicated by BMBX RDY bit.
         * It should clean up any stale info in FW for this fn.
@@ -1647,3 +1734,87 @@ int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp)
        mutex_unlock(&ctrl->mbox_lock);
        return status;
 }
+
+/*
+ * beiscsi_detect_ue()- Detect Unrecoverable Error on adapter
+ * @phba: Driver priv structure
+ *
+ * Read registers linked to UE and check for the UE status
+ **/
+int beiscsi_detect_ue(struct beiscsi_hba *phba)
+{
+       uint32_t ue_mask_hi = 0, ue_mask_lo = 0;
+       uint32_t ue_hi = 0, ue_lo = 0;
+       uint8_t i = 0;
+       int ret = 0;
+
+       pci_read_config_dword(phba->pcidev,
+                             PCICFG_UE_STATUS_LOW, &ue_lo);
+       pci_read_config_dword(phba->pcidev,
+                             PCICFG_UE_STATUS_MASK_LOW,
+                             &ue_mask_lo);
+       pci_read_config_dword(phba->pcidev,
+                             PCICFG_UE_STATUS_HIGH,
+                             &ue_hi);
+       pci_read_config_dword(phba->pcidev,
+                             PCICFG_UE_STATUS_MASK_HI,
+                             &ue_mask_hi);
+
+       ue_lo = (ue_lo & ~ue_mask_lo);
+       ue_hi = (ue_hi & ~ue_mask_hi);
+
+
+       if (ue_lo || ue_hi) {
+               set_bit(BEISCSI_HBA_IN_UE, &phba->state);
+               __beiscsi_log(phba, KERN_ERR,
+                             "BC_%d : HBA error detected\n");
+               ret = 1;
+       }
+
+       if (ue_lo) {
+               for (i = 0; ue_lo; ue_lo >>= 1, i++) {
+                       if (ue_lo & 1)
+                               __beiscsi_log(phba, KERN_ERR,
+                                             "BC_%d : UE_LOW %s bit set\n",
+                                             desc_ue_status_low[i]);
+               }
+       }
+
+       if (ue_hi) {
+               for (i = 0; ue_hi; ue_hi >>= 1, i++) {
+                       if (ue_hi & 1)
+                               __beiscsi_log(phba, KERN_ERR,
+                                             "BC_%d : UE_HIGH %s bit set\n",
+                                             desc_ue_status_hi[i]);
+               }
+       }
+       return ret;
+}
+
+/*
+ * beiscsi_detect_tpe()- Detect Transient Parity Error on adapter
+ * @phba: Driver priv structure
+ *
+ * Read SLIPORT SEMAPHORE register to check for UER
+ *
+ **/
+int beiscsi_detect_tpe(struct beiscsi_hba *phba)
+{
+       u32 post, status;
+       int ret = 0;
+
+       post = beiscsi_get_post_stage(phba);
+       status = post & POST_STAGE_MASK;
+       if ((status & POST_ERR_RECOVERY_CODE_MASK) ==
+           POST_STAGE_RECOVERABLE_ERR) {
+               set_bit(BEISCSI_HBA_IN_TPE, &phba->state);
+               __beiscsi_log(phba, KERN_INFO,
+                             "BC_%d : HBA error recoverable: 0x%x\n", post);
+               ret = 1;
+       } else {
+               __beiscsi_log(phba, KERN_INFO,
+                             "BC_%d : HBA in UE: 0x%x\n", post);
+       }
+
+       return ret;
+}
index cf4239987acf2ff4164696bb34c58cd195faaa15..26d7921f48a4cfe52b0c64be6a4aaaa1aeea37e3 100644 (file)
@@ -770,6 +770,10 @@ int beiscsi_init_sliport(struct beiscsi_hba *phba);
 
 int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num);
 
+int beiscsi_detect_ue(struct beiscsi_hba *phba);
+
+int beiscsi_detect_tpe(struct beiscsi_hba *phba);
+
 int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
                          struct be_queue_info *eq, int eq_delay);
 
index 677491a4b0b431fe2b95d3e735d008170f48f1de..35f7d3aab366d5988f21455863df4535335ad01c 100644 (file)
@@ -58,7 +58,7 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
        beiscsi_ep = ep->dd_data;
        phba = beiscsi_ep->phba;
 
-       if (beiscsi_hba_in_error(phba)) {
+       if (!beiscsi_hba_is_online(phba)) {
                beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
                            "BS_%d : HBA in error 0x%lx\n", phba->state);
                return NULL;
@@ -444,7 +444,7 @@ int beiscsi_iface_set_param(struct Scsi_Host *shost,
        uint32_t rm_len = dt_len;
        int ret;
 
-       if (beiscsi_hba_in_error(phba)) {
+       if (!beiscsi_hba_is_online(phba)) {
                beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
                            "BS_%d : HBA in error 0x%lx\n", phba->state);
                return -EBUSY;
@@ -587,7 +587,7 @@ int beiscsi_iface_get_param(struct iscsi_iface *iface,
 
        if (param_type != ISCSI_NET_PARAM)
                return 0;
-       if (beiscsi_hba_in_error(phba)) {
+       if (!beiscsi_hba_is_online(phba)) {
                beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
                            "BS_%d : HBA in error 0x%lx\n", phba->state);
                return -EBUSY;
@@ -797,7 +797,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
        struct beiscsi_hba *phba = iscsi_host_priv(shost);
        int status = 0;
 
-       if (beiscsi_hba_in_error(phba)) {
+       if (!beiscsi_hba_is_online(phba)) {
                beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
                            "BS_%d : HBA in error 0x%lx\n", phba->state);
                return -EBUSY;
@@ -945,7 +945,7 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
 
        phba = ((struct beiscsi_conn *)conn->dd_data)->phba;
 
-       if (beiscsi_hba_in_error(phba)) {
+       if (!beiscsi_hba_is_online(phba)) {
                beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
                            "BS_%d : HBA in error 0x%lx\n", phba->state);
                return -EBUSY;
@@ -1175,7 +1175,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
        }
 
        phba = iscsi_host_priv(shost);
-       if (beiscsi_hba_in_error(phba)) {
+       if (!beiscsi_hba_is_online(phba)) {
                ret = -EIO;
                beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
                            "BS_%d : HBA in error 0x%lx\n", phba->state);
@@ -1335,7 +1335,7 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
                tcp_upload_flag = CONNECTION_UPLOAD_ABORT;
        }
 
-       if (beiscsi_hba_in_error(phba)) {
+       if (!beiscsi_hba_is_online(phba)) {
                beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
                            "BS_%d : HBA in error 0x%lx\n", phba->state);
                goto free_ep;
index e7741072995add29dc6cde4e79489b4e5c156d7f..0625bd0c449fe892f45951e3650a489f520b502f 100644 (file)
@@ -3525,10 +3525,53 @@ static void free_wrb_handles(struct beiscsi_hba *phba)
 
 static void be_mcc_queues_destroy(struct beiscsi_hba *phba)
 {
-       struct be_queue_info *q;
        struct be_ctrl_info *ctrl = &phba->ctrl;
+       struct be_dma_mem *ptag_mem;
+       struct be_queue_info *q;
+       int i, tag;
 
        q = &phba->ctrl.mcc_obj.q;
+       for (i = 0; i < MAX_MCC_CMD; i++) {
+               tag = i + 1;
+               if (!test_bit(MCC_TAG_STATE_RUNNING,
+                             &ctrl->ptag_state[tag].tag_state))
+                       continue;
+
+               if (test_bit(MCC_TAG_STATE_TIMEOUT,
+                            &ctrl->ptag_state[tag].tag_state)) {
+                       ptag_mem = &ctrl->ptag_state[tag].tag_mem_state;
+                       if (ptag_mem->size) {
+                               pci_free_consistent(ctrl->pdev,
+                                                   ptag_mem->size,
+                                                   ptag_mem->va,
+                                                   ptag_mem->dma);
+                               ptag_mem->size = 0;
+                       }
+                       continue;
+               }
+               /**
+                * If MCC is still active and waiting then wake up the process.
+                * We are here only because port is going offline. The process
+                * sees that (BEISCSI_HBA_ONLINE is cleared) and EIO error is
+                * returned for the operation and allocated memory cleaned up.
+                */
+               if (waitqueue_active(&ctrl->mcc_wait[tag])) {
+                       ctrl->mcc_tag_status[tag] = MCC_STATUS_FAILED;
+                       ctrl->mcc_tag_status[tag] |= CQE_VALID_MASK;
+                       wake_up_interruptible(&ctrl->mcc_wait[tag]);
+                       /*
+                        * Control tag info gets reinitialized in enable
+                        * so wait for the process to clear running state.
+                        */
+                       while (test_bit(MCC_TAG_STATE_RUNNING,
+                                       &ctrl->ptag_state[tag].tag_state))
+                               schedule_timeout_uninterruptible(HZ);
+               }
+               /**
+                * For MCC with tag_states MCC_TAG_STATE_ASYNC and
+                * MCC_TAG_STATE_IGNORE nothing needs to done.
+                */
+       }
        if (q->created) {
                beiscsi_cmd_q_destroy(ctrl, q, QTYPE_MCCQ);
                be_queue_free(phba, q);
@@ -3541,69 +3584,6 @@ static void be_mcc_queues_destroy(struct beiscsi_hba *phba)
        }
 }
 
-static void hwi_cleanup_port(struct beiscsi_hba *phba)
-{
-       struct be_queue_info *q;
-       struct be_ctrl_info *ctrl = &phba->ctrl;
-       struct hwi_controller *phwi_ctrlr;
-       struct hwi_context_memory *phwi_context;
-       struct hwi_async_pdu_context *pasync_ctx;
-       int i, eq_for_mcc, ulp_num;
-
-       phwi_ctrlr = phba->phwi_ctrlr;
-       phwi_context = phwi_ctrlr->phwi_ctxt;
-
-       be_cmd_iscsi_remove_template_hdr(ctrl);
-
-       for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
-               q = &phwi_context->be_wrbq[i];
-               if (q->created)
-                       beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ);
-       }
-       kfree(phwi_context->be_wrbq);
-       free_wrb_handles(phba);
-
-       for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
-               if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
-
-                       q = &phwi_context->be_def_hdrq[ulp_num];
-                       if (q->created)
-                               beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
-
-                       q = &phwi_context->be_def_dataq[ulp_num];
-                       if (q->created)
-                               beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
-
-                       pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num];
-               }
-       }
-
-       beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
-
-       for (i = 0; i < (phba->num_cpus); i++) {
-               q = &phwi_context->be_cq[i];
-               if (q->created) {
-                       be_queue_free(phba, q);
-                       beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ);
-               }
-       }
-
-       be_mcc_queues_destroy(phba);
-       if (phba->msix_enabled)
-               eq_for_mcc = 1;
-       else
-               eq_for_mcc = 0;
-       for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) {
-               q = &phwi_context->be_eq[i].q;
-               if (q->created) {
-                       be_queue_free(phba, q);
-                       beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ);
-               }
-       }
-       /* last communication, indicate driver is unloading */
-       beiscsi_cmd_special_wrb(&phba->ctrl, 0);
-}
-
 static int be_mcc_queues_create(struct beiscsi_hba *phba,
                                struct hwi_context_memory *phwi_context)
 {
@@ -3685,6 +3665,115 @@ static void find_num_cpus(struct beiscsi_hba *phba)
        }
 }
 
+static void hwi_purge_eq(struct beiscsi_hba *phba)
+{
+       struct hwi_controller *phwi_ctrlr;
+       struct hwi_context_memory *phwi_context;
+       struct be_queue_info *eq;
+       struct be_eq_entry *eqe = NULL;
+       int i, eq_msix;
+       unsigned int num_processed;
+
+       if (beiscsi_hba_in_error(phba))
+               return;
+
+       phwi_ctrlr = phba->phwi_ctrlr;
+       phwi_context = phwi_ctrlr->phwi_ctxt;
+       if (phba->msix_enabled)
+               eq_msix = 1;
+       else
+               eq_msix = 0;
+
+       for (i = 0; i < (phba->num_cpus + eq_msix); i++) {
+               eq = &phwi_context->be_eq[i].q;
+               eqe = queue_tail_node(eq);
+               num_processed = 0;
+               while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+                                       & EQE_VALID_MASK) {
+                       AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+                       queue_tail_inc(eq);
+                       eqe = queue_tail_node(eq);
+                       num_processed++;
+               }
+
+               if (num_processed)
+                       hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1);
+       }
+}
+
+static void hwi_cleanup_port(struct beiscsi_hba *phba)
+{
+       struct be_queue_info *q;
+       struct be_ctrl_info *ctrl = &phba->ctrl;
+       struct hwi_controller *phwi_ctrlr;
+       struct hwi_context_memory *phwi_context;
+       struct hwi_async_pdu_context *pasync_ctx;
+       int i, eq_for_mcc, ulp_num;
+
+       for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
+               if (test_bit(ulp_num, &phba->fw_config.ulp_supported))
+                       beiscsi_cmd_iscsi_cleanup(phba, ulp_num);
+
+       /**
+        * Purge all EQ entries that may have been left out. This is to
+        * workaround a problem we've seen occasionally where driver gets an
+        * interrupt with EQ entry bit set after stopping the controller.
+        */
+       hwi_purge_eq(phba);
+
+       phwi_ctrlr = phba->phwi_ctrlr;
+       phwi_context = phwi_ctrlr->phwi_ctxt;
+
+       be_cmd_iscsi_remove_template_hdr(ctrl);
+
+       for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
+               q = &phwi_context->be_wrbq[i];
+               if (q->created)
+                       beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ);
+       }
+       kfree(phwi_context->be_wrbq);
+       free_wrb_handles(phba);
+
+       for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++) {
+               if (test_bit(ulp_num, &phba->fw_config.ulp_supported)) {
+
+                       q = &phwi_context->be_def_hdrq[ulp_num];
+                       if (q->created)
+                               beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
+
+                       q = &phwi_context->be_def_dataq[ulp_num];
+                       if (q->created)
+                               beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
+
+                       pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx[ulp_num];
+               }
+       }
+
+       beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
+
+       for (i = 0; i < (phba->num_cpus); i++) {
+               q = &phwi_context->be_cq[i];
+               if (q->created) {
+                       be_queue_free(phba, q);
+                       beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ);
+               }
+       }
+
+       be_mcc_queues_destroy(phba);
+       if (phba->msix_enabled)
+               eq_for_mcc = 1;
+       else
+               eq_for_mcc = 0;
+       for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) {
+               q = &phwi_context->be_eq[i].q;
+               if (q->created) {
+                       be_queue_free(phba, q);
+                       beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ);
+               }
+       }
+       /* last communication, indicate driver is unloading */
+       beiscsi_cmd_special_wrb(&phba->ctrl, 0);
+}
 static int hwi_init_port(struct beiscsi_hba *phba)
 {
        struct hwi_controller *phwi_ctrlr;
@@ -4206,50 +4295,11 @@ do_cleanup_ctrlr:
        return ret;
 }
 
-static void hwi_purge_eq(struct beiscsi_hba *phba)
-{
-       struct hwi_controller *phwi_ctrlr;
-       struct hwi_context_memory *phwi_context;
-       struct be_queue_info *eq;
-       struct be_eq_entry *eqe = NULL;
-       int i, eq_msix;
-       unsigned int num_processed;
-
-       phwi_ctrlr = phba->phwi_ctrlr;
-       phwi_context = phwi_ctrlr->phwi_ctxt;
-       if (phba->msix_enabled)
-               eq_msix = 1;
-       else
-               eq_msix = 0;
-
-       for (i = 0; i < (phba->num_cpus + eq_msix); i++) {
-               eq = &phwi_context->be_eq[i].q;
-               eqe = queue_tail_node(eq);
-               num_processed = 0;
-               while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
-                                       & EQE_VALID_MASK) {
-                       AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
-                       queue_tail_inc(eq);
-                       eqe = queue_tail_node(eq);
-                       num_processed++;
-               }
-
-               if (num_processed)
-                       hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1);
-       }
-}
-
 static void beiscsi_cleanup_port(struct beiscsi_hba *phba)
 {
        struct ulp_cid_info *ptr_cid_info = NULL;
        int ulp_num;
 
-       for (ulp_num = 0; ulp_num < BEISCSI_ULP_COUNT; ulp_num++)
-               if (test_bit(ulp_num, (void *)&phba->fw_config.ulp_supported))
-                       beiscsi_cmd_iscsi_cleanup(phba, ulp_num);
-
-       hwi_purge_eq(phba);
-       hwi_cleanup_port(phba);
        kfree(phba->io_sgl_hndl_base);
        kfree(phba->eh_sgl_hndl_base);
        kfree(phba->ep_array);
@@ -4266,7 +4316,6 @@ static void beiscsi_cleanup_port(struct beiscsi_hba *phba)
                        }
                }
        }
-
 }
 
 /**
@@ -4840,7 +4889,7 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
         * operational if FW still gets heartbeat from EP FW. Is management
         * path really needed to continue further?
         */
-       if (beiscsi_hba_in_error(phba))
+       if (!beiscsi_hba_is_online(phba))
                return -EIO;
 
        if (!io_task->conn->login_in_progress)
@@ -4896,7 +4945,7 @@ static int beiscsi_bsg_request(struct bsg_job *job)
        shost = iscsi_job_to_shost(job);
        phba = iscsi_host_priv(shost);
 
-       if (beiscsi_hba_in_error(phba)) {
+       if (!beiscsi_hba_is_online(phba)) {
                beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
                            "BM_%d : HBA in error 0x%lx\n", phba->state);
                return -ENXIO;
@@ -4929,6 +4978,14 @@ static int beiscsi_bsg_request(struct bsg_job *job)
                                        phba->ctrl.mcc_tag_status[tag],
                                        msecs_to_jiffies(
                                        BEISCSI_HOST_MBX_TIMEOUT));
+
+               if (!test_bit(BEISCSI_HBA_ONLINE, &phba->state)) {
+                       clear_bit(MCC_TAG_STATE_RUNNING,
+                                 &phba->ctrl.ptag_state[tag].tag_state);
+                       pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+                                           nonemb_cmd.va, nonemb_cmd.dma);
+                       return -EIO;
+               }
                extd_status = (phba->ctrl.mcc_tag_status[tag] &
                               CQE_STATUS_ADDL_MASK) >> CQE_STATUS_ADDL_SHIFT;
                status = phba->ctrl.mcc_tag_status[tag] & CQE_STATUS_MASK;
@@ -4972,102 +5029,10 @@ void beiscsi_hba_attrs_init(struct beiscsi_hba *phba)
        beiscsi_log_enable_init(phba, beiscsi_log_enable);
 }
 
-/*
- * beiscsi_quiesce()- Cleanup Driver resources
- * @phba: Instance Priv structure
- *
- * Free the OS and HW resources held by the driver
- **/
-static void beiscsi_quiesce(struct beiscsi_hba *phba)
+void beiscsi_start_boot_work(struct beiscsi_hba *phba, unsigned int s_handle)
 {
-       struct hwi_controller *phwi_ctrlr;
-       struct hwi_context_memory *phwi_context;
-       struct be_eq_obj *pbe_eq;
-       unsigned int i, msix_vec;
-
-       phwi_ctrlr = phba->phwi_ctrlr;
-       phwi_context = phwi_ctrlr->phwi_ctxt;
-       hwi_disable_intr(phba);
-       if (phba->msix_enabled) {
-               for (i = 0; i <= phba->num_cpus; i++) {
-                       msix_vec = phba->msix_entries[i].vector;
-                       free_irq(msix_vec, &phwi_context->be_eq[i]);
-                       kfree(phba->msi_name[i]);
-               }
-       } else
-               if (phba->pcidev->irq)
-                       free_irq(phba->pcidev->irq, phba);
-       pci_disable_msix(phba->pcidev);
-       cancel_delayed_work_sync(&phba->eqd_update);
-       cancel_work_sync(&phba->boot_work);
-       del_timer_sync(&phba->hw_check);
-
-       for (i = 0; i < phba->num_cpus; i++) {
-               pbe_eq = &phwi_context->be_eq[i];
-               irq_poll_disable(&pbe_eq->iopoll);
-       }
-
-       /* PCI_ERR is set then check if driver is not unloading */
-       if (test_bit(BEISCSI_HBA_RUNNING, &phba->state) &&
-           test_bit(BEISCSI_HBA_PCI_ERR, &phba->state)) {
-               hwi_cleanup_port(phba);
-               return;
-       }
-
-       destroy_workqueue(phba->wq);
-       beiscsi_cleanup_port(phba);
-       beiscsi_free_mem(phba);
-
-       beiscsi_unmap_pci_function(phba);
-       pci_free_consistent(phba->pcidev,
-                           phba->ctrl.mbox_mem_alloced.size,
-                           phba->ctrl.mbox_mem_alloced.va,
-                           phba->ctrl.mbox_mem_alloced.dma);
-}
-
-static void beiscsi_remove(struct pci_dev *pcidev)
-{
-       struct beiscsi_hba *phba = NULL;
-
-       phba = pci_get_drvdata(pcidev);
-       if (!phba) {
-               dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n");
-               return;
-       }
-
-       clear_bit(BEISCSI_HBA_RUNNING, &phba->state);
-       beiscsi_iface_destroy_default(phba);
-       iscsi_host_remove(phba->shost);
-       beiscsi_quiesce(phba);
-       /* after cancelling boot_work */
-       iscsi_boot_destroy_kset(phba->boot_struct.boot_kset);
-       pci_dev_put(phba->pcidev);
-       iscsi_host_free(phba->shost);
-       pci_disable_pcie_error_reporting(pcidev);
-       pci_set_drvdata(pcidev, NULL);
-       pci_release_regions(pcidev);
-       pci_disable_device(pcidev);
-}
-
-static void beiscsi_msix_enable(struct beiscsi_hba *phba)
-{
-       int i, status;
-
-       for (i = 0; i <= phba->num_cpus; i++)
-               phba->msix_entries[i].entry = i;
-
-       status = pci_enable_msix_range(phba->pcidev, phba->msix_entries,
-                                      phba->num_cpus + 1, phba->num_cpus + 1);
-       if (status > 0)
-               phba->msix_enabled = true;
-
-       return;
-}
-
-void beiscsi_start_boot_work(struct beiscsi_hba *phba, unsigned int s_handle)
-{
-       if (phba->boot_struct.boot_kset)
-               return;
+       if (phba->boot_struct.boot_kset)
+               return;
 
        /* skip if boot work is already in progress */
        if (test_and_set_bit(BEISCSI_HBA_BOOT_WORK, &phba->state))
@@ -5179,7 +5144,6 @@ static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf)
        return rc;
 }
 
-
 static umode_t beiscsi_tgt_get_attr_visibility(void *data, int type)
 {
        umode_t rc = 0;
@@ -5212,7 +5176,6 @@ static umode_t beiscsi_ini_get_attr_visibility(void *data, int type)
        return rc;
 }
 
-
 static umode_t beiscsi_eth_get_attr_visibility(void *data, int type)
 {
        umode_t rc = 0;
@@ -5300,7 +5263,7 @@ static void beiscsi_boot_work(struct work_struct *work)
        struct boot_struct *bs = &phba->boot_struct;
        unsigned int tag = 0;
 
-       if (beiscsi_hba_in_error(phba))
+       if (!beiscsi_hba_is_online(phba))
                return;
 
        beiscsi_log(phba, KERN_INFO,
@@ -5339,19 +5302,6 @@ static void beiscsi_boot_work(struct work_struct *work)
        }
 }
 
-static void beiscsi_hw_health_check(unsigned long ptr)
-{
-       struct beiscsi_hba *phba;
-
-       phba = (struct beiscsi_hba *)ptr;
-       beiscsi_ue_detect(phba);
-       if (test_bit(BEISCSI_HBA_IN_UE, &phba->state))
-               return;
-
-       mod_timer(&phba->hw_check,
-                 jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL));
-}
-
 static void beiscsi_eqd_update_work(struct work_struct *work)
 {
        struct hwi_context_memory *phwi_context;
@@ -5365,7 +5315,7 @@ static void beiscsi_eqd_update_work(struct work_struct *work)
        unsigned long now;
 
        phba = container_of(work, struct beiscsi_hba, eqd_update.work);
-       if (beiscsi_hba_in_error(phba))
+       if (!beiscsi_hba_is_online(phba))
                return;
 
        phwi_ctrlr = phba->phwi_ctrlr;
@@ -5408,6 +5358,219 @@ static void beiscsi_eqd_update_work(struct work_struct *work)
                              msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL));
 }
 
+static void beiscsi_msix_enable(struct beiscsi_hba *phba)
+{
+       int i, status;
+
+       for (i = 0; i <= phba->num_cpus; i++)
+               phba->msix_entries[i].entry = i;
+
+       status = pci_enable_msix_range(phba->pcidev, phba->msix_entries,
+                                      phba->num_cpus + 1, phba->num_cpus + 1);
+       if (status > 0)
+               phba->msix_enabled = true;
+}
+
+static void beiscsi_hw_tpe_check(unsigned long ptr)
+{
+       struct beiscsi_hba *phba;
+       u32 wait;
+
+       phba = (struct beiscsi_hba *)ptr;
+       /* if not TPE, do nothing */
+       if (!beiscsi_detect_tpe(phba))
+               return;
+
+       /* wait default 4000ms before recovering */
+       wait = 4000;
+       if (phba->ue2rp > BEISCSI_UE_DETECT_INTERVAL)
+               wait = phba->ue2rp - BEISCSI_UE_DETECT_INTERVAL;
+       queue_delayed_work(phba->wq, &phba->recover_port,
+                          msecs_to_jiffies(wait));
+}
+
+static void beiscsi_hw_health_check(unsigned long ptr)
+{
+       struct beiscsi_hba *phba;
+
+       phba = (struct beiscsi_hba *)ptr;
+       beiscsi_detect_ue(phba);
+       if (beiscsi_detect_ue(phba)) {
+               __beiscsi_log(phba, KERN_ERR,
+                             "BM_%d : port in error: %lx\n", phba->state);
+               /* detect TPE if UER supported */
+               if (!test_bit(BEISCSI_HBA_UER_SUPP, &phba->state))
+                       return;
+               /* modify this timer to check TPE */
+               phba->hw_check.function = beiscsi_hw_tpe_check;
+       }
+
+       mod_timer(&phba->hw_check,
+                 jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL));
+}
+
+/*
+ * beiscsi_enable_port()- Enables the disabled port.
+ * Only port resources freed in disable function are reallocated.
+ * This is called in HBA error handling path.
+ *
+ * @phba: Instance of driver private structure
+ *
+ **/
+static int beiscsi_enable_port(struct beiscsi_hba *phba)
+{
+       struct hwi_context_memory *phwi_context;
+       struct hwi_controller *phwi_ctrlr;
+       struct be_eq_obj *pbe_eq;
+       int ret, i;
+
+       if (test_bit(BEISCSI_HBA_ONLINE, &phba->state)) {
+               __beiscsi_log(phba, KERN_ERR,
+                             "BM_%d : %s : port is online %lx\n",
+                             __func__, phba->state);
+               return 0;
+       }
+
+       ret = beiscsi_init_sliport(phba);
+       if (ret)
+               return ret;
+
+       if (enable_msix)
+               find_num_cpus(phba);
+       else
+               phba->num_cpus = 1;
+       if (enable_msix) {
+               beiscsi_msix_enable(phba);
+               if (!phba->msix_enabled)
+                       phba->num_cpus = 1;
+       }
+
+       beiscsi_get_params(phba);
+       /* Re-enable UER. If different TPE occurs then it is recoverable. */
+       beiscsi_set_uer_feature(phba);
+
+       phba->shost->max_id = phba->params.cxns_per_ctrl;
+       phba->shost->can_queue = phba->params.ios_per_ctrl;
+       ret = hwi_init_controller(phba);
+       if (ret) {
+               __beiscsi_log(phba, KERN_ERR,
+                             "BM_%d : init controller failed %d\n", ret);
+               goto disable_msix;
+       }
+
+       for (i = 0; i < MAX_MCC_CMD; i++) {
+               init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]);
+               phba->ctrl.mcc_tag[i] = i + 1;
+               phba->ctrl.mcc_tag_status[i + 1] = 0;
+               phba->ctrl.mcc_tag_available++;
+       }
+
+       phwi_ctrlr = phba->phwi_ctrlr;
+       phwi_context = phwi_ctrlr->phwi_ctxt;
+       for (i = 0; i < phba->num_cpus; i++) {
+               pbe_eq = &phwi_context->be_eq[i];
+               irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, be_iopoll);
+       }
+
+       i = (phba->msix_enabled) ? i : 0;
+       /* Work item for MCC handling */
+       pbe_eq = &phwi_context->be_eq[i];
+       INIT_WORK(&pbe_eq->mcc_work, beiscsi_mcc_work);
+
+       ret = beiscsi_init_irqs(phba);
+       if (ret < 0) {
+               __beiscsi_log(phba, KERN_ERR,
+                             "BM_%d : setup IRQs failed %d\n", ret);
+               goto cleanup_port;
+       }
+       hwi_enable_intr(phba);
+       /* port operational: clear all error bits */
+       set_bit(BEISCSI_HBA_ONLINE, &phba->state);
+       __beiscsi_log(phba, KERN_INFO,
+                     "BM_%d : port online: 0x%lx\n", phba->state);
+
+       /* start hw_check timer and eqd_update work */
+       schedule_delayed_work(&phba->eqd_update,
+                             msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL));
+
+       /**
+        * Timer function gets modified for TPE detection.
+        * Always reinit to do health check first.
+        */
+       phba->hw_check.function = beiscsi_hw_health_check;
+       mod_timer(&phba->hw_check,
+                 jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL));
+       return 0;
+
+cleanup_port:
+       for (i = 0; i < phba->num_cpus; i++) {
+               pbe_eq = &phwi_context->be_eq[i];
+               irq_poll_disable(&pbe_eq->iopoll);
+       }
+       hwi_cleanup_port(phba);
+
+disable_msix:
+       if (phba->msix_enabled)
+               pci_disable_msix(phba->pcidev);
+
+       return ret;
+}
+
+/*
+ * beiscsi_disable_port()- Disable port and cleanup driver resources.
+ * This is called in HBA error handling and driver removal.
+ * @phba: Instance Priv structure
+ * @unload: indicate driver is unloading
+ *
+ * Free the OS and HW resources held by the driver
+ **/
+static void beiscsi_disable_port(struct beiscsi_hba *phba, int unload)
+{
+       struct hwi_context_memory *phwi_context;
+       struct hwi_controller *phwi_ctrlr;
+       struct be_eq_obj *pbe_eq;
+       unsigned int i, msix_vec;
+
+       if (!test_and_clear_bit(BEISCSI_HBA_ONLINE, &phba->state))
+               return;
+
+       phwi_ctrlr = phba->phwi_ctrlr;
+       phwi_context = phwi_ctrlr->phwi_ctxt;
+       hwi_disable_intr(phba);
+       if (phba->msix_enabled) {
+               for (i = 0; i <= phba->num_cpus; i++) {
+                       msix_vec = phba->msix_entries[i].vector;
+                       free_irq(msix_vec, &phwi_context->be_eq[i]);
+                       kfree(phba->msi_name[i]);
+               }
+       } else
+               if (phba->pcidev->irq)
+                       free_irq(phba->pcidev->irq, phba);
+       pci_disable_msix(phba->pcidev);
+
+       for (i = 0; i < phba->num_cpus; i++) {
+               pbe_eq = &phwi_context->be_eq[i];
+               irq_poll_disable(&pbe_eq->iopoll);
+       }
+       cancel_delayed_work_sync(&phba->eqd_update);
+       cancel_work_sync(&phba->boot_work);
+       /* WQ might be running cancel queued mcc_work if we are not exiting */
+       if (!unload && beiscsi_hba_in_error(phba)) {
+               pbe_eq = &phwi_context->be_eq[i];
+               cancel_work_sync(&pbe_eq->mcc_work);
+       }
+       hwi_cleanup_port(phba);
+}
+
+static void beiscsi_recover_port(struct work_struct *work)
+{
+       struct beiscsi_hba *phba;
+
+       phba = container_of(work, struct beiscsi_hba, recover_port.work);
+       iscsi_host_for_each_session(phba->shost, beiscsi_session_fail);
+       beiscsi_disable_port(phba, 0);
+       beiscsi_enable_port(phba);
+}
 
 static pci_ers_result_t beiscsi_eeh_err_detected(struct pci_dev *pdev,
                pci_channel_state_t state)
@@ -5420,7 +5583,11 @@ static pci_ers_result_t beiscsi_eeh_err_detected(struct pci_dev *pdev,
        beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
                    "BM_%d : EEH error detected\n");
 
-       beiscsi_quiesce(phba);
+       /* first stop UE detection when PCI error detected */
+       del_timer_sync(&phba->hw_check);
+       cancel_delayed_work_sync(&phba->recover_port);
+
+       beiscsi_disable_port(phba, 0);
 
        if (state == pci_channel_io_perm_failure) {
                beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
@@ -5476,82 +5643,16 @@ static pci_ers_result_t beiscsi_eeh_reset(struct pci_dev *pdev)
 
 static void beiscsi_eeh_resume(struct pci_dev *pdev)
 {
-       int ret, i;
-       struct be_eq_obj *pbe_eq;
-       struct beiscsi_hba *phba = NULL;
-       struct hwi_controller *phwi_ctrlr;
-       struct hwi_context_memory *phwi_context;
+       struct beiscsi_hba *phba;
+       int ret;
 
        phba = (struct beiscsi_hba *)pci_get_drvdata(pdev);
        pci_save_state(pdev);
 
-       if (enable_msix)
-               find_num_cpus(phba);
-       else
-               phba->num_cpus = 1;
-
-       if (enable_msix) {
-               beiscsi_msix_enable(phba);
-               if (!phba->msix_enabled)
-                       phba->num_cpus = 1;
-       }
-
-       ret = beiscsi_init_sliport(phba);
+       ret = beiscsi_enable_port(phba);
        if (ret)
-               goto ret_err;
-
-       beiscsi_get_params(phba);
-       phba->shost->max_id = phba->params.cxns_per_ctrl;
-       phba->shost->can_queue = phba->params.ios_per_ctrl;
-       ret = hwi_init_controller(phba);
-       if (ret) {
-               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                           "BM_%d : beiscsi_eeh_resume -"
-                            "Failed to initialize beiscsi_hba.\n");
-               goto ret_err;
-       }
-
-       for (i = 0; i < MAX_MCC_CMD; i++) {
-               init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]);
-               phba->ctrl.mcc_tag[i] = i + 1;
-               phba->ctrl.mcc_tag_status[i + 1] = 0;
-               phba->ctrl.mcc_tag_available++;
-       }
-
-       phwi_ctrlr = phba->phwi_ctrlr;
-       phwi_context = phwi_ctrlr->phwi_ctxt;
-
-       for (i = 0; i < phba->num_cpus; i++) {
-               pbe_eq = &phwi_context->be_eq[i];
-               irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget,
-                               be_iopoll);
-       }
-
-       i = (phba->msix_enabled) ? i : 0;
-       /* Work item for MCC handling */
-       pbe_eq = &phwi_context->be_eq[i];
-       INIT_WORK(&pbe_eq->mcc_work, beiscsi_mcc_work);
-
-       ret = beiscsi_init_irqs(phba);
-       if (ret < 0) {
-               beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                           "BM_%d : beiscsi_eeh_resume - "
-                           "Failed to beiscsi_init_irqs\n");
-               goto ret_err;
-       }
-
-       hwi_enable_intr(phba);
-       clear_bit(BEISCSI_HBA_PCI_ERR, &phba->state);
-
-       /* start hw_check timer and eqd_update work */
-       schedule_delayed_work(&phba->eqd_update,
-                             msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL));
-       mod_timer(&phba->hw_check,
-                 jiffies + msecs_to_jiffies(BEISCSI_UE_DETECT_INTERVAL));
-       return;
-ret_err:
-       beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
-                   "BM_%d : AER EEH Resume Failed\n");
+               __beiscsi_log(phba, KERN_ERR,
+                             "BM_%d : AER EEH resume failed\n");
 }
 
 static int beiscsi_dev_probe(struct pci_dev *pcidev,
@@ -5623,7 +5724,6 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
        if (ret)
                goto hba_free;
 
-       set_bit(BEISCSI_HBA_RUNNING, &phba->state);
        spin_lock_init(&phba->io_sgl_lock);
        spin_lock_init(&phba->mgmt_sgl_lock);
        spin_lock_init(&phba->async_pdu_lock);
@@ -5690,8 +5790,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
 
        for (i = 0; i < phba->num_cpus; i++) {
                pbe_eq = &phwi_context->be_eq[i];
-               irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget,
-                               be_iopoll);
+               irq_poll_init(&pbe_eq->iopoll, be_iopoll_budget, be_iopoll);
        }
 
        i = (phba->msix_enabled) ? i : 0;
@@ -5708,9 +5807,15 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
        }
        hwi_enable_intr(phba);
 
-       if (iscsi_host_add(phba->shost, &phba->pcidev->dev))
+       ret = iscsi_host_add(phba->shost, &phba->pcidev->dev);
+       if (ret)
                goto free_blkenbld;
 
+       /* set online bit after port is operational */
+       set_bit(BEISCSI_HBA_ONLINE, &phba->state);
+       __beiscsi_log(phba, KERN_INFO,
+                     "BM_%d : port online: 0x%lx\n", phba->state);
+
        INIT_WORK(&phba->boot_work, beiscsi_boot_work);
        ret = beiscsi_boot_get_shandle(phba, &s_handle);
        if (ret > 0) {
@@ -5726,6 +5831,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
        beiscsi_iface_create_default(phba);
        schedule_delayed_work(&phba->eqd_update,
                              msecs_to_jiffies(BEISCSI_EQD_UPDATE_INTERVAL));
+
+       INIT_DELAYED_WORK(&phba->recover_port, beiscsi_recover_port);
        /**
         * Start UE detection here. UE before this will cause stall in probe
         * and eventually fail the probe.
@@ -5747,6 +5854,7 @@ free_blkenbld:
                irq_poll_disable(&pbe_eq->iopoll);
        }
 free_twq:
+       hwi_cleanup_port(phba);
        beiscsi_cleanup_port(phba);
        beiscsi_free_mem(phba);
 free_port:
@@ -5767,6 +5875,48 @@ disable_pci:
        return ret;
 }
 
+static void beiscsi_remove(struct pci_dev *pcidev)
+{
+       struct beiscsi_hba *phba = NULL;
+
+       phba = pci_get_drvdata(pcidev);
+       if (!phba) {
+               dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n");
+               return;
+       }
+
+       /* first stop UE detection before unloading */
+       del_timer_sync(&phba->hw_check);
+       cancel_delayed_work_sync(&phba->recover_port);
+
+       beiscsi_iface_destroy_default(phba);
+       iscsi_host_remove(phba->shost);
+       beiscsi_disable_port(phba, 1);
+
+       /* after cancelling boot_work */
+       iscsi_boot_destroy_kset(phba->boot_struct.boot_kset);
+
+       /* free all resources */
+       destroy_workqueue(phba->wq);
+       beiscsi_cleanup_port(phba);
+       beiscsi_free_mem(phba);
+
+       /* ctrl uninit */
+       beiscsi_unmap_pci_function(phba);
+       pci_free_consistent(phba->pcidev,
+                           phba->ctrl.mbox_mem_alloced.size,
+                           phba->ctrl.mbox_mem_alloced.va,
+                           phba->ctrl.mbox_mem_alloced.dma);
+
+       pci_dev_put(phba->pcidev);
+       iscsi_host_free(phba->shost);
+       pci_disable_pcie_error_reporting(pcidev);
+       pci_set_drvdata(pcidev, NULL);
+       pci_release_regions(pcidev);
+       pci_disable_device(pcidev);
+}
+
+
 static struct pci_error_handlers beiscsi_eeh_handlers = {
        .error_detected = beiscsi_eeh_err_detected,
        .slot_reset = beiscsi_eeh_reset,
@@ -5814,7 +5964,6 @@ static struct pci_driver beiscsi_pci_driver = {
        .err_handler = &beiscsi_eeh_handlers
 };
 
-
 static int __init beiscsi_module_init(void)
 {
        int ret;
index 4cdb34c3de5dc31514b0a75af27ec74bf14fa2f7..1fd6c1868366d941f2ba9c6493cedb1ece1ef94f 100644 (file)
@@ -393,7 +393,7 @@ struct beiscsi_hba {
        } fw_config;
 
        unsigned long state;
-#define BEISCSI_HBA_RUNNING    0
+#define BEISCSI_HBA_ONLINE     0
 #define BEISCSI_HBA_LINK_UP    1
 #define BEISCSI_HBA_BOOT_FOUND 2
 #define BEISCSI_HBA_BOOT_WORK  3
@@ -417,6 +417,7 @@ struct beiscsi_hba {
        /* check for UE every 1000ms */
 #define BEISCSI_UE_DETECT_INTERVAL     1000
        u32 ue2rp;
+       struct delayed_work recover_port;
 
        bool mac_addr_set;
        u8 mac_address[ETH_ALEN];
@@ -455,6 +456,9 @@ struct beiscsi_hba {
 };
 
 #define beiscsi_hba_in_error(phba) ((phba)->state & BEISCSI_HBA_IN_ERR)
+#define beiscsi_hba_is_online(phba) \
+       (!beiscsi_hba_in_error((phba)) && \
+        test_bit(BEISCSI_HBA_ONLINE, &phba->state))
 
 struct beiscsi_session {
        struct pci_pool *bhs_pool;
index a844299ea9798f6e82a9e6cb043167fed2d791d3..736eca38ea0bcb630dcaacae307d9a286488194f 100644 (file)
 #include "be_iscsi.h"
 #include "be_main.h"
 
-/* UE Status Low CSR */
-static const char * const desc_ue_status_low[] = {
-       "CEV",
-       "CTX",
-       "DBUF",
-       "ERX",
-       "Host",
-       "MPU",
-       "NDMA",
-       "PTC ",
-       "RDMA ",
-       "RXF ",
-       "RXIPS ",
-       "RXULP0 ",
-       "RXULP1 ",
-       "RXULP2 ",
-       "TIM ",
-       "TPOST ",
-       "TPRE ",
-       "TXIPS ",
-       "TXULP0 ",
-       "TXULP1 ",
-       "UC ",
-       "WDMA ",
-       "TXULP2 ",
-       "HOST1 ",
-       "P0_OB_LINK ",
-       "P1_OB_LINK ",
-       "HOST_GPIO ",
-       "MBOX ",
-       "AXGMAC0",
-       "AXGMAC1",
-       "JTAG",
-       "MPU_INTPEND"
-};
-
-/* UE Status High CSR */
-static const char * const desc_ue_status_hi[] = {
-       "LPCMEMHOST",
-       "MGMT_MAC",
-       "PCS0ONLINE",
-       "MPU_IRAM",
-       "PCS1ONLINE",
-       "PCTL0",
-       "PCTL1",
-       "PMEM",
-       "RR",
-       "TXPB",
-       "RXPP",
-       "XAUI",
-       "TXP",
-       "ARM",
-       "IPC",
-       "HOST2",
-       "HOST3",
-       "HOST4",
-       "HOST5",
-       "HOST6",
-       "HOST7",
-       "HOST8",
-       "HOST9",
-       "NETC",
-       "Unknown",
-       "Unknown",
-       "Unknown",
-       "Unknown",
-       "Unknown",
-       "Unknown",
-       "Unknown",
-       "Unknown"
-};
-
-/*
- * beiscsi_ue_detect()- Detect Unrecoverable Error on adapter
- * @phba: Driver priv structure
- *
- * Read registers linked to UE and check for the UE status
- **/
-void beiscsi_ue_detect(struct beiscsi_hba *phba)
-{
-       uint32_t ue_hi = 0, ue_lo = 0;
-       uint32_t ue_mask_hi = 0, ue_mask_lo = 0;
-       uint8_t i = 0;
-
-       pci_read_config_dword(phba->pcidev,
-                             PCICFG_UE_STATUS_LOW, &ue_lo);
-       pci_read_config_dword(phba->pcidev,
-                             PCICFG_UE_STATUS_MASK_LOW,
-                             &ue_mask_lo);
-       pci_read_config_dword(phba->pcidev,
-                             PCICFG_UE_STATUS_HIGH,
-                             &ue_hi);
-       pci_read_config_dword(phba->pcidev,
-                             PCICFG_UE_STATUS_MASK_HI,
-                             &ue_mask_hi);
-
-       ue_lo = (ue_lo & ~ue_mask_lo);
-       ue_hi = (ue_hi & ~ue_mask_hi);
-
-
-       if (ue_lo || ue_hi) {
-               set_bit(BEISCSI_HBA_IN_UE, &phba->state);
-               beiscsi_log(phba, KERN_ERR,
-                           BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
-                           "BG_%d : HBA error detected\n");
-       }
-
-       if (ue_lo) {
-               for (i = 0; ue_lo; ue_lo >>= 1, i++) {
-                       if (ue_lo & 1)
-                               beiscsi_log(phba, KERN_ERR,
-                                           BEISCSI_LOG_CONFIG,
-                                           "BG_%d : UE_LOW %s bit set\n",
-                                           desc_ue_status_low[i]);
-               }
-       }
-
-       if (ue_hi) {
-               for (i = 0; ue_hi; ue_hi >>= 1, i++) {
-                       if (ue_hi & 1)
-                               beiscsi_log(phba, KERN_ERR,
-                                           BEISCSI_LOG_CONFIG,
-                                           "BG_%d : UE_HIGH %s bit set\n",
-                                           desc_ue_status_hi[i]);
-               }
-       }
-}
-
 int beiscsi_modify_eq_delay(struct beiscsi_hba *phba,
                            struct be_set_eqd *set_eqd,
                            int num)
index dab128fb2ce3ff9e0c75f475b505fe1ef58cf693..ee6fd7e663cd6a388875b5b1955a00be5dda9402 100644 (file)
@@ -329,7 +329,6 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
                             struct wrb_handle *pwrb_handle,
                             struct hwi_wrb_context *pwrb_context);
 
-void beiscsi_ue_detect(struct beiscsi_hba *phba);
 int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
                         struct be_set_eqd *, int num);