trivial: fix typo "to to" in multiple files
[safe/jmp/linux-2.6] / drivers / scsi / megaraid / megaraid_sas.c
index a8c9627..a39addc 100644 (file)
@@ -2,7 +2,7 @@
  *
  *             Linux MegaRAID driver for SAS based RAID controllers
  *
- * Copyright (c) 2003-2005  LSI Logic Corporation.
+ * Copyright (c) 2003-2005  LSI Corporation.
  *
  *        This program is free software; you can redistribute it and/or
  *        modify it under the terms of the GNU General Public License
  *        2 of the License, or (at your option) any later version.
  *
  * FILE                : megaraid_sas.c
- * Version     : v00.00.03.01
+ * Version     : v00.00.04.01-rc1
  *
  * Authors:
- *     Sreenivas Bagalkote     <Sreenivas.Bagalkote@lsil.com>
- *     Sumant Patro            <Sumant.Patro@lsil.com>
+ *     (email-id : megaraidlinux@lsi.com)
+ *     Sreenivas Bagalkote
+ *     Sumant Patro
+ *     Bo Yang
  *
  * List of supported controllers
  *
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
 #include <linux/uio.h>
 #include <asm/uaccess.h>
 #include <linux/fs.h>
 #include <linux/compat.h>
+#include <linux/blkdev.h>
 #include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include "megaraid_sas.h"
 
+/*
+ * poll_mode_io:1- schedule complete completion from q cmd
+ */
+static unsigned int poll_mode_io;
+module_param_named(poll_mode_io, poll_mode_io, int, 0);
+MODULE_PARM_DESC(poll_mode_io,
+       "Complete cmds from IO path, (default=0)");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
-MODULE_AUTHOR("sreenivas.bagalkote@lsil.com");
-MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
+MODULE_AUTHOR("megaraidlinux@lsi.com");
+MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
 
 /*
  * PCI ID table for all supported controllers
  */
 static struct pci_device_id megasas_pci_table[] = {
 
-       {
-        PCI_VENDOR_ID_LSI_LOGIC,
-        PCI_DEVICE_ID_LSI_SAS1064R, /* xscale IOP */
-        PCI_ANY_ID,
-        PCI_ANY_ID,
-        },
-       {
-        PCI_VENDOR_ID_LSI_LOGIC,
-        PCI_DEVICE_ID_LSI_SAS1078R, /* ppc IOP */
-        PCI_ANY_ID,
-        PCI_ANY_ID,
-       },
-       {
-        PCI_VENDOR_ID_LSI_LOGIC,
-        PCI_DEVICE_ID_LSI_VERDE_ZCR,   /* xscale IOP, vega */
-        PCI_ANY_ID,
-        PCI_ANY_ID,
-        },
-       {
-        PCI_VENDOR_ID_DELL,
-        PCI_DEVICE_ID_DELL_PERC5, /* xscale IOP */
-        PCI_ANY_ID,
-        PCI_ANY_ID,
-        },
-       {0}                     /* Terminating entry */
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)},
+       /* xscale IOP */
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)},
+       /* ppc IOP */
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078DE)},
+       /* ppc IOP */
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078GEN2)},
+       /* gen2*/
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0079GEN2)},
+       /* gen2*/
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
+       /* xscale IOP, vega */
+       {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
+       /* xscale IOP */
+       {}
 };
 
 MODULE_DEVICE_TABLE(pci, megasas_pci_table);
@@ -87,6 +89,12 @@ static struct megasas_mgmt_info megasas_mgmt_info;
 static struct fasync_struct *megasas_async_queue;
 static DEFINE_MUTEX(megasas_async_queue_mutex);
 
+static u32 megasas_dbg_lvl;
+
+static void
+megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+                    u8 alt_status);
+
 /**
  * megasas_get_cmd -   Get a command from the free pool
  * @instance:          Adapter soft state
@@ -151,6 +159,19 @@ megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
 }
 
 /**
+ * megasas_disable_intr_xscale -Disables interrupt
+ * @regs:                      MFI register set
+ */
+static inline void
+megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs)
+{
+       u32 mask = 0x1f;
+       writel(mask, &regs->outbound_intr_mask);
+       /* Dummy readl to force pci flush */
+       readl(&regs->outbound_intr_mask);
+}
+
+/**
  * megasas_read_fw_status_reg_xscale - returns the current FW status value
  * @regs:                      MFI register set
  */
@@ -181,6 +202,9 @@ megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
         */
        writel(status, &regs->outbound_intr_status);
 
+       /* Dummy readl to force pci flush */
+       readl(&regs->outbound_intr_status);
+
        return 0;
 }
 
@@ -201,6 +225,7 @@ static struct megasas_instance_template megasas_instance_template_xscale = {
 
        .fire_cmd = megasas_fire_cmd_xscale,
        .enable_intr = megasas_enable_intr_xscale,
+       .disable_intr = megasas_disable_intr_xscale,
        .clear_intr = megasas_clear_intr_xscale,
        .read_fw_status_reg = megasas_read_fw_status_reg_xscale,
 };
@@ -231,6 +256,19 @@ megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
 }
 
 /**
+ * megasas_disable_intr_ppc -  Disable interrupt
+ * @regs:                      MFI register set
+ */
+static inline void
+megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs)
+{
+       u32 mask = 0xFFFFFFFF;
+       writel(mask, &regs->outbound_intr_mask);
+       /* Dummy readl to force pci flush */
+       readl(&regs->outbound_intr_mask);
+}
+
+/**
  * megasas_read_fw_status_reg_ppc - returns the current FW status value
  * @regs:                      MFI register set
  */
@@ -262,6 +300,9 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
         */
        writel(status, &regs->outbound_doorbell_clear);
 
+       /* Dummy readl to force pci flush */
+       readl(&regs->outbound_doorbell_clear);
+
        return 0;
 }
 /**
@@ -281,35 +322,110 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
        
        .fire_cmd = megasas_fire_cmd_ppc,
        .enable_intr = megasas_enable_intr_ppc,
+       .disable_intr = megasas_disable_intr_ppc,
        .clear_intr = megasas_clear_intr_ppc,
        .read_fw_status_reg = megasas_read_fw_status_reg_ppc,
 };
 
 /**
-*      This is the end of set of functions & definitions
-*      specific to ppc (deviceid : 0x60) controllers
+*      The following functions are defined for gen2 (deviceid : 0x78 0x79)
+*      controllers
 */
 
 /**
- * megasas_disable_intr -      Disables interrupts
- * @regs:                      MFI register set
+ * megasas_enable_intr_gen2 -  Enables interrupts
+ * @regs:                      MFI register set
  */
 static inline void
-megasas_disable_intr(struct megasas_instance *instance)
+megasas_enable_intr_gen2(struct megasas_register_set __iomem *regs)
 {
-       u32 mask = 0x1f; 
-       struct megasas_register_set __iomem *regs = instance->reg_set;
+       writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
 
-       if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R)
-               mask = 0xffffffff;
+       /* write ~0x00000005 (4 & 1) to the intr mask*/
+       writel(~MFI_GEN2_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
 
-       writel(mask, &regs->outbound_intr_mask);
+       /* Dummy readl to force pci flush */
+       readl(&regs->outbound_intr_mask);
+}
 
+/**
+ * megasas_disable_intr_gen2 - Disables interrupt
+ * @regs:                      MFI register set
+ */
+static inline void
+megasas_disable_intr_gen2(struct megasas_register_set __iomem *regs)
+{
+       u32 mask = 0xFFFFFFFF;
+       writel(mask, &regs->outbound_intr_mask);
        /* Dummy readl to force pci flush */
        readl(&regs->outbound_intr_mask);
 }
 
 /**
+ * megasas_read_fw_status_reg_gen2 - returns the current FW status value
+ * @regs:                      MFI register set
+ */
+static u32
+megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem *regs)
+{
+       return readl(&(regs)->outbound_scratch_pad);
+}
+
+/**
+ * megasas_clear_interrupt_gen2 -      Check & clear interrupt
+ * @regs:                              MFI register set
+ */
+static int
+megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
+{
+       u32 status;
+       /*
+        * Check if it is our interrupt
+        */
+       status = readl(&regs->outbound_intr_status);
+
+       if (!(status & MFI_GEN2_ENABLE_INTERRUPT_MASK))
+               return 1;
+
+       /*
+        * Clear the interrupt by writing back the same value
+        */
+       writel(status, &regs->outbound_doorbell_clear);
+
+       /* Dummy readl to force pci flush */
+       readl(&regs->outbound_intr_status);
+
+       return 0;
+}
+/**
+ * megasas_fire_cmd_gen2 -     Sends command to the FW
+ * @frame_phys_addr :          Physical address of cmd
+ * @frame_count :              Number of frames for the command
+ * @regs :                     MFI register set
+ */
+static inline void
+megasas_fire_cmd_gen2(dma_addr_t frame_phys_addr, u32 frame_count,
+                       struct megasas_register_set __iomem *regs)
+{
+       writel((frame_phys_addr | (frame_count<<1))|1,
+                       &(regs)->inbound_queue_port);
+}
+
+static struct megasas_instance_template megasas_instance_template_gen2 = {
+
+       .fire_cmd = megasas_fire_cmd_gen2,
+       .enable_intr = megasas_enable_intr_gen2,
+       .disable_intr = megasas_disable_intr_gen2,
+       .clear_intr = megasas_clear_intr_gen2,
+       .read_fw_status_reg = megasas_read_fw_status_reg_gen2,
+};
+
+/**
+*      This is the end of set of functions & definitions
+*      specific to ppc (deviceid : 0x60) controllers
+*/
+
+/**
  * megasas_issue_polled -      Issues a polling command
  * @instance:                  Adapter soft state
  * @cmd:                       Command packet to be issued 
@@ -352,6 +468,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
  * @cmd:                       Command to be issued
  *
  * This function waits on an event for the command to be returned from ISR.
+ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
  * Used to issue ioctl commands.
  */
 static int
@@ -362,7 +479,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
 
        instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
 
-       wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));
+       wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
+               MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
 
        return 0;
 }
@@ -374,7 +492,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
  *
  * MFI firmware can abort previously issued AEN comamnd (automatic event
  * notification). The megasas_issue_blocked_abort_cmd() issues such abort
- * cmd and blocks till it is completed.
+ * cmd and waits for return status.
+ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
  */
 static int
 megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
@@ -408,7 +527,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
        /*
         * Wait for this cmd to complete
         */
-       wait_event(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF));
+       wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),
+               MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
 
        megasas_return_cmd(instance, cmd);
        return 0;
@@ -431,34 +551,15 @@ megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
        int sge_count;
        struct scatterlist *os_sgl;
 
-       /*
-        * Return 0 if there is no data transfer
-        */
-       if (!scp->request_buffer || !scp->request_bufflen)
-               return 0;
-
-       if (!scp->use_sg) {
-               mfi_sgl->sge32[0].phys_addr = pci_map_single(instance->pdev,
-                                                            scp->
-                                                            request_buffer,
-                                                            scp->
-                                                            request_bufflen,
-                                                            scp->
-                                                            sc_data_direction);
-               mfi_sgl->sge32[0].length = scp->request_bufflen;
-
-               return 1;
-       }
-
-       os_sgl = (struct scatterlist *)scp->request_buffer;
-       sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,
-                              scp->sc_data_direction);
+       sge_count = scsi_dma_map(scp);
+       BUG_ON(sge_count < 0);
 
-       for (i = 0; i < sge_count; i++, os_sgl++) {
-               mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);
-               mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);
+       if (sge_count) {
+               scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+                       mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);
+                       mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);
+               }
        }
-
        return sge_count;
 }
 
@@ -479,36 +580,66 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
        int sge_count;
        struct scatterlist *os_sgl;
 
-       /*
-        * Return 0 if there is no data transfer
-        */
-       if (!scp->request_buffer || !scp->request_bufflen)
-               return 0;
+       sge_count = scsi_dma_map(scp);
+       BUG_ON(sge_count < 0);
 
-       if (!scp->use_sg) {
-               mfi_sgl->sge64[0].phys_addr = pci_map_single(instance->pdev,
-                                                            scp->
-                                                            request_buffer,
-                                                            scp->
-                                                            request_bufflen,
-                                                            scp->
-                                                            sc_data_direction);
+       if (sge_count) {
+               scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+                       mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);
+                       mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);
+               }
+       }
+       return sge_count;
+}
 
-               mfi_sgl->sge64[0].length = scp->request_bufflen;
+ /**
+ * megasas_get_frame_count - Computes the number of frames
+ * @frame_type         : type of frame- io or pthru frame
+ * @sge_count          : number of sg elements
+ *
+ * Returns the number of frames required for numnber of sge's (sge_count)
+ */
 
-               return 1;
+static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
+{
+       int num_cnt;
+       int sge_bytes;
+       u32 sge_sz;
+       u32 frame_count=0;
+
+       sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+           sizeof(struct megasas_sge32);
+
+       /*
+        * Main frame can contain 2 SGEs for 64-bit SGLs and
+        * 3 SGEs for 32-bit SGLs for ldio &
+        * 1 SGEs for 64-bit SGLs and
+        * 2 SGEs for 32-bit SGLs for pthru frame
+        */
+       if (unlikely(frame_type == PTHRU_FRAME)) {
+               if (IS_DMA64)
+                       num_cnt = sge_count - 1;
+               else
+                       num_cnt = sge_count - 2;
+       } else {
+               if (IS_DMA64)
+                       num_cnt = sge_count - 2;
+               else
+                       num_cnt = sge_count - 3;
        }
 
-       os_sgl = (struct scatterlist *)scp->request_buffer;
-       sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,
-                              scp->sc_data_direction);
+       if(num_cnt>0){
+               sge_bytes = sge_sz * num_cnt;
 
-       for (i = 0; i < sge_count; i++, os_sgl++) {
-               mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);
-               mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);
+               frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
+                   ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
        }
+       /* Main frame */
+       frame_count +=1;
 
-       return sge_count;
+       if (frame_count > 7)
+               frame_count = 8;
+       return frame_count;
 }
 
 /**
@@ -524,8 +655,6 @@ static int
 megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
                   struct megasas_cmd *cmd)
 {
-       u32 sge_sz;
-       int sge_bytes;
        u32 is_logical;
        u32 device_id;
        u16 flags = 0;
@@ -553,16 +682,13 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
        pthru->cdb_len = scp->cmd_len;
        pthru->timeout = 0;
        pthru->flags = flags;
-       pthru->data_xfer_len = scp->request_bufflen;
+       pthru->data_xfer_len = scsi_bufflen(scp);
 
        memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
 
        /*
         * Construct SGL
         */
