[SCSI] mpt2sas: move even handling of MPT2SAS_TURN_ON_FAULT_LED into process context
authorKashyap, Desai <kashyap.desai@lsi.com>
Wed, 4 May 2011 11:05:58 +0000 (16:35 +0530)
committerJames Bottomley <jbottomley@parallels.com>
Tue, 24 May 2011 16:33:01 +0000 (12:33 -0400)
Driver was a sending a SEP request during interrupt context which
required to go to sleep.

The fix is to rearrange the code so a fake event
MPT2SAS_TURN_ON_FAULT_LED is fired from interrupt context, then later
during the kernel worker threads processing, the SEP request is issued
to firmware.

Cc: stable@kernel.org
Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com>
Signed-off-by: James Bottomley <jbottomley@parallels.com>
drivers/scsi/mpt2sas/mpt2sas_scsih.c

index f12e023..e97363c 100644 (file)
@@ -113,6 +113,7 @@ struct sense_info {
 };
 
 
+#define MPT2SAS_TURN_ON_FAULT_LED (0xFFFC)
 #define MPT2SAS_RESCAN_AFTER_HOST_RESET (0xFFFF)
 
 /**
@@ -121,6 +122,7 @@ struct sense_info {
  * @work: work object (ioc->fault_reset_work_q)
  * @cancel_pending_work: flag set during reset handling
  * @ioc: per adapter object
+ * @device_handle: device handle
  * @VF_ID: virtual function id
  * @VP_ID: virtual port id
  * @ignore: flag meaning this event has been marked to ignore
@@ -134,6 +136,7 @@ struct fw_event_work {
        u8                      cancel_pending_work;
        struct delayed_work     delayed_work;
        struct MPT2SAS_ADAPTER *ioc;
+       u16                     device_handle;
        u8                      VF_ID;
        u8                      VP_ID;
        u8                      ignore;
@@ -4047,17 +4050,75 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
 #endif
 
 /**
- * _scsih_smart_predicted_fault - illuminate Fault LED
+ * _scsih_turn_on_fault_led - illuminate Fault LED
  * @ioc: per adapter object
  * @handle: device handle
+ * Context: process
  *
  * Return nothing.
  */
 static void
-_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+_scsih_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
 {
        Mpi2SepReply_t mpi_reply;
        Mpi2SepRequest_t mpi_request;
+
+       memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
+       mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
+       mpi_request.SlotStatus =
+           cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
+       mpi_request.DevHandle = cpu_to_le16(handle);
+       mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
+       if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
+           &mpi_request)) != 0) {
+               printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
+               __FILE__, __LINE__, __func__);
+               return;
+       }
+
+       if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
+               dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "enclosure_processor: "
+                   "ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name,
+                   le16_to_cpu(mpi_reply.IOCStatus),
+                   le32_to_cpu(mpi_reply.IOCLogInfo)));
+               return;
+       }
+}
+
+/**
+ * _scsih_send_event_to_turn_on_fault_led - fire delayed event
+ * @ioc: per adapter object
+ * @handle: device handle
+ * Context: interrupt.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_send_event_to_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct fw_event_work *fw_event;
+
+       fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+       if (!fw_event)
+               return;
+       fw_event->event = MPT2SAS_TURN_ON_FAULT_LED;
+       fw_event->device_handle = handle;
+       fw_event->ioc = ioc;
+       _scsih_fw_event_add(ioc, fw_event);
+}
+
+/**
+ * _scsih_smart_predicted_fault - process smart errors
+ * @ioc: per adapter object
+ * @handle: device handle
+ * Context: interrupt.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
        struct scsi_target *starget;
        struct MPT2SAS_TARGET *sas_target_priv_data;
        Mpi2EventNotificationReply_t *event_reply;
@@ -4084,30 +4145,8 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
        starget_printk(KERN_WARNING, starget, "predicted fault\n");
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
-       if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) {
-               memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
-               mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
-               mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
-               mpi_request.SlotStatus =
-                   cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
-               mpi_request.DevHandle = cpu_to_le16(handle);
-               mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
-               if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
-                   &mpi_request)) != 0) {
-                       printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
-                           ioc->name, __FILE__, __LINE__, __func__);
-                       return;
-               }
-
-               if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
-                       dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
-                           "enclosure_processor: ioc_status (0x%04x), "
-                           "loginfo(0x%08x)\n", ioc->name,
-                           le16_to_cpu(mpi_reply.IOCStatus),
-                           le32_to_cpu(mpi_reply.IOCLogInfo)));
-                       return;
-               }
-       }
+       if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
+               _scsih_send_event_to_turn_on_fault_led(ioc, handle);
 
        /* insert into event log */
        sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
@@ -6753,6 +6792,9 @@ _firmware_event_work(struct work_struct *work)
        }
 
        switch (fw_event->event) {
+       case MPT2SAS_TURN_ON_FAULT_LED:
+               _scsih_turn_on_fault_led(ioc, fw_event->device_handle);
+               break;
        case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
                _scsih_sas_topology_change_event(ioc, fw_event);
                break;