* [PATCH V2 10/10] pm80xx: Firmware logging support
@ 2013-09-26 5:43 Anand
2013-09-26 7:12 ` Jack Wang
2013-09-27 13:02 ` Tomas Henzl
0 siblings, 2 replies; 5+ messages in thread
From: Anand @ 2013-09-26 5:43 UTC (permalink / raw)
To: linux-scsi
Cc: Sangeetha.Gnanasekaran, Nikith.Ganigarakoppal, Viswas.G, xjtuwjp
>From ab1b030500a835eacda3d86e5570366099b21311 Mon Sep 17 00:00:00 2001
From: Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>
Date: Wed, 4 Sep 2013 12:57:00 +0530
Subject: [PATCH V2 10/10] 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.
Signed-off-by: Anandkumar.Santhanam@pmcs.com
---
drivers/scsi/pm8001/pm8001_ctl.c | 129 +++++++++++++++++++++
drivers/scsi/pm8001/pm8001_ctl.h | 4 +
drivers/scsi/pm8001/pm8001_defs.h | 3 +-
drivers/scsi/pm8001/pm8001_hwi.c | 83 ++++++++++++++
drivers/scsi/pm8001/pm8001_hwi.h | 3 +
drivers/scsi/pm8001/pm8001_init.c | 4 +
drivers/scsi/pm8001/pm8001_sas.h | 68 +++++++++++
drivers/scsi/pm8001/pm80xx_hwi.c | 225 +++++++++++++++++++++++++++++++++++++
drivers/scsi/pm8001/pm80xx_hwi.h | 2 +
9 files changed, 520 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index 5a19e19..2ca79a5 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -309,6 +309,94 @@ static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,
}
static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);
/**
+ * pm8001_ctl_ib_queue_log_show - Out bound Queue log
+ * @cdev:pointer to embedded class device
+ * @buf: the buffer returned
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t pm8001_ctl_ib_queue_log_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;
+ int offset;
+ char *str = buf;
+ int start = 0;
+#define IB_MEMMAP(c) \
+ (*(u32 *)((u8 *)pm8001_ha-> \
+ memoryMap.region[IB].virt_ptr + \
+ pm8001_ha->evtlog_ib_offset + (c)))
+
+#define IB_MEMMAP_SPC(c) \
+ (*(u32 *)((u8 *)pm8001_ha-> \
+ memoryMap.region[IB].virt_ptr + \
+ pm8001_ha->evtlog_ib_offset + (c)))
+
+ for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
+ if (pm8001_ha->chip_id != chip_8001)
+ str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
+ else
+ str += sprintf(str, "0x%08x\n", IB_MEMMAP_SPC(start));
+ start = start + 4;
+ }
+ pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;
+ if ((((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
+ && (pm8001_ha->chip_id != chip_8001))
+ pm8001_ha->evtlog_ib_offset = 0;
+ if ((((pm8001_ha->evtlog_ib_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
+ && (pm8001_ha->chip_id == chip_8001))
+ pm8001_ha->evtlog_ib_offset = 0;
+
+ return str - buf;
+}
+
+static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL);
+/**
+ * pm8001_ctl_ob_queue_log_show - Out bound Queue log
+ * @cdev:pointer to embedded class device
+ * @buf: the buffer returned
+ * A sysfs 'read-only' shost attribute.
+ */
+
+static ssize_t pm8001_ctl_ob_queue_log_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;
+ int offset;
+ char *str = buf;
+ int start = 0;
+#define OB_MEMMAP(c) \
+ (*(u32 *)((u8 *)pm8001_ha-> \
+ memoryMap.region[OB].virt_ptr + \
+ pm8001_ha->evtlog_ob_offset + (c)))
+
+#define OB_MEMMAP_SPC(c) \
+ (*(u32 *)((u8 *)pm8001_ha-> \
+ memoryMap.region[OB].virt_ptr + \
+ pm8001_ha->evtlog_ob_offset + (c)))
+
+ for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
+ if (pm8001_ha->chip_id != chip_8001)
+ str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
+ else
+ str += sprintf(str, "0x%08x\n", OB_MEMMAP_SPC(start));
+ start = start + 4;
+ }
+ pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;
+ if ((((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
+ && (pm8001_ha->chip_id != chip_8001))
+ pm8001_ha->evtlog_ob_offset = 0;
+ if ((((pm8001_ha->evtlog_ob_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
+ && (pm8001_ha->chip_id == chip_8001))
+ pm8001_ha->evtlog_ob_offset = 0;
+
+ return str - buf;
+}
+static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL);
+/**
* pm8001_ctl_bios_version_show - Bios version Display
* @cdev:pointer to embedded class device
* @buf:the buffer returned
@@ -377,6 +465,43 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
}
static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
+/**
+ ** pm8001_ctl_fatal_log_show - fatal error logging
+ ** @cdev:pointer to embedded class device
+ ** @buf: the buffer returned
+ **
+ ** A sysfs 'read-only' shost attribute.
+ **/
+
+static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 count;
+
+ count = pm80xx_get_fatal_dump(cdev, attr, buf);
+ return count;
+}
+
+static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);
+
+
+/**
+ ** pm8001_ctl_gsm_log_show - gsm dump collection
+ ** @cdev:pointer to embedded class device
+ ** @buf: the buffer returned
+ **A sysfs 'read-only' shost attribute.
+ **/
+static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 count;
+
+ count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);
+ return count;
+}
+
+static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL);
+
#define FLASH_CMD_NONE 0x00
#define FLASH_CMD_UPDATE 0x01
#define FLASH_CMD_SET_NVMD 0x02
@@ -636,6 +761,8 @@ struct device_attribute *pm8001_host_attrs[] = {
&dev_attr_update_fw,
&dev_attr_aap_log,
&dev_attr_iop_log,
+ &dev_attr_fatal_log,
+ &dev_attr_gsm_log,
&dev_attr_max_out_io,
&dev_attr_max_devices,
&dev_attr_max_sg_list,
@@ -643,6 +770,8 @@ struct device_attribute *pm8001_host_attrs[] = {
&dev_attr_logging_level,
&dev_attr_host_sas_address,
&dev_attr_bios_version,
+ &dev_attr_ib_log,
+ &dev_attr_ob_log,
NULL,
};
diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h
index c6d8fdd..d0d43a2 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.h
+++ b/drivers/scsi/pm8001/pm8001_ctl.h
@@ -55,5 +55,9 @@
#define FAIL_OUT_MEMORY 0x000c00
#define FLASH_IN_PROGRESS 0x001000
+#define IB_OB_READ_TIMES 256
+#define SYSFS_OFFSET 1024
+#define PM80XX_IB_OB_QUEUE_SIZE (32 * 1024)
+#define PM8001_IB_OB_QUEUE_SIZE (16 * 1024)
#endif /* PM8001_CTL_H_INCLUDED */
diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h
index 4bb304d..74a4bb9 100644
--- a/drivers/scsi/pm8001/pm8001_defs.h
+++ b/drivers/scsi/pm8001/pm8001_defs.h
@@ -102,7 +102,8 @@ enum memory_region_num {
NVMD, /* NVM device */
DEV_MEM, /* memory for devices */
CCB_MEM, /* memory for command control block */
- FW_FLASH /* memory for fw flash update */
+ FW_FLASH, /* memory for fw flash update */
+ FORENSIC_MEM /* memory for fw forensic data */
};
#define PM8001_EVENT_LOG_SIZE (128 * 1024)
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 502c7d6..75a8b46 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -5015,6 +5015,89 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
return rc;
}
+ssize_t
+pm8001_get_gsm_dump(struct device *cdev, u32 length, char* buf)
+{
+ u32 value, rem, offset = 0, bar = 0;
+ u32 index, work_offset, dw_length;
+ u32 shift_value, gsm_base, gsm_dump_offset;
+ char *direct_data;
+ 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;
+
+ direct_data = buf;
+ gsm_dump_offset = pm8001_ha->fatal_forensic_shift_offset;
+
+ /* check max is 1 Mbytes */
+ if ((length > 0x100000) || (gsm_dump_offset & 3) ||
+ ((gsm_dump_offset + length) > 0x1000000))
+ return 1;
+
+ if (pm8001_ha->chip_id == chip_8001)
+ bar = 2;
+ else
+ bar = 1;
+
+ work_offset = gsm_dump_offset & 0xFFFF0000;
+ offset = gsm_dump_offset & 0x0000FFFF;
+ gsm_dump_offset = work_offset;
+ /* adjust length to dword boundary */
+ rem = length & 3;
+ dw_length = length >> 2;
+
+ for (index = 0; index < dw_length; index++) {
+ if ((work_offset + offset) & 0xFFFF0000) {
+ if (pm8001_ha->chip_id == chip_8001)
+ shift_value = ((gsm_dump_offset + offset) &
+ SHIFT_REG_64K_MASK);
+ else
+ shift_value = (((gsm_dump_offset + offset) &
+ SHIFT_REG_64K_MASK) >>
+ SHIFT_REG_BIT_SHIFT);
+
+ if (pm8001_ha->chip_id == chip_8001) {
+ gsm_base = GSM_BASE;
+ if (-1 == pm8001_bar4_shift(pm8001_ha,
+ (gsm_base + shift_value)))
+ return 1;
+ } else {
+ gsm_base = 0;
+ if (-1 == pm80xx_bar4_shift(pm8001_ha,
+ (gsm_base + shift_value)))
+ return 1;
+ }
+ gsm_dump_offset = (gsm_dump_offset + offset) &
+ 0xFFFF0000;
+ work_offset = 0;
+ offset = offset & 0x0000FFFF;
+ }
+ value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
+ 0x0000FFFF);
+ direct_data += sprintf(direct_data, "%08x ", value);
+ offset += 4;
+ }
+ if (rem != 0) {
+ value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
+ 0x0000FFFF);
+ /* xfr for non_dw */
+ direct_data += sprintf(direct_data, "%08x ", value);
+ }
+ /* Shift back to BAR4 original address */
+ if (pm8001_ha->chip_id == chip_8001) {
+ if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
+ return 1;
+ } else {
+ if (-1 == pm80xx_bar4_shift(pm8001_ha, 0))
+ return 1;
+ }
+ pm8001_ha->fatal_forensic_shift_offset += 1024;
+
+ if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000)
+ pm8001_ha->fatal_forensic_shift_offset = 0;
+ return direct_data - buf;
+}
+
int
pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,
struct pm8001_device *pm8001_dev, u32 state)
diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
index d7c1e20..6d91e24 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.h
+++ b/drivers/scsi/pm8001/pm8001_hwi.h
@@ -1027,5 +1027,8 @@ struct set_dev_state_resp {
#define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
#define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
+#define GSM_BASE 0x4F0000
+#define SHIFT_REG_64K_MASK 0xffff0000
+#define SHIFT_REG_BIT_SHIFT 8
#endif
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index b31d25a..49cfe45 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,
/* Memory region for fw flash */
pm8001_ha->memoryMap.region[FW_FLASH].total_len = 4096;
+ pm8001_ha->memoryMap.region[FORENSIC_MEM].num_elements = 1;
+ pm8001_ha->memoryMap.region[FORENSIC_MEM].total_len = 0x10000;
+ pm8001_ha->memoryMap.region[FORENSIC_MEM].element_size = 0x10000;
+ pm8001_ha->memoryMap.region[FORENSIC_MEM].alignment = 0x10000;
for (i = 0; i < USI_MAX_MEMCNT; i++) {
if (pm8001_mem_alloc(pm8001_ha->pdev,
&pm8001_ha->memoryMap.region[i].virt_ptr,
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index cbde11a..9241c04 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -132,6 +132,61 @@ struct pm8001_ioctl_payload {
u8 *func_specific;
};
+#define MPI_FATAL_ERROR_TABLE_OFFSET_MASK 0xFFFFFF
+#define MPI_FATAL_ERROR_TABLE_SIZE(value) ((0xFF000000 & value) >> SHIFT24)
+#define MPI_FATAL_EDUMP_TABLE_LO_OFFSET 0x00 /* HNFBUFL */
+#define MPI_FATAL_EDUMP_TABLE_HI_OFFSET 0x04 /* HNFBUFH */
+#define MPI_FATAL_EDUMP_TABLE_LENGTH 0x08 /* HNFBLEN */
+#define MPI_FATAL_EDUMP_TABLE_HANDSHAKE 0x0C /* FDDHSHK */
+#define MPI_FATAL_EDUMP_TABLE_STATUS 0x10 /* FDDTSTAT */
+#define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN 0x14 /* ACCDDLEN */
+#define MPI_FATAL_EDUMP_HANDSHAKE_RDY 0x1
+#define MPI_FATAL_EDUMP_HANDSHAKE_BUSY 0x0
+#define MPI_FATAL_EDUMP_TABLE_STAT_RSVD 0x0
+#define MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED 0x1
+#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA 0x2
+#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE 0x3
+#define TYPE_GSM_SPACE 1
+#define TYPE_QUEUE 2
+#define TYPE_FATAL 3
+#define TYPE_NON_FATAL 4
+#define TYPE_INBOUND 1
+#define TYPE_OUTBOUND 2
+struct forensic_data {
+ u32 data_type;
+ union {
+ struct {
+ u32 direct_len;
+ u32 direct_offset;
+ void *direct_data;
+ } gsm_buf;
+ struct {
+ u16 queue_type;
+ u16 queue_index;
+ u32 direct_len;
+ void *direct_data;
+ } queue_buf;
+ struct {
+ u32 direct_len;
+ u32 direct_offset;
+ u32 read_len;
+ void *direct_data;
+ } data_buf;
+ };
+};
+
+/* bit31-26 - mask bar */
+#define SCRATCH_PAD0_BAR_MASK 0xFC000000
+/* bit25-0 - offset mask */
+#define SCRATCH_PAD0_OFFSET_MASK 0x03FFFFFF
+/* if AAP error state */
+#define SCRATCH_PAD0_AAPERR_MASK 0xFFFFFFFF
+/* Inbound doorbell bit7 */
+#define SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP 0x80
+/* Inbound doorbell bit7 SPCV */
+#define SPCV_MSGU_CFG_TABLE_TRANSFER_DEBUG_INFO 0x80
+#define MAIN_MERRDCTO_MERRDCES 0xA0/* DWORD 0x28) */
+
struct pm8001_dispatch {
char *name;
int (*chip_init)(struct pm8001_hba_info *pm8001_ha);
@@ -346,6 +401,7 @@ union main_cfg_table {
u32 phy_attr_table_offset;
u32 port_recovery_timer;
u32 interrupt_reassertion_delay;
+ u32 fatal_n_non_fatal_dump; /* 0x28 */
} pm80xx_tbl;
};
@@ -420,6 +476,13 @@ struct pm8001_hba_info {
struct pm8001_hba_memspace io_mem[6];
struct mpi_mem_req memoryMap;
struct encrypt encrypt_info; /* support encryption */
+ struct forensic_data forensic_info;
+ u32 fatal_bar_loc;
+ u32 forensic_last_offset;
+ u32 fatal_forensic_shift_offset;
+ u32 forensic_fatal_step;
+ u32 evtlog_ib_offset;
+ u32 evtlog_ob_offset;
void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/
void __iomem *main_cfg_tbl_addr;/*Main Config Table Addr*/
void __iomem *general_stat_tbl_addr;/*General Status Table Addr*/
@@ -428,6 +491,7 @@ struct pm8001_hba_info {
void __iomem *pspa_q_tbl_addr;
/*MPI SAS PHY attributes Queue Config Table Addr*/
void __iomem *ivt_tbl_addr; /*MPI IVT Table Addr */
+ void __iomem *fatal_tbl_addr; /*MPI IVT Table Addr */
union main_cfg_table main_cfg_tbl;
union general_status_table gs_tbl;
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);
int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
u32 length, u8 *buf);
+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 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 94de2ed..7b87e96 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -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",
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h
index 872d5cf..c86816b 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.h
+++ b/drivers/scsi/pm8001/pm80xx_hwi.h
@@ -1525,4 +1525,6 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
#define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
#define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
+
+#define MEMBASE_II_SHIFT_REGISTER 0x1010
#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH V2 10/10] pm80xx: Firmware logging support
2013-09-26 5:43 [PATCH V2 10/10] pm80xx: Firmware logging support Anand
@ 2013-09-26 7:12 ` Jack Wang
2013-09-27 13:02 ` Tomas Henzl
1 sibling, 0 replies; 5+ messages in thread
From: Jack Wang @ 2013-09-26 7:12 UTC (permalink / raw)
To: Anand; +Cc: linux-scsi, Sangeetha.Gnanasekaran, Nikith.Ganigarakoppal,
Viswas.G
On 09/26/2013 07:43 AM, Anand wrote:
> From ab1b030500a835eacda3d86e5570366099b21311 Mon Sep 17 00:00:00 2001
> From: Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>
> Date: Wed, 4 Sep 2013 12:57:00 +0530
> Subject: [PATCH V2 10/10] 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.
>
> Signed-off-by: Anandkumar.Santhanam@pmcs.com
Reviewed-by: Jack Wang <jinpu.wang@profitbricks.com>
> ---
> drivers/scsi/pm8001/pm8001_ctl.c | 129 +++++++++++++++++++++
> drivers/scsi/pm8001/pm8001_ctl.h | 4 +
> drivers/scsi/pm8001/pm8001_defs.h | 3 +-
> drivers/scsi/pm8001/pm8001_hwi.c | 83 ++++++++++++++
> drivers/scsi/pm8001/pm8001_hwi.h | 3 +
> drivers/scsi/pm8001/pm8001_init.c | 4 +
> drivers/scsi/pm8001/pm8001_sas.h | 68 +++++++++++
> drivers/scsi/pm8001/pm80xx_hwi.c | 225 +++++++++++++++++++++++++++++++++++++
> drivers/scsi/pm8001/pm80xx_hwi.h | 2 +
> 9 files changed, 520 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
> index 5a19e19..2ca79a5 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.c
> +++ b/drivers/scsi/pm8001/pm8001_ctl.c
> @@ -309,6 +309,94 @@ static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,
> }
> static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);
> /**
> + * pm8001_ctl_ib_queue_log_show - Out bound Queue log
> + * @cdev:pointer to embedded class device
> + * @buf: the buffer returned
> + * A sysfs 'read-only' shost attribute.
> + */
> +static ssize_t pm8001_ctl_ib_queue_log_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;
> + int offset;
> + char *str = buf;
> + int start = 0;
> +#define IB_MEMMAP(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[IB].virt_ptr + \
> + pm8001_ha->evtlog_ib_offset + (c)))
> +
> +#define IB_MEMMAP_SPC(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[IB].virt_ptr + \
> + pm8001_ha->evtlog_ib_offset + (c)))
> +
> + for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
> + if (pm8001_ha->chip_id != chip_8001)
> + str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
> + else
> + str += sprintf(str, "0x%08x\n", IB_MEMMAP_SPC(start));
> + start = start + 4;
> + }
> + pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;
> + if ((((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id != chip_8001))
> + pm8001_ha->evtlog_ib_offset = 0;
> + if ((((pm8001_ha->evtlog_ib_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id == chip_8001))
> + pm8001_ha->evtlog_ib_offset = 0;
> +
> + return str - buf;
> +}
> +
> +static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL);
> +/**
> + * pm8001_ctl_ob_queue_log_show - Out bound Queue log
> + * @cdev:pointer to embedded class device
> + * @buf: the buffer returned
> + * A sysfs 'read-only' shost attribute.
> + */
> +
> +static ssize_t pm8001_ctl_ob_queue_log_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;
> + int offset;
> + char *str = buf;
> + int start = 0;
> +#define OB_MEMMAP(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[OB].virt_ptr + \
> + pm8001_ha->evtlog_ob_offset + (c)))
> +
> +#define OB_MEMMAP_SPC(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[OB].virt_ptr + \
> + pm8001_ha->evtlog_ob_offset + (c)))
> +
> + for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
> + if (pm8001_ha->chip_id != chip_8001)
> + str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
> + else
> + str += sprintf(str, "0x%08x\n", OB_MEMMAP_SPC(start));
> + start = start + 4;
> + }
> + pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;
> + if ((((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id != chip_8001))
> + pm8001_ha->evtlog_ob_offset = 0;
> + if ((((pm8001_ha->evtlog_ob_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id == chip_8001))
> + pm8001_ha->evtlog_ob_offset = 0;
> +
> + return str - buf;
> +}
> +static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL);
> +/**
> * pm8001_ctl_bios_version_show - Bios version Display
> * @cdev:pointer to embedded class device
> * @buf:the buffer returned
> @@ -377,6 +465,43 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
> }
> static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
>
> +/**
> + ** pm8001_ctl_fatal_log_show - fatal error logging
> + ** @cdev:pointer to embedded class device
> + ** @buf: the buffer returned
> + **
> + ** A sysfs 'read-only' shost attribute.
> + **/
> +
> +static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
> + struct device_attribute *attr, char *buf)
> +{
> + u32 count;
> +
> + count = pm80xx_get_fatal_dump(cdev, attr, buf);
> + return count;
> +}
> +
> +static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);
> +
> +
> +/**
> + ** pm8001_ctl_gsm_log_show - gsm dump collection
> + ** @cdev:pointer to embedded class device
> + ** @buf: the buffer returned
> + **A sysfs 'read-only' shost attribute.
> + **/
> +static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
> + struct device_attribute *attr, char *buf)
> +{
> + u32 count;
> +
> + count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);
> + return count;
> +}
> +
> +static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL);
> +
> #define FLASH_CMD_NONE 0x00
> #define FLASH_CMD_UPDATE 0x01
> #define FLASH_CMD_SET_NVMD 0x02
> @@ -636,6 +761,8 @@ struct device_attribute *pm8001_host_attrs[] = {
> &dev_attr_update_fw,
> &dev_attr_aap_log,
> &dev_attr_iop_log,
> + &dev_attr_fatal_log,
> + &dev_attr_gsm_log,
> &dev_attr_max_out_io,
> &dev_attr_max_devices,
> &dev_attr_max_sg_list,
> @@ -643,6 +770,8 @@ struct device_attribute *pm8001_host_attrs[] = {
> &dev_attr_logging_level,
> &dev_attr_host_sas_address,
> &dev_attr_bios_version,
> + &dev_attr_ib_log,
> + &dev_attr_ob_log,
> NULL,
> };
>
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h
> index c6d8fdd..d0d43a2 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.h
> +++ b/drivers/scsi/pm8001/pm8001_ctl.h
> @@ -55,5 +55,9 @@
> #define FAIL_OUT_MEMORY 0x000c00
> #define FLASH_IN_PROGRESS 0x001000
>
> +#define IB_OB_READ_TIMES 256
> +#define SYSFS_OFFSET 1024
> +#define PM80XX_IB_OB_QUEUE_SIZE (32 * 1024)
> +#define PM8001_IB_OB_QUEUE_SIZE (16 * 1024)
> #endif /* PM8001_CTL_H_INCLUDED */
>
> diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h
> index 4bb304d..74a4bb9 100644
> --- a/drivers/scsi/pm8001/pm8001_defs.h
> +++ b/drivers/scsi/pm8001/pm8001_defs.h
> @@ -102,7 +102,8 @@ enum memory_region_num {
> NVMD, /* NVM device */
> DEV_MEM, /* memory for devices */
> CCB_MEM, /* memory for command control block */
> - FW_FLASH /* memory for fw flash update */
> + FW_FLASH, /* memory for fw flash update */
> + FORENSIC_MEM /* memory for fw forensic data */
> };
> #define PM8001_EVENT_LOG_SIZE (128 * 1024)
>
> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
> index 502c7d6..75a8b46 100644
> --- a/drivers/scsi/pm8001/pm8001_hwi.c
> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
> @@ -5015,6 +5015,89 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
> return rc;
> }
>
> +ssize_t
> +pm8001_get_gsm_dump(struct device *cdev, u32 length, char* buf)
> +{
> + u32 value, rem, offset = 0, bar = 0;
> + u32 index, work_offset, dw_length;
> + u32 shift_value, gsm_base, gsm_dump_offset;
> + char *direct_data;
> + 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;
> +
> + direct_data = buf;
> + gsm_dump_offset = pm8001_ha->fatal_forensic_shift_offset;
> +
> + /* check max is 1 Mbytes */
> + if ((length > 0x100000) || (gsm_dump_offset & 3) ||
> + ((gsm_dump_offset + length) > 0x1000000))
> + return 1;
> +
> + if (pm8001_ha->chip_id == chip_8001)
> + bar = 2;
> + else
> + bar = 1;
> +
> + work_offset = gsm_dump_offset & 0xFFFF0000;
> + offset = gsm_dump_offset & 0x0000FFFF;
> + gsm_dump_offset = work_offset;
> + /* adjust length to dword boundary */
> + rem = length & 3;
> + dw_length = length >> 2;
> +
> + for (index = 0; index < dw_length; index++) {
> + if ((work_offset + offset) & 0xFFFF0000) {
> + if (pm8001_ha->chip_id == chip_8001)
> + shift_value = ((gsm_dump_offset + offset) &
> + SHIFT_REG_64K_MASK);
> + else
> + shift_value = (((gsm_dump_offset + offset) &
> + SHIFT_REG_64K_MASK) >>
> + SHIFT_REG_BIT_SHIFT);
> +
> + if (pm8001_ha->chip_id == chip_8001) {
> + gsm_base = GSM_BASE;
> + if (-1 == pm8001_bar4_shift(pm8001_ha,
> + (gsm_base + shift_value)))
> + return 1;
> + } else {
> + gsm_base = 0;
> + if (-1 == pm80xx_bar4_shift(pm8001_ha,
> + (gsm_base + shift_value)))
> + return 1;
> + }
> + gsm_dump_offset = (gsm_dump_offset + offset) &
> + 0xFFFF0000;
> + work_offset = 0;
> + offset = offset & 0x0000FFFF;
> + }
> + value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
> + 0x0000FFFF);
> + direct_data += sprintf(direct_data, "%08x ", value);
> + offset += 4;
> + }
> + if (rem != 0) {
> + value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
> + 0x0000FFFF);
> + /* xfr for non_dw */
> + direct_data += sprintf(direct_data, "%08x ", value);
> + }
> + /* Shift back to BAR4 original address */
> + if (pm8001_ha->chip_id == chip_8001) {
> + if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
> + return 1;
> + } else {
> + if (-1 == pm80xx_bar4_shift(pm8001_ha, 0))
> + return 1;
> + }
> + pm8001_ha->fatal_forensic_shift_offset += 1024;
> +
> + if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000)
> + pm8001_ha->fatal_forensic_shift_offset = 0;
> + return direct_data - buf;
> +}
> +
> int
> pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,
> struct pm8001_device *pm8001_dev, u32 state)
> diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
> index d7c1e20..6d91e24 100644
> --- a/drivers/scsi/pm8001/pm8001_hwi.h
> +++ b/drivers/scsi/pm8001/pm8001_hwi.h
> @@ -1027,5 +1027,8 @@ struct set_dev_state_resp {
> #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
> #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
>
> +#define GSM_BASE 0x4F0000
> +#define SHIFT_REG_64K_MASK 0xffff0000
> +#define SHIFT_REG_BIT_SHIFT 8
> #endif
>
> diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
> index b31d25a..49cfe45 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,
> /* Memory region for fw flash */
> pm8001_ha->memoryMap.region[FW_FLASH].total_len = 4096;
>
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].num_elements = 1;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].total_len = 0x10000;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].element_size = 0x10000;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].alignment = 0x10000;
> for (i = 0; i < USI_MAX_MEMCNT; i++) {
> if (pm8001_mem_alloc(pm8001_ha->pdev,
> &pm8001_ha->memoryMap.region[i].virt_ptr,
> diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
> index cbde11a..9241c04 100644
> --- a/drivers/scsi/pm8001/pm8001_sas.h
> +++ b/drivers/scsi/pm8001/pm8001_sas.h
> @@ -132,6 +132,61 @@ struct pm8001_ioctl_payload {
> u8 *func_specific;
> };
>
> +#define MPI_FATAL_ERROR_TABLE_OFFSET_MASK 0xFFFFFF
> +#define MPI_FATAL_ERROR_TABLE_SIZE(value) ((0xFF000000 & value) >> SHIFT24)
> +#define MPI_FATAL_EDUMP_TABLE_LO_OFFSET 0x00 /* HNFBUFL */
> +#define MPI_FATAL_EDUMP_TABLE_HI_OFFSET 0x04 /* HNFBUFH */
> +#define MPI_FATAL_EDUMP_TABLE_LENGTH 0x08 /* HNFBLEN */
> +#define MPI_FATAL_EDUMP_TABLE_HANDSHAKE 0x0C /* FDDHSHK */
> +#define MPI_FATAL_EDUMP_TABLE_STATUS 0x10 /* FDDTSTAT */
> +#define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN 0x14 /* ACCDDLEN */
> +#define MPI_FATAL_EDUMP_HANDSHAKE_RDY 0x1
> +#define MPI_FATAL_EDUMP_HANDSHAKE_BUSY 0x0
> +#define MPI_FATAL_EDUMP_TABLE_STAT_RSVD 0x0
> +#define MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED 0x1
> +#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA 0x2
> +#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE 0x3
> +#define TYPE_GSM_SPACE 1
> +#define TYPE_QUEUE 2
> +#define TYPE_FATAL 3
> +#define TYPE_NON_FATAL 4
> +#define TYPE_INBOUND 1
> +#define TYPE_OUTBOUND 2
> +struct forensic_data {
> + u32 data_type;
> + union {
> + struct {
> + u32 direct_len;
> + u32 direct_offset;
> + void *direct_data;
> + } gsm_buf;
> + struct {
> + u16 queue_type;
> + u16 queue_index;
> + u32 direct_len;
> + void *direct_data;
> + } queue_buf;
> + struct {
> + u32 direct_len;
> + u32 direct_offset;
> + u32 read_len;
> + void *direct_data;
> + } data_buf;
> + };
> +};
> +
> +/* bit31-26 - mask bar */
> +#define SCRATCH_PAD0_BAR_MASK 0xFC000000
> +/* bit25-0 - offset mask */
> +#define SCRATCH_PAD0_OFFSET_MASK 0x03FFFFFF
> +/* if AAP error state */
> +#define SCRATCH_PAD0_AAPERR_MASK 0xFFFFFFFF
> +/* Inbound doorbell bit7 */
> +#define SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP 0x80
> +/* Inbound doorbell bit7 SPCV */
> +#define SPCV_MSGU_CFG_TABLE_TRANSFER_DEBUG_INFO 0x80
> +#define MAIN_MERRDCTO_MERRDCES 0xA0/* DWORD 0x28) */
> +
> struct pm8001_dispatch {
> char *name;
> int (*chip_init)(struct pm8001_hba_info *pm8001_ha);
> @@ -346,6 +401,7 @@ union main_cfg_table {
> u32 phy_attr_table_offset;
> u32 port_recovery_timer;
> u32 interrupt_reassertion_delay;
> + u32 fatal_n_non_fatal_dump; /* 0x28 */
> } pm80xx_tbl;
> };
>
> @@ -420,6 +476,13 @@ struct pm8001_hba_info {
> struct pm8001_hba_memspace io_mem[6];
> struct mpi_mem_req memoryMap;
> struct encrypt encrypt_info; /* support encryption */
> + struct forensic_data forensic_info;
> + u32 fatal_bar_loc;
> + u32 forensic_last_offset;
> + u32 fatal_forensic_shift_offset;
> + u32 forensic_fatal_step;
> + u32 evtlog_ib_offset;
> + u32 evtlog_ob_offset;
> void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/
> void __iomem *main_cfg_tbl_addr;/*Main Config Table Addr*/
> void __iomem *general_stat_tbl_addr;/*General Status Table Addr*/
> @@ -428,6 +491,7 @@ struct pm8001_hba_info {
> void __iomem *pspa_q_tbl_addr;
> /*MPI SAS PHY attributes Queue Config Table Addr*/
> void __iomem *ivt_tbl_addr; /*MPI IVT Table Addr */
> + void __iomem *fatal_tbl_addr; /*MPI IVT Table Addr */
> union main_cfg_table main_cfg_tbl;
> union general_status_table gs_tbl;
> 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);
> int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
> void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
> u32 length, u8 *buf);
> +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 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 94de2ed..7b87e96 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
> @@ -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",
> diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h
> index 872d5cf..c86816b 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.h
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.h
> @@ -1525,4 +1525,6 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
> #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
> #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
>
> +
> +#define MEMBASE_II_SHIFT_REGISTER 0x1010
> #endif
>
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH V2 10/10] pm80xx: Firmware logging support
2013-09-26 5:43 [PATCH V2 10/10] pm80xx: Firmware logging support Anand
2013-09-26 7:12 ` Jack Wang
@ 2013-09-27 13:02 ` Tomas Henzl
2013-09-30 6:38 ` Sangeetha Gnanasekaran
2013-10-01 11:11 ` Anand Kumar Santhanam
1 sibling, 2 replies; 5+ messages in thread
From: Tomas Henzl @ 2013-09-27 13:02 UTC (permalink / raw)
To: Anand
Cc: linux-scsi, Sangeetha.Gnanasekaran, Nikith.Ganigarakoppal,
Viswas.G, xjtuwjp
On 09/26/2013 07:43 AM, Anand wrote:
> From ab1b030500a835eacda3d86e5570366099b21311 Mon Sep 17 00:00:00 2001
> From: Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>
> Date: Wed, 4 Sep 2013 12:57:00 +0530
> Subject: [PATCH V2 10/10] 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.
>
> Signed-off-by: Anandkumar.Santhanam@pmcs.com
>
> ---
> drivers/scsi/pm8001/pm8001_ctl.c | 129 +++++++++++++++++++++
> drivers/scsi/pm8001/pm8001_ctl.h | 4 +
> drivers/scsi/pm8001/pm8001_defs.h | 3 +-
> drivers/scsi/pm8001/pm8001_hwi.c | 83 ++++++++++++++
> drivers/scsi/pm8001/pm8001_hwi.h | 3 +
> drivers/scsi/pm8001/pm8001_init.c | 4 +
> drivers/scsi/pm8001/pm8001_sas.h | 68 +++++++++++
> drivers/scsi/pm8001/pm80xx_hwi.c | 225 +++++++++++++++++++++++++++++++++++++
> drivers/scsi/pm8001/pm80xx_hwi.h | 2 +
> 9 files changed, 520 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
> index 5a19e19..2ca79a5 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.c
> +++ b/drivers/scsi/pm8001/pm8001_ctl.c
> @@ -309,6 +309,94 @@ static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,
> }
> static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);
> /**
> + * pm8001_ctl_ib_queue_log_show - Out bound Queue log
> + * @cdev:pointer to embedded class device
> + * @buf: the buffer returned
> + * A sysfs 'read-only' shost attribute.
> + */
> +static ssize_t pm8001_ctl_ib_queue_log_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;
> + int offset;
> + char *str = buf;
> + int start = 0;
> +#define IB_MEMMAP(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[IB].virt_ptr + \
> + pm8001_ha->evtlog_ib_offset + (c)))
> +
> +#define IB_MEMMAP_SPC(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[IB].virt_ptr + \
> + pm8001_ha->evtlog_ib_offset + (c)))
The IB_MEMMAP and IB_MEMMAP_SPC seems to be exactly the same - is that intentional?
and btw. why do you use macros, when they are used just once?
(In the function below there is a similar pattern - again two identical macros)
Cheers, Tomas
> +
> + for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
> + if (pm8001_ha->chip_id != chip_8001)
> + str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
> + else
> + str += sprintf(str, "0x%08x\n", IB_MEMMAP_SPC(start));
> + start = start + 4;
> + }
> + pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;
> + if ((((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id != chip_8001))
> + pm8001_ha->evtlog_ib_offset = 0;
> + if ((((pm8001_ha->evtlog_ib_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id == chip_8001))
> + pm8001_ha->evtlog_ib_offset = 0;
> +
> + return str - buf;
> +}
> +
> +static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL);
> +/**
> + * pm8001_ctl_ob_queue_log_show - Out bound Queue log
> + * @cdev:pointer to embedded class device
> + * @buf: the buffer returned
> + * A sysfs 'read-only' shost attribute.
> + */
> +
> +static ssize_t pm8001_ctl_ob_queue_log_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;
> + int offset;
> + char *str = buf;
> + int start = 0;
> +#define OB_MEMMAP(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[OB].virt_ptr + \
> + pm8001_ha->evtlog_ob_offset + (c)))
> +
> +#define OB_MEMMAP_SPC(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[OB].virt_ptr + \
> + pm8001_ha->evtlog_ob_offset + (c)))
> +
> + for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
> + if (pm8001_ha->chip_id != chip_8001)
> + str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
> + else
> + str += sprintf(str, "0x%08x\n", OB_MEMMAP_SPC(start));
> + start = start + 4;
> + }
> + pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;
> + if ((((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id != chip_8001))
> + pm8001_ha->evtlog_ob_offset = 0;
> + if ((((pm8001_ha->evtlog_ob_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id == chip_8001))
> + pm8001_ha->evtlog_ob_offset = 0;
> +
> + return str - buf;
> +}
> +static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL);
> +/**
> * pm8001_ctl_bios_version_show - Bios version Display
> * @cdev:pointer to embedded class device
> * @buf:the buffer returned
> @@ -377,6 +465,43 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
> }
> static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
>
> +/**
> + ** pm8001_ctl_fatal_log_show - fatal error logging
> + ** @cdev:pointer to embedded class device
> + ** @buf: the buffer returned
> + **
> + ** A sysfs 'read-only' shost attribute.
> + **/
> +
> +static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
> + struct device_attribute *attr, char *buf)
> +{
> + u32 count;
> +
> + count = pm80xx_get_fatal_dump(cdev, attr, buf);
> + return count;
> +}
> +
> +static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);
> +
> +
> +/**
> + ** pm8001_ctl_gsm_log_show - gsm dump collection
> + ** @cdev:pointer to embedded class device
> + ** @buf: the buffer returned
> + **A sysfs 'read-only' shost attribute.
> + **/
> +static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
> + struct device_attribute *attr, char *buf)
> +{
> + u32 count;
> +
> + count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);
> + return count;
> +}
> +
> +static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL);
> +
> #define FLASH_CMD_NONE 0x00
> #define FLASH_CMD_UPDATE 0x01
> #define FLASH_CMD_SET_NVMD 0x02
> @@ -636,6 +761,8 @@ struct device_attribute *pm8001_host_attrs[] = {
> &dev_attr_update_fw,
> &dev_attr_aap_log,
> &dev_attr_iop_log,
> + &dev_attr_fatal_log,
> + &dev_attr_gsm_log,
> &dev_attr_max_out_io,
> &dev_attr_max_devices,
> &dev_attr_max_sg_list,
> @@ -643,6 +770,8 @@ struct device_attribute *pm8001_host_attrs[] = {
> &dev_attr_logging_level,
> &dev_attr_host_sas_address,
> &dev_attr_bios_version,
> + &dev_attr_ib_log,
> + &dev_attr_ob_log,
> NULL,
> };
>
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.h b/drivers/scsi/pm8001/pm8001_ctl.h
> index c6d8fdd..d0d43a2 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.h
> +++ b/drivers/scsi/pm8001/pm8001_ctl.h
> @@ -55,5 +55,9 @@
> #define FAIL_OUT_MEMORY 0x000c00
> #define FLASH_IN_PROGRESS 0x001000
>
> +#define IB_OB_READ_TIMES 256
> +#define SYSFS_OFFSET 1024
> +#define PM80XX_IB_OB_QUEUE_SIZE (32 * 1024)
> +#define PM8001_IB_OB_QUEUE_SIZE (16 * 1024)
> #endif /* PM8001_CTL_H_INCLUDED */
>
> diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h
> index 4bb304d..74a4bb9 100644
> --- a/drivers/scsi/pm8001/pm8001_defs.h
> +++ b/drivers/scsi/pm8001/pm8001_defs.h
> @@ -102,7 +102,8 @@ enum memory_region_num {
> NVMD, /* NVM device */
> DEV_MEM, /* memory for devices */
> CCB_MEM, /* memory for command control block */
> - FW_FLASH /* memory for fw flash update */
> + FW_FLASH, /* memory for fw flash update */
> + FORENSIC_MEM /* memory for fw forensic data */
> };
> #define PM8001_EVENT_LOG_SIZE (128 * 1024)
>
> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
> index 502c7d6..75a8b46 100644
> --- a/drivers/scsi/pm8001/pm8001_hwi.c
> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
> @@ -5015,6 +5015,89 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
> return rc;
> }
>
> +ssize_t
> +pm8001_get_gsm_dump(struct device *cdev, u32 length, char* buf)
> +{
> + u32 value, rem, offset = 0, bar = 0;
> + u32 index, work_offset, dw_length;
> + u32 shift_value, gsm_base, gsm_dump_offset;
> + char *direct_data;
> + 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;
> +
> + direct_data = buf;
> + gsm_dump_offset = pm8001_ha->fatal_forensic_shift_offset;
> +
> + /* check max is 1 Mbytes */
> + if ((length > 0x100000) || (gsm_dump_offset & 3) ||
> + ((gsm_dump_offset + length) > 0x1000000))
> + return 1;
> +
> + if (pm8001_ha->chip_id == chip_8001)
> + bar = 2;
> + else
> + bar = 1;
> +
> + work_offset = gsm_dump_offset & 0xFFFF0000;
> + offset = gsm_dump_offset & 0x0000FFFF;
> + gsm_dump_offset = work_offset;
> + /* adjust length to dword boundary */
> + rem = length & 3;
> + dw_length = length >> 2;
> +
> + for (index = 0; index < dw_length; index++) {
> + if ((work_offset + offset) & 0xFFFF0000) {
> + if (pm8001_ha->chip_id == chip_8001)
> + shift_value = ((gsm_dump_offset + offset) &
> + SHIFT_REG_64K_MASK);
> + else
> + shift_value = (((gsm_dump_offset + offset) &
> + SHIFT_REG_64K_MASK) >>
> + SHIFT_REG_BIT_SHIFT);
> +
> + if (pm8001_ha->chip_id == chip_8001) {
> + gsm_base = GSM_BASE;
> + if (-1 == pm8001_bar4_shift(pm8001_ha,
> + (gsm_base + shift_value)))
> + return 1;
> + } else {
> + gsm_base = 0;
> + if (-1 == pm80xx_bar4_shift(pm8001_ha,
> + (gsm_base + shift_value)))
> + return 1;
> + }
> + gsm_dump_offset = (gsm_dump_offset + offset) &
> + 0xFFFF0000;
> + work_offset = 0;
> + offset = offset & 0x0000FFFF;
> + }
> + value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
> + 0x0000FFFF);
> + direct_data += sprintf(direct_data, "%08x ", value);
> + offset += 4;
> + }
> + if (rem != 0) {
> + value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
> + 0x0000FFFF);
> + /* xfr for non_dw */
> + direct_data += sprintf(direct_data, "%08x ", value);
> + }
> + /* Shift back to BAR4 original address */
> + if (pm8001_ha->chip_id == chip_8001) {
> + if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
> + return 1;
> + } else {
> + if (-1 == pm80xx_bar4_shift(pm8001_ha, 0))
> + return 1;
> + }
> + pm8001_ha->fatal_forensic_shift_offset += 1024;
> +
> + if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000)
> + pm8001_ha->fatal_forensic_shift_offset = 0;
> + return direct_data - buf;
> +}
> +
> int
> pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,
> struct pm8001_device *pm8001_dev, u32 state)
> diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
> index d7c1e20..6d91e24 100644
> --- a/drivers/scsi/pm8001/pm8001_hwi.h
> +++ b/drivers/scsi/pm8001/pm8001_hwi.h
> @@ -1027,5 +1027,8 @@ struct set_dev_state_resp {
> #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
> #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
>
> +#define GSM_BASE 0x4F0000
> +#define SHIFT_REG_64K_MASK 0xffff0000
> +#define SHIFT_REG_BIT_SHIFT 8
> #endif
>
> diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
> index b31d25a..49cfe45 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,
> /* Memory region for fw flash */
> pm8001_ha->memoryMap.region[FW_FLASH].total_len = 4096;
>
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].num_elements = 1;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].total_len = 0x10000;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].element_size = 0x10000;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].alignment = 0x10000;
> for (i = 0; i < USI_MAX_MEMCNT; i++) {
> if (pm8001_mem_alloc(pm8001_ha->pdev,
> &pm8001_ha->memoryMap.region[i].virt_ptr,
> diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
> index cbde11a..9241c04 100644
> --- a/drivers/scsi/pm8001/pm8001_sas.h
> +++ b/drivers/scsi/pm8001/pm8001_sas.h
> @@ -132,6 +132,61 @@ struct pm8001_ioctl_payload {
> u8 *func_specific;
> };
>
> +#define MPI_FATAL_ERROR_TABLE_OFFSET_MASK 0xFFFFFF
> +#define MPI_FATAL_ERROR_TABLE_SIZE(value) ((0xFF000000 & value) >> SHIFT24)
> +#define MPI_FATAL_EDUMP_TABLE_LO_OFFSET 0x00 /* HNFBUFL */
> +#define MPI_FATAL_EDUMP_TABLE_HI_OFFSET 0x04 /* HNFBUFH */
> +#define MPI_FATAL_EDUMP_TABLE_LENGTH 0x08 /* HNFBLEN */
> +#define MPI_FATAL_EDUMP_TABLE_HANDSHAKE 0x0C /* FDDHSHK */
> +#define MPI_FATAL_EDUMP_TABLE_STATUS 0x10 /* FDDTSTAT */
> +#define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN 0x14 /* ACCDDLEN */
> +#define MPI_FATAL_EDUMP_HANDSHAKE_RDY 0x1
> +#define MPI_FATAL_EDUMP_HANDSHAKE_BUSY 0x0
> +#define MPI_FATAL_EDUMP_TABLE_STAT_RSVD 0x0
> +#define MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED 0x1
> +#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA 0x2
> +#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE 0x3
> +#define TYPE_GSM_SPACE 1
> +#define TYPE_QUEUE 2
> +#define TYPE_FATAL 3
> +#define TYPE_NON_FATAL 4
> +#define TYPE_INBOUND 1
> +#define TYPE_OUTBOUND 2
> +struct forensic_data {
> + u32 data_type;
> + union {
> + struct {
> + u32 direct_len;
> + u32 direct_offset;
> + void *direct_data;
> + } gsm_buf;
> + struct {
> + u16 queue_type;
> + u16 queue_index;
> + u32 direct_len;
> + void *direct_data;
> + } queue_buf;
> + struct {
> + u32 direct_len;
> + u32 direct_offset;
> + u32 read_len;
> + void *direct_data;
> + } data_buf;
> + };
> +};
> +
> +/* bit31-26 - mask bar */
> +#define SCRATCH_PAD0_BAR_MASK 0xFC000000
> +/* bit25-0 - offset mask */
> +#define SCRATCH_PAD0_OFFSET_MASK 0x03FFFFFF
> +/* if AAP error state */
> +#define SCRATCH_PAD0_AAPERR_MASK 0xFFFFFFFF
> +/* Inbound doorbell bit7 */
> +#define SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP 0x80
> +/* Inbound doorbell bit7 SPCV */
> +#define SPCV_MSGU_CFG_TABLE_TRANSFER_DEBUG_INFO 0x80
> +#define MAIN_MERRDCTO_MERRDCES 0xA0/* DWORD 0x28) */
> +
> struct pm8001_dispatch {
> char *name;
> int (*chip_init)(struct pm8001_hba_info *pm8001_ha);
> @@ -346,6 +401,7 @@ union main_cfg_table {
> u32 phy_attr_table_offset;
> u32 port_recovery_timer;
> u32 interrupt_reassertion_delay;
> + u32 fatal_n_non_fatal_dump; /* 0x28 */
> } pm80xx_tbl;
> };
>
> @@ -420,6 +476,13 @@ struct pm8001_hba_info {
> struct pm8001_hba_memspace io_mem[6];
> struct mpi_mem_req memoryMap;
> struct encrypt encrypt_info; /* support encryption */
> + struct forensic_data forensic_info;
> + u32 fatal_bar_loc;
> + u32 forensic_last_offset;
> + u32 fatal_forensic_shift_offset;
> + u32 forensic_fatal_step;
> + u32 evtlog_ib_offset;
> + u32 evtlog_ob_offset;
> void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/
> void __iomem *main_cfg_tbl_addr;/*Main Config Table Addr*/
> void __iomem *general_stat_tbl_addr;/*General Status Table Addr*/
> @@ -428,6 +491,7 @@ struct pm8001_hba_info {
> void __iomem *pspa_q_tbl_addr;
> /*MPI SAS PHY attributes Queue Config Table Addr*/
> void __iomem *ivt_tbl_addr; /*MPI IVT Table Addr */
> + void __iomem *fatal_tbl_addr; /*MPI IVT Table Addr */
> union main_cfg_table main_cfg_tbl;
> union general_status_table gs_tbl;
> 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);
> int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
> void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
> u32 length, u8 *buf);
> +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 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 94de2ed..7b87e96 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
> @@ -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",
> diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h
> index 872d5cf..c86816b 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.h
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.h
> @@ -1525,4 +1525,6 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
> #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
> #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
>
> +
> +#define MEMBASE_II_SHIFT_REGISTER 0x1010
> #endif
^ permalink raw reply [flat|nested] 5+ messages in thread* RE: [PATCH V2 10/10] pm80xx: Firmware logging support
2013-09-27 13:02 ` Tomas Henzl
@ 2013-09-30 6:38 ` Sangeetha Gnanasekaran
2013-10-01 11:11 ` Anand Kumar Santhanam
1 sibling, 0 replies; 5+ messages in thread
From: Sangeetha Gnanasekaran @ 2013-09-30 6:38 UTC (permalink / raw)
To: Tomas Henzl
Cc: linux-scsi, Nikith Ganigarakoppal, Viswas G, xjtuwjp,
Anand Kumar Santhanam
Hi Tomas,
We will remove duplicate macro and resubmit updated patch.
Thanks,
Sangeetha
-----Original Message-----
From: Tomas Henzl [mailto:thenzl@redhat.com]
Sent: Friday, September 27, 2013 6:32 PM
To: Anand Kumar Santhanam
Cc: linux-scsi@vger.kernel.org; Sangeetha Gnanasekaran; Nikith
Ganigarakoppal; Viswas G; xjtuwjp@gmail.com
Subject: Re: [PATCH V2 10/10] pm80xx: Firmware logging support
On 09/26/2013 07:43 AM, Anand wrote:
> From ab1b030500a835eacda3d86e5570366099b21311 Mon Sep 17 00:00:00 2001
> From: Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>
> Date: Wed, 4 Sep 2013 12:57:00 +0530
> Subject: [PATCH V2 10/10] 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.
>
> Signed-off-by: Anandkumar.Santhanam@pmcs.com
>
> ---
> drivers/scsi/pm8001/pm8001_ctl.c | 129 +++++++++++++++++++++
> drivers/scsi/pm8001/pm8001_ctl.h | 4 +
> drivers/scsi/pm8001/pm8001_defs.h | 3 +-
> drivers/scsi/pm8001/pm8001_hwi.c | 83 ++++++++++++++
> drivers/scsi/pm8001/pm8001_hwi.h | 3 +
> drivers/scsi/pm8001/pm8001_init.c | 4 +
> drivers/scsi/pm8001/pm8001_sas.h | 68 +++++++++++
> drivers/scsi/pm8001/pm80xx_hwi.c | 225
+++++++++++++++++++++++++++++++++++++
> drivers/scsi/pm8001/pm80xx_hwi.h | 2 +
> 9 files changed, 520 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.c
> b/drivers/scsi/pm8001/pm8001_ctl.c
> index 5a19e19..2ca79a5 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.c
> +++ b/drivers/scsi/pm8001/pm8001_ctl.c
> @@ -309,6 +309,94 @@ static ssize_t pm8001_ctl_aap_log_show(struct
> device *cdev, } static DEVICE_ATTR(aap_log, S_IRUGO,
> pm8001_ctl_aap_log_show, NULL);
> /**
> + * pm8001_ctl_ib_queue_log_show - Out bound Queue log
> + * @cdev:pointer to embedded class device
> + * @buf: the buffer returned
> + * A sysfs 'read-only' shost attribute.
> + */
> +static ssize_t pm8001_ctl_ib_queue_log_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;
> + int offset;
> + char *str = buf;
> + int start = 0;
> +#define IB_MEMMAP(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[IB].virt_ptr + \
> + pm8001_ha->evtlog_ib_offset + (c)))
> +
> +#define IB_MEMMAP_SPC(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[IB].virt_ptr + \
> + pm8001_ha->evtlog_ib_offset + (c)))
The IB_MEMMAP and IB_MEMMAP_SPC seems to be exactly the same - is that
intentional?
and btw. why do you use macros, when they are used just once?
(In the function below there is a similar pattern - again two identical
macros) Cheers, Tomas
> +
> + for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
> + if (pm8001_ha->chip_id != chip_8001)
> + str += sprintf(str, "0x%08x\n",
IB_MEMMAP(start));
> + else
> + str += sprintf(str, "0x%08x\n",
IB_MEMMAP_SPC(start));
> + start = start + 4;
> + }
> + pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;
> + if ((((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE))
== 0)
> + && (pm8001_ha->chip_id != chip_8001))
> + pm8001_ha->evtlog_ib_offset = 0;
> + if ((((pm8001_ha->evtlog_ib_offset) % (PM8001_IB_OB_QUEUE_SIZE))
== 0)
> + && (pm8001_ha->chip_id == chip_8001))
> + pm8001_ha->evtlog_ib_offset = 0;
> +
> + return str - buf;
> +}
> +
> +static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show,
> +NULL);
> +/**
> + * pm8001_ctl_ob_queue_log_show - Out bound Queue log
> + * @cdev:pointer to embedded class device
> + * @buf: the buffer returned
> + * A sysfs 'read-only' shost attribute.
> + */
> +
> +static ssize_t pm8001_ctl_ob_queue_log_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;
> + int offset;
> + char *str = buf;
> + int start = 0;
> +#define OB_MEMMAP(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[OB].virt_ptr + \
> + pm8001_ha->evtlog_ob_offset + (c)))
> +
> +#define OB_MEMMAP_SPC(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[OB].virt_ptr + \
> + pm8001_ha->evtlog_ob_offset + (c)))
> +
> + for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
> + if (pm8001_ha->chip_id != chip_8001)
> + str += sprintf(str, "0x%08x\n",
OB_MEMMAP(start));
> + else
> + str += sprintf(str, "0x%08x\n",
OB_MEMMAP_SPC(start));
> + start = start + 4;
> + }
> + pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;
> + if ((((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE))
== 0)
> + && (pm8001_ha->chip_id != chip_8001))
> + pm8001_ha->evtlog_ob_offset = 0;
> + if ((((pm8001_ha->evtlog_ob_offset) % (PM8001_IB_OB_QUEUE_SIZE))
== 0)
> + && (pm8001_ha->chip_id == chip_8001))
> + pm8001_ha->evtlog_ob_offset = 0;
> +
> + return str - buf;
> +}
> +static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show,
> +NULL);
> +/**
> * pm8001_ctl_bios_version_show - Bios version Display
> * @cdev:pointer to embedded class device
> * @buf:the buffer returned
> @@ -377,6 +465,43 @@ static ssize_t pm8001_ctl_iop_log_show(struct
> device *cdev, } static DEVICE_ATTR(iop_log, S_IRUGO,
> pm8001_ctl_iop_log_show, NULL);
>
> +/**
> + ** pm8001_ctl_fatal_log_show - fatal error logging
> + ** @cdev:pointer to embedded class device
> + ** @buf: the buffer returned
> + **
> + ** A sysfs 'read-only' shost attribute.
> + **/
> +
> +static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
> + struct device_attribute *attr, char *buf) {
> + u32 count;
> +
> + count = pm80xx_get_fatal_dump(cdev, attr, buf);
> + return count;
> +}
> +
> +static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show,
> +NULL);
> +
> +
> +/**
> + ** pm8001_ctl_gsm_log_show - gsm dump collection
> + ** @cdev:pointer to embedded class device
> + ** @buf: the buffer returned
> + **A sysfs 'read-only' shost attribute.
> + **/
> +static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
> + struct device_attribute *attr, char *buf) {
> + u32 count;
> +
> + count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);
> + return count;
> +}
> +
> +static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL);
> +
> #define FLASH_CMD_NONE 0x00
> #define FLASH_CMD_UPDATE 0x01
> #define FLASH_CMD_SET_NVMD 0x02
> @@ -636,6 +761,8 @@ struct device_attribute *pm8001_host_attrs[] = {
> &dev_attr_update_fw,
> &dev_attr_aap_log,
> &dev_attr_iop_log,
> + &dev_attr_fatal_log,
> + &dev_attr_gsm_log,
> &dev_attr_max_out_io,
> &dev_attr_max_devices,
> &dev_attr_max_sg_list,
> @@ -643,6 +770,8 @@ struct device_attribute *pm8001_host_attrs[] = {
> &dev_attr_logging_level,
> &dev_attr_host_sas_address,
> &dev_attr_bios_version,
> + &dev_attr_ib_log,
> + &dev_attr_ob_log,
> NULL,
> };
>
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.h
> b/drivers/scsi/pm8001/pm8001_ctl.h
> index c6d8fdd..d0d43a2 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.h
> +++ b/drivers/scsi/pm8001/pm8001_ctl.h
> @@ -55,5 +55,9 @@
> #define FAIL_OUT_MEMORY 0x000c00
> #define FLASH_IN_PROGRESS 0x001000
>
> +#define IB_OB_READ_TIMES 256
> +#define SYSFS_OFFSET 1024
> +#define PM80XX_IB_OB_QUEUE_SIZE (32 * 1024)
> +#define PM8001_IB_OB_QUEUE_SIZE (16 * 1024)
> #endif /* PM8001_CTL_H_INCLUDED */
>
> diff --git a/drivers/scsi/pm8001/pm8001_defs.h
> b/drivers/scsi/pm8001/pm8001_defs.h
> index 4bb304d..74a4bb9 100644
> --- a/drivers/scsi/pm8001/pm8001_defs.h
> +++ b/drivers/scsi/pm8001/pm8001_defs.h
> @@ -102,7 +102,8 @@ enum memory_region_num {
> NVMD, /* NVM device */
> DEV_MEM, /* memory for devices */
> CCB_MEM, /* memory for command control block */
> - FW_FLASH /* memory for fw flash update */
> + FW_FLASH, /* memory for fw flash update */
> + FORENSIC_MEM /* memory for fw forensic data */
> };
> #define PM8001_EVENT_LOG_SIZE (128 * 1024)
>
> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c
> b/drivers/scsi/pm8001/pm8001_hwi.c
> index 502c7d6..75a8b46 100644
> --- a/drivers/scsi/pm8001/pm8001_hwi.c
> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
> @@ -5015,6 +5015,89 @@ pm8001_chip_fw_flash_update_req(struct
pm8001_hba_info *pm8001_ha,
> return rc;
> }
>
> +ssize_t
> +pm8001_get_gsm_dump(struct device *cdev, u32 length, char* buf) {
> + u32 value, rem, offset = 0, bar = 0;
> + u32 index, work_offset, dw_length;
> + u32 shift_value, gsm_base, gsm_dump_offset;
> + char *direct_data;
> + 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;
> +
> + direct_data = buf;
> + gsm_dump_offset = pm8001_ha->fatal_forensic_shift_offset;
> +
> + /* check max is 1 Mbytes */
> + if ((length > 0x100000) || (gsm_dump_offset & 3) ||
> + ((gsm_dump_offset + length) > 0x1000000))
> + return 1;
> +
> + if (pm8001_ha->chip_id == chip_8001)
> + bar = 2;
> + else
> + bar = 1;
> +
> + work_offset = gsm_dump_offset & 0xFFFF0000;
> + offset = gsm_dump_offset & 0x0000FFFF;
> + gsm_dump_offset = work_offset;
> + /* adjust length to dword boundary */
> + rem = length & 3;
> + dw_length = length >> 2;
> +
> + for (index = 0; index < dw_length; index++) {
> + if ((work_offset + offset) & 0xFFFF0000) {
> + if (pm8001_ha->chip_id == chip_8001)
> + shift_value = ((gsm_dump_offset +
offset) &
> + SHIFT_REG_64K_MASK);
> + else
> + shift_value = (((gsm_dump_offset +
offset) &
> + SHIFT_REG_64K_MASK) >>
> + SHIFT_REG_BIT_SHIFT);
> +
> + if (pm8001_ha->chip_id == chip_8001) {
> + gsm_base = GSM_BASE;
> + if (-1 == pm8001_bar4_shift(pm8001_ha,
> + (gsm_base +
shift_value)))
> + return 1;
> + } else {
> + gsm_base = 0;
> + if (-1 == pm80xx_bar4_shift(pm8001_ha,
> + (gsm_base +
shift_value)))
> + return 1;
> + }
> + gsm_dump_offset = (gsm_dump_offset + offset) &
> + 0xFFFF0000;
> + work_offset = 0;
> + offset = offset & 0x0000FFFF;
> + }
> + value = pm8001_cr32(pm8001_ha, bar, (work_offset +
offset) &
> + 0x0000FFFF);
> + direct_data += sprintf(direct_data, "%08x ", value);
> + offset += 4;
> + }
> + if (rem != 0) {
> + value = pm8001_cr32(pm8001_ha, bar, (work_offset +
offset) &
> + 0x0000FFFF);
> + /* xfr for non_dw */
> + direct_data += sprintf(direct_data, "%08x ", value);
> + }
> + /* Shift back to BAR4 original address */
> + if (pm8001_ha->chip_id == chip_8001) {
> + if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
> + return 1;
> + } else {
> + if (-1 == pm80xx_bar4_shift(pm8001_ha, 0))
> + return 1;
> + }
> + pm8001_ha->fatal_forensic_shift_offset += 1024;
> +
> + if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000)
> + pm8001_ha->fatal_forensic_shift_offset = 0;
> + return direct_data - buf;
> +}
> +
> int
> pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,
> struct pm8001_device *pm8001_dev, u32 state) diff --git
> a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
> index d7c1e20..6d91e24 100644
> --- a/drivers/scsi/pm8001/pm8001_hwi.h
> +++ b/drivers/scsi/pm8001/pm8001_hwi.h
> @@ -1027,5 +1027,8 @@ struct set_dev_state_resp {
> #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
> #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
>
> +#define GSM_BASE 0x4F0000
> +#define SHIFT_REG_64K_MASK 0xffff0000
> +#define SHIFT_REG_BIT_SHIFT 8
> #endif
>
> diff --git a/drivers/scsi/pm8001/pm8001_init.c
> b/drivers/scsi/pm8001/pm8001_init.c
> index b31d25a..49cfe45 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,
> /* Memory region for fw flash */
> pm8001_ha->memoryMap.region[FW_FLASH].total_len = 4096;
>
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].num_elements = 1;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].total_len = 0x10000;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].element_size =
0x10000;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].alignment = 0x10000;
> for (i = 0; i < USI_MAX_MEMCNT; i++) {
> if (pm8001_mem_alloc(pm8001_ha->pdev,
> &pm8001_ha->memoryMap.region[i].virt_ptr,
> diff --git a/drivers/scsi/pm8001/pm8001_sas.h
> b/drivers/scsi/pm8001/pm8001_sas.h
> index cbde11a..9241c04 100644
> --- a/drivers/scsi/pm8001/pm8001_sas.h
> +++ b/drivers/scsi/pm8001/pm8001_sas.h
> @@ -132,6 +132,61 @@ struct pm8001_ioctl_payload {
> u8 *func_specific;
> };
>
> +#define MPI_FATAL_ERROR_TABLE_OFFSET_MASK 0xFFFFFF #define
> +MPI_FATAL_ERROR_TABLE_SIZE(value) ((0xFF000000 & value) >> SHIFT24)
> +#define MPI_FATAL_EDUMP_TABLE_LO_OFFSET 0x00 /*
HNFBUFL */
> +#define MPI_FATAL_EDUMP_TABLE_HI_OFFSET 0x04 /*
HNFBUFH */
> +#define MPI_FATAL_EDUMP_TABLE_LENGTH 0x08 /*
HNFBLEN */
> +#define MPI_FATAL_EDUMP_TABLE_HANDSHAKE 0x0C /*
FDDHSHK */
> +#define MPI_FATAL_EDUMP_TABLE_STATUS 0x10 /*
FDDTSTAT */
> +#define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN 0x14 /*
ACCDDLEN */
> +#define MPI_FATAL_EDUMP_HANDSHAKE_RDY 0x1
> +#define MPI_FATAL_EDUMP_HANDSHAKE_BUSY 0x0
> +#define MPI_FATAL_EDUMP_TABLE_STAT_RSVD 0x0
> +#define MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED 0x1
> +#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA 0x2
> +#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE 0x3
> +#define TYPE_GSM_SPACE 1
> +#define TYPE_QUEUE 2
> +#define TYPE_FATAL 3
> +#define TYPE_NON_FATAL 4
> +#define TYPE_INBOUND 1
> +#define TYPE_OUTBOUND 2
> +struct forensic_data {
> + u32 data_type;
> + union {
> + struct {
> + u32 direct_len;
> + u32 direct_offset;
> + void *direct_data;
> + } gsm_buf;
> + struct {
> + u16 queue_type;
> + u16 queue_index;
> + u32 direct_len;
> + void *direct_data;
> + } queue_buf;
> + struct {
> + u32 direct_len;
> + u32 direct_offset;
> + u32 read_len;
> + void *direct_data;
> + } data_buf;
> + };
> +};
> +
> +/* bit31-26 - mask bar */
> +#define SCRATCH_PAD0_BAR_MASK 0xFC000000
> +/* bit25-0 - offset mask */
> +#define SCRATCH_PAD0_OFFSET_MASK 0x03FFFFFF
> +/* if AAP error state */
> +#define SCRATCH_PAD0_AAPERR_MASK 0xFFFFFFFF
> +/* Inbound doorbell bit7 */
> +#define SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP 0x80
> +/* Inbound doorbell bit7 SPCV */
> +#define SPCV_MSGU_CFG_TABLE_TRANSFER_DEBUG_INFO 0x80
> +#define MAIN_MERRDCTO_MERRDCES 0xA0/* DWORD
0x28) */
> +
> struct pm8001_dispatch {
> char *name;
> int (*chip_init)(struct pm8001_hba_info *pm8001_ha); @@ -346,6
> +401,7 @@ union main_cfg_table {
> u32 phy_attr_table_offset;
> u32 port_recovery_timer;
> u32 interrupt_reassertion_delay;
> + u32 fatal_n_non_fatal_dump; /* 0x28
*/
> } pm80xx_tbl;
> };
>
> @@ -420,6 +476,13 @@ struct pm8001_hba_info {
> struct pm8001_hba_memspace io_mem[6];
> struct mpi_mem_req memoryMap;
> struct encrypt encrypt_info; /* support encryption */
> + struct forensic_data forensic_info;
> + u32 fatal_bar_loc;
> + u32 forensic_last_offset;
> + u32 fatal_forensic_shift_offset;
> + u32 forensic_fatal_step;
> + u32 evtlog_ib_offset;
> + u32 evtlog_ob_offset;
> void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/
> void __iomem *main_cfg_tbl_addr;/*Main Config Table Addr*/
> void __iomem *general_stat_tbl_addr;/*General Status Table
Addr*/
> @@ -428,6 +491,7 @@ struct pm8001_hba_info {
> void __iomem *pspa_q_tbl_addr;
> /*MPI SAS PHY attributes Queue Config Table
Addr*/
> void __iomem *ivt_tbl_addr; /*MPI IVT Table Addr */
> + void __iomem *fatal_tbl_addr; /*MPI IVT Table Addr */
> union main_cfg_table main_cfg_tbl;
> union general_status_table gs_tbl;
> 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); int pm8001_bar4_shift(struct
> pm8001_hba_info *pm8001_ha, u32 shiftValue); void
pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
> u32 length, u8 *buf);
> +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
> +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 94de2ed..7b87e96 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
> @@ -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", diff --git
> a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h
> index 872d5cf..c86816b 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.h
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.h
> @@ -1525,4 +1525,6 @@ typedef struct SASProtocolTimerConfig
SASProtocolTimerConfig_t;
> #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
> #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
>
> +
> +#define MEMBASE_II_SHIFT_REGISTER 0x1010
> #endif
^ permalink raw reply [flat|nested] 5+ messages in thread* RE: [PATCH V2 10/10] pm80xx: Firmware logging support
2013-09-27 13:02 ` Tomas Henzl
2013-09-30 6:38 ` Sangeetha Gnanasekaran
@ 2013-10-01 11:11 ` Anand Kumar Santhanam
1 sibling, 0 replies; 5+ messages in thread
From: Anand Kumar Santhanam @ 2013-10-01 11:11 UTC (permalink / raw)
To: 'Tomas Henzl'
Cc: linux-scsi@vger.kernel.org, Sangeetha Gnanasekaran,
Nikith Ganigarakoppal, Viswas G, xjtuwjp@gmail.com
Tomas,
Pls see replies inline.
Regards
Anand
-----Original Message-----
From: Tomas Henzl [mailto:thenzl@redhat.com]
Sent: Friday, September 27, 2013 6:32 PM
To: Anand Kumar Santhanam
Cc: linux-scsi@vger.kernel.org; Sangeetha Gnanasekaran; Nikith Ganigarakoppal; Viswas G; xjtuwjp@gmail.com
Subject: Re: [PATCH V2 10/10] pm80xx: Firmware logging support
On 09/26/2013 07:43 AM, Anand wrote:
> From ab1b030500a835eacda3d86e5570366099b21311 Mon Sep 17 00:00:00 2001
> From: Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>
> Date: Wed, 4 Sep 2013 12:57:00 +0530
> Subject: [PATCH V2 10/10] 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.
>
> Signed-off-by: Anandkumar.Santhanam@pmcs.com
>
> ---
> drivers/scsi/pm8001/pm8001_ctl.c | 129 +++++++++++++++++++++
> drivers/scsi/pm8001/pm8001_ctl.h | 4 +
> drivers/scsi/pm8001/pm8001_defs.h | 3 +-
> drivers/scsi/pm8001/pm8001_hwi.c | 83 ++++++++++++++
> drivers/scsi/pm8001/pm8001_hwi.h | 3 +
> drivers/scsi/pm8001/pm8001_init.c | 4 +
> drivers/scsi/pm8001/pm8001_sas.h | 68 +++++++++++
> drivers/scsi/pm8001/pm80xx_hwi.c | 225 +++++++++++++++++++++++++++++++++++++
> drivers/scsi/pm8001/pm80xx_hwi.h | 2 +
> 9 files changed, 520 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.c
> b/drivers/scsi/pm8001/pm8001_ctl.c
> index 5a19e19..2ca79a5 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.c
> +++ b/drivers/scsi/pm8001/pm8001_ctl.c
> @@ -309,6 +309,94 @@ static ssize_t pm8001_ctl_aap_log_show(struct
> device *cdev, } static DEVICE_ATTR(aap_log, S_IRUGO,
> pm8001_ctl_aap_log_show, NULL);
> /**
> + * pm8001_ctl_ib_queue_log_show - Out bound Queue log
> + * @cdev:pointer to embedded class device
> + * @buf: the buffer returned
> + * A sysfs 'read-only' shost attribute.
> + */
> +static ssize_t pm8001_ctl_ib_queue_log_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;
> + int offset;
> + char *str = buf;
> + int start = 0;
> +#define IB_MEMMAP(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[IB].virt_ptr + \
> + pm8001_ha->evtlog_ib_offset + (c)))
> +
> +#define IB_MEMMAP_SPC(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[IB].virt_ptr + \
> + pm8001_ha->evtlog_ib_offset + (c)))
The IB_MEMMAP and IB_MEMMAP_SPC seems to be exactly the same - is that intentional?
and btw. why do you use macros, when they are used just once?
(In the function below there is a similar pattern - again two identical macros) Cheers, Tomas
Anand> The updated patch has been submitted.
We are using macro for better readability.
> +
> + for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
> + if (pm8001_ha->chip_id != chip_8001)
> + str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
> + else
> + str += sprintf(str, "0x%08x\n", IB_MEMMAP_SPC(start));
> + start = start + 4;
> + }
> + pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;
> + if ((((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id != chip_8001))
> + pm8001_ha->evtlog_ib_offset = 0;
> + if ((((pm8001_ha->evtlog_ib_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id == chip_8001))
> + pm8001_ha->evtlog_ib_offset = 0;
> +
> + return str - buf;
> +}
> +
> +static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show,
> +NULL);
> +/**
> + * pm8001_ctl_ob_queue_log_show - Out bound Queue log
> + * @cdev:pointer to embedded class device
> + * @buf: the buffer returned
> + * A sysfs 'read-only' shost attribute.
> + */
> +
> +static ssize_t pm8001_ctl_ob_queue_log_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;
> + int offset;
> + char *str = buf;
> + int start = 0;
> +#define OB_MEMMAP(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[OB].virt_ptr + \
> + pm8001_ha->evtlog_ob_offset + (c)))
> +
> +#define OB_MEMMAP_SPC(c) \
> + (*(u32 *)((u8 *)pm8001_ha-> \
> + memoryMap.region[OB].virt_ptr + \
> + pm8001_ha->evtlog_ob_offset + (c)))
> +
> + for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
> + if (pm8001_ha->chip_id != chip_8001)
> + str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
> + else
> + str += sprintf(str, "0x%08x\n", OB_MEMMAP_SPC(start));
> + start = start + 4;
> + }
> + pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;
> + if ((((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id != chip_8001))
> + pm8001_ha->evtlog_ob_offset = 0;
> + if ((((pm8001_ha->evtlog_ob_offset) % (PM8001_IB_OB_QUEUE_SIZE)) == 0)
> + && (pm8001_ha->chip_id == chip_8001))
> + pm8001_ha->evtlog_ob_offset = 0;
> +
> + return str - buf;
> +}
> +static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show,
> +NULL);
> +/**
> * pm8001_ctl_bios_version_show - Bios version Display
> * @cdev:pointer to embedded class device
> * @buf:the buffer returned
> @@ -377,6 +465,43 @@ static ssize_t pm8001_ctl_iop_log_show(struct
> device *cdev, } static DEVICE_ATTR(iop_log, S_IRUGO,
> pm8001_ctl_iop_log_show, NULL);
>
> +/**
> + ** pm8001_ctl_fatal_log_show - fatal error logging
> + ** @cdev:pointer to embedded class device
> + ** @buf: the buffer returned
> + **
> + ** A sysfs 'read-only' shost attribute.
> + **/
> +
> +static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
> + struct device_attribute *attr, char *buf) {
> + u32 count;
> +
> + count = pm80xx_get_fatal_dump(cdev, attr, buf);
> + return count;
> +}
> +
> +static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show,
> +NULL);
> +
> +
> +/**
> + ** pm8001_ctl_gsm_log_show - gsm dump collection
> + ** @cdev:pointer to embedded class device
> + ** @buf: the buffer returned
> + **A sysfs 'read-only' shost attribute.
> + **/
> +static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
> + struct device_attribute *attr, char *buf) {
> + u32 count;
> +
> + count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);
> + return count;
> +}
> +
> +static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL);
> +
> #define FLASH_CMD_NONE 0x00
> #define FLASH_CMD_UPDATE 0x01
> #define FLASH_CMD_SET_NVMD 0x02
> @@ -636,6 +761,8 @@ struct device_attribute *pm8001_host_attrs[] = {
> &dev_attr_update_fw,
> &dev_attr_aap_log,
> &dev_attr_iop_log,
> + &dev_attr_fatal_log,
> + &dev_attr_gsm_log,
> &dev_attr_max_out_io,
> &dev_attr_max_devices,
> &dev_attr_max_sg_list,
> @@ -643,6 +770,8 @@ struct device_attribute *pm8001_host_attrs[] = {
> &dev_attr_logging_level,
> &dev_attr_host_sas_address,
> &dev_attr_bios_version,
> + &dev_attr_ib_log,
> + &dev_attr_ob_log,
> NULL,
> };
>
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.h
> b/drivers/scsi/pm8001/pm8001_ctl.h
> index c6d8fdd..d0d43a2 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.h
> +++ b/drivers/scsi/pm8001/pm8001_ctl.h
> @@ -55,5 +55,9 @@
> #define FAIL_OUT_MEMORY 0x000c00
> #define FLASH_IN_PROGRESS 0x001000
>
> +#define IB_OB_READ_TIMES 256
> +#define SYSFS_OFFSET 1024
> +#define PM80XX_IB_OB_QUEUE_SIZE (32 * 1024)
> +#define PM8001_IB_OB_QUEUE_SIZE (16 * 1024)
> #endif /* PM8001_CTL_H_INCLUDED */
>
> diff --git a/drivers/scsi/pm8001/pm8001_defs.h
> b/drivers/scsi/pm8001/pm8001_defs.h
> index 4bb304d..74a4bb9 100644
> --- a/drivers/scsi/pm8001/pm8001_defs.h
> +++ b/drivers/scsi/pm8001/pm8001_defs.h
> @@ -102,7 +102,8 @@ enum memory_region_num {
> NVMD, /* NVM device */
> DEV_MEM, /* memory for devices */
> CCB_MEM, /* memory for command control block */
> - FW_FLASH /* memory for fw flash update */
> + FW_FLASH, /* memory for fw flash update */
> + FORENSIC_MEM /* memory for fw forensic data */
> };
> #define PM8001_EVENT_LOG_SIZE (128 * 1024)
>
> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c
> b/drivers/scsi/pm8001/pm8001_hwi.c
> index 502c7d6..75a8b46 100644
> --- a/drivers/scsi/pm8001/pm8001_hwi.c
> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
> @@ -5015,6 +5015,89 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
> return rc;
> }
>
> +ssize_t
> +pm8001_get_gsm_dump(struct device *cdev, u32 length, char* buf) {
> + u32 value, rem, offset = 0, bar = 0;
> + u32 index, work_offset, dw_length;
> + u32 shift_value, gsm_base, gsm_dump_offset;
> + char *direct_data;
> + 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;
> +
> + direct_data = buf;
> + gsm_dump_offset = pm8001_ha->fatal_forensic_shift_offset;
> +
> + /* check max is 1 Mbytes */
> + if ((length > 0x100000) || (gsm_dump_offset & 3) ||
> + ((gsm_dump_offset + length) > 0x1000000))
> + return 1;
> +
> + if (pm8001_ha->chip_id == chip_8001)
> + bar = 2;
> + else
> + bar = 1;
> +
> + work_offset = gsm_dump_offset & 0xFFFF0000;
> + offset = gsm_dump_offset & 0x0000FFFF;
> + gsm_dump_offset = work_offset;
> + /* adjust length to dword boundary */
> + rem = length & 3;
> + dw_length = length >> 2;
> +
> + for (index = 0; index < dw_length; index++) {
> + if ((work_offset + offset) & 0xFFFF0000) {
> + if (pm8001_ha->chip_id == chip_8001)
> + shift_value = ((gsm_dump_offset + offset) &
> + SHIFT_REG_64K_MASK);
> + else
> + shift_value = (((gsm_dump_offset + offset) &
> + SHIFT_REG_64K_MASK) >>
> + SHIFT_REG_BIT_SHIFT);
> +
> + if (pm8001_ha->chip_id == chip_8001) {
> + gsm_base = GSM_BASE;
> + if (-1 == pm8001_bar4_shift(pm8001_ha,
> + (gsm_base + shift_value)))
> + return 1;
> + } else {
> + gsm_base = 0;
> + if (-1 == pm80xx_bar4_shift(pm8001_ha,
> + (gsm_base + shift_value)))
> + return 1;
> + }
> + gsm_dump_offset = (gsm_dump_offset + offset) &
> + 0xFFFF0000;
> + work_offset = 0;
> + offset = offset & 0x0000FFFF;
> + }
> + value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
> + 0x0000FFFF);
> + direct_data += sprintf(direct_data, "%08x ", value);
> + offset += 4;
> + }
> + if (rem != 0) {
> + value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
> + 0x0000FFFF);
> + /* xfr for non_dw */
> + direct_data += sprintf(direct_data, "%08x ", value);
> + }
> + /* Shift back to BAR4 original address */
> + if (pm8001_ha->chip_id == chip_8001) {
> + if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
> + return 1;
> + } else {
> + if (-1 == pm80xx_bar4_shift(pm8001_ha, 0))
> + return 1;
> + }
> + pm8001_ha->fatal_forensic_shift_offset += 1024;
> +
> + if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000)
> + pm8001_ha->fatal_forensic_shift_offset = 0;
> + return direct_data - buf;
> +}
> +
> int
> pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,
> struct pm8001_device *pm8001_dev, u32 state) diff --git
> a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h
> index d7c1e20..6d91e24 100644
> --- a/drivers/scsi/pm8001/pm8001_hwi.h
> +++ b/drivers/scsi/pm8001/pm8001_hwi.h
> @@ -1027,5 +1027,8 @@ struct set_dev_state_resp {
> #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
> #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
>
> +#define GSM_BASE 0x4F0000
> +#define SHIFT_REG_64K_MASK 0xffff0000
> +#define SHIFT_REG_BIT_SHIFT 8
> #endif
>
> diff --git a/drivers/scsi/pm8001/pm8001_init.c
> b/drivers/scsi/pm8001/pm8001_init.c
> index b31d25a..49cfe45 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,
> /* Memory region for fw flash */
> pm8001_ha->memoryMap.region[FW_FLASH].total_len = 4096;
>
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].num_elements = 1;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].total_len = 0x10000;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].element_size = 0x10000;
> + pm8001_ha->memoryMap.region[FORENSIC_MEM].alignment = 0x10000;
> for (i = 0; i < USI_MAX_MEMCNT; i++) {
> if (pm8001_mem_alloc(pm8001_ha->pdev,
> &pm8001_ha->memoryMap.region[i].virt_ptr,
> diff --git a/drivers/scsi/pm8001/pm8001_sas.h
> b/drivers/scsi/pm8001/pm8001_sas.h
> index cbde11a..9241c04 100644
> --- a/drivers/scsi/pm8001/pm8001_sas.h
> +++ b/drivers/scsi/pm8001/pm8001_sas.h
> @@ -132,6 +132,61 @@ struct pm8001_ioctl_payload {
> u8 *func_specific;
> };
>
> +#define MPI_FATAL_ERROR_TABLE_OFFSET_MASK 0xFFFFFF #define
> +MPI_FATAL_ERROR_TABLE_SIZE(value) ((0xFF000000 & value) >> SHIFT24)
> +#define MPI_FATAL_EDUMP_TABLE_LO_OFFSET 0x00 /* HNFBUFL */
> +#define MPI_FATAL_EDUMP_TABLE_HI_OFFSET 0x04 /* HNFBUFH */
> +#define MPI_FATAL_EDUMP_TABLE_LENGTH 0x08 /* HNFBLEN */
> +#define MPI_FATAL_EDUMP_TABLE_HANDSHAKE 0x0C /* FDDHSHK */
> +#define MPI_FATAL_EDUMP_TABLE_STATUS 0x10 /* FDDTSTAT */
> +#define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN 0x14 /* ACCDDLEN */
> +#define MPI_FATAL_EDUMP_HANDSHAKE_RDY 0x1
> +#define MPI_FATAL_EDUMP_HANDSHAKE_BUSY 0x0
> +#define MPI_FATAL_EDUMP_TABLE_STAT_RSVD 0x0
> +#define MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED 0x1
> +#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA 0x2
> +#define MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE 0x3
> +#define TYPE_GSM_SPACE 1
> +#define TYPE_QUEUE 2
> +#define TYPE_FATAL 3
> +#define TYPE_NON_FATAL 4
> +#define TYPE_INBOUND 1
> +#define TYPE_OUTBOUND 2
> +struct forensic_data {
> + u32 data_type;
> + union {
> + struct {
> + u32 direct_len;
> + u32 direct_offset;
> + void *direct_data;
> + } gsm_buf;
> + struct {
> + u16 queue_type;
> + u16 queue_index;
> + u32 direct_len;
> + void *direct_data;
> + } queue_buf;
> + struct {
> + u32 direct_len;
> + u32 direct_offset;
> + u32 read_len;
> + void *direct_data;
> + } data_buf;
> + };
> +};
> +
> +/* bit31-26 - mask bar */
> +#define SCRATCH_PAD0_BAR_MASK 0xFC000000
> +/* bit25-0 - offset mask */
> +#define SCRATCH_PAD0_OFFSET_MASK 0x03FFFFFF
> +/* if AAP error state */
> +#define SCRATCH_PAD0_AAPERR_MASK 0xFFFFFFFF
> +/* Inbound doorbell bit7 */
> +#define SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP 0x80
> +/* Inbound doorbell bit7 SPCV */
> +#define SPCV_MSGU_CFG_TABLE_TRANSFER_DEBUG_INFO 0x80
> +#define MAIN_MERRDCTO_MERRDCES 0xA0/* DWORD 0x28) */
> +
> struct pm8001_dispatch {
> char *name;
> int (*chip_init)(struct pm8001_hba_info *pm8001_ha); @@ -346,6
> +401,7 @@ union main_cfg_table {
> u32 phy_attr_table_offset;
> u32 port_recovery_timer;
> u32 interrupt_reassertion_delay;
> + u32 fatal_n_non_fatal_dump; /* 0x28 */
> } pm80xx_tbl;
> };
>
> @@ -420,6 +476,13 @@ struct pm8001_hba_info {
> struct pm8001_hba_memspace io_mem[6];
> struct mpi_mem_req memoryMap;
> struct encrypt encrypt_info; /* support encryption */
> + struct forensic_data forensic_info;
> + u32 fatal_bar_loc;
> + u32 forensic_last_offset;
> + u32 fatal_forensic_shift_offset;
> + u32 forensic_fatal_step;
> + u32 evtlog_ib_offset;
> + u32 evtlog_ob_offset;
> void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/
> void __iomem *main_cfg_tbl_addr;/*Main Config Table Addr*/
> void __iomem *general_stat_tbl_addr;/*General Status Table Addr*/
> @@ -428,6 +491,7 @@ struct pm8001_hba_info {
> void __iomem *pspa_q_tbl_addr;
> /*MPI SAS PHY attributes Queue Config Table Addr*/
> void __iomem *ivt_tbl_addr; /*MPI IVT Table Addr */
> + void __iomem *fatal_tbl_addr; /*MPI IVT Table Addr */
> union main_cfg_table main_cfg_tbl;
> union general_status_table gs_tbl;
> 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); int pm8001_bar4_shift(struct
> pm8001_hba_info *pm8001_ha, u32 shiftValue); void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
> u32 length, u8 *buf);
> +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
> +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 94de2ed..7b87e96 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
> @@ -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", diff --git
> a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h
> index 872d5cf..c86816b 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.h
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.h
> @@ -1525,4 +1525,6 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
> #define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06
> #define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07
>
> +
> +#define MEMBASE_II_SHIFT_REGISTER 0x1010
> #endif
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2013-10-01 11:37 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-26 5:43 [PATCH V2 10/10] pm80xx: Firmware logging support Anand
2013-09-26 7:12 ` Jack Wang
2013-09-27 13:02 ` Tomas Henzl
2013-09-30 6:38 ` Sangeetha Gnanasekaran
2013-10-01 11:11 ` Anand Kumar Santhanam
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).