[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>
Šī revīzija ir iekļauta:

revīziju iesūtīja
James Bottomley

vecāks
279094079a
revīzija
d078b5117f
@@ -45,6 +45,228 @@
|
||||
|
||||
#define SMP_DIRECT 1
|
||||
#define SMP_INDIRECT 2
|
||||
|
||||
|
||||
int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value)
|
||||
{
|
||||
u32 reg_val;
|
||||
unsigned long start;
|
||||
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, shift_value);
|
||||
/* confirm the setting is written */
|
||||
start = jiffies + HZ; /* 1 sec */
|
||||
do {
|
||||
reg_val = pm8001_cr32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER);
|
||||
} while ((reg_val != shift_value) && time_before(jiffies, start));
|
||||
if (reg_val != shift_value) {
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER"
|
||||
" = 0x%x\n", reg_val));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pm80xx_pci_mem_copy(struct pm8001_hba_info *pm8001_ha, u32 soffset,
|
||||
const void *destination,
|
||||
u32 dw_count, u32 bus_base_number)
|
||||
{
|
||||
u32 index, value, offset;
|
||||
u32 *destination1;
|
||||
destination1 = (u32 *)destination;
|
||||
|
||||
for (index = 0; index < dw_count; index += 4, destination1++) {
|
||||
offset = (soffset + index / 4);
|
||||
if (offset < (64 * 1024)) {
|
||||
value = pm8001_cr32(pm8001_ha, bus_base_number, offset);
|
||||
*destination1 = cpu_to_le32(value);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t pm80xx_get_fatal_dump(struct device *cdev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct Scsi_Host *shost = class_to_shost(cdev);
|
||||
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
|
||||
struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
|
||||
void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr;
|
||||
u32 status = 1;
|
||||
u32 accum_len , reg_val, index, *temp;
|
||||
unsigned long start;
|
||||
u8 *direct_data;
|
||||
char *fatal_error_data = buf;
|
||||
|
||||
pm8001_ha->forensic_info.data_buf.direct_data = buf;
|
||||
if (pm8001_ha->chip_id == chip_8001) {
|
||||
pm8001_ha->forensic_info.data_buf.direct_data +=
|
||||
sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
|
||||
"Not supported for SPC controller");
|
||||
return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
|
||||
(char *)buf;
|
||||
}
|
||||
if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("forensic_info TYPE_NON_FATAL..............\n"));
|
||||
direct_data = (u8 *)fatal_error_data;
|
||||
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_offset = 0;
|
||||
pm8001_ha->forensic_info.data_buf.read_len = 0;
|
||||
|
||||
pm8001_ha->forensic_info.data_buf.direct_data = direct_data;
|
||||
}
|
||||
|
||||
if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
|
||||
/* start to get data */
|
||||
/* Program the MEMBASE II Shifting Register with 0x00.*/
|
||||
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
|
||||
pm8001_ha->fatal_forensic_shift_offset);
|
||||
pm8001_ha->forensic_last_offset = 0;
|
||||
pm8001_ha->forensic_fatal_step = 0;
|
||||
pm8001_ha->fatal_bar_loc = 0;
|
||||
}
|
||||
/* Read until accum_len is retrived */
|
||||
accum_len = pm8001_mr32(fatal_table_address,
|
||||
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
|
||||
PM8001_IO_DBG(pm8001_ha, pm8001_printk("accum_len 0x%x\n",
|
||||
accum_len));
|
||||
if (accum_len == 0xFFFFFFFF) {
|
||||
PM8001_IO_DBG(pm8001_ha,
|
||||
pm8001_printk("Possible PCI issue 0x%x not expected\n",
|
||||
accum_len));
|
||||
return status;
|
||||
}
|
||||
if (accum_len == 0 || accum_len >= 0x100000) {
|
||||
pm8001_ha->forensic_info.data_buf.direct_data +=
|
||||
sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
|
||||
"%08x ", 0xFFFFFFFF);
|
||||
return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
|
||||
(char *)buf;
|
||||
}
|
||||
temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr;
|
||||
if (pm8001_ha->forensic_fatal_step == 0) {
|
||||
moreData:
|
||||
if (pm8001_ha->forensic_info.data_buf.direct_data) {
|
||||
/* Data is in bar, copy to host memory */
|
||||
pm80xx_pci_mem_copy(pm8001_ha, pm8001_ha->fatal_bar_loc,
|
||||
pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr,
|
||||
pm8001_ha->forensic_info.data_buf.direct_len ,
|
||||
1);
|
||||
}
|
||||
pm8001_ha->fatal_bar_loc +=
|
||||
pm8001_ha->forensic_info.data_buf.direct_len;
|
||||
pm8001_ha->forensic_info.data_buf.direct_offset +=
|
||||
pm8001_ha->forensic_info.data_buf.direct_len;
|
||||
pm8001_ha->forensic_last_offset +=
|
||||
pm8001_ha->forensic_info.data_buf.direct_len;
|
||||
pm8001_ha->forensic_info.data_buf.read_len =
|
||||
pm8001_ha->forensic_info.data_buf.direct_len;
|
||||
|
||||
if (pm8001_ha->forensic_last_offset >= accum_len) {
|
||||
pm8001_ha->forensic_info.data_buf.direct_data +=
|
||||
sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
|
||||
"%08x ", 3);
|
||||
for (index = 0; index < (SYSFS_OFFSET / 4); index++) {
|
||||
pm8001_ha->forensic_info.data_buf.direct_data +=
|
||||
sprintf(pm8001_ha->
|
||||
forensic_info.data_buf.direct_data,
|
||||
"%08x ", *(temp + index));
|
||||
}
|
||||
|
||||
pm8001_ha->fatal_bar_loc = 0;
|
||||
pm8001_ha->forensic_fatal_step = 1;
|
||||
pm8001_ha->fatal_forensic_shift_offset = 0;
|
||||
pm8001_ha->forensic_last_offset = 0;
|
||||
status = 0;
|
||||
return (char *)pm8001_ha->
|
||||
forensic_info.data_buf.direct_data -
|
||||
(char *)buf;
|
||||
}
|
||||
if (pm8001_ha->fatal_bar_loc < (64 * 1024)) {
|
||||
pm8001_ha->forensic_info.data_buf.direct_data +=
|
||||
sprintf(pm8001_ha->
|
||||
forensic_info.data_buf.direct_data,
|
||||
"%08x ", 2);
|
||||
for (index = 0; index < (SYSFS_OFFSET / 4); index++) {
|
||||
pm8001_ha->forensic_info.data_buf.direct_data +=
|
||||
sprintf(pm8001_ha->
|
||||
forensic_info.data_buf.direct_data,
|
||||
"%08x ", *(temp + index));
|
||||
}
|
||||
status = 0;
|
||||
return (char *)pm8001_ha->
|
||||
forensic_info.data_buf.direct_data -
|
||||
(char *)buf;
|
||||
}
|
||||
|
||||
/* Increment the MEMBASE II Shifting Register value by 0x100.*/
|
||||
pm8001_ha->forensic_info.data_buf.direct_data +=
|
||||
sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
|
||||
"%08x ", 2);
|
||||
for (index = 0; index < 256; index++) {
|
||||
pm8001_ha->forensic_info.data_buf.direct_data +=
|
||||
sprintf(pm8001_ha->
|
||||
forensic_info.data_buf.direct_data,
|
||||
"%08x ", *(temp + index));
|
||||
}
|
||||
pm8001_ha->fatal_forensic_shift_offset += 0x100;
|
||||
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
|
||||
pm8001_ha->fatal_forensic_shift_offset);
|
||||
pm8001_ha->fatal_bar_loc = 0;
|
||||
status = 0;
|
||||
return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
|
||||
(char *)buf;
|
||||
}
|
||||
if (pm8001_ha->forensic_fatal_step == 1) {
|
||||
pm8001_ha->fatal_forensic_shift_offset = 0;
|
||||
/* Read 64K of the debug data. */
|
||||
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
|
||||
pm8001_ha->fatal_forensic_shift_offset);
|
||||
pm8001_mw32(fatal_table_address,
|
||||
MPI_FATAL_EDUMP_TABLE_HANDSHAKE,
|
||||
MPI_FATAL_EDUMP_HANDSHAKE_RDY);
|
||||
|
||||
/* Poll FDDHSHK until clear */
|
||||
start = jiffies + (2 * HZ); /* 2 sec */
|
||||
|
||||
do {
|
||||
reg_val = pm8001_mr32(fatal_table_address,
|
||||
MPI_FATAL_EDUMP_TABLE_HANDSHAKE);
|
||||
} while ((reg_val) && time_before(jiffies, start));
|
||||
|
||||
if (reg_val != 0) {
|
||||
PM8001_FAIL_DBG(pm8001_ha,
|
||||
pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER"
|
||||
" = 0x%x\n", reg_val));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read the next 64K of the debug data. */
|
||||
pm8001_ha->forensic_fatal_step = 0;
|
||||
if (pm8001_mr32(fatal_table_address,
|
||||
MPI_FATAL_EDUMP_TABLE_STATUS) !=
|
||||
MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) {
|
||||
pm8001_mw32(fatal_table_address,
|
||||
MPI_FATAL_EDUMP_TABLE_HANDSHAKE, 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;
|
||||
status = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
|
||||
(char *)buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_main_config_table - read the configure table and save it.
|
||||
* @pm8001_ha: our hba card information
|
||||
@@ -583,6 +805,9 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
|
||||
pm8001_ha->pspa_q_tbl_addr =
|
||||
base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x90) &
|
||||
0xFFFFFF);
|
||||
pm8001_ha->fatal_tbl_addr =
|
||||
base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0xA0) &
|
||||
0xFFFFFF);
|
||||
|
||||
PM8001_INIT_DBG(pm8001_ha,
|
||||
pm8001_printk("GST OFFSET 0x%x\n",
|
||||
|
Atsaukties uz šo jaunā problēmā
Block a user