[SCSI] be2iscsi: Fix Unrecoverable Error Detection
authorJohn Soni Jose <sony.john-n@emulex.com>
Fri, 19 Oct 2012 23:15:51 +0000 (04:45 +0530)
committerJames Bottomley <JBottomley@Parallels.com>
Tue, 27 Nov 2012 04:59:42 +0000 (08:59 +0400)
Driver periodically checks adapter state,is up fine or not.
Based on the value updates the internal structures of driver.

Signed-off-by: John Soni Jose <sony.john-n@emulex.com>
Signed-off-by: Jayamohan Kallickal <jayamohan.kallickal@emulex.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/be2iscsi/be_cmds.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 352fc53..5c87768 100644 (file)
@@ -157,6 +157,9 @@ int beiscsi_mccq_compl(struct beiscsi_hba *phba,
        struct be_cmd_req_hdr *ioctl_hdr;
        struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q;
 
+       if (beiscsi_error(phba))
+               return -EIO;
+
        /* wait for the mccq completion */
        rc = wait_event_interruptible_timeout(
                                phba->ctrl.mcc_wait[tag],
@@ -423,7 +426,7 @@ static int be_mcc_wait_compl(struct beiscsi_hba *phba)
 {
        int i, status;
        for (i = 0; i < mcc_timeout; i++) {
-               if (phba->fw_timeout)
+               if (beiscsi_error(phba))
                        return -EIO;
 
                status = beiscsi_process_mcc(phba);
@@ -439,6 +442,7 @@ static int be_mcc_wait_compl(struct beiscsi_hba *phba)
                            BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
                            "BC_%d : FW Timed Out\n");
                phba->fw_timeout = true;
+               beiscsi_ue_detect(phba);
                return -EBUSY;
        }
        return 0;
@@ -479,7 +483,8 @@ static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
        u32 ready;
 
        do {
-               if (phba->fw_timeout)
+
+               if (beiscsi_error(phba))
                        return -EIO;
 
                ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
@@ -491,6 +496,7 @@ static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
                                    BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
                                    "BC_%d : FW Timed Out\n");
                        phba->fw_timeout = true;
+                       beiscsi_ue_detect(phba);
                        return -EBUSY;
                }
 
index 73a29b2..48d37dd 100644 (file)
@@ -4717,6 +4717,8 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba)
                            phba->ctrl.mbox_mem_alloced.size,
                            phba->ctrl.mbox_mem_alloced.va,
                            phba->ctrl.mbox_mem_alloced.dma);
+
+       cancel_delayed_work_sync(&phba->beiscsi_hw_check_task);
 }
 
 static void beiscsi_remove(struct pci_dev *pcidev)
@@ -4769,6 +4771,25 @@ static void beiscsi_msix_enable(struct beiscsi_hba *phba)
        return;
 }
 
+/*
+ * beiscsi_hw_health_check()- Check adapter health
+ * @work: work item to check HW health
+ *
+ * Check if adapter in an unrecoverable state or not.
+ **/
+static void
+beiscsi_hw_health_check(struct work_struct *work)
+{
+       struct beiscsi_hba *phba =
+               container_of(work, struct beiscsi_hba,
+                            beiscsi_hw_check_task.work);
+
+       beiscsi_ue_detect(phba);
+
+       schedule_delayed_work(&phba->beiscsi_hw_check_task,
+                             msecs_to_jiffies(1000));
+}
+
 static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
                                const struct pci_device_id *id)
 {
@@ -4892,6 +4913,8 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
                goto free_twq;
        }
 
+       INIT_DELAYED_WORK(&phba->beiscsi_hw_check_task,
+                         beiscsi_hw_health_check);
 
        phwi_ctrlr = phba->phwi_ctrlr;
        phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -4941,6 +4964,9 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
                            "iSCSI boot info.\n");
 
        beiscsi_create_def_ifaces(phba);
+       schedule_delayed_work(&phba->beiscsi_hw_check_task,
+                             msecs_to_jiffies(1000));
+
        beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_INIT,
                    "\n\n\n BM_%d : SUCCESS - DRIVER LOADED\n\n\n");
        return 0;
index 033c053..5b27275 100644 (file)
@@ -750,6 +750,11 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle);
 
 void beiscsi_process_all_cqs(struct work_struct *work);
 
+static inline bool beiscsi_error(struct beiscsi_hba *phba)
+{
+       return phba->ue_detected || phba->fw_timeout;
+}
+
 struct pdu_nop_out {
        u32 dw[12];
 };
index 688bf64..a6c2fe4 100644 (file)
 #include <scsi/scsi_bsg_iscsi.h>
 #include "be_mgmt.h"
 #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_detec()- 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;
+
+       if (phba->ue_detected)
+               return;
+
+       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) {
+               phba->ue_detected = true;
+               beiscsi_log(phba, KERN_ERR,
+                           BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
+                           "BG_%d : Error detected on the adapter\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]);
+               }
+       }
+}
 
 /**
  * mgmt_reopen_session()- Reopen a session based on reopen_type
index 88a8ed2..2e4968a 100644 (file)
 #define IP_V6_LEN      16
 #define IP_V4_LEN      4
 
+/* UE Status and Mask register */
+#define PCICFG_UE_STATUS_LOW            0xA0
+#define PCICFG_UE_STATUS_HIGH           0xA4
+#define PCICFG_UE_STATUS_MASK_LOW       0xA8
+#define PCICFG_UE_STATUS_MASK_HI        0xAC
+
 /**
  * Pseudo amap definition in which each bit of the actual structure is defined
  * as a byte: used to calculate offset/shift/mask of each field
@@ -314,5 +320,6 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
 
 void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
                             struct wrb_handle *pwrb_handle);
+void beiscsi_ue_detect(struct beiscsi_hba *phba);
 
 #endif