scsi: aacraid: Added support for hotplug
authorRaghava Aditya Renukunta <RaghavaAditya.Renukunta@microsemi.com>
Thu, 2 Feb 2017 23:53:28 +0000 (15:53 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 3 Feb 2017 15:35:03 +0000 (10:35 -0500)
Added support for drive hotplug add and removal

Signed-off-by: Raghava Aditya Renukunta <RaghavaAditya.Renukunta@microsemi.com>
Signed-off-by: Dave Carroll <David.Carroll@microsemi.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/aacraid/aachba.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/commsup.c

index 20908a1..5719ac3 100644 (file)
@@ -1595,7 +1595,7 @@ out:
  *     Update our hba map with the information gathered from the FW
  */
 void aac_update_hba_map(struct aac_dev *dev,
-               struct aac_ciss_phys_luns_resp *phys_luns)
+               struct aac_ciss_phys_luns_resp *phys_luns, int rescan)
 {
        /* ok and extended reporting */
        u32 lun_count, nexus;
@@ -1640,7 +1640,10 @@ void aac_update_hba_map(struct aac_dev *dev,
                        dev->hba_map[bus][target].qd_limit = 32;
 
 update_devtype:
-               dev->hba_map[bus][target].devtype = devtype;
+               if (rescan == AAC_INIT)
+                       dev->hba_map[bus][target].devtype = devtype;
+               else
+                       dev->hba_map[bus][target].new_devtype = devtype;
        }
 }
 
@@ -1652,7 +1655,7 @@ update_devtype:
  *     Execute a CISS REPORT PHYS LUNS and process the results into
  *     the current hba_map.
  */
-int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr)
+int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan)
 {
        int fibsize, datasize;
        struct aac_ciss_phys_luns_resp *phys_luns;
@@ -1712,7 +1715,7 @@ int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr)
        /* analyse data */
        if (rcode >= 0 && phys_luns->resp_flag == 2) {
                /* ok and extended reporting */
-               aac_update_hba_map(dev, phys_luns);
+               aac_update_hba_map(dev, phys_luns, rescan);
        }
 
        pci_free_consistent(dev->pdev, datasize, (void *) phys_luns, addr);
