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);
+
+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
        &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,
 
                (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