[SCSI] qla4xxx: Fix failure of mbox 0x31
authorVikas Chaudhary <vikas.chaudhary@qlogic.com>
Fri, 17 Jan 2014 09:43:28 +0000 (04:43 -0500)
committerJames Bottomley <JBottomley@Parallels.com>
Sat, 15 Mar 2014 17:19:15 +0000 (10:19 -0700)
Issue:
While unloading driver MBOX 0x31 fail as DDB logout (MBOX 0x56)
operation is not completed.

Fix:
Wait for DDB Logout completion before MBOX 0x31

Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/qla4xxx/ql4_os.c

index a27da31..7807a13 100644 (file)
@@ -8886,10 +8886,56 @@ static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha)
        }
 }
 
+static void qla4xxx_destroy_ddb(struct scsi_qla_host *ha,
+               struct ddb_entry *ddb_entry)
+{
+       struct dev_db_entry *fw_ddb_entry = NULL;
+       dma_addr_t fw_ddb_entry_dma;
+       unsigned long wtime;
+       uint32_t ddb_state;
+       int options;
+       int status;
+
+       options = LOGOUT_OPTION_CLOSE_SESSION;
+       if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) {
+               ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
+               goto clear_ddb;
+       }
+
+       fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+                                         &fw_ddb_entry_dma, GFP_KERNEL);
+       if (!fw_ddb_entry) {
+               ql4_printk(KERN_ERR, ha,
+                          "%s: Unable to allocate dma buffer\n", __func__);
+               goto clear_ddb;
+       }
+
+       wtime = jiffies + (HZ * LOGOUT_TOV);
+       do {
+               status = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
+                                                fw_ddb_entry, fw_ddb_entry_dma,
+                                                NULL, NULL, &ddb_state, NULL,
+                                                NULL, NULL);
+               if (status == QLA_ERROR)
+                       goto free_ddb;
+
+               if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
+                   (ddb_state == DDB_DS_SESSION_FAILED))
+                       goto free_ddb;
+
+               schedule_timeout_uninterruptible(HZ);
+       } while ((time_after(wtime, jiffies)));
+
+free_ddb:
+       dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+                         fw_ddb_entry, fw_ddb_entry_dma);
+clear_ddb:
+       qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
+}
+
 static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
 {
        struct ddb_entry *ddb_entry;
-       int options;
        int idx;
 
        for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
@@ -8898,13 +8944,7 @@ static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
                if ((ddb_entry != NULL) &&
                    (ddb_entry->ddb_type == FLASH_DDB)) {
 
-                       options = LOGOUT_OPTION_CLOSE_SESSION;
-                       if (qla4xxx_session_logout_ddb(ha, ddb_entry, options)
-                           == QLA_ERROR)
-                               ql4_printk(KERN_ERR, ha, "%s: Logout failed\n",
-                                          __func__);
-
-                       qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
+                       qla4xxx_destroy_ddb(ha, ddb_entry);
                        /*
                         * we have decremented the reference count of the driver
                         * when we setup the session to have the driver unload