[SCSI] megaraid_sas: add the logical drive list to driver
[safe/jmp/linux-2.6] / drivers / scsi / megaraid / megaraid_sas.c
index 9aee254..a92998f 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
@@ -10,7 +10,7 @@
  *        2 of the License, or (at your option) any later version.
  *
  * FILE                : megaraid_sas.c
- * Version     : v00.00.03.10-rc5
+ * Version     : v00.00.04.12-rc1
  *
  * Authors:
  *     (email-id : megaraidlinux@lsi.com)
 #include <linux/moduleparam.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <linux/mutex.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 <linux/poll.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.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("megaraidlinux@lsi.com");
-MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
+MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
 
 /*
  * PCI ID table for all supported controllers
@@ -61,6 +70,16 @@ static struct pci_device_id megasas_pci_table[] = {
        /* 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_SAS0073SKINNY)},
+       /* skinny*/
+       {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0071SKINNY)},
+       /* skinny*/
        {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)},
@@ -75,8 +94,18 @@ static struct megasas_mgmt_info megasas_mgmt_info;
 static struct fasync_struct *megasas_async_queue;
 static DEFINE_MUTEX(megasas_async_queue_mutex);
 
+static int megasas_poll_wait_aen;
+static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
+static u32 support_poll_for_event;
 static u32 megasas_dbg_lvl;
 
+/* define lock for aen poll */
+spinlock_t poll_aen_lock;
+
+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
@@ -184,6 +213,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;
 }
 
@@ -194,7 +226,10 @@ megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
  * @regs :                     MFI register set
  */
 static inline void 
-megasas_fire_cmd_xscale(dma_addr_t frame_phys_addr,u32 frame_count, struct megasas_register_set __iomem *regs)
+megasas_fire_cmd_xscale(struct megasas_instance *instance,
+               dma_addr_t frame_phys_addr,
+               u32 frame_count,
+               struct megasas_register_set __iomem *regs)
 {
        writel((frame_phys_addr >> 3)|(frame_count),
               &(regs)->inbound_queue_port);
@@ -279,6 +314,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;
 }
 /**
@@ -288,7 +326,10 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
  * @regs :                     MFI register set
  */
 static inline void 
-megasas_fire_cmd_ppc(dma_addr_t frame_phys_addr, u32 frame_count, struct megasas_register_set __iomem *regs)
+megasas_fire_cmd_ppc(struct megasas_instance *instance,
+               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);
@@ -304,6 +345,199 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
 };
 
 /**
+ * megasas_enable_intr_skinny -        Enables interrupts
+ * @regs:                      MFI register set
+ */
+static inline void
+megasas_enable_intr_skinny(struct megasas_register_set __iomem *regs)
+{
+       writel(0xFFFFFFFF, &(regs)->outbound_intr_mask);
+
+       writel(~MFI_SKINNY_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
+
+       /* Dummy readl to force pci flush */
+       readl(&regs->outbound_intr_mask);
+}
+
+/**
+ * megasas_disable_intr_skinny -       Disables interrupt
+ * @regs:                      MFI register set
+ */
+static inline void
+megasas_disable_intr_skinny(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_skinny - returns the current FW status value
+ * @regs:                      MFI register set
+ */
+static u32
+megasas_read_fw_status_reg_skinny(struct megasas_register_set __iomem *regs)
+{
+       return readl(&(regs)->outbound_scratch_pad);
+}
+
+/**
+ * megasas_clear_interrupt_skinny -    Check & clear interrupt
+ * @regs:                              MFI register set
+ */
+static int
+megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs)
+{
+       u32 status;
+       /*
+        * Check if it is our interrupt
+        */
+       status = readl(&regs->outbound_intr_status);
+
+       if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) {
+               return 1;
+       }
+
+       /*
+        * Clear the interrupt by writing back the same value
+        */
+       writel(status, &regs->outbound_intr_status);
+
+       /*
+       * dummy read to flush PCI
+       */
+       readl(&regs->outbound_intr_status);
+
+       return 0;
+}
+
+/**
+ * megasas_fire_cmd_skinny -   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_skinny(struct megasas_instance *instance,
+                       dma_addr_t frame_phys_addr,
+                       u32 frame_count,
+                       struct megasas_register_set __iomem *regs)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&instance->fire_lock, flags);
+       writel(0, &(regs)->inbound_high_queue_port);
+       writel((frame_phys_addr | (frame_count<<1))|1,
+               &(regs)->inbound_low_queue_port);
+       spin_unlock_irqrestore(&instance->fire_lock, flags);
+}
+
+static struct megasas_instance_template megasas_instance_template_skinny = {
+
+       .fire_cmd = megasas_fire_cmd_skinny,
+       .enable_intr = megasas_enable_intr_skinny,
+       .disable_intr = megasas_disable_intr_skinny,
+       .clear_intr = megasas_clear_intr_skinny,
+       .read_fw_status_reg = megasas_read_fw_status_reg_skinny,
+};
+
+
+/**
+*      The following functions are defined for gen2 (deviceid : 0x78 0x79)
+*      controllers
+*/
+
+/**
+ * megasas_enable_intr_gen2 -  Enables interrupts
+ * @regs:                      MFI register set
+ */
+static inline void
+megasas_enable_intr_gen2(struct megasas_register_set __iomem *regs)
+{
+       writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
+
+       /* write ~0x00000005 (4 & 1) to the intr mask*/
+       writel(~MFI_GEN2_ENABLE_INTERRUPT_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(struct megasas_instance *instance,
+                       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
 */
@@ -329,7 +563,8 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
        /*
         * Issue the frame using inbound queue port
         */
-       instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+       instance->instancet->fire_cmd(instance,
+                       cmd->frame_phys_addr, 0, instance->reg_set);
 
        /*
         * Wait for cmd_status to change
@@ -360,7 +595,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
 {
        cmd->cmd_status = ENODATA;
 
-       instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+       instance->instancet->fire_cmd(instance,
+                       cmd->frame_phys_addr, 0, instance->reg_set);
 
        wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
                MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
@@ -405,7 +641,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
        cmd->sync_cmd = 1;
        cmd->cmd_status = 0xFF;
 
-       instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+       instance->instancet->fire_cmd(instance,
+                       cmd->frame_phys_addr, 0, instance->reg_set);
 
        /*
         * Wait for this cmd to complete
@@ -475,14 +712,45 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
        return sge_count;
 }
 
+/**
+ * megasas_make_sgl_skinny - Prepares IEEE SGL
+ * @instance:           Adapter soft state
+ * @scp:                SCSI command from the mid-layer
+ * @mfi_sgl:            SGL to be filled in
+ *
+ * If successful, this function returns the number of SG elements. Otherwise,
+ * it returnes -1.
+ */
+static int
+megasas_make_sgl_skinny(struct megasas_instance *instance,
+               struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl)
+{
+       int i;
+       int sge_count;
+       struct scatterlist *os_sgl;
+
+       sge_count = scsi_dma_map(scp);
+
+       if (sge_count) {
+               scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+                       mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
+                       mfi_sgl->sge_skinny[i].phys_addr =
+                                               sg_dma_address(os_sgl);
+               }
+       }
+       return sge_count;
+}
+
  /**
  * 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)
  */
 
-static u32 megasas_get_frame_count(u8 sge_count)
+static u32 megasas_get_frame_count(struct megasas_instance *instance,
+                       u8 sge_count, u8 frame_type)
 {
        int num_cnt;
        int sge_bytes;
@@ -492,14 +760,31 @@ static u32 megasas_get_frame_count(u8 sge_count)
        sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
            sizeof(struct megasas_sge32);
 
+       if (instance->flag_ieee) {
+               sge_sz = sizeof(struct megasas_sge_skinny);
+       }
+
        /*
-       * Main frame can contain 2 SGEs for 64-bit SGLs and
-       * 3 SGEs for 32-bit SGLs
-       */
-       if (IS_DMA64)
-               num_cnt = sge_count - 2;
-       else
-               num_cnt = sge_count - 3;
+        * 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 (instance->flag_ieee == 1) {
+                       num_cnt = sge_count - 1;
+               } else if (IS_DMA64)
+                       num_cnt = sge_count - 1;
+               else
+                       num_cnt = sge_count - 2;
+       } else {
+               if (instance->flag_ieee == 1) {
+                       num_cnt = sge_count - 1;
+               } else if (IS_DMA64)
+                       num_cnt = sge_count - 2;
+               else
+                       num_cnt = sge_count - 3;
+       }
 
        if(num_cnt>0){
                sge_bytes = sge_sz * num_cnt;
@@ -544,6 +829,10 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
        else if (scp->sc_data_direction == PCI_DMA_NONE)
                flags = MFI_FRAME_DIR_NONE;
 
+       if (instance->flag_ieee == 1) {
+               flags |= MFI_FRAME_IEEE;
+       }
+
        /*
         * Prepare the DCDB frame
         */
@@ -554,15 +843,31 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
        pthru->lun = scp->device->lun;
        pthru->cdb_len = scp->cmd_len;
        pthru->timeout = 0;
+       pthru->pad_0 = 0;
        pthru->flags = flags;
        pthru->data_xfer_len = scsi_bufflen(scp);
 
        memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
 
        /*
+       * If the command is for the tape device, set the
+       * pthru timeout to the os layer timeout value.
+       */
+       if (scp->device->type == TYPE_TAPE) {
+               if ((scp->request->timeout / HZ) > 0xFFFF)
+                       pthru->timeout = 0xFFFF;
+               else
+                       pthru->timeout = scp->request->timeout / HZ;
+       }
+
+       /*
         * Construct SGL
         */
-       if (IS_DMA64) {
+       if (instance->flag_ieee == 1) {
+               pthru->flags |= MFI_FRAME_SGL64;
+               pthru->sge_count = megasas_make_sgl_skinny(instance, scp,
+                                                     &pthru->sgl);
+       } else if (IS_DMA64) {
                pthru->flags |= MFI_FRAME_SGL64;
                pthru->sge_count = megasas_make_sgl64(instance, scp,
                                                      &pthru->sgl);
@@ -570,6 +875,12 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
                pthru->sge_count = megasas_make_sgl32(instance, scp,
                                                      &pthru->sgl);
 
+       if (pthru->sge_count > instance->max_num_sge) {
+               printk(KERN_ERR "megasas: DCDB two many SGE NUM=%x\n",
+                       pthru->sge_count);
+               return 0;
+       }
+
        /*
         * Sense info specific
         */
@@ -581,7 +892,8 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
         * 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(pthru->sge_count);
+       cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count,
+                                                       PTHRU_FRAME);
 
        return cmd->frame_count;
 }
@@ -590,7 +902,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.
  */
@@ -611,6 +923,10 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
        else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
                flags = MFI_FRAME_DIR_READ;
 
+       if (instance->flag_ieee == 1) {
+               flags |= MFI_FRAME_IEEE;
+       }
+
        /*
         * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
         */
@@ -681,12 +997,22 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
        /*
         * Construct SGL
         */
-       if (IS_DMA64) {
+       if (instance->flag_ieee) {
+               ldio->flags |= MFI_FRAME_SGL64;
+               ldio->sge_count = megasas_make_sgl_skinny(instance, scp,
+                                             &ldio->sgl);
+       } else if (IS_DMA64) {
                ldio->flags |= MFI_FRAME_SGL64;
                ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
        } else
                ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl);
 
+       if (ldio->sge_count > instance->max_num_sge) {
+               printk(KERN_ERR "megasas: build_ld_io: sge_count = %x\n",
+                       ldio->sge_count);
+               return 0;
+       }
+
        /*
         * Sense info specific
         */
@@ -698,7 +1024,8 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
         * 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);
+       cmd->frame_count = megasas_get_frame_count(instance,
+                       ldio->sge_count, IO_FRAME);
 
        return cmd->frame_count;
 }
@@ -855,7 +1182,14 @@ 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);
+       instance->instancet->fire_cmd(instance, 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;
 
@@ -866,26 +1200,144 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
        return 0;
 }
 
+static struct megasas_instance *megasas_lookup_instance(u16 host_no)
+{
+       int i;
+
+       for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+
+               if ((megasas_mgmt_info.instance[i]) &&
+                   (megasas_mgmt_info.instance[i]->host->host_no == host_no))
+                       return megasas_mgmt_info.instance[i];
+       }
+
+       return NULL;
+}
+
 static int megasas_slave_configure(struct scsi_device *sdev)
 {
+       u16             pd_index = 0;
+       struct  megasas_instance *instance ;
+
+       instance = megasas_lookup_instance(sdev->host->host_no);
+
        /*
-        * Don't export physical disk devices to the disk driver.
-        *
-        * FIXME: Currently we don't export them to the midlayer at all.
-        *        That will be fixed once LSI engineers have audited the
-        *        firmware for possible issues.
-        */
-       if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && sdev->type == TYPE_DISK)
+       * Don't export physical disk devices to the disk driver.
+       *
+       * FIXME: Currently we don't export them to the midlayer at all.
+       *        That will be fixed once LSI engineers have audited the
+       *        firmware for possible issues.
+       */
+       if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
+                               sdev->type == TYPE_DISK) {
+               pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+                                                               sdev->id;
+               if (instance->pd_list[pd_index].driveState ==
+                                               MR_PD_STATE_SYSTEM) {
+                       blk_queue_rq_timeout(sdev->request_queue,
+                               MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
+                       return 0;
+               }
                return -ENXIO;
+       }
 
        /*
-        * The RAID firmware may require extended timeouts.
-        */
-       if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS)
-               sdev->timeout = MEGASAS_DEFAULT_CMD_TIMEOUT * HZ;
+       * The RAID firmware may require extended timeouts.
+       */
+       blk_queue_rq_timeout(sdev->request_queue,
+               MEGASAS_DEFAULT_CMD_TIMEOUT * HZ);
        return 0;
 }
 
