diff options
author | Hannes Reinecke | 2011-08-24 10:51:15 +0200 |
---|---|---|
committer | James Bottomley | 2011-08-30 12:28:30 -0700 |
commit | 6c3633d08acf514e2e89aa95d2346ce9d64d719a (patch) | |
tree | dcd1adaca314f4acb3f0979df75756b36b20e0ef /drivers/scsi/device_handler/scsi_dh.c | |
parent | 2a9ab40f74eb22cdf02e8f687bef7f3eac7f6cfa (diff) |
[SCSI] scsi_dh: Implement match callback function
Some device handler types are not tied to the vendor/model
but rather to a specific capability. Eg ALUA is supported
if the 'TPGS' setting in the standard inquiry is set.
This patch implements a 'match' callback for device handler
which supersedes the original vendor/model lookup and
implements the callback for the ALUA handler.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/device_handler/scsi_dh.c')
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh.c | 53 |
1 files changed, 46 insertions, 7 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index fccd0f6cfc90..3ac71cf6b7f0 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -60,6 +60,46 @@ static struct scsi_device_handler *get_device_handler_by_idx(int idx) } /* + * device_handler_match_function - Match a device handler to a device + * @sdev - SCSI device to be tested + * + * Tests @sdev against the match function of all registered device_handler. + * Returns the found device handler or NULL if not found. + */ +static struct scsi_device_handler * +device_handler_match_function(struct scsi_device *sdev) +{ + struct scsi_device_handler *tmp_dh, *found_dh = NULL; + + spin_lock(&list_lock); + list_for_each_entry(tmp_dh, &scsi_dh_list, list) { + if (tmp_dh->match && tmp_dh->match(sdev)) { + found_dh = tmp_dh; + break; + } + } + spin_unlock(&list_lock); + return found_dh; +} + +/* + * device_handler_match_devlist - Match a device handler to a device + * @sdev - SCSI device to be tested + * + * Tests @sdev against all device_handler registered in the devlist. + * Returns the found device handler or NULL if not found. + */ +static struct scsi_device_handler * +device_handler_match_devlist(struct scsi_device *sdev) +{ + int idx; + + idx = scsi_get_device_flags_keyed(sdev, sdev->vendor, sdev->model, + SCSI_DEVINFO_DH); + return get_device_handler_by_idx(idx); +} + +/* * device_handler_match - Attach a device handler to a device * @scsi_dh - The device handler to match against or NULL * @sdev - SCSI device to be tested against @scsi_dh @@ -72,12 +112,11 @@ static struct scsi_device_handler * device_handler_match(struct scsi_device_handler *scsi_dh, struct scsi_device *sdev) { - struct scsi_device_handler *found_dh = NULL; - int idx; + struct scsi_device_handler *found_dh; - idx = scsi_get_device_flags_keyed(sdev, sdev->vendor, sdev->model, - SCSI_DEVINFO_DH); - found_dh = get_device_handler_by_idx(idx); + found_dh = device_handler_match_function(sdev); + if (!found_dh) + found_dh = device_handler_match_devlist(sdev); if (scsi_dh && found_dh != scsi_dh) found_dh = NULL; @@ -327,7 +366,7 @@ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) list_add(&scsi_dh->list, &scsi_dh_list); spin_unlock(&list_lock); - for (i = 0; scsi_dh->devlist[i].vendor; i++) { + for (i = 0; scsi_dh->devlist && scsi_dh->devlist[i].vendor; i++) { scsi_dev_info_list_add_keyed(0, scsi_dh->devlist[i].vendor, scsi_dh->devlist[i].model, @@ -360,7 +399,7 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_remove); - for (i = 0; scsi_dh->devlist[i].vendor; i++) { + for (i = 0; scsi_dh->devlist && scsi_dh->devlist[i].vendor; i++) { scsi_dev_info_list_del_keyed(scsi_dh->devlist[i].vendor, scsi_dh->devlist[i].model, SCSI_DEVINFO_DH); |