-       sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
-           sizeof(struct megasas_sge32);
-
        if (IS_DMA64) {
                pthru->flags |= MFI_FRAME_SGL64;
                pthru->sge_count = megasas_make_sgl64(instance, scp,
@@ -578,17 +704,12 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
        pthru->sense_buf_phys_addr_hi = 0;
        pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
 
-       sge_bytes = sge_sz * pthru->sge_count;
-
        /*
         * Compute the total number of frames this command consumes. FW uses
         * this number to pull sufficient number of frames from host memory.
         */
-       cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
-           ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
-
-       if (cmd->frame_count > 7)
-               cmd->frame_count = 8;
+       cmd->frame_count = megasas_get_frame_count(pthru->sge_count,
+                                                       PTHRU_FRAME);
 
        return cmd->frame_count;
 }
@@ -597,7 +718,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
  * megasas_build_ldio -        Prepares IOs to logical devices
  * @instance:          Adapter soft state
  * @scp:               SCSI command
- * @cmd:               Command to to be prepared
+ * @cmd:               Command to be prepared
  *
  * Frames (and accompanying SGLs) for regular SCSI IOs use this function.
  */
@@ -605,8 +726,6 @@ static int
 megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
                   struct megasas_cmd *cmd)
 {
-       u32 sge_sz;
-       int sge_bytes;
        u32 device_id;
        u8 sc = scp->cmnd[0];
        u16 flags = 0;
@@ -621,7 +740,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
                flags = MFI_FRAME_DIR_READ;
 
        /*
-        * Preare the Logical IO frame: 2nd bit is zero for all read cmds
+        * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
         */
        ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
        ldio->cmd_status = 0x0;
@@ -690,9 +809,6 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
        /*
         * Construct SGL
         */
-       sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
-           sizeof(struct megasas_sge32);
-
        if (IS_DMA64) {
                ldio->flags |= MFI_FRAME_SGL64;
                ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
@@ -706,13 +822,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
        ldio->sense_buf_phys_addr_hi = 0;
        ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
 
-       sge_bytes = sge_sz * ldio->sge_count;
-
-       cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
-           ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
-
-       if (cmd->frame_count > 7)
-               cmd->frame_count = 8;
+       /*
+        * Compute the total number of frames this command consumes. FW uses
+        * this number to pull sufficient number of frames from host memory.
+        */
+       cmd->frame_count = megasas_get_frame_count(ldio->sge_count, IO_FRAME);
 
        return cmd->frame_count;
 }
@@ -743,6 +857,69 @@ static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
        }
 }
 
+ /**
+ * megasas_dump_pending_frames -       Dumps the frame address of all pending cmds
+ *                                     in FW
+ * @instance:                          Adapter soft state
+ */
+static inline void
+megasas_dump_pending_frames(struct megasas_instance *instance)
+{
+       struct megasas_cmd *cmd;
+       int i,n;
+       union megasas_sgl *mfi_sgl;
+       struct megasas_io_frame *ldio;
+       struct megasas_pthru_frame *pthru;
+       u32 sgcount;
+       u32 max_cmd = instance->max_fw_cmds;
+
+       printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
+       printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
+       if (IS_DMA64)
+               printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
+       else
+               printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
+
+       printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no);
+       for (i = 0; i < max_cmd; i++) {
+               cmd = instance->cmd_list[i];
+               if(!cmd->scmd)
+                       continue;
+               printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
+               if (megasas_is_ldio(cmd->scmd)){
+                       ldio = (struct megasas_io_frame *)cmd->frame;
+                       mfi_sgl = &ldio->sgl;
+                       sgcount = ldio->sge_count;
+                       printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);
+               }
+               else {
+                       pthru = (struct megasas_pthru_frame *) cmd->frame;
+                       mfi_sgl = &pthru->sgl;
+                       sgcount = pthru->sge_count;
+                       printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);
+               }
+       if(megasas_dbg_lvl & MEGASAS_DBG_LVL){
+               for (n = 0; n < sgcount; n++){
+                       if (IS_DMA64)
+                               printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;
+                       else
+                               printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;
+                       }
+               }
+               printk(KERN_ERR "\n");
+       } /*for max_cmd*/
+       printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
+       for (i = 0; i < max_cmd; i++) {
+
+               cmd = instance->cmd_list[i];
+
+               if(cmd->sync_cmd == 1){
+                       printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
+               }
+       }
+       printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
+}
+
 /**
  * megasas_queue_command -     Queue entry point
  * @scmd:                      SCSI command to be queued
@@ -757,6 +934,11 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
 
        instance = (struct megasas_instance *)
            scmd->device->host->hostdata;
+
+       /* Don't process if we have already declared adapter dead */
+       if (instance->hw_crit_error)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
        scmd->scsi_done = done;
        scmd->result = 0;
 
@@ -766,6 +948,18 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
                goto out_done;
        }
 
+       switch (scmd->cmnd[0]) {
+       case SYNCHRONIZE_CACHE:
+               /*
+                * FW takes care of flush cache on its own
+                * No need to send it down
+                */
+               scmd->result = DID_OK << 16;
+               goto out_done;
+       default:
+               break;
+       }
+
        cmd = megasas_get_cmd(instance);
        if (!cmd)
                return SCSI_MLQUEUE_HOST_BUSY;
@@ -782,6 +976,7 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
                goto out_return_cmd;
 
        cmd->scmd = scmd;
+       scmd->SCp.ptr = (char *)cmd;
 
        /*
         * Issue the command to the FW
@@ -789,6 +984,12 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
        atomic_inc(&instance->fw_outstanding);
 
        instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
+       /*
+        * Check if we have pend cmds to be completed
+        */
+       if (poll_mode_io && atomic_read(&instance->fw_outstanding))
+               tasklet_schedule(&instance->isr_tasklet);
+
 
        return 0;
 
@@ -815,11 +1016,70 @@ static int megasas_slave_configure(struct scsi_device *sdev)
         * The RAID firmware may require extended timeouts.
         */
        if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS)
-               sdev->timeout = 90 * HZ;
+               blk_queue_rq_timeout(sdev->request_queue,
+                                    MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
        return 0;
 }
 
 /**
+ * megasas_complete_cmd_dpc     -      Returns FW's controller structure
+ * @instance_addr:                     Address of adapter soft state
+ *
+ * Tasklet to complete cmds
+ */
+static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+{
+       u32 producer;
+       u32 consumer;
+       u32 context;
+       struct megasas_cmd *cmd;
+       struct megasas_instance *instance =
+                               (struct megasas_instance *)instance_addr;
+       unsigned long flags;
+
+       /* If we have already declared adapter dead, donot complete cmds */
+       if (instance->hw_crit_error)
+               return;
+
+       spin_lock_irqsave(&instance->completion_lock, flags);
+
+       producer = *instance->producer;
+       consumer = *instance->consumer;
+
+       while (consumer != producer) {
+               context = instance->reply_queue[consumer];
+
+               cmd = instance->cmd_list[context];
+
+               megasas_complete_cmd(instance, cmd, DID_OK);
+
+               consumer++;
+               if (consumer == (instance->max_fw_cmds + 1)) {
+                       consumer = 0;
+               }
+       }
+
+       *instance->consumer = producer;
+
+       spin_unlock_irqrestore(&instance->completion_lock, flags);
+
+       /*
+        * Check if we can restore can_queue
+        */
+       if (instance->flag & MEGASAS_FW_BUSY
+               && time_after(jiffies, instance->last_time + 5 * HZ)
+               && atomic_read(&instance->fw_outstanding) < 17) {
+
+               spin_lock_irqsave(instance->host->host_lock, flags);
+               instance->flag &= ~MEGASAS_FW_BUSY;
+               instance->host->can_queue =
+                               instance->max_fw_cmds - MEGASAS_INT_CMDS;
+
+               spin_unlock_irqrestore(instance->host->host_lock, flags);
+       }
+}
+
+/**
  * megasas_wait_for_outstanding -      Wait for all outstanding cmds
  * @instance:                          Adapter soft state
  *
@@ -842,12 +1102,24 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
                if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
                        printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
                               "commands to complete\n",i,outstanding);
+                       /*
+                        * Call cmd completion routine. Cmd to be
+                        * be completed directly without depending on isr.
+                        */
+                       megasas_complete_cmd_dpc((unsigned long)instance);
                }
 
                msleep(1000);
        }
 
        if (atomic_read(&instance->fw_outstanding)) {
+               /*
+               * Send signal to FW to stop processing any pending cmds.
+               * The controller will be taken offline by the OS now.
+               */
+               writel(MFI_STOP_ADP,
+                               &instance->reg_set->inbound_doorbell);
+               megasas_dump_pending_frames(instance);
                instance->hw_crit_error = 1;
                return FAILED;
        }
