[SCSI] qla2xxx: Addition of shutdown callback handler.
authorMadhuranath Iyengar <Madhu.Iyengar@qlogic.com>
Fri, 15 Oct 2010 18:27:46 +0000 (11:27 -0700)
committerJames Bottomley <James.Bottomley@suse.de>
Mon, 25 Oct 2010 21:03:18 +0000 (16:03 -0500)
This patch adds a shutdown handler to qla2xxx driver to make sure that all
DMA and firmware activities are stopped, and any associated driver resources
are released. The need for this handler arose when executing kexec in specific
environments caused the data of the 2nd kernel to be corrupted, due to DMA
activities.

Signed-off-by: Madhuranath Iyengar <Madhu.Iyengar@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_os.c

index 77c68a7..a7ad22b 100644 (file)
@@ -1344,6 +1344,13 @@ cont_alloc:
                qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
                    "firmware dump!!!\n", dump_size / 1024);
 
+               if (ha->fce) {
+                       dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
+                           ha->fce_dma);
+                       ha->fce = NULL;
+                       ha->fce_dma = 0;
+               }
+
                if (ha->eft) {
                        dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
                            ha->eft_dma);
index 941b4a6..05977e7 100644 (file)
@@ -260,6 +260,7 @@ static void qla2x00_rst_aen(scsi_qla_host_t *);
 
 static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t,
        struct req_que **, struct rsp_que **);
+static void qla2x00_free_fw_dump(struct qla_hw_data *);
 static void qla2x00_mem_free(struct qla_hw_data *);
 static void qla2x00_sp_free_dma(srb_t *);
 
@@ -2341,6 +2342,42 @@ probe_out:
        return ret;
 }
 
+static void
+qla2x00_shutdown(struct pci_dev *pdev)
+{
+       scsi_qla_host_t *vha;
+       struct qla_hw_data  *ha;
+
+       vha = pci_get_drvdata(pdev);
+       ha = vha->hw;
+
+       /* Turn-off FCE trace */
+       if (ha->flags.fce_enabled) {
+               qla2x00_disable_fce_trace(vha, NULL, NULL);
+               ha->flags.fce_enabled = 0;
+       }
+
+       /* Turn-off EFT trace */
+       if (ha->eft)
+               qla2x00_disable_eft_trace(vha);
+
+       /* Stop currently executing firmware. */
+       qla2x00_try_to_stop_firmware(vha);
+
+       /* Turn adapter off line */
+       vha->flags.online = 0;
+
+       /* turn-off interrupts on the card */
+       if (ha->interrupts_on) {
+               vha->flags.init_done = 0;
+               ha->isp_ops->disable_intrs(ha);
+       }
+
+       qla2x00_free_irqs(vha);
+
+       qla2x00_free_fw_dump(ha);
+}
+
 static void
 qla2x00_remove_one(struct pci_dev *pdev)
 {
@@ -2830,28 +2867,48 @@ fail:
 }
 
 /*
-* qla2x00_mem_free
-*      Frees all adapter allocated memory.
+* qla2x00_free_fw_dump
+*      Frees fw dump stuff.
 *
 * Input:
-*      ha = adapter block pointer.
+*      ha = adapter block pointer.
 */
 static void
-qla2x00_mem_free(struct qla_hw_data *ha)
+qla2x00_free_fw_dump(struct qla_hw_data *ha)
 {
-       if (ha->srb_mempool)
-               mempool_destroy(ha->srb_mempool);
-
        if (ha->fce)
                dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
-               ha->fce_dma);
+                   ha->fce_dma);
 
        if (ha->fw_dump) {
                if (ha->eft)
                        dma_free_coherent(&ha->pdev->dev,
-                       ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
+                           ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
                vfree(ha->fw_dump);
        }
+       ha->fce = NULL;
+       ha->fce_dma = 0;
+       ha->eft = NULL;
+       ha->eft_dma = 0;
+       ha->fw_dump = NULL;
+       ha->fw_dumped = 0;
+       ha->fw_dump_reading = 0;
+}
+
+/*
+* qla2x00_mem_free
+*      Frees all adapter allocated memory.
+*
+* Input:
+*      ha = adapter block pointer.
+*/
+static void
+qla2x00_mem_free(struct qla_hw_data *ha)
+{
+       qla2x00_free_fw_dump(ha);
+
+       if (ha->srb_mempool)
+               mempool_destroy(ha->srb_mempool);
 
        if (ha->dcbx_tlv)
                dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
@@ -2925,8 +2982,6 @@ qla2x00_mem_free(struct qla_hw_data *ha)
 
        ha->srb_mempool = NULL;
        ha->ctx_mempool = NULL;
-       ha->eft = NULL;
-       ha->eft_dma = 0;
        ha->sns_cmd = NULL;
        ha->sns_cmd_dma = 0;
        ha->ct_sns = NULL;
@@ -2946,10 +3001,6 @@ qla2x00_mem_free(struct qla_hw_data *ha)
 
        ha->gid_list = NULL;
        ha->gid_list_dma = 0;
-
-       ha->fw_dump = NULL;
-       ha->fw_dumped = 0;
-       ha->fw_dump_reading = 0;
 }
 
 struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
@@ -4049,6 +4100,7 @@ static struct pci_driver qla2xxx_pci_driver = {
        .id_table       = qla2xxx_pci_tbl,
        .probe          = qla2x00_probe_one,
        .remove         = qla2x00_remove_one,
+       .shutdown       = qla2x00_shutdown,
        .err_handler    = &qla2xxx_err_handler,
 };