+static int megasas_slave_alloc(struct scsi_device *sdev)
+{
+       u16             pd_index = 0;
+       struct megasas_instance *instance ;
+       instance = megasas_lookup_instance(sdev->host->host_no);
+       if ((sdev->channel < MEGASAS_MAX_PD_CHANNELS) &&
+                               (sdev->type == TYPE_DISK)) {
+               /*
+                * Open the OS scan to the SYSTEM PD
+                */
+               pd_index =
+                       (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+                       sdev->id;
+               if ((instance->pd_list[pd_index].driveState ==
+                                       MR_PD_STATE_SYSTEM) &&
+                       (instance->pd_list[pd_index].driveType ==
+                                               TYPE_DISK)) {
+                       return 0;
+               }
+               return -ENXIO;
+       }
+       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;
+               if ((instance->pdev->device ==
+                       PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+                       (instance->pdev->device ==
+                       PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+                       instance->host->can_queue =
+                               instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+               } else
+                       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
@@ -909,6 +1361,11 @@ 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);
@@ -919,8 +1376,16 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
                * Send signal to FW to stop processing any pending cmds.
                * The controller will be taken offline by the OS now.
                */
-               writel(MFI_STOP_ADP,
+               if ((instance->pdev->device ==
+                       PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+                       (instance->pdev->device ==
+                       PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+                       writel(MFI_STOP_ADP,
+                               &instance->reg_set->reserved_0[0]);
+               } else {
+                       writel(MFI_STOP_ADP,
                                &instance->reg_set->inbound_doorbell);
+               }
                megasas_dump_pending_frames(instance);
                instance->hw_crit_error = 1;
                return FAILED;
@@ -970,7 +1435,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
  * cmd has not been completed within the timeout period.
  */
 static enum
-scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+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;
@@ -978,7 +1443,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 
        if (time_after(jiffies, scmd->jiffies_at_alloc +
                                (MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
-               return EH_NOT_HANDLED;
+               return BLK_EH_NOT_HANDLED;
        }
 
        instance = cmd->instance;
@@ -992,7 +1457,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 
                spin_unlock_irqrestore(instance->host->host_lock, flags);
        }
-       return EH_RESET_TIMER;
+       return BLK_EH_RESET_TIMER;
 }
 
 /**
@@ -1068,6 +1533,8 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
        return 0;
 }
 
+static void megasas_aen_polling(struct work_struct *work);
+
 /**
  * megasas_service_aen -       Processes an event notification
  * @instance:                  Adapter soft state
@@ -1083,16 +1550,36 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev,
 static void
 megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
+       unsigned long flags;
        /*
         * Don't signal app if it is just an aborted previously registered aen
         */
-       if (!cmd->abort_aen)
+       if ((!cmd->abort_aen) && (instance->unload == 0)) {
+               spin_lock_irqsave(&poll_aen_lock, flags);
+               megasas_poll_wait_aen = 1;
+               spin_unlock_irqrestore(&poll_aen_lock, flags);
+               wake_up(&megasas_poll_wait);
                kill_fasync(&megasas_async_queue, SIGIO, POLL_IN);
+       }
        else
                cmd->abort_aen = 0;
 
        instance->aen_cmd = NULL;
        megasas_return_cmd(instance, cmd);
+
+       if (instance->unload == 0) {
+               struct megasas_aen_event *ev;
+               ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+               if (!ev) {
+                       printk(KERN_ERR "megasas_service_aen: out of memory\n");
+               } else {
+                       ev->instance = instance;
+                       instance->ev = ev;
+                       INIT_WORK(&ev->hotplug_work, megasas_aen_polling);
+                       schedule_delayed_work(
+                               (struct delayed_work *)&ev->hotplug_work, 0);
+               }
+       }
 }
 
 /*
@@ -1101,9 +1588,10 @@ 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,
+       .slave_alloc = megasas_slave_alloc,
        .queuecommand = megasas_queue_command,
        .eh_device_reset_handler = megasas_reset_device,
        .eh_bus_reset_handler = megasas_reset_bus_host,
@@ -1111,7 +1599,6 @@ static struct scsi_host_template megasas_template = {
        .eh_timed_out = megasas_reset_timer,
        .bios_param = megasas_bios_param,
        .use_clustering = ENABLE_CLUSTERING,
-       .use_sg_chaining = ENABLE_SG_CHAINING,
 };
 
 /**
@@ -1173,6 +1660,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 {
        int exception = 0;
        struct megasas_header *hdr = &cmd->frame->hdr;
+       unsigned long flags;
 
        if (cmd->scmd)
                cmd->scmd->SCp.ptr = NULL;
@@ -1262,6 +1750,12 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
        case MFI_CMD_SMP:
        case MFI_CMD_STP:
        case MFI_CMD_DCMD:
+               if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
+                       cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
+                       spin_lock_irqsave(&poll_aen_lock, flags);
+                       megasas_poll_wait_aen = 0;
+                       spin_unlock_irqrestore(&poll_aen_lock, flags);
+               }
 
                /*
                 * See if got an event notification
@@ -1339,6 +1833,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
        u8 max_wait;
        u32 fw_state;
        u32 cur_state;
+       u32 abs_state, curr_abs_state;
 
        fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
 
@@ -1348,6 +1843,9 @@ megasas_transition_to_ready(struct megasas_instance* instance)
 
        while (fw_state != MFI_STATE_READY) {
 
+               abs_state =
+               instance->instancet->read_fw_status_reg(instance->reg_set);
+
                switch (fw_state) {
 
                case MFI_STATE_FAULT:
@@ -1359,18 +1857,36 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                        /*
                         * Set the CLR bit in inbound doorbell
                         */
-                       writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
-                               &instance->reg_set->inbound_doorbell);
+                       if ((instance->pdev->device ==
+                               PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+                               (instance->pdev->device ==
+                               PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+
+                               writel(
+                                 MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+                                 &instance->reg_set->reserved_0[0]);
+                       } else {
+                               writel(
+                                   MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+                                       &instance->reg_set->inbound_doorbell);
+                       }
 
-                       max_wait = 2;
+                       max_wait = MEGASAS_RESET_WAIT_TIME;
                        cur_state = MFI_STATE_WAIT_HANDSHAKE;
                        break;
 
                case MFI_STATE_BOOT_MESSAGE_PENDING:
-                       writel(MFI_INIT_HOTPLUG,
-                               &instance->reg_set->inbound_doorbell);
+                       if ((instance->pdev->device ==
+                               PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+                       (instance->pdev->device ==
+                               PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+                               writel(MFI_INIT_HOTPLUG,
+                               &instance->reg_set->reserved_0[0]);
+                       } else
+                               writel(MFI_INIT_HOTPLUG,
+                                       &instance->reg_set->inbound_doorbell);
 
-                       max_wait = 10;
+                       max_wait = MEGASAS_RESET_WAIT_TIME;
                        cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
                        break;
 
@@ -1379,9 +1895,17 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                         * Bring it to READY state; assuming max wait 10 secs
                         */
                        instance->instancet->disable_intr(instance->reg_set);
-                       writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
+                       if ((instance->pdev->device ==
+                               PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+                               (instance->pdev->device ==
+                               PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+                               writel(MFI_RESET_FLAGS,
+                                       &instance->reg_set->reserved_0[0]);
+                       } else
+                               writel(MFI_RESET_FLAGS,
+                                       &instance->reg_set->inbound_doorbell);
 
-                       max_wait = 10;
+                       max_wait = MEGASAS_RESET_WAIT_TIME;
                        cur_state = MFI_STATE_OPERATIONAL;
                        break;
 
@@ -1389,32 +1913,32 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                        /*
                         * This state should not last for more than 2 seconds
                         */
-                       max_wait = 2;
+                       max_wait = MEGASAS_RESET_WAIT_TIME;
                        cur_state = MFI_STATE_UNDEFINED;
                        break;
 
                case MFI_STATE_BB_INIT:
-                       max_wait = 2;
+                       max_wait = MEGASAS_RESET_WAIT_TIME;
                        cur_state = MFI_STATE_BB_INIT;
                        break;
 
                case MFI_STATE_FW_INIT:
-                       max_wait = 20;
+                       max_wait = MEGASAS_RESET_WAIT_TIME;
                        cur_state = MFI_STATE_FW_INIT;
                        break;
 
                case MFI_STATE_FW_INIT_2:
-                       max_wait = 20;
+                       max_wait = MEGASAS_RESET_WAIT_TIME;
                        cur_state = MFI_STATE_FW_INIT_2;
                        break;
 
                case MFI_STATE_DEVICE_SCAN:
-                       max_wait = 20;
+                       max_wait = MEGASAS_RESET_WAIT_TIME;
                        cur_state = MFI_STATE_DEVICE_SCAN;
                        break;
 
                case MFI_STATE_FLUSH_CACHE:
-                       max_wait = 20;
+                       max_wait = MEGASAS_RESET_WAIT_TIME;
                        cur_state = MFI_STATE_FLUSH_CACHE;
                        break;
 
@@ -1430,8 +1954,10 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                for (i = 0; i < (max_wait * 1000); i++) {
                        fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &  
                                        MFI_STATE_MASK ;
+               curr_abs_state =
+               instance->instancet->read_fw_status_reg(instance->reg_set);
 
-                       if (fw_state == cur_state) {
+                       if (abs_state == curr_abs_state) {
                                msleep(1);
                        } else
                                break;
@@ -1440,7 +1966,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
                /*
                 * Return error if fw_state hasn't changed after max_wait
                 */
-               if (fw_state == cur_state) {
+               if (curr_abs_state == abs_state) {
                        printk(KERN_DEBUG "FW state [%d] hasn't changed "
                               "in %d secs\n", fw_state, max_wait);
                        return -ENODEV;
@@ -1518,6 +2044,10 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
        sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
            sizeof(struct megasas_sge32);
 
+       if (instance->flag_ieee) {
+               sge_sz = sizeof(struct megasas_sge_skinny);
+       }
+
        /*
         * Calculated the number of 64byte frames required for SGL
         */
@@ -1580,6 +2110,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
                }
 
                cmd->frame->io.context = cmd->index;
+               cmd->frame->io.pad_0 = 0;
        }
 
        return 0;
@@ -1658,31 +2189,203 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
                        kfree(instance->cmd_list);
                        instance->cmd_list = NULL;
 
-                       return -ENOMEM;
-               }
+                       return -ENOMEM;
+               }
+       }
+
+       /*
+        * Add all the commands to command pool (instance->cmd_pool)
+        */
+       for (i = 0; i < max_cmd; i++) {
+               cmd = instance->cmd_list[i];
+               memset(cmd, 0, sizeof(struct megasas_cmd));
+               cmd->index = i;
+               cmd->instance = instance;
+
+               list_add_tail(&cmd->list, &instance->cmd_pool);
+       }
+
+       /*
+        * Create a frame pool and assign one frame to each cmd
+        */
+       if (megasas_create_frame_pool(instance)) {
+               printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n");
+               megasas_free_cmds(instance);
+       }
+
+       return 0;
+}
+
+/*
+ * megasas_get_pd_list_info -  Returns FW's pd_list structure
+ * @instance:                          Adapter soft state
+ * @pd_list:                           pd_list structure
+ *
+ * Issues an internal command (DCMD) to get the FW's controller PD
+ * list structure.  This information is mainly used to find out SYSTEM
+ * supported by the FW.
+ */
+static int
+megasas_get_pd_list(struct megasas_instance *instance)
+{
+       int ret = 0, pd_index = 0;
+       struct megasas_cmd *cmd;
+       struct megasas_dcmd_frame *dcmd;
+       struct MR_PD_LIST *ci;
+       struct MR_PD_ADDRESS *pd_addr;
+       dma_addr_t ci_h = 0;
+
+       cmd = megasas_get_cmd(instance);
+
+       if (!cmd) {
+               printk(KERN_DEBUG "megasas (get_pd_list): Failed to get cmd\n");
+               return -ENOMEM;
+       }
+
+       dcmd = &cmd->frame->dcmd;
+
+       ci = pci_alloc_consistent(instance->pdev,
+                 MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), &ci_h);
+
+       if (!ci) {
+               printk(KERN_DEBUG "Failed to alloc mem for pd_list\n");
+               megasas_return_cmd(instance, cmd);
+               return -ENOMEM;
+       }
+
+       memset(ci, 0, sizeof(*ci));
+       memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+       dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
+       dcmd->mbox.b[1] = 0;
+       dcmd->cmd = MFI_CMD_DCMD;
+       dcmd->cmd_status = 0xFF;
+       dcmd->sge_count = 1;
+       dcmd->flags = MFI_FRAME_DIR_READ;
+       dcmd->timeout = 0;
+       dcmd->pad_0 = 0;
+       dcmd->data_xfer_len = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
+       dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
+       dcmd->sgl.sge32[0].phys_addr = ci_h;
+       dcmd->sgl.sge32[0].length = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
+
+       if (!megasas_issue_polled(instance, cmd)) {
+               ret = 0;
+       } else {
+               ret = -1;
+       }
+
+       /*
+       * the following function will get the instance PD LIST.
+       */
+
+       pd_addr = ci->addr;
+
+       if ( ret == 0 &&
+               (ci->count <
+                 (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
+
+               memset(instance->pd_list, 0,
+                       MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
+
+               for (pd_index = 0; pd_index < ci->count; pd_index++) {
+
+                       instance->pd_list[pd_addr->deviceId].tid        =
+                                                       pd_addr->deviceId;
+                       instance->pd_list[pd_addr->deviceId].driveType  =
+                                                       pd_addr->scsiDevType;
+                       instance->pd_list[pd_addr->deviceId].driveState =
+                                                       MR_PD_STATE_SYSTEM;
+                       pd_addr++;
+               }
+       }
+
+       pci_free_consistent(instance->pdev,
+                               MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST),
+                               ci, ci_h);
+       megasas_return_cmd(instance, cmd);
+
+       return ret;
+}
+
+/*
+ * megasas_get_ld_list_info -  Returns FW's ld_list structure
+ * @instance:                          Adapter soft state
+ * @ld_list:                           ld_list structure
+ *
+ * Issues an internal command (DCMD) to get the FW's controller PD
+ * list structure.  This information is mainly used to find out SYSTEM
+ * supported by the FW.
+ */
+static int
+megasas_get_ld_list(struct megasas_instance *instance)
+{
+       int ret = 0, ld_index = 0, ids = 0;
+       struct megasas_cmd *cmd;
+       struct megasas_dcmd_frame *dcmd;
+       struct MR_LD_LIST *ci;
+       dma_addr_t ci_h = 0;
+
+       cmd = megasas_get_cmd(instance);
+
+       if (!cmd) {
+               printk(KERN_DEBUG "megasas_get_ld_list: Failed to get cmd\n");
+               return -ENOMEM;
+       }
+
+       dcmd = &cmd->frame->dcmd;
+
+       ci = pci_alloc_consistent(instance->pdev,
+                               sizeof(struct MR_LD_LIST),
+                               &ci_h);
+
+       if (!ci) {
+               printk(KERN_DEBUG "Failed to alloc mem in get_ld_list\n");
+               megasas_return_cmd(instance, cmd);
+               return -ENOMEM;
+       }
+
+       memset(ci, 0, sizeof(*ci));
+       memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+       dcmd->cmd = MFI_CMD_DCMD;
+       dcmd->cmd_status = 0xFF;
+       dcmd->sge_count = 1;
+       dcmd->flags = MFI_FRAME_DIR_READ;
+       dcmd->timeout = 0;
+       dcmd->data_xfer_len = sizeof(struct MR_LD_LIST);
+       dcmd->opcode = MR_DCMD_LD_GET_LIST;
+       dcmd->sgl.sge32[0].phys_addr = ci_h;
+       dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST);
+       dcmd->pad_0  = 0;
+
+       if (!megasas_issue_polled(instance, cmd)) {
+               ret = 0;
+       } else {
+               ret = -1;
        }
 
-       /*
-        * Add all the commands to command pool (instance->cmd_pool)
-        */
-       for (i = 0; i < max_cmd; i++) {
-               cmd = instance->cmd_list[i];
-               memset(cmd, 0, sizeof(struct megasas_cmd));
-               cmd->index = i;
-               cmd->instance = instance;
+       /* the following function will get the instance PD LIST */
 
-               list_add_tail(&cmd->list, &instance->cmd_pool);
-       }
+       if ((ret == 0) && (ci->ldCount < MAX_LOGICAL_DRIVES)) {
+               memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
 
-       /*
-        * Create a frame pool and assign one frame to each cmd
-        */
-       if (megasas_create_frame_pool(instance)) {
-               printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n");
-               megasas_free_cmds(instance);
+               for (ld_index = 0; ld_index < ci->ldCount; ld_index++) {
+                       if (ci->ldList[ld_index].state != 0) {
+                               ids = ci->ldList[ld_index].ref.targetId;
+                               instance->ld_ids[ids] =
+                                       ci->ldList[ld_index].ref.targetId;
+                       }
+               }
        }
 
-       return 0;
+       pci_free_consistent(instance->pdev,
+                               sizeof(struct MR_LD_LIST),
+                               ci,
+                               ci_h);
+
+       megasas_return_cmd(instance, cmd);
+       return ret;
 }
 
 /**
@@ -1730,6 +2433,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
        dcmd->sge_count = 1;
        dcmd->flags = MFI_FRAME_DIR_READ;
        dcmd->timeout = 0;
+       dcmd->pad_0 = 0;
        dcmd->data_xfer_len = sizeof(struct megasas_ctrl_info);
        dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
        dcmd->sgl.sge32[0].phys_addr = ci_h;
@@ -1750,60 +2454,6 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
 }
 
 /**
- * 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;
-
-       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;
-
-       /*
-        * 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_issue_init_mfi -    Initializes the FW
  * @instance:          Adapter soft state
  *
@@ -1879,6 +2529,47 @@ fail_fw_init:
 }
 
 /**
+ * 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;
+
+       if (atomic_read(&instance->fw_outstanding))
+               tasklet_schedule(&instance->isr_tasklet);
+
+       /* Restart timer */
+       if (poll_mode_io)
+               mod_timer(&instance->io_completion_timer,
+                       jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
+}
+
+/**
  * megasas_init_mfi -  Initializes the FW
  * @instance:          Adapter soft state
  *
@@ -1890,14 +2581,24 @@ 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_ctrl_info *ctrl_info;
        /*
         * 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_SAS0071SKINNY) ||
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+               (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_selected_regions(instance->pdev,
+               pci_select_bars(instance->pdev, IORESOURCE_MEM),
+               "megasas: LSI")) {
                printk(KERN_DEBUG "megasas: IO memory region busy!\n");
                return -EBUSY;
        }
@@ -1913,9 +2614,18 @@ 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_SAS0073SKINNY:
+               case PCI_DEVICE_ID_LSI_SAS0071SKINNY:
+                       instance->instancet = &megasas_instance_template_skinny;
+                       break;
                case PCI_DEVICE_ID_LSI_SAS1064R:
                case PCI_DEVICE_ID_DELL_PERC5:
                default:
@@ -1971,6 +2681,13 @@ static int megasas_init_mfi(struct megasas_instance *instance)
        if (megasas_issue_init_mfi(instance))
                goto fail_fw_init;
 
+       memset(instance->pd_list, 0 ,
+               (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)));
+       megasas_get_pd_list(instance);
+
+       memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
+       megasas_get_ld_list(instance);
+
        ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
 
        /*
@@ -1982,17 +2699,20 @@ 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);
 
@@ -2000,8 +2720,14 @@ static int megasas_init_mfi(struct megasas_instance *instance)
        * Setup tasklet for cmd completion
        */
 
-        tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
-                        (unsigned long)instance);
+       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:
@@ -2016,7 +2742,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
        iounmap(instance->reg_set);
 
       fail_ioremap:
-       pci_release_regions(instance->pdev);
+       pci_release_selected_regions(instance->pdev,
+               pci_select_bars(instance->pdev, IORESOURCE_MEM));
 
        return -EINVAL;
 }
@@ -2036,7 +2763,8 @@ static void megasas_release_mfi(struct megasas_instance *instance)
 
        iounmap(instance->reg_set);
 
-       pci_release_regions(instance->pdev);
+       pci_release_selected_regions(instance->pdev,
+               pci_select_bars(instance->pdev, IORESOURCE_MEM));
 }
 
 /**
@@ -2084,6 +2812,7 @@ megasas_get_seq_num(struct megasas_instance *instance,
        dcmd->sge_count = 1;
        dcmd->flags = MFI_FRAME_DIR_READ;
        dcmd->timeout = 0;
+       dcmd->pad_0 = 0;
        dcmd->data_xfer_len = sizeof(struct megasas_evt_log_info);
        dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
        dcmd->sgl.sge32[0].phys_addr = el_info_h;
@@ -2198,6 +2927,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
        dcmd->sge_count = 1;
        dcmd->flags = MFI_FRAME_DIR_READ;
        dcmd->timeout = 0;
+       dcmd->pad_0 = 0;
        dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);
        dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
        dcmd->mbox.w[0] = seq_num;
@@ -2205,6 +2935,11 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
        dcmd->sgl.sge32[0].phys_addr = (u32) instance->evt_detail_h;
        dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_detail);
 
+       if (instance->aen_cmd != NULL) {
+               megasas_return_cmd(instance, cmd);
+               return 0;
+       }
+
        /*
         * Store reference to the cmd used to register for AEN. When an
         * application wants us to register for AEN, we have to abort this
@@ -2215,7 +2950,8 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
        /*
         * Issue the aen registration frame
         */
-       instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
+       instance->instancet->fire_cmd(instance,
+                       cmd->frame_phys_addr, 0, instance->reg_set);
 
        return 0;
 }
@@ -2261,7 +2997,13 @@ static int megasas_io_attach(struct megasas_instance *instance)
         */
        host->irq = instance->pdev->irq;
        host->unique_id = instance->unique_id;
-       host->can_queue = instance->max_fw_cmds - MEGASAS_INT_CMDS;
+       if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+               host->can_queue =
+                       instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
+       } else
+               host->can_queue =
+                       instance->max_fw_cmds - MEGASAS_INT_CMDS;
        host->this_id = instance->init_id;
        host->sg_tablesize = instance->max_num_sge;
        host->max_sectors = instance->max_sectors_per_req;
@@ -2293,13 +3035,13 @@ 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_64BIT_MASK) != 0) {
+               if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
 
-                       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 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_32BIT_MASK) != 0)
+               if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
                        goto fail_set_dma_mask;
        }
        return 0;
