[SCSI] hpsa: update device attributes when they change
authorScott Teel <scott.teel@hp.com>
Thu, 19 Jan 2012 20:01:30 +0000 (14:01 -0600)
committerJames Bottomley <JBottomley@Parallels.com>
Sun, 19 Feb 2012 14:08:57 +0000 (08:08 -0600)
Certain types of changes to devices should not be interpreted as a device
change that would cause the device to be removed and re-added.  These include
RAID level and Firmware revision changes.  However, these attribute changes DO
need to be reflected in the controller info structure's dev structure list, so
that sysfs and /proc info files for the devices will reflect the new values.

Signed-off-by: Scott Teel <scott.stacy.teel@hp.com>
Acked-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/hpsa.c

index 74326b3..1319507 100644 (file)
@@ -677,6 +677,20 @@ lun_assigned:
        return 0;
 }
 
+/* Update an entry in h->dev[] array. */
+static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
+       int entry, struct hpsa_scsi_dev_t *new_entry)
+{
+       /* assumes h->devlock is held */
+       BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES);
+
+       /* Raid level changed. */
+       h->dev[entry]->raid_level = new_entry->raid_level;
+       dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n",
+               scsi_device_type(new_entry->devtype), hostno, new_entry->bus,
+               new_entry->target, new_entry->lun);
+}
+
 /* Replace an entry from h->dev[] array. */
 static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
        int entry, struct hpsa_scsi_dev_t *new_entry,
@@ -783,10 +797,25 @@ static inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1,
        return 1;
 }
 
+static inline int device_updated(struct hpsa_scsi_dev_t *dev1,
+       struct hpsa_scsi_dev_t *dev2)
+{
+       /* Device attributes that can change, but don't mean
+        * that the device is a different device, nor that the OS
+        * needs to be told anything about the change.
+        */
+       if (dev1->raid_level != dev2->raid_level)
+               return 1;
+       return 0;
+}
+
 /* Find needle in haystack.  If exact match found, return DEVICE_SAME,
  * and return needle location in *index.  If scsi3addr matches, but not
  * vendor, model, serial num, etc. return DEVICE_CHANGED, and return needle
- * location in *index.  If needle not found, return DEVICE_NOT_FOUND.
+ * location in *index.
+ * In the case of a minor device attribute change, such as RAID level, just
+ * return DEVICE_UPDATED, along with the updated device's location in index.
+ * If needle not found, return DEVICE_NOT_FOUND.
  */
 static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
        struct hpsa_scsi_dev_t *haystack[], int haystack_size,
@@ -796,15 +825,19 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
 #define DEVICE_NOT_FOUND 0
 #define DEVICE_CHANGED 1
 #define DEVICE_SAME 2
+#define DEVICE_UPDATED 3
        for (i = 0; i < haystack_size; i++) {
                if (haystack[i] == NULL) /* previously removed. */
                        continue;
                if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) {
                        *index = i;
-                       if (device_is_the_same(needle, haystack[i]))
+                       if (device_is_the_same(needle, haystack[i])) {
+                               if (device_updated(needle, haystack[i]))
+                                       return DEVICE_UPDATED;
                                return DEVICE_SAME;
-                       else
+                       } else {
                                return DEVICE_CHANGED;
+                       }
                }
        }
        *index = -1;
@@ -840,6 +873,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
         * sd[] and remove them from h->dev[], and for any
         * devices which have changed, remove the old device
         * info and add the new device info.
+        * If minor device attributes change, just update
+        * the existing device structure.
         */
        i = 0;
        nremoved = 0;
@@ -860,6 +895,8 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
                         * at the bottom of hpsa_update_scsi_devices()
                         */
                        sd[entry] = NULL;
+               } else if (device_change == DEVICE_UPDATED) {
+                       hpsa_scsi_update_entry(h, hostno, i, sd[entry]);
                }
                i++;
        }