diff options
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 88 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 4 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_ctl.c | 41 | ||||
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 2 |
4 files changed, 119 insertions, 16 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 670241efa4b5..617664cbf3f7 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c | |||
@@ -77,6 +77,32 @@ static int msix_disable = -1; | |||
77 | module_param(msix_disable, int, 0); | 77 | module_param(msix_disable, int, 0); |
78 | MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); | 78 | MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); |
79 | 79 | ||
80 | int mpt2sas_fwfault_debug; | ||
81 | MODULE_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 | */ | ||
88 | static 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 | } | ||
103 | module_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 | */ | ||
213 | void | ||
214 | mpt2sas_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 | */ | ||
229 | void | ||
230 | mpt2sas_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 | */ | ||
535 | void | ||
536 | mpt2sas_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); |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index fa99ff204e46..0c75c0e137f7 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h | |||
@@ -466,6 +466,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); | |||
466 | * @chip_phys: physical addrss prior to mapping | 466 | * @chip_phys: physical addrss prior to mapping |
467 | * @pio_chip: I/O mapped register space | 467 | * @pio_chip: I/O mapped register space |
468 | * @logging_level: see mpt2sas_debug.h | 468 | * @logging_level: see mpt2sas_debug.h |
469 | * @fwfault_debug: debuging FW timeouts | ||
469 | * @ir_firmware: IR firmware present | 470 | * @ir_firmware: IR firmware present |
470 | * @bars: bitmask of BAR's that must be configured | 471 | * @bars: bitmask of BAR's that must be configured |
471 | * @mask_interrupts: ignore interrupt | 472 | * @mask_interrupts: ignore interrupt |
@@ -587,6 +588,7 @@ struct MPT2SAS_ADAPTER { | |||
587 | unsigned long chip_phys; | 588 | unsigned long chip_phys; |
588 | unsigned long pio_chip; | 589 | unsigned long pio_chip; |
589 | int logging_level; | 590 | int logging_level; |
591 | int fwfault_debug; | ||
590 | u8 ir_firmware; | 592 | u8 ir_firmware; |
591 | int bars; | 593 | int bars; |
592 | u8 mask_interrupts; | 594 | u8 mask_interrupts; |
@@ -803,6 +805,8 @@ int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, | |||
803 | Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request); | 805 | Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request); |
804 | void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type); | 806 | void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type); |
805 | 807 | ||
808 | void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); | ||
809 | |||
806 | /* scsih shared API */ | 810 | /* scsih shared API */ |
807 | u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, | 811 | u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, |
808 | u32 reply); | 812 | u32 reply); |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 57d724633906..6901a6706ede 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c | |||
@@ -896,6 +896,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, | |||
896 | printk(MPT2SAS_INFO_FMT "issue target reset: handle " | 896 | printk(MPT2SAS_INFO_FMT "issue target reset: handle " |
897 | "= (0x%04x)\n", ioc->name, | 897 | "= (0x%04x)\n", ioc->name, |
898 | mpi_request->FunctionDependent1); | 898 | mpi_request->FunctionDependent1); |
899 | mpt2sas_halt_firmware(ioc); | ||
899 | mutex_lock(&ioc->tm_cmds.mutex); | 900 | mutex_lock(&ioc->tm_cmds.mutex); |
900 | mpt2sas_scsih_issue_tm(ioc, | 901 | mpt2sas_scsih_issue_tm(ioc, |
901 | mpi_request->FunctionDependent1, 0, | 902 | mpi_request->FunctionDependent1, 0, |
@@ -2474,6 +2475,43 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, | |||
2474 | static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, | 2475 | static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, |
2475 | _ctl_logging_level_show, _ctl_logging_level_store); | 2476 | _ctl_logging_level_show, _ctl_logging_level_store); |
2476 | 2477 | ||
2478 | /* device attributes */ | ||
2479 | /* | ||
2480 | * _ctl_fwfault_debug_show - show/store fwfault_debug | ||
2481 | * @cdev - pointer to embedded class device | ||
2482 | * @buf - the buffer returned | ||
2483 | * | ||
2484 | * mpt2sas_fwfault_debug is command line option | ||
2485 | * A sysfs 'read/write' shost attribute. | ||
2486 | */ | ||
2487 | static ssize_t | ||
2488 | _ctl_fwfault_debug_show(struct device *cdev, | ||
2489 | struct device_attribute *attr, char *buf) | ||
2490 | { | ||
2491 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2492 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2493 | |||
2494 | return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug); | ||
2495 | } | ||
2496 | static ssize_t | ||
2497 | _ctl_fwfault_debug_store(struct device *cdev, | ||
2498 | struct device_attribute *attr, const char *buf, size_t count) | ||
2499 | { | ||
2500 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
2501 | struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); | ||
2502 | int val = 0; | ||
2503 | |||
2504 | if (sscanf(buf, "%d", &val) != 1) | ||
2505 | return -EINVAL; | ||
2506 | |||
2507 | ioc->fwfault_debug = val; | ||
2508 | printk(MPT2SAS_INFO_FMT "fwfault_debug=%d\n", ioc->name, | ||
2509 | ioc->fwfault_debug); | ||
2510 | return strlen(buf); | ||
2511 | } | ||
2512 | static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, | ||
2513 | _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); | ||
2514 | |||
2477 | struct device_attribute *mpt2sas_host_attrs[] = { | 2515 | struct device_attribute *mpt2sas_host_attrs[] = { |
2478 | &dev_attr_version_fw, | 2516 | &dev_attr_version_fw, |
2479 | &dev_attr_version_bios, | 2517 | &dev_attr_version_bios, |
@@ -2487,13 +2525,12 @@ struct device_attribute *mpt2sas_host_attrs[] = { | |||
2487 | &dev_attr_io_delay, | 2525 | &dev_attr_io_delay, |
2488 | &dev_attr_device_delay, | 2526 | &dev_attr_device_delay, |
2489 | &dev_attr_logging_level, | 2527 | &dev_attr_logging_level, |
2528 | &dev_attr_fwfault_debug, | ||
2490 | &dev_attr_fw_queue_depth, | 2529 | &dev_attr_fw_queue_depth, |
2491 | &dev_attr_host_sas_address, | 2530 | &dev_attr_host_sas_address, |
2492 | NULL, | 2531 | NULL, |
2493 | }; | 2532 | }; |
2494 | 2533 | ||
2495 | /* device attributes */ | ||
2496 | |||
2497 | /** | 2534 | /** |
2498 | * _ctl_device_sas_address_show - sas address | 2535 | * _ctl_device_sas_address_show - sas address |
2499 | * @cdev - pointer to embedded class device | 2536 | * @cdev - pointer to embedded class device |
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 91d61154a46c..59ea821c2a3c 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c | |||
@@ -1929,6 +1929,8 @@ _scsih_abort(struct scsi_cmnd *scmd) | |||
1929 | goto out; | 1929 | goto out; |
1930 | } | 1930 | } |
1931 | 1931 | ||
1932 | mpt2sas_halt_firmware(ioc); | ||
1933 | |||
1932 | mutex_lock(&ioc->tm_cmds.mutex); | 1934 | mutex_lock(&ioc->tm_cmds.mutex); |
1933 | handle = sas_device_priv_data->sas_target->handle; | 1935 | handle = sas_device_priv_data->sas_target->handle; |
1934 | mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun, | 1936 | mpt2sas_scsih_issue_tm(ioc, handle, sas_device_priv_data->lun, |