[SCSI] megaraid_sas: add the logical drive list to driver
[safe/jmp/linux-2.6] / drivers / scsi / megaraid / megaraid_sas.c
index a454f94..a92998f 100644 (file)
@@ -10,7 +10,7 @@
  *        2 of the License, or (at your option) any later version.
  *
  * FILE                : megaraid_sas.c
- * Version     : v00.00.04.01-rc1
+ * Version     : v00.00.04.12-rc1
  *
  * Authors:
  *     (email-id : megaraidlinux@lsi.com)
@@ -40,6 +40,7 @@
 #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>
@@ -75,6 +76,10 @@ static struct pci_device_id megasas_pci_table[] = {
        /* 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)},
@@ -89,8 +94,14 @@ 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);
@@ -215,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);
@@ -312,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);
@@ -328,6 +345,104 @@ 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
 */
@@ -404,7 +519,9 @@ megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
  * @regs :                     MFI register set
  */
 static inline void
-megasas_fire_cmd_gen2(dma_addr_t frame_phys_addr, u32 frame_count,
+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,
@@ -446,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
@@ -477,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);
@@ -522,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
@@ -592,6 +712,35 @@ 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
@@ -600,7 +749,8 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
  * Returns the number of frames required for numnber of sge's (sge_count)
  */
 
-static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
+static u32 megasas_get_frame_count(struct megasas_instance *instance,
+                       u8 sge_count, u8 frame_type)
 {
        int num_cnt;
        int sge_bytes;
@@ -610,6 +760,10 @@ static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
        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 for ldio &
@@ -617,12 +771,16 @@ static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type)
         * 2 SGEs for 32-bit SGLs for pthru frame
         */
        if (unlikely(frame_type == PTHRU_FRAME)) {
-               if (IS_DMA64)
+               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 (IS_DMA64)
+               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;
@@ -671,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
         */
@@ -681,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);
@@ -697,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
         */
@@ -708,7 +892,7 @@ 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;
@@ -718,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.
  */
@@ -739,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
         */
@@ -809,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
         */
@@ -826,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, IO_FRAME);
+       cmd->frame_count = megasas_get_frame_count(instance,
+                       ldio->sge_count, IO_FRAME);
 
        return cmd->frame_count;
 }
@@ -983,7 +1182,8 @@ 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
         */
@@ -1000,23 +1200,76 @@ 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;
 }
 
@@ -1071,7 +1324,14 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
 
                spin_lock_irqsave(instance->host->host_lock, flags);
                instance->flag &= ~MEGASAS_FW_BUSY;
-               instance->host->can_queue =
+               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);
@@ -1116,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;
@@ -1265,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
@@ -1280,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);
+               }
+       }
 }
 
 /*
@@ -1301,6 +1591,7 @@ static struct scsi_host_template megasas_template = {
        .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,
@@ -1369,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;
@@ -1458,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
@@ -1535,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;
 
@@ -1544,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:
@@ -1555,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;
 
@@ -1575,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 = 60;
+                       max_wait = MEGASAS_RESET_WAIT_TIME;
                        cur_state = MFI_STATE_OPERATIONAL;
                        break;
 
@@ -1585,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;
 
@@ -1626,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;
@@ -1636,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;
@@ -1714,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
         */
@@ -1776,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;
@@ -1881,6 +2216,178 @@ static int megasas_alloc_cmds(struct megasas_instance *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;
+       }
+
+       /* the following function will get the instance PD LIST */
+
+       if ((ret == 0) && (ci->ldCount < MAX_LOGICAL_DRIVES)) {
+               memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
+
+               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;
+                       }
+               }
+       }
+
+       pci_free_consistent(instance->pdev,
+                               sizeof(struct MR_LD_LIST),
+                               ci,
+                               ci_h);
+
+       megasas_return_cmd(instance, cmd);
+       return ret;
+}
+
 /**
  * megasas_get_controller_info -       Returns FW's controller structure
  * @instance:                          Adapter soft state
@@ -1926,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;
@@ -2080,13 +2588,17 @@ static int megasas_init_mfi(struct megasas_instance *instance)
         * Map the message registers
         */
        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")) {
+       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;
        }
@@ -2110,6 +2622,10 @@ static int megasas_init_mfi(struct megasas_instance *instance)
                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:
@@ -2165,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);
 
        /*
@@ -2219,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;
 }
@@ -2239,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));
 }
 
 /**
@@ -2287,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;
@@ -2401,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;
@@ -2408,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
@@ -2418,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;
 }
@@ -2464,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;
@@ -2496,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;
@@ -2536,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;
@@ -2571,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
@@ -2594,10 +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
@@ -2607,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;
 
        /*
@@ -2654,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:
@@ -2714,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;
@@ -2753,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;
 
@@ -2777,12 +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);
@@ -2817,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");
@@ -2872,6 +3437,8 @@ megasas_resume(struct pci_dev *pdev)
                megasas_start_timer(instance, &instance->io_completion_timer,
                                megasas_io_completion_timer,
                                MEGASAS_COMPLETION_TIMER_INTERVAL);
+       instance->unload = 0;
+
        return 0;
 
 fail_irq:
@@ -2912,6 +3479,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
        struct megasas_instance *instance;
 
        instance = pci_get_drvdata(pdev);
+       instance->unload = 1;
        host = instance->host;
 
        if (poll_mode_io)
@@ -2920,6 +3488,16 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
        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);
 
        /*
@@ -2968,6 +3546,7 @@ static void __devexit 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);
 }
@@ -3015,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
@@ -3031,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));
 
@@ -3055,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
@@ -3108,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;
        }
 
@@ -3139,8 +3736,8 @@ 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)) {
@@ -3176,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 =
@@ -3213,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
         */
@@ -3248,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);
@@ -3336,6 +3938,7 @@ static const struct file_operations megasas_mgmt_fops = {
        .open = megasas_mgmt_open,
        .fasync = megasas_mgmt_fasync,
        .unlocked_ioctl = megasas_mgmt_ioctl,
+       .poll = megasas_mgmt_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = megasas_mgmt_compat_ioctl,
 #endif
@@ -3377,6 +3980,15 @@ 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\n", megasas_dbg_lvl);
@@ -3450,7 +4062,93 @@ out:
        return retval;
 }
 
-static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO,
+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);
 
@@ -3467,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));
 
        /*
@@ -3499,6 +4199,12 @@ 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)
@@ -3515,7 +4221,12 @@ err_dcf_poll_mode_io:
                           &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: