|
@@ -37,6 +37,7 @@
|
|
|
#include <linux/kthread.h>
|
|
|
#include <../drivers/ata/ahci.h>
|
|
|
#include <linux/export.h>
|
|
|
+#include <linux/debugfs.h>
|
|
|
#include "mtip32xx.h"
|
|
|
|
|
|
#define HW_CMD_SLOT_SZ (MTIP_MAX_COMMAND_SLOTS * 32)
|
|
@@ -85,6 +86,7 @@ static int instance;
|
|
|
* allocated in mtip_init().
|
|
|
*/
|
|
|
static int mtip_major;
|
|
|
+static struct dentry *dfs_parent;
|
|
|
|
|
|
static DEFINE_SPINLOCK(rssd_index_lock);
|
|
|
static DEFINE_IDA(rssd_index_ida);
|
|
@@ -2546,7 +2548,7 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Sysfs register/status dump.
|
|
|
+ * Sysfs status dump.
|
|
|
*
|
|
|
* @dev Pointer to the device structure, passed by the kernrel.
|
|
|
* @attr Pointer to the device_attribute structure passed by the kernel.
|
|
@@ -2555,45 +2557,68 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
|
|
|
* return value
|
|
|
* The size, in bytes, of the data copied into buf.
|
|
|
*/
|
|
|
-static ssize_t mtip_hw_show_registers(struct device *dev,
|
|
|
+static ssize_t mtip_hw_show_status(struct device *dev,
|
|
|
struct device_attribute *attr,
|
|
|
char *buf)
|
|
|
{
|
|
|
- u32 group_allocated;
|
|
|
struct driver_data *dd = dev_to_disk(dev)->private_data;
|
|
|
int size = 0;
|
|
|
+
|
|
|
+ if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))
|
|
|
+ size += sprintf(buf, "%s", "thermal_shutdown\n");
|
|
|
+ else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag))
|
|
|
+ size += sprintf(buf, "%s", "write_protect\n");
|
|
|
+ else
|
|
|
+ size += sprintf(buf, "%s", "online\n");
|
|
|
+
|
|
|
+ return size;
|
|
|
+}
|
|
|
+
|
|
|
+static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
|
|
|
+
|
|
|
+static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
|
|
|
+ size_t len, loff_t *offset)
|
|
|
+{
|
|
|
+ struct driver_data *dd = (struct driver_data *)f->private_data;
|
|
|
+ char buf[MTIP_DFS_MAX_BUF_SIZE];
|
|
|
+ u32 group_allocated;
|
|
|
+ int size = *offset;
|
|
|
int n;
|
|
|
|
|
|
- size += sprintf(&buf[size], "Hardware\n--------\n");
|
|
|
- size += sprintf(&buf[size], "S ACTive : [ 0x");
|
|
|
+ if (!len || size)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (size < 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ size += sprintf(&buf[size], "H/ S ACTive : [ 0x");
|
|
|
|
|
|
for (n = dd->slot_groups-1; n >= 0; n--)
|
|
|
size += sprintf(&buf[size], "%08X ",
|
|
|
readl(dd->port->s_active[n]));
|
|
|
|
|
|
size += sprintf(&buf[size], "]\n");
|
|
|
- size += sprintf(&buf[size], "Command Issue : [ 0x");
|
|
|
+ size += sprintf(&buf[size], "H/ Command Issue : [ 0x");
|
|
|
|
|
|
for (n = dd->slot_groups-1; n >= 0; n--)
|
|
|
size += sprintf(&buf[size], "%08X ",
|
|
|
readl(dd->port->cmd_issue[n]));
|
|
|
|
|
|
size += sprintf(&buf[size], "]\n");
|
|
|
- size += sprintf(&buf[size], "Completed : [ 0x");
|
|
|
+ size += sprintf(&buf[size], "H/ Completed : [ 0x");
|
|
|
|
|
|
for (n = dd->slot_groups-1; n >= 0; n--)
|
|
|
size += sprintf(&buf[size], "%08X ",
|
|
|
readl(dd->port->completed[n]));
|
|
|
|
|
|
size += sprintf(&buf[size], "]\n");
|
|
|
- size += sprintf(&buf[size], "PORT IRQ STAT : [ 0x%08X ]\n",
|
|
|
+ size += sprintf(&buf[size], "H/ PORT IRQ STAT : [ 0x%08X ]\n",
|
|
|
readl(dd->port->mmio + PORT_IRQ_STAT));
|
|
|
- size += sprintf(&buf[size], "HOST IRQ STAT : [ 0x%08X ]\n",
|
|
|
+ size += sprintf(&buf[size], "H/ HOST IRQ STAT : [ 0x%08X ]\n",
|
|
|
readl(dd->mmio + HOST_IRQ_STAT));
|
|
|
size += sprintf(&buf[size], "\n");
|
|
|
|
|
|
- size += sprintf(&buf[size], "Local\n-----\n");
|
|
|
- size += sprintf(&buf[size], "Allocated : [ 0x");
|
|
|
+ size += sprintf(&buf[size], "L/ Allocated : [ 0x");
|
|
|
|
|
|
for (n = dd->slot_groups-1; n >= 0; n--) {
|
|
|
if (sizeof(long) > sizeof(u32))
|
|
@@ -2605,7 +2630,7 @@ static ssize_t mtip_hw_show_registers(struct device *dev,
|
|
|
}
|
|
|
size += sprintf(&buf[size], "]\n");
|
|
|
|
|
|
- size += sprintf(&buf[size], "Commands in Q: [ 0x");
|
|
|
+ size += sprintf(&buf[size], "L/ Commands in Q : [ 0x");
|
|
|
|
|
|
for (n = dd->slot_groups-1; n >= 0; n--) {
|
|
|
if (sizeof(long) > sizeof(u32))
|
|
@@ -2617,44 +2642,53 @@ static ssize_t mtip_hw_show_registers(struct device *dev,
|
|
|
}
|
|
|
size += sprintf(&buf[size], "]\n");
|
|
|
|
|
|
- return size;
|
|
|
+ *offset = size <= len ? size : len;
|
|
|
+ size = copy_to_user(ubuf, buf, *offset);
|
|
|
+ if (size)
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ return *offset;
|
|
|
}
|
|
|
|
|
|
-static ssize_t mtip_hw_show_status(struct device *dev,
|
|
|
- struct device_attribute *attr,
|
|
|
- char *buf)
|
|
|
+static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
|
|
|
+ size_t len, loff_t *offset)
|
|
|
{
|
|
|
- struct driver_data *dd = dev_to_disk(dev)->private_data;
|
|
|
- int size = 0;
|
|
|
+ struct driver_data *dd = (struct driver_data *)f->private_data;
|
|
|
+ char buf[MTIP_DFS_MAX_BUF_SIZE];
|
|
|
+ int size = *offset;
|
|
|
|
|
|
- if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))
|
|
|
- size += sprintf(buf, "%s", "thermal_shutdown\n");
|
|
|
- else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag))
|
|
|
- size += sprintf(buf, "%s", "write_protect\n");
|
|
|
- else
|
|
|
- size += sprintf(buf, "%s", "online\n");
|
|
|
-
|
|
|
- return size;
|
|
|
-}
|
|
|
+ if (!len || size)
|
|
|
+ return 0;
|
|
|
|
|
|
-static ssize_t mtip_hw_show_flags(struct device *dev,
|
|
|
- struct device_attribute *attr,
|
|
|
- char *buf)
|
|
|
-{
|
|
|
- struct driver_data *dd = dev_to_disk(dev)->private_data;
|
|
|
- int size = 0;
|
|
|
+ if (size < 0)
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
- size += sprintf(&buf[size], "Flag in port struct : [ %08lX ]\n",
|
|
|
+ size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n",
|
|
|
dd->port->flags);
|
|
|
- size += sprintf(&buf[size], "Flag in dd struct : [ %08lX ]\n",
|
|
|
+ size += sprintf(&buf[size], "Flag-dd : [ %08lX ]\n",
|
|
|
dd->dd_flag);
|
|
|
|
|
|
- return size;
|
|
|
+ *offset = size <= len ? size : len;
|
|
|
+ size = copy_to_user(ubuf, buf, *offset);
|
|
|
+ if (size)
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ return *offset;
|
|
|
}
|
|
|
|
|
|
-static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL);
|
|
|
-static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
|
|
|
-static DEVICE_ATTR(flags, S_IRUGO, mtip_hw_show_flags, NULL);
|
|
|
+static const struct file_operations mtip_regs_fops = {
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .open = simple_open,
|
|
|
+ .read = mtip_hw_read_registers,
|
|
|
+ .llseek = no_llseek,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct file_operations mtip_flags_fops = {
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .open = simple_open,
|
|
|
+ .read = mtip_hw_read_flags,
|
|
|
+ .llseek = no_llseek,
|
|
|
+};
|
|
|
|
|
|
/*
|
|
|
* Create the sysfs related attributes.
|
|
@@ -2671,15 +2705,9 @@ static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj)
|
|
|
if (!kobj || !dd)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (sysfs_create_file(kobj, &dev_attr_registers.attr))
|
|
|
- dev_warn(&dd->pdev->dev,
|
|
|
- "Error creating 'registers' sysfs entry\n");
|
|
|
if (sysfs_create_file(kobj, &dev_attr_status.attr))
|
|
|
dev_warn(&dd->pdev->dev,
|
|
|
"Error creating 'status' sysfs entry\n");
|
|
|
- if (sysfs_create_file(kobj, &dev_attr_flags.attr))
|
|
|
- dev_warn(&dd->pdev->dev,
|
|
|
- "Error creating 'flags' sysfs entry\n");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2698,13 +2726,39 @@ static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj)
|
|
|
if (!kobj || !dd)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- sysfs_remove_file(kobj, &dev_attr_registers.attr);
|
|
|
sysfs_remove_file(kobj, &dev_attr_status.attr);
|
|
|
- sysfs_remove_file(kobj, &dev_attr_flags.attr);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int mtip_hw_debugfs_init(struct driver_data *dd)
|
|
|
+{
|
|
|
+ if (!dfs_parent)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ dd->dfs_node = debugfs_create_dir(dd->disk->disk_name, dfs_parent);
|
|
|
+ if (IS_ERR_OR_NULL(dd->dfs_node)) {
|
|
|
+ dev_warn(&dd->pdev->dev,
|
|
|
+ "Error creating node %s under debugfs\n",
|
|
|
+ dd->disk->disk_name);
|
|
|
+ dd->dfs_node = NULL;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ debugfs_create_file("flags", S_IRUGO, dd->dfs_node, dd,
|
|
|
+ &mtip_flags_fops);
|
|
|
+ debugfs_create_file("registers", S_IRUGO, dd->dfs_node, dd,
|
|
|
+ &mtip_regs_fops);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void mtip_hw_debugfs_exit(struct driver_data *dd)
|
|
|
+{
|
|
|
+ debugfs_remove_recursive(dd->dfs_node);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* Perform any init/resume time hardware setup
|
|
|
*
|
|
@@ -3730,6 +3784,7 @@ skip_create_disk:
|
|
|
mtip_hw_sysfs_init(dd, kobj);
|
|
|
kobject_put(kobj);
|
|
|
}
|
|
|
+ mtip_hw_debugfs_init(dd);
|
|
|
|
|
|
if (dd->mtip_svc_handler) {
|
|
|
set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag);
|
|
@@ -3755,6 +3810,8 @@ start_service_thread:
|
|
|
return rv;
|
|
|
|
|
|
kthread_run_error:
|
|
|
+ mtip_hw_debugfs_exit(dd);
|
|
|
+
|
|
|
/* Delete our gendisk. This also removes the device from /dev */
|
|
|
del_gendisk(dd->disk);
|
|
|
|
|
@@ -3805,6 +3862,7 @@ static int mtip_block_remove(struct driver_data *dd)
|
|
|
kobject_put(kobj);
|
|
|
}
|
|
|
}
|
|
|
+ mtip_hw_debugfs_exit(dd);
|
|
|
|
|
|
/*
|
|
|
* Delete our gendisk structure. This also removes the device
|
|
@@ -4152,10 +4210,20 @@ static int __init mtip_init(void)
|
|
|
}
|
|
|
mtip_major = error;
|
|
|
|
|
|
+ if (!dfs_parent) {
|
|
|
+ dfs_parent = debugfs_create_dir("rssd", NULL);
|
|
|
+ if (IS_ERR_OR_NULL(dfs_parent)) {
|
|
|
+ printk(KERN_WARNING "Error creating debugfs parent\n");
|
|
|
+ dfs_parent = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/* Register our PCI operations. */
|
|
|
error = pci_register_driver(&mtip_pci_driver);
|
|
|
- if (error)
|
|
|
+ if (error) {
|
|
|
+ debugfs_remove(dfs_parent);
|
|
|
unregister_blkdev(mtip_major, MTIP_DRV_NAME);
|
|
|
+ }
|
|
|
|
|
|
return error;
|
|
|
}
|
|
@@ -4172,6 +4240,8 @@ static int __init mtip_init(void)
|
|
|
*/
|
|
|
static void __exit mtip_exit(void)
|
|
|
{
|
|
|
+ debugfs_remove_recursive(dfs_parent);
|
|
|
+
|
|
|
/* Release the allocated major block device number. */
|
|
|
unregister_blkdev(mtip_major, MTIP_DRV_NAME);
|
|
|
|