Commit c42b3654 authored by Alan Stern's avatar Alan Stern Committed by James Bottomley

SCSI: refactor device-matching code in scsi_devinfo.c

In drivers/scsi/scsi_devinfo.c, the scsi_dev_info_list_del_keyed() and
scsi_get_device_flags_keyed() routines contain a large amount of
duplicate code for finding vendor/product matches in a
scsi_dev_info_list.  This patch factors out the duplicate code and
puts it in a separate function, scsi_dev_info_list_find().
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Suggested-by: default avatarGiulio Bernardi <ugilio@gmail.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Odin.com>
parent fd6ddfa4
...@@ -390,25 +390,26 @@ int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model, ...@@ -390,25 +390,26 @@ int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model,
EXPORT_SYMBOL(scsi_dev_info_list_add_keyed); EXPORT_SYMBOL(scsi_dev_info_list_add_keyed);
/** /**
* scsi_dev_info_list_del_keyed - remove one dev_info list entry. * scsi_dev_info_list_find - find a matching dev_info list entry.
* @vendor: vendor string * @vendor: vendor string
* @model: model (product) string * @model: model (product) string
* @key: specify list to use * @key: specify list to use
* *
* Description: * Description:
* Remove and destroy one dev_info entry for @vendor, @model * Finds the first dev_info entry matching @vendor, @model
* in list specified by @key. * in list specified by @key.
* *
* Returns: 0 OK, -error on failure. * Returns: pointer to matching entry, or ERR_PTR on failure.
**/ **/
int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key) static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor,
const char *model, int key)
{ {
struct scsi_dev_info_list *devinfo, *found = NULL; struct scsi_dev_info_list *devinfo;
struct scsi_dev_info_list_table *devinfo_table = struct scsi_dev_info_list_table *devinfo_table =
scsi_devinfo_lookup_by_key(key); scsi_devinfo_lookup_by_key(key);
if (IS_ERR(devinfo_table)) if (IS_ERR(devinfo_table))
return PTR_ERR(devinfo_table); return (struct scsi_dev_info_list *) devinfo_table;
list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list, list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list,
dev_info_list) { dev_info_list) {
...@@ -452,25 +453,42 @@ int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key) ...@@ -452,25 +453,42 @@ int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key)
if (memcmp(devinfo->model, model, if (memcmp(devinfo->model, model,
min(max, strlen(devinfo->model)))) min(max, strlen(devinfo->model))))
continue; continue;
found = devinfo; return devinfo;
} else { } else {
if (!memcmp(devinfo->vendor, vendor, if (!memcmp(devinfo->vendor, vendor,
sizeof(devinfo->vendor)) && sizeof(devinfo->vendor)) &&
!memcmp(devinfo->model, model, !memcmp(devinfo->model, model,
sizeof(devinfo->model))) sizeof(devinfo->model)))
found = devinfo; return devinfo;
} }
if (found)
break;
} }
if (found) { return ERR_PTR(-ENOENT);
list_del(&found->dev_info_list); }
kfree(found);
return 0; /**
} * 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 *found;
return -ENOENT; found = scsi_dev_info_list_find(vendor, model, key);
if (IS_ERR(found))
return PTR_ERR(found);
list_del(&found->dev_info_list);
kfree(found);
return 0;
} }
EXPORT_SYMBOL(scsi_dev_info_list_del_keyed); EXPORT_SYMBOL(scsi_dev_info_list_del_keyed);
...@@ -565,64 +583,16 @@ int scsi_get_device_flags_keyed(struct scsi_device *sdev, ...@@ -565,64 +583,16 @@ int scsi_get_device_flags_keyed(struct scsi_device *sdev,
int key) int key)
{ {
struct scsi_dev_info_list *devinfo; struct scsi_dev_info_list *devinfo;
struct scsi_dev_info_list_table *devinfo_table; int err;
devinfo_table = scsi_devinfo_lookup_by_key(key); devinfo = scsi_dev_info_list_find(vendor, model, key);
if (!IS_ERR(devinfo))
return devinfo->flags;
if (IS_ERR(devinfo_table)) err = PTR_ERR(devinfo);
return PTR_ERR(devinfo_table); if (err != -ENOENT)
return err;
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;
return devinfo->flags;
} else {
if (!memcmp(devinfo->vendor, vendor,
sizeof(devinfo->vendor)) &&
!memcmp(devinfo->model, model,
sizeof(devinfo->model)))
return devinfo->flags;
}
}
/* nothing found, return nothing */ /* nothing found, return nothing */
if (key != SCSI_DEVINFO_GLOBAL) if (key != SCSI_DEVINFO_GLOBAL)
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment