aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/device_handler/scsi_dh.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/device_handler/scsi_dh.c')
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c130
1 files changed, 51 insertions, 79 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index 6fae3d285ae7..0119b8147797 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -25,16 +25,9 @@
25#include <scsi/scsi_dh.h> 25#include <scsi/scsi_dh.h>
26#include "../scsi_priv.h" 26#include "../scsi_priv.h"
27 27
28struct scsi_dh_devinfo_list {
29 struct list_head node;
30 char vendor[9];
31 char model[17];
32 struct scsi_device_handler *handler;
33};
34
35static DEFINE_SPINLOCK(list_lock); 28static DEFINE_SPINLOCK(list_lock);
36static LIST_HEAD(scsi_dh_list); 29static LIST_HEAD(scsi_dh_list);
37static LIST_HEAD(scsi_dh_dev_list); 30static int scsi_dh_list_idx = 1;
38 31
39static struct scsi_device_handler *get_device_handler(const char *name) 32static struct scsi_device_handler *get_device_handler(const char *name)
40{ 33{
@@ -51,40 +44,18 @@ static struct scsi_device_handler *get_device_handler(const char *name)
51 return found; 44 return found;
52} 45}
53 46
54 47static struct scsi_device_handler *get_device_handler_by_idx(int idx)
55static struct scsi_device_handler *
56scsi_dh_cache_lookup(struct scsi_device *sdev)
57{ 48{
58 struct scsi_dh_devinfo_list *tmp; 49 struct scsi_device_handler *tmp, *found = NULL;
59 struct scsi_device_handler *found_dh = NULL;
60 50
61 spin_lock(&list_lock); 51 spin_lock(&list_lock);
62 list_for_each_entry(tmp, &scsi_dh_dev_list, node) { 52 list_for_each_entry(tmp, &scsi_dh_list, list) {
63 if (!strncmp(sdev->vendor, tmp->vendor, strlen(tmp->vendor)) && 53 if (tmp->idx == idx) {
64 !strncmp(sdev->model, tmp->model, strlen(tmp->model))) { 54 found = tmp;
65 found_dh = tmp->handler;
66 break; 55 break;
67 } 56 }
68 } 57 }
69 spin_unlock(&list_lock); 58 spin_unlock(&list_lock);
70
71 return found_dh;
72}
73
74static int scsi_dh_handler_lookup(struct scsi_device_handler *scsi_dh,
75 struct scsi_device *sdev)
76{
77 int i, found = 0;
78
79 for(i = 0; scsi_dh->devlist[i].vendor; i++) {
80 if (!strncmp(sdev->vendor, scsi_dh->devlist[i].vendor,
81 strlen(scsi_dh->devlist[i].vendor)) &&
82 !strncmp(sdev->model, scsi_dh->devlist[i].model,
83 strlen(scsi_dh->devlist[i].model))) {
84 found = 1;
85 break;
86 }
87 }
88 return found; 59 return found;
89} 60}
90 61
@@ -102,41 +73,14 @@ device_handler_match(struct scsi_device_handler *scsi_dh,
102 struct scsi_device *sdev) 73 struct scsi_device *sdev)
103{ 74{
104 struct scsi_device_handler *found_dh = NULL; 75 struct scsi_device_handler *found_dh = NULL;
105 struct scsi_dh_devinfo_list *tmp; 76 int idx;
106 77
107 found_dh = scsi_dh_cache_lookup(sdev); 78 idx = scsi_get_device_flags_keyed(sdev, sdev->vendor, sdev->model,
108 if (found_dh) 79 SCSI_DEVINFO_DH);
109 return found_dh; 80 found_dh = get_device_handler_by_idx(idx);
110 81
111 if (scsi_dh) { 82 if (scsi_dh && found_dh != scsi_dh)
112 if (scsi_dh_handler_lookup(scsi_dh, sdev)) 83 found_dh = NULL;
113 found_dh = scsi_dh;
114 } else {
115 struct scsi_device_handler *tmp_dh;
116
117 spin_lock(&list_lock);
118 list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
119 if (scsi_dh_handler_lookup(tmp_dh, sdev))
120 found_dh = tmp_dh;
121 }
122 spin_unlock(&list_lock);
123 }
124
125 if (found_dh) { /* If device is found, add it to the cache */
126 tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
127 if (tmp) {
128 strncpy(tmp->vendor, sdev->vendor, 8);
129 strncpy(tmp->model, sdev->model, 16);
130 tmp->vendor[8] = '\0';
131 tmp->model[16] = '\0';
132 tmp->handler = found_dh;
133 spin_lock(&list_lock);
134 list_add(&tmp->node, &scsi_dh_dev_list);
135 spin_unlock(&list_lock);
136 } else {
137 found_dh = NULL;
138 }
139 }
140 84
141 return found_dh; 85 return found_dh;
142} 86}
@@ -373,12 +317,25 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data)
373 */ 317 */
374int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) 318int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
375{ 319{
320 int i;
321
376 if (get_device_handler(scsi_dh->name)) 322 if (get_device_handler(scsi_dh->name))
377 return -EBUSY; 323 return -EBUSY;
378 324
379 spin_lock(&list_lock); 325 spin_lock(&list_lock);
326 scsi_dh->idx = scsi_dh_list_idx++;
380 list_add(&scsi_dh->list, &scsi_dh_list); 327 list_add(&scsi_dh->list, &scsi_dh_list);
381 spin_unlock(&list_lock); 328 spin_unlock(&list_lock);
329
330 for (i = 0; scsi_dh->devlist[i].vendor; i++) {
331 scsi_dev_info_list_add_keyed(0,
332 scsi_dh->devlist[i].vendor,
333 scsi_dh->devlist[i].model,
334 NULL,
335 scsi_dh->idx,
336 SCSI_DEVINFO_DH);
337 }
338
382 bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); 339 bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
383 printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name); 340 printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
384 341
@@ -395,7 +352,7 @@ EXPORT_SYMBOL_GPL(scsi_register_device_handler);
395 */ 352 */
396int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) 353int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
397{ 354{
398 struct scsi_dh_devinfo_list *tmp, *pos; 355 int i;
399 356
400 if (!get_device_handler(scsi_dh->name)) 357 if (!get_device_handler(scsi_dh->name))
401 return -ENODEV; 358 return -ENODEV;
@@ -403,14 +360,14 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
403 bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, 360 bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
404 scsi_dh_notifier_remove); 361 scsi_dh_notifier_remove);
405 362
363 for (i = 0; scsi_dh->devlist[i].vendor; i++) {
364 scsi_dev_info_list_del_keyed(scsi_dh->devlist[i].vendor,
365 scsi_dh->devlist[i].model,
366 SCSI_DEVINFO_DH);
367 }
368
406 spin_lock(&list_lock); 369 spin_lock(&list_lock);
407 list_del(&scsi_dh->list); 370 list_del(&scsi_dh->list);
408 list_for_each_entry_safe(pos, tmp, &scsi_dh_dev_list, node) {
409 if (pos->handler == scsi_dh) {
410 list_del(&pos->node);
411 kfree(pos);
412 }
413 }
414 spin_unlock(&list_lock); 371 spin_unlock(&list_lock);
415 printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name); 372 printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
416 373
@@ -437,21 +394,31 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
437 unsigned long flags; 394 unsigned long flags;
438 struct scsi_device *sdev; 395 struct scsi_device *sdev;
439 struct scsi_device_handler *scsi_dh = NULL; 396 struct scsi_device_handler *scsi_dh = NULL;
397 struct device *dev = NULL;
440 398
441 spin_lock_irqsave(q->queue_lock, flags); 399 spin_lock_irqsave(q->queue_lock, flags);
442 sdev = q->queuedata; 400 sdev = q->queuedata;
443 if (sdev && sdev->scsi_dh_data) 401 if (sdev && sdev->scsi_dh_data)
444 scsi_dh = sdev->scsi_dh_data->scsi_dh; 402 scsi_dh = sdev->scsi_dh_data->scsi_dh;
445 if (!scsi_dh || !get_device(&sdev->sdev_gendev)) 403 dev = get_device(&sdev->sdev_gendev);
404 if (!scsi_dh || !dev ||
405 sdev->sdev_state == SDEV_CANCEL ||
406 sdev->sdev_state == SDEV_DEL)
446 err = SCSI_DH_NOSYS; 407 err = SCSI_DH_NOSYS;
408 if (sdev->sdev_state == SDEV_OFFLINE)
409 err = SCSI_DH_DEV_OFFLINED;
447 spin_unlock_irqrestore(q->queue_lock, flags); 410 spin_unlock_irqrestore(q->queue_lock, flags);
448 411
449 if (err) 412 if (err) {
450 return err; 413 if (fn)
414 fn(data, err);
415 goto out;
416 }
451 417
452 if (scsi_dh->activate) 418 if (scsi_dh->activate)
453 err = scsi_dh->activate(sdev, fn, data); 419 err = scsi_dh->activate(sdev, fn, data);
454 put_device(&sdev->sdev_gendev); 420out:
421 put_device(dev);
455 return err; 422 return err;
456} 423}
457EXPORT_SYMBOL_GPL(scsi_dh_activate); 424EXPORT_SYMBOL_GPL(scsi_dh_activate);
@@ -569,6 +536,10 @@ static int __init scsi_dh_init(void)
569{ 536{
570 int r; 537 int r;
571 538
539 r = scsi_dev_info_add_list(SCSI_DEVINFO_DH, "SCSI Device Handler");
540 if (r)
541 return r;
542
572 r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb); 543 r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);
573 544
574 if (!r) 545 if (!r)
@@ -583,6 +554,7 @@ static void __exit scsi_dh_exit(void)
583 bus_for_each_dev(&scsi_bus_type, NULL, NULL, 554 bus_for_each_dev(&scsi_bus_type, NULL, NULL,
584 scsi_dh_sysfs_attr_remove); 555 scsi_dh_sysfs_attr_remove);
585 bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb); 556 bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
557 scsi_dev_info_remove_list(SCSI_DEVINFO_DH);
586} 558}
587 559
588module_init(scsi_dh_init); 560module_init(scsi_dh_init);