@@ -870,8 +1142,8 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
 
        instance = (struct megasas_instance *)scmd->device->host->hostdata;
 
-       scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x\n",
-              scmd->serial_number, scmd->cmnd[0]);
+       scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n",
+                scmd->serial_number, scmd->cmnd[0], scmd->retries);
 
        if (instance->hw_crit_error) {
                printk(KERN_ERR "megasas: cannot recover from previous reset "
@@ -889,6 +1161,39 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
 }
 
 /**
+ * megasas_reset_timer - quiesce the adapter if required
+ * @scmd:              scsi cmnd
+ *
+ * Sets the FW busy flag and reduces the host->can_queue if the
+ * cmd has not been completed within the timeout period.
+ */
+static enum
+blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+{
+       struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
+       struct megasas_instance *instance;
+       unsigned long flags;
+
+       if (time_after(jiffies, scmd->jiffies_at_alloc +
+                               (MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
+               return BLK_EH_NOT_HANDLED;
+       }
+
+       instance = cmd->instance;
+       if (!(instance->flag & MEGASAS_FW_BUSY)) {
+               /* FW is busy, throttle IO */
+               spin_lock_irqsave(instance->host->host_lock, flags);
+
+               instance->host->can_queue = 16;
+               instance->last_time = jiffies;
+               instance->flag |= MEGASAS_FW_BUSY;
+
+               spin_unlock_irqrestore(instance->host->host_lock, flags);
+       }
+       return BLK_EH_RESET_TIMER;
+}
+
+/**
  * megasas_reset_device -      Device reset handler entry point
  */
 static int megasas_reset_device(struct scsi_cmnd *scmd)
@@ -919,6 +1224,49 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
 }
 
 /**
+ * megasas_bios_param - Returns disk geometry for a disk
+ * @sdev:              device handle
+ * @bdev:              block device
+ * @capacity:          drive capacity
+ * @geom:              geometry parameters
+ */
+static int
+megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+                sector_t capacity, int geom[])
+{
+       int heads;
+       int sectors;
+       sector_t cylinders;
+       unsigned long tmp;
+       /* Default heads (64) & sectors (32) */
+       heads = 64;
+       sectors = 32;
+
+       tmp = heads * sectors;
+       cylinders = capacity;
+
+       sector_div(cylinders, tmp);
+
+       /*
+        * Handle extended translation size for logical drives > 1Gb
+        */
+
+       if (capacity >= 0x200000) {
+               heads = 255;
+               sectors = 63;
+               tmp = heads*sectors;
+               cylinders = capacity;
+               sector_div(cylinders, tmp);
+       }
+
+       geom[0] = heads;
+       geom[1] = sectors;
+       geom[2] = cylinders;
+
+       return 0;
+}
+
+/**
  * megasas_service_aen -       Processes an event notification
  * @instance:                  Adapter soft state
  * @cmd:                       AEN command completed by the ISR
@@ -951,13 +1299,15 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
 static struct scsi_host_template megasas_template = {
 
        .module = THIS_MODULE,
-       .name = "LSI Logic SAS based MegaRAID driver",
+       .name = "LSI SAS based MegaRAID driver",
        .proc_name = "megaraid_sas",
        .slave_configure = megasas_slave_configure,
        .queuecommand = megasas_queue_command,
        .eh_device_reset_handler = megasas_reset_device,
        .eh_bus_reset_handler = megasas_reset_bus_host,
        .eh_host_reset_handler = megasas_reset_bus_host,
+       .eh_timed_out = megasas_reset_timer,
+       .bios_param = megasas_bios_param,
        .use_clustering = ENABLE_CLUSTERING,
 };
 
@@ -1005,45 +1355,6 @@ megasas_complete_abort(struct megasas_instance *instance,
 }
 
 /**
- * megasas_unmap_sgbuf -       Unmap SG buffers
- * @instance:                  Adapter soft state
- * @cmd:                       Completed command
- */
-static void
-megasas_unmap_sgbuf(struct megasas_instance *instance, struct megasas_cmd *cmd)
-{
-       dma_addr_t buf_h;
-       u8 opcode;
-
-       if (cmd->scmd->use_sg) {
-               pci_unmap_sg(instance->pdev, cmd->scmd->request_buffer,
-                            cmd->scmd->use_sg, cmd->scmd->sc_data_direction);
-               return;
-       }
-
-       if (!cmd->scmd->request_bufflen)
-               return;
-
-       opcode = cmd->frame->hdr.cmd;
-
-       if ((opcode == MFI_CMD_LD_READ) || (opcode == MFI_CMD_LD_WRITE)) {
-               if (IS_DMA64)
-                       buf_h = cmd->frame->io.sgl.sge64[0].phys_addr;
-               else
-                       buf_h = cmd->frame->io.sgl.sge32[0].phys_addr;
-       } else {
-               if (IS_DMA64)
-                       buf_h = cmd->frame->pthru.sgl.sge64[0].phys_addr;
-               else
-                       buf_h = cmd->frame->pthru.sgl.sge32[0].phys_addr;
-       }
-
-       pci_unmap_single(instance->pdev, buf_h, cmd->scmd->request_bufflen,
-                        cmd->scmd->sc_data_direction);
-       return;
-}
-
-/**
  * megasas_complete_cmd -      Completes a command
  * @instance:                  Adapter soft state
  * @cmd:                       Command to be completed
@@ -1060,9 +1371,8 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
        int exception = 0;
        struct megasas_header *hdr = &cmd->frame->hdr;
 
-       if (cmd->scmd) {
-               cmd->scmd->SCp.ptr = (char *)0;
-       }
+       if (cmd->scmd)
+               cmd->scmd->SCp.ptr = NULL;
 
        switch (hdr->cmd) {
 
@@ -1092,7 +1402,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 
                        atomic_dec(&instance->fw_outstanding);
 
-                       megasas_unmap_sgbuf(instance, cmd);
+                       scsi_dma_unmap(cmd->scmd);
                        cmd->scmd->scsi_done(cmd->scmd);
                        megasas_return_cmd(instance, cmd);
 
@@ -1140,7 +1450,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 
                atomic_dec(&instance->fw_outstanding);
 
-               megasas_unmap_sgbuf(instance, cmd);
+               scsi_dma_unmap(cmd->scmd);
                cmd->scmd->scsi_done(cmd->scmd);
                megasas_return_cmd(instance, cmd);
 
@@ -1184,11 +1494,6 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 static int
 megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
 {
-       u32 producer;
-       u32 consumer;
-       u32 context;
-       struct megasas_cmd *cmd;
-
        /*
         * Check if it is our interrupt
         * Clear the interrupt 
@@ -1196,31 +1501,20 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
        if(instance->instancet->clear_intr(instance->reg_set))
                return IRQ_NONE;
 
-       producer = *instance->producer;
-       consumer = *instance->consumer;
-
-       while (consumer != producer) {
-               context = instance->reply_queue[consumer];
-
-               cmd = instance->cmd_list[context];
-
-               megasas_complete_cmd(instance, cmd, alt_status);
-
-               consumer++;
-               if (consumer == (instance->max_fw_cmds + 1)) {
-                       consumer = 0;
-               }
-       }
-
-       *instance->consumer = producer;
-
+       if (instance->hw_crit_error)
+               goto out_done;
+        /*
+        * Schedule the tasklet for cmd completion
+        */
+       tasklet_schedule(&instance->isr_tasklet);
+out_done:
        return IRQ_HANDLED;
 }
 
 /**
  * megasas_isr - isr entry point
  */
-static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
+static irqreturn_t megasas_isr(int irq, void *devp)
 {
        return megasas_deplete_reply_queue((struct megasas_instance *)devp,
                                           DID_OK);
@@ -1245,10 +1539,12 @@ megasas_transition_to_ready(struct megasas_instance* instance)
 
        fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
 
+       if (fw_state != MFI_STATE_READY)
+               printk(KERN_INFO "megasas: Waiting for FW to come to ready"
+                      " state\n");
+
        while (fw_state != MFI_STATE_READY) {
 
-               printk(KERN_INFO "megasas: Waiting for FW to come to ready"
-                      " state\n");
                switch (fw_state) {
 
                case MFI_STATE_FAULT:
@@ -1260,21 +1556,29 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                        /*
                         * Set the CLR bit in inbound doorbell
                         */
-                       writel(MFI_INIT_CLEAR_HANDSHAKE,
+                       writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
                                &instance->reg_set->inbound_doorbell);
 
                        max_wait = 2;
                        cur_state = MFI_STATE_WAIT_HANDSHAKE;
                        break;
 
+               case MFI_STATE_BOOT_MESSAGE_PENDING:
+                       writel(MFI_INIT_HOTPLUG,
+                               &instance->reg_set->inbound_doorbell);
+
+                       max_wait = 10;
+                       cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
+                       break;
+
                case MFI_STATE_OPERATIONAL:
                        /*
-                        * Bring it to READY state; assuming max wait 2 secs
+                        * Bring it to READY state; assuming max wait 10 secs
                         */
-                       megasas_disable_intr(instance);
-                       writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
+                       instance->instancet->disable_intr(instance->reg_set);
+                       writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
 
-                       max_wait = 10;
+                       max_wait = 60;
                        cur_state = MFI_STATE_OPERATIONAL;
                        break;
 
@@ -1339,6 +1643,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                        return -ENODEV;
                }
        };
+       printk(KERN_INFO "megasas: FW now in Ready state\n");
 
        return 0;
 }
@@ -1368,7 +1673,7 @@ static void megasas_teardown_frame_pool(struct megasas_instance *instance)
                                      cmd->frame_phys_addr);
 
                if (cmd->sense)
-                       pci_pool_free(instance->sense_dma_pool, cmd->frame,
+                       pci_pool_free(instance->sense_dma_pool, cmd->sense,
                                      cmd->sense_phys_addr);
        }
 
@@ -1530,15 +1835,13 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
         * Allocate the dynamic array first and then allocate individual
         * commands.
         */
-       instance->cmd_list = kmalloc(sizeof(struct megasas_cmd *) * max_cmd,
-                                    GFP_KERNEL);
+       instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL);
 
        if (!instance->cmd_list) {
                printk(KERN_DEBUG "megasas: out of memory\n");
                return -ENOMEM;
        }
 
-       memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) * max_cmd);
 
        for (i = 0; i < max_cmd; i++) {
                instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
@@ -1629,18 +1932,134 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
        dcmd->sgl.sge32[0].phys_addr = ci_h;
        dcmd->sgl.sge32[0].length = sizeof(struct megasas_ctrl_info);
 
-       if (!megasas_issue_polled(instance, cmd)) {
-               ret = 0;
-               memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));
-       } else {
-               ret = -1;
-       }
+       if (!megasas_issue_polled(instance, cmd)) {
+               ret = 0;
+               memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));
+       } else {
+               ret = -1;
+       }
+
+       pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
+                           ci, ci_h);
+
+       megasas_return_cmd(instance, cmd);
+       return ret;
+}
+
+/**
+ * megasas_issue_init_mfi -    Initializes the FW
+ * @instance:          Adapter soft state
+ *
+ * Issues the INIT MFI cmd
+ */
+static int
+megasas_issue_init_mfi(struct megasas_instance *instance)
+{
+       u32 context;
+
+       struct megasas_cmd *cmd;
+
+       struct megasas_init_frame *init_frame;
+       struct megasas_init_queue_info *initq_info;
+       dma_addr_t init_frame_h;
+       dma_addr_t initq_info_h;
+
+       /*
+        * Prepare a init frame. Note the init frame points to queue info
+        * structure. Each frame has SGL allocated after first 64 bytes. For
+        * this frame - since we don't need any SGL - we use SGL's space as
+        * queue info structure
+        *
+        * We will not get a NULL command below. We just created the pool.
+        */
+       cmd = megasas_get_cmd(instance);
+
+       init_frame = (struct megasas_init_frame *)cmd->frame;
+       initq_info = (struct megasas_init_queue_info *)
+               ((unsigned long)init_frame + 64);
+
+       init_frame_h = cmd->frame_phys_addr;
+       initq_info_h = init_frame_h + 64;
+
+       context = init_frame->context;
+       memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
+       memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
+       init_frame->context = context;
+
+       initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
+       initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
+
+       initq_info->producer_index_phys_addr_lo = instance->producer_h;
+       initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
+
+       init_frame->cmd = MFI_CMD_INIT;
+       init_frame->cmd_status = 0xFF;
+       init_frame->queue_info_new_phys_addr_lo = initq_info_h;
+
+       init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
+
+       /*
+        * disable the intr before firing the init frame to FW
+        */
+       instance->instancet->disable_intr(instance->reg_set);
+
+       /*
+        * Issue the init frame in polled mode
+        */
+
+       if (megasas_issue_polled(instance, cmd)) {
+               printk(KERN_ERR "megasas: Failed to init firmware\n");
+               megasas_return_cmd(instance, cmd);
+               goto fail_fw_init;
+       }
+
+       megasas_return_cmd(instance, cmd);
+
+       return 0;
+
+fail_fw_init:
+       return -EINVAL;
+}
+
+/**
+ * megasas_start_timer - Initializes a timer object
+ * @instance:          Adapter soft state
+ * @timer:             timer object to be initialized
+ * @fn:                        timer function
+ * @interval:          time interval between timer function call
+ */
+static inline void
+megasas_start_timer(struct megasas_instance *instance,
+                       struct timer_list *timer,
+                       void *fn, unsigned long interval)
+{
+       init_timer(timer);
+       timer->expires = jiffies + interval;
+       timer->data = (unsigned long)instance;
+       timer->function = fn;
+       add_timer(timer);
+}
+
+/**
+ * megasas_io_completion_timer - Timer fn
+ * @instance_addr:     Address of adapter soft state
+ *
+ * Schedules tasklet for cmd completion
+ * if poll_mode_io is set
+ */
+static void
+megasas_io_completion_timer(unsigned long instance_addr)
+{
+       struct megasas_instance *instance =
+                       (struct megasas_instance *)instance_addr;
 
-       pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
-                           ci, ci_h);
+       if (atomic_read(&instance->fw_outstanding))
+               tasklet_schedule(&instance->isr_tasklet);
 
