diff options
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_base.c')
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.c | 152 |
1 files changed, 122 insertions, 30 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 670241efa4b5..6422e258fd52 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c | |||
@@ -57,6 +57,7 @@ | |||
57 | #include <linux/dma-mapping.h> | 57 | #include <linux/dma-mapping.h> |
58 | #include <linux/sort.h> | 58 | #include <linux/sort.h> |
59 | #include <linux/io.h> | 59 | #include <linux/io.h> |
60 | #include <linux/time.h> | ||
60 | 61 | ||
61 | #include "mpt2sas_base.h" | 62 | #include "mpt2sas_base.h" |
62 | 63 | ||
@@ -77,6 +78,44 @@ static int msix_disable = -1; | |||
77 | module_param(msix_disable, int, 0); | 78 | module_param(msix_disable, int, 0); |
78 | MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); | 79 | MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); |
79 | 80 | ||
81 | /* diag_buffer_enable is bitwise | ||
82 | * bit 0 set = TRACE | ||
83 | * bit 1 set = SNAPSHOT | ||
84 | * bit 2 set = EXTENDED | ||
85 | * | ||
86 | * Either bit can be set, or both | ||
87 | */ | ||
88 | static int diag_buffer_enable; | ||
89 | module_param(diag_buffer_enable, int, 0); | ||
90 | MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " | ||
91 | "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); | ||
92 | |||
93 | int mpt2sas_fwfault_debug; | ||
94 | MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " | ||
95 | "and halt firmware - (default=0)"); | ||
96 | |||
97 | /** | ||
98 | * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. | ||
99 | * | ||
100 | */ | ||
101 | static int | ||
102 | _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) | ||
103 | { | ||
104 | int ret = param_set_int(val, kp); | ||
105 | struct MPT2SAS_ADAPTER *ioc; | ||
106 | |||
107 | if (ret) | ||
108 | return ret; | ||
109 | |||
110 | printk(KERN_INFO "setting logging_level(0x%08x)\n", | ||
111 | mpt2sas_fwfault_debug); | ||
112 | list_for_each_entry(ioc, &mpt2sas_ioc_list, list) | ||
113 | ioc->fwfault_debug = mpt2sas_fwfault_debug; | ||
114 | return 0; | ||
115 | } | ||
116 | module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug, | ||
117 | param_get_int, &mpt2sas_fwfault_debug, 0644); | ||
118 | |||
80 | /** | 119 | /** |
81 | * _base_fault_reset_work - workq handling ioc fault conditions | 120 | * _base_fault_reset_work - workq handling ioc fault conditions |
82 | * @work: input argument, used to derive ioc | 121 | * @work: input argument, used to derive ioc |
@@ -121,7 +160,7 @@ _base_fault_reset_work(struct work_struct *work) | |||
121 | 160 | ||
122 | /** | 161 | /** |
123 | * mpt2sas_base_start_watchdog - start the fault_reset_work_q | 162 | * mpt2sas_base_start_watchdog - start the fault_reset_work_q |
124 | * @ioc: pointer to scsi command object | 163 | * @ioc: per adapter object |
125 | * Context: sleep. | 164 | * Context: sleep. |
126 | * | 165 | * |
127 | * Return nothing. | 166 | * Return nothing. |
@@ -155,7 +194,7 @@ mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc) | |||
155 | 194 | ||
156 | /** | 195 | /** |
157 | * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q | 196 | * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q |
158 | * @ioc: pointer to scsi command object | 197 | * @ioc: per adapter object |
159 | * Context: sleep. | 198 | * Context: sleep. |
160 | * | 199 | * |
161 | * Return nothing. | 200 | * Return nothing. |
@@ -177,10 +216,55 @@ mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc) | |||
177 | } | 216 | } |
178 | } | 217 | } |
179 | 218 | ||
219 | /** | ||
220 | * mpt2sas_base_fault_info - verbose translation of firmware FAULT code | ||
221 | * @ioc: per adapter object | ||
222 | * @fault_code: fault code | ||
223 | * | ||
224 | * Return nothing. | ||
225 | */ | ||
226 | void | ||
227 | mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code) | ||
228 | { | ||
229 | printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n", | ||
230 | ioc->name, fault_code); | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * mpt2sas_halt_firmware - halt's mpt controller firmware | ||
235 | * @ioc: per adapter object | ||
236 | * | ||
237 | * For debugging timeout related issues. Writing 0xCOFFEE00 | ||
238 | * to the doorbell register will halt controller firmware. With | ||
239 | * the purpose to stop both driver and firmware, the enduser can | ||
240 | * obtain a ring buffer from controller UART. | ||
241 | */ | ||
242 | void | ||
243 | mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc) | ||
244 | { | ||
245 | u32 doorbell; | ||
246 | |||
247 | if (!ioc->fwfault_debug) | ||
248 | return; | ||
249 | |||
250 | dump_stack(); | ||
251 | |||
252 | doorbell = readl(&ioc->chip->Doorbell); | ||
253 | if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) | ||
254 | mpt2sas_base_fault_info(ioc , doorbell); | ||
255 | else { | ||
256 | writel(0xC0FFEE00, &ioc->chip->Doorbell); | ||
257 | printk(MPT2SAS_ERR_FMT "Firmware is halted due to command " | ||
258 | "timeout\n", ioc->name); | ||
259 | } | ||
260 | |||
261 | panic("panic in %s\n", __func__); | ||
262 | } | ||
263 | |||
180 | #ifdef CONFIG_SCSI_MPT2SAS_LOGGING | 264 | #ifdef CONFIG_SCSI_MPT2SAS_LOGGING |
181 | /** | 265 | /** |
182 | * _base_sas_ioc_info - verbose translation of the ioc status | 266 | * _base_sas_ioc_info - verbose translation of the ioc status |
183 | * @ioc: pointer to scsi command object | 267 | * @ioc: per adapter object |
184 | * @mpi_reply: reply mf payload returned from firmware | 268 | * @mpi_reply: reply mf payload returned from firmware |
185 | * @request_hdr: request mf | 269 | * @request_hdr: request mf |
186 | * | 270 | * |
@@ -394,7 +478,7 @@ _base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, | |||
394 | 478 | ||
395 | /** | 479 | /** |
396 | * _base_display_event_data - verbose translation of firmware asyn events | 480 | * _base_display_event_data - verbose translation of firmware asyn events |
397 | * @ioc: pointer to scsi command object | 481 | * @ioc: per adapter object |
398 | * @mpi_reply: reply mf payload returned from firmware | 482 | * @mpi_reply: reply mf payload returned from firmware |
399 | * | 483 | * |
400 | * Return nothing. | 484 | * Return nothing. |
@@ -474,7 +558,7 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc, | |||
474 | 558 | ||
475 | /** | 559 | /** |
476 | * _base_sas_log_info - verbose translation of firmware log info | 560 | * _base_sas_log_info - verbose translation of firmware log info |
477 | * @ioc: pointer to scsi command object | 561 | * @ioc: per adapter object |
478 | * @log_info: log info | 562 | * @log_info: log info |
479 | * | 563 | * |
480 | * Return nothing. | 564 | * Return nothing. |
@@ -526,22 +610,8 @@ _base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info) | |||
526 | } | 610 | } |
527 | 611 | ||
528 | /** | 612 | /** |
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 - | 613 | * _base_display_reply_info - |
544 | * @ioc: pointer to scsi command object | 614 | * @ioc: per adapter object |
545 | * @smid: system request message index | 615 | * @smid: system request message index |
546 | * @msix_index: MSIX table index supplied by the OS | 616 | * @msix_index: MSIX table index supplied by the OS |
547 | * @reply: reply message frame(lower 32bit addr) | 617 | * @reply: reply message frame(lower 32bit addr) |
@@ -570,7 +640,7 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, | |||
570 | 640 | ||
571 | /** | 641 | /** |
572 | * mpt2sas_base_done - base internal command completion routine | 642 | * mpt2sas_base_done - base internal command completion routine |
573 | * @ioc: pointer to scsi command object | 643 | * @ioc: per adapter object |
574 | * @smid: system request message index | 644 | * @smid: system request message index |
575 | * @msix_index: MSIX table index supplied by the OS | 645 | * @msix_index: MSIX table index supplied by the OS |
576 | * @reply: reply message frame(lower 32bit addr) | 646 | * @reply: reply message frame(lower 32bit addr) |
@@ -603,7 +673,7 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, | |||
603 | 673 | ||
604 | /** | 674 | /** |
605 | * _base_async_event - main callback handler for firmware asyn events | 675 | * _base_async_event - main callback handler for firmware asyn events |
606 | * @ioc: pointer to scsi command object | 676 | * @ioc: per adapter object |
607 | * @msix_index: MSIX table index supplied by the OS | 677 | * @msix_index: MSIX table index supplied by the OS |
608 | * @reply: reply message frame(lower 32bit addr) | 678 | * @reply: reply message frame(lower 32bit addr) |
609 | * | 679 | * |
@@ -684,7 +754,7 @@ _base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid) | |||
684 | 754 | ||
685 | /** | 755 | /** |
686 | * _base_mask_interrupts - disable interrupts | 756 | * _base_mask_interrupts - disable interrupts |
687 | * @ioc: pointer to scsi command object | 757 | * @ioc: per adapter object |
688 | * | 758 | * |
689 | * Disabling ResetIRQ, Reply and Doorbell Interrupts | 759 | * Disabling ResetIRQ, Reply and Doorbell Interrupts |
690 | * | 760 | * |
@@ -704,7 +774,7 @@ _base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc) | |||
704 | 774 | ||
705 | /** | 775 | /** |
706 | * _base_unmask_interrupts - enable interrupts | 776 | * _base_unmask_interrupts - enable interrupts |
707 | * @ioc: pointer to scsi command object | 777 | * @ioc: per adapter object |
708 | * | 778 | * |
709 | * Enabling only Reply Interrupts | 779 | * Enabling only Reply Interrupts |
710 | * | 780 | * |
@@ -1258,12 +1328,13 @@ mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid) | |||
1258 | * @ioc: per adapter object | 1328 | * @ioc: per adapter object |
1259 | * @smid: system request message index | 1329 | * @smid: system request message index |
1260 | * | 1330 | * |
1261 | * Returns phys pointer to sense buffer. | 1331 | * Returns phys pointer to the low 32bit address of the sense buffer. |
1262 | */ | 1332 | */ |
1263 | dma_addr_t | 1333 | __le32 |
1264 | mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) | 1334 | mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) |
1265 | { | 1335 | { |
1266 | return ioc->sense_dma + ((smid - 1) * SCSI_SENSE_BUFFERSIZE); | 1336 | return cpu_to_le32(ioc->sense_dma + |
1337 | ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); | ||
1267 | } | 1338 | } |
1268 | 1339 | ||
1269 | /** | 1340 | /** |
@@ -1697,6 +1768,12 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) | |||
1697 | } | 1768 | } |
1698 | 1769 | ||
1699 | if (ioc->facts.IOCCapabilities & | 1770 | if (ioc->facts.IOCCapabilities & |
1771 | MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) { | ||
1772 | printk(KERN_INFO "%sDiag Extended Buffer", i ? "," : ""); | ||
1773 | i++; | ||
1774 | } | ||
1775 | |||
1776 | if (ioc->facts.IOCCapabilities & | ||
1700 | MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { | 1777 | MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { |
1701 | printk("%sTask Set Full", i ? "," : ""); | 1778 | printk("%sTask Set Full", i ? "," : ""); |
1702 | i++; | 1779 | i++; |
@@ -2871,6 +2948,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
2871 | Mpi2IOCInitRequest_t mpi_request; | 2948 | Mpi2IOCInitRequest_t mpi_request; |
2872 | Mpi2IOCInitReply_t mpi_reply; | 2949 | Mpi2IOCInitReply_t mpi_reply; |
2873 | int r; | 2950 | int r; |
2951 | struct timeval current_time; | ||
2952 | u16 ioc_status; | ||
2874 | 2953 | ||
2875 | dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, | 2954 | dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, |
2876 | __func__)); | 2955 | __func__)); |
@@ -2921,6 +3000,13 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
2921 | cpu_to_le32(ioc->reply_post_free_dma); | 3000 | cpu_to_le32(ioc->reply_post_free_dma); |
2922 | #endif | 3001 | #endif |
2923 | 3002 | ||
3003 | /* This time stamp specifies number of milliseconds | ||
3004 | * since epoch ~ midnight January 1, 1970. | ||
3005 | */ | ||
3006 | do_gettimeofday(¤t_time); | ||
3007 | mpi_request.TimeStamp = (current_time.tv_sec * 1000) + | ||
3008 | (current_time.tv_usec >> 3); | ||
3009 | |||
2924 | if (ioc->logging_level & MPT_DEBUG_INIT) { | 3010 | if (ioc->logging_level & MPT_DEBUG_INIT) { |
2925 | u32 *mfp; | 3011 | u32 *mfp; |
2926 | int i; | 3012 | int i; |
@@ -2943,7 +3029,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) | |||
2943 | return r; | 3029 | return r; |
2944 | } | 3030 | } |
2945 | 3031 | ||
2946 | if (mpi_reply.IOCStatus != MPI2_IOCSTATUS_SUCCESS || | 3032 | ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; |
3033 | if (ioc_status != MPI2_IOCSTATUS_SUCCESS || | ||
2947 | mpi_reply.IOCLogInfo) { | 3034 | mpi_reply.IOCLogInfo) { |
2948 | printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__); | 3035 | printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__); |
2949 | r = -EIO; | 3036 | r = -EIO; |
@@ -3461,11 +3548,11 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) | |||
3461 | return r; | 3548 | return r; |
3462 | 3549 | ||
3463 | pci_set_drvdata(ioc->pdev, ioc->shost); | 3550 | pci_set_drvdata(ioc->pdev, ioc->shost); |
3464 | r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); | 3551 | r = _base_get_ioc_facts(ioc, CAN_SLEEP); |
3465 | if (r) | 3552 | if (r) |
3466 | goto out_free_resources; | 3553 | goto out_free_resources; |
3467 | 3554 | ||
3468 | r = _base_get_ioc_facts(ioc, CAN_SLEEP); | 3555 | r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); |
3469 | if (r) | 3556 | if (r) |
3470 | goto out_free_resources; | 3557 | goto out_free_resources; |
3471 | 3558 | ||
@@ -3531,6 +3618,8 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) | |||
3531 | goto out_free_resources; | 3618 | goto out_free_resources; |
3532 | 3619 | ||
3533 | mpt2sas_base_start_watchdog(ioc); | 3620 | mpt2sas_base_start_watchdog(ioc); |
3621 | if (diag_buffer_enable != 0) | ||
3622 | mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); | ||
3534 | return 0; | 3623 | return 0; |
3535 | 3624 | ||
3536 | out_free_resources: | 3625 | out_free_resources: |
@@ -3684,6 +3773,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, | 3773 | dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, |
3685 | __func__)); | 3774 | __func__)); |
3686 | 3775 | ||
3776 | if (mpt2sas_fwfault_debug) | ||
3777 | mpt2sas_halt_firmware(ioc); | ||
3778 | |||
3687 | spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); | 3779 | spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); |
3688 | if (ioc->shost_recovery) { | 3780 | if (ioc->shost_recovery) { |
3689 | spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); | 3781 | spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); |