diff options
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh.c | 112 | ||||
-rw-r--r-- | drivers/scsi/scsi_priv.h | 1 | ||||
-rw-r--r-- | include/scsi/scsi_device.h | 1 |
3 files changed, 39 insertions, 75 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index b837c5b3c8f9..564e6ecd17c2 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 | ||
28 | struct 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 | |||
35 | static DEFINE_SPINLOCK(list_lock); | 28 | static DEFINE_SPINLOCK(list_lock); |
36 | static LIST_HEAD(scsi_dh_list); | 29 | static LIST_HEAD(scsi_dh_list); |
37 | static LIST_HEAD(scsi_dh_dev_list); | 30 | static int scsi_dh_list_idx = 1; |
38 | 31 | ||
39 | static struct scsi_device_handler *get_device_handler(const char *name) | 32 | static 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 | 47 | static struct scsi_device_handler *get_device_handler_by_idx(int idx) | |
55 | static struct scsi_device_handler * | ||
56 | scsi_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 | |||
74 | static 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 | */ |
374 | int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) | 318 | int 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 | */ |
396 | int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) | 353 | int 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 | ||
@@ -576,6 +533,10 @@ static int __init scsi_dh_init(void) | |||
576 | { | 533 | { |
577 | int r; | 534 | int r; |
578 | 535 | ||
536 | r = scsi_dev_info_add_list(SCSI_DEVINFO_DH, "SCSI Device Handler"); | ||
537 | if (r) | ||
538 | return r; | ||
539 | |||
579 | r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb); | 540 | r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb); |
580 | 541 | ||
581 | if (!r) | 542 | if (!r) |
@@ -590,6 +551,7 @@ static void __exit scsi_dh_exit(void) | |||
590 | bus_for_each_dev(&scsi_bus_type, NULL, NULL, | 551 | bus_for_each_dev(&scsi_bus_type, NULL, NULL, |
591 | scsi_dh_sysfs_attr_remove); | 552 | scsi_dh_sysfs_attr_remove); |
592 | bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb); | 553 | bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb); |
554 | scsi_dev_info_remove_list(SCSI_DEVINFO_DH); | ||
593 | } | 555 | } |
594 | 556 | ||
595 | module_init(scsi_dh_init); | 557 | module_init(scsi_dh_init); |
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index ce9e0adc8df8..9868afdb24e2 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
@@ -45,6 +45,7 @@ static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) | |||
45 | enum { | 45 | enum { |
46 | SCSI_DEVINFO_GLOBAL = 0, | 46 | SCSI_DEVINFO_GLOBAL = 0, |
47 | SCSI_DEVINFO_SPI, | 47 | SCSI_DEVINFO_SPI, |
48 | SCSI_DEVINFO_DH, | ||
48 | }; | 49 | }; |
49 | 50 | ||
50 | extern int scsi_get_device_flags(struct scsi_device *sdev, | 51 | extern int scsi_get_device_flags(struct scsi_device *sdev, |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 85867dcde335..f171c65dc5a8 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
@@ -184,6 +184,7 @@ typedef void (*activate_complete)(void *, int); | |||
184 | struct scsi_device_handler { | 184 | struct scsi_device_handler { |
185 | /* Used by the infrastructure */ | 185 | /* Used by the infrastructure */ |
186 | struct list_head list; /* list of scsi_device_handlers */ | 186 | struct list_head list; /* list of scsi_device_handlers */ |
187 | int idx; | ||
187 | 188 | ||
188 | /* Filled by the hardware handler */ | 189 | /* Filled by the hardware handler */ |
189 | struct module *module; | 190 | struct module *module; |