Commit 570c67ac authored by Kashyap, Desai's avatar Kashyap, Desai Committed by James Bottomley

[SCSI] mpt2sas: Added sysfs support for trace buffer

Added support so the diag ring buffer can be pulled via sysfs
Added three new shost attributes: host_trace_buffer,
host_trace_buffer_enable, and host_trace_buffer_size.  The
host_trace_buffer_enable attribute is used to either post or release
the trace buffers.   The host_trace_buffer_size attribute contains
the size of the trace buffer. The host_trace_buffer atttribute contains
a maximum 4KB window of the buffer. In order to read the entire host buffer,
you will need to write the offset to  host_trace_buffer prior to reading
it. release the host buffer, then write the entire host buffer contents to
a file.
In addition to this enhancement, we moved the automatic posting of host buffers
at driver load time to be called prior to port_enable, instead of after.
That way discovery is available in the host buffer.
Signed-off-by: default avatarKashyap Desai <kashyap.desai@lsi.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 203d65b1
...@@ -3529,8 +3529,12 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) ...@@ -3529,8 +3529,12 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
if (sleep_flag == CAN_SLEEP) if (sleep_flag == CAN_SLEEP)
_base_static_config_pages(ioc); _base_static_config_pages(ioc);
if (ioc->wait_for_port_enable_to_complete && disable_discovery > 0) if (ioc->wait_for_port_enable_to_complete) {
if (diag_buffer_enable != 0)
mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
if (disable_discovery > 0)
return r; return r;
}
r = _base_send_port_enable(ioc, sleep_flag); r = _base_send_port_enable(ioc, sleep_flag);
if (r) if (r)
...@@ -3679,8 +3683,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) ...@@ -3679,8 +3683,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
goto out_free_resources; goto out_free_resources;
mpt2sas_base_start_watchdog(ioc); mpt2sas_base_start_watchdog(ioc);
if (diag_buffer_enable != 0)
mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
return 0; return 0;
out_free_resources: out_free_resources:
......
...@@ -750,6 +750,8 @@ struct MPT2SAS_ADAPTER { ...@@ -750,6 +750,8 @@ struct MPT2SAS_ADAPTER {
Mpi2ManufacturingPage10_t manu_pg10; Mpi2ManufacturingPage10_t manu_pg10;
u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23];
u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
u32 ring_buffer_offset;
u32 ring_buffer_sz;
}; };
typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
......
...@@ -2603,6 +2603,195 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, ...@@ -2603,6 +2603,195 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
static DEVICE_ATTR(ioc_reset_count, S_IRUGO, static DEVICE_ATTR(ioc_reset_count, S_IRUGO,
_ctl_ioc_reset_count_show, NULL); _ctl_ioc_reset_count_show, NULL);
struct DIAG_BUFFER_START {
u32 Size;
u32 DiagVersion;
u8 BufferType;
u8 Reserved[3];
u32 Reserved1;
u32 Reserved2;
u32 Reserved3;
};
/**
* _ctl_host_trace_buffer_size_show - host buffer size (trace only)
* @cdev - pointer to embedded class device
* @buf - the buffer returned
*
* A sysfs 'read-only' shost attribute.
*/
static ssize_t
_ctl_host_trace_buffer_size_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
u32 size = 0;
struct DIAG_BUFFER_START *request_data;
if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
"registered\n", ioc->name, __func__);
return 0;
}
if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
"registered\n", ioc->name, __func__);
return 0;
}
request_data = (struct DIAG_BUFFER_START *)
ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE];
if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 ||
le32_to_cpu(request_data->DiagVersion) == 0x01000000) &&
le32_to_cpu(request_data->Reserved3) == 0x4742444c)
size = le32_to_cpu(request_data->Size);
ioc->ring_buffer_sz = size;
return snprintf(buf, PAGE_SIZE, "%d\n", size);
}
static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO,
_ctl_host_trace_buffer_size_show, NULL);
/**
* _ctl_host_trace_buffer_show - firmware ring buffer (trace only)
* @cdev - pointer to embedded class device
* @buf - the buffer returned
*
* A sysfs 'read/write' shost attribute.
*
* You will only be able to read 4k bytes of ring buffer at a time.
* In order to read beyond 4k bytes, you will have to write out the
* offset to the same attribute, it will move the pointer.
*/
static ssize_t
_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
void *request_data;
u32 size;
if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
"registered\n", ioc->name, __func__);
return 0;
}
if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
"registered\n", ioc->name, __func__);
return 0;
}
if (ioc->ring_buffer_offset > ioc->ring_buffer_sz)
return 0;
size = ioc->ring_buffer_sz - ioc->ring_buffer_offset;
size = (size > PAGE_SIZE) ? PAGE_SIZE : size;
request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset;
memcpy(buf, request_data, size);
return size;
}
static ssize_t
_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
int val = 0;
if (sscanf(buf, "%d", &val) != 1)
return -EINVAL;
ioc->ring_buffer_offset = val;
return strlen(buf);
}
static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR,
_ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store);
/*****************************************/
/**
* _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only)
* @cdev - pointer to embedded class device
* @buf - the buffer returned
*
* A sysfs 'read/write' shost attribute.
*
* This is a mechnism to post/release host_trace_buffers
*/
static ssize_t
_ctl_host_trace_buffer_enable_show(struct device *cdev,
struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = class_to_shost(cdev);
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) ||
((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT2_DIAG_BUFFER_IS_REGISTERED) == 0))
return snprintf(buf, PAGE_SIZE, "off\n");
else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT2_DIAG_BUFFER_IS_RELEASED))
return snprintf(buf, PAGE_SIZE, "release\n");
else
return snprintf(buf, PAGE_SIZE, "post\n");
}
static ssize_t
_ctl_host_trace_buffer_enable_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct Scsi_Host *shost = class_to_shost(cdev);
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
char str[10] = "";
struct mpt2_diag_register diag_register;
u8 issue_reset = 0;
if (sscanf(buf, "%s", str) != 1)
return -EINVAL;
if (!strcmp(str, "post")) {
/* exit out if host buffers are already posted */
if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) &&
(ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT2_DIAG_BUFFER_IS_REGISTERED) &&
((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT2_DIAG_BUFFER_IS_RELEASED) == 0))
goto out;
memset(&diag_register, 0, sizeof(struct mpt2_diag_register));
printk(MPT2SAS_INFO_FMT "posting host trace buffers\n",
ioc->name);
diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
diag_register.requested_buffer_size = (1024 * 1024);
diag_register.unique_id = 0x7075900;
ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0;
_ctl_diag_register_2(ioc, &diag_register);
} else if (!strcmp(str, "release")) {
/* exit out if host buffers are already released */
if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE])
goto out;
if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)
goto out;
if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
MPT2_DIAG_BUFFER_IS_RELEASED))
goto out;
printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n",
ioc->name);
_ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset);
}
out:
return strlen(buf);
}
static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR,
_ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store);
struct device_attribute *mpt2sas_host_attrs[] = { struct device_attribute *mpt2sas_host_attrs[] = {
&dev_attr_version_fw, &dev_attr_version_fw,
...@@ -2621,6 +2810,9 @@ struct device_attribute *mpt2sas_host_attrs[] = { ...@@ -2621,6 +2810,9 @@ struct device_attribute *mpt2sas_host_attrs[] = {
&dev_attr_fw_queue_depth, &dev_attr_fw_queue_depth,
&dev_attr_host_sas_address, &dev_attr_host_sas_address,
&dev_attr_ioc_reset_count, &dev_attr_ioc_reset_count,
&dev_attr_host_trace_buffer_size,
&dev_attr_host_trace_buffer,
&dev_attr_host_trace_buffer_enable,
NULL, NULL,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment