Skip to content

Commit

Permalink
[SCSI] pm80xx: Firmware logging support.
Browse files Browse the repository at this point in the history
Supports below logging facilities,
Inbound outbound queues dump.
Non fatal dump in case of IO failures.
Fatal dump in case of firmware failure.

[jejb: checkpatch spacing fixes]
Signed-off-by: Anandkumar.Santhanam@pmcs.com
Reviewed-by: Jack Wang <jinpu.wang@profitbricks.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
  • Loading branch information
Anand Kumar Santhanam authored and James Bottomley committed Oct 25, 2013
1 parent 2790940 commit d078b51
Show file tree
Hide file tree
Showing 9 changed files with 510 additions and 1 deletion.
119 changes: 119 additions & 0 deletions drivers/scsi/pm8001/pm8001_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,84 @@ static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,
return str - buf;
}
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)))

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(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)))

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(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
Expand Down Expand Up @@ -377,6 +455,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
Expand Down Expand Up @@ -636,13 +751,17 @@ 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,
&dev_attr_sas_spec_support,
&dev_attr_logging_level,
&dev_attr_host_sas_address,
&dev_attr_bios_version,
&dev_attr_ib_log,
&dev_attr_ob_log,
NULL,
};

4 changes: 4 additions & 0 deletions drivers/scsi/pm8001/pm8001_ctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

3 changes: 2 additions & 1 deletion drivers/scsi/pm8001/pm8001_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
83 changes: 83 additions & 0 deletions drivers/scsi/pm8001/pm8001_hwi.c
Original file line number Diff line number Diff line change
Expand Up @@ -5001,6 +5001,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)
Expand Down
3 changes: 3 additions & 0 deletions drivers/scsi/pm8001/pm8001_hwi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

4 changes: 4 additions & 0 deletions drivers/scsi/pm8001/pm8001_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
68 changes: 68 additions & 0 deletions drivers/scsi/pm8001/pm8001_sas.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
};

Expand Down Expand Up @@ -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*/
Expand All @@ -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];
Expand Down Expand Up @@ -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[];

Expand Down
Loading

0 comments on commit d078b51

Please sign in to comment.