aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/mpt2sas/mpt2sas_base.c
diff options
context:
space:
mode:
authorKashyap, Desai <kashyap.desai@lsi.com>2009-09-23 07:56:58 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-10-29 13:03:10 -0400
commitfa7f31673583a6e0876f8bb420735cdd8a3ffa57 (patch)
tree5b547d903081571bc2cc5950de513beba4895ed0 /drivers/scsi/mpt2sas/mpt2sas_base.c
parent9fec5f9fc2fbe7c6e39db01ae296528d9a20a5b1 (diff)
[SCSI] mpt2sas: Support for stopping driver when Firmware encounters
Added command line option and shost sysfs attribute called mpt2sas_fwfault_debug. When enduser writes a "1" to this parameter, this will enable support in the driver for debugging firmware timeout related issues. This handling was added in three areas (a) scsi error handling callback called task_abort, (b) IOCTL interface, and (c) other timeouts that result in diag resets, such as manufacturing config pages. When this support is enabled, the driver will provide dump_stack to console, halt controller firmware, and panic driver. The end user probably would want to setup serial console redirection so the dump stack can be seen. Here are the three methods for enable this support: (a) # insmod mpt2sas.ko mpt2sas_fwfault_debug=1 (b) # echo 1 > /sys/module/mpt2sas/parameters/mpt2sas_fwfault_debug (c) # echo 1 > /sys/class/scsi_host/host#/fwfault_debug (where # is the host number) 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>
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_base.c')
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c88
1 files changed, 74 insertions, 14 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 670241efa4b..617664cbf3f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -77,6 +77,32 @@ static int msix_disable = -1;
77module_param(msix_disable, int, 0); 77module_param(msix_disable, int, 0);
78MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); 78MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
79 79
80int mpt2sas_fwfault_debug;
81MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault "
82 "and halt firmware - (default=0)");
83
84/**
85 * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
86 *
87 */
88static int
89_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp)
90{
91 int ret = param_set_int(val, kp);
92 struct MPT2SAS_ADAPTER *ioc;
93
94 if (ret)
95 return ret;
96
97 printk(KERN_INFO "setting logging_level(0x%08x)\n",
98 mpt2sas_fwfault_debug);
99 list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
100 ioc->fwfault_debug = mpt2sas_fwfault_debug;
101 return 0;
102}
103module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug,
104 param_get_int, &mpt2sas_fwfault_debug, 0644);
105
80/** 106/**
81 * _base_fault_reset_work - workq handling ioc fault conditions 107 * _base_fault_reset_work - workq handling ioc fault conditions
82 * @work: input argument, used to derive ioc 108 * @work: input argument, used to derive ioc
@@ -177,6 +203,51 @@ mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc)
177 } 203 }
178} 204}
179 205
206/**
207 * mpt2sas_base_fault_info - verbose translation of firmware FAULT code
208 * @ioc: per adapter object
209 * @fault_code: fault code
210 *
211 * Return nothing.
212 */
213void
214mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
215{
216 printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
217 ioc->name, fault_code);
218}
219
220/**
221 * mpt2sas_halt_firmware - halt's mpt controller firmware
222 * @ioc: per adapter object
223 *
224 * For debugging timeout related issues. Writing 0xCOFFEE00
225 * to the doorbell register will halt controller firmware. With
226 * the purpose to stop both driver and firmware, the enduser can
227 * obtain a ring buffer from controller UART.
228 */
229void
230mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc)
231{
232 u32 doorbell;
233
234 if (!ioc->fwfault_debug)
235 return;
236
237 dump_stack();
238
239 doorbell = readl(&ioc->chip->Doorbell);
240 if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
241 mpt2sas_base_fault_info(ioc , doorbell);
242 else {
243 writel(0xC0FFEE00, &ioc->chip->Doorbell);
244 printk(MPT2SAS_ERR_FMT "Firmware is halted due to command "
245 "timeout\n", ioc->name);
246 }
247
248 panic("panic in %s\n", __func__);
249}
250
180#ifdef CONFIG_SCSI_MPT2SAS_LOGGING 251#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
181/** 252/**
182 * _base_sas_ioc_info - verbose translation of the ioc status 253 * _base_sas_ioc_info - verbose translation of the ioc status
@@ -526,20 +597,6 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info)
526} 597}
527 598
528/** 599/**
529 * mpt2sas_base_fault_info - verbose translation of firmware FAULT code
530 * @ioc: pointer to scsi command object
531 * @fault_code: fault code
532 *
533 * Return nothing.
534 */
535void
536mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
537{
538 printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
539 ioc->name, fault_code);
540}
541
542/**
543 * _base_display_reply_info - 600 * _base_display_reply_info -
544 * @ioc: pointer to scsi command object 601 * @ioc: pointer to scsi command object
545 * @smid: system request message index 602 * @smid: system request message index
@@ -3684,6 +3741,9 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
3684 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, 3741 dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
3685 __func__)); 3742 __func__));
3686 3743
3744 if (mpt2sas_fwfault_debug)
3745 mpt2sas_halt_firmware(ioc);
3746
3687 spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); 3747 spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
3688 if (ioc->shost_recovery) { 3748 if (ioc->shost_recovery) {
3689 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); 3749 spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);