[SCSI] mpt2sas : Add support for RAID Action System Shutdown Initiated at OS shutdown
authorKashyap, Desai <kashyap.desai@lsi.com>
Mon, 5 Oct 2009 10:26:56 +0000 (15:56 +0530)
committerJames Bottomley <James.Bottomley@suse.de>
Thu, 29 Oct 2009 17:03:16 +0000 (13:03 -0400)
(1) Added new function _scsih_ir_shutdown.  This function will issue the
MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED request via
MPI2_FUNCTION_RAID_ACTION. The function will wait 10 seconds for reply
message frame, then print out the ioc status and loginfo.  This function is
only called when there are raid volumes present.

(2) Add shutdown callback in the struct pci_driver object scsih_driver. This
will be called only when the system is shutting down. From this function, we
will call _scsih_ir_shutdown mentioned above.

(3) Add support in _scsih_remove to call _scsih_ir_shutdown. The function
_scsih_remove will be called when the driver is unloaded (and system is
still running).

scsih internal command contex is added to send internal message frames
from mpt2sas_scsih.c.

Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com>
Signed-off-by: Eric Moore <Eric.moore@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/mpt2sas/mpt2sas_base.h
drivers/scsi/mpt2sas/mpt2sas_scsih.c

index 7efb6ab749dffa6a8f6729baf74963fd717678a8..eb51fe9f369d247e154209c1a5cab2819b3c9b45 100644 (file)
@@ -492,12 +492,14 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
  * @msix_table_backup: backup msix table
  * @scsi_io_cb_idx: shost generated commands
  * @tm_cb_idx: task management commands
+ * @scsih_cb_idx: scsih internal commands
  * @transport_cb_idx: transport internal commands
  * @ctl_cb_idx: clt internal commands
  * @base_cb_idx: base internal commands
  * @config_cb_idx: base internal commands
  * @base_cmds:
  * @transport_cmds:
+ * @scsih_cmds:
  * @tm_cmds:
  * @ctl_cmds:
  * @config_cmds:
@@ -624,6 +626,7 @@ struct MPT2SAS_ADAPTER {
        u8              scsi_io_cb_idx;
        u8              tm_cb_idx;
        u8              transport_cb_idx;
+       u8              scsih_cb_idx;
        u8              ctl_cb_idx;
        u8              base_cb_idx;
        u8              config_cb_idx;
@@ -631,6 +634,7 @@ struct MPT2SAS_ADAPTER {
        u8              tm_sas_control_cb_idx;
        struct _internal_cmd base_cmds;
        struct _internal_cmd transport_cmds;
+       struct _internal_cmd scsih_cmds;
        struct _internal_cmd tm_cmds;
        struct _internal_cmd ctl_cmds;
        struct _internal_cmd config_cmds;
index c81e84291d2eb8bbb18c7c341ebd3ab62a3a3880..5916bddf3551b51bf362e88dcfc62a8e2028122a 100644 (file)
@@ -76,6 +76,7 @@ static u8 tm_cb_idx = -1;
 static u8 ctl_cb_idx = -1;
 static u8 base_cb_idx = -1;
 static u8 transport_cb_idx = -1;
+static u8 scsih_cb_idx = -1;
 static u8 config_cb_idx = -1;
 static int mpt_ids;
 
@@ -3793,6 +3794,40 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
        return rc;
 }
 
+/**
+ * _scsih_done -  scsih callback handler.
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @msix_index: MSIX table index supplied by the OS
+ * @reply: reply message frame(lower 32bit addr)
+ *
+ * Callback handler when sending internal generated message frames.
+ * The callback index passed is `ioc->scsih_cb_idx`
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ *        0 means the mf is freed from this function.
+ */
+static u8
+_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
+{
+       MPI2DefaultReply_t *mpi_reply;
+
+       mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);
+       if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
+               return 1;
+       if (ioc->scsih_cmds.smid != smid)
+               return 1;
+       ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
+       if (mpi_reply) {
+               memcpy(ioc->scsih_cmds.reply, mpi_reply,
+                   mpi_reply->MsgLength*4);
+               ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
+       }
+       ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
+       complete(&ioc->scsih_cmds.done);
+       return 1;
+}
+
 /**
  * _scsih_expander_remove - removing expander object
  * @ioc: per adapter object
@@ -5853,10 +5888,100 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
        kfree(sas_expander);
 }
 
+/**
+ * _scsih_ir_shutdown - IR shutdown notification
+ * @ioc: per adapter object
+ *
+ * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
+ * the host system is shutting down.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
+{
+       Mpi2RaidActionRequest_t *mpi_request;
+       Mpi2RaidActionReply_t *mpi_reply;
+       u16 smid;
+
+       /* is IR firmware build loaded ? */
+       if (!ioc->ir_firmware)
+               return;
+
+       /* are there any volumes ? */
+       if (list_empty(&ioc->raid_device_list))
+               return;
+
+       mutex_lock(&ioc->scsih_cmds.mutex);
+
+       if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
+               printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
+                   ioc->name, __func__);
+               goto out;
+       }
+       ioc->scsih_cmds.status = MPT2_CMD_PENDING;
+
+       smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
+       if (!smid) {
+               printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+                   ioc->name, __func__);
+               ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
+               goto out;
+       }
+
+       mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
+       ioc->scsih_cmds.smid = smid;
+       memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
+
+       mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
+       mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
+
+       printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
+       init_completion(&ioc->scsih_cmds.done);
+       mpt2sas_base_put_smid_default(ioc, smid);
+       wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
+
+       if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
+               printk(MPT2SAS_ERR_FMT "%s: timeout\n",
+                   ioc->name, __func__);
+               goto out;
+       }
+
+       if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
+               mpi_reply = ioc->scsih_cmds.reply;
+
+               printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
+                   "ioc_status(0x%04x), loginfo(0x%08x)\n",
+                   ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
+                   le32_to_cpu(mpi_reply->IOCLogInfo));
+       }
+
+ out:
+       ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
+       mutex_unlock(&ioc->scsih_cmds.mutex);
+}
+
+/**
+ * _scsih_shutdown - routine call during system shutdown
+ * @pdev: PCI device struct
+ *
+ * Return nothing.
+ */
+static void
+_scsih_shutdown(struct pci_dev *pdev)
+{
+       struct Scsi_Host *shost = pci_get_drvdata(pdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+
+       _scsih_ir_shutdown(ioc);
+       mpt2sas_base_detach(ioc);
+}
+
 /**
  * _scsih_remove - detach and remove add host
  * @pdev: PCI device struct
  *
+ * Routine called when unloading the driver.
  * Return nothing.
  */
 static void __devexit
@@ -5913,7 +6038,7 @@ _scsih_remove(struct pci_dev *pdev)
        }
 
        sas_remove_host(shost);
-       mpt2sas_base_detach(ioc);
+       _scsih_shutdown(pdev);
        list_del(&ioc->list);
        scsi_remove_host(shost);
        scsi_host_put(shost);
@@ -6097,6 +6222,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        ioc->ctl_cb_idx = ctl_cb_idx;
        ioc->base_cb_idx = base_cb_idx;
        ioc->transport_cb_idx = transport_cb_idx;
+       ioc->scsih_cb_idx = scsih_cb_idx;
        ioc->config_cb_idx = config_cb_idx;
        ioc->tm_tr_cb_idx = tm_tr_cb_idx;
        ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
@@ -6234,6 +6360,7 @@ static struct pci_driver scsih_driver = {
        .id_table       = scsih_pci_table,
        .probe          = _scsih_probe,
        .remove         = __devexit_p(_scsih_remove),
+       .shutdown       = _scsih_shutdown,
 #ifdef CONFIG_PM
        .suspend        = _scsih_suspend,
        .resume         = _scsih_resume,
@@ -6275,6 +6402,9 @@ _scsih_init(void)
        transport_cb_idx = mpt2sas_base_register_callback_handler(
            mpt2sas_transport_done);
 
+       /* scsih internal commands callback handler */
+       scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
+
        /* configuration page API internal commands callback handler */
        config_cb_idx = mpt2sas_base_register_callback_handler(
            mpt2sas_config_done);
@@ -6314,6 +6444,7 @@ _scsih_exit(void)
        mpt2sas_base_release_callback_handler(tm_cb_idx);
        mpt2sas_base_release_callback_handler(base_cb_idx);
        mpt2sas_base_release_callback_handler(transport_cb_idx);
+       mpt2sas_base_release_callback_handler(scsih_cb_idx);
        mpt2sas_base_release_callback_handler(config_cb_idx);
        mpt2sas_base_release_callback_handler(ctl_cb_idx);