[SCSI] Add scsi_dev_info_list_del_keyed()
authorPeter Jones <pjones@redhat.com>
Thu, 6 Jan 2011 20:31:29 +0000 (15:31 -0500)
committerJames Bottomley <James.Bottomley@suse.de>
Mon, 24 Jan 2011 18:01:07 +0000 (12:01 -0600)
For scsi_dh.c to use devinfo lists, we have to be able to remove entries
before rmmod.

Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/scsi_devinfo.c
drivers/scsi/scsi_priv.h

index 43fad4c09beb6714ec2712fbc1ba8d39af607845..82e9e5c0476eefd62c3ad3a3f0451f5e45afa638 100644 (file)
@@ -381,6 +381,91 @@ int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model,
 }
 EXPORT_SYMBOL(scsi_dev_info_list_add_keyed);
 
+/**
+ * scsi_dev_info_list_del_keyed - remove one dev_info list entry.
+ * @vendor:    vendor string
+ * @model:     model (product) string
+ * @key:       specify list to use
+ *
+ * Description:
+ *     Remove and destroy one dev_info entry for @vendor, @model
+ *     in list specified by @key.
+ *
+ * Returns: 0 OK, -error on failure.
+ **/
+int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key)
+{
+       struct scsi_dev_info_list *devinfo, *found = NULL;
+       struct scsi_dev_info_list_table *devinfo_table =
+               scsi_devinfo_lookup_by_key(key);
+
+       if (IS_ERR(devinfo_table))
+               return PTR_ERR(devinfo_table);
+
+       list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list,
+                           dev_info_list) {
+               if (devinfo->compatible) {
+                       /*
+                        * Behave like the older version of get_device_flags.
+                        */
+                       size_t max;
+                       /*
+                        * XXX why skip leading spaces? If an odd INQUIRY
+                        * value, that should have been part of the
+                        * scsi_static_device_list[] entry, such as "  FOO"
+                        * rather than "FOO". Since this code is already
+                        * here, and we don't know what device it is
+                        * trying to work with, leave it as-is.
+                        */
+                       max = 8;        /* max length of vendor */
+                       while ((max > 0) && *vendor == ' ') {
+                               max--;
+                               vendor++;
+                       }
+                       /*
+                        * XXX removing the following strlen() would be
+                        * good, using it means that for a an entry not in
+                        * the list, we scan every byte of every vendor
+                        * listed in scsi_static_device_list[], and never match
+                        * a single one (and still have to compare at
+                        * least the first byte of each vendor).
+                        */
+                       if (memcmp(devinfo->vendor, vendor,
+                                   min(max, strlen(devinfo->vendor))))
+                               continue;
+                       /*
+                        * Skip spaces again.
+                        */
+                       max = 16;       /* max length of model */
+                       while ((max > 0) && *model == ' ') {
+                               max--;
+                               model++;
+                       }
+                       if (memcmp(devinfo->model, model,
+                                  min(max, strlen(devinfo->model))))
+                               continue;
+                       found = devinfo;
+               } else {
+                       if (!memcmp(devinfo->vendor, vendor,
+                                    sizeof(devinfo->vendor)) &&
+                            !memcmp(devinfo->model, model,
+                                     sizeof(devinfo->model)))
+                               found = devinfo;
+               }
+               if (found)
+                       break;
+       }
+
+       if (found) {
+               list_del(&found->dev_info_list);
+               kfree(found);
+               return 0;
+       }
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL(scsi_dev_info_list_del_keyed);
+
 /**
  * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list.
  * @dev_list:  string of device flags to add
index b4056d14f812d7ecc4e8affc0c234bf6e4837424..ce9e0adc8df83ceffc9280447dd95767c29bd6d8 100644 (file)
@@ -56,6 +56,7 @@ extern int scsi_get_device_flags_keyed(struct scsi_device *sdev,
 extern int scsi_dev_info_list_add_keyed(int compatible, char *vendor,
                                        char *model, char *strflags,
                                        int flags, int key);
+extern int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key);
 extern int scsi_dev_info_add_list(int key, const char *name);
 extern int scsi_dev_info_remove_list(int key);