diff options
author | Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com> | 2013-09-04 03:27:00 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-10-25 04:58:16 -0400 |
commit | d078b5117f18dce57b895df640d9bf2614864829 (patch) | |
tree | 6d6141a83ba64f24848a0348804e3522866ae815 /drivers/scsi | |
parent | 279094079a442c19ff7e7c0fd9511d9404cb2518 (diff) |
[SCSI] pm80xx: Firmware logging support.
Supports below logging facilities,
Inbound outbound queues dump.
Non fatal dump in case of IO failures.
Fatal dump in case of firmware failure.
[jejb: checkpatch spacing fixes]
Signed-off-by: Anandkumar.Santhanam@pmcs.com
Reviewed-by: Jack Wang <jinpu.wang@profitbricks.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/pm8001/pm8001_ctl.c | 119 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_ctl.h | 4 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_defs.h | 3 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.c | 83 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.h | 3 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_init.c | 4 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.h | 68 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.c | 225 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.h | 2 |
9 files changed, 510 insertions, 1 deletions
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index 5a19e1930b4b..a04b4ff8c7f6 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c | |||
@@ -309,6 +309,84 @@ static ssize_t pm8001_ctl_aap_log_show(struct device *cdev, | |||
309 | } | 309 | } |
310 | static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL); | 310 | static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL); |
311 | /** | 311 | /** |
312 | * pm8001_ctl_ib_queue_log_show - Out bound Queue log | ||
313 | * @cdev:pointer to embedded class device | ||
314 | * @buf: the buffer returned | ||
315 | * A sysfs 'read-only' shost attribute. | ||
316 | */ | ||
317 | static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev, | ||
318 | struct device_attribute *attr, char *buf) | ||
319 | { | ||
320 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
321 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); | ||
322 | struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; | ||
323 | int offset; | ||
324 | char *str = buf; | ||
325 | int start = 0; | ||
326 | #define IB_MEMMAP(c) \ | ||
327 | (*(u32 *)((u8 *)pm8001_ha-> \ | ||
328 | memoryMap.region[IB].virt_ptr + \ | ||
329 | pm8001_ha->evtlog_ib_offset + (c))) | ||
330 | |||
331 | for (offset = 0; offset < IB_OB_READ_TIMES; offset++) { | ||
332 | if (pm8001_ha->chip_id != chip_8001) | ||
333 | str += sprintf(str, "0x%08x\n", IB_MEMMAP(start)); | ||
334 | else | ||
335 | str += sprintf(str, "0x%08x\n", IB_MEMMAP(start)); | ||
336 | start = start + 4; | ||
337 | } | ||
338 | pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET; | ||
339 | if ((((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0) | ||
340 | && (pm8001_ha->chip_id != chip_8001)) | ||
341 | pm8001_ha->evtlog_ib_offset = 0; | ||
342 | if ((((pm8001_ha->evtlog_ib_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0) | ||
343 | && (pm8001_ha->chip_id == chip_8001)) | ||
344 | pm8001_ha->evtlog_ib_offset = 0; | ||
345 | |||
346 | return str - buf; | ||
347 | } | ||
348 | |||
349 | static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL); | ||
350 | /** | ||
351 | * pm8001_ctl_ob_queue_log_show - Out bound Queue log | ||
352 | * @cdev:pointer to embedded class device | ||
353 | * @buf: the buffer returned | ||
354 | * A sysfs 'read-only' shost attribute. | ||
355 | */ | ||
356 | |||
357 | static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev, | ||
358 | struct device_attribute *attr, char *buf) | ||
359 | { | ||
360 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
361 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); | ||
362 | struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; | ||
363 | int offset; | ||
364 | char *str = buf; | ||
365 | int start = 0; | ||
366 | #define OB_MEMMAP(c) \ | ||
367 | (*(u32 *)((u8 *)pm8001_ha-> \ | ||
368 | memoryMap.region[OB].virt_ptr + \ | ||
369 | pm8001_ha->evtlog_ob_offset + (c))) | ||
370 | |||
371 | for (offset = 0; offset < IB_OB_READ_TIMES; offset++) { | ||
372 | if (pm8001_ha->chip_id != chip_8001) | ||
373 | str += sprintf(str, "0x%08x\n", OB_MEMMAP(start)); | ||
374 | else | ||
375 | str += sprintf(str, "0x%08x\n", OB_MEMMAP(start)); | ||
376 | start = start + 4; | ||
377 | } | ||
378 | pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET; | ||
379 | if ((((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0) | ||
380 | && (pm8001_ha->chip_id != chip_8001)) | ||
381 | pm8001_ha->evtlog_ob_offset = 0; | ||
382 | if ((((pm8001_ha->evtlog_ob_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0) | ||
383 | && (pm8001_ha->chip_id == chip_8001)) | ||
384 | pm8001_ha->evtlog_ob_offset = 0; | ||
385 | |||
386 | return str - buf; | ||
387 | } | ||
388 | static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL); | ||
389 | /** | ||
312 | * pm8001_ctl_bios_version_show - Bios version Display | 390 | * pm8001_ctl_bios_version_show - Bios version Display |
313 | * @cdev:pointer to embedded class device | 391 | * @cdev:pointer to embedded class device |
314 | * @buf:the buffer returned | 392 | * @buf:the buffer returned |
@@ -377,6 +455,43 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev, | |||
377 | } | 455 | } |
378 | static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL); | 456 | static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL); |
379 | 457 | ||
458 | /** | ||
459 | ** pm8001_ctl_fatal_log_show - fatal error logging | ||
460 | ** @cdev:pointer to embedded class device | ||
461 | ** @buf: the buffer returned | ||
462 | ** | ||
463 | ** A sysfs 'read-only' shost attribute. | ||
464 | **/ | ||
465 | |||
466 | static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev, | ||
467 | struct device_attribute *attr, char *buf) | ||
468 | { | ||
469 | u32 count; | ||
470 | |||
471 | count = pm80xx_get_fatal_dump(cdev, attr, buf); | ||
472 | return count; | ||
473 | } | ||
474 | |||
475 | static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL); | ||
476 | |||
477 | |||
478 | /** | ||
479 | ** pm8001_ctl_gsm_log_show - gsm dump collection | ||
480 | ** @cdev:pointer to embedded class device | ||
481 | ** @buf: the buffer returned | ||
482 | **A sysfs 'read-only' shost attribute. | ||
483 | **/ | ||
484 | static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev, | ||
485 | struct device_attribute *attr, char *buf) | ||
486 | { | ||
487 | u32 count; | ||
488 | |||
489 | count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf); | ||
490 | return count; | ||
491 | } | ||
492 | |||
493 | static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL); | ||
494 | |||
380 | #define FLASH_CMD_NONE 0x00 | 495 | #define FLASH_CMD_NONE 0x00 |
381 | #define FLASH_CMD_UPDATE 0x01 | 496 | #define FLASH_CMD_UPDATE 0x01 |
382 | #define FLASH_CMD_SET_NVMD 0x02 | 497 | #define FLASH_CMD_SET_NVMD 0x02 |
@@ -636,6 +751,8 @@ struct device_attribute *pm8001_host_attrs[] = { | |||
636 | &dev_attr_update_fw, | 751 | &dev_attr_update_fw, |
637 | &dev_attr_aap_log, | 752 | &dev_attr_aap_log, |
638 | &dev_attr_iop_log, | 753 | &dev_attr_iop_log, |
754 | &dev_attr_fatal_log, | ||
755 | &dev_attr_gsm_log, | ||
639 | &dev_attr_max_out_io, | 756 | &dev_attr_max_out_io, |
640 | &dev_attr_max_devices, | 757 | &dev_attr_max_devices, |
641 | &dev_attr_max_sg_list, | 758 | &dev_attr_max_sg_list, |
@@ -643,6 +760,8 @@ struct device_attribute *pm8001_host_attrs[] = { | |||
643 | &dev_attr_logging_level, | 760 | &dev_attr_logging_level, |
644 | &dev_attr_host_sas_address, | 761 | &dev_attr_host_sas_address, |
645 | &dev_attr_bios_version, | 762 | &dev_attr_bios_version, |
763 | &dev_attr_ib_log, | ||
764 | &dev_attr_ob_log, | ||
646 | NULL, | 765 | NULL, |
647 | }; | 766 | }; |
648 | 767 | ||
diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h index c6d8fdd3b9b9..d0d43a250b9e 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.h +++ b/drivers/scsi/pm8001/pm8001_ctl.h | |||
@@ -55,5 +55,9 @@ | |||
55 | #define FAIL_OUT_MEMORY 0x000c00 | 55 | #define FAIL_OUT_MEMORY 0x000c00 |
56 | #define FLASH_IN_PROGRESS 0x001000 | 56 | #define FLASH_IN_PROGRESS 0x001000 |
57 | 57 | ||
58 | #define IB_OB_READ_TIMES 256 | ||
59 | #define SYSFS_OFFSET 1024 | ||
60 | #define PM80XX_IB_OB_QUEUE_SIZE (32 * 1024) | ||
61 | #define PM8001_IB_OB_QUEUE_SIZE (16 * 1024) | ||
58 | #endif /* PM8001_CTL_H_INCLUDED */ | 62 | #endif /* PM8001_CTL_H_INCLUDED */ |
59 | 63 | ||
diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h index 4bb304d379da..74a4bb9af07b 100644 --- a/drivers/scsi/pm8001/pm8001_defs.h +++ b/drivers/scsi/pm8001/pm8001_defs.h | |||
@@ -102,7 +102,8 @@ enum memory_region_num { | |||
102 | NVMD, /* NVM device */ | 102 | NVMD, /* NVM device */ |
103 | DEV_MEM, /* memory for devices */ | 103 | DEV_MEM, /* memory for devices */ |
104 | CCB_MEM, /* memory for command control block */ | 104 | CCB_MEM, /* memory for command control block */ |
105 | FW_FLASH /* memory for fw flash update */ | 105 | FW_FLASH, /* memory for fw flash update */ |
106 | FORENSIC_MEM /* memory for fw forensic data */ | ||
106 | }; | 107 | }; |
107 | #define PM8001_EVENT_LOG_SIZE (128 * 1024) | 108 | #define PM8001_EVENT_LOG_SIZE (128 * 1024) |
108 | 109 | ||
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 9d1178bcf689..f16ece91b94a 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c | |||
@@ -5001,6 +5001,89 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha, | |||
5001 | return rc; | 5001 | return rc; |
5002 | } | 5002 | } |
5003 | 5003 | ||
5004 | ssize_t | ||
5005 | pm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf) | ||
5006 | { | ||
5007 | u32 value, rem, offset = 0, bar = 0; | ||
5008 | u32 index, work_offset, dw_length; | ||
5009 | u32 shift_value, gsm_base, gsm_dump_offset; | ||
5010 | char *direct_data; | ||
5011 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
5012 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); | ||
5013 | struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; | ||
5014 | |||
5015 | direct_data = buf; | ||
5016 | gsm_dump_offset = pm8001_ha->fatal_forensic_shift_offset; | ||
5017 | |||
5018 | /* check max is 1 Mbytes */ | ||
5019 | if ((length > 0x100000) || (gsm_dump_offset & 3) || | ||
5020 | ((gsm_dump_offset + length) > 0x1000000)) | ||
5021 | return 1; | ||
5022 | |||
5023 | if (pm8001_ha->chip_id == chip_8001) | ||
5024 | bar = 2; | ||
5025 | else | ||
5026 | bar = 1; | ||
5027 | |||
5028 | work_offset = gsm_dump_offset & 0xFFFF0000; | ||
5029 | offset = gsm_dump_offset & 0x0000FFFF; | ||
5030 | gsm_dump_offset = work_offset; | ||
5031 | /* adjust length to dword boundary */ | ||
5032 | rem = length & 3; | ||
5033 | dw_length = length >> 2; | ||
5034 | |||
5035 | for (index = 0; index < dw_length; index++) { | ||
5036 | if ((work_offset + offset) & 0xFFFF0000) { | ||
5037 | if (pm8001_ha->chip_id == chip_8001) | ||
5038 | shift_value = ((gsm_dump_offset + offset) & | ||
5039 | SHIFT_REG_64K_MASK); | ||
5040 | else | ||
5041 | shift_value = (((gsm_dump_offset + offset) & | ||
5042 | SHIFT_REG_64K_MASK) >> | ||
5043 | SHIFT_REG_BIT_SHIFT); | ||
5044 | |||
5045 | if (pm8001_ha->chip_id == chip_8001) { | ||
5046 | gsm_base = GSM_BASE; | ||
5047 | if (-1 == pm8001_bar4_shift(pm8001_ha, | ||
5048 | (gsm_base + shift_value))) | ||
5049 | return 1; | ||
5050 | } else { | ||
5051 | gsm_base = 0; | ||
5052 | if (-1 == pm80xx_bar4_shift(pm8001_ha, | ||
5053 | (gsm_base + shift_value))) | ||
5054 | return 1; | ||
5055 | } | ||
5056 | gsm_dump_offset = (gsm_dump_offset + offset) & | ||
5057 | 0xFFFF0000; | ||
5058 | work_offset = 0; | ||
5059 | offset = offset & 0x0000FFFF; | ||
5060 | } | ||
5061 | value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) & | ||
5062 | 0x0000FFFF); | ||
5063 | direct_data += sprintf(direct_data, "%08x ", value); | ||
5064 | offset += 4; | ||
5065 | } | ||
5066 | if (rem != 0) { | ||
5067 | value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) & | ||
5068 | 0x0000FFFF); | ||
5069 | /* xfr for non_dw */ | ||
5070 | direct_data += sprintf(direct_data, "%08x ", value); | ||
5071 | } | ||
5072 | /* Shift back to BAR4 original address */ | ||
5073 | if (pm8001_ha->chip_id == chip_8001) { | ||
5074 | if (-1 == pm8001_bar4_shift(pm8001_ha, 0)) | ||
5075 | return 1; | ||
5076 | } else { | ||
5077 | if (-1 == pm80xx_bar4_shift(pm8001_ha, 0)) | ||
5078 | return 1; | ||
5079 | } | ||
5080 | pm8001_ha->fatal_forensic_shift_offset += 1024; | ||
5081 | |||
5082 | if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000) | ||
5083 | pm8001_ha->fatal_forensic_shift_offset = 0; | ||
5084 | return direct_data - buf; | ||
5085 | } | ||
5086 | |||
5004 | int | 5087 | int |
5005 | pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha, | 5088 | pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha, |
5006 | struct pm8001_device *pm8001_dev, u32 state) | 5089 | struct pm8001_device *pm8001_dev, u32 state) |
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h index d7c1e2034226..6d91e2446542 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.h +++ b/drivers/scsi/pm8001/pm8001_hwi.h | |||
@@ -1027,5 +1027,8 @@ struct set_dev_state_resp { | |||
1027 | #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06 | 1027 | #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06 |
1028 | #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07 | 1028 | #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07 |
1029 | 1029 | ||
1030 | #define GSM_BASE 0x4F0000 | ||
1031 | #define SHIFT_REG_64K_MASK 0xffff0000 | ||
1032 | #define SHIFT_REG_BIT_SHIFT 8 | ||
1030 | #endif | 1033 | #endif |
1031 | 1034 | ||
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 92a18c4d2ebb..662bf13c42f0 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c | |||
@@ -347,6 +347,10 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, | |||
347 | /* Memory region for fw flash */ | 347 | /* Memory region for fw flash */ |
348 | pm8001_ha->memoryMap.region[FW_FLASH].total_len = 4096; | 348 | pm8001_ha->memoryMap.region[FW_FLASH].total_len = 4096; |
349 | 349 | ||
350 | pm8001_ha->memoryMap.region[FORENSIC_MEM].num_elements = 1; | ||
351 | pm8001_ha->memoryMap.region[FORENSIC_MEM].total_len = 0x10000; | ||
352 | pm8001_ha->memoryMap.region[FORENSIC_MEM].element_size = 0x10000; | ||
353 | pm8001_ha->memoryMap.region[FORENSIC_MEM].alignment = 0x10000; | ||
350 | for (i = 0; i < USI_MAX_MEMCNT; i++) { | 354 | for (i = 0; i < USI_MAX_MEMCNT; i++) { |
351 | if (pm8001_mem_alloc(pm8001_ha->pdev, | 355 | if (pm8001_mem_alloc(pm8001_ha->pdev, |
352 | &pm8001_ha->memoryMap.region[i].virt_ptr, | 356 | &pm8001_ha->memoryMap.region[i].virt_ptr, |
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index cbde11a57a92..6037d477a183 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h | |||
@@ -132,6 +132,61 @@ struct pm8001_ioctl_payload { | |||
132 | u8 *func_specific; | 132 | u8 *func_specific; |
133 | }; | 133 | }; |
134 | 134 | ||
135 | #define MPI_FATAL_ERROR_TABLE_OFFSET_MASK 0xFFFFFF | ||
136 | #define MPI_FATAL_ERROR_TABLE_SIZE(value) ((0xFF000000 & value) >> SHIFT24) | ||
137 | #define MPI_FATAL_EDUMP_TABLE_LO_OFFSET 0x00 /* HNFBUFL */ | ||
138 | #define MPI_FATAL_EDUMP_TABLE_HI_OFFSET 0x04 /* HNFBUFH */ | ||
139 | #define MPI_FATAL_EDUMP_TABLE_LENGTH 0x08 /* HNFBLEN */ | ||
140 | #define MPI_FATAL_EDUMP_TABLE_HANDSHAKE 0x0C /* FDDHSHK */ | ||
141 | #define MPI_FATAL_EDUMP_TABLE_STATUS 0x10 /* FDDTSTAT */ | ||
142 | #define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN 0x14 /* ACCDDLEN */ | ||
143 | #define MPI_FATAL_EDUMP_HANDSHAKE_RDY 0x1 | ||
144 | #define MPI_FATAL_EDUMP_HANDSHAKE_BUSY 0x0 | ||
145 | #define MPI_FATAL_EDUMP_TABLE_STAT_RSVD 0x0 | ||
146 | #define MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED 0x1 | ||
147 | #define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA 0x2 | ||
148 | #define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE 0x3 | ||
149 | #define TYPE_GSM_SPACE 1 | ||
150 | #define TYPE_QUEUE 2 | ||
151 | #define TYPE_FATAL 3 | ||
152 | #define TYPE_NON_FATAL 4 | ||
153 | #define TYPE_INBOUND 1 | ||
154 | #define TYPE_OUTBOUND 2 | ||
155 | struct forensic_data { | ||
156 | u32 data_type; | ||
157 | union { | ||
158 | struct { | ||
159 | u32 direct_len; | ||
160 | u32 direct_offset; | ||
161 | void *direct_data; | ||
162 | } gsm_buf; | ||
163 | struct { | ||
164 | u16 queue_type; | ||
165 | u16 queue_index; | ||
166 | u32 direct_len; | ||
167 | void *direct_data; | ||
168 | } queue_buf; | ||
169 | struct { | ||
170 | u32 direct_len; | ||
171 | u32 direct_offset; | ||
172 | u32 read_len; | ||
173 | void *direct_data; | ||
174 | } data_buf; | ||
175 | }; | ||
176 | }; | ||
177 | |||
178 | /* bit31-26 - mask bar */ | ||
179 | #define SCRATCH_PAD0_BAR_MASK 0xFC000000 | ||
180 | /* bit25-0 - offset mask */ | ||
181 | #define SCRATCH_PAD0_OFFSET_MASK 0x03FFFFFF | ||
182 | /* if AAP error state */ | ||
183 | #define SCRATCH_PAD0_AAPERR_MASK 0xFFFFFFFF | ||
184 | /* Inbound doorbell bit7 */ | ||
185 | #define SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP 0x80 | ||
186 | /* Inbound doorbell bit7 SPCV */ | ||
187 | #define SPCV_MSGU_CFG_TABLE_TRANSFER_DEBUG_INFO 0x80 | ||
188 | #define MAIN_MERRDCTO_MERRDCES 0xA0/* DWORD 0x28) */ | ||
189 | |||
135 | struct pm8001_dispatch { | 190 | struct pm8001_dispatch { |
136 | char *name; | 191 | char *name; |
137 | int (*chip_init)(struct pm8001_hba_info *pm8001_ha); | 192 | int (*chip_init)(struct pm8001_hba_info *pm8001_ha); |
@@ -346,6 +401,7 @@ union main_cfg_table { | |||
346 | u32 phy_attr_table_offset; | 401 | u32 phy_attr_table_offset; |
347 | u32 port_recovery_timer; | 402 | u32 port_recovery_timer; |
348 | u32 interrupt_reassertion_delay; | 403 | u32 interrupt_reassertion_delay; |
404 | u32 fatal_n_non_fatal_dump; /* 0x28 */ | ||
349 | } pm80xx_tbl; | 405 | } pm80xx_tbl; |
350 | }; | 406 | }; |
351 | 407 | ||
@@ -420,6 +476,13 @@ struct pm8001_hba_info { | |||
420 | struct pm8001_hba_memspace io_mem[6]; | 476 | struct pm8001_hba_memspace io_mem[6]; |
421 | struct mpi_mem_req memoryMap; | 477 | struct mpi_mem_req memoryMap; |
422 | struct encrypt encrypt_info; /* support encryption */ | 478 | struct encrypt encrypt_info; /* support encryption */ |
479 | struct forensic_data forensic_info; | ||
480 | u32 fatal_bar_loc; | ||
481 | u32 forensic_last_offset; | ||
482 | u32 fatal_forensic_shift_offset; | ||
483 | u32 forensic_fatal_step; | ||
484 | u32 evtlog_ib_offset; | ||
485 | u32 evtlog_ob_offset; | ||
423 | void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/ | 486 | void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/ |
424 | void __iomem *main_cfg_tbl_addr;/*Main Config Table Addr*/ | 487 | void __iomem *main_cfg_tbl_addr;/*Main Config Table Addr*/ |
425 | void __iomem *general_stat_tbl_addr;/*General Status Table Addr*/ | 488 | void __iomem *general_stat_tbl_addr;/*General Status Table Addr*/ |
@@ -428,6 +491,7 @@ struct pm8001_hba_info { | |||
428 | void __iomem *pspa_q_tbl_addr; | 491 | void __iomem *pspa_q_tbl_addr; |
429 | /*MPI SAS PHY attributes Queue Config Table Addr*/ | 492 | /*MPI SAS PHY attributes Queue Config Table Addr*/ |
430 | void __iomem *ivt_tbl_addr; /*MPI IVT Table Addr */ | 493 | void __iomem *ivt_tbl_addr; /*MPI IVT Table Addr */ |
494 | void __iomem *fatal_tbl_addr; /*MPI IVT Table Addr */ | ||
431 | union main_cfg_table main_cfg_tbl; | 495 | union main_cfg_table main_cfg_tbl; |
432 | union general_status_table gs_tbl; | 496 | union general_status_table gs_tbl; |
433 | struct inbound_queue_table inbnd_q_tbl[PM8001_MAX_SPCV_INB_NUM]; | 497 | struct inbound_queue_table inbnd_q_tbl[PM8001_MAX_SPCV_INB_NUM]; |
@@ -634,6 +698,10 @@ int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha); | |||
634 | int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); | 698 | int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); |
635 | void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, | 699 | void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, |
636 | u32 length, u8 *buf); | 700 | u32 length, u8 *buf); |
701 | int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); | ||
702 | ssize_t pm80xx_get_fatal_dump(struct device *cdev, | ||
703 | struct device_attribute *attr, char *buf); | ||
704 | ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf); | ||
637 | /* ctl shared API */ | 705 | /* ctl shared API */ |
638 | extern struct device_attribute *pm8001_host_attrs[]; | 706 | extern struct device_attribute *pm8001_host_attrs[]; |
639 | 707 | ||
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 91cf4242a03d..8987b1706216 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c | |||
@@ -45,6 +45,228 @@ | |||
45 | 45 | ||
46 | #define SMP_DIRECT 1 | 46 | #define SMP_DIRECT 1 |
47 | #define SMP_INDIRECT 2 | 47 | #define SMP_INDIRECT 2 |
48 | |||
49 | |||
50 | int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value) | ||
51 | { | ||
52 | u32 reg_val; | ||
53 | unsigned long start; | ||
54 | pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, shift_value); | ||
55 | /* confirm the setting is written */ | ||
56 | start = jiffies + HZ; /* 1 sec */ | ||
57 | do { | ||
58 | reg_val = pm8001_cr32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER); | ||
59 | } while ((reg_val != shift_value) && time_before(jiffies, start)); | ||
60 | if (reg_val != shift_value) { | ||
61 | PM8001_FAIL_DBG(pm8001_ha, | ||
62 | pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER" | ||
63 | " = 0x%x\n", reg_val)); | ||
64 | return -1; | ||
65 | } | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | void pm80xx_pci_mem_copy(struct pm8001_hba_info *pm8001_ha, u32 soffset, | ||
70 | const void *destination, | ||
71 | u32 dw_count, u32 bus_base_number) | ||
72 | { | ||
73 | u32 index, value, offset; | ||
74 | u32 *destination1; | ||
75 | destination1 = (u32 *)destination; | ||
76 | |||
77 | for (index = 0; index < dw_count; index += 4, destination1++) { | ||
78 | offset = (soffset + index / 4); | ||
79 | if (offset < (64 * 1024)) { | ||
80 | value = pm8001_cr32(pm8001_ha, bus_base_number, offset); | ||
81 | *destination1 = cpu_to_le32(value); | ||
82 | } | ||
83 | } | ||
84 | return; | ||
85 | } | ||
86 | |||
87 | ssize_t pm80xx_get_fatal_dump(struct device *cdev, | ||
88 | struct device_attribute *attr, char *buf) | ||
89 | { | ||
90 | struct Scsi_Host *shost = class_to_shost(cdev); | ||
91 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); | ||
92 | struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; | ||
93 | void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr; | ||
94 | u32 status = 1; | ||
95 | u32 accum_len , reg_val, index, *temp; | ||
96 | unsigned long start; | ||
97 | u8 *direct_data; | ||
98 | char *fatal_error_data = buf; | ||
99 | |||
100 | pm8001_ha->forensic_info.data_buf.direct_data = buf; | ||
101 | if (pm8001_ha->chip_id == chip_8001) { | ||
102 | pm8001_ha->forensic_info.data_buf.direct_data += | ||
103 | sprintf(pm8001_ha->forensic_info.data_buf.direct_data, | ||
104 | "Not supported for SPC controller"); | ||
105 | return (char *)pm8001_ha->forensic_info.data_buf.direct_data - | ||
106 | (char *)buf; | ||
107 | } | ||
108 | if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { | ||
109 | PM8001_IO_DBG(pm8001_ha, | ||
110 | pm8001_printk("forensic_info TYPE_NON_FATAL..............\n")); | ||
111 | direct_data = (u8 *)fatal_error_data; | ||
112 | pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL; | ||
113 | pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET; | ||
114 | pm8001_ha->forensic_info.data_buf.direct_offset = 0; | ||
115 | pm8001_ha->forensic_info.data_buf.read_len = 0; | ||
116 | |||
117 | pm8001_ha->forensic_info.data_buf.direct_data = direct_data; | ||
118 | } | ||
119 | |||
120 | if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { | ||
121 | /* start to get data */ | ||
122 | /* Program the MEMBASE II Shifting Register with 0x00.*/ | ||
123 | pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, | ||
124 | pm8001_ha->fatal_forensic_shift_offset); | ||
125 | pm8001_ha->forensic_last_offset = 0; | ||
126 | pm8001_ha->forensic_fatal_step = 0; | ||
127 | pm8001_ha->fatal_bar_loc = 0; | ||
128 | } | ||
129 | /* Read until accum_len is retrived */ | ||
130 | accum_len = pm8001_mr32(fatal_table_address, | ||
131 | MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); | ||
132 | PM8001_IO_DBG(pm8001_ha, pm8001_printk("accum_len 0x%x\n", | ||
133 | accum_len)); | ||
134 | if (accum_len == 0xFFFFFFFF) { | ||
135 | PM8001_IO_DBG(pm8001_ha, | ||
136 | pm8001_printk("Possible PCI issue 0x%x not expected\n", | ||
137 | accum_len)); | ||
138 | return status; | ||
139 | } | ||
140 | if (accum_len == 0 || accum_len >= 0x100000) { | ||
141 | pm8001_ha->forensic_info.data_buf.direct_data += | ||
142 | sprintf(pm8001_ha->forensic_info.data_buf.direct_data, | ||
143 | "%08x ", 0xFFFFFFFF); | ||
144 | return (char *)pm8001_ha->forensic_info.data_buf.direct_data - | ||
145 | (char *)buf; | ||
146 | } | ||
147 | temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; | ||
148 | if (pm8001_ha->forensic_fatal_step == 0) { | ||
149 | moreData: | ||
150 | if (pm8001_ha->forensic_info.data_buf.direct_data) { | ||
151 | /* Data is in bar, copy to host memory */ | ||
152 | pm80xx_pci_mem_copy(pm8001_ha, pm8001_ha->fatal_bar_loc, | ||
153 | pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr, | ||
154 | pm8001_ha->forensic_info.data_buf.direct_len , | ||
155 | 1); | ||
156 | } | ||
157 | pm8001_ha->fatal_bar_loc += | ||
158 | pm8001_ha->forensic_info.data_buf.direct_len; | ||
159 | pm8001_ha->forensic_info.data_buf.direct_offset += | ||
160 | pm8001_ha->forensic_info.data_buf.direct_len; | ||
161 | pm8001_ha->forensic_last_offset += | ||
162 | pm8001_ha->forensic_info.data_buf.direct_len; | ||
163 | pm8001_ha->forensic_info.data_buf.read_len = | ||
164 | pm8001_ha->forensic_info.data_buf.direct_len; | ||
165 | |||
166 | if (pm8001_ha->forensic_last_offset >= accum_len) { | ||
167 | pm8001_ha->forensic_info.data_buf.direct_data += | ||
168 | sprintf(pm8001_ha->forensic_info.data_buf.direct_data, | ||
169 | "%08x ", 3); | ||
170 | for (index = 0; index < (SYSFS_OFFSET / 4); index++) { | ||
171 | pm8001_ha->forensic_info.data_buf.direct_data += | ||
172 | sprintf(pm8001_ha-> | ||
173 | forensic_info.data_buf.direct_data, | ||
174 | "%08x ", *(temp + index)); | ||
175 | } | ||
176 | |||
177 | pm8001_ha->fatal_bar_loc = 0; | ||
178 | pm8001_ha->forensic_fatal_step = 1; | ||
179 | pm8001_ha->fatal_forensic_shift_offset = 0; | ||
180 | pm8001_ha->forensic_last_offset = 0; | ||
181 | status = 0; | ||
182 | return (char *)pm8001_ha-> | ||
183 | forensic_info.data_buf.direct_data - | ||
184 | (char *)buf; | ||
185 | } | ||
186 | if (pm8001_ha->fatal_bar_loc < (64 * 1024)) { | ||
187 | pm8001_ha->forensic_info.data_buf.direct_data += | ||
188 | sprintf(pm8001_ha-> | ||
189 | forensic_info.data_buf.direct_data, | ||
190 | "%08x ", 2); | ||
191 | for (index = 0; index < (SYSFS_OFFSET / 4); index++) { | ||
192 | pm8001_ha->forensic_info.data_buf.direct_data += | ||
193 | sprintf(pm8001_ha-> | ||
194 | forensic_info.data_buf.direct_data, | ||
195 | "%08x ", *(temp + index)); | ||
196 | } | ||
197 | status = 0; | ||
198 | return (char *)pm8001_ha-> | ||
199 | forensic_info.data_buf.direct_data - | ||
200 | (char *)buf; | ||
201 | } | ||
202 | |||
203 | /* Increment the MEMBASE II Shifting Register value by 0x100.*/ | ||
204 | pm8001_ha->forensic_info.data_buf.direct_data += | ||
205 | sprintf(pm8001_ha->forensic_info.data_buf.direct_data, | ||
206 | "%08x ", 2); | ||
207 | for (index = 0; index < 256; index++) { | ||
208 | pm8001_ha->forensic_info.data_buf.direct_data += | ||
209 | sprintf(pm8001_ha-> | ||
210 | forensic_info.data_buf.direct_data, | ||
211 | "%08x ", *(temp + index)); | ||
212 | } | ||
213 | pm8001_ha->fatal_forensic_shift_offset += 0x100; | ||
214 | pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, | ||
215 | pm8001_ha->fatal_forensic_shift_offset); | ||
216 | pm8001_ha->fatal_bar_loc = 0; | ||
217 | status = 0; | ||
218 | return (char *)pm8001_ha->forensic_info.data_buf.direct_data - | ||
219 | (char *)buf; | ||
220 | } | ||
221 | if (pm8001_ha->forensic_fatal_step == 1) { | ||
222 | pm8001_ha->fatal_forensic_shift_offset = 0; | ||
223 | /* Read 64K of the debug data. */ | ||
224 | pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, | ||
225 | pm8001_ha->fatal_forensic_shift_offset); | ||
226 | pm8001_mw32(fatal_table_address, | ||
227 | MPI_FATAL_EDUMP_TABLE_HANDSHAKE, | ||
228 | MPI_FATAL_EDUMP_HANDSHAKE_RDY); | ||
229 | |||
230 | /* Poll FDDHSHK until clear */ | ||
231 | start = jiffies + (2 * HZ); /* 2 sec */ | ||
232 | |||
233 | do { | ||
234 | reg_val = pm8001_mr32(fatal_table_address, | ||
235 | MPI_FATAL_EDUMP_TABLE_HANDSHAKE); | ||
236 | } while ((reg_val) && time_before(jiffies, start)); | ||
237 | |||
238 | if (reg_val != 0) { | ||
239 | PM8001_FAIL_DBG(pm8001_ha, | ||
240 | pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER" | ||
241 | " = 0x%x\n", reg_val)); | ||
242 | return -1; | ||
243 | } | ||
244 | |||
245 | /* Read the next 64K of the debug data. */ | ||
246 | pm8001_ha->forensic_fatal_step = 0; | ||
247 | if (pm8001_mr32(fatal_table_address, | ||
248 | MPI_FATAL_EDUMP_TABLE_STATUS) != | ||
249 | MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) { | ||
250 | pm8001_mw32(fatal_table_address, | ||
251 | MPI_FATAL_EDUMP_TABLE_HANDSHAKE, 0); | ||
252 | goto moreData; | ||
253 | } else { | ||
254 | pm8001_ha->forensic_info.data_buf.direct_data += | ||
255 | sprintf(pm8001_ha-> | ||
256 | forensic_info.data_buf.direct_data, | ||
257 | "%08x ", 4); | ||
258 | pm8001_ha->forensic_info.data_buf.read_len = 0xFFFFFFFF; | ||
259 | pm8001_ha->forensic_info.data_buf.direct_len = 0; | ||
260 | pm8001_ha->forensic_info.data_buf.direct_offset = 0; | ||
261 | pm8001_ha->forensic_info.data_buf.read_len = 0; | ||
262 | status = 0; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | return (char *)pm8001_ha->forensic_info.data_buf.direct_data - | ||
267 | (char *)buf; | ||
268 | } | ||
269 | |||
48 | /** | 270 | /** |
49 | * read_main_config_table - read the configure table and save it. | 271 | * read_main_config_table - read the configure table and save it. |
50 | * @pm8001_ha: our hba card information | 272 | * @pm8001_ha: our hba card information |
@@ -583,6 +805,9 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) | |||
583 | pm8001_ha->pspa_q_tbl_addr = | 805 | pm8001_ha->pspa_q_tbl_addr = |
584 | base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x90) & | 806 | base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x90) & |
585 | 0xFFFFFF); | 807 | 0xFFFFFF); |
808 | pm8001_ha->fatal_tbl_addr = | ||
809 | base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0xA0) & | ||
810 | 0xFFFFFF); | ||
586 | 811 | ||
587 | PM8001_INIT_DBG(pm8001_ha, | 812 | PM8001_INIT_DBG(pm8001_ha, |
588 | pm8001_printk("GST OFFSET 0x%x\n", | 813 | pm8001_printk("GST OFFSET 0x%x\n", |
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index 872d5cff824f..c86816bea424 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h | |||
@@ -1525,4 +1525,6 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t; | |||
1525 | #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06 | 1525 | #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06 |
1526 | #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07 | 1526 | #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07 |
1527 | 1527 | ||
1528 | |||
1529 | #define MEMBASE_II_SHIFT_REGISTER 0x1010 | ||
1528 | #endif | 1530 | #endif |