]> git.karo-electronics.de Git - linux-beck.git/commitdiff
[SCSI] mpt fusion: RAID device handling and Dual port Raid support is added
authorKashyap, Desai <kashyap.desai@lsi.com>
Fri, 29 May 2009 11:23:56 +0000 (16:53 +0530)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Tue, 9 Jun 2009 22:44:11 +0000 (17:44 -0500)
1. Handle integrated Raid device(Add/Delete) and error condition and check
   related to Raid device. is_logical_volume will represent logical volume
   device.
2. Raid device dual port support is added. Main functions to support this
   feature are mpt_raid_phys_disk_get_num_paths and mpt_raid_phys_disk_pg1.

Signed-off-by: Kashyap Desai <kadesai@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptsas.h
drivers/message/fusion/mptscsih.c

index 9f6b315624aaf2ba3907d783367f77fc71fb6005..44b9315044579639e9e1e10463887f866c38c9ef 100644 (file)
@@ -5762,6 +5762,161 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
        return rc;
 }
 
+/**
+ *     mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
+ *     @ioc: Pointer to a Adapter Structure
+ *     @phys_disk_num: io unit unique phys disk num generated by the ioc
+ *
+ *     Return:
+ *     returns number paths
+ **/
+int
+mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
+{
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
+       dma_addr_t                      dma_handle;
+       pRaidPhysDiskPage1_t            buffer = NULL;
+       int                             rc;
+
+       memset(&cfg, 0 , sizeof(CONFIGPARMS));
+       memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+
+       hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+       hdr.PageNumber = 1;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = 0;
+               goto out;
+       }
+
+       if (!hdr.PageLength) {
+               rc = 0;
+               goto out;
+       }
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+           &dma_handle);
+
+       if (!buffer) {
+               rc = 0;
+               goto out;
+       }
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.pageAddr = phys_disk_num;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = 0;
+               goto out;
+       }
+
+       rc = buffer->NumPhysDiskPaths;
+ out:
+
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+                   dma_handle);
+
+       return rc;
+}
+EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
+
+/**
+ *     mpt_raid_phys_disk_pg1 - returns phys disk page 1
+ *     @ioc: Pointer to a Adapter Structure
+ *     @phys_disk_num: io unit unique phys disk num generated by the ioc
+ *     @phys_disk: requested payload data returned
+ *
+ *     Return:
+ *     0 on success
+ *     -EFAULT if read of config page header fails or data pointer not NULL
+ *     -ENOMEM if pci_alloc failed
+ **/
+int
+mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
+               RaidPhysDiskPage1_t *phys_disk)
+{
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
+       dma_addr_t                      dma_handle;
+       pRaidPhysDiskPage1_t            buffer = NULL;
+       int                             rc;
+       int                             i;
+       __le64                          sas_address;
+
+       memset(&cfg, 0 , sizeof(CONFIGPARMS));
+       memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+       rc = 0;
+
+       hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
+       hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
+       hdr.PageNumber = 1;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.physAddr = -1;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       if (!hdr.PageLength) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
+           &dma_handle);
+
+       if (!buffer) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       cfg.physAddr = dma_handle;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+       cfg.pageAddr = phys_disk_num;
+
+       if (mpt_config(ioc, &cfg) != 0) {
+               rc = -EFAULT;
+               goto out;
+       }
+
+       phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
+       phys_disk->PhysDiskNum = phys_disk_num;
+       for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
+               phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
+               phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
+               phys_disk->Path[i].OwnerIdentifier =
+                               buffer->Path[i].OwnerIdentifier;
+               phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
+               memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
+               sas_address = le64_to_cpu(sas_address);
+               memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
+               memcpy(&sas_address,
+                               &buffer->Path[i].OwnerWWID, sizeof(__le64));
+               sas_address = le64_to_cpu(sas_address);
+               memcpy(&phys_disk->Path[i].OwnerWWID,
+                               &sas_address, sizeof(__le64));
+       }
+
+ out:
+
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+                   dma_handle);
+
+       return rc;
+}
+EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
+
+
 /**
  *     mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
  *     @ioc: Pointer to a Adapter Strucutre
@@ -7170,6 +7325,18 @@ mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
                            "id=%d channel=%d phys_num=%d",
                            id, channel, phys_num);
                        break;
+               case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Dual Port Added: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
+                       break;
+               case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
+                       snprintf(evStr, EVENT_DESCR_STR_SZ,
+                           "IR2: Dual Port Removed: "
+                           "id=%d channel=%d phys_num=%d",
+                           id, channel, phys_num);
+                       break;
                default:
                        ds = "IR2";
                break;
index 91499d1275c4db5e57f7928368fa01daca5b0c15..4f3d4c34bcd8427c1585986c8a157a3ad61d4961 100644 (file)
@@ -958,6 +958,10 @@ extern void         mpt_free_fw_memory(MPT_ADAPTER *ioc);
 extern int      mpt_findImVolumes(MPT_ADAPTER *ioc);
 extern int      mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
 extern int      mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk);
+extern int     mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
+               pRaidPhysDiskPage1_t phys_disk);
+extern int     mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc,
+               u8 phys_disk_num);
 extern int      mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
 extern void     mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
 extern void     mpt_halt_firmware(MPT_ADAPTER *ioc);
index da22141152d7a1caf7a1df01b2c767bbd53b2071..72158237f5e892f6a84f84c62b84bb6a7dd807e2 100644 (file)
@@ -121,6 +121,7 @@ static void mptsas_expander_delete(MPT_ADAPTER *ioc,
 static void mptsas_send_expander_event(struct fw_event_work *fw_event);
 static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
 static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
+static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
 
 static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
                                        MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
@@ -542,9 +543,10 @@ mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
        mutex_lock(&ioc->sas_device_info_mutex);
        list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
            list) {
-               if ((sas_info->sas_address == sas_address ||
-                       (sas_info->fw.channel == channel &&
-                       sas_info->fw.id == id))) {
+               if (!sas_info->is_logical_volume &&
+                   (sas_info->sas_address == sas_address ||
+                   (sas_info->fw.channel == channel &&
+                    sas_info->fw.id == id))) {
                        list_del(&sas_info->list);
                        kfree(sas_info);
                }
@@ -616,6 +618,100 @@ mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
            sas_device.slot, enclosure_info.enclosure_logical_id);
 }
 
+/**
+ *     mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding
+ *     each individual device to list
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @channel: fw mapped id's
+ *     @id:
+ *
+ **/
+static void
+mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
+               struct scsi_target *starget)
+{
+       CONFIGPARMS                     cfg;
+       ConfigPageHeader_t              hdr;
+       dma_addr_t                      dma_handle;
+       pRaidVolumePage0_t              buffer = NULL;
+       int                             i;
+       RaidPhysDiskPage0_t             phys_disk;
+       struct mptsas_device_info       *sas_info, *next;
+
+       memset(&cfg, 0 , sizeof(CONFIGPARMS));
+       memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+       hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
+       /* assumption that all volumes on channel = 0 */
+       cfg.pageAddr = starget->id;
+       cfg.cfghdr.hdr = &hdr;
+       cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+       cfg.timeout = 10;
+
+       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->NumPhysDisks)
+               goto out;
+
+       /*
+        * Adding entry for hidden components
+        */
+       for (i = 0; i < buffer->NumPhysDisks; i++) {
+
+               if (mpt_raid_phys_disk_pg0(ioc,
+                   buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
+                       continue;
+
+               mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
+                   phys_disk.PhysDiskID);
+
+       }
+
+       /*
+        * Delete all matching devices out of the list
+        */
+       mutex_lock(&ioc->sas_device_info_mutex);
+       list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
+           list) {
+               if (sas_info->is_logical_volume && sas_info->fw.id ==
+                   starget->id) {
+                       list_del(&sas_info->list);
+                       kfree(sas_info);
+               }
+       }
+
+       sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
+       if (sas_info) {
+               sas_info->fw.id = starget->id;
+               sas_info->os.id = starget->id;
+               sas_info->os.channel = starget->channel;
+               sas_info->is_logical_volume = 1;
+               INIT_LIST_HEAD(&sas_info->list);
+               list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
+       }
+       mutex_unlock(&ioc->sas_device_info_mutex);
+
+ out:
+       if (buffer)
+               pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
+                   dma_handle);
+}
+
 /**
  *     mptsas_add_device_component_starget -
  *     @ioc: Pointer to MPT_ADAPTER structure
@@ -817,6 +913,10 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
                if ((vdevice == NULL) ||
                        (vdevice->vtarget == NULL))
                        continue;
+               if ((vdevice->vtarget->tflags &
+                   MPT_TARGET_FLAGS_RAID_COMPONENT ||
+                   vdevice->vtarget->raidVolume))
+                       continue;
                if (vdevice->vtarget->id == id &&
                        vdevice->vtarget->channel == channel)
                        vtarget = vdevice->vtarget;
@@ -1487,9 +1587,21 @@ mptsas_slave_configure(struct scsi_device *sdev)
        struct Scsi_Host        *host = sdev->host;
        MPT_SCSI_HOST   *hd = shost_priv(host);
        MPT_ADAPTER     *ioc = hd->ioc;
+       VirtDevice      *vdevice = sdev->hostdata;
 
-       if (sdev->channel == MPTSAS_RAID_CHANNEL)
+       if (vdevice->vtarget->deleted) {
+               sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
+               vdevice->vtarget->deleted = 0;
+       }
+
+       /*
+        * RAID volumes placed beyond the last expected port.
+        * Ignore sending sas mode pages in that case..
+        */
+       if (sdev->channel == MPTSAS_RAID_CHANNEL) {
+               mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
                goto out;
+       }
 
        sas_read_port_mode_page(sdev);
 
@@ -1525,9 +1637,18 @@ mptsas_target_alloc(struct scsi_target *starget)
         * RAID volumes placed beyond the last expected port.
         */
        if (starget->channel == MPTSAS_RAID_CHANNEL) {
-               for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
-                       if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
-                               channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
+               if (!ioc->raid_data.pIocPg2) {
+                       kfree(vtarget);
+                       return -ENXIO;
+               }
+               for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+                       if (id == ioc->raid_data.pIocPg2->
+                                       RaidVolume[i].VolumeID) {
+                               channel = ioc->raid_data.pIocPg2->
+                                       RaidVolume[i].VolumeBus;
+                       }
+               }
+               vtarget->raidVolume = 1;
                goto out;
        }
 
@@ -3277,59 +3398,66 @@ mptsas_not_responding_devices(MPT_ADAPTER *ioc)
        mutex_lock(&ioc->sas_device_info_mutex);
  redo_device_scan:
        list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
-               sas_device.handle = 0;
-               retry_count = 0;
+               if (!sas_info->is_logical_volume) {
+                       sas_device.handle = 0;
+                       retry_count = 0;
 retry_page:
-               retval = mptsas_sas_device_pg0(ioc, &sas_device,
+                       retval = mptsas_sas_device_pg0(ioc, &sas_device,
                                (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
                                << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
                                (sas_info->fw.channel << 8) +
                                sas_info->fw.id);
 
-               if (sas_device.handle)
-                       continue;
-               if (retval == -EBUSY) {
-                       spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
-                       if (ioc->ioc_reset_in_progress) {
-                               dfailprintk(ioc,
-                                   printk(MYIOC_s_DEBUG_FMT
-                                   "%s: exiting due to reset\n",
-                                   ioc->name, __func__));
-                               spin_unlock_irqrestore
-                                   (&ioc->taskmgmt_lock, flags);
-                               mutex_unlock(&ioc->sas_device_info_mutex);
-                               return;
+                       if (sas_device.handle)
+                               continue;
+                       if (retval == -EBUSY) {
+                               spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
+                               if (ioc->ioc_reset_in_progress) {
+                                       dfailprintk(ioc,
+                                       printk(MYIOC_s_DEBUG_FMT
+                                       "%s: exiting due to reset\n",
+                                       ioc->name, __func__));
+                                       spin_unlock_irqrestore
+                                       (&ioc->taskmgmt_lock, flags);
+                                       mutex_unlock(&ioc->
+                                       sas_device_info_mutex);
+                                       return;
+                               }
+                               spin_unlock_irqrestore(&ioc->taskmgmt_lock,
+                               flags);
                        }
-                       spin_unlock_irqrestore(&ioc->taskmgmt_lock,
-                       flags);
-               }
 
-               if (retval && (retval != -ENODEV)) {
-                       if (retry_count < 10) {
-                               retry_count++;
-                               goto retry_page;
-                       } else {
-                               devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
-                               "%s: Config page retry exceeded retry "
-                               "count deleting device 0x%llx\n",
-                               ioc->name, __func__,
-                               sas_info->sas_address));
+                       if (retval && (retval != -ENODEV)) {
+                               if (retry_count < 10) {
+                                       retry_count++;
+                                       goto retry_page;
+                               } else {
+                                       devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+                                       "%s: Config page retry exceeded retry "
+                                       "count deleting device 0x%llx\n",
+                                       ioc->name, __func__,
+                                       sas_info->sas_address));
+                               }
                        }
-               }
 
-               /* delete device */
-               vtarget = mptsas_find_vtarget(ioc,
+                       /* delete device */
+                       vtarget = mptsas_find_vtarget(ioc,
                                sas_info->fw.channel, sas_info->fw.id);
-               if (vtarget)
-                       vtarget->deleted = 1;
-               phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
-                   sas_info->sas_address);
-               if (phy_info) {
-                       mptsas_del_end_device(ioc, phy_info);
-                       goto redo_device_scan;
-               }
+
+                       if (vtarget)
+                               vtarget->deleted = 1;
+
+                       phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                                       sas_info->sas_address);
+
+                       if (phy_info) {
+                               mptsas_del_end_device(ioc, phy_info);
+                               goto redo_device_scan;
+                       }
+               } else
+                       mptsas_volume_delete(ioc, sas_info->fw.id);
        }
