#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)
  * 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);
 
 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;
+
+       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], "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], "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], "H/ PORT IRQ STAT : [ 0x%08X ]\n",
+                               readl(dd->port->mmio + PORT_IRQ_STAT));
+       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], "L/ Allocated     : [ 0x");
+
+       for (n = dd->slot_groups-1; n >= 0; n--) {
+               if (sizeof(long) > sizeof(u32))
+                       group_allocated =
+                               dd->port->allocated[n/2] >> (32*(n&1));
+               else
+                       group_allocated = dd->port->allocated[n];
+               size += sprintf(&buf[size], "%08X ", group_allocated);
+       }
+       size += sprintf(&buf[size], "]\n");
+
+       size += sprintf(&buf[size], "L/ Commands in Q : [ 0x");
+
+       for (n = dd->slot_groups-1; n >= 0; n--) {
+               if (sizeof(long) > sizeof(u32))
+                       group_allocated =
+                               dd->port->cmds_to_issue[n/2] >> (32*(n&1));
+               else
+                       group_allocated = dd->port->cmds_to_issue[n];
+               size += sprintf(&buf[size], "%08X ", group_allocated);
+       }
+       size += sprintf(&buf[size], "]\n");
+
+       *offset = size <= len ? size : len;
+       size = copy_to_user(ubuf, buf, *offset);
+       if (size)
+               return -EFAULT;
+
+       return *offset;
+}
+
+static ssize_t mtip_hw_read_flags(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];
+       int size = *offset;
+
+       if (!len || size)
+               return 0;
+
+       if (size < 0)
+               return -EINVAL;
+
+       size += sprintf(&buf[size], "Flag-port : [ %08lX ]\n",
+                                                       dd->port->flags);
+       size += sprintf(&buf[size], "Flag-dd   : [ %08lX ]\n",
+                                                       dd->dd_flag);
+
+       *offset = size <= len ? size : len;
+       size = copy_to_user(ubuf, buf, *offset);
+       if (size)
+               return -EFAULT;
+
+       return *offset;
+}
+
+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.
  *
        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
  *
                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);
        return rv;
 
 kthread_run_error:
+       mtip_hw_debugfs_exit(dd);
+
        /* Delete our gendisk. This also removes the device from /dev */
        del_gendisk(dd->disk);
 
                        kobject_put(kobj);
                }
        }
+       mtip_hw_debugfs_exit(dd);
 
        /*
         * Delete our gendisk structure. This also removes the device
        }
        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;
 }
  */
 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);