-       megasas_return_cmd(instance, cmd);
-       return ret;
+       /* Restart timer */
+       if (poll_mode_io)
+               mod_timer(&instance->io_completion_timer,
+                       jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
 }
 
 /**
@@ -1655,22 +2074,20 @@ static int megasas_init_mfi(struct megasas_instance *instance)
        u32 reply_q_sz;
        u32 max_sectors_1;
        u32 max_sectors_2;
+       u32 tmp_sectors;
        struct megasas_register_set __iomem *reg_set;
-
-       struct megasas_cmd *cmd;
        struct megasas_ctrl_info *ctrl_info;
-
-       struct megasas_init_frame *init_frame;
-       struct megasas_init_queue_info *initq_info;
-       dma_addr_t init_frame_h;
-       dma_addr_t initq_info_h;
-
        /*
         * Map the message registers
         */
-       instance->base_addr = pci_resource_start(instance->pdev, 0);
+       if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0079GEN2)) {
+               instance->base_addr = pci_resource_start(instance->pdev, 1);
+       } else {
+               instance->base_addr = pci_resource_start(instance->pdev, 0);
+       }
 
-       if (pci_request_regions(instance->pdev, "megasas: LSI Logic")) {
+       if (pci_request_regions(instance->pdev, "megasas: LSI")) {
                printk(KERN_DEBUG "megasas: IO memory region busy!\n");
                return -EBUSY;
        }
@@ -1686,9 +2103,14 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 
        switch(instance->pdev->device)
        {
-               case PCI_DEVICE_ID_LSI_SAS1078R:        
+               case PCI_DEVICE_ID_LSI_SAS1078R:
+               case PCI_DEVICE_ID_LSI_SAS1078DE:
                        instance->instancet = &megasas_instance_template_ppc;
                        break;
+               case PCI_DEVICE_ID_LSI_SAS1078GEN2:
+               case PCI_DEVICE_ID_LSI_SAS0079GEN2:
+                       instance->instancet = &megasas_instance_template_gen2;
+                       break;
                case PCI_DEVICE_ID_LSI_SAS1064R:
                case PCI_DEVICE_ID_DELL_PERC5:
                default:
@@ -1706,6 +2128,12 @@ static int megasas_init_mfi(struct megasas_instance *instance)
         * Get various operational parameters from status register
         */
        instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+       /*
+        * Reduce the max supported cmds by 1. This is to ensure that the
+        * reply_q_sz (1 more than the max cmd that driver may send)
+        * does not exceed max cmds that the FW can support
+        */
+       instance->max_fw_cmds = instance->max_fw_cmds-1;
        instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >> 
                                        0x10;
        /*
@@ -1735,52 +2163,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
                goto fail_reply_queue;
        }
 
-       /*
-        * Prepare a init frame. Note the init frame points to queue info
-        * structure. Each frame has SGL allocated after first 64 bytes. For
-        * this frame - since we don't need any SGL - we use SGL's space as
-        * queue info structure
-        *
-        * We will not get a NULL command below. We just created the pool.
-        */
-       cmd = megasas_get_cmd(instance);
-
-       init_frame = (struct megasas_init_frame *)cmd->frame;
-       initq_info = (struct megasas_init_queue_info *)
-           ((unsigned long)init_frame + 64);
-
-       init_frame_h = cmd->frame_phys_addr;
-       initq_info_h = init_frame_h + 64;
-
-       memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
-       memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
-
-       initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
-       initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
-
-       initq_info->producer_index_phys_addr_lo = instance->producer_h;
-       initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
-
-       init_frame->cmd = MFI_CMD_INIT;
-       init_frame->cmd_status = 0xFF;
-       init_frame->queue_info_new_phys_addr_lo = initq_info_h;
-
-       init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
-
-       /*
-        * disable the intr before firing the init frame to FW
-        */
-       megasas_disable_intr(instance);
-
-       /*
-        * Issue the init frame in polled mode
-        */
-       if (megasas_issue_polled(instance, cmd)) {
-               printk(KERN_DEBUG "megasas: Failed to init firmware\n");
+       if (megasas_issue_init_mfi(instance))
                goto fail_fw_init;
-       }
-
-       megasas_return_cmd(instance, cmd);
 
        ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
 
@@ -1793,24 +2177,38 @@ static int megasas_init_mfi(struct megasas_instance *instance)
         * Note that older firmwares ( < FW ver 30) didn't report information
         * to calculate max_sectors_1. So the number ended up as zero always.
         */
+       tmp_sectors = 0;
        if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) {
 
                max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
                    ctrl_info->max_strips_per_io;
                max_sectors_2 = ctrl_info->max_request_size;
 
-               instance->max_sectors_per_req = (max_sectors_1 < max_sectors_2)
-                   ? max_sectors_1 : max_sectors_2;
-       } else
-               instance->max_sectors_per_req = instance->max_num_sge *
-                   PAGE_SIZE / 512;
+               tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
+       }
+
+       instance->max_sectors_per_req = instance->max_num_sge *
+                                               PAGE_SIZE / 512;
+       if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
+               instance->max_sectors_per_req = tmp_sectors;
 
        kfree(ctrl_info);
 
+        /*
+       * Setup tasklet for cmd completion
+       */
+
+       tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+               (unsigned long)instance);
+
+       /* Initialize the cmd completion timer */
+       if (poll_mode_io)
+               megasas_start_timer(instance, &instance->io_completion_timer,
+                               megasas_io_completion_timer,
+                               MEGASAS_COMPLETION_TIMER_INTERVAL);
        return 0;
 
       fail_fw_init:
-       megasas_return_cmd(instance, cmd);
 
        pci_free_consistent(instance->pdev, reply_q_sz,
                            instance->reply_queue, instance->reply_queue_h);
@@ -2092,6 +2490,28 @@ static int megasas_io_attach(struct megasas_instance *instance)
        return 0;
 }
 
+static int
+megasas_set_dma_mask(struct pci_dev *pdev)
+{
+       /*
+        * All our contollers are capable of performing 64-bit DMA
+        */
+       if (IS_DMA64) {
+               if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
+
+                       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
+                               goto fail_set_dma_mask;
+               }
+       } else {
+               if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
+                       goto fail_set_dma_mask;
+       }
+       return 0;
+
+fail_set_dma_mask:
+       return 1;
+}
+
 /**
  * megasas_probe_one - PCI hotplug entry point
  * @pdev:              PCI device structure
@@ -2125,19 +2545,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        pci_set_master(pdev);
 
-       /*
-        * All our contollers are capable of performing 64-bit DMA
-        */
-       if (IS_DMA64) {
-               if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
-
-                       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
-                               goto fail_set_dma_mask;
-               }
-       } else {
-               if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
-                       goto fail_set_dma_mask;
-       }
+       if (megasas_set_dma_mask(pdev))
+               goto fail_set_dma_mask;
 
        host = scsi_host_alloc(&megasas_template,
                               sizeof(struct megasas_instance));
@@ -2186,8 +2595,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        init_waitqueue_head(&instance->abort_cmd_wait_q);
 
        spin_lock_init(&instance->cmd_pool_lock);
+       spin_lock_init(&instance->completion_lock);
 
-       sema_init(&instance->aen_mutex, 1);
+       mutex_init(&instance->aen_mutex);
        sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
 
        /*
@@ -2198,6 +2608,10 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
        instance->init_id = MEGASAS_DEFAULT_INIT_ID;
 
+       megasas_dbg_lvl = 0;
+       instance->flag = 0;
+       instance->last_time = 0;
+
        /*
         * Initialize MFI Firmware
         */
