blob: 1dba62c5cf6a0b364df79805f5e8ee857ba36b46 [file] [log] [blame]
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -07001/*
2 * SCSI device handler infrastruture.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 * Copyright IBM Corporation, 2007
19 * Authors:
20 * Chandra Seetharaman <sekharan@us.ibm.com>
21 * Mike Anderson <andmike@linux.vnet.ibm.com>
22 */
23
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090024#include <linux/slab.h>
Paul Gortmakeracf3368f2011-05-27 09:47:43 -040025#include <linux/module.h>
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -070026#include <scsi/scsi_dh.h>
27#include "../scsi_priv.h"
28
29static DEFINE_SPINLOCK(list_lock);
30static LIST_HEAD(scsi_dh_list);
31
32static struct scsi_device_handler *get_device_handler(const char *name)
33{
34 struct scsi_device_handler *tmp, *found = NULL;
35
36 spin_lock(&list_lock);
37 list_for_each_entry(tmp, &scsi_dh_list, list) {
Hannes Reinecke765cbc62008-07-17 16:52:51 -070038 if (!strncmp(tmp->name, name, strlen(tmp->name))) {
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -070039 found = tmp;
40 break;
41 }
42 }
43 spin_unlock(&list_lock);
44 return found;
45}
46
Hannes Reinecke7c32c7a2008-07-17 16:53:33 -070047/*
Hannes Reinecke6c3633d2011-08-24 10:51:15 +020048 * device_handler_match_function - Match a device handler to a device
49 * @sdev - SCSI device to be tested
50 *
51 * Tests @sdev against the match function of all registered device_handler.
52 * Returns the found device handler or NULL if not found.
53 */
54static struct scsi_device_handler *
55device_handler_match_function(struct scsi_device *sdev)
56{
57 struct scsi_device_handler *tmp_dh, *found_dh = NULL;
58
59 spin_lock(&list_lock);
60 list_for_each_entry(tmp_dh, &scsi_dh_list, list) {
61 if (tmp_dh->match && tmp_dh->match(sdev)) {
62 found_dh = tmp_dh;
63 break;
64 }
65 }
66 spin_unlock(&list_lock);
67 return found_dh;
68}
69
70/*
Hannes Reinecke7c32c7a2008-07-17 16:53:33 -070071 * device_handler_match - Attach a device handler to a device
72 * @scsi_dh - The device handler to match against or NULL
73 * @sdev - SCSI device to be tested against @scsi_dh
74 *
75 * Tests @sdev against the device handler @scsi_dh or against
76 * all registered device_handler if @scsi_dh == NULL.
77 * Returns the found device handler or NULL if not found.
78 */
79static struct scsi_device_handler *
80device_handler_match(struct scsi_device_handler *scsi_dh,
81 struct scsi_device *sdev)
82{
Hannes Reinecke6c3633d2011-08-24 10:51:15 +020083 struct scsi_device_handler *found_dh;
Hannes Reinecke7c32c7a2008-07-17 16:53:33 -070084
Hannes Reinecke6c3633d2011-08-24 10:51:15 +020085 found_dh = device_handler_match_function(sdev);
Hannes Reinecke7c32c7a2008-07-17 16:53:33 -070086
Peter Jones940d7fa2011-01-06 15:38:24 -050087 if (scsi_dh && found_dh != scsi_dh)
88 found_dh = NULL;
Hannes Reinecke765cbc62008-07-17 16:52:51 -070089
Hannes Reinecke7c32c7a2008-07-17 16:53:33 -070090 return found_dh;
Hannes Reinecke765cbc62008-07-17 16:52:51 -070091}
92
93/*
94 * scsi_dh_handler_attach - Attach a device handler to a device
95 * @sdev - SCSI device the device handler should attach to
96 * @scsi_dh - The device handler to attach
97 */
98static int scsi_dh_handler_attach(struct scsi_device *sdev,
99 struct scsi_device_handler *scsi_dh)
100{
Christoph Hellwig1d520322014-09-14 11:08:21 -0700101 struct scsi_dh_data *d;
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700102
103 if (sdev->scsi_dh_data) {
104 if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
Christoph Hellwig27c888f2014-09-13 19:41:16 -0700105 return -EBUSY;
106
107 kref_get(&sdev->scsi_dh_data->kref);
108 return 0;
109 }
110
Christoph Hellwig1f12ffa2014-09-13 20:08:44 -0700111 if (!try_module_get(scsi_dh->module))
112 return -EINVAL;
Christoph Hellwig27c888f2014-09-13 19:41:16 -0700113
Christoph Hellwig1d520322014-09-14 11:08:21 -0700114 d = scsi_dh->attach(sdev);
115 if (IS_ERR(d)) {
116 sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%ld)\n",
117 scsi_dh->name, PTR_ERR(d));
Christoph Hellwig1f12ffa2014-09-13 20:08:44 -0700118 module_put(scsi_dh->module);
Christoph Hellwig1d520322014-09-14 11:08:21 -0700119 return PTR_ERR(d);
Chandra Seetharaman6c10db72009-06-26 19:30:06 -0700120 }
Christoph Hellwig1f12ffa2014-09-13 20:08:44 -0700121
Christoph Hellwig1d520322014-09-14 11:08:21 -0700122 d->scsi_dh = scsi_dh;
123 kref_init(&d->kref);
124 d->sdev = sdev;
125
126 spin_lock_irq(sdev->request_queue->queue_lock);
127 sdev->scsi_dh_data = d;
128 spin_unlock_irq(sdev->request_queue->queue_lock);
129 return 0;
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700130}
131
Chandra Seetharaman6c10db72009-06-26 19:30:06 -0700132static void __detach_handler (struct kref *kref)
133{
Christoph Hellwig27c888f2014-09-13 19:41:16 -0700134 struct scsi_dh_data *scsi_dh_data =
135 container_of(kref, struct scsi_dh_data, kref);
136 struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh;
Christoph Hellwig1d520322014-09-14 11:08:21 -0700137 struct scsi_device *sdev = scsi_dh_data->sdev;
Christoph Hellwig27c888f2014-09-13 19:41:16 -0700138
Christoph Hellwig1d520322014-09-14 11:08:21 -0700139 spin_lock_irq(sdev->request_queue->queue_lock);
140 sdev->scsi_dh_data = NULL;
141 spin_unlock_irq(sdev->request_queue->queue_lock);
142
143 scsi_dh->detach(sdev);
144 sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name);
Christoph Hellwig27c888f2014-09-13 19:41:16 -0700145 module_put(scsi_dh->module);
Chandra Seetharaman6c10db72009-06-26 19:30:06 -0700146}
147
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700148/*
149 * scsi_dh_handler_detach - Detach a device handler from a device
150 * @sdev - SCSI device the device handler should be detached from
151 * @scsi_dh - Device handler to be detached
152 *
153 * Detach from a device handler. If a device handler is specified,
Hannes Reinecke4c05ae52008-07-17 16:52:57 -0700154 * only detach if the currently attached handler matches @scsi_dh.
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700155 */
156static void scsi_dh_handler_detach(struct scsi_device *sdev,
157 struct scsi_device_handler *scsi_dh)
158{
159 if (!sdev->scsi_dh_data)
160 return;
161
162 if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh)
163 return;
164
165 if (!scsi_dh)
166 scsi_dh = sdev->scsi_dh_data->scsi_dh;
167
Christoph Hellwig1f12ffa2014-09-13 20:08:44 -0700168 if (scsi_dh)
Chandra Seetharaman6c10db72009-06-26 19:30:06 -0700169 kref_put(&sdev->scsi_dh_data->kref, __detach_handler);
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700170}
171
172/*
Hannes Reinecke4c05ae52008-07-17 16:52:57 -0700173 * Functions for sysfs attribute 'dh_state'
174 */
175static ssize_t
176store_dh_state(struct device *dev, struct device_attribute *attr,
177 const char *buf, size_t count)
178{
179 struct scsi_device *sdev = to_scsi_device(dev);
180 struct scsi_device_handler *scsi_dh;
181 int err = -EINVAL;
182
Hannes Reinecke6bc8d2a2011-08-24 10:51:17 +0200183 if (sdev->sdev_state == SDEV_CANCEL ||
184 sdev->sdev_state == SDEV_DEL)
185 return -ENODEV;
186
Hannes Reinecke4c05ae52008-07-17 16:52:57 -0700187 if (!sdev->scsi_dh_data) {
188 /*
189 * Attach to a device handler
190 */
191 if (!(scsi_dh = get_device_handler(buf)))
192 return err;
193 err = scsi_dh_handler_attach(sdev, scsi_dh);
194 } else {
195 scsi_dh = sdev->scsi_dh_data->scsi_dh;
196 if (!strncmp(buf, "detach", 6)) {
197 /*
198 * Detach from a device handler
199 */
200 scsi_dh_handler_detach(sdev, scsi_dh);
201 err = 0;
202 } else if (!strncmp(buf, "activate", 8)) {
203 /*
204 * Activate a device handler
205 */
206 if (scsi_dh->activate)
Chandra Seetharaman3ae31f62009-10-21 09:22:46 -0700207 err = scsi_dh->activate(sdev, NULL, NULL);
Hannes Reinecke4c05ae52008-07-17 16:52:57 -0700208 else
209 err = 0;
210 }
211 }
212
213 return err<0?err:count;
214}
215
216static ssize_t
217show_dh_state(struct device *dev, struct device_attribute *attr, char *buf)
218{
219 struct scsi_device *sdev = to_scsi_device(dev);
220
221 if (!sdev->scsi_dh_data)
222 return snprintf(buf, 20, "detached\n");
223
224 return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name);
225}
226
227static struct device_attribute scsi_dh_state_attr =
228 __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state,
229 store_dh_state);
230
231/*
232 * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh
233 */
234static int scsi_dh_sysfs_attr_add(struct device *dev, void *data)
235{
236 struct scsi_device *sdev;
237 int err;
238
239 if (!scsi_is_sdev_device(dev))
240 return 0;
241
242 sdev = to_scsi_device(dev);
243
244 err = device_create_file(&sdev->sdev_gendev,
245 &scsi_dh_state_attr);
246
247 return 0;
248}
249
250/*
251 * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh
252 */
253static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data)
254{
255 struct scsi_device *sdev;
256
257 if (!scsi_is_sdev_device(dev))
258 return 0;
259
260 sdev = to_scsi_device(dev);
261
262 device_remove_file(&sdev->sdev_gendev,
263 &scsi_dh_state_attr);
264
265 return 0;
266}
267
268/*
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700269 * scsi_dh_notifier - notifier chain callback
270 */
271static int scsi_dh_notifier(struct notifier_block *nb,
272 unsigned long action, void *data)
273{
274 struct device *dev = data;
275 struct scsi_device *sdev;
276 int err = 0;
Hannes Reinecke7c32c7a2008-07-17 16:53:33 -0700277 struct scsi_device_handler *devinfo = NULL;
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700278
279 if (!scsi_is_sdev_device(dev))
280 return 0;
281
282 sdev = to_scsi_device(dev);
283
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700284 if (action == BUS_NOTIFY_ADD_DEVICE) {
Chandra Seetharaman59172902009-09-11 10:20:35 -0700285 err = device_create_file(dev, &scsi_dh_state_attr);
286 /* don't care about err */
Hannes Reinecke7c32c7a2008-07-17 16:53:33 -0700287 devinfo = device_handler_match(NULL, sdev);
Chandra Seetharaman59172902009-09-11 10:20:35 -0700288 if (devinfo)
289 err = scsi_dh_handler_attach(sdev, devinfo);
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700290 } else if (action == BUS_NOTIFY_DEL_DEVICE) {
Hannes Reinecke4c05ae52008-07-17 16:52:57 -0700291 device_remove_file(dev, &scsi_dh_state_attr);
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700292 scsi_dh_handler_detach(sdev, NULL);
293 }
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700294 return err;
295}
296
297/*
298 * scsi_dh_notifier_add - Callback for scsi_register_device_handler
299 */
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700300static int scsi_dh_notifier_add(struct device *dev, void *data)
301{
302 struct scsi_device_handler *scsi_dh = data;
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700303 struct scsi_device *sdev;
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700304
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700305 if (!scsi_is_sdev_device(dev))
306 return 0;
307
308 if (!get_device(dev))
309 return 0;
310
311 sdev = to_scsi_device(dev);
312
313 if (device_handler_match(scsi_dh, sdev))
314 scsi_dh_handler_attach(sdev, scsi_dh);
315
316 put_device(dev);
317
318 return 0;
319}
320
321/*
322 * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler
323 */
324static int scsi_dh_notifier_remove(struct device *dev, void *data)
325{
326 struct scsi_device_handler *scsi_dh = data;
327 struct scsi_device *sdev;
328
329 if (!scsi_is_sdev_device(dev))
330 return 0;
331
332 if (!get_device(dev))
333 return 0;
334
335 sdev = to_scsi_device(dev);
336
337 scsi_dh_handler_detach(sdev, scsi_dh);
338
339 put_device(dev);
340
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700341 return 0;
342}
343
344/*
345 * scsi_register_device_handler - register a device handler personality
346 * module.
347 * @scsi_dh - device handler to be registered.
348 *
349 * Returns 0 on success, -EBUSY if handler already registered.
350 */
351int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
352{
Peter Jones940d7fa2011-01-06 15:38:24 -0500353
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700354 if (get_device_handler(scsi_dh->name))
355 return -EBUSY;
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700356
Christoph Hellwig1f12ffa2014-09-13 20:08:44 -0700357 if (!scsi_dh->attach || !scsi_dh->detach)
358 return -EINVAL;
359
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700360 spin_lock(&list_lock);
361 list_add(&scsi_dh->list, &scsi_dh_list);
362 spin_unlock(&list_lock);
Peter Jones940d7fa2011-01-06 15:38:24 -0500363
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700364 bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
365 printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700366
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700367 return SCSI_DH_OK;
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700368}
369EXPORT_SYMBOL_GPL(scsi_register_device_handler);
370
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700371/*
372 * scsi_unregister_device_handler - register a device handler personality
373 * module.
374 * @scsi_dh - device handler to be unregistered.
375 *
376 * Returns 0 on success, -ENODEV if handler not registered.
377 */
378int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
379{
Hannes Reinecke7c32c7a2008-07-17 16:53:33 -0700380
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700381 if (!get_device_handler(scsi_dh->name))
382 return -ENODEV;
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700383
384 bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700385 scsi_dh_notifier_remove);
386
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700387 spin_lock(&list_lock);
388 list_del(&scsi_dh->list);
389 spin_unlock(&list_lock);
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700390 printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700391
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700392 return SCSI_DH_OK;
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700393}
394EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
395
396/*
397 * scsi_dh_activate - activate the path associated with the scsi_device
398 * corresponding to the given request queue.
Chandra Seetharaman3ae31f62009-10-21 09:22:46 -0700399 * Returns immediately without waiting for activation to be completed.
400 * @q - Request queue that is associated with the scsi_device to be
401 * activated.
402 * @fn - Function to be called upon completion of the activation.
403 * Function fn is called with data (below) and the error code.
404 * Function fn may be called from the same calling context. So,
405 * do not hold the lock in the caller which may be needed in fn.
406 * @data - data passed to the function fn upon completion.
407 *
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700408 */
Chandra Seetharaman3ae31f62009-10-21 09:22:46 -0700409int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700410{
411 int err = 0;
412 unsigned long flags;
413 struct scsi_device *sdev;
414 struct scsi_device_handler *scsi_dh = NULL;
Mike Snitzer0b839352011-04-08 15:05:36 -0400415 struct device *dev = NULL;
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700416
417 spin_lock_irqsave(q->queue_lock, flags);
418 sdev = q->queuedata;
Moger, Babua18a9202011-10-26 14:29:38 -0400419 if (!sdev) {
420 spin_unlock_irqrestore(q->queue_lock, flags);
421 err = SCSI_DH_NOSYS;
422 if (fn)
423 fn(data, err);
424 return err;
425 }
426
427 if (sdev->scsi_dh_data)
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700428 scsi_dh = sdev->scsi_dh_data->scsi_dh;
Mike Snitzer0b839352011-04-08 15:05:36 -0400429 dev = get_device(&sdev->sdev_gendev);
430 if (!scsi_dh || !dev ||
Menny Hamburgerdb422312010-12-16 14:57:07 -0500431 sdev->sdev_state == SDEV_CANCEL ||
432 sdev->sdev_state == SDEV_DEL)
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700433 err = SCSI_DH_NOSYS;
Menny Hamburgerdb422312010-12-16 14:57:07 -0500434 if (sdev->sdev_state == SDEV_OFFLINE)
435 err = SCSI_DH_DEV_OFFLINED;
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700436 spin_unlock_irqrestore(q->queue_lock, flags);
437
Menny Hamburgerdb422312010-12-16 14:57:07 -0500438 if (err) {
439 if (fn)
440 fn(data, err);
Mike Snitzer0b839352011-04-08 15:05:36 -0400441 goto out;
Menny Hamburgerdb422312010-12-16 14:57:07 -0500442 }
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700443
444 if (scsi_dh->activate)
Chandra Seetharaman3ae31f62009-10-21 09:22:46 -0700445 err = scsi_dh->activate(sdev, fn, data);
Mike Snitzer0b839352011-04-08 15:05:36 -0400446out:
447 put_device(dev);
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700448 return err;
449}
450EXPORT_SYMBOL_GPL(scsi_dh_activate);
451
452/*
Chandra Seetharaman18ee70c2009-08-03 12:42:33 -0700453 * scsi_dh_set_params - set the parameters for the device as per the
454 * string specified in params.
455 * @q - Request queue that is associated with the scsi_device for
456 * which the parameters to be set.
457 * @params - parameters in the following format
458 * "no_of_params\0param1\0param2\0param3\0...\0"
459 * for example, string for 2 parameters with value 10 and 21
460 * is specified as "2\010\021\0".
461 */
462int scsi_dh_set_params(struct request_queue *q, const char *params)
463{
464 int err = -SCSI_DH_NOSYS;
465 unsigned long flags;
466 struct scsi_device *sdev;
467 struct scsi_device_handler *scsi_dh = NULL;
468
469 spin_lock_irqsave(q->queue_lock, flags);
470 sdev = q->queuedata;
471 if (sdev && sdev->scsi_dh_data)
472 scsi_dh = sdev->scsi_dh_data->scsi_dh;
473 if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev))
474 err = 0;
475 spin_unlock_irqrestore(q->queue_lock, flags);
476
477 if (err)
478 return err;
479 err = scsi_dh->set_params(sdev, params);
480 put_device(&sdev->sdev_gendev);
481 return err;
482}
483EXPORT_SYMBOL_GPL(scsi_dh_set_params);
484
485/*
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700486 * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for
487 * the given name. FALSE(0) otherwise.
488 * @name - name of the device handler.
489 */
490int scsi_dh_handler_exist(const char *name)
491{
492 return (get_device_handler(name) != NULL);
493}
494EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
495
Hannes Reineckeae11b1b2008-07-17 17:49:02 -0700496/*
Hannes Reinecke2a9ab402011-08-24 10:51:14 +0200497 * scsi_dh_attach - Attach device handler
Mike Snitzer7e8a74b2012-06-26 14:32:03 -0400498 * @q - Request queue that is associated with the scsi_device
499 * the handler should be attached to
Hannes Reineckeae11b1b2008-07-17 17:49:02 -0700500 * @name - name of the handler to attach
501 */
502int scsi_dh_attach(struct request_queue *q, const char *name)
503{
504 unsigned long flags;
505 struct scsi_device *sdev;
506 struct scsi_device_handler *scsi_dh;
507 int err = 0;
508
509 scsi_dh = get_device_handler(name);
510 if (!scsi_dh)
511 return -EINVAL;
512
513 spin_lock_irqsave(q->queue_lock, flags);
514 sdev = q->queuedata;
515 if (!sdev || !get_device(&sdev->sdev_gendev))
516 err = -ENODEV;
517 spin_unlock_irqrestore(q->queue_lock, flags);
518
519 if (!err) {
520 err = scsi_dh_handler_attach(sdev, scsi_dh);
Hannes Reineckeae11b1b2008-07-17 17:49:02 -0700521 put_device(&sdev->sdev_gendev);
522 }
523 return err;
524}
525EXPORT_SYMBOL_GPL(scsi_dh_attach);
526
527/*
Hannes Reinecke2a9ab402011-08-24 10:51:14 +0200528 * scsi_dh_detach - Detach device handler
Mike Snitzer7e8a74b2012-06-26 14:32:03 -0400529 * @q - Request queue that is associated with the scsi_device
530 * the handler should be detached from
Hannes Reineckeae11b1b2008-07-17 17:49:02 -0700531 *
532 * This function will detach the device handler only
533 * if the sdev is not part of the internal list, ie
534 * if it has been attached manually.
535 */
536void scsi_dh_detach(struct request_queue *q)
537{
538 unsigned long flags;
539 struct scsi_device *sdev;
540 struct scsi_device_handler *scsi_dh = NULL;
541
542 spin_lock_irqsave(q->queue_lock, flags);
543 sdev = q->queuedata;
544 if (!sdev || !get_device(&sdev->sdev_gendev))
545 sdev = NULL;
546 spin_unlock_irqrestore(q->queue_lock, flags);
547
548 if (!sdev)
549 return;
550
551 if (sdev->scsi_dh_data) {
Hannes Reineckeae11b1b2008-07-17 17:49:02 -0700552 scsi_dh = sdev->scsi_dh_data->scsi_dh;
Chandra Seetharaman6c10db72009-06-26 19:30:06 -0700553 scsi_dh_handler_detach(sdev, scsi_dh);
Hannes Reineckeae11b1b2008-07-17 17:49:02 -0700554 }
555 put_device(&sdev->sdev_gendev);
556}
557EXPORT_SYMBOL_GPL(scsi_dh_detach);
558
Mike Snitzer7e8a74b2012-06-26 14:32:03 -0400559/*
560 * scsi_dh_attached_handler_name - Get attached device handler's name
561 * @q - Request queue that is associated with the scsi_device
562 * that may have a device handler attached
563 * @gfp - the GFP mask used in the kmalloc() call when allocating memory
564 *
565 * Returns name of attached handler, NULL if no handler is attached.
566 * Caller must take care to free the returned string.
567 */
568const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
569{
570 unsigned long flags;
571 struct scsi_device *sdev;
572 const char *handler_name = NULL;
573
574 spin_lock_irqsave(q->queue_lock, flags);
575 sdev = q->queuedata;
576 if (!sdev || !get_device(&sdev->sdev_gendev))
577 sdev = NULL;
578 spin_unlock_irqrestore(q->queue_lock, flags);
579
580 if (!sdev)
581 return NULL;
582
583 if (sdev->scsi_dh_data)
584 handler_name = kstrdup(sdev->scsi_dh_data->scsi_dh->name, gfp);
585
586 put_device(&sdev->sdev_gendev);
587 return handler_name;
588}
589EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);
590
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700591static struct notifier_block scsi_dh_nb = {
592 .notifier_call = scsi_dh_notifier
593};
594
595static int __init scsi_dh_init(void)
596{
597 int r;
598
599 r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);
600
Hannes Reinecke4c05ae52008-07-17 16:52:57 -0700601 if (!r)
602 bus_for_each_dev(&scsi_bus_type, NULL, NULL,
603 scsi_dh_sysfs_attr_add);
604
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700605 return r;
606}
607
608static void __exit scsi_dh_exit(void)
609{
Hannes Reinecke4c05ae52008-07-17 16:52:57 -0700610 bus_for_each_dev(&scsi_bus_type, NULL, NULL,
611 scsi_dh_sysfs_attr_remove);
Hannes Reinecke765cbc62008-07-17 16:52:51 -0700612 bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
613}
614
615module_init(scsi_dh_init);
616module_exit(scsi_dh_exit);
617
Chandra Seetharamana6a8d9f2008-05-01 14:49:46 -0700618MODULE_DESCRIPTION("SCSI device handler");
619MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
620MODULE_LICENSE("GPL");