@@ -1825,7 +1828,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
        if (!dev->sync_mode && dev->sa_firmware &&
                        dev->supplement_adapter_info.VirtDeviceBus != 0xffff) {
                /* Thor SA Firmware -> CISS_REPORT_PHYSICAL_LUNS */
-               rcode = aac_report_phys_luns(dev, fibptr);
+               rcode = aac_report_phys_luns(dev, fibptr, AAC_INIT);
        }
 
        if (!dev->in_reset) {
index 02b0279..a8b418e 100644 (file)
@@ -74,7 +74,7 @@ enum {
 #define AAC_NUM_IO_FIB         (1024 - AAC_NUM_MGT_FIB)
 #define AAC_NUM_FIB            (AAC_NUM_IO_FIB + AAC_NUM_MGT_FIB)
 
-#define AAC_MAX_LUN            (256)
+#define AAC_MAX_LUN            256
 
 #define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff)
 #define AAC_MAX_32BIT_SGBCOUNT ((unsigned short)256)
@@ -87,6 +87,14 @@ enum {
 #define AAC_MAX_TARGETS                256
 #define AAC_MAX_NATIVE_SIZE            2048
 
+/* Thor AIF events */
+#define SA_AIF_HOTPLUG                 (1<<1)
+#define SA_AIF_HARDWARE                (1<<2)
+#define SA_AIF_PDEV_CHANGE             (1<<4)
+#define SA_AIF_LDEV_CHANGE             (1<<5)
+#define SA_AIF_BPSTAT_CHANGE           (1<<30)
+#define SA_AIF_BPCFG_CHANGE            (1<<31)
+
 #define CISS_REPORT_PHYSICAL_LUNS      0xc3
 #define WRITE_HOST_WELLNESS            0xa5
 #define CISS_IDENTIFY_PHYSICAL_DEVICE  0x15
@@ -194,6 +202,7 @@ struct aac_ciss_identify_pd {
 #define CONTAINER_TO_CHANNEL(cont)     (CONTAINER_CHANNEL)
 #define CONTAINER_TO_ID(cont)          (cont)
 #define CONTAINER_TO_LUN(cont)         (0)
+#define ENCLOSURE_CHANNEL              (3)
 
 #define PMC_DEVICE_S6  0x28b
 #define PMC_DEVICE_S7  0x28c
@@ -1098,6 +1107,9 @@ struct fib {
        u32                     hbacmd_size;    /* cmd size for native */
 };
 
+#define AAC_INIT                       0
+#define AAC_RESCAN                     1
+
 #define AAC_DEVTYPE_RAID_MEMBER        1
 #define AAC_DEVTYPE_ARC_RAW            2
 #define AAC_DEVTYPE_NATIVE_RAW         3
@@ -1107,6 +1119,7 @@ struct fib {
 struct aac_hba_map_info {
        __le32  rmw_nexus;              /* nexus for native HBA devices */
        u8              devtype;        /* device type */
+       u8              new_devtype;
        u8              reset_state;    /* 0 - no reset, 1..x - */
                                        /* after xth TM LUN reset */
        u16             qd_limit;
@@ -2317,7 +2330,7 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
 
 int aac_acquire_irq(struct aac_dev *dev);
 void aac_free_irq(struct aac_dev *dev);
-int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr);
+int aac_report_phys_luns(struct aac_dev *dev, struct fib *fibptr, int rescan);
 int aac_issue_bmic_identify(struct aac_dev *dev, u32 bus, u32 target);
 const char *aac_driverinfo(struct Scsi_Host *);
 void aac_fib_vector_assign(struct aac_dev *dev);
index a56aa2e..e906ae1 100644 (file)
@@ -1730,6 +1730,137 @@ out:
        return BlinkLED;
 }
 
+
+static void aac_resolve_luns(struct aac_dev *dev)
+{
+       int bus, target, channel;
+       struct scsi_device *sdev;
+       u8 devtype;
+       u8 new_devtype;
+
+       for (bus = 0; bus < AAC_MAX_BUSES; bus++) {
+               for (target = 0; target < AAC_MAX_TARGETS; target++) {
+
+                       if (aac_phys_to_logical(bus) == ENCLOSURE_CHANNEL)
+                               continue;
+
+                       if (bus == CONTAINER_CHANNEL)
+                               channel = CONTAINER_CHANNEL;
+                       else
+                               channel = aac_phys_to_logical(bus);
+
+                       devtype = dev->hba_map[bus][target].devtype;
+                       new_devtype = dev->hba_map[bus][target].new_devtype;
+
+                       sdev = scsi_device_lookup(dev->scsi_host_ptr, channel,
+                                       target, 0);
+
+                       if (!sdev && devtype)
+                               scsi_add_device(dev->scsi_host_ptr, channel,
+                                               target, 0);
+                       else if (sdev && new_devtype != devtype)
+                               scsi_remove_device(sdev);
+                       else if (sdev && new_devtype == devtype)
+                               scsi_rescan_device(&sdev->sdev_gendev);
+
+                       if (sdev)
+                               scsi_device_put(sdev);
+
+                       dev->hba_map[bus][target].devtype = new_devtype;
+               }
+       }
+}
+
+/**
+ *     aac_handle_sa_aif       Handle a message from the firmware
+ *     @dev: Which adapter this fib is from
+ *     @fibptr: Pointer to fibptr from adapter
+ *
+ *     This routine handles a driver notify fib from the adapter and
+ *     dispatches it to the appropriate routine for handling.
+ */
+static void aac_handle_sa_aif(struct aac_dev *dev, struct fib *fibptr)
+{
+       int i, bus, target, container, rcode = 0;
+       u32 events = 0;
+       struct fib *fib;
+       struct scsi_device *sdev;
+
+       if (fibptr->hbacmd_size & SA_AIF_HOTPLUG)
+               events = SA_AIF_HOTPLUG;
+       else if (fibptr->hbacmd_size & SA_AIF_HARDWARE)
+               events = SA_AIF_HARDWARE;
+       else if (fibptr->hbacmd_size & SA_AIF_PDEV_CHANGE)
+               events = SA_AIF_PDEV_CHANGE;
+       else if (fibptr->hbacmd_size & SA_AIF_LDEV_CHANGE)
+               events = SA_AIF_LDEV_CHANGE;
+       else if (fibptr->hbacmd_size & SA_AIF_BPSTAT_CHANGE)
+               events = SA_AIF_BPSTAT_CHANGE;
+       else if (fibptr->hbacmd_size & SA_AIF_BPCFG_CHANGE)
+               events = SA_AIF_BPCFG_CHANGE;
+
+       switch (events) {
+       case SA_AIF_HOTPLUG:
+       case SA_AIF_HARDWARE:
+       case SA_AIF_PDEV_CHANGE:
+       case SA_AIF_LDEV_CHANGE:
+       case SA_AIF_BPCFG_CHANGE:
+
+               fib = aac_fib_alloc(dev);
+               if (!fib) {
+                       pr_err("aac_handle_sa_aif: out of memory\n");
+                       return;
+               }
+               for (bus = 0; bus < AAC_MAX_BUSES; bus++)
+                       for (target = 0; target < AAC_MAX_TARGETS; target++)
+                               dev->hba_map[bus][target].new_devtype = 0;
+
+               rcode = aac_report_phys_luns(dev, fib, AAC_RESCAN);
+
+               if (rcode != -ERESTARTSYS)
+                       aac_fib_free(fib);
+
+               aac_resolve_luns(dev);
+
+               if (events == SA_AIF_LDEV_CHANGE ||
+                   events == SA_AIF_BPCFG_CHANGE) {
+                       aac_get_containers(dev);
+                       for (container = 0; container <
+                       dev->maximum_num_containers; ++container) {
+                               sdev = scsi_device_lookup(dev->scsi_host_ptr,
+                                               CONTAINER_CHANNEL,
+                                               container, 0);
+                               if (dev->fsa_dev[container].valid && !sdev) {
+                                       scsi_add_device(dev->scsi_host_ptr,
+                                               CONTAINER_CHANNEL,
+                                               container, 0);
+                               } else if (!dev->fsa_dev[container].valid &&
+                                       sdev) {
+                                       scsi_remove_device(sdev);
+                                       scsi_device_put(sdev);
+                               } else if (sdev) {
+                                       scsi_rescan_device(&sdev->sdev_gendev);
+                                       scsi_device_put(sdev);
+                               }
+                       }
+               }
+               break;
+
+       case SA_AIF_BPSTAT_CHANGE:
+               /* currently do nothing */
+               break;
+       }
+
+       for (i = 1; i <= 10; ++i) {
+               events = src_readl(dev, MUnit.IDR);
+               if (events & (1<<23)) {
+                       pr_warn(" AIF not cleared by firmware - %d/%d)\n",
+                               i, 10);
+                       ssleep(1);
+               }
+       }
+}
+
 static int get_fib_count(struct aac_dev *dev)
 {
        unsigned int num = 0;
@@ -1913,6 +2044,12 @@ static void aac_process_events(struct aac_dev *dev)
 
                fib = list_entry(entry, struct fib, fiblink);
                hw_fib = fib->hw_fib_va;
+               if (dev->sa_firmware) {
+                       /* Thor AIF */
+                       aac_handle_sa_aif(dev, fib);
+                       aac_fib_adapter_complete(fib, (u16)sizeof(u32));
+                       continue;
+               }
                /*
                 *      We will process the FIB here or pass it to a
                 *      worker thread that is TBD. We Really can't