Commit 044f59de authored by Deepak Ukey's avatar Deepak Ukey Committed by Martin K. Petersen

scsi: pm80xx: Modified the logic to collect fatal dump

Added the correct method to collect the fatal dump.

Link: https://lore.kernel.org/r/20191114100910.6153-14-deepak.ukey@microchip.comReported-by: default avatarkbuild test robot <lkp@intel.com>
Acked-by: default avatarJack Wang <jinpu.wang@cloud.ionos.com>
Signed-off-by: default avatarDeepak Ukey <deepak.ukey@microchip.com>
Signed-off-by: default avatarViswas G <Viswas.G@microchip.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 72954936
...@@ -152,6 +152,8 @@ struct pm8001_ioctl_payload { ...@@ -152,6 +152,8 @@ struct pm8001_ioctl_payload {
#define MPI_FATAL_EDUMP_TABLE_HANDSHAKE 0x0C /* FDDHSHK */ #define MPI_FATAL_EDUMP_TABLE_HANDSHAKE 0x0C /* FDDHSHK */
#define MPI_FATAL_EDUMP_TABLE_STATUS 0x10 /* FDDTSTAT */ #define MPI_FATAL_EDUMP_TABLE_STATUS 0x10 /* FDDTSTAT */
#define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN 0x14 /* ACCDDLEN */ #define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN 0x14 /* ACCDDLEN */
#define MPI_FATAL_EDUMP_TABLE_TOTAL_LEN 0x18 /* TOTALLEN */
#define MPI_FATAL_EDUMP_TABLE_SIGNATURE 0x1C /* SIGNITURE */
#define MPI_FATAL_EDUMP_HANDSHAKE_RDY 0x1 #define MPI_FATAL_EDUMP_HANDSHAKE_RDY 0x1
#define MPI_FATAL_EDUMP_HANDSHAKE_BUSY 0x0 #define MPI_FATAL_EDUMP_HANDSHAKE_BUSY 0x0
#define MPI_FATAL_EDUMP_TABLE_STAT_RSVD 0x0 #define MPI_FATAL_EDUMP_TABLE_STAT_RSVD 0x0
...@@ -507,6 +509,7 @@ struct pm8001_hba_info { ...@@ -507,6 +509,7 @@ struct pm8001_hba_info {
u32 forensic_last_offset; u32 forensic_last_offset;
u32 fatal_forensic_shift_offset; u32 fatal_forensic_shift_offset;
u32 forensic_fatal_step; u32 forensic_fatal_step;
u32 forensic_preserved_accumulated_transfer;
u32 evtlog_ib_offset; u32 evtlog_ib_offset;
u32 evtlog_ob_offset; u32 evtlog_ob_offset;
void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/ void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/
......
...@@ -76,7 +76,7 @@ void pm80xx_pci_mem_copy(struct pm8001_hba_info *pm8001_ha, u32 soffset, ...@@ -76,7 +76,7 @@ void pm80xx_pci_mem_copy(struct pm8001_hba_info *pm8001_ha, u32 soffset,
destination1 = (u32 *)destination; destination1 = (u32 *)destination;
for (index = 0; index < dw_count; index += 4, destination1++) { for (index = 0; index < dw_count; index += 4, destination1++) {
offset = (soffset + index / 4); offset = (soffset + index);
if (offset < (64 * 1024)) { if (offset < (64 * 1024)) {
value = pm8001_cr32(pm8001_ha, bus_base_number, offset); value = pm8001_cr32(pm8001_ha, bus_base_number, offset);
*destination1 = cpu_to_le32(value); *destination1 = cpu_to_le32(value);
...@@ -93,9 +93,12 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, ...@@ -93,9 +93,12 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr; void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr;
u32 accum_len , reg_val, index, *temp; u32 accum_len , reg_val, index, *temp;
u32 status = 1;
unsigned long start; unsigned long start;
u8 *direct_data; u8 *direct_data;
char *fatal_error_data = buf; char *fatal_error_data = buf;
u32 length_to_read;
u32 offset;
pm8001_ha->forensic_info.data_buf.direct_data = buf; pm8001_ha->forensic_info.data_buf.direct_data = buf;
if (pm8001_ha->chip_id == chip_8001) { if (pm8001_ha->chip_id == chip_8001) {
...@@ -105,16 +108,35 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, ...@@ -105,16 +108,35 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
return (char *)pm8001_ha->forensic_info.data_buf.direct_data - return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf; (char *)buf;
} }
/* initialize variables for very first call from host application */
if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
PM8001_IO_DBG(pm8001_ha, PM8001_IO_DBG(pm8001_ha,
pm8001_printk("forensic_info TYPE_NON_FATAL..............\n")); pm8001_printk("forensic_info TYPE_NON_FATAL..............\n"));
direct_data = (u8 *)fatal_error_data; direct_data = (u8 *)fatal_error_data;
pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL; pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL;
pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET; pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET;
pm8001_ha->forensic_info.data_buf.direct_offset = 0;
pm8001_ha->forensic_info.data_buf.read_len = 0; pm8001_ha->forensic_info.data_buf.read_len = 0;
pm8001_ha->forensic_preserved_accumulated_transfer = 0;
pm8001_ha->forensic_info.data_buf.direct_data = direct_data; /* Write signature to fatal dump table */
pm8001_mw32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_SIGNATURE, 0x1234abcd);
pm8001_ha->forensic_info.data_buf.direct_data = direct_data;
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("ossaHwCB: status1 %d\n", status));
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("ossaHwCB: read_len 0x%x\n",
pm8001_ha->forensic_info.data_buf.read_len));
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("ossaHwCB: direct_len 0x%x\n",
pm8001_ha->forensic_info.data_buf.direct_len));
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("ossaHwCB: direct_offset 0x%x\n",
pm8001_ha->forensic_info.data_buf.direct_offset));
}
if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
/* start to get data */ /* start to get data */
/* Program the MEMBASE II Shifting Register with 0x00.*/ /* Program the MEMBASE II Shifting Register with 0x00.*/
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
...@@ -127,30 +149,66 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, ...@@ -127,30 +149,66 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
/* Read until accum_len is retrived */ /* Read until accum_len is retrived */
accum_len = pm8001_mr32(fatal_table_address, accum_len = pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
PM8001_IO_DBG(pm8001_ha, pm8001_printk("accum_len 0x%x\n", /* Determine length of data between previously stored transfer length
accum_len)); * and current accumulated transfer length
*/
length_to_read =
accum_len - pm8001_ha->forensic_preserved_accumulated_transfer;
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("get_fatal_spcv: accum_len 0x%x\n", accum_len));
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("get_fatal_spcv: length_to_read 0x%x\n",
length_to_read));
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("get_fatal_spcv: last_offset 0x%x\n",
pm8001_ha->forensic_last_offset));
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("get_fatal_spcv: read_len 0x%x\n",
pm8001_ha->forensic_info.data_buf.read_len));
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("get_fatal_spcv:: direct_len 0x%x\n",
pm8001_ha->forensic_info.data_buf.direct_len));
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("get_fatal_spcv:: direct_offset 0x%x\n",
pm8001_ha->forensic_info.data_buf.direct_offset));
/* If accumulated length failed to read correctly fail the attempt.*/
if (accum_len == 0xFFFFFFFF) { if (accum_len == 0xFFFFFFFF) {
PM8001_IO_DBG(pm8001_ha, PM8001_IO_DBG(pm8001_ha,
pm8001_printk("Possible PCI issue 0x%x not expected\n", pm8001_printk("Possible PCI issue 0x%x not expected\n",
accum_len)); accum_len));
return -EIO; return status;
} }
if (accum_len == 0 || accum_len >= 0x100000) { /* If accumulated length is zero fail the attempt */
if (accum_len == 0) {
pm8001_ha->forensic_info.data_buf.direct_data += pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha->forensic_info.data_buf.direct_data, sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 0xFFFFFFFF); "%08x ", 0xFFFFFFFF);
return (char *)pm8001_ha->forensic_info.data_buf.direct_data - return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf; (char *)buf;
} }
/* Accumulated length is good so start capturing the first data */
temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr;
if (pm8001_ha->forensic_fatal_step == 0) { if (pm8001_ha->forensic_fatal_step == 0) {
moreData: moreData:
/* If data to read is less than SYSFS_OFFSET then reduce the
* length of dataLen
*/
if (pm8001_ha->forensic_last_offset + SYSFS_OFFSET
> length_to_read) {
pm8001_ha->forensic_info.data_buf.direct_len =
length_to_read -
pm8001_ha->forensic_last_offset;
} else {
pm8001_ha->forensic_info.data_buf.direct_len =
SYSFS_OFFSET;
}
if (pm8001_ha->forensic_info.data_buf.direct_data) { if (pm8001_ha->forensic_info.data_buf.direct_data) {
/* Data is in bar, copy to host memory */ /* Data is in bar, copy to host memory */
pm80xx_pci_mem_copy(pm8001_ha, pm8001_ha->fatal_bar_loc, pm80xx_pci_mem_copy(pm8001_ha,
pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr, pm8001_ha->fatal_bar_loc,
pm8001_ha->forensic_info.data_buf.direct_len , pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr,
1); pm8001_ha->forensic_info.data_buf.direct_len, 1);
} }
pm8001_ha->fatal_bar_loc += pm8001_ha->fatal_bar_loc +=
pm8001_ha->forensic_info.data_buf.direct_len; pm8001_ha->forensic_info.data_buf.direct_len;
...@@ -161,21 +219,29 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, ...@@ -161,21 +219,29 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
pm8001_ha->forensic_info.data_buf.read_len = pm8001_ha->forensic_info.data_buf.read_len =
pm8001_ha->forensic_info.data_buf.direct_len; pm8001_ha->forensic_info.data_buf.direct_len;
if (pm8001_ha->forensic_last_offset >= accum_len) { if (pm8001_ha->forensic_last_offset >= length_to_read) {
pm8001_ha->forensic_info.data_buf.direct_data += pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha->forensic_info.data_buf.direct_data, sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 3); "%08x ", 3);
for (index = 0; index < (SYSFS_OFFSET / 4); index++) { for (index = 0; index <
(pm8001_ha->forensic_info.data_buf.direct_len
/ 4); index++) {
pm8001_ha->forensic_info.data_buf.direct_data += pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha-> sprintf(
forensic_info.data_buf.direct_data, pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", *(temp + index)); "%08x ", *(temp + index));
} }
pm8001_ha->fatal_bar_loc = 0; pm8001_ha->fatal_bar_loc = 0;
pm8001_ha->forensic_fatal_step = 1; pm8001_ha->forensic_fatal_step = 1;
pm8001_ha->fatal_forensic_shift_offset = 0; pm8001_ha->fatal_forensic_shift_offset = 0;
pm8001_ha->forensic_last_offset = 0; pm8001_ha->forensic_last_offset = 0;
status = 0;
offset = (int)
((char *)pm8001_ha->forensic_info.data_buf.direct_data
- (char *)buf);
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("get_fatal_spcv:return1 0x%x\n", offset));
return (char *)pm8001_ha-> return (char *)pm8001_ha->
forensic_info.data_buf.direct_data - forensic_info.data_buf.direct_data -
(char *)buf; (char *)buf;
...@@ -185,12 +251,20 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, ...@@ -185,12 +251,20 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
sprintf(pm8001_ha-> sprintf(pm8001_ha->
forensic_info.data_buf.direct_data, forensic_info.data_buf.direct_data,
"%08x ", 2); "%08x ", 2);
for (index = 0; index < (SYSFS_OFFSET / 4); index++) { for (index = 0; index <
pm8001_ha->forensic_info.data_buf.direct_data += (pm8001_ha->forensic_info.data_buf.direct_len
sprintf(pm8001_ha-> / 4); index++) {
pm8001_ha->forensic_info.data_buf.direct_data
+= sprintf(pm8001_ha->
forensic_info.data_buf.direct_data, forensic_info.data_buf.direct_data,
"%08x ", *(temp + index)); "%08x ", *(temp + index));
} }
status = 0;
offset = (int)
((char *)pm8001_ha->forensic_info.data_buf.direct_data
- (char *)buf);
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("get_fatal_spcv:return2 0x%x\n", offset));
return (char *)pm8001_ha-> return (char *)pm8001_ha->
forensic_info.data_buf.direct_data - forensic_info.data_buf.direct_data -
(char *)buf; (char *)buf;
...@@ -200,63 +274,122 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, ...@@ -200,63 +274,122 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
pm8001_ha->forensic_info.data_buf.direct_data += pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha->forensic_info.data_buf.direct_data, sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 2); "%08x ", 2);
for (index = 0; index < 256; index++) { for (index = 0; index <
(pm8001_ha->forensic_info.data_buf.direct_len
/ 4) ; index++) {
pm8001_ha->forensic_info.data_buf.direct_data += pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha-> sprintf(pm8001_ha->
forensic_info.data_buf.direct_data, forensic_info.data_buf.direct_data,
"%08x ", *(temp + index)); "%08x ", *(temp + index));
} }
pm8001_ha->fatal_forensic_shift_offset += 0x100; pm8001_ha->fatal_forensic_shift_offset += 0x100;
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
pm8001_ha->fatal_forensic_shift_offset); pm8001_ha->fatal_forensic_shift_offset);
pm8001_ha->fatal_bar_loc = 0; pm8001_ha->fatal_bar_loc = 0;
status = 0;
offset = (int)
((char *)pm8001_ha->forensic_info.data_buf.direct_data
- (char *)buf);
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("get_fatal_spcv: return3 0x%x\n", offset));
return (char *)pm8001_ha->forensic_info.data_buf.direct_data - return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf; (char *)buf;
} }
if (pm8001_ha->forensic_fatal_step == 1) { if (pm8001_ha->forensic_fatal_step == 1) {
pm8001_ha->fatal_forensic_shift_offset = 0; /* store previous accumulated length before triggering next
/* Read 64K of the debug data. */ * accumulated length update
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, */
pm8001_ha->fatal_forensic_shift_offset); pm8001_ha->forensic_preserved_accumulated_transfer =
pm8001_mw32(fatal_table_address, pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_HANDSHAKE, MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
/* continue capturing the fatal log until Dump status is 0x3 */
if (pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_STATUS) <
MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) {
/* reset fddstat bit by writing to zero*/
pm8001_mw32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_STATUS, 0x0);
/* set dump control value to '1' so that new data will
* be transferred to shared memory
*/
pm8001_mw32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_HANDSHAKE,
MPI_FATAL_EDUMP_HANDSHAKE_RDY); MPI_FATAL_EDUMP_HANDSHAKE_RDY);
/* Poll FDDHSHK until clear */ /*Poll FDDHSHK until clear */
start = jiffies + (2 * HZ); /* 2 sec */ start = jiffies + (2 * HZ); /* 2 sec */
do { do {
reg_val = pm8001_mr32(fatal_table_address, reg_val = pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_HANDSHAKE); MPI_FATAL_EDUMP_TABLE_HANDSHAKE);
} while ((reg_val) && time_before(jiffies, start)); } while ((reg_val) && time_before(jiffies, start));
if (reg_val != 0) { if (reg_val != 0) {
PM8001_FAIL_DBG(pm8001_ha, PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER" "TIMEOUT:MPI_FATAL_EDUMP_TABLE_HDSHAKE 0x%x\n",
" = 0x%x\n", reg_val)); reg_val));
return -EIO; /* Fail the dump if a timeout occurs */
} pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(
/* Read the next 64K of the debug data. */ pm8001_ha->forensic_info.data_buf.direct_data,
pm8001_ha->forensic_fatal_step = 0; "%08x ", 0xFFFFFFFF);
if (pm8001_mr32(fatal_table_address, return((char *)
MPI_FATAL_EDUMP_TABLE_STATUS) != pm8001_ha->forensic_info.data_buf.direct_data
MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) { - (char *)buf);
pm8001_mw32(fatal_table_address, }
MPI_FATAL_EDUMP_TABLE_HANDSHAKE, 0); /* Poll status register until set to 2 or
goto moreData; * 3 for up to 2 seconds
} else { */
pm8001_ha->forensic_info.data_buf.direct_data += start = jiffies + (2 * HZ); /* 2 sec */
sprintf(pm8001_ha->
forensic_info.data_buf.direct_data, do {
"%08x ", 4); reg_val = pm8001_mr32(fatal_table_address,
pm8001_ha->forensic_info.data_buf.read_len = 0xFFFFFFFF; MPI_FATAL_EDUMP_TABLE_STATUS);
pm8001_ha->forensic_info.data_buf.direct_len = 0; } while (((reg_val != 2) || (reg_val != 3)) &&
pm8001_ha->forensic_info.data_buf.direct_offset = 0; time_before(jiffies, start));
pm8001_ha->forensic_info.data_buf.read_len = 0;
if (reg_val < 2) {
PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
"TIMEOUT:MPI_FATAL_EDUMP_TABLE_STATUS = 0x%x\n",
reg_val));
/* Fail the dump if a timeout occurs */
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(
pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 0xFFFFFFFF);
pm8001_cw32(pm8001_ha, 0,
MEMBASE_II_SHIFT_REGISTER,
pm8001_ha->fatal_forensic_shift_offset);
}
/* Read the next block of the debug data.*/
length_to_read = pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN) -
pm8001_ha->forensic_preserved_accumulated_transfer;
if (length_to_read != 0x0) {
pm8001_ha->forensic_fatal_step = 0;
goto moreData;
} else {
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(
pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 4);
pm8001_ha->forensic_info.data_buf.read_len
= 0xFFFFFFFF;
pm8001_ha->forensic_info.data_buf.direct_len
= 0;
pm8001_ha->forensic_info.data_buf.direct_offset
= 0;
pm8001_ha->forensic_info.data_buf.read_len = 0;
}
} }
} }
offset = (int)((char *)pm8001_ha->forensic_info.data_buf.direct_data
- (char *)buf);
PM8001_IO_DBG(pm8001_ha,
pm8001_printk("get_fatal_spcv: return4 0x%x\n", offset));
return (char *)pm8001_ha->forensic_info.data_buf.direct_data - return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf; (char *)buf;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment