diff options
Diffstat (limited to 'drivers/scsi/device_handler/scsi_dh.c')
-rw-r--r-- | drivers/scsi/device_handler/scsi_dh.c | 72 |
1 files changed, 62 insertions, 10 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 0119b8147797..23149b9e297c 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/module.h> | ||
25 | #include <scsi/scsi_dh.h> | 26 | #include <scsi/scsi_dh.h> |
26 | #include "../scsi_priv.h" | 27 | #include "../scsi_priv.h" |
27 | 28 | ||
@@ -60,6 +61,46 @@ static struct scsi_device_handler *get_device_handler_by_idx(int idx) | |||
60 | } | 61 | } |
61 | 62 | ||
62 | /* | 63 | /* |
64 | * device_handler_match_function - Match a device handler to a device | ||
65 | * @sdev - SCSI device to be tested | ||
66 | * | ||
67 | * Tests @sdev against the match function of all registered device_handler. | ||
68 | * Returns the found device handler or NULL if not found. | ||
69 | */ | ||
70 | static struct scsi_device_handler * | ||
71 | device_handler_match_function(struct scsi_device *sdev) | ||
72 | { | ||
73 | struct scsi_device_handler *tmp_dh, *found_dh = NULL; | ||
74 | |||
75 | spin_lock(&list_lock); | ||
76 | list_for_each_entry(tmp_dh, &scsi_dh_list, list) { | ||
77 | if (tmp_dh->match && tmp_dh->match(sdev)) { | ||
78 | found_dh = tmp_dh; | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | spin_unlock(&list_lock); | ||
83 | return found_dh; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * device_handler_match_devlist - Match a device handler to a device | ||
88 | * @sdev - SCSI device to be tested | ||
89 | * | ||
90 | * Tests @sdev against all device_handler registered in the devlist. | ||
91 | * Returns the found device handler or NULL if not found. | ||
92 | */ | ||
93 | static struct scsi_device_handler * | ||
94 | device_handler_match_devlist(struct scsi_device *sdev) | ||
95 | { | ||
96 | int idx; | ||
97 | |||
98 | idx = scsi_get_device_flags_keyed(sdev, sdev->vendor, sdev->model, | ||
99 | SCSI_DEVINFO_DH); | ||
100 | return get_device_handler_by_idx(idx); | ||
101 | } | ||
102 | |||
103 | /* | ||
63 | * device_handler_match - Attach a device handler to a device | 104 | * device_handler_match - Attach a device handler to a device |
64 | * @scsi_dh - The device handler to match against or NULL | 105 | * @scsi_dh - The device handler to match against or NULL |
65 | * @sdev - SCSI device to be tested against @scsi_dh | 106 | * @sdev - SCSI device to be tested against @scsi_dh |
@@ -72,12 +113,11 @@ static struct scsi_device_handler * | |||
72 | device_handler_match(struct scsi_device_handler *scsi_dh, | 113 | device_handler_match(struct scsi_device_handler *scsi_dh, |
73 | struct scsi_device *sdev) | 114 | struct scsi_device *sdev) |
74 | { | 115 | { |
75 | struct scsi_device_handler *found_dh = NULL; | 116 | struct scsi_device_handler *found_dh; |
76 | int idx; | ||
77 | 117 | ||
78 | idx = scsi_get_device_flags_keyed(sdev, sdev->vendor, sdev->model, | 118 | found_dh = device_handler_match_function(sdev); |
79 | SCSI_DEVINFO_DH); | 119 | if (!found_dh) |
80 | found_dh = get_device_handler_by_idx(idx); | 120 | found_dh = device_handler_match_devlist(sdev); |
81 | 121 | ||
82 | if (scsi_dh && found_dh != scsi_dh) | 122 | if (scsi_dh && found_dh != scsi_dh) |
83 | found_dh = NULL; | 123 | found_dh = NULL; |
@@ -151,6 +191,10 @@ store_dh_state(struct device *dev, struct device_attribute *attr, | |||
151 | struct scsi_device_handler *scsi_dh; | 191 | struct scsi_device_handler *scsi_dh; |
152 | int err = -EINVAL; | 192 | int err = -EINVAL; |
153 | 193 | ||
194 | if (sdev->sdev_state == SDEV_CANCEL || | ||
195 | sdev->sdev_state == SDEV_DEL) | ||
196 | return -ENODEV; | ||
197 | |||
154 | if (!sdev->scsi_dh_data) { | 198 | if (!sdev->scsi_dh_data) { |
155 | /* | 199 | /* |
156 | * Attach to a device handler | 200 | * Attach to a device handler |
@@ -327,7 +371,7 @@ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) | |||
327 | list_add(&scsi_dh->list, &scsi_dh_list); | 371 | list_add(&scsi_dh->list, &scsi_dh_list); |
328 | spin_unlock(&list_lock); | 372 | spin_unlock(&list_lock); |
329 | 373 | ||
330 | for (i = 0; scsi_dh->devlist[i].vendor; i++) { | 374 | for (i = 0; scsi_dh->devlist && scsi_dh->devlist[i].vendor; i++) { |
331 | scsi_dev_info_list_add_keyed(0, | 375 | scsi_dev_info_list_add_keyed(0, |
332 | scsi_dh->devlist[i].vendor, | 376 | scsi_dh->devlist[i].vendor, |
333 | scsi_dh->devlist[i].model, | 377 | scsi_dh->devlist[i].model, |
@@ -360,7 +404,7 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) | |||
360 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, | 404 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, |
361 | scsi_dh_notifier_remove); | 405 | scsi_dh_notifier_remove); |
362 | 406 | ||
363 | for (i = 0; scsi_dh->devlist[i].vendor; i++) { | 407 | for (i = 0; scsi_dh->devlist && scsi_dh->devlist[i].vendor; i++) { |
364 | scsi_dev_info_list_del_keyed(scsi_dh->devlist[i].vendor, | 408 | scsi_dev_info_list_del_keyed(scsi_dh->devlist[i].vendor, |
365 | scsi_dh->devlist[i].model, | 409 | scsi_dh->devlist[i].model, |
366 | SCSI_DEVINFO_DH); | 410 | SCSI_DEVINFO_DH); |
@@ -398,7 +442,15 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) | |||
398 | 442 | ||
399 | spin_lock_irqsave(q->queue_lock, flags); | 443 | spin_lock_irqsave(q->queue_lock, flags); |
400 | sdev = q->queuedata; | 444 | sdev = q->queuedata; |
401 | if (sdev && sdev->scsi_dh_data) | 445 | if (!sdev) { |
446 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
447 | err = SCSI_DH_NOSYS; | ||
448 | if (fn) | ||
449 | fn(data, err); | ||
450 | return err; | ||
451 | } | ||
452 | |||
453 | if (sdev->scsi_dh_data) | ||
402 | scsi_dh = sdev->scsi_dh_data->scsi_dh; | 454 | scsi_dh = sdev->scsi_dh_data->scsi_dh; |
403 | dev = get_device(&sdev->sdev_gendev); | 455 | dev = get_device(&sdev->sdev_gendev); |
404 | if (!scsi_dh || !dev || | 456 | if (!scsi_dh || !dev || |
@@ -468,7 +520,7 @@ int scsi_dh_handler_exist(const char *name) | |||
468 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); | 520 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); |
469 | 521 | ||
470 | /* | 522 | /* |
471 | * scsi_dh_handler_attach - Attach device handler | 523 | * scsi_dh_attach - Attach device handler |
472 | * @sdev - sdev the handler should be attached to | 524 | * @sdev - sdev the handler should be attached to |
473 | * @name - name of the handler to attach | 525 | * @name - name of the handler to attach |
474 | */ | 526 | */ |
@@ -498,7 +550,7 @@ int scsi_dh_attach(struct request_queue *q, const char *name) | |||
498 | EXPORT_SYMBOL_GPL(scsi_dh_attach); | 550 | EXPORT_SYMBOL_GPL(scsi_dh_attach); |
499 | 551 | ||
500 | /* | 552 | /* |
501 | * scsi_dh_handler_detach - Detach device handler | 553 | * scsi_dh_detach - Detach device handler |
502 | * @sdev - sdev the handler should be detached from | 554 | * @sdev - sdev the handler should be detached from |
503 | * | 555 | * |
504 | * This function will detach the device handler only | 556 | * This function will detach the device handler only |