Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d078b511 authored by Anand Kumar Santhanam's avatar Anand Kumar Santhanam Committed by James Bottomley
Browse files

[SCSI] pm80xx: Firmware logging support.



Supports below logging facilities,
Inbound outbound queues dump.
Non fatal dump in case of IO failures.
Fatal dump in case of firmware failure.

[jejb: checkpatch spacing fixes]
Signed-off-by: default avatar <Anandkumar.Santhanam@pmcs.com>
Reviewed-by: default avatarJack Wang <jinpu.wang@profitbricks.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 27909407
Loading
Loading
Loading
Loading
+119 −0
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -636,6 +751,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 +760,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,
};
+4 −0
Original line number Diff line number Diff line
@@ -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 */
+2 −1
Original line number Diff line number Diff line
@@ -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)

+83 −0
Original line number Diff line number Diff line
@@ -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)
+3 −0
Original line number Diff line number Diff line
@@ -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
Loading