diff options
Diffstat (limited to 'drivers/message/fusion/mptctl.c')
| -rw-r--r-- | drivers/message/fusion/mptctl.c | 252 |
1 files changed, 151 insertions, 101 deletions
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 352acd05c46..8a050e88568 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -54,7 +54,7 @@ #include <linux/pci.h> #include <linux/delay.h> /* for mdelay */ #include <linux/miscdevice.h> -#include <linux/smp_lock.h> +#include <linux/mutex.h> #include <linux/compat.h> #include <asm/io.h> @@ -83,6 +83,7 @@ MODULE_VERSION(my_VERSION); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +static DEFINE_MUTEX(mpctl_mutex); static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptctl_taskmgmt_id = MPT_MAX_PROTOCOL_DRIVERS; @@ -128,7 +129,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 @@ -262,10 +262,16 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) /* We are done, issue wake up */ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { - if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) + if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) { mpt_clear_taskmgmt_in_progress_flag(ioc); - ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; - complete(&ioc->ioctl_cmds.done); + ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->ioctl_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); + } else { + ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->ioctl_cmds.done); + } } out_continuation: @@ -275,45 +281,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) @@ -338,17 +305,15 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) mpt_clear_taskmgmt_in_progress_flag(ioc); ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; complete(&ioc->taskmgmt_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); return 1; } 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 +324,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 +333,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 +349,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 +373,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 +391,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 +414,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 +429,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 +447,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 @@ -582,12 +602,12 @@ mptctl_fasync(int fd, struct file *filep, int mode) MPT_ADAPTER *ioc; int ret; - lock_kernel(); + mutex_lock(&mpctl_mutex); list_for_each_entry(ioc, &ioc_list, list) ioc->aen_event_read_flag=0; ret = fasync_helper(fd, filep, mode, &async_queue); - unlock_kernel(); + mutex_unlock(&mpctl_mutex); return ret; } @@ -679,9 +699,9 @@ static long mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&mpctl_mutex); ret = __mptctl_ioctl(file, cmd, arg); - unlock_kernel(); + mutex_unlock(&mpctl_mutex); return ret; } @@ -935,9 +955,12 @@ retry_wait: mpt_free_msg_frame(iocp, mf); goto fwdl_out; } - if (!timeleft) + if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "FW download timeout, doorbell=0x%08x\n", + iocp->name, mpt_GetIocState(iocp, 0)); mptctl_timeout_expired(iocp, mf); - else + } else goto retry_wait; goto fwdl_out; } @@ -955,7 +978,7 @@ retry_wait: ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply; iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; if (iocstat == MPI_IOCSTATUS_SUCCESS) { - printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name); + printk(MYIOC_s_INFO_FMT "F/W update successful!\n", iocp->name); return 0; } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) { printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n", @@ -1220,7 +1243,6 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) int iocnum; unsigned int port; int cim_rev; - u8 revision; struct scsi_device *sdev; VirtDevice *vdevice; @@ -1284,16 +1306,17 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) else karg->adapterType = MPT_IOCTL_INTERFACE_SCSI; - if (karg->hdr.port > 1) + if (karg->hdr.port > 1) { + kfree(karg); return -EINVAL; + } port = karg->hdr.port; karg->port = port; pdev = (struct pci_dev *) ioc->pcidev; karg->pciId = pdev->device; - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - karg->hwRev = revision; + karg->hwRev = pdev->revision; karg->subSystemDevice = pdev->subsystem_device; karg->subSystemVendor = pdev->subsystem_vendor; @@ -1318,6 +1341,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 +1464,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 +1994,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)) @@ -2275,6 +2305,10 @@ retry_wait: goto done_free_mem; } if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "mpt cmd timeout, doorbell=0x%08x" + " function=0x%x\n", + ioc->name, mpt_GetIocState(ioc, 0), function); if (function == MPI_FUNCTION_SCSI_TASK_MGMT) mutex_unlock(&ioc->taskmgmt_cmds.mutex); mptctl_timeout_expired(ioc, mf); @@ -2364,7 +2398,7 @@ done_free_mem: } /* mf is null if command issued successfully - * otherwise, failure occured after mf acquired. + * otherwise, failure occurred after mf acquired. */ if (mf) mpt_free_msg_frame(ioc, mf); @@ -2398,9 +2432,9 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) int rc, cim_rev; ToolboxIstwiReadWriteRequest_t *IstwiRWRequest; MPT_FRAME_HDR *mf = NULL; - MPIHeader_t *mpi_hdr; unsigned long timeleft; int retval; + u32 msgcontext; /* Reset long to int. Should affect IA64 and SPARC only */ @@ -2547,11 +2581,11 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) } IstwiRWRequest = (ToolboxIstwiReadWriteRequest_t *)mf; - mpi_hdr = (MPIHeader_t *) mf; + msgcontext = IstwiRWRequest->MsgContext; memset(IstwiRWRequest,0,sizeof(ToolboxIstwiReadWriteRequest_t)); + IstwiRWRequest->MsgContext = msgcontext; IstwiRWRequest->Function = MPI_FUNCTION_TOOLBOX; IstwiRWRequest->Tool = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL; - IstwiRWRequest->MsgContext = mpi_hdr->MsgContext; IstwiRWRequest->Flags = MPI_TB_ISTWI_FLAGS_READ; IstwiRWRequest->NumAddressBytes = 0x01; IstwiRWRequest->DataLength = cpu_to_le16(0x04); @@ -2582,9 +2616,12 @@ retry_wait: mpt_free_msg_frame(ioc, mf); goto out; } - if (!timeleft) + if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "HOST INFO command timeout, doorbell=0x%08x\n", + ioc->name, mpt_GetIocState(ioc, 0)); mptctl_timeout_expired(ioc, mf); - else + } else goto retry_wait; goto out; } @@ -2890,7 +2927,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd, static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); + mutex_lock(&mpctl_mutex); switch (cmd) { case MPTIOCINFO: case MPTIOCINFO1: @@ -2915,7 +2952,7 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a ret = -ENOIOCTLCMD; break; } - unlock_kernel(); + mutex_unlock(&mpctl_mutex); return ret; } @@ -2982,7 +3019,8 @@ static int __init mptctl_init(void) * Install our handler */ ++where; - mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER); + mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER, + "mptctl_reply"); if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) { printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); misc_deregister(&mptctl_miscdev); @@ -2990,7 +3028,16 @@ static int __init mptctl_init(void) goto out_fail; } - mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER); + mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER, + "mptctl_taskmgmt_reply"); + 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 +3057,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); |
