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.c72
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 */
70static struct scsi_device_handler *
71device_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 */
93static struct scsi_device_handler *
94device_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 *
72device_handler_match(struct scsi_device_handler *scsi_dh, 113device_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)
468EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); 520EXPORT_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)
498EXPORT_SYMBOL_GPL(scsi_dh_attach); 550EXPORT_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