@@ -2250,7 +2664,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        megasas_mgmt_info.max_index--;
 
        pci_set_drvdata(pdev, NULL);
-       megasas_disable_intr(instance);
+       instance->instancet->disable_intr(instance->reg_set);
        free_irq(instance->pdev->irq, instance);
 
        megasas_release_mfi(instance);
@@ -2315,8 +2729,10 @@ static void megasas_flush_cache(struct megasas_instance *instance)
 /**
  * megasas_shutdown_controller -       Instructs FW to shutdown the controller
  * @instance:                          Adapter soft state
+ * @opcode:                            Shutdown/Hibernate
  */
-static void megasas_shutdown_controller(struct megasas_instance *instance)
+static void megasas_shutdown_controller(struct megasas_instance *instance,
+                                       u32 opcode)
 {
        struct megasas_cmd *cmd;
        struct megasas_dcmd_frame *dcmd;
@@ -2339,7 +2755,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance)
        dcmd->flags = MFI_FRAME_DIR_NONE;
        dcmd->timeout = 0;
        dcmd->data_xfer_len = 0;
-       dcmd->opcode = MR_DCMD_CTRL_SHUTDOWN;
+       dcmd->opcode = opcode;
 
        megasas_issue_blocked_cmd(instance, cmd);
 
@@ -2348,11 +2764,149 @@ static void megasas_shutdown_controller(struct megasas_instance *instance)
        return;
 }
 
+#ifdef CONFIG_PM
+/**
+ * megasas_suspend -   driver suspend entry point
+ * @pdev:              PCI device structure
+ * @state:             PCI power state to suspend routine
+ */
+static int
+megasas_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct Scsi_Host *host;
+       struct megasas_instance *instance;
+
+       instance = pci_get_drvdata(pdev);
+       host = instance->host;
+
+       if (poll_mode_io)
+               del_timer_sync(&instance->io_completion_timer);
+
+       megasas_flush_cache(instance);
+       megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
+       tasklet_kill(&instance->isr_tasklet);
+
+       pci_set_drvdata(instance->pdev, instance);
+       instance->instancet->disable_intr(instance->reg_set);
+       free_irq(instance->pdev->irq, instance);
+
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+/**
+ * megasas_resume-      driver resume entry point
+ * @pdev:               PCI device structure
+ */
+static int
+megasas_resume(struct pci_dev *pdev)
+{
+       int rval;
+       struct Scsi_Host *host;
+       struct megasas_instance *instance;
+
+       instance = pci_get_drvdata(pdev);
+       host = instance->host;
+       pci_set_power_state(pdev, PCI_D0);
+       pci_enable_wake(pdev, PCI_D0, 0);
+       pci_restore_state(pdev);
+
+       /*
+        * PCI prepping: enable device set bus mastering and dma mask
+        */
+       rval = pci_enable_device(pdev);
+
+       if (rval) {
+               printk(KERN_ERR "megasas: Enable device failed\n");
+               return rval;
+       }
+
+       pci_set_master(pdev);
+
+       if (megasas_set_dma_mask(pdev))
+               goto fail_set_dma_mask;
+
+       /*
+        * Initialize MFI Firmware
+        */
+
+       *instance->producer = 0;
+       *instance->consumer = 0;
+
+       atomic_set(&instance->fw_outstanding, 0);
+
+       /*
+        * We expect the FW state to be READY
+        */
+       if (megasas_transition_to_ready(instance))
+               goto fail_ready_state;
+
+       if (megasas_issue_init_mfi(instance))
+               goto fail_init_mfi;
+
+       tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+                       (unsigned long)instance);
+
+       /*
+        * Register IRQ
+        */
+       if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
+               "megasas", instance)) {
+               printk(KERN_ERR "megasas: Failed to register IRQ\n");
+               goto fail_irq;
+       }
+
+       instance->instancet->enable_intr(instance->reg_set);
+
+       /*
+        * Initiate AEN (Asynchronous Event Notification)
+        */
+       if (megasas_start_aen(instance))
+               printk(KERN_ERR "megasas: Start AEN failed\n");
+
+       /* Initialize the cmd completion timer */
+       if (poll_mode_io)
+               megasas_start_timer(instance, &instance->io_completion_timer,
+                               megasas_io_completion_timer,
+                               MEGASAS_COMPLETION_TIMER_INTERVAL);
+       return 0;
+
+fail_irq:
+fail_init_mfi:
+       if (instance->evt_detail)
+               pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+                               instance->evt_detail,
+                               instance->evt_detail_h);
+
+       if (instance->producer)
+               pci_free_consistent(pdev, sizeof(u32), instance->producer,
+                               instance->producer_h);
+       if (instance->consumer)
+               pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+                               instance->consumer_h);
+       scsi_host_put(host);
+
+fail_set_dma_mask:
+fail_ready_state:
+
+       pci_disable_device(pdev);
+
+       return -ENODEV;
+}
+#else
+#define megasas_suspend        NULL
+#define megasas_resume NULL
+#endif
+
 /**
  * megasas_detach_one -        PCI hot"un"plug entry point
  * @pdev:              PCI device structure
  */
-static void megasas_detach_one(struct pci_dev *pdev)
+static void __devexit megasas_detach_one(struct pci_dev *pdev)
 {
        int i;
        struct Scsi_Host *host;
@@ -2361,9 +2915,13 @@ static void megasas_detach_one(struct pci_dev *pdev)
        instance = pci_get_drvdata(pdev);
        host = instance->host;
 
+       if (poll_mode_io)
+               del_timer_sync(&instance->io_completion_timer);
+
        scsi_remove_host(instance->host);
        megasas_flush_cache(instance);
-       megasas_shutdown_controller(instance);
+       megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
+       tasklet_kill(&instance->isr_tasklet);
 
        /*
         * Take the instance off the instance array. Note that we will not
@@ -2380,7 +2938,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
 
        pci_set_drvdata(instance->pdev, NULL);
 
-       megasas_disable_intr(instance);
+       instance->instancet->disable_intr(instance->reg_set);
 
        free_irq(instance->pdev->irq, instance);
 
@@ -2412,6 +2970,7 @@ static void megasas_shutdown(struct pci_dev *pdev)
 {
        struct megasas_instance *instance = pci_get_drvdata(pdev);
        megasas_flush_cache(instance);
+       megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
 }
 
 /**
@@ -2419,6 +2978,7 @@ static void megasas_shutdown(struct pci_dev *pdev)
  */
 static int megasas_mgmt_open(struct inode *inode, struct file *filep)
 {
+       cycle_kernel_lock();
        /*
         * Allow only those users with admin rights
         */
@@ -2429,17 +2989,6 @@ static int megasas_mgmt_open(struct inode *inode, struct file *filep)
 }
 
 /**
- * megasas_mgmt_release - char node "release" entry point
- */
-static int megasas_mgmt_release(struct inode *inode, struct file *filep)
-{
-       filep->private_data = NULL;
-       fasync_helper(-1, filep, 0, &megasas_async_queue);
-
-       return 0;
-}
-
-/**
  * megasas_mgmt_fasync -       Async notifier registration from applications
  *
  * This function adds the calling process to a driver global queue. When an
@@ -2523,9 +3072,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
         * For each user buffer, create a mirror buffer and copy in
         */
        for (i = 0; i < ioc->sge_count; i++) {
-               kbuff_arr[i] = pci_alloc_consistent(instance->pdev,
+               kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev,
                                                    ioc->sgl[i].iov_len,
-                                                   &buf_handle);
+                                                   &buf_handle, GFP_KERNEL);
                if (!kbuff_arr[i]) {
                        printk(KERN_DEBUG "megasas: Failed to alloc "
                               "kernel SGL buffer for IOCTL \n");
@@ -2552,8 +3101,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
        }
 
        if (ioc->sense_len) {
-               sense = pci_alloc_consistent(instance->pdev, ioc->sense_len,
-                                            &sense_handle);
+               sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len,
+                                            &sense_handle, GFP_KERNEL);
                if (!sense) {
                        error = -ENOMEM;
                        goto out;
@@ -2596,6 +3145,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
 
                if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
                                 sense, ioc->sense_len)) {
+                       printk(KERN_ERR "megasas: Failed to copy out to user "
+                                       "sense data\n");
                        error = -EFAULT;
                        goto out;
                }
