On Tue, Dec 24, 2019 at 5:41 AM Deepak Ukey <deepak.ukey@xxxxxxxxxxxxx> wrote: > > From: Deepak Ukey <Deepak.Ukey@xxxxxxxxxxxxx> > > Added the functionality to collect non fatal dump. Please extend the commit message, what the use case, how to use it. > > Signed-off-by: Deepak Ukey <deepak.ukey@xxxxxxxxxxxxx> > Signed-off-by: Viswas G <Viswas.G@xxxxxxxxxxxxx> > Signed-off-by: Vishakha Channapattan <vishakhavc@xxxxxxxxxx> > Signed-off-by: Bhavesh Jashnani <bjashnani@xxxxxxxxxx> > Signed-off-by: Radha Ramachandran <radha@xxxxxxxxxx> > Signed-off-by: Akshat Jain <akshatzen@xxxxxxxxxx> > Signed-off-by: Yu Zheng <yuuzheng@xxxxxxxxxx> > --- > drivers/scsi/pm8001/pm8001_ctl.c | 45 +++++++++++++ > drivers/scsi/pm8001/pm8001_init.c | 1 + > drivers/scsi/pm8001/pm8001_sas.h | 4 ++ > drivers/scsi/pm8001/pm80xx_hwi.c | 130 ++++++++++++++++++++++++++++++++++++++ > 4 files changed, 180 insertions(+) > > diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c > index 3e59b2a7185a..669c60a8d123 100644 > --- a/drivers/scsi/pm8001/pm8001_ctl.c > +++ b/drivers/scsi/pm8001/pm8001_ctl.c > @@ -577,6 +577,49 @@ static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev, > > static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL); > > +/** > + ** non_fatal_log_show - non fatal error logging > + ** @cdev:pointer to embedded class device > + ** @buf: the buffer returned > + ** > + ** A sysfs 'read-only' shost attribute. > + **/ > +static ssize_t non_fatal_log_show(struct device *cdev, > + struct device_attribute *attr, char *buf) > +{ > + u32 count; > + > + count = pm80xx_get_non_fatal_dump(cdev, attr, buf); > + return count; > +} > +static DEVICE_ATTR_RO(non_fatal_log); I would suggest to use pm8001_ctl_non_fatal_log_show as function name, or convert remove the prefix for other functions, it's annoying to have different naming convention. > + > +static ssize_t non_fatal_count_show(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; > + > + return snprintf(buf, PAGE_SIZE, "%08x", > + pm8001_ha->non_fatal_count); > +} > + > +static ssize_t non_fatal_count_store(struct device *cdev, > + struct device_attribute *attr, const char *buf, size_t count) > +{ > + 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; > + int val = 0; > + > + if (kstrtoint(buf, 16, &val) != 0) > + return -EINVAL; > + > + pm8001_ha->non_fatal_count = val; > + return strlen(buf); > +} > +static DEVICE_ATTR_RW(non_fatal_count); > > /** > ** pm8001_ctl_gsm_log_show - gsm dump collection > @@ -853,6 +896,8 @@ struct device_attribute *pm8001_host_attrs[] = { > &dev_attr_aap_log, > &dev_attr_iop_log, > &dev_attr_fatal_log, > + &dev_attr_non_fatal_log, > + &dev_attr_non_fatal_count, > &dev_attr_gsm_log, > &dev_attr_max_out_io, > &dev_attr_max_devices, > diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c > index c8414f1b9652..b74282bc1ed0 100644 > --- a/drivers/scsi/pm8001/pm8001_init.c > +++ b/drivers/scsi/pm8001/pm8001_init.c > @@ -484,6 +484,7 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, > pm8001_ha->shost = shost; > pm8001_ha->id = pm8001_id++; > pm8001_ha->logging_level = logging_level; > + pm8001_ha->non_fatal_count = 0; > if (link_rate >= 1 && link_rate <= 15) > pm8001_ha->link_rate = (link_rate << 8); > else { > diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h > index f95f4d714983..47607a25f819 100644 > --- a/drivers/scsi/pm8001/pm8001_sas.h > +++ b/drivers/scsi/pm8001/pm8001_sas.h > @@ -601,6 +601,8 @@ struct pm8001_hba_info { > struct sgpio_ioctl_resp sgpio_resp; > struct phy_prof_resp phy_profile_resp; > u32 reset_in_progress; > + u32 non_fatal_count; > + u32 non_fatal_read_length; > }; > > struct pm8001_work { > @@ -790,6 +792,8 @@ void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, > int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); > ssize_t pm80xx_get_fatal_dump(struct device *cdev, > struct device_attribute *attr, char *buf); > +ssize_t pm80xx_get_non_fatal_dump(struct device *cdev, > + struct device_attribute *attr, char *buf); > ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf); > /* ctl shared API */ > extern struct device_attribute *pm8001_host_attrs[]; > diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c > index bbcdcff5d25b..4923660304aa 100644 > --- a/drivers/scsi/pm8001/pm80xx_hwi.c > +++ b/drivers/scsi/pm8001/pm80xx_hwi.c > @@ -393,6 +393,136 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, > (char *)buf; > } > > +/* pm80xx_get_non_fatal_dump - dump the nonfatal data from the dma > + * location by the firmware. > + */ > +ssize_t pm80xx_get_non_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 *nonfatal_table_address = pm8001_ha->fatal_tbl_addr; > + u32 accum_len = 0; > + u32 total_len = 0; > + u32 reg_val = 0; > + u32 *temp = NULL; > + u32 index = 0; > + u32 output_length; > + unsigned long start = 0; > + char *buf_copy = buf; > + > + temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; > + if (++pm8001_ha->non_fatal_count == 1) { > + if (pm8001_ha->chip_id == chip_8001) { > + snprintf(pm8001_ha->forensic_info.data_buf.direct_data, > + PAGE_SIZE, "Not supported for SPC controller"); > + return 0; > + } > + PM8001_IO_DBG(pm8001_ha, > + pm8001_printk("forensic_info TYPE_NON_FATAL...\n")); > + /* > + * Step 1: Write the host buffer parameters in the MPI Fatal and > + * Non-Fatal Error Dump Capture Table.This is the buffer > + * where debug data will be DMAed to. > + */ > + pm8001_mw32(nonfatal_table_address, > + MPI_FATAL_EDUMP_TABLE_LO_OFFSET, > + pm8001_ha->memoryMap.region[FORENSIC_MEM].phys_addr_lo); > + > + pm8001_mw32(nonfatal_table_address, > + MPI_FATAL_EDUMP_TABLE_HI_OFFSET, > + pm8001_ha->memoryMap.region[FORENSIC_MEM].phys_addr_hi); > + > + pm8001_mw32(nonfatal_table_address, > + MPI_FATAL_EDUMP_TABLE_LENGTH, SYSFS_OFFSET); > + > + /* Optionally, set the DUMPCTRL bit to 1 if the host > + * keeps sending active I/Os while capturing the non-fatal > + * debug data. Otherwise, leave this bit set to zero > + */ > + pm8001_mw32(nonfatal_table_address, > + MPI_FATAL_EDUMP_TABLE_HANDSHAKE, MPI_FATAL_EDUMP_HANDSHAKE_RDY); > + > + /* > + * Step 2: Clear Accumulative Length of Debug Data Transferred > + * [ACCDDLEN] field in the MPI Fatal and Non-Fatal Error Dump > + * Capture Table to zero. > + */ > + pm8001_mw32(nonfatal_table_address, > + MPI_FATAL_EDUMP_TABLE_ACCUM_LEN, 0); > + > + /* initiallize previous accumulated length to 0 */ > + pm8001_ha->forensic_preserved_accumulated_transfer = 0; > + pm8001_ha->non_fatal_read_length = 0; > + } > + > + total_len = pm8001_mr32(nonfatal_table_address, > + MPI_FATAL_EDUMP_TABLE_TOTAL_LEN); > + /* > + * Step 3:Clear Fatal/Non-Fatal Debug Data Transfer Status [FDDTSTAT] > + * field and then request that the SPCv controller transfer the debug > + * data by setting bit 7 of the Inbound Doorbell Set Register. > + */ > + pm8001_mw32(nonfatal_table_address, MPI_FATAL_EDUMP_TABLE_STATUS, 0); > + pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, > + SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP); > + > + /* > + * Step 4.1: Read back the Inbound Doorbell Set Register (by polling for > + * 2 seconds) until register bit 7 is cleared. > + * This step only indicates the request is accepted by the controller. > + */ > + start = jiffies + (2 * HZ); /* 2 sec */ > + do { > + reg_val = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET) & > + SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP; > + } while ((reg_val != 0) && time_before(jiffies, start)); > + > + /* Step 4.2: To check the completion of the transfer, poll the Fatal/Non > + * Fatal Debug Data Transfer Status [FDDTSTAT] field for 2 seconds in > + * the MPI Fatal and Non-Fatal Error Dump Capture Table. > + */ > + start = jiffies + (2 * HZ); /* 2 sec */ > + do { > + reg_val = pm8001_mr32(nonfatal_table_address, > + MPI_FATAL_EDUMP_TABLE_STATUS); > + } while ((!reg_val) && time_before(jiffies, start)); > + > + if ((reg_val == 0x00) || > + (reg_val == MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED) || > + (reg_val > MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE)) { > + pm8001_ha->non_fatal_read_length = 0; > + buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 0xFFFFFFFF); > + pm8001_ha->non_fatal_count = 0; > + return (buf_copy - buf); > + } else if (reg_val == > + MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA) { > + buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 2); > + } else if ((reg_val == MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) || > + (pm8001_ha->non_fatal_read_length >= total_len)) { > + pm8001_ha->non_fatal_read_length = 0; > + buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 4); > + pm8001_ha->non_fatal_count = 0; > + } > + accum_len = pm8001_mr32(nonfatal_table_address, > + MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); > + output_length = accum_len - > + pm8001_ha->forensic_preserved_accumulated_transfer; > + > + for (index = 0; index < output_length/4; index++) > + buf_copy += snprintf(buf_copy, PAGE_SIZE, > + "%08x ", *(temp+index)); > + > + pm8001_ha->non_fatal_read_length += output_length; > + > + /* store current accumulated length to use in next iteration as > + * the previous accumulated length > + */ > + pm8001_ha->forensic_preserved_accumulated_transfer = accum_len; > + return (buf_copy - buf); > +} > + > /** > * read_main_config_table - read the configure table and save it. > * @pm8001_ha: our hba card information > -- > 2.16.3 >