Merge branch 'master' into for_paulus
[linux-drm-fsl-dcu.git] / drivers / message / fusion / mptsas.c
index b752a479f6dbb01a43cc31d5b7d62f736c9f2d84..84b8b485e95bd8b57b6a11685a2cf64cd317d704 100644 (file)
@@ -3,9 +3,9 @@
  *      For use with LSI Logic PCI chip/adapter(s)
  *      running LSI Logic Fusion MPT (Message Passing Technology) firmware.
  *
- *  Copyright (c) 1999-2005 LSI Logic Corporation
- *  (mailto:mpt_linux_developer@lsil.com)
- *  Copyright (c) 2005-2006 Dell
+ *  Copyright (c) 1999-2007 LSI Logic Corporation
+ *  (mailto:mpt_linux_developer@lsi.com)
+ *  Copyright (c) 2005-2007 Dell
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -75,6 +75,7 @@
 MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(my_VERSION);
 
 static int mpt_pt_clear;
 module_param(mpt_pt_clear, int, 0);
@@ -82,17 +83,31 @@ MODULE_PARM_DESC(mpt_pt_clear,
                " Clear persistency table: enable=1  "
                "(default=MPTSCSIH_PT_CLEAR=0)");
 
+/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
+#define MPTSAS_MAX_LUN (16895)
+static int max_lun = MPTSAS_MAX_LUN;
+module_param(max_lun, int, 0);
+MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
+
 static int     mptsasDoneCtx = -1;
 static int     mptsasTaskCtx = -1;
 static int     mptsasInternalCtx = -1; /* Used only for internal commands */
 static int     mptsasMgmtCtx = -1;
 
+static void mptsas_hotplug_work(struct work_struct *work);
+
+struct mptsas_target_reset_event {
+       struct list_head        list;
+       EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
+       u8      target_reset_issued;
+};
 
 enum mptsas_hotplug_action {
        MPTSAS_ADD_DEVICE,
        MPTSAS_DEL_DEVICE,
        MPTSAS_ADD_RAID,
        MPTSAS_DEL_RAID,
+       MPTSAS_ADD_INACTIVE_VOLUME,
        MPTSAS_IGNORE_EVENT,
 };
 
@@ -101,14 +116,15 @@ struct mptsas_hotplug_event {
        MPT_ADAPTER             *ioc;
        enum mptsas_hotplug_action event_type;
        u64                     sas_address;
-       u32                     channel;
-       u32                     id;
+       u                     channel;
+       u                     id;
        u32                     device_info;
        u16                     handle;
        u16                     parent_handle;
        u8                      phy_id;
-       u8                      phys_disk_num;
-       u8                      phys_disk_num_valid;
+       u8                      phys_disk_num_valid;    /* hrc (hidden raid component) */
+       u8                      phys_disk_num;          /* hrc - unique index*/
+       u8                      hidden_raid_component;  /* hrc - don't expose*/
 };
 
 struct mptsas_discovery_event {
@@ -133,6 +149,7 @@ struct mptsas_devinfo {
        u8      port_id;        /* sas physical port this device
                                   is assoc'd with */
        u8      id;             /* logical target id of this device */
+       u32     phys_disk_num;  /* phys disk id, for csmi-ioctls */
        u8      channel;        /* logical bus number of this device */
        u64     sas_address;    /* WWN of this device,
                                   SATA is assigned by HBA,expander */
@@ -152,6 +169,7 @@ struct mptsas_portinfo_details{
 };
 
 struct mptsas_phyinfo {
+       u16     handle;                 /* unique id to address this */
        u8      phy_id;                 /* phy index */
        u8      port_id;                /* firmware port identifier */
        u8      negotiated_link_rate;   /* nego'd link rate for this phy */
@@ -167,7 +185,6 @@ struct mptsas_phyinfo {
 
 struct mptsas_portinfo {
        struct list_head list;
-       u16             handle;         /* unique id to address this */
        u16             num_phys;       /* number of phys */
        struct mptsas_phyinfo *phy_info;
 };
@@ -245,7 +262,8 @@ static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
        printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
        printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
        printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
-       printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address));
+       printk("SAS Address=0x%llX\n", (unsigned long long)
+           le64_to_cpu(sas_address));
        printk("Target ID=0x%X\n", pg0->TargetID);
        printk("Bus=0x%X\n", pg0->Bus);
        /* The PhyNum field specifies the PHY number of the parent
@@ -349,9 +367,9 @@ mptsas_port_delete(struct mptsas_portinfo_details * port_details)
        phy_info = port_info->phy_info;
 
        dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d "
-               "bitmask=0x%016llX\n",
-               __FUNCTION__, port_details, port_details->num_phys,
-                   port_details->phy_bitmask));
+           "bitmask=0x%016llX\n", __FUNCTION__, port_details,
+           port_details->num_phys, (unsigned long long)
+           port_details->phy_bitmask));
 
        for (i = 0; i < port_info->num_phys; i++, phy_info++) {
                if(phy_info->port_details != port_details)
@@ -476,7 +494,7 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
        for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
                sas_address = phy_info->attached.sas_address;
                dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
-                       i, sas_address));
+                   i, (unsigned long long)sas_address));
                if (!sas_address)
                        continue;
                port_details = phy_info->port_details;
@@ -495,8 +513,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                                    (1 << phy_info->phy_id);
                        phy_info->sas_port_add_phy=1;
                        dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t"
-                               "phy_id=%d sas_address=0x%018llX\n",
-                               i, sas_address));
+                           "phy_id=%d sas_address=0x%018llX\n",
+                           i, (unsigned long long)sas_address));
                        phy_info->port_details = port_details;
                }
 
@@ -512,8 +530,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                        if (phy_info_cmp->port_details == port_details )
                                continue;
                        dsaswideprintk((KERN_DEBUG
-                               "\t\tphy_id=%d sas_address=0x%018llX\n",
-                               j, phy_info_cmp->attached.sas_address));
+                           "\t\tphy_id=%d sas_address=0x%018llX\n",
+                           j, (unsigned long long)
+                           phy_info_cmp->attached.sas_address));
                        if (phy_info_cmp->port_details) {
                                port_details->rphy =
                                    mptsas_get_rphy(phy_info_cmp);
@@ -546,11 +565,10 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                if (!port_details)
                        continue;
                dsaswideprintk((KERN_DEBUG
-                       "%s: [%p]: phy_id=%02d num_phys=%02d "
-                       "bitmask=0x%016llX\n",
-                       __FUNCTION__,
-                       port_details, i, port_details->num_phys,
-                       port_details->phy_bitmask));
+                   "%s: [%p]: phy_id=%02d num_phys=%02d "
+                   "bitmask=0x%016llX\n", __FUNCTION__,
+                   port_details, i, port_details->num_phys,
+                   (unsigned long long)port_details->phy_bitmask));
                dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
                        port_details->port, port_details->rphy));
        }
@@ -559,22 +577,273 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
        mutex_unlock(&ioc->sas_topology_mutex);
 }
 
+/**
+ * csmisas_find_vtarget
+ *
+ * @ioc
+ * @volume_id
+ * @volume_bus
+ *
+ **/
+static VirtTarget *
+mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       struct scsi_device              *sdev;
+       VirtDevice                      *vdev;
+       VirtTarget                      *vtarget = NULL;
+
+       shost_for_each_device(sdev, ioc->sh) {
+               if ((vdev = sdev->hostdata) == NULL)
+                       continue;
+               if (vdev->vtarget->id == id &&
+                   vdev->vtarget->channel == channel)
+                       vtarget = vdev->vtarget;
+       }
+       return vtarget;
+}
+
+/**
+ * mptsas_target_reset
+ *
+ * Issues TARGET_RESET to end device using handshaking method
+ *
+ * @ioc
+ * @channel
+ * @id
+ *
+ * Returns (1) success
+ *         (0) failure
+ *
+ **/
+static int
+mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       MPT_FRAME_HDR   *mf;
+       SCSITaskMgmt_t  *pScsiTm;
+
+       if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+               dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
+                   ioc->name,__FUNCTION__, __LINE__));
+               return 0;
+       }
+
+       /* Format the Request
+        */
+       pScsiTm = (SCSITaskMgmt_t *) mf;
+       memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
+       pScsiTm->TargetID = id;
+       pScsiTm->Bus = channel;
+       pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
+       pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+       pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
+
+       DBG_DUMP_TM_REQUEST_FRAME(mf);
+
+       if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
+           sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
+               mpt_free_msg_frame(ioc, mf);
+               dfailprintk((MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
+                   ioc->name,__FUNCTION__, __LINE__));
+               return 0;
+       }
+
+       return 1;
+}
+
+/**
+ * mptsas_target_reset_queue
+ *
+ * Receive request for TARGET_RESET after recieving an firmware
+ * event NOT_RESPONDING_EVENT, then put command in link list
+ * and queue if task_queue already in use.
+ *
+ * @ioc
+ * @sas_event_data
+ *
+ **/
 static void
-mptsas_target_reset(MPT_ADAPTER *ioc, VirtTarget * vtarget)
+mptsas_target_reset_queue(MPT_ADAPTER *ioc,
+    EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
 {
-       MPT_SCSI_HOST           *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+       VirtTarget *vtarget = NULL;
+       struct mptsas_target_reset_event *target_reset_list;
+       u8              id, channel;
 
-       if (mptscsih_TMHandler(hd,
-            MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
-            vtarget->bus_id, vtarget->target_id, 0, 0, 5) < 0) {
-               hd->tmPending = 0;
-               hd->tmState = TM_STATE_NONE;
-               printk(MYIOC_s_WARN_FMT
-              "Error processing TaskMgmt id=%d TARGET_RESET\n",
-                       ioc->name, vtarget->target_id);
+       id = sas_event_data->TargetID;
+       channel = sas_event_data->Bus;
+
+       if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
+               return;
+
+       vtarget->deleted = 1; /* block IO */
+
+       target_reset_list = kzalloc(sizeof(*target_reset_list),
+           GFP_ATOMIC);
+       if (!target_reset_list) {
+               dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
+                   ioc->name,__FUNCTION__, __LINE__));
+               return;
+       }
+
+       memcpy(&target_reset_list->sas_event_data, sas_event_data,
+               sizeof(*sas_event_data));
+       list_add_tail(&target_reset_list->list, &hd->target_reset_list);
+
+       if (hd->resetPending)
+               return;
+
+       if (mptsas_target_reset(ioc, channel, id)) {
+               target_reset_list->target_reset_issued = 1;
+               hd->resetPending = 1;
        }
 }
 
+/**
+ * mptsas_dev_reset_complete
+ *
+ * Completion for TARGET_RESET after NOT_RESPONDING_EVENT,
+ * enable work queue to finish off removing device from upper layers.
+ * then send next TARGET_RESET in the queue.
+ *
+ * @ioc
+ *
+ **/
+static void
+mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
+{
+       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+        struct list_head *head = &hd->target_reset_list;
+       struct mptsas_target_reset_event *target_reset_list;
+       struct mptsas_hotplug_event *ev;
+       EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
+       u8              id, channel;
+       __le64          sas_address;
+
+       if (list_empty(head))
+               return;
+
+       target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, list);
+
+       sas_event_data = &target_reset_list->sas_event_data;
+       id = sas_event_data->TargetID;
+       channel = sas_event_data->Bus;
+       hd->resetPending = 0;
+
+       /*
+        * retry target reset
+        */
+       if (!target_reset_list->target_reset_issued) {
+               if (mptsas_target_reset(ioc, channel, id)) {
+                       target_reset_list->target_reset_issued = 1;
+                       hd->resetPending = 1;
+               }
+               return;
+       }
+
+       /*
+        * enable work queue to remove device from upper layers
+        */
+       list_del(&target_reset_list->list);
+
+       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+       if (!ev) {
+               dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
+                   ioc->name,__FUNCTION__, __LINE__));
+               return;
+       }
+
+       INIT_WORK(&ev->work, mptsas_hotplug_work);
+       ev->ioc = ioc;
+       ev->handle = le16_to_cpu(sas_event_data->DevHandle);
+       ev->parent_handle =
+           le16_to_cpu(sas_event_data->ParentDevHandle);
+       ev->channel = channel;
+       ev->id =id;
+       ev->phy_id = sas_event_data->PhyNum;
+       memcpy(&sas_address, &sas_event_data->SASAddress,
+           sizeof(__le64));
+       ev->sas_address = le64_to_cpu(sas_address);
+       ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
+       ev->event_type = MPTSAS_DEL_DEVICE;
+       schedule_work(&ev->work);
+       kfree(target_reset_list);
+
+       /*
+        * issue target reset to next device in the queue
+        */
+
+       head = &hd->target_reset_list;
+       if (list_empty(head))
+               return;
+
+       target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
+           list);
+
+       sas_event_data = &target_reset_list->sas_event_data;
+       id = sas_event_data->TargetID;
+       channel = sas_event_data->Bus;
+
+       if (mptsas_target_reset(ioc, channel, id)) {
+               target_reset_list->target_reset_issued = 1;
+               hd->resetPending = 1;
+       }
+}
+
+/**
+ * mptsas_taskmgmt_complete
+ *
+ * @ioc
+ * @mf
+ * @mr
+ *
+ **/
+static int
+mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
+{
+       mptsas_dev_reset_complete(ioc);
+       return mptscsih_taskmgmt_complete(ioc, mf, mr);
+}
+
+/**
+ * mptscsih_ioc_reset
+ *
+ * @ioc
+ * @reset_phase
+ *
+ **/
+static int
+mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
+{
+       MPT_SCSI_HOST   *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+       struct mptsas_target_reset_event *target_reset_list, *n;
+       int rc;
+
+       rc = mptscsih_ioc_reset(ioc, reset_phase);
+
+       if (ioc->bus_type != SAS)
+               goto out;
+
+       if (reset_phase != MPT_IOC_POST_RESET)
+               goto out;
+
+       if (!hd || !hd->ioc)
+               goto out;
+
+       if (list_empty(&hd->target_reset_list))
+               goto out;
+
+       /* flush the target_reset_list */
+       list_for_each_entry_safe(target_reset_list, n,
+           &hd->target_reset_list, list) {
+               list_del(&target_reset_list->list);
+               kfree(target_reset_list);
+       }
+
+ out:
+       return rc;
+}
+
 static int
 mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
                u32 form, u32 form_specific)
@@ -659,8 +928,7 @@ mptsas_target_alloc(struct scsi_target *starget)
        struct Scsi_Host *host = dev_to_shost(&starget->dev);
        MPT_SCSI_HOST           *hd = (MPT_SCSI_HOST *)host->hostdata;
        VirtTarget              *vtarget;
-       u32                     target_id;
-       u32                     channel;
+       u8                      id, channel;
        struct sas_rphy         *rphy;
        struct mptsas_portinfo  *p;
        int                      i;
@@ -671,15 +939,19 @@ mptsas_target_alloc(struct scsi_target *starget)
 
        vtarget->starget = starget;
        vtarget->ioc_id = hd->ioc->id;
-       vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
-
-       target_id = starget->id;
+       vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
+       id = starget->id;
        channel = 0;
 
-       hd->Targets[target_id] = vtarget;
-
-       if (starget->channel == MPTSAS_RAID_CHANNEL)
+       /*
+        * RAID volumes placed beyond the last expected port.
+        */
+       if (starget->channel == MPTSAS_RAID_CHANNEL) {
+               for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
+                       if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
+                               channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
                goto out;
+       }
 
        rphy = dev_to_rphy(starget->dev.parent);
        mutex_lock(&hd->ioc->sas_topology_mutex);
@@ -688,18 +960,19 @@ mptsas_target_alloc(struct scsi_target *starget)
                        if (p->phy_info[i].attached.sas_address !=
                                        rphy->identify.sas_address)
                                continue;
-                       target_id = p->phy_info[i].attached.id;
+                       id = p->phy_info[i].attached.id;
                        channel = p->phy_info[i].attached.channel;
                        mptsas_set_starget(&p->phy_info[i], starget);
 
                        /*
                         * Exposing hidden raid components
                         */
-                       if (mptscsih_is_phys_disk(hd->ioc, target_id)) {
-                               target_id = mptscsih_raid_id_to_num(hd,
-                                               target_id);
+                       if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
+                               id = mptscsih_raid_id_to_num(hd->ioc,
+                                               channel, id);
                                vtarget->tflags |=
                                    MPT_TARGET_FLAGS_RAID_COMPONENT;
+                               p->phy_info[i].attached.phys_disk_num = id;
                        }
                        mutex_unlock(&hd->ioc->sas_topology_mutex);
                        goto out;
@@ -711,8 +984,8 @@ mptsas_target_alloc(struct scsi_target *starget)
        return -ENXIO;
 
  out:
-       vtarget->target_id = target_id;
-       vtarget->bus_id = channel;
+       vtarget->id = id;
+       vtarget->channel = channel;
        starget->hostdata = vtarget;
        return 0;
 }
@@ -784,7 +1057,8 @@ mptsas_slave_alloc(struct scsi_device *sdev)
                         * Exposing hidden raid components
                         */
                        if (mptscsih_is_phys_disk(hd->ioc,
-                                       p->phy_info[i].attached.id))
+                           p->phy_info[i].attached.channel,
+                           p->phy_info[i].attached.id))
                                sdev->no_uld_attach = 1;
                        mutex_unlock(&hd->ioc->sas_topology_mutex);
                        goto out;
@@ -806,13 +1080,14 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 {
        VirtDevice      *vdev = SCpnt->device->hostdata;
 
-//     scsi_print_command(SCpnt);
-       if (vdev->vtarget->deleted) {
+       if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
                SCpnt->result = DID_NO_CONNECT << 16;
                done(SCpnt);
                return 0;
        }
 
+//     scsi_print_command(SCpnt);
+
        return mptscsih_qcmd(SCpnt,done);
 }
 
@@ -1112,9 +1387,6 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                goto out_free_consistent;
        }
 
-       if (port_info->num_phys)
-               port_info->handle =
-                   le16_to_cpu(buffer->PhyData[0].ControllerDevHandle);
        for (i = 0; i < port_info->num_phys; i++) {
                mptsas_print_phy_data(&buffer->PhyData[i]);
                port_info->phy_info[i].phy_id = i;
@@ -1123,6 +1395,8 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
                port_info->phy_info[i].negotiated_link_rate =
                    buffer->PhyData[i].NegotiatedLinkRate;
                port_info->phy_info[i].portinfo = port_info;
+               port_info->phy_info[i].handle =
+                   le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
        }
 
  out_free_consistent:
@@ -1259,6 +1533,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
        device_info->phy_id = buffer->PhyNum;
        device_info->port_id = buffer->PhysicalPort;
        device_info->id = buffer->TargetID;
+       device_info->phys_disk_num = ~0;
        device_info->channel = buffer->Bus;
        memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
        device_info->sas_address = le64_to_cpu(sas_address);
@@ -1323,7 +1598,6 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
 
        /* save config data */
        port_info->num_phys = buffer->NumPhys;
-       port_info->handle = le16_to_cpu(buffer->DevHandle);
        port_info->phy_info = kcalloc(port_info->num_phys,
                sizeof(*port_info->phy_info),GFP_KERNEL);
        if (!port_info->phy_info) {
@@ -1331,8 +1605,11 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
                goto out_free_consistent;
        }
 
-       for (i = 0; i < port_info->num_phys; i++)
+       for (i = 0; i < port_info->num_phys; i++) {
                port_info->phy_info[i].portinfo = port_info;
+               port_info->phy_info[i].handle =
+                   le16_to_cpu(buffer->DevHandle);
+       }
 
  out_free_consistent:
        pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
@@ -1700,7 +1977,6 @@ static int
 mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
 {
        struct mptsas_portinfo *port_info, *hba;
-       u32 handle = 0xFFFF;
        int error = -ENOMEM, i;
 
        hba = kzalloc(sizeof(*port_info), GFP_KERNEL);
@@ -1712,34 +1988,36 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
                goto out_free_port_info;
 
        mutex_lock(&ioc->sas_topology_mutex);
-       ioc->handle = hba->handle;
-       port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle);
+       ioc->handle = hba->phy_info[0].handle;
+       port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
        if (!port_info) {
                port_info = hba;
                list_add_tail(&port_info->list, &ioc->sas_topology);
        } else {
-               port_info->handle = hba->handle;
-               for (i = 0; i < hba->num_phys; i++)
+               for (i = 0; i < hba->num_phys; i++) {
                        port_info->phy_info[i].negotiated_link_rate =
                                hba->phy_info[i].negotiated_link_rate;
+                       port_info->phy_info[i].handle =
+                               hba->phy_info[i].handle;
+                       port_info->phy_info[i].port_id =
+                               hba->phy_info[i].port_id;
+               }
                kfree(hba->phy_info);
                kfree(hba);
                hba = NULL;
        }
        mutex_unlock(&ioc->sas_topology_mutex);
-
        for (i = 0; i < port_info->num_phys; i++) {
                mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
                        (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
                         MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
 
                mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
-                       (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE <<
-                        MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle);
+                       (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+                        MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                        port_info->phy_info[i].handle);
                port_info->phy_info[i].identify.phy_id =
-                   port_info->phy_info[i].phy_id;
-               handle = port_info->phy_info[i].identify.handle;
-
+                   port_info->phy_info[i].phy_id = i;
                if (port_info->phy_info[i].attached.handle)
                        mptsas_sas_device_pg0(ioc,
                                &port_info->phy_info[i].attached,
@@ -1775,12 +2053,12 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
                goto out;
 
        error = mptsas_sas_expander_pg0(ioc, ex,
-               (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
-                MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
+           (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
+            MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);
        if (error)
                goto out_free_port_info;
 
-       *handle = ex->handle;
+       *handle = ex->phy_info[0].handle;
 
        mutex_lock(&ioc->sas_topology_mutex);
        port_info = mptsas_find_portinfo_by_handle(ioc, *handle);
@@ -1788,7 +2066,12 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
                port_info = ex;
                list_add_tail(&port_info->list, &ioc->sas_topology);
        } else {
-               port_info->handle = ex->handle;
+               for (i = 0; i < ex->num_phys; i++) {
+                       port_info->phy_info[i].handle =
+                               ex->phy_info[i].handle;
+                       port_info->phy_info[i].port_id =
+                               ex->phy_info[i].port_id;
+               }
                kfree(ex->phy_info);
                kfree(ex);
                ex = NULL;
@@ -1866,8 +2149,6 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
        struct mptsas_portinfo buffer;
        struct mptsas_portinfo *port_info, *n, *parent;
        struct mptsas_phyinfo *phy_info;
-       struct scsi_target * starget;
-       VirtTarget * vtarget;
        struct sas_port * port;
        int i;
        u64     expander_sas_address;
@@ -1882,26 +2163,8 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
 
                if (mptsas_sas_expander_pg0(ioc, &buffer,
                     (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
-                    MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
-
-                       /*
-                        * Issue target reset to all child end devices
-                        * then mark them deleted to prevent further
-                        * IO going to them.
-                        */
-                       phy_info = port_info->phy_info;
-                       for (i = 0; i < port_info->num_phys; i++, phy_info++) {
-                               starget = mptsas_get_starget(phy_info);
-                               if (!starget)
-                                       continue;
-                               vtarget = starget->hostdata;
-                               if(vtarget->deleted)
-                                       continue;
-                               vtarget->deleted = 1;
-                               mptsas_target_reset(ioc, vtarget);
-                               sas_port_delete(mptsas_get_port(phy_info));
-                               mptsas_port_delete(phy_info->port_details);
-                       }
+                    MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
+                    port_info->phy_info[0].handle)) {
 
                        /*
                         * Obtain the port_info instance to the parent port
@@ -1970,11 +2233,13 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
        /*
          Reporting RAID volumes.
        */
+       if (!ioc->ir_firmware)
+               goto out;
        if (!ioc->raid_data.pIocPg2)
                goto out;
        if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
                goto out;
-       for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+       for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
                scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
                    ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
        }
@@ -2006,9 +2271,10 @@ __mptsas_discovery_work(MPT_ADAPTER *ioc)
  *(Mutex LOCKED)
  */
 static void
-mptsas_discovery_work(void * arg)
+mptsas_discovery_work(struct work_struct *work)
 {
-       struct mptsas_discovery_event *ev = arg;
+       struct mptsas_discovery_event *ev =
+               container_of(work, struct mptsas_discovery_event, work);
        MPT_ADAPTER *ioc = ev->ioc;
 
        mutex_lock(&ioc->sas_discovery_mutex);
@@ -2027,12 +2293,37 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
        mutex_lock(&ioc->sas_topology_mutex);
        list_for_each_entry(port_info, &ioc->sas_topology, list) {
                for (i = 0; i < port_info->num_phys; i++) {
+                       if (!mptsas_is_end_device(
+                               &port_info->phy_info[i].attached))
+                               continue;
                        if (port_info->phy_info[i].attached.sas_address
                            != sas_address)
                                continue;
+                       phy_info = &port_info->phy_info[i];
+                       break;
+               }
+       }
+       mutex_unlock(&ioc->sas_topology_mutex);
+       return phy_info;
+}
+
+static struct mptsas_phyinfo *
+mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       struct mptsas_portinfo *port_info;
+       struct mptsas_phyinfo *phy_info = NULL;
+       int i;
+
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_for_each_entry(port_info, &ioc->sas_topology, list) {
+               for (i = 0; i < port_info->num_phys; i++) {
                        if (!mptsas_is_end_device(
                                &port_info->phy_info[i].attached))
                                continue;
+                       if (port_info->phy_info[i].attached.id != id)
+                               continue;
+                       if (port_info->phy_info[i].attached.channel != channel)
+                               continue;
                        phy_info = &port_info->phy_info[i];
                        break;
                }
@@ -2042,7 +2333,7 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
 }
 
 static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
+mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
        struct mptsas_portinfo *port_info;
        struct mptsas_phyinfo *phy_info = NULL;
@@ -2051,11 +2342,15 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
        mutex_lock(&ioc->sas_topology_mutex);
        list_for_each_entry(port_info, &ioc->sas_topology, list) {
                for (i = 0; i < port_info->num_phys; i++) {
-                       if (port_info->phy_info[i].attached.id != id)
-                               continue;
                        if (!mptsas_is_end_device(
                                &port_info->phy_info[i].attached))
                                continue;
+                       if (port_info->phy_info[i].attached.phys_disk_num == ~0)
+                               continue;
+                       if (port_info->phy_info[i].attached.phys_disk_num != id)
+                               continue;
+                       if (port_info->phy_info[i].attached.channel != channel)
+                               continue;
                        phy_info = &port_info->phy_info[i];
                        break;
                }
@@ -2068,9 +2363,9 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
  * Work queue thread to clear the persitency table
  */
 static void
-mptsas_persist_clear_table(void * arg)
+mptsas_persist_clear_table(struct work_struct *work)
 {
-       MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
+       MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
 
        mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
 }
@@ -2078,8 +2373,10 @@ mptsas_persist_clear_table(void * arg)
 static void
 mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
 {
+       int rc;
+
        sdev->no_uld_attach = data ? 1 : 0;
-       scsi_device_reprobe(sdev);
+       rc = scsi_device_reprobe(sdev);
 }
 
 static void
@@ -2089,13 +2386,85 @@ mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
                        mptsas_reprobe_lun);
 }
 
+static void
+mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
+{
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
+       dma_addr_t                      dma_handle;
+       pRaidVolumePage0_t              buffer = NULL;
+       RaidPhysDiskPage0_t             phys_disk;
+       int                             i;
+       struct mptsas_hotplug_event     *ev;
+
+       memset(&cfg, 0 , sizeof(CONFIGPARMS));
+       memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+       hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+       cfg.pageAddr = (channel << 8) + id;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+       if (mpt_config(ioc, &cfg) != 0)
+               goto out;
+
+       if (!hdr.PageLength)
+               goto out;
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+           &dma_handle);
+
+       if (!buffer)
+               goto out;
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+       if (mpt_config(ioc, &cfg) != 0)
+               goto out;
+
+       if (!(buffer->VolumeStatus.Flags &
+           MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
+               goto out;
+
+       if (!buffer->NumPhysDisks)
+               goto out;
+
+       for (i = 0; i < buffer->NumPhysDisks; i++) {
+
+               if (mpt_raid_phys_disk_pg0(ioc,
+                   buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
+                       continue;
+
+               ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+               if (!ev) {
+                       printk(KERN_WARNING "mptsas: lost hotplug event\n");
+                       goto out;
+               }
+
+               INIT_WORK(&ev->work, mptsas_hotplug_work);
+               ev->ioc = ioc;
+               ev->id = phys_disk.PhysDiskID;
+               ev->channel = phys_disk.PhysDiskBus;
+               ev->phys_disk_num_valid = 1;
+               ev->phys_disk_num = phys_disk.PhysDiskNum;
+               ev->event_type = MPTSAS_ADD_DEVICE;
+               schedule_work(&ev->work);
+       }
+
+ out:
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+                   dma_handle);
+}
 /*
  * Work queue thread to handle SAS hotplug events
  */
 static void
-mptsas_hotplug_work(void *arg)
+mptsas_hotplug_work(struct work_struct *work)
 {
-       struct mptsas_hotplug_event *ev = arg;
+       struct mptsas_hotplug_event *ev =
+               container_of(work, struct mptsas_hotplug_event, work);
+
        MPT_ADAPTER *ioc = ev->ioc;
        struct mptsas_phyinfo *phy_info;
        struct sas_rphy *rphy;
@@ -2108,17 +2477,43 @@ mptsas_hotplug_work(void *arg)
        VirtTarget *vtarget;
        VirtDevice *vdevice;
 
-
        mutex_lock(&ioc->sas_discovery_mutex);
        switch (ev->event_type) {
        case MPTSAS_DEL_DEVICE:
 
-               phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id);
+               phy_info = NULL;
+               if (ev->phys_disk_num_valid) {
+                       if (ev->hidden_raid_component){
+                               if (mptsas_sas_device_pg0(ioc, &sas_device,
+                                   (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
+                                    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                                   (ev->channel << 8) + ev->id)) {
+                                       dfailprintk((MYIOC_s_ERR_FMT
+                                       "%s: exit at line=%d\n", ioc->name,
+                                               __FUNCTION__, __LINE__));
+                                       break;
+                               }
+                               phy_info = mptsas_find_phyinfo_by_sas_address(
+                                   ioc, sas_device.sas_address);
+                       }else
+                               phy_info = mptsas_find_phyinfo_by_phys_disk_num(
+                                   ioc, ev->channel, ev->phys_disk_num);
+               }
+
+               if (!phy_info)
+                       phy_info = mptsas_find_phyinfo_by_target(ioc,
+                           ev->channel, ev->id);
 
                /*
                 * Sanity checks, for non-existing phys and remote rphys.
                 */
-               if (!phy_info || !phy_info->port_details) {
+               if (!phy_info){
+                       dfailprintk((MYIOC_s_ERR_FMT
+                               "%s: exit at line=%d\n", ioc->name,
+                               __FUNCTION__, __LINE__));
+                       break;
+               }
+               if (!phy_info->port_details) {
                        dfailprintk((MYIOC_s_ERR_FMT
                                "%s: exit at line=%d\n", ioc->name,
                                __FUNCTION__, __LINE__));
@@ -2131,6 +2526,7 @@ mptsas_hotplug_work(void *arg)
                                __FUNCTION__, __LINE__));
                        break;
                }
+
                port = mptsas_get_port(phy_info);
                if (!port) {
                        dfailprintk((MYIOC_s_ERR_FMT
@@ -2153,28 +2549,35 @@ mptsas_hotplug_work(void *arg)
                        /*
                         * Handling  RAID components
                         */
-                       if (ev->phys_disk_num_valid) {
-                               vtarget->target_id = ev->phys_disk_num;
-                               vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
+                       if (ev->phys_disk_num_valid &&
+                           ev->hidden_raid_component) {
+                               printk(MYIOC_s_INFO_FMT
+                                   "RAID Hidding: channel=%d, id=%d, "
+                                   "physdsk %d \n", ioc->name, ev->channel,
+                                   ev->id, ev->phys_disk_num);
+                               vtarget->id = ev->phys_disk_num;
+                               vtarget->tflags |=
+                                   MPT_TARGET_FLAGS_RAID_COMPONENT;
                                mptsas_reprobe_target(starget, 1);
-                               break;
+                               phy_info->attached.phys_disk_num =
+                                   ev->phys_disk_num;
+                       break;
                        }
-
-                       vtarget->deleted = 1;
-                       mptsas_target_reset(ioc, vtarget);
                }
 
-               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+               if (phy_info->attached.device_info &
+                   MPI_SAS_DEVICE_INFO_SSP_TARGET)
                        ds = "ssp";
-               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
+               if (phy_info->attached.device_info &
+                   MPI_SAS_DEVICE_INFO_STP_TARGET)
                        ds = "stp";
-               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+               if (phy_info->attached.device_info &
+                   MPI_SAS_DEVICE_INFO_SATA_DEVICE)
                        ds = "sata";
 
                printk(MYIOC_s_INFO_FMT
                       "removing %s device, channel %d, id %d, phy %d\n",
                       ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
-
 #ifdef MPT_DEBUG_SAS_WIDE
                dev_printk(KERN_DEBUG, &port->dev,
                    "delete port (%d)\n", port->port_identifier);
@@ -2192,14 +2595,14 @@ mptsas_hotplug_work(void *arg)
                 */
                if (mptsas_sas_device_pg0(ioc, &sas_device,
                    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
-                    MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) {
+                    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+                       (ev->channel << 8) + ev->id)) {
                                dfailprintk((MYIOC_s_ERR_FMT
                                        "%s: exit at line=%d\n", ioc->name,
                                        __FUNCTION__, __LINE__));
                        break;
                }
 
-               ssleep(2);
                __mptsas_discovery_work(ioc);
 
                phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
@@ -2213,7 +2616,8 @@ mptsas_hotplug_work(void *arg)
                }
 
                starget = mptsas_get_starget(phy_info);
-               if (starget) {
+               if (starget && (!ev->hidden_raid_component)){
+
                        vtarget = starget->hostdata;
 
                        if (!vtarget) {
@@ -2226,9 +2630,15 @@ mptsas_hotplug_work(void *arg)
                         * Handling  RAID components
                         */
                        if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
-                               vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
-                               vtarget->target_id = ev->id;
+                               printk(MYIOC_s_INFO_FMT
+                                   "RAID Exposing: channel=%d, id=%d, "
+                                   "physdsk %d \n", ioc->name, ev->channel,
+                                   ev->id, ev->phys_disk_num);
+                               vtarget->tflags &=
+                                   ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+                               vtarget->id = ev->id;
                                mptsas_reprobe_target(starget, 0);
+                               phy_info->attached.phys_disk_num = ~0;
                        }
                        break;
                }
@@ -2237,8 +2647,10 @@ mptsas_hotplug_work(void *arg)
                        dfailprintk((MYIOC_s_ERR_FMT
                                "%s: exit at line=%d\n", ioc->name,
                                __FUNCTION__, __LINE__));
+                       if (ev->channel) printk("%d\n", __LINE__);
                        break;
                }
+
                port = mptsas_get_port(phy_info);
                if (!port) {
                        dfailprintk((MYIOC_s_ERR_FMT
@@ -2246,15 +2658,17 @@ mptsas_hotplug_work(void *arg)
                                __FUNCTION__, __LINE__));
                        break;
                }
-
                memcpy(&phy_info->attached, &sas_device,
                    sizeof(struct mptsas_devinfo));
 
-               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+               if (phy_info->attached.device_info &
+                   MPI_SAS_DEVICE_INFO_SSP_TARGET)
                        ds = "ssp";
-               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
+               if (phy_info->attached.device_info &
+                   MPI_SAS_DEVICE_INFO_STP_TARGET)
                        ds = "stp";
-               if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+               if (phy_info->attached.device_info &
+                   MPI_SAS_DEVICE_INFO_SATA_DEVICE)
                        ds = "sata";
 
                printk(MYIOC_s_INFO_FMT
@@ -2295,19 +2709,21 @@ mptsas_hotplug_work(void *arg)
                break;
        case MPTSAS_DEL_RAID:
                sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
-                   ev->id, 0);
+                   ev->id, 0);
                if (!sdev)
                        break;
                printk(MYIOC_s_INFO_FMT
                       "removing raid volume, channel %d, id %d\n",
                       ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
                vdevice = sdev->hostdata;
-               vdevice->vtarget->deleted = 1;
-               mptsas_target_reset(ioc, vdevice->vtarget);
                scsi_remove_device(sdev);
                scsi_device_put(sdev);
                mpt_findImVolumes(ioc);
                break;
+       case MPTSAS_ADD_INACTIVE_VOLUME:
+               mptsas_adding_inactive_raid_components(ioc,
+                   ev->channel, ev->id);
+               break;
        case MPTSAS_IGNORE_EVENT:
        default:
                break;
@@ -2315,7 +2731,6 @@ mptsas_hotplug_work(void *arg)
 
        mutex_unlock(&ioc->sas_discovery_mutex);
        kfree(ev);
-
 }
 
 static void
@@ -2333,15 +2748,19 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
                return;
 
        switch (sas_event_data->ReasonCode) {
-       case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
        case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
+
+               mptsas_target_reset_queue(ioc, sas_event_data);
+               break;
+
+       case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
                ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
                if (!ev) {
                        printk(KERN_WARNING "mptsas: lost hotplug event\n");
                        break;
                }
 
-               INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
+               INIT_WORK(&ev->work, mptsas_hotplug_work);
                ev->ioc = ioc;
                ev->handle = le16_to_cpu(sas_event_data->DevHandle);
                ev->parent_handle =
@@ -2366,18 +2785,23 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
         * Persistent table is full.
         */
                INIT_WORK(&ioc->sas_persist_task,
-                   mptsas_persist_clear_table, (void *)ioc);
+                   mptsas_persist_clear_table);
                schedule_work(&ioc->sas_persist_task);
                break;
+       /*
+        * TODO, handle other events
+        */
        case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
-       /* TODO */
+       case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
        case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
-       /* TODO */
+       case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
+       case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
+       case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
+       case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
        default:
                break;
        }
 }
-
 static void
 mptsas_send_raid_event(MPT_ADAPTER *ioc,
                EVENT_DATA_RAID *raid_event_data)
@@ -2395,34 +2819,39 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc,
                return;
        }
 
-       INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
+       INIT_WORK(&ev->work, mptsas_hotplug_work);
        ev->ioc = ioc;
        ev->id = raid_event_data->VolumeID;
+       ev->channel = raid_event_data->VolumeBus;
        ev->event_type = MPTSAS_IGNORE_EVENT;
 
        switch (raid_event_data->ReasonCode) {
        case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
+               ev->phys_disk_num_valid = 1;
+               ev->phys_disk_num = raid_event_data->PhysDiskNum;
                ev->event_type = MPTSAS_ADD_DEVICE;
                break;
        case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
-               ioc->raid_data.isRaid = 1;
                ev->phys_disk_num_valid = 1;
                ev->phys_disk_num = raid_event_data->PhysDiskNum;
+               ev->hidden_raid_component = 1;
                ev->event_type = MPTSAS_DEL_DEVICE;
                break;
        case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
                switch (state) {
                case MPI_PD_STATE_ONLINE:
-                       ioc->raid_data.isRaid = 1;
+               case MPI_PD_STATE_NOT_COMPATIBLE:
                        ev->phys_disk_num_valid = 1;
                        ev->phys_disk_num = raid_event_data->PhysDiskNum;
+                       ev->hidden_raid_component = 1;
                        ev->event_type = MPTSAS_ADD_DEVICE;
                        break;
                case MPI_PD_STATE_MISSING:
-               case MPI_PD_STATE_NOT_COMPATIBLE:
                case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
                case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
                case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
+                       ev->phys_disk_num_valid = 1;
+                       ev->phys_disk_num = raid_event_data->PhysDiskNum;
                        ev->event_type = MPTSAS_DEL_DEVICE;
                        break;
                default:
@@ -2474,11 +2903,40 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc,
        ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
        if (!ev)
                return;
-       INIT_WORK(&ev->work, mptsas_discovery_work, ev);
+       INIT_WORK(&ev->work, mptsas_discovery_work);
        ev->ioc = ioc;
        schedule_work(&ev->work);
 };
 
+/*
+ * mptsas_send_ir2_event - handle exposing hidden disk when
+ * an inactive raid volume is added
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @ir2_data
+ *
+ */
+static void
+mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data)
+{
+       struct mptsas_hotplug_event *ev;
+
+       if (ir2_data->ReasonCode !=
+           MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED)
+               return;
+
+       ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+       if (!ev)
+               return;
+
+       INIT_WORK(&ev->work, mptsas_hotplug_work);
+       ev->ioc = ioc;
+       ev->id = ir2_data->TargetID;
+       ev->channel = ir2_data->Bus;
+       ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
+
+       schedule_work(&ev->work);
+};
 
 static int
 mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
@@ -2511,14 +2969,17 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
                break;
        case MPI_EVENT_PERSISTENT_TABLE_FULL:
                INIT_WORK(&ioc->sas_persist_task,
-                   mptsas_persist_clear_table,
-                   (void *)ioc);
+                   mptsas_persist_clear_table);
                schedule_work(&ioc->sas_persist_task);
                break;
         case MPI_EVENT_SAS_DISCOVERY:
                mptsas_send_discovery_event(ioc,
                        (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
                break;
+       case MPI_EVENT_IR2:
+               mptsas_send_ir2_event(ioc,
+                   (PTR_MPI_EVENT_DATA_IR2)reply->Data);
+               break;
        default:
                rc = mptscsih_event_process(ioc, reply);
                break;
@@ -2606,12 +3067,11 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        /* set 16 byte cdb's */
        sh->max_cmd_len = 16;
 
-       sh->max_id = ioc->pfacts->MaxDevices + 1;
+       sh->max_id = ioc->pfacts[0].PortSCSIID;
+       sh->max_lun = max_lun;
 
        sh->transportt = mptsas_transport_template;
 
-       sh->max_lun = MPT_LAST_LUN + 1;
-       sh->max_channel = 0;
        sh->this_id = ioc->pfacts[0].PortSCSIID;
 
        /* Required entry.
@@ -2654,8 +3114,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                sh->sg_tablesize = numSGE;
        }
 
-       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
-
        hd = (MPT_SCSI_HOST *) sh->hostdata;
        hd->ioc = ioc;
 
@@ -2671,19 +3129,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
                 ioc->name, hd->ScsiLookup));
 
-       /* Allocate memory for the device structures.
-        * A non-Null pointer at an offset
-        * indicates a device exists.
-        * max_id = 1 + maximum id (hosts.h)
-        */
-       hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
-       if (!hd->Targets) {
-               error = -ENOMEM;
-               goto out_mptsas_probe;
-       }
-
-       dprintk((KERN_INFO "  vtarget @ %p\n", hd->Targets));
-
        /* Clear the TM flags
         */
        hd->tmPending = 0;
@@ -2708,15 +3153,17 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        ioc->sas_data.ptClear = mpt_pt_clear;
 
+       init_waitqueue_head(&hd->scandv_waitq);
+       hd->scandv_wait_done = 0;
+       hd->last_queue_full = 0;
+       INIT_LIST_HEAD(&hd->target_reset_list);
+       spin_unlock_irqrestore(&ioc->FreeQlock, flags);
+
        if (ioc->sas_data.ptClear==1) {
                mptbase_sas_persist_operation(
                    ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
        }
 
-       init_waitqueue_head(&hd->scandv_waitq);
-       hd->scandv_wait_done = 0;
-       hd->last_queue_full = 0;
-
        error = scsi_add_host(sh, &ioc->pcidev->dev);
        if (error) {
                dprintk((KERN_ERR MYNAM
@@ -2740,7 +3187,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
        struct mptsas_portinfo *p, *n;
        int i;
 
-       ioc->sas_discovery_ignore_events=1;
+       ioc->sas_discovery_ignore_events = 1;
        sas_remove_host(ioc->sh);
 
        mutex_lock(&ioc->sas_topology_mutex);
@@ -2795,7 +3242,7 @@ mptsas_init(void)
                return -ENODEV;
 
        mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
-       mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
+       mptsasTaskCtx = mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
        mptsasInternalCtx =
                mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
        mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
@@ -2805,7 +3252,7 @@ mptsas_init(void)
                  ": Registered for IOC event notifications\n"));
        }
 
-       if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) {
+       if (mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset) == 0) {
                dprintk((KERN_INFO MYNAM
                  ": Registered for IOC reset notifications\n"));
        }