Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / message / fusion / mptctl.c
index caa8f56..f06b291 100644 (file)
@@ -128,7 +128,6 @@ static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags
                struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc);
 static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma,
                struct buflist *buflist, MPT_ADAPTER *ioc);
-static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function);
 
 /*
  * Reset Handler cleanup function
@@ -275,45 +274,6 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
        return 1;
 }
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* mptctl_timeout_expired
- *
- * Expecting an interrupt, however timed out.
- *
- */
-static void
-mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
-{
-       unsigned long flags;
-
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
-               ioc->name, __func__));
-
-       if (mpt_fwfault_debug)
-               mpt_halt_firmware(ioc);
-
-       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
-       if (ioc->ioc_reset_in_progress) {
-               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
-               CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
-               mpt_free_msg_frame(ioc, mf);
-               return;
-       }
-       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
-
-
-       if (!mptctl_bus_reset(ioc, mf->u.hdr.Function))
-               return;
-
-       /* Issue a reset for this device.
-        * The IOC is not responding.
-        */
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
-                ioc->name));
-       CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
-       mpt_HardResetHandler(ioc, CAN_SLEEP);
-       mpt_free_msg_frame(ioc, mf);
-}
 
 static int
 mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
@@ -343,12 +303,8 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
        return 0;
 }
 
-/* mptctl_bus_reset
- *
- * Bus reset code.
- *
- */
-static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
+static int
+mptctl_do_taskmgmt(MPT_ADAPTER *ioc, u8 tm_type, u8 bus_id, u8 target_id)
 {
        MPT_FRAME_HDR   *mf;
        SCSITaskMgmt_t  *pScsiTm;
@@ -359,13 +315,6 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
        unsigned long    time_count;
        u16              iocstatus;
 
-       /* bus reset is only good for SCSI IO, RAID PASSTHRU */
-       if (!(function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
-               function == MPI_FUNCTION_SCSI_IO_REQUEST)) {
-               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-                       "TaskMgmt, not SCSI_IO!!\n", ioc->name));
-               return -EPERM;
-       }
 
        mutex_lock(&ioc->taskmgmt_cmds.mutex);
        if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
@@ -375,15 +324,14 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
 
        retval = 0;
 
-       /* Send request
-        */
        mf = mpt_get_msg_frame(mptctl_taskmgmt_id, ioc);
        if (mf == NULL) {
-               dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
-                       "TaskMgmt, no msg frames!!\n", ioc->name));
+               dtmprintk(ioc,
+                       printk(MYIOC_s_WARN_FMT "TaskMgmt, no msg frames!!\n",
+                       ioc->name));
                mpt_clear_taskmgmt_in_progress_flag(ioc);
                retval = -ENOMEM;
-               goto mptctl_bus_reset_done;
+               goto tm_done;
        }
 
        dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
@@ -392,10 +340,13 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
        pScsiTm = (SCSITaskMgmt_t *) mf;
        memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
        pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
-       pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS;
-       pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
-       pScsiTm->TargetID = 0;
-       pScsiTm->Bus = 0;
+       pScsiTm->TaskType = tm_type;
+       if ((tm_type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) &&
+               (ioc->bus_type == FC))
+               pScsiTm->MsgFlags =
+                               MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+       pScsiTm->TargetID = target_id;
+       pScsiTm->Bus = bus_id;
        pScsiTm->ChainOffset = 0;
        pScsiTm->Reserved = 0;
        pScsiTm->Reserved1 = 0;
@@ -413,17 +364,16 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
                timeout = 30;
                break;
        case SPI:
-       default:
-               timeout = 2;
+               default:
+               timeout = 10;
                break;
        }
 
-       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-               "TaskMgmt type=%d timeout=%ld\n",
-               ioc->name, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, timeout));
+       dtmprintk(ioc,
+               printk(MYIOC_s_DEBUG_FMT "TaskMgmt type=%d timeout=%ld\n",
+               ioc->name, tm_type, timeout));
 
        INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
-       CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
        time_count = jiffies;
        if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
            (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
@@ -432,17 +382,20 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
                retval = mpt_send_handshake_request(mptctl_taskmgmt_id, ioc,
                    sizeof(SCSITaskMgmt_t), (u32 *)pScsiTm, CAN_SLEEP);
                if (retval != 0) {
-                       dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+                       dfailprintk(ioc,
+                               printk(MYIOC_s_ERR_FMT
                                "TaskMgmt send_handshake FAILED!"
                                " (ioc %p, mf %p, rc=%d) \n", ioc->name,
                                ioc, mf, retval));
+                       mpt_free_msg_frame(ioc, mf);
                        mpt_clear_taskmgmt_in_progress_flag(ioc);
-                       goto mptctl_bus_reset_done;
+                       goto tm_done;
                }
        }
 
        /* Now wait for the command to complete */
        ii = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, timeout*HZ);
+
        if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
                dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                    "TaskMgmt failed\n", ioc->name));
@@ -452,14 +405,14 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
                        retval = 0;
                else
                        retval = -1; /* return failure */
-               goto mptctl_bus_reset_done;
+               goto tm_done;
        }
 
        if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
                dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
                    "TaskMgmt failed\n", ioc->name));
                retval = -1; /* return failure */
-               goto mptctl_bus_reset_done;
+               goto tm_done;
        }
 
        pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
@@ -467,7 +420,7 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
            "TaskMgmt fw_channel = %d, fw_id = %d, task_type=0x%02X, "
            "iocstatus=0x%04X\n\tloginfo=0x%08X, response_code=0x%02X, "
            "term_cmnds=%d\n", ioc->name, pScsiTmReply->Bus,
-           pScsiTmReply->TargetID, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+           pScsiTmReply->TargetID, tm_type,
            le16_to_cpu(pScsiTmReply->IOCStatus),
            le32_to_cpu(pScsiTmReply->IOCLogInfo),
            pScsiTmReply->ResponseCode,
@@ -485,13 +438,71 @@ static int mptctl_bus_reset(MPT_ADAPTER *ioc, u8 function)
                retval = -1; /* return failure */
        }
 
-
- mptctl_bus_reset_done:
+ tm_done:
        mutex_unlock(&ioc->taskmgmt_cmds.mutex);
        CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
        return retval;
 }
 
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/* mptctl_timeout_expired
+ *
+ * Expecting an interrupt, however timed out.
+ *
+ */
+static void
+mptctl_timeout_expired(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+{
+       unsigned long flags;
+       int ret_val = -1;
+       SCSIIORequest_t *scsi_req = (SCSIIORequest_t *) mf;
+       u8 function = mf->u.hdr.Function;
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": %s\n",
+               ioc->name, __func__));
+
+       if (mpt_fwfault_debug)
+               mpt_halt_firmware(ioc);
+
+       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+       if (ioc->ioc_reset_in_progress) {
+               spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+               CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+               mpt_free_msg_frame(ioc, mf);
+               return;
+       }
+       spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
+
+
+       CLEAR_MGMT_PENDING_STATUS(ioc->ioctl_cmds.status)
+
+       if (ioc->bus_type == SAS) {
+               if (function == MPI_FUNCTION_SCSI_IO_REQUEST)
+                       ret_val = mptctl_do_taskmgmt(ioc,
+                               MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+                               scsi_req->Bus, scsi_req->TargetID);
+               else if (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
+                       ret_val = mptctl_do_taskmgmt(ioc,
+                               MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+                               scsi_req->Bus, 0);
+               if (!ret_val)
+                       return;
+       } else {
+               if ((function == MPI_FUNCTION_SCSI_IO_REQUEST) ||
+                       (function == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH))
+                       ret_val = mptctl_do_taskmgmt(ioc,
+                               MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
+                               scsi_req->Bus, 0);
+               if (!ret_val)
+                       return;
+       }
+
+       dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling Reset! \n",
+                ioc->name));
+       mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
+       mpt_free_msg_frame(ioc, mf);
+}
+
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /* mptctl_ioc_reset
@@ -1318,6 +1329,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
        if (ioc->sh) {
                shost_for_each_device(sdev, ioc->sh) {
                        vdevice = sdev->hostdata;
+                       if (vdevice == NULL || vdevice->vtarget == NULL)
+                               continue;
                        if (vdevice->vtarget->tflags &
                            MPT_TARGET_FLAGS_RAID_COMPONENT)
                                continue;
@@ -1439,6 +1452,8 @@ mptctl_gettargetinfo (unsigned long arg)
                        if (!maxWordsLeft)
                                continue;
                        vdevice = sdev->hostdata;
+                       if (vdevice == NULL || vdevice->vtarget == NULL)
+                               continue;
                        if (vdevice->vtarget->tflags &
                            MPT_TARGET_FLAGS_RAID_COMPONENT)
                                continue;
@@ -1967,6 +1982,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
                                struct scsi_target *starget = scsi_target(sdev);
                                VirtTarget *vtarget = starget->hostdata;
 
+                               if (vtarget == NULL)
+                                       continue;
+
                                if ((pScsiReq->TargetID == vtarget->id) &&
                                    (pScsiReq->Bus == vtarget->channel) &&
                                    (vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
@@ -2991,6 +3009,14 @@ static int __init mptctl_init(void)
        }
 
        mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER);
+       if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) {
+               printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
+               mpt_deregister(mptctl_id);
+               misc_deregister(&mptctl_miscdev);
+               err = -EBUSY;
+               goto out_fail;
+       }
+
        mpt_reset_register(mptctl_id, mptctl_ioc_reset);
        mpt_event_register(mptctl_id, mptctl_event_process);
 
@@ -3010,12 +3036,15 @@ static void mptctl_exit(void)
        printk(KERN_INFO MYNAM ": Deregistered /dev/%s @ (major,minor=%d,%d)\n",
                         mptctl_miscdev.name, MISC_MAJOR, mptctl_miscdev.minor);
 
+       /* De-register event handler from base module */
+       mpt_event_deregister(mptctl_id);
+
        /* De-register reset handler from base module */
        mpt_reset_deregister(mptctl_id);
 
        /* De-register callback handler from base module */
+       mpt_deregister(mptctl_taskmgmt_id);
        mpt_deregister(mptctl_id);
-       mpt_reset_deregister(mptctl_taskmgmt_id);
 
         mpt_device_driver_deregister(MPTCTL_DRIVER);