[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: Anandkumar.Santhanam@pmcs.com
Reviewed-by: Jack Wang <jinpu.wang@profitbricks.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c
index 5a19e19..a04b4ff 100644
--- a/drivers/scsi/pm8001/pm8001_ctl.c
+++ b/drivers/scsi/pm8001/pm8001_ctl.c
@@ -309,6 +309,84 @@
 }
 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
  * @buf:the buffer returned
@@ -377,6 +455,43 @@
 }
 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 @@
 	&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 @@
 	&dev_attr_logging_level,
 	&dev_attr_host_sas_address,
 	&dev_attr_bios_version,
+	&dev_attr_ib_log,
+	&dev_attr_ob_log,
 	NULL,
 };