@@ -2333,7 +3075,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        /*
         * PCI prepping: enable device set bus mastering and dma mask
         */
-       rval = pci_enable_device(pdev);
+       rval = pci_enable_device_mem(pdev);
 
        if (rval) {
                return rval;
@@ -2368,6 +3110,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        *instance->producer = 0;
        *instance->consumer = 0;
+       megasas_poll_wait_aen = 0;
+       instance->flag_ieee = 0;
+       instance->ev = NULL;
 
        instance->evt_detail = pci_alloc_consistent(pdev,
                                                    sizeof(struct
@@ -2391,9 +3136,11 @@ 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->fire_lock);
+       spin_lock_init(&instance->completion_lock);
+       spin_lock_init(&poll_aen_lock);
 
        mutex_init(&instance->aen_mutex);
-       sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
 
        /*
         * Initialize PCI related and misc parameters
@@ -2403,8 +3150,16 @@ 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;
 
+       if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+               instance->flag_ieee = 1;
+               sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
+       } else
+               sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
+
        megasas_dbg_lvl = 0;
        instance->flag = 0;
+       instance->unload = 1;
        instance->last_time = 0;
 
        /*
@@ -2450,6 +3205,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        if (megasas_io_attach(instance))
                goto fail_io_attach;
 
+       instance->unload = 0;
        return 0;
 
       fail_start_aen:
@@ -2510,6 +3266,7 @@ static void megasas_flush_cache(struct megasas_instance *instance)
        dcmd->sge_count = 0;
        dcmd->flags = MFI_FRAME_DIR_NONE;
        dcmd->timeout = 0;
+       dcmd->pad_0 = 0;
        dcmd->data_xfer_len = 0;
        dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
        dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
@@ -2549,6 +3306,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
        dcmd->sge_count = 0;
        dcmd->flags = MFI_FRAME_DIR_NONE;
        dcmd->timeout = 0;
+       dcmd->pad_0 = 0;
        dcmd->data_xfer_len = 0;
        dcmd->opcode = opcode;
 
@@ -2559,12 +3317,13 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
        return;
 }
 
+#ifdef CONFIG_PM
 /**
- * megasas_suspend -    driver suspend entry point
- * @pdev:               PCI device structure
+ * megasas_suspend -   driver suspend entry point
+ * @pdev:              PCI device structure
  * @state:             PCI power state to suspend routine
  */
-static int __devinit
+static int
 megasas_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct Scsi_Host *host;
@@ -2572,9 +3331,23 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
 
        instance = pci_get_drvdata(pdev);
        host = instance->host;
+       instance->unload = 1;
+
+       if (poll_mode_io)
+               del_timer_sync(&instance->io_completion_timer);
 
        megasas_flush_cache(instance);
        megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
+
+       /* cancel the delayed work if this work still in queue */
+       if (instance->ev != NULL) {
+               struct megasas_aen_event *ev = instance->ev;
+               cancel_delayed_work(
+                       (struct delayed_work *)&ev->hotplug_work);
+               flush_scheduled_work();
+               instance->ev = NULL;
+       }
+
        tasklet_kill(&instance->isr_tasklet);
 
        pci_set_drvdata(instance->pdev, instance);
@@ -2593,7 +3366,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
  * megasas_resume-      driver resume entry point
  * @pdev:               PCI device structure
  */
-static int __devinit
+static int
 megasas_resume(struct pci_dev *pdev)
 {
        int rval;
@@ -2609,7 +3382,7 @@ megasas_resume(struct pci_dev *pdev)
        /*
         * PCI prepping: enable device set bus mastering and dma mask
         */
-       rval = pci_enable_device(pdev);
+       rval = pci_enable_device_mem(pdev);
 
        if (rval) {
                printk(KERN_ERR "megasas: Enable device failed\n");
@@ -2659,6 +3432,13 @@ megasas_resume(struct pci_dev *pdev)
        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);
+       instance->unload = 0;
+
        return 0;
 
 fail_irq:
@@ -2683,23 +3463,41 @@ fail_ready_state:
 
        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;
        struct megasas_instance *instance;
 
        instance = pci_get_drvdata(pdev);
+       instance->unload = 1;
        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, MR_DCMD_CTRL_SHUTDOWN);
+
+       /* cancel the delayed work if this work still in queue*/
+       if (instance->ev != NULL) {
+               struct megasas_aen_event *ev = instance->ev;
+               cancel_delayed_work(
+                       (struct delayed_work *)&ev->hotplug_work);
+               flush_scheduled_work();
+               instance->ev = NULL;
+       }
+
        tasklet_kill(&instance->isr_tasklet);
 
        /*
@@ -2748,7 +3546,9 @@ static void megasas_detach_one(struct pci_dev *pdev)
 static void megasas_shutdown(struct pci_dev *pdev)
 {
        struct megasas_instance *instance = pci_get_drvdata(pdev);
+       instance->unload = 1;
        megasas_flush_cache(instance);
+       megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
 }
 
 /**
@@ -2756,6 +3556,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
         */
@@ -2766,17 +3567,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
@@ -2804,6 +3594,23 @@ static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
 }
 
 /**
+ * megasas_mgmt_poll -  char node "poll" entry point
+ * */
+static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask;
+       unsigned long flags;
+       poll_wait(file, &megasas_poll_wait, wait);
+       spin_lock_irqsave(&poll_aen_lock, flags);
+       if (megasas_poll_wait_aen)
+               mask =   (POLLIN | POLLRDNORM);
+       else
+               mask = 0;
+       spin_unlock_irqrestore(&poll_aen_lock, flags);
+       return mask;
+}
+
+/**
  * megasas_mgmt_fw_ioctl -     Issues management ioctls to FW
  * @instance:                  Adapter soft state
  * @argp:                      User's ioctl packet
@@ -2820,7 +3627,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
        int error = 0, i;
        void *sense = NULL;
        dma_addr_t sense_handle;
-       u32 *sense_ptr;
+       unsigned long *sense_ptr;
 
        memset(kbuff_arr, 0, sizeof(kbuff_arr));
 
@@ -2844,6 +3651,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
         */
        memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
        cmd->frame->hdr.context = cmd->index;