@@ -2612,12 +3163,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
 
       out:
        if (sense) {
-               pci_free_consistent(instance->pdev, ioc->sense_len,
+               dma_free_coherent(&instance->pdev->dev, ioc->sense_len,
                                    sense, sense_handle);
        }
 
        for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {
-               pci_free_consistent(instance->pdev,
+               dma_free_coherent(&instance->pdev->dev,
                                    kern_sge32[i].length,
                                    kbuff_arr[i], kern_sge32[i].phys_addr);
        }
@@ -2698,10 +3249,10 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
        if (!instance)
                return -ENODEV;
 
-       down(&instance->aen_mutex);
+       mutex_lock(&instance->aen_mutex);
        error = megasas_register_aen(instance, aen.seq_num,
                                     aen.class_locale_word);
-       up(&instance->aen_mutex);
+       mutex_unlock(&instance->aen_mutex);
        return error;
 }
 
@@ -2732,7 +3283,8 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
        int i;
        int error = 0;
 
-       clear_user(ioc, sizeof(*ioc));
+       if (clear_user(ioc, sizeof(*ioc)))
+               return -EFAULT;
 
        if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
            copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
@@ -2780,10 +3332,9 @@ megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
 /*
  * File operations structure for management interface
  */
-static struct file_operations megasas_mgmt_fops = {
+static const struct file_operations megasas_mgmt_fops = {
        .owner = THIS_MODULE,
        .open = megasas_mgmt_open,
-       .release = megasas_mgmt_release,
        .fasync = megasas_mgmt_fasync,
        .unlocked_ioctl = megasas_mgmt_ioctl,
 #ifdef CONFIG_COMPAT
@@ -2800,6 +3351,8 @@ static struct pci_driver megasas_pci_driver = {
        .id_table = megasas_pci_table,
        .probe = megasas_probe_one,
        .remove = __devexit_p(megasas_detach_one),
+       .suspend = megasas_suspend,
+       .resume = megasas_resume,
        .shutdown = megasas_shutdown,
 };
 
@@ -2824,6 +3377,84 @@ megasas_sysfs_show_release_date(struct device_driver *dd, char *buf)
 static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
                   NULL);
 
+static ssize_t
+megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
+{
+       return sprintf(buf, "%u\n", megasas_dbg_lvl);
+}
+
+static ssize_t
+megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count)
+{
+       int retval = count;
+       if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){
+               printk(KERN_ERR "megasas: could not set dbg_lvl\n");
+               retval = -EINVAL;
+       }
+       return retval;
+}
+
+static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUSR, megasas_sysfs_show_dbg_lvl,
+               megasas_sysfs_set_dbg_lvl);
+
+static ssize_t
+megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf)
+{
+       return sprintf(buf, "%u\n", poll_mode_io);
+}
+
+static ssize_t
+megasas_sysfs_set_poll_mode_io(struct device_driver *dd,
+                               const char *buf, size_t count)
+{
+       int retval = count;
+       int tmp = poll_mode_io;
+       int i;
+       struct megasas_instance *instance;
+
+       if (sscanf(buf, "%u", &poll_mode_io) < 1) {
+               printk(KERN_ERR "megasas: could not set poll_mode_io\n");
+               retval = -EINVAL;
+       }
+
+       /*
+        * Check if poll_mode_io is already set or is same as previous value
+        */
+       if ((tmp && poll_mode_io) || (tmp == poll_mode_io))
+               goto out;
+
+       if (poll_mode_io) {
+               /*
+                * Start timers for all adapters
+                */
+               for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+                       instance = megasas_mgmt_info.instance[i];
+                       if (instance) {
+                               megasas_start_timer(instance,
+                                       &instance->io_completion_timer,
+                                       megasas_io_completion_timer,
+                                       MEGASAS_COMPLETION_TIMER_INTERVAL);
+                       }
+               }
+       } else {
+               /*
+                * Delete timers for all adapters
+                */
+               for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+                       instance = megasas_mgmt_info.instance[i];
+                       if (instance)
+                               del_timer_sync(&instance->io_completion_timer);
+               }
+       }
+
+out:
+       return retval;
+}
+
+static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO,
+               megasas_sysfs_show_poll_mode_io,
+               megasas_sysfs_set_poll_mode_io);
+
 /**
  * megasas_init - Driver load entry point
  */
@@ -2854,18 +3485,45 @@ static int __init megasas_init(void)
        /*
         * Register ourselves as PCI hotplug module
         */
-       rval = pci_module_init(&megasas_pci_driver);
+       rval = pci_register_driver(&megasas_pci_driver);
 
        if (rval) {
                printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
-               unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
-       }
-
-       driver_create_file(&megasas_pci_driver.driver, &driver_attr_version);
-       driver_create_file(&megasas_pci_driver.driver,
-                          &driver_attr_release_date);
+               goto err_pcidrv;
+       }
+
+       rval = driver_create_file(&megasas_pci_driver.driver,
+                                 &driver_attr_version);
+       if (rval)
+               goto err_dcf_attr_ver;
+       rval = driver_create_file(&megasas_pci_driver.driver,
+                                 &driver_attr_release_date);
+       if (rval)
+               goto err_dcf_rel_date;
+       rval = driver_create_file(&megasas_pci_driver.driver,
+                                 &driver_attr_dbg_lvl);
+       if (rval)
+               goto err_dcf_dbg_lvl;
+       rval = driver_create_file(&megasas_pci_driver.driver,
+                                 &driver_attr_poll_mode_io);
+       if (rval)
+               goto err_dcf_poll_mode_io;
 
        return rval;
+
+err_dcf_poll_mode_io:
+       driver_remove_file(&megasas_pci_driver.driver,
+                          &driver_attr_dbg_lvl);
+err_dcf_dbg_lvl:
+       driver_remove_file(&megasas_pci_driver.driver,
+                          &driver_attr_release_date);
+err_dcf_rel_date:
+       driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+err_dcf_attr_ver:
+       pci_unregister_driver(&megasas_pci_driver);
+err_pcidrv:
+       unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+       return rval;
 }
 
 /**
@@ -2873,9 +3531,13 @@ static int __init megasas_init(void)
  */
 static void __exit megasas_exit(void)
 {
-       driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+       driver_remove_file(&megasas_pci_driver.driver,
+                          &driver_attr_poll_mode_io);
+       driver_remove_file(&megasas_pci_driver.driver,
+                          &driver_attr_dbg_lvl);
        driver_remove_file(&megasas_pci_driver.driver,
                           &driver_attr_release_date);
+       driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
 
        pci_unregister_driver(&megasas_pci_driver);
        unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");