aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2011-08-24 04:51:15 -0400
committerJames Bottomley <JBottomley@Parallels.com>2011-08-30 15:28:30 -0400
commit6c3633d08acf514e2e89aa95d2346ce9d64d719a (patch)
treedcd1adaca314f4acb3f0979df75756b36b20e0ef
parent2a9ab40f74eb22cdf02e8f687bef7f3eac7f6cfa (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>
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c53
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c23
-rw-r--r--include/scsi/scsi_device.h1
3 files changed, 52 insertions, 25 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index fccd0f6cfc9..3ac71cf6b7f 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)
60} 60}
61 61
62/* 62/*
63 * device_handler_match_function - Match a device handler to a device
64 * @sdev - SCSI device to be tested
65 *
66 * Tests @sdev against the match function of all registered device_handler.
67 * Returns the found device handler or NULL if not found.
68 */
69static struct scsi_device_handler *
70device_handler_match_function(struct scsi_device *sdev)
71{
72 struct scsi_device_handler *tmp_dh, *found_dh = NULL;
73
74 spin_lock(&list_lock);
75 list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
76 if (tmp_dh->match && tmp_dh->match(sdev)) {
77 found_dh = tmp_dh;
78 break;
79 }
80 }
81 spin_unlock(&list_lock);
82 return found_dh;
83}
84
85/*
86 * device_handler_match_devlist - Match a device handler to a device
87 * @sdev - SCSI device to be tested
88 *
89 * Tests @sdev against all device_handler registered in the devlist.
90 * Returns the found device handler or NULL if not found.
91 */
92static struct scsi_device_handler *
93device_handler_match_devlist(struct scsi_device *sdev)
94{
95 int idx;
96
97 idx = scsi_get_device_flags_keyed(sdev, sdev->vendor, sdev->model,
98 SCSI_DEVINFO_DH);
99 return get_device_handler_by_idx(idx);
100}
101
102/*
63 * device_handler_match - Attach a device handler to a device 103 * device_handler_match - Attach a device handler to a device
64 * @scsi_dh - The device handler to match against or NULL 104 * @scsi_dh - The device handler to match against or NULL
65 * @sdev - SCSI device to be tested against @scsi_dh 105 * @sdev - SCSI device to be tested against @scsi_dh
@@ -72,12 +112,11 @@ static struct scsi_device_handler *
72device_handler_match(struct scsi_device_handler *scsi_dh, 112device_handler_match(struct scsi_device_handler *scsi_dh,
73 struct scsi_device *sdev) 113 struct scsi_device *sdev)
74{ 114{
75 struct scsi_device_handler *found_dh = NULL; 115 struct scsi_device_handler *found_dh;
76 int idx;
77 116
78 idx = scsi_get_device_flags_keyed(sdev, sdev->vendor, sdev->model, 117 found_dh = device_handler_match_function(sdev);
79 SCSI_DEVINFO_DH); 118 if (!found_dh)
80 found_dh = get_device_handler_by_idx(idx); 119 found_dh = device_handler_match_devlist(sdev);
81 120
82 if (scsi_dh && found_dh != scsi_dh) 121 if (scsi_dh && found_dh != scsi_dh)
83 found_dh = NULL; 122 found_dh = NULL;
@@ -327,7 +366,7 @@ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
327 list_add(&scsi_dh->list, &scsi_dh_list); 366 list_add(&scsi_dh->list, &scsi_dh_list);
328 spin_unlock(&list_lock); 367 spin_unlock(&list_lock);
329 368
330 for (i = 0; scsi_dh->devlist[i].vendor; i++) { 369 for (i = 0; scsi_dh->devlist && scsi_dh->devlist[i].vendor; i++) {
331 scsi_dev_info_list_add_keyed(0, 370 scsi_dev_info_list_add_keyed(0,
332 scsi_dh->devlist[i].vendor, 371 scsi_dh->devlist[i].vendor,
333 scsi_dh->devlist[i].model, 372 scsi_dh->devlist[i].model,
@@ -360,7 +399,7 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
360 bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, 399 bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
361 scsi_dh_notifier_remove); 400 scsi_dh_notifier_remove);
362 401
363 for (i = 0; scsi_dh->devlist[i].vendor; i++) { 402 for (i = 0; scsi_dh->devlist && scsi_dh->devlist[i].vendor; i++) {
364 scsi_dev_info_list_del_keyed(scsi_dh->devlist[i].vendor, 403 scsi_dev_info_list_del_keyed(scsi_dh->devlist[i].vendor,
365 scsi_dh->devlist[i].model, 404 scsi_dh->devlist[i].model,
366 SCSI_DEVINFO_DH); 405 SCSI_DEVINFO_DH);
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 432677889ea..80c5cf327b8 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -677,23 +677,10 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
677 677
678} 678}
679 679
680static const struct scsi_dh_devlist alua_dev_list[] = { 680static bool alua_match(struct scsi_device *sdev)
681 {"HP", "MSA VOLUME" }, 681{
682 {"HP", "HSV101" }, 682 return (scsi_device_tpgs(sdev) != 0);
683 {"HP", "HSV111" }, 683}
684 {"HP", "HSV200" },
685 {"HP", "HSV210" },
686 {"HP", "HSV300" },
687 {"IBM", "2107900" },
688 {"IBM", "2145" },
689 {"Pillar", "Axiom" },
690 {"Intel", "Multi-Flex"},
691 {"NETAPP", "LUN"},
692 {"NETAPP", "LUN C-Mode"},
693 {"AIX", "NVDISK"},
694 {"Promise", "VTrak"},
695 {NULL, NULL}
696};
697 684
698static int alua_bus_attach(struct scsi_device *sdev); 685static int alua_bus_attach(struct scsi_device *sdev);
699static void alua_bus_detach(struct scsi_device *sdev); 686static void alua_bus_detach(struct scsi_device *sdev);
@@ -701,12 +688,12 @@ static void alua_bus_detach(struct scsi_device *sdev);
701static struct scsi_device_handler alua_dh = { 688static struct scsi_device_handler alua_dh = {
702 .name = ALUA_DH_NAME, 689 .name = ALUA_DH_NAME,
703 .module = THIS_MODULE, 690 .module = THIS_MODULE,
704 .devlist = alua_dev_list,
705 .attach = alua_bus_attach, 691 .attach = alua_bus_attach,
706 .detach = alua_bus_detach, 692 .detach = alua_bus_detach,
707 .prep_fn = alua_prep_fn, 693 .prep_fn = alua_prep_fn,
708 .check_sense = alua_check_sense, 694 .check_sense = alua_check_sense,
709 .activate = alua_activate, 695 .activate = alua_activate,
696 .match = alua_match,
710}; 697};
711 698
712/* 699/*
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index f751d37685e..5591ed54dc9 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -197,6 +197,7 @@ struct scsi_device_handler {
197 int (*activate)(struct scsi_device *, activate_complete, void *); 197 int (*activate)(struct scsi_device *, activate_complete, void *);
198 int (*prep_fn)(struct scsi_device *, struct request *); 198 int (*prep_fn)(struct scsi_device *, struct request *);
199 int (*set_params)(struct scsi_device *, const char *); 199 int (*set_params)(struct scsi_device *, const char *);
200 bool (*match)(struct scsi_device *);
200}; 201};
201 202
202struct scsi_dh_data { 203struct scsi_dh_data {