+       cmd->frame->hdr.pad_0 = 0;
 
        /*
         * The management interface between applications and the fw uses
@@ -2897,7 +3705,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
                }
 
                sense_ptr =
-                   (u32 *) ((unsigned long)cmd->frame + ioc->sense_off);
+               (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off);
                *sense_ptr = sense_handle;
        }
 
@@ -2928,11 +3736,13 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
                 * sense_ptr points to the location that has the user
                 * sense buffer address
                 */
-               sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw +
-                                    ioc->sense_off);
+               sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw +
+                               ioc->sense_off);
 
                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;
                }
@@ -2963,20 +3773,6 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
        return error;
 }
 
-static struct megasas_instance *megasas_lookup_instance(u16 host_no)
-{
-       int i;
-
-       for (i = 0; i < megasas_mgmt_info.max_index; i++) {
-
-               if ((megasas_mgmt_info.instance[i]) &&
-                   (megasas_mgmt_info.instance[i]->host->host_no == host_no))
-                       return megasas_mgmt_info.instance[i];
-       }
-
-       return NULL;
-}
-
 static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
 {
        struct megasas_iocpacket __user *user_ioc =
@@ -3000,6 +3796,17 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
                goto out_kfree_ioc;
        }
 
+       if (instance->hw_crit_error == 1) {
+               printk(KERN_DEBUG "Controller in Crit ERROR\n");
+               error = -ENODEV;
+               goto out_kfree_ioc;
+       }
+
+       if (instance->unload == 1) {
+               error = -ENODEV;
+               goto out_kfree_ioc;
+       }
+
        /*
         * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds
         */
@@ -3035,6 +3842,14 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
        if (!instance)
                return -ENODEV;
 
+       if (instance->hw_crit_error == 1) {
+               error = -ENODEV;
+       }
+
+       if (instance->unload == 1) {
+               return -ENODEV;
+       }
+
        mutex_lock(&instance->aen_mutex);
        error = megasas_register_aen(instance, aen.seq_num,
                                     aen.class_locale_word);
@@ -3121,9 +3936,9 @@ megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
 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,
+       .poll = megasas_mgmt_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = megasas_mgmt_compat_ioctl,
 #endif
@@ -3165,9 +3980,18 @@ static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
                   NULL);
 
 static ssize_t
+megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf)
+{
+       return sprintf(buf, "%u\n", support_poll_for_event);
+}
+
+static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
+                       megasas_sysfs_show_support_poll_for_event, NULL);
+
+static ssize_t
 megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
 {
-       return sprintf(buf,"%u",megasas_dbg_lvl);
+       return sprintf(buf, "%u\n", megasas_dbg_lvl);
 }
 
 static ssize_t
@@ -3181,8 +4005,152 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun
        return retval;
 }
 
-static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
-                  megasas_sysfs_set_dbg_lvl);
+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 void
+megasas_aen_polling(struct work_struct *work)
+{
+       struct megasas_aen_event *ev =
+               container_of(work, struct megasas_aen_event, hotplug_work);
+       struct megasas_instance *instance = ev->instance;
+       union megasas_evt_class_locale class_locale;
+       struct  Scsi_Host *host;
+       struct  scsi_device *sdev1;
+       u16     pd_index = 0;
+       int     i, j, doscan = 0;
+       u32 seq_num;
+       int error;
+
+       if (!instance) {
+               printk(KERN_ERR "invalid instance!\n");
+               kfree(ev);
+               return;
+       }
+       instance->ev = NULL;
+       host = instance->host;
+       if (instance->evt_detail) {
+
+               switch (instance->evt_detail->code) {
+               case MR_EVT_PD_INSERTED:
+               case MR_EVT_PD_REMOVED:
+               case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED:
+                       doscan = 1;
+                       break;
+               default:
+                       doscan = 0;
+                       break;
+               }
+       } else {
+               printk(KERN_ERR "invalid evt_detail!\n");
+               kfree(ev);
+               return;
+       }
+
+       if (doscan) {
+               printk(KERN_INFO "scanning ...\n");
+               megasas_get_pd_list(instance);
+               for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
+                       for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
+                               pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
+                               sdev1 = scsi_device_lookup(host, i, j, 0);
+                               if (instance->pd_list[pd_index].driveState ==
+                                                       MR_PD_STATE_SYSTEM) {
+                                       if (!sdev1) {
+                                               scsi_add_device(host, i, j, 0);
+                                       }
+                                       if (sdev1)
+                                               scsi_device_put(sdev1);
+                               } else {
+                                       if (sdev1) {
+                                               scsi_remove_device(sdev1);
+                                               scsi_device_put(sdev1);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if ( instance->aen_cmd != NULL ) {
+               kfree(ev);
+               return ;
+       }
+
+       seq_num = instance->evt_detail->seq_num + 1;
+
+       /* Register AEN with FW for latest sequence number plus 1 */
+       class_locale.members.reserved = 0;
+       class_locale.members.locale = MR_EVT_LOCALE_ALL;
+       class_locale.members.class = MR_EVT_CLASS_DEBUG;
+       mutex_lock(&instance->aen_mutex);
+       error = megasas_register_aen(instance, seq_num,
+                                       class_locale.word);
+       mutex_unlock(&instance->aen_mutex);
+
+       if (error)
+               printk(KERN_ERR "register aen failed error %x\n", error);
+
+       kfree(ev);
+}
+
+
+static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUSR,
+               megasas_sysfs_show_poll_mode_io,
+               megasas_sysfs_set_poll_mode_io);
 
 /**
  * megasas_init - Driver load entry point
@@ -3197,6 +4165,8 @@ static int __init megasas_init(void)
        printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
               MEGASAS_EXT_VERSION);
 
+       support_poll_for_event = 2;
+
        memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
 
        /*
@@ -3229,15 +4199,34 @@ static int __init megasas_init(void)
                                  &driver_attr_release_date);
        if (rval)
                goto err_dcf_rel_date;
+
+       rval = driver_create_file(&megasas_pci_driver.driver,
+                               &driver_attr_support_poll_for_event);
+       if (rval)
+               goto err_dcf_support_poll_for_event;
+
        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_support_poll_for_event);
+
+err_dcf_support_poll_for_event:
+       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:
@@ -3253,6 +4242,8 @@ err_pcidrv:
 static void __exit megasas_exit(void)
 {
        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);