-       mutex_unlock(&ioc->sas_device_info_mutex);
+       mutex_lock(&ioc->sas_device_info_mutex);
 
        /* expanders */
        mutex_lock(&ioc->sas_topology_mutex);
@@ -3508,28 +3636,74 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
        return phy_info;
 }
 
-
+/**
+ *     mptsas_find_phyinfo_by_phys_disk_num -
+ *     @ioc: Pointer to MPT_ADAPTER structure
+ *     @phys_disk_num:
+ *     @channel:
+ *     @id:
+ *
+ **/
 static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
+mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
+       u8 channel, u8 id)
 {
-       struct mptsas_portinfo *port_info;
        struct mptsas_phyinfo *phy_info = NULL;
+       struct mptsas_portinfo *port_info;
+       RaidPhysDiskPage1_t *phys_disk = NULL;
+       int num_paths;
+       u64 sas_address = 0;
        int i;
 
+       phy_info = NULL;
+       if (!ioc->raid_data.pIocPg3)
+               return NULL;
+       /* dual port support */
+       num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
+       if (!num_paths)
+               goto out;
+       phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
+          (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+       if (!phys_disk)
+               goto out;
+       mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
+       for (i = 0; i < num_paths; i++) {
+               if ((phys_disk->Path[i].Flags & 1) != 0)
+                       /* entry no longer valid */
+                       continue;
+               if ((id == phys_disk->Path[i].PhysDiskID) &&
+                   (channel == phys_disk->Path[i].PhysDiskBus)) {
+                       memcpy(&sas_address, &phys_disk->Path[i].WWID,
+                               sizeof(u64));
+                       phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+                                       sas_address);
+                       goto out;
+               }
+       }
+
+ out:
+       kfree(phys_disk);
+       if (phy_info)
+               return phy_info;
+
+       /*
+        * Extra code to handle RAID0 case, where the sas_address is not updated
+        * in phys_disk_page_1 when hotswapped
+        */
        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++) {
+               for (i = 0; i < port_info->num_phys && !phy_info; i++) {
                        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;
+                       if ((port_info->phy_info[i].attached.phys_disk_num ==
+                           phys_disk_num) &&
+                           (port_info->phy_info[i].attached.id == id) &&
+                           (port_info->phy_info[i].attached.channel ==
+                            channel))
+                               phy_info = &port_info->phy_info[i];
                }
        }
        mutex_unlock(&ioc->sas_topology_mutex);
@@ -3683,8 +3857,9 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
                mpt_findImVolumes(ioc);
 
                phy_info = mptsas_find_phyinfo_by_phys_disk_num(
-                               ioc, hot_plug_info->channel,
-                               hot_plug_info->phys_disk_num);
+                               ioc, hot_plug_info->phys_disk_num,
+                               hot_plug_info->channel,
+                               hot_plug_info->id);
                mptsas_del_end_device(ioc, phy_info);
                break;
 
@@ -4032,6 +4207,7 @@ mptsas_send_ir2_event(struct fw_event_work *fw_event)
        struct mptsas_hotplug_event hot_plug_info;
        MPI_EVENT_DATA_IR2      *ir2_data;
        u8 reasonCode;
+       RaidPhysDiskPage0_t phys_disk;
 
        ioc = fw_event->ioc;
        ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
@@ -4047,6 +4223,17 @@ mptsas_send_ir2_event(struct fw_event_work *fw_event)
        case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
                hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
                break;
+       case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
+               hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
+               hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
+               break;
+       case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
+               hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
+               mpt_raid_phys_disk_pg0(ioc,
+                   ir2_data->PhysDiskNum, &phys_disk);
+               hot_plug_info.id = phys_disk.PhysDiskID;
+               hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
+               break;
        default:
                mptsas_free_fw_event(ioc, fw_event);
                return;
@@ -4132,6 +4319,31 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
        return 0;
 }
 
+/* Delete a volume when no longer listed in ioc pg2
+ */
+static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
+{
+       struct scsi_device *sdev;
+       int i;
+
+       sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
+       if (!sdev)
+               return;
+       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++)
+               if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
+                       goto release_sdev;
+ out:
+       printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
+           "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
+       scsi_remove_device(sdev);
+ release_sdev:
+       scsi_device_put(sdev);
+}
+
 static int
 mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
index 9e0885a86d23a709cdea865ad5282ba6bc4d592c..57258b60369ef1001ab46014be7d6073442573f2 100644 (file)
@@ -82,6 +82,7 @@ struct mptsas_device_info {
        u32                     device_info; /* specific bits for devices */
        u16                     slot;           /* enclosure slot id */
        u64                     enclosure_logical_id; /*enclosure address */
+       u8                      is_logical_volume; /* is this logical volume */
 };
 
 struct mptsas_hotplug_event {
index 6424dcbd59084aa5b76dd77a246cd5d5a13eb2d1..cf1aba18a09fc349411d0637db4a3d5c44d53d13 100644 (file)
@@ -2087,8 +2087,10 @@ int
 mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
        struct inactive_raid_component_info *component_info;
-       int i;
+       int i, j;
+       RaidPhysDiskPage1_t *phys_disk;
        int rc = 0;
+       int num_paths;
 
        if (!ioc->raid_data.pIocPg3)
                goto out;
@@ -2100,6 +2102,45 @@ mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
                }
        }
 
+       if (ioc->bus_type != SAS)
+               goto out;
+
+       /*
+        * Check if dual path
+        */
+       for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+               num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
+               if (num_paths < 2)
+                       continue;
+               phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
+                  (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+               if (!phys_disk)
+                       continue;
+               if ((mpt_raid_phys_disk_pg1(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
+                   phys_disk))) {
+                       kfree(phys_disk);
+                       continue;
+               }
+               for (j = 0; j < num_paths; j++) {
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_INVALID))
+                               continue;
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_BROKEN))
+                               continue;
+                       if ((id == phys_disk->Path[j].PhysDiskID) &&
+                           (channel == phys_disk->Path[j].PhysDiskBus)) {
+                               rc = 1;
+                               kfree(phys_disk);
+                               goto out;
+                       }
+               }
+               kfree(phys_disk);
+       }
+
+
        /*
         * Check inactive list for matching phys disks
         */
@@ -2124,8 +2165,10 @@ u8
 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
 {
        struct inactive_raid_component_info *component_info;
-       int i;
+       int i, j;
+       RaidPhysDiskPage1_t *phys_disk;
        int rc = -ENXIO;
+       int num_paths;
 
        if (!ioc->raid_data.pIocPg3)
                goto out;
@@ -2137,6 +2180,44 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
                }
        }
 
+       if (ioc->bus_type != SAS)
+               goto out;
+
+       /*
+        * Check if dual path
+        */
+       for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
+               num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
+               if (num_paths < 2)
+                       continue;
+               phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
+                  (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
+               if (!phys_disk)
+                       continue;
+               if ((mpt_raid_phys_disk_pg1(ioc,
+                   ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
+                   phys_disk))) {
+                       kfree(phys_disk);
+                       continue;
+               }
+               for (j = 0; j < num_paths; j++) {
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_INVALID))
+                               continue;
+                       if ((phys_disk->Path[j].Flags &
+                           MPI_RAID_PHYSDISK1_FLAG_BROKEN))
+                               continue;
+                       if ((id == phys_disk->Path[j].PhysDiskID) &&
+                           (channel == phys_disk->Path[j].PhysDiskBus)) {
+                               rc = phys_disk->PhysDiskNum;
+                               kfree(phys_disk);
+                               goto out;
+                       }
+               }
+               kfree(phys_disk);
+       }
+
        /*
         * Check inactive list for matching phys disks
         */