diff options
Diffstat (limited to 'drivers/message')
-rw-r--r-- | drivers/message/fusion/mptbase.c | 92 | ||||
-rw-r--r-- | drivers/message/fusion/mptbase.h | 72 | ||||
-rw-r--r-- | drivers/message/fusion/mptsas.c | 47 | ||||
-rw-r--r-- | drivers/message/fusion/mptscsih.c | 18 | ||||
-rw-r--r-- | drivers/message/fusion/mptscsih.h | 1 |
5 files changed, 185 insertions, 45 deletions
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 7956a10f9488..e9c6a6047a00 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -63,6 +63,8 @@ #ifdef CONFIG_MTRR #include <asm/mtrr.h> #endif +#include <linux/kthread.h> +#include <scsi/scsi_host.h> #include "mptbase.h" #include "lsi/mpi_log_fc.h" @@ -323,6 +325,32 @@ mpt_is_discovery_complete(MPT_ADAPTER *ioc) return rc; } + +/** + * mpt_remove_dead_ioc_func - kthread context to remove dead ioc + * @arg: input argument, used to derive ioc + * + * Return 0 if controller is removed from pci subsystem. + * Return -1 for other case. + */ +static int mpt_remove_dead_ioc_func(void *arg) +{ + MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; + struct pci_dev *pdev; + + if ((ioc == NULL)) + return -1; + + pdev = ioc->pcidev; + if ((pdev == NULL)) + return -1; + + pci_remove_bus_device(pdev); + return 0; +} + + + /** * mpt_fault_reset_work - work performed on workq after ioc fault * @work: input argument, used to derive ioc @@ -336,12 +364,45 @@ mpt_fault_reset_work(struct work_struct *work) u32 ioc_raw_state; int rc; unsigned long flags; + MPT_SCSI_HOST *hd; + struct task_struct *p; if (ioc->ioc_reset_in_progress || !ioc->active) goto out; + ioc_raw_state = mpt_GetIocState(ioc, 0); - if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { + if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_MASK) { + printk(MYIOC_s_INFO_FMT "%s: IOC is non-operational !!!!\n", + ioc->name, __func__); + + /* + * Call mptscsih_flush_pending_cmds callback so that we + * flush all pending commands back to OS. + * This call is required to aovid deadlock at block layer. + * Dead IOC will fail to do diag reset,and this call is safe + * since dead ioc will never return any command back from HW. + */ + hd = shost_priv(ioc->sh); + ioc->schedule_dead_ioc_flush_running_cmds(hd); + + /*Remove the Dead Host */ + p = kthread_run(mpt_remove_dead_ioc_func, ioc, + "mpt_dead_ioc_%d", ioc->id); + if (IS_ERR(p)) { + printk(MYIOC_s_ERR_FMT + "%s: Running mpt_dead_ioc thread failed !\n", + ioc->name, __func__); + } else { + printk(MYIOC_s_WARN_FMT + "%s: Running mpt_dead_ioc thread success !\n", + ioc->name, __func__); + } + return; /* don't rearm timer */ + } + + if ((ioc_raw_state & MPI_IOC_STATE_MASK) + == MPI_IOC_STATE_FAULT) { printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", @@ -6413,8 +6474,19 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) pReq->Action, ioc->mptbase_cmds.status, timeleft)); if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) goto out; - if (!timeleft) + if (!timeleft) { + spin_lock_irqsave(&ioc->taskmgmt_lock, flags); + if (ioc->ioc_reset_in_progress) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, + flags); + printk(MYIOC_s_INFO_FMT "%s: host reset in" + " progress mpt_config timed out.!!\n", + __func__, ioc->name); + return -EFAULT; + } + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); issue_hard_reset = 1; + } goto out; } @@ -7128,7 +7200,18 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) spin_lock_irqsave(&ioc->taskmgmt_lock, flags); if (ioc->ioc_reset_in_progress) { spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); - return 0; + ioc->wait_on_reset_completion = 1; + do { + ssleep(1); + } while (ioc->ioc_reset_in_progress == 1); + ioc->wait_on_reset_completion = 0; + return ioc->reset_status; + } + if (ioc->wait_on_reset_completion) { + spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + rc = 0; + time_count = jiffies; + goto exit; } ioc->ioc_reset_in_progress = 1; if (ioc->alt_ioc) @@ -7165,6 +7248,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) ioc->ioc_reset_in_progress = 0; ioc->taskmgmt_quiesce_io = 0; ioc->taskmgmt_in_progress = 0; + ioc->reset_status = rc; if (ioc->alt_ioc) { ioc->alt_ioc->ioc_reset_in_progress = 0; ioc->alt_ioc->taskmgmt_quiesce_io = 0; @@ -7180,7 +7264,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) ioc->alt_ioc, MPT_IOC_POST_RESET); } } - +exit: dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler: completed (%d seconds): %s\n", ioc->name, diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index fe902338539b..b4d24dc081ae 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.19" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.19" +#define MPT_LINUX_VERSION_COMMON "3.04.20" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.20" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -554,10 +554,47 @@ struct mptfc_rport_info u8 flags; }; +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/* + * MPT_SCSI_HOST defines - Used by the IOCTL and the SCSI drivers + * Private to the driver. + */ + +#define MPT_HOST_BUS_UNKNOWN (0xFF) +#define MPT_HOST_TOO_MANY_TM (0x05) +#define MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) +#define MPT_HOST_NO_CHAIN (0xFFFFFFFF) +#define MPT_NVRAM_MASK_TIMEOUT (0x000000FF) +#define MPT_NVRAM_SYNC_MASK (0x0000FF00) +#define MPT_NVRAM_SYNC_SHIFT (8) +#define MPT_NVRAM_DISCONNECT_ENABLE (0x00010000) +#define MPT_NVRAM_ID_SCAN_ENABLE (0x00020000) +#define MPT_NVRAM_LUN_SCAN_ENABLE (0x00040000) +#define MPT_NVRAM_TAG_QUEUE_ENABLE (0x00080000) +#define MPT_NVRAM_WIDE_DISABLE (0x00100000) +#define MPT_NVRAM_BOOT_CHOICE (0x00200000) + +typedef enum { + FC, + SPI, + SAS +} BUS_TYPE; + +typedef struct _MPT_SCSI_HOST { + struct _MPT_ADAPTER *ioc; + ushort sel_timeout[MPT_MAX_FC_DEVICES]; + char *info_kbuf; + long last_queue_full; + u16 spi_pending; + struct list_head target_reset_list; +} MPT_SCSI_HOST; + typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr); typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr); typedef void (*MPT_SCHEDULE_TARGET_RESET)(void *ioc); +typedef void (*MPT_FLUSH_RUNNING_CMDS)(MPT_SCSI_HOST *hd); /* * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS @@ -716,7 +753,10 @@ typedef struct _MPT_ADAPTER int taskmgmt_in_progress; u8 taskmgmt_quiesce_io; u8 ioc_reset_in_progress; + u8 reset_status; + u8 wait_on_reset_completion; MPT_SCHEDULE_TARGET_RESET schedule_target_reset; + MPT_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; struct work_struct sas_persist_task; struct work_struct fc_setup_reset_work; @@ -830,19 +870,6 @@ typedef struct _MPT_LOCAL_REPLY { u32 pad; } MPT_LOCAL_REPLY; -#define MPT_HOST_BUS_UNKNOWN (0xFF) -#define MPT_HOST_TOO_MANY_TM (0x05) -#define MPT_HOST_NVRAM_INVALID (0xFFFFFFFF) -#define MPT_HOST_NO_CHAIN (0xFFFFFFFF) -#define MPT_NVRAM_MASK_TIMEOUT (0x000000FF) -#define MPT_NVRAM_SYNC_MASK (0x0000FF00) -#define MPT_NVRAM_SYNC_SHIFT (8) -#define MPT_NVRAM_DISCONNECT_ENABLE (0x00010000) -#define MPT_NVRAM_ID_SCAN_ENABLE (0x00020000) -#define MPT_NVRAM_LUN_SCAN_ENABLE (0x00040000) -#define MPT_NVRAM_TAG_QUEUE_ENABLE (0x00080000) -#define MPT_NVRAM_WIDE_DISABLE (0x00100000) -#define MPT_NVRAM_BOOT_CHOICE (0x00200000) /* The TM_STATE variable is used to provide strict single threading of TM * requests as well as communicate TM error conditions. @@ -851,21 +878,6 @@ typedef struct _MPT_LOCAL_REPLY { #define TM_STATE_IN_PROGRESS (1) #define TM_STATE_ERROR (2) -typedef enum { - FC, - SPI, - SAS -} BUS_TYPE; - -typedef struct _MPT_SCSI_HOST { - MPT_ADAPTER *ioc; - ushort sel_timeout[MPT_MAX_FC_DEVICES]; - char *info_kbuf; - long last_queue_full; - u16 spi_pending; - struct list_head target_reset_list; -} MPT_SCSI_HOST; - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * More Dynamic Multi-Pathing stuff... diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 7596aecd5072..9d9504298549 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -92,6 +92,11 @@ static int max_lun = MPTSAS_MAX_LUN; module_param(max_lun, int, 0); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); +static int mpt_loadtime_max_sectors = 8192; +module_param(mpt_loadtime_max_sectors, int, 0); +MODULE_PARM_DESC(mpt_loadtime_max_sectors, + " Maximum sector define for Host Bus Adaptor.Range 64 to 8192 default=8192"); + static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */ @@ -285,10 +290,11 @@ mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, spin_lock_irqsave(&ioc->fw_event_lock, flags); list_add_tail(&fw_event->list, &ioc->fw_event_list); INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work); - devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n", - ioc->name, __func__, fw_event)); - queue_delayed_work(ioc->fw_event_q, &fw_event->work, - delay); + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)" + "on cpuid %d\n", ioc->name, __func__, + fw_event, smp_processor_id())); + queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q, + &fw_event->work, delay); spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } @@ -300,10 +306,11 @@ mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, unsigned long flags; spin_lock_irqsave(&ioc->fw_event_lock, flags); devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task " - "(fw_event=0x%p)\n", ioc->name, __func__, fw_event)); + "(fw_event=0x%p)on cpuid %d\n", ioc->name, __func__, + fw_event, smp_processor_id())); fw_event->retries++; - queue_delayed_work(ioc->fw_event_q, &fw_event->work, - msecs_to_jiffies(delay)); + queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q, + &fw_event->work, msecs_to_jiffies(delay)); spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } @@ -1943,6 +1950,15 @@ static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc) goto done; } + /* In case if IOC is in reset from internal context. + * Do not execute EEH for the same IOC. SML should to reset timer. + */ + if (ioc->ioc_reset_in_progress) { + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset," + "SML need to reset the timer (sc=%p)\n", + ioc->name, __func__, sc)); + rc = BLK_EH_RESET_TIMER; + } vdevice = sc->device->hostdata; if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD || vdevice->vtarget->deleted)) { @@ -5142,6 +5158,8 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->TaskCtx = mptsasTaskCtx; ioc->InternalCtx = mptsasInternalCtx; ioc->schedule_target_reset = &mptsas_schedule_target_reset; + ioc->schedule_dead_ioc_flush_running_cmds = + &mptscsih_flush_running_cmds; /* Added sanity check on readiness of the MPT adapter. */ if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { @@ -5239,6 +5257,21 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) sh->sg_tablesize = numSGE; } + if (mpt_loadtime_max_sectors) { + if (mpt_loadtime_max_sectors < 64 || + mpt_loadtime_max_sectors > 8192) { + printk(MYIOC_s_INFO_FMT "Invalid value passed for" + "mpt_loadtime_max_sectors %d." + "Range from 64 to 8192\n", ioc->name, + mpt_loadtime_max_sectors); + } + mpt_loadtime_max_sectors &= 0xFFFFFFFE; + dprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Resetting max sector to %d from %d\n", + ioc->name, mpt_loadtime_max_sectors, sh->max_sectors)); + sh->max_sectors = mpt_loadtime_max_sectors; + } + hd = shost_priv(sh); hd->ioc = ioc; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index ce61a5769765..0c3ced70707b 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -830,7 +830,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) if ((pScsiReq->CDB[0] == READ_6 && ((pScsiReq->CDB[1] & 0x02) == 0)) || pScsiReq->CDB[0] == READ_10 || pScsiReq->CDB[0] == READ_12 || - pScsiReq->CDB[0] == READ_16 || + (pScsiReq->CDB[0] == READ_16 && + ((pScsiReq->CDB[1] & 0x02) == 0)) || pScsiReq->CDB[0] == VERIFY || pScsiReq->CDB[0] == VERIFY_16) { if (scsi_bufflen(sc) != @@ -1024,7 +1025,7 @@ out: * * Must be called while new I/Os are being queued. */ -static void +void mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) { MPT_ADAPTER *ioc = hd->ioc; @@ -1055,6 +1056,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) sc->scsi_done(sc); } } +EXPORT_SYMBOL(mptscsih_flush_running_cmds); /* * mptscsih_search_running_cmds - Delete any commands associated @@ -1629,7 +1631,13 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, return 0; } - if (ioc_raw_state & MPI_DOORBELL_ACTIVE) { + /* DOORBELL ACTIVE check is not required if + * MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q is supported. + */ + + if (!((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) + && (ioc->facts.MsgVersion >= MPI_VERSION_01_05)) && + (ioc_raw_state & MPI_DOORBELL_ACTIVE)) { printk(MYIOC_s_WARN_FMT "TaskMgmt type=%x: ioc_state: " "DOORBELL_ACTIVE (0x%x)!\n", @@ -1728,7 +1736,9 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!! doorbell=0x%08x\n", ioc->name, __func__, mpt_GetIocState(ioc, 0)); - retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); + retval = (ioc->bus_type == SAS) ? + mpt_HardResetHandler(ioc, CAN_SLEEP) : + mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); mpt_free_msg_frame(ioc, mf); } diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 45a5ff3eff61..43e75ff39921 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -135,3 +135,4 @@ extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); extern struct device_attribute *mptscsih_host_attrs[]; extern struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); +extern void mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd); |