diff options
author | Hannes Reinecke <hare@suse.de> | 2008-07-17 19:52:51 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-07-26 15:14:51 -0400 |
commit | 765cbc6dad16b87724803e359d6be792ddf08614 (patch) | |
tree | 2cedfbe6b55c9f7a3e4cc3fb4f0d1f4d9d18f625 | |
parent | 6d49f63b415ca02223e01e187076cb69a5a38eaf (diff) |
[SCSI] scsi_dh: Implement common device table handling
Instead of having each and every driver implement its own
device table scanning code we should rather implement a common
routine and scan the device tables there.
This allows us also to implement a general notifier chain
callback for all device handler instead for one per handler.
[sekharan: Fix rejections caused by conflicting bug fix]
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh.c | 202 | ||||
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_emc.c | 109 | ||||
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_hp_sw.c | 86 | ||||
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh_rdac.c | 109 | ||||
-rw-r--r-- | include/scsi/scsi_device.h | 9 |
5 files changed, 296 insertions, 219 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index ab6c21cd9689..3f798171ed69 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c | |||
@@ -33,7 +33,7 @@ static struct scsi_device_handler *get_device_handler(const char *name) | |||
33 | 33 | ||
34 | spin_lock(&list_lock); | 34 | spin_lock(&list_lock); |
35 | list_for_each_entry(tmp, &scsi_dh_list, list) { | 35 | list_for_each_entry(tmp, &scsi_dh_list, list) { |
36 | if (!strcmp(tmp->name, name)) { | 36 | if (!strncmp(tmp->name, name, strlen(tmp->name))) { |
37 | found = tmp; | 37 | found = tmp; |
38 | break; | 38 | break; |
39 | } | 39 | } |
@@ -42,51 +42,173 @@ static struct scsi_device_handler *get_device_handler(const char *name) | |||
42 | return found; | 42 | return found; |
43 | } | 43 | } |
44 | 44 | ||
45 | static int scsi_dh_notifier_add(struct device *dev, void *data) | 45 | static int device_handler_match(struct scsi_device_handler *tmp, |
46 | struct scsi_device *sdev) | ||
46 | { | 47 | { |
47 | struct scsi_device_handler *scsi_dh = data; | 48 | int i; |
49 | |||
50 | for(i = 0; tmp->devlist[i].vendor; i++) { | ||
51 | if (!strncmp(sdev->vendor, tmp->devlist[i].vendor, | ||
52 | strlen(tmp->devlist[i].vendor)) && | ||
53 | !strncmp(sdev->model, tmp->devlist[i].model, | ||
54 | strlen(tmp->devlist[i].model))) { | ||
55 | return 1; | ||
56 | } | ||
57 | } | ||
48 | 58 | ||
49 | scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_ADD_DEVICE, dev); | ||
50 | return 0; | 59 | return 0; |
51 | } | 60 | } |
52 | 61 | ||
53 | /* | 62 | /* |
54 | * scsi_register_device_handler - register a device handler personality | 63 | * scsi_dh_handler_attach - Attach a device handler to a device |
55 | * module. | 64 | * @sdev - SCSI device the device handler should attach to |
56 | * @scsi_dh - device handler to be registered. | 65 | * @scsi_dh - The device handler to attach |
66 | */ | ||
67 | static int scsi_dh_handler_attach(struct scsi_device *sdev, | ||
68 | struct scsi_device_handler *scsi_dh) | ||
69 | { | ||
70 | int err = 0; | ||
71 | |||
72 | if (sdev->scsi_dh_data) { | ||
73 | if (sdev->scsi_dh_data->scsi_dh != scsi_dh) | ||
74 | err = -EBUSY; | ||
75 | } else if (scsi_dh->attach) | ||
76 | err = scsi_dh->attach(sdev); | ||
77 | |||
78 | return err; | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * scsi_dh_handler_detach - Detach a device handler from a device | ||
83 | * @sdev - SCSI device the device handler should be detached from | ||
84 | * @scsi_dh - Device handler to be detached | ||
57 | * | 85 | * |
58 | * Returns 0 on success, -EBUSY if handler already registered. | 86 | * Detach from a device handler. If a device handler is specified, |
87 | * only detach if the currently attached handler is equal to it. | ||
59 | */ | 88 | */ |
60 | int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) | 89 | static void scsi_dh_handler_detach(struct scsi_device *sdev, |
90 | struct scsi_device_handler *scsi_dh) | ||
61 | { | 91 | { |
62 | int ret = -EBUSY; | 92 | if (!sdev->scsi_dh_data) |
63 | struct scsi_device_handler *tmp; | 93 | return; |
64 | 94 | ||
65 | tmp = get_device_handler(scsi_dh->name); | 95 | if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh) |
66 | if (tmp) | 96 | return; |
67 | goto done; | ||
68 | 97 | ||
69 | ret = bus_register_notifier(&scsi_bus_type, &scsi_dh->nb); | 98 | if (!scsi_dh) |
99 | scsi_dh = sdev->scsi_dh_data->scsi_dh; | ||
100 | |||
101 | if (scsi_dh && scsi_dh->detach) | ||
102 | scsi_dh->detach(sdev); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * scsi_dh_notifier - notifier chain callback | ||
107 | */ | ||
108 | static int scsi_dh_notifier(struct notifier_block *nb, | ||
109 | unsigned long action, void *data) | ||
110 | { | ||
111 | struct device *dev = data; | ||
112 | struct scsi_device *sdev; | ||
113 | int err = 0; | ||
114 | struct scsi_device_handler *tmp, *devinfo = NULL; | ||
115 | |||
116 | if (!scsi_is_sdev_device(dev)) | ||
117 | return 0; | ||
118 | |||
119 | sdev = to_scsi_device(dev); | ||
70 | 120 | ||
71 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); | ||
72 | spin_lock(&list_lock); | 121 | spin_lock(&list_lock); |
73 | list_add(&scsi_dh->list, &scsi_dh_list); | 122 | list_for_each_entry(tmp, &scsi_dh_list, list) { |
123 | if (device_handler_match(tmp, sdev)) { | ||
124 | devinfo = tmp; | ||
125 | break; | ||
126 | } | ||
127 | } | ||
74 | spin_unlock(&list_lock); | 128 | spin_unlock(&list_lock); |
75 | 129 | ||
76 | done: | 130 | if (!devinfo) |
77 | return ret; | 131 | goto out; |
132 | |||
133 | if (action == BUS_NOTIFY_ADD_DEVICE) { | ||
134 | err = scsi_dh_handler_attach(sdev, devinfo); | ||
135 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | ||
136 | scsi_dh_handler_detach(sdev, NULL); | ||
137 | } | ||
138 | out: | ||
139 | return err; | ||
78 | } | 140 | } |
79 | EXPORT_SYMBOL_GPL(scsi_register_device_handler); | ||
80 | 141 | ||
142 | /* | ||
143 | * scsi_dh_notifier_add - Callback for scsi_register_device_handler | ||
144 | */ | ||
145 | static int scsi_dh_notifier_add(struct device *dev, void *data) | ||
146 | { | ||
147 | struct scsi_device_handler *scsi_dh = data; | ||
148 | struct scsi_device *sdev; | ||
149 | |||
150 | if (!scsi_is_sdev_device(dev)) | ||
151 | return 0; | ||
152 | |||
153 | if (!get_device(dev)) | ||
154 | return 0; | ||
155 | |||
156 | sdev = to_scsi_device(dev); | ||
157 | |||
158 | if (device_handler_match(scsi_dh, sdev)) | ||
159 | scsi_dh_handler_attach(sdev, scsi_dh); | ||
160 | |||
161 | put_device(dev); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler | ||
168 | */ | ||
81 | static int scsi_dh_notifier_remove(struct device *dev, void *data) | 169 | static int scsi_dh_notifier_remove(struct device *dev, void *data) |
82 | { | 170 | { |
83 | struct scsi_device_handler *scsi_dh = data; | 171 | struct scsi_device_handler *scsi_dh = data; |
172 | struct scsi_device *sdev; | ||
173 | |||
174 | if (!scsi_is_sdev_device(dev)) | ||
175 | return 0; | ||
176 | |||
177 | if (!get_device(dev)) | ||
178 | return 0; | ||
179 | |||
180 | sdev = to_scsi_device(dev); | ||
181 | |||
182 | scsi_dh_handler_detach(sdev, scsi_dh); | ||
183 | |||
184 | put_device(dev); | ||
84 | 185 | ||
85 | scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_DEL_DEVICE, dev); | ||
86 | return 0; | 186 | return 0; |
87 | } | 187 | } |
88 | 188 | ||
89 | /* | 189 | /* |
190 | * scsi_register_device_handler - register a device handler personality | ||
191 | * module. | ||
192 | * @scsi_dh - device handler to be registered. | ||
193 | * | ||
194 | * Returns 0 on success, -EBUSY if handler already registered. | ||
195 | */ | ||
196 | int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) | ||
197 | { | ||
198 | if (get_device_handler(scsi_dh->name)) | ||
199 | return -EBUSY; | ||
200 | |||
201 | spin_lock(&list_lock); | ||
202 | list_add(&scsi_dh->list, &scsi_dh_list); | ||
203 | spin_unlock(&list_lock); | ||
204 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); | ||
205 | printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name); | ||
206 | |||
207 | return SCSI_DH_OK; | ||
208 | } | ||
209 | EXPORT_SYMBOL_GPL(scsi_register_device_handler); | ||
210 | |||
211 | /* | ||
90 | * scsi_unregister_device_handler - register a device handler personality | 212 | * scsi_unregister_device_handler - register a device handler personality |
91 | * module. | 213 | * module. |
92 | * @scsi_dh - device handler to be unregistered. | 214 | * @scsi_dh - device handler to be unregistered. |
@@ -95,23 +217,18 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data) | |||
95 | */ | 217 | */ |
96 | int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) | 218 | int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) |
97 | { | 219 | { |
98 | int ret = -ENODEV; | 220 | if (!get_device_handler(scsi_dh->name)) |
99 | struct scsi_device_handler *tmp; | 221 | return -ENODEV; |
100 | |||
101 | tmp = get_device_handler(scsi_dh->name); | ||
102 | if (!tmp) | ||
103 | goto done; | ||
104 | |||
105 | ret = bus_unregister_notifier(&scsi_bus_type, &scsi_dh->nb); | ||
106 | 222 | ||
107 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, | 223 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, |
108 | scsi_dh_notifier_remove); | 224 | scsi_dh_notifier_remove); |
225 | |||
109 | spin_lock(&list_lock); | 226 | spin_lock(&list_lock); |
110 | list_del(&scsi_dh->list); | 227 | list_del(&scsi_dh->list); |
111 | spin_unlock(&list_lock); | 228 | spin_unlock(&list_lock); |
229 | printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name); | ||
112 | 230 | ||
113 | done: | 231 | return SCSI_DH_OK; |
114 | return ret; | ||
115 | } | 232 | } |
116 | EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); | 233 | EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); |
117 | 234 | ||
@@ -157,6 +274,27 @@ int scsi_dh_handler_exist(const char *name) | |||
157 | } | 274 | } |
158 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); | 275 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); |
159 | 276 | ||
277 | static struct notifier_block scsi_dh_nb = { | ||
278 | .notifier_call = scsi_dh_notifier | ||
279 | }; | ||
280 | |||
281 | static int __init scsi_dh_init(void) | ||
282 | { | ||
283 | int r; | ||
284 | |||
285 | r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb); | ||
286 | |||
287 | return r; | ||
288 | } | ||
289 | |||
290 | static void __exit scsi_dh_exit(void) | ||
291 | { | ||
292 | bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb); | ||
293 | } | ||
294 | |||
295 | module_init(scsi_dh_init); | ||
296 | module_exit(scsi_dh_exit); | ||
297 | |||
160 | MODULE_DESCRIPTION("SCSI device handler"); | 298 | MODULE_DESCRIPTION("SCSI device handler"); |
161 | MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>"); | 299 | MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>"); |
162 | MODULE_LICENSE("GPL"); | 300 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index f2467e936e55..bf0a389c52d8 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c | |||
@@ -238,12 +238,12 @@ done: | |||
238 | } | 238 | } |
239 | 239 | ||
240 | /* | 240 | /* |
241 | * Get block request for REQ_BLOCK_PC command issued to path. Currently | 241 | * Get block request for REQ_BLOCK_PC command issued to path. Currently |
242 | * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands. | 242 | * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands. |
243 | * | 243 | * |
244 | * Uses data and sense buffers in hardware handler context structure and | 244 | * Uses data and sense buffers in hardware handler context structure and |
245 | * assumes serial servicing of commands, both issuance and completion. | 245 | * assumes serial servicing of commands, both issuance and completion. |
246 | */ | 246 | */ |
247 | static struct request *get_req(struct scsi_device *sdev, int cmd) | 247 | static struct request *get_req(struct scsi_device *sdev, int cmd) |
248 | { | 248 | { |
249 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | 249 | struct clariion_dh_data *csdev = get_clariion_data(sdev); |
@@ -390,21 +390,21 @@ static int clariion_check_sense(struct scsi_device *sdev, | |||
390 | return SUCCESS; | 390 | return SUCCESS; |
391 | } | 391 | } |
392 | 392 | ||
393 | static const struct { | 393 | const struct scsi_dh_devlist clariion_dev_list[] = { |
394 | char *vendor; | ||
395 | char *model; | ||
396 | } clariion_dev_list[] = { | ||
397 | {"DGC", "RAID"}, | 394 | {"DGC", "RAID"}, |
398 | {"DGC", "DISK"}, | 395 | {"DGC", "DISK"}, |
399 | {NULL, NULL}, | 396 | {NULL, NULL}, |
400 | }; | 397 | }; |
401 | 398 | ||
402 | static int clariion_bus_notify(struct notifier_block *, unsigned long, void *); | 399 | static int clariion_bus_attach(struct scsi_device *sdev); |
400 | static void clariion_bus_detach(struct scsi_device *sdev); | ||
403 | 401 | ||
404 | static struct scsi_device_handler clariion_dh = { | 402 | static struct scsi_device_handler clariion_dh = { |
405 | .name = CLARIION_NAME, | 403 | .name = CLARIION_NAME, |
406 | .module = THIS_MODULE, | 404 | .module = THIS_MODULE, |
407 | .nb.notifier_call = clariion_bus_notify, | 405 | .devlist = clariion_dev_list, |
406 | .attach = clariion_bus_attach, | ||
407 | .detach = clariion_bus_detach, | ||
408 | .check_sense = clariion_check_sense, | 408 | .check_sense = clariion_check_sense, |
409 | .activate = clariion_activate, | 409 | .activate = clariion_activate, |
410 | }; | 410 | }; |
@@ -412,73 +412,50 @@ static struct scsi_device_handler clariion_dh = { | |||
412 | /* | 412 | /* |
413 | * TODO: need some interface so we can set trespass values | 413 | * TODO: need some interface so we can set trespass values |
414 | */ | 414 | */ |
415 | static int clariion_bus_notify(struct notifier_block *nb, | 415 | static int clariion_bus_attach(struct scsi_device *sdev) |
416 | unsigned long action, void *data) | ||
417 | { | 416 | { |
418 | struct device *dev = data; | ||
419 | struct scsi_device *sdev; | ||
420 | struct scsi_dh_data *scsi_dh_data; | 417 | struct scsi_dh_data *scsi_dh_data; |
421 | struct clariion_dh_data *h; | 418 | struct clariion_dh_data *h; |
422 | int i, found = 0; | ||
423 | unsigned long flags; | 419 | unsigned long flags; |
424 | 420 | ||
425 | if (!scsi_is_sdev_device(dev)) | 421 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) |
426 | return 0; | 422 | + sizeof(*h) , GFP_KERNEL); |
427 | 423 | if (!scsi_dh_data) { | |
428 | sdev = to_scsi_device(dev); | 424 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", |
429 | 425 | CLARIION_NAME); | |
430 | if (action == BUS_NOTIFY_ADD_DEVICE) { | 426 | return -ENOMEM; |
431 | for (i = 0; clariion_dev_list[i].vendor; i++) { | 427 | } |
432 | if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor, | ||
433 | strlen(clariion_dev_list[i].vendor)) && | ||
434 | !strncmp(sdev->model, clariion_dev_list[i].model, | ||
435 | strlen(clariion_dev_list[i].model))) { | ||
436 | found = 1; | ||
437 | break; | ||
438 | } | ||
439 | } | ||
440 | if (!found) | ||
441 | goto out; | ||
442 | |||
443 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
444 | + sizeof(*h) , GFP_KERNEL); | ||
445 | if (!scsi_dh_data) { | ||
446 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", | ||
447 | CLARIION_NAME); | ||
448 | goto out; | ||
449 | } | ||
450 | 428 | ||
451 | scsi_dh_data->scsi_dh = &clariion_dh; | 429 | scsi_dh_data->scsi_dh = &clariion_dh; |
452 | h = (struct clariion_dh_data *) scsi_dh_data->buf; | 430 | h = (struct clariion_dh_data *) scsi_dh_data->buf; |
453 | h->default_sp = CLARIION_UNBOUND_LU; | 431 | h->default_sp = CLARIION_UNBOUND_LU; |
454 | h->current_sp = CLARIION_UNBOUND_LU; | 432 | h->current_sp = CLARIION_UNBOUND_LU; |
455 | 433 | ||
456 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | 434 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); |
457 | sdev->scsi_dh_data = scsi_dh_data; | 435 | sdev->scsi_dh_data = scsi_dh_data; |
458 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | 436 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); |
459 | 437 | ||
460 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME); | 438 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME); |
461 | try_module_get(THIS_MODULE); | 439 | try_module_get(THIS_MODULE); |
462 | 440 | ||
463 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | 441 | return 0; |
464 | if (sdev->scsi_dh_data == NULL || | 442 | } |
465 | sdev->scsi_dh_data->scsi_dh != &clariion_dh) | ||
466 | goto out; | ||
467 | 443 | ||
468 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | 444 | static void clariion_bus_detach(struct scsi_device *sdev) |
469 | scsi_dh_data = sdev->scsi_dh_data; | 445 | { |
470 | sdev->scsi_dh_data = NULL; | 446 | struct scsi_dh_data *scsi_dh_data; |
471 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | 447 | unsigned long flags; |
472 | 448 | ||
473 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", | 449 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); |
474 | CLARIION_NAME); | 450 | scsi_dh_data = sdev->scsi_dh_data; |
451 | sdev->scsi_dh_data = NULL; | ||
452 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
475 | 453 | ||
476 | kfree(scsi_dh_data); | 454 | sdev_printk(KERN_NOTICE, sdev, "Detached %s.\n", |
477 | module_put(THIS_MODULE); | 455 | CLARIION_NAME); |
478 | } | ||
479 | 456 | ||
480 | out: | 457 | kfree(scsi_dh_data); |
481 | return 0; | 458 | module_put(THIS_MODULE); |
482 | } | 459 | } |
483 | 460 | ||
484 | static int __init clariion_init(void) | 461 | static int __init clariion_init(void) |
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index ae6be87d6a83..78259bc5dfc9 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c | |||
@@ -108,85 +108,63 @@ done: | |||
108 | return ret; | 108 | return ret; |
109 | } | 109 | } |
110 | 110 | ||
111 | static const struct { | 111 | const struct scsi_dh_devlist hp_sw_dh_data_list[] = { |
112 | char *vendor; | ||
113 | char *model; | ||
114 | } hp_sw_dh_data_list[] = { | ||
115 | {"COMPAQ", "MSA"}, | 112 | {"COMPAQ", "MSA"}, |
116 | {"HP", "HSV"}, | 113 | {"HP", "HSV"}, |
117 | {"DEC", "HSG80"}, | 114 | {"DEC", "HSG80"}, |
118 | {NULL, NULL}, | 115 | {NULL, NULL}, |
119 | }; | 116 | }; |
120 | 117 | ||
121 | static int hp_sw_bus_notify(struct notifier_block *, unsigned long, void *); | 118 | static int hp_sw_bus_attach(struct scsi_device *sdev); |
119 | static void hp_sw_bus_detach(struct scsi_device *sdev); | ||
122 | 120 | ||
123 | static struct scsi_device_handler hp_sw_dh = { | 121 | static struct scsi_device_handler hp_sw_dh = { |
124 | .name = HP_SW_NAME, | 122 | .name = HP_SW_NAME, |
125 | .module = THIS_MODULE, | 123 | .module = THIS_MODULE, |
126 | .nb.notifier_call = hp_sw_bus_notify, | 124 | .devlist = hp_sw_dh_data_list, |
125 | .attach = hp_sw_bus_attach, | ||
126 | .detach = hp_sw_bus_detach, | ||
127 | .activate = hp_sw_activate, | 127 | .activate = hp_sw_activate, |
128 | }; | 128 | }; |
129 | 129 | ||
130 | static int hp_sw_bus_notify(struct notifier_block *nb, | 130 | static int hp_sw_bus_attach(struct scsi_device *sdev) |
131 | unsigned long action, void *data) | ||
132 | { | 131 | { |
133 | struct device *dev = data; | ||
134 | struct scsi_device *sdev; | ||
135 | struct scsi_dh_data *scsi_dh_data; | 132 | struct scsi_dh_data *scsi_dh_data; |
136 | int i, found = 0; | ||
137 | unsigned long flags; | 133 | unsigned long flags; |
138 | 134 | ||
139 | if (!scsi_is_sdev_device(dev)) | 135 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) |
136 | + sizeof(struct hp_sw_dh_data) , GFP_KERNEL); | ||
137 | if (!scsi_dh_data) { | ||
138 | sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n", | ||
139 | HP_SW_NAME); | ||
140 | return 0; | 140 | return 0; |
141 | } | ||
141 | 142 | ||
142 | sdev = to_scsi_device(dev); | 143 | scsi_dh_data->scsi_dh = &hp_sw_dh; |
143 | 144 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | |
144 | if (action == BUS_NOTIFY_ADD_DEVICE) { | 145 | sdev->scsi_dh_data = scsi_dh_data; |
145 | for (i = 0; hp_sw_dh_data_list[i].vendor; i++) { | 146 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); |
146 | if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor, | 147 | try_module_get(THIS_MODULE); |
147 | strlen(hp_sw_dh_data_list[i].vendor)) && | ||
148 | !strncmp(sdev->model, hp_sw_dh_data_list[i].model, | ||
149 | strlen(hp_sw_dh_data_list[i].model))) { | ||
150 | found = 1; | ||
151 | break; | ||
152 | } | ||
153 | } | ||
154 | if (!found) | ||
155 | goto out; | ||
156 | |||
157 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
158 | + sizeof(struct hp_sw_dh_data) , GFP_KERNEL); | ||
159 | if (!scsi_dh_data) { | ||
160 | sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n", | ||
161 | HP_SW_NAME); | ||
162 | goto out; | ||
163 | } | ||
164 | 148 | ||
165 | scsi_dh_data->scsi_dh = &hp_sw_dh; | 149 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME); |
166 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
167 | sdev->scsi_dh_data = scsi_dh_data; | ||
168 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
169 | try_module_get(THIS_MODULE); | ||
170 | 150 | ||
171 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME); | 151 | return 0; |
172 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | 152 | } |
173 | if (sdev->scsi_dh_data == NULL || | ||
174 | sdev->scsi_dh_data->scsi_dh != &hp_sw_dh) | ||
175 | goto out; | ||
176 | 153 | ||
177 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | 154 | static void hp_sw_bus_detach( struct scsi_device *sdev ) |
178 | scsi_dh_data = sdev->scsi_dh_data; | 155 | { |
179 | sdev->scsi_dh_data = NULL; | 156 | struct scsi_dh_data *scsi_dh_data; |
180 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | 157 | unsigned long flags; |
181 | module_put(THIS_MODULE); | ||
182 | 158 | ||
183 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", HP_SW_NAME); | 159 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); |
160 | scsi_dh_data = sdev->scsi_dh_data; | ||
161 | sdev->scsi_dh_data = NULL; | ||
162 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
163 | module_put(THIS_MODULE); | ||
184 | 164 | ||
185 | kfree(scsi_dh_data); | 165 | sdev_printk(KERN_NOTICE, sdev, "Detached %s\n", HP_SW_NAME); |
186 | } | ||
187 | 166 | ||
188 | out: | 167 | kfree(scsi_dh_data); |
189 | return 0; | ||
190 | } | 168 | } |
191 | 169 | ||
192 | static int __init hp_sw_init(void) | 170 | static int __init hp_sw_init(void) |
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index fdf34b0ec6e1..0e25a6e9c82d 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c | |||
@@ -569,10 +569,7 @@ static int rdac_check_sense(struct scsi_device *sdev, | |||
569 | return SCSI_RETURN_NOT_HANDLED; | 569 | return SCSI_RETURN_NOT_HANDLED; |
570 | } | 570 | } |
571 | 571 | ||
572 | static const struct { | 572 | const struct scsi_dh_devlist rdac_dev_list[] = { |
573 | char *vendor; | ||
574 | char *model; | ||
575 | } rdac_dev_list[] = { | ||
576 | {"IBM", "1722"}, | 573 | {"IBM", "1722"}, |
577 | {"IBM", "1724"}, | 574 | {"IBM", "1724"}, |
578 | {"IBM", "1726"}, | 575 | {"IBM", "1726"}, |
@@ -590,89 +587,69 @@ static const struct { | |||
590 | {NULL, NULL}, | 587 | {NULL, NULL}, |
591 | }; | 588 | }; |
592 | 589 | ||
593 | static int rdac_bus_notify(struct notifier_block *, unsigned long, void *); | 590 | static int rdac_bus_attach(struct scsi_device *sdev); |
591 | static void rdac_bus_detach(struct scsi_device *sdev); | ||
594 | 592 | ||
595 | static struct scsi_device_handler rdac_dh = { | 593 | static struct scsi_device_handler rdac_dh = { |
596 | .name = RDAC_NAME, | 594 | .name = RDAC_NAME, |
597 | .module = THIS_MODULE, | 595 | .module = THIS_MODULE, |
598 | .nb.notifier_call = rdac_bus_notify, | 596 | .devlist = rdac_dev_list, |
599 | .prep_fn = rdac_prep_fn, | 597 | .prep_fn = rdac_prep_fn, |
600 | .check_sense = rdac_check_sense, | 598 | .check_sense = rdac_check_sense, |
599 | .attach = rdac_bus_attach, | ||
600 | .detach = rdac_bus_detach, | ||
601 | .activate = rdac_activate, | 601 | .activate = rdac_activate, |
602 | }; | 602 | }; |
603 | 603 | ||
604 | /* | 604 | static int rdac_bus_attach(struct scsi_device *sdev) |
605 | * TODO: need some interface so we can set trespass values | ||
606 | */ | ||
607 | static int rdac_bus_notify(struct notifier_block *nb, | ||
608 | unsigned long action, void *data) | ||
609 | { | 605 | { |
610 | struct device *dev = data; | ||
611 | struct scsi_device *sdev; | ||
612 | struct scsi_dh_data *scsi_dh_data; | 606 | struct scsi_dh_data *scsi_dh_data; |
613 | struct rdac_dh_data *h; | 607 | struct rdac_dh_data *h; |
614 | int i, found = 0; | ||
615 | unsigned long flags; | 608 | unsigned long flags; |
616 | 609 | ||
617 | if (!scsi_is_sdev_device(dev)) | 610 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) |
611 | + sizeof(*h) , GFP_KERNEL); | ||
612 | if (!scsi_dh_data) { | ||
613 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", | ||
614 | RDAC_NAME); | ||
618 | return 0; | 615 | return 0; |
616 | } | ||
619 | 617 | ||
620 | sdev = to_scsi_device(dev); | 618 | scsi_dh_data->scsi_dh = &rdac_dh; |
621 | 619 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | |
622 | if (action == BUS_NOTIFY_ADD_DEVICE) { | 620 | h->lun = UNINITIALIZED_LUN; |
623 | for (i = 0; rdac_dev_list[i].vendor; i++) { | 621 | h->state = RDAC_STATE_ACTIVE; |
624 | if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor, | 622 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); |
625 | strlen(rdac_dev_list[i].vendor)) && | 623 | sdev->scsi_dh_data = scsi_dh_data; |
626 | !strncmp(sdev->model, rdac_dev_list[i].model, | 624 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); |
627 | strlen(rdac_dev_list[i].model))) { | 625 | try_module_get(THIS_MODULE); |
628 | found = 1; | ||
629 | break; | ||
630 | } | ||
631 | } | ||
632 | if (!found) | ||
633 | goto out; | ||
634 | |||
635 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
636 | + sizeof(*h) , GFP_KERNEL); | ||
637 | if (!scsi_dh_data) { | ||
638 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", | ||
639 | RDAC_NAME); | ||
640 | goto out; | ||
641 | } | ||
642 | 626 | ||
643 | scsi_dh_data->scsi_dh = &rdac_dh; | 627 | sdev_printk(KERN_NOTICE, sdev, "Attached %s\n", RDAC_NAME); |
644 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | ||
645 | h->lun = UNINITIALIZED_LUN; | ||
646 | h->state = RDAC_STATE_ACTIVE; | ||
647 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
648 | sdev->scsi_dh_data = scsi_dh_data; | ||
649 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
650 | try_module_get(THIS_MODULE); | ||
651 | |||
652 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", RDAC_NAME); | ||
653 | |||
654 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | ||
655 | if (sdev->scsi_dh_data == NULL || | ||
656 | sdev->scsi_dh_data->scsi_dh != &rdac_dh) | ||
657 | goto out; | ||
658 | |||
659 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
660 | scsi_dh_data = sdev->scsi_dh_data; | ||
661 | sdev->scsi_dh_data = NULL; | ||
662 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
663 | |||
664 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | ||
665 | if (h->ctlr) | ||
666 | kref_put(&h->ctlr->kref, release_controller); | ||
667 | kfree(scsi_dh_data); | ||
668 | module_put(THIS_MODULE); | ||
669 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", RDAC_NAME); | ||
670 | } | ||
671 | 628 | ||
672 | out: | ||
673 | return 0; | 629 | return 0; |
674 | } | 630 | } |
675 | 631 | ||
632 | static void rdac_bus_detach( struct scsi_device *sdev ) | ||
633 | { | ||
634 | struct scsi_dh_data *scsi_dh_data; | ||
635 | struct rdac_dh_data *h; | ||
636 | unsigned long flags; | ||
637 | |||
638 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
639 | scsi_dh_data = sdev->scsi_dh_data; | ||
640 | sdev->scsi_dh_data = NULL; | ||
641 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
642 | |||
643 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | ||
644 | if (h->ctlr) | ||
645 | kref_put(&h->ctlr->kref, release_controller); | ||
646 | kfree(scsi_dh_data); | ||
647 | module_put(THIS_MODULE); | ||
648 | sdev_printk(KERN_NOTICE, sdev, "Detached %s\n", RDAC_NAME); | ||
649 | } | ||
650 | |||
651 | |||
652 | |||
676 | static int __init rdac_init(void) | 653 | static int __init rdac_init(void) |
677 | { | 654 | { |
678 | int r; | 655 | int r; |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 6467f78b191f..4deb9349eebf 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
@@ -167,15 +167,22 @@ struct scsi_device { | |||
167 | unsigned long sdev_data[0]; | 167 | unsigned long sdev_data[0]; |
168 | } __attribute__((aligned(sizeof(unsigned long)))); | 168 | } __attribute__((aligned(sizeof(unsigned long)))); |
169 | 169 | ||
170 | struct scsi_dh_devlist { | ||
171 | char *vendor; | ||
172 | char *model; | ||
173 | }; | ||
174 | |||
170 | struct scsi_device_handler { | 175 | struct scsi_device_handler { |
171 | /* Used by the infrastructure */ | 176 | /* Used by the infrastructure */ |
172 | struct list_head list; /* list of scsi_device_handlers */ | 177 | struct list_head list; /* list of scsi_device_handlers */ |
173 | struct notifier_block nb; | ||
174 | 178 | ||
175 | /* Filled by the hardware handler */ | 179 | /* Filled by the hardware handler */ |
176 | struct module *module; | 180 | struct module *module; |
177 | const char *name; | 181 | const char *name; |
182 | const struct scsi_dh_devlist *devlist; | ||
178 | int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *); | 183 | int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *); |
184 | int (*attach)(struct scsi_device *); | ||
185 | void (*detach)(struct scsi_device *); | ||
179 | int (*activate)(struct scsi_device *); | 186 | int (*activate)(struct scsi_device *); |
180 | int (*prep_fn)(struct scsi_device *, struct request *); | 187 | int (*prep_fn)(struct scsi_device *, struct request *); |
181 | }; | 188 | }; |