xref: /openbmc/linux/drivers/scsi/scsi_dh.c (revision ae98ddf0)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2daaa858bSChristoph Hellwig /*
3*ae98ddf0SBhaskar Chowdhury  * SCSI device handler infrastructure.
4daaa858bSChristoph Hellwig  *
5daaa858bSChristoph Hellwig  * Copyright IBM Corporation, 2007
6daaa858bSChristoph Hellwig  *      Authors:
7daaa858bSChristoph Hellwig  *               Chandra Seetharaman <sekharan@us.ibm.com>
8daaa858bSChristoph Hellwig  *               Mike Anderson <andmike@linux.vnet.ibm.com>
9daaa858bSChristoph Hellwig  */
10daaa858bSChristoph Hellwig 
11daaa858bSChristoph Hellwig #include <linux/slab.h>
12daaa858bSChristoph Hellwig #include <linux/module.h>
13daaa858bSChristoph Hellwig #include <scsi/scsi_dh.h>
14daaa858bSChristoph Hellwig #include "scsi_priv.h"
15daaa858bSChristoph Hellwig 
16daaa858bSChristoph Hellwig static DEFINE_SPINLOCK(list_lock);
17daaa858bSChristoph Hellwig static LIST_HEAD(scsi_dh_list);
18daaa858bSChristoph Hellwig 
19d95dbff2SChristoph Hellwig struct scsi_dh_blist {
20d95dbff2SChristoph Hellwig 	const char *vendor;
21d95dbff2SChristoph Hellwig 	const char *model;
22d95dbff2SChristoph Hellwig 	const char *driver;
23d95dbff2SChristoph Hellwig };
24d95dbff2SChristoph Hellwig 
25d95dbff2SChristoph Hellwig static const struct scsi_dh_blist scsi_dh_blist[] = {
260ba43a81SXose Vazquez Perez 	{"DGC", "RAID",			"emc" },
270ba43a81SXose Vazquez Perez 	{"DGC", "DISK",			"emc" },
280ba43a81SXose Vazquez Perez 	{"DGC", "VRAID",		"emc" },
29d95dbff2SChristoph Hellwig 
30d95dbff2SChristoph Hellwig 	{"COMPAQ", "MSA1000 VOLUME",	"hp_sw" },
31d95dbff2SChristoph Hellwig 	{"COMPAQ", "HSV110",		"hp_sw" },
32d95dbff2SChristoph Hellwig 	{"HP", "HSV100",		"hp_sw"},
33d95dbff2SChristoph Hellwig 	{"DEC", "HSG80",		"hp_sw"},
34d95dbff2SChristoph Hellwig 
35d95dbff2SChristoph Hellwig 	{"IBM", "1722",			"rdac", },
36d95dbff2SChristoph Hellwig 	{"IBM", "1724",			"rdac", },
37d95dbff2SChristoph Hellwig 	{"IBM", "1726",			"rdac", },
38d95dbff2SChristoph Hellwig 	{"IBM", "1742",			"rdac", },
39d95dbff2SChristoph Hellwig 	{"IBM", "1745",			"rdac", },
40d95dbff2SChristoph Hellwig 	{"IBM", "1746",			"rdac", },
41d95dbff2SChristoph Hellwig 	{"IBM", "1813",			"rdac", },
42d95dbff2SChristoph Hellwig 	{"IBM", "1814",			"rdac", },
43d95dbff2SChristoph Hellwig 	{"IBM", "1815",			"rdac", },
44d95dbff2SChristoph Hellwig 	{"IBM", "1818",			"rdac", },
45d95dbff2SChristoph Hellwig 	{"IBM", "3526",			"rdac", },
464b3aec2bSXose Vazquez Perez 	{"IBM", "3542",			"rdac", },
474b3aec2bSXose Vazquez Perez 	{"IBM", "3552",			"rdac", },
4837b37d26SXose Vazquez Perez 	{"SGI", "TP9300",		"rdac", },
4937b37d26SXose Vazquez Perez 	{"SGI", "TP9400",		"rdac", },
5037b37d26SXose Vazquez Perez 	{"SGI", "TP9500",		"rdac", },
5137b37d26SXose Vazquez Perez 	{"SGI", "TP9700",		"rdac", },
52d95dbff2SChristoph Hellwig 	{"SGI", "IS",			"rdac", },
534b3aec2bSXose Vazquez Perez 	{"STK", "OPENstorage",		"rdac", },
54d95dbff2SChristoph Hellwig 	{"STK", "FLEXLINE 380",		"rdac", },
554b3aec2bSXose Vazquez Perez 	{"STK", "BladeCtlr",		"rdac", },
56d95dbff2SChristoph Hellwig 	{"SUN", "CSM",			"rdac", },
57d95dbff2SChristoph Hellwig 	{"SUN", "LCSM100",		"rdac", },
58d95dbff2SChristoph Hellwig 	{"SUN", "STK6580_6780",		"rdac", },
59d95dbff2SChristoph Hellwig 	{"SUN", "SUN_6180",		"rdac", },
60d95dbff2SChristoph Hellwig 	{"SUN", "ArrayStorage",		"rdac", },
61d95dbff2SChristoph Hellwig 	{"DELL", "MD3",			"rdac", },
62d95dbff2SChristoph Hellwig 	{"NETAPP", "INF-01-00",		"rdac", },
63d95dbff2SChristoph Hellwig 	{"LSI", "INF-01-00",		"rdac", },
64d95dbff2SChristoph Hellwig 	{"ENGENIO", "INF-01-00",	"rdac", },
651cb1d2c6SXose Vazquez Perez 	{"LENOVO", "DE_Series",		"rdac", },
66e094fd34SSteve Schremmer 	{"FUJITSU", "ETERNUS_AHB",	"rdac", },
67d95dbff2SChristoph Hellwig 	{NULL, NULL,			NULL },
68d95dbff2SChristoph Hellwig };
69d95dbff2SChristoph Hellwig 
70d95dbff2SChristoph Hellwig static const char *
scsi_dh_find_driver(struct scsi_device * sdev)71d95dbff2SChristoph Hellwig scsi_dh_find_driver(struct scsi_device *sdev)
72d95dbff2SChristoph Hellwig {
73d95dbff2SChristoph Hellwig 	const struct scsi_dh_blist *b;
74d95dbff2SChristoph Hellwig 
75d95dbff2SChristoph Hellwig 	if (scsi_device_tpgs(sdev))
76d95dbff2SChristoph Hellwig 		return "alua";
77d95dbff2SChristoph Hellwig 
78d95dbff2SChristoph Hellwig 	for (b = scsi_dh_blist; b->vendor; b++) {
79d95dbff2SChristoph Hellwig 		if (!strncmp(sdev->vendor, b->vendor, strlen(b->vendor)) &&
80d95dbff2SChristoph Hellwig 		    !strncmp(sdev->model, b->model, strlen(b->model))) {
81d95dbff2SChristoph Hellwig 			return b->driver;
82d95dbff2SChristoph Hellwig 		}
83d95dbff2SChristoph Hellwig 	}
84d95dbff2SChristoph Hellwig 	return NULL;
85d95dbff2SChristoph Hellwig }
86d95dbff2SChristoph Hellwig 
87d95dbff2SChristoph Hellwig 
__scsi_dh_lookup(const char * name)88daaa858bSChristoph Hellwig static struct scsi_device_handler *__scsi_dh_lookup(const char *name)
89daaa858bSChristoph Hellwig {
90daaa858bSChristoph Hellwig 	struct scsi_device_handler *tmp, *found = NULL;
91daaa858bSChristoph Hellwig 
92daaa858bSChristoph Hellwig 	spin_lock(&list_lock);
93daaa858bSChristoph Hellwig 	list_for_each_entry(tmp, &scsi_dh_list, list) {
94daaa858bSChristoph Hellwig 		if (!strncmp(tmp->name, name, strlen(tmp->name))) {
95daaa858bSChristoph Hellwig 			found = tmp;
96daaa858bSChristoph Hellwig 			break;
97daaa858bSChristoph Hellwig 		}
98daaa858bSChristoph Hellwig 	}
99daaa858bSChristoph Hellwig 	spin_unlock(&list_lock);
100daaa858bSChristoph Hellwig 	return found;
101daaa858bSChristoph Hellwig }
102daaa858bSChristoph Hellwig 
scsi_dh_lookup(const char * name)103daaa858bSChristoph Hellwig static struct scsi_device_handler *scsi_dh_lookup(const char *name)
104daaa858bSChristoph Hellwig {
105daaa858bSChristoph Hellwig 	struct scsi_device_handler *dh;
106daaa858bSChristoph Hellwig 
1072ee5671eSJohannes Thumshirn 	if (!name || strlen(name) == 0)
1082ee5671eSJohannes Thumshirn 		return NULL;
1092ee5671eSJohannes Thumshirn 
110daaa858bSChristoph Hellwig 	dh = __scsi_dh_lookup(name);
111daaa858bSChristoph Hellwig 	if (!dh) {
1121378889cSPaul Mackerras 		request_module("scsi_dh_%s", name);
113daaa858bSChristoph Hellwig 		dh = __scsi_dh_lookup(name);
114daaa858bSChristoph Hellwig 	}
115daaa858bSChristoph Hellwig 
116daaa858bSChristoph Hellwig 	return dh;
117daaa858bSChristoph Hellwig }
118daaa858bSChristoph Hellwig 
119daaa858bSChristoph Hellwig /*
120daaa858bSChristoph Hellwig  * scsi_dh_handler_attach - Attach a device handler to a device
121daaa858bSChristoph Hellwig  * @sdev - SCSI device the device handler should attach to
122daaa858bSChristoph Hellwig  * @scsi_dh - The device handler to attach
123daaa858bSChristoph Hellwig  */
scsi_dh_handler_attach(struct scsi_device * sdev,struct scsi_device_handler * scsi_dh)124daaa858bSChristoph Hellwig static int scsi_dh_handler_attach(struct scsi_device *sdev,
125daaa858bSChristoph Hellwig 				  struct scsi_device_handler *scsi_dh)
126daaa858bSChristoph Hellwig {
1272a8f7a03SHannes Reinecke 	int error, ret = 0;
128daaa858bSChristoph Hellwig 
129daaa858bSChristoph Hellwig 	if (!try_module_get(scsi_dh->module))
130daaa858bSChristoph Hellwig 		return -EINVAL;
131daaa858bSChristoph Hellwig 
132ee14c674SChristoph Hellwig 	error = scsi_dh->attach(sdev);
1332a8f7a03SHannes Reinecke 	if (error != SCSI_DH_OK) {
1342a8f7a03SHannes Reinecke 		switch (error) {
1352a8f7a03SHannes Reinecke 		case SCSI_DH_NOMEM:
1362a8f7a03SHannes Reinecke 			ret = -ENOMEM;
1372a8f7a03SHannes Reinecke 			break;
1382a8f7a03SHannes Reinecke 		case SCSI_DH_RES_TEMP_UNAVAIL:
1392a8f7a03SHannes Reinecke 			ret = -EAGAIN;
1402a8f7a03SHannes Reinecke 			break;
1412930f817SHannes Reinecke 		case SCSI_DH_DEV_UNSUPP:
1422930f817SHannes Reinecke 		case SCSI_DH_NOSYS:
1432930f817SHannes Reinecke 			ret = -ENODEV;
1442930f817SHannes Reinecke 			break;
1452a8f7a03SHannes Reinecke 		default:
1462a8f7a03SHannes Reinecke 			ret = -EINVAL;
1472a8f7a03SHannes Reinecke 			break;
1482a8f7a03SHannes Reinecke 		}
1492930f817SHannes Reinecke 		if (ret != -ENODEV)
150ee14c674SChristoph Hellwig 			sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%d)\n",
151ee14c674SChristoph Hellwig 				    scsi_dh->name, error);
152daaa858bSChristoph Hellwig 		module_put(scsi_dh->module);
153ee14c674SChristoph Hellwig 	} else
154ee14c674SChristoph Hellwig 		sdev->handler = scsi_dh;
155daaa858bSChristoph Hellwig 
1562a8f7a03SHannes Reinecke 	return ret;
157daaa858bSChristoph Hellwig }
158daaa858bSChristoph Hellwig 
159daaa858bSChristoph Hellwig /*
160daaa858bSChristoph Hellwig  * scsi_dh_handler_detach - Detach a device handler from a device
161daaa858bSChristoph Hellwig  * @sdev - SCSI device the device handler should be detached from
162daaa858bSChristoph Hellwig  */
scsi_dh_handler_detach(struct scsi_device * sdev)163daaa858bSChristoph Hellwig static void scsi_dh_handler_detach(struct scsi_device *sdev)
164daaa858bSChristoph Hellwig {
165ee14c674SChristoph Hellwig 	sdev->handler->detach(sdev);
166ee14c674SChristoph Hellwig 	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", sdev->handler->name);
167ee14c674SChristoph Hellwig 	module_put(sdev->handler->module);
168daaa858bSChristoph Hellwig }
169daaa858bSChristoph Hellwig 
scsi_dh_add_device(struct scsi_device * sdev)1702930f817SHannes Reinecke void scsi_dh_add_device(struct scsi_device *sdev)
171daaa858bSChristoph Hellwig {
172d95dbff2SChristoph Hellwig 	struct scsi_device_handler *devinfo = NULL;
173d95dbff2SChristoph Hellwig 	const char *drv;
174daaa858bSChristoph Hellwig 
175d95dbff2SChristoph Hellwig 	drv = scsi_dh_find_driver(sdev);
176d95dbff2SChristoph Hellwig 	if (drv)
177d6a32b98SChristoph Hellwig 		devinfo = __scsi_dh_lookup(drv);
1782930f817SHannes Reinecke 	/*
1792930f817SHannes Reinecke 	 * device_handler is optional, so ignore errors
1802930f817SHannes Reinecke 	 * from scsi_dh_handler_attach()
1812930f817SHannes Reinecke 	 */
182daaa858bSChristoph Hellwig 	if (devinfo)
1832930f817SHannes Reinecke 		(void)scsi_dh_handler_attach(sdev, devinfo);
184daaa858bSChristoph Hellwig }
185daaa858bSChristoph Hellwig 
scsi_dh_release_device(struct scsi_device * sdev)18623695e41SJunichi Nomura void scsi_dh_release_device(struct scsi_device *sdev)
187daaa858bSChristoph Hellwig {
188ee14c674SChristoph Hellwig 	if (sdev->handler)
189daaa858bSChristoph Hellwig 		scsi_dh_handler_detach(sdev);
19023695e41SJunichi Nomura }
19123695e41SJunichi Nomura 
192daaa858bSChristoph Hellwig /*
193daaa858bSChristoph Hellwig  * scsi_register_device_handler - register a device handler personality
194daaa858bSChristoph Hellwig  *      module.
195daaa858bSChristoph Hellwig  * @scsi_dh - device handler to be registered.
196daaa858bSChristoph Hellwig  *
197daaa858bSChristoph Hellwig  * Returns 0 on success, -EBUSY if handler already registered.
198daaa858bSChristoph Hellwig  */
scsi_register_device_handler(struct scsi_device_handler * scsi_dh)199daaa858bSChristoph Hellwig int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
200daaa858bSChristoph Hellwig {
201daaa858bSChristoph Hellwig 	if (__scsi_dh_lookup(scsi_dh->name))
202daaa858bSChristoph Hellwig 		return -EBUSY;
203daaa858bSChristoph Hellwig 
204daaa858bSChristoph Hellwig 	if (!scsi_dh->attach || !scsi_dh->detach)
205daaa858bSChristoph Hellwig 		return -EINVAL;
206daaa858bSChristoph Hellwig 
207daaa858bSChristoph Hellwig 	spin_lock(&list_lock);
208daaa858bSChristoph Hellwig 	list_add(&scsi_dh->list, &scsi_dh_list);
209daaa858bSChristoph Hellwig 	spin_unlock(&list_lock);
210daaa858bSChristoph Hellwig 
211daaa858bSChristoph Hellwig 	printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
212daaa858bSChristoph Hellwig 
213daaa858bSChristoph Hellwig 	return SCSI_DH_OK;
214daaa858bSChristoph Hellwig }
215daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_register_device_handler);
216daaa858bSChristoph Hellwig 
217daaa858bSChristoph Hellwig /*
218daaa858bSChristoph Hellwig  * scsi_unregister_device_handler - register a device handler personality
219daaa858bSChristoph Hellwig  *      module.
220daaa858bSChristoph Hellwig  * @scsi_dh - device handler to be unregistered.
221daaa858bSChristoph Hellwig  *
222daaa858bSChristoph Hellwig  * Returns 0 on success, -ENODEV if handler not registered.
223daaa858bSChristoph Hellwig  */
scsi_unregister_device_handler(struct scsi_device_handler * scsi_dh)224daaa858bSChristoph Hellwig int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
225daaa858bSChristoph Hellwig {
226daaa858bSChristoph Hellwig 	if (!__scsi_dh_lookup(scsi_dh->name))
227daaa858bSChristoph Hellwig 		return -ENODEV;
228daaa858bSChristoph Hellwig 
229daaa858bSChristoph Hellwig 	spin_lock(&list_lock);
230daaa858bSChristoph Hellwig 	list_del(&scsi_dh->list);
231daaa858bSChristoph Hellwig 	spin_unlock(&list_lock);
232daaa858bSChristoph Hellwig 	printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
233daaa858bSChristoph Hellwig 
234daaa858bSChristoph Hellwig 	return SCSI_DH_OK;
235daaa858bSChristoph Hellwig }
236daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
237daaa858bSChristoph Hellwig 
238daaa858bSChristoph Hellwig /*
239daaa858bSChristoph Hellwig  * scsi_dh_activate - activate the path associated with the scsi_device
240daaa858bSChristoph Hellwig  *      corresponding to the given request queue.
241daaa858bSChristoph Hellwig  *     Returns immediately without waiting for activation to be completed.
242daaa858bSChristoph Hellwig  * @q    - Request queue that is associated with the scsi_device to be
243daaa858bSChristoph Hellwig  *         activated.
244daaa858bSChristoph Hellwig  * @fn   - Function to be called upon completion of the activation.
245daaa858bSChristoph Hellwig  *         Function fn is called with data (below) and the error code.
246daaa858bSChristoph Hellwig  *         Function fn may be called from the same calling context. So,
247daaa858bSChristoph Hellwig  *         do not hold the lock in the caller which may be needed in fn.
248daaa858bSChristoph Hellwig  * @data - data passed to the function fn upon completion.
249daaa858bSChristoph Hellwig  *
250daaa858bSChristoph Hellwig  */
scsi_dh_activate(struct request_queue * q,activate_complete fn,void * data)251daaa858bSChristoph Hellwig int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
252daaa858bSChristoph Hellwig {
253daaa858bSChristoph Hellwig 	struct scsi_device *sdev;
254e959ed9aSChristoph Hellwig 	int err = SCSI_DH_NOSYS;
255daaa858bSChristoph Hellwig 
256857de6e0SHannes Reinecke 	sdev = scsi_device_from_queue(q);
257daaa858bSChristoph Hellwig 	if (!sdev) {
258daaa858bSChristoph Hellwig 		if (fn)
259daaa858bSChristoph Hellwig 			fn(data, err);
260daaa858bSChristoph Hellwig 		return err;
261daaa858bSChristoph Hellwig 	}
262daaa858bSChristoph Hellwig 
263e959ed9aSChristoph Hellwig 	if (!sdev->handler)
264e959ed9aSChristoph Hellwig 		goto out_fn;
265710105fdSHannes Reinecke 	err = SCSI_DH_NOTCONN;
266e959ed9aSChristoph Hellwig 	if (sdev->sdev_state == SDEV_CANCEL ||
267daaa858bSChristoph Hellwig 	    sdev->sdev_state == SDEV_DEL)
268e959ed9aSChristoph Hellwig 		goto out_fn;
269daaa858bSChristoph Hellwig 
270e959ed9aSChristoph Hellwig 	err = SCSI_DH_DEV_OFFLINED;
271e959ed9aSChristoph Hellwig 	if (sdev->sdev_state == SDEV_OFFLINE)
272e959ed9aSChristoph Hellwig 		goto out_fn;
273daaa858bSChristoph Hellwig 
274ee14c674SChristoph Hellwig 	if (sdev->handler->activate)
275ee14c674SChristoph Hellwig 		err = sdev->handler->activate(sdev, fn, data);
276e959ed9aSChristoph Hellwig 
277e959ed9aSChristoph Hellwig out_put_device:
278e959ed9aSChristoph Hellwig 	put_device(&sdev->sdev_gendev);
279daaa858bSChristoph Hellwig 	return err;
280e959ed9aSChristoph Hellwig 
281e959ed9aSChristoph Hellwig out_fn:
282e959ed9aSChristoph Hellwig 	if (fn)
283e959ed9aSChristoph Hellwig 		fn(data, err);
284e959ed9aSChristoph Hellwig 	goto out_put_device;
285daaa858bSChristoph Hellwig }
286daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_activate);
287daaa858bSChristoph Hellwig 
288daaa858bSChristoph Hellwig /*
289daaa858bSChristoph Hellwig  * scsi_dh_set_params - set the parameters for the device as per the
290daaa858bSChristoph Hellwig  *      string specified in params.
291daaa858bSChristoph Hellwig  * @q - Request queue that is associated with the scsi_device for
292daaa858bSChristoph Hellwig  *      which the parameters to be set.
293daaa858bSChristoph Hellwig  * @params - parameters in the following format
294daaa858bSChristoph Hellwig  *      "no_of_params\0param1\0param2\0param3\0...\0"
295daaa858bSChristoph Hellwig  *      for example, string for 2 parameters with value 10 and 21
296daaa858bSChristoph Hellwig  *      is specified as "2\010\021\0".
297daaa858bSChristoph Hellwig  */
scsi_dh_set_params(struct request_queue * q,const char * params)298daaa858bSChristoph Hellwig int scsi_dh_set_params(struct request_queue *q, const char *params)
299daaa858bSChristoph Hellwig {
300daaa858bSChristoph Hellwig 	struct scsi_device *sdev;
301e959ed9aSChristoph Hellwig 	int err = -SCSI_DH_NOSYS;
302daaa858bSChristoph Hellwig 
303857de6e0SHannes Reinecke 	sdev = scsi_device_from_queue(q);
304e959ed9aSChristoph Hellwig 	if (!sdev)
305daaa858bSChristoph Hellwig 		return err;
306e959ed9aSChristoph Hellwig 
307e959ed9aSChristoph Hellwig 	if (sdev->handler && sdev->handler->set_params)
308ee14c674SChristoph Hellwig 		err = sdev->handler->set_params(sdev, params);
309daaa858bSChristoph Hellwig 	put_device(&sdev->sdev_gendev);
310daaa858bSChristoph Hellwig 	return err;
311daaa858bSChristoph Hellwig }
312daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_set_params);
313daaa858bSChristoph Hellwig 
314daaa858bSChristoph Hellwig /*
315daaa858bSChristoph Hellwig  * scsi_dh_attach - Attach device handler
316daaa858bSChristoph Hellwig  * @q - Request queue that is associated with the scsi_device
317daaa858bSChristoph Hellwig  *      the handler should be attached to
318daaa858bSChristoph Hellwig  * @name - name of the handler to attach
319daaa858bSChristoph Hellwig  */
scsi_dh_attach(struct request_queue * q,const char * name)320daaa858bSChristoph Hellwig int scsi_dh_attach(struct request_queue *q, const char *name)
321daaa858bSChristoph Hellwig {
322daaa858bSChristoph Hellwig 	struct scsi_device *sdev;
323daaa858bSChristoph Hellwig 	struct scsi_device_handler *scsi_dh;
324daaa858bSChristoph Hellwig 	int err = 0;
325daaa858bSChristoph Hellwig 
326857de6e0SHannes Reinecke 	sdev = scsi_device_from_queue(q);
327e959ed9aSChristoph Hellwig 	if (!sdev)
328e959ed9aSChristoph Hellwig 		return -ENODEV;
329e959ed9aSChristoph Hellwig 
330daaa858bSChristoph Hellwig 	scsi_dh = scsi_dh_lookup(name);
331e959ed9aSChristoph Hellwig 	if (!scsi_dh) {
332e959ed9aSChristoph Hellwig 		err = -EINVAL;
333e959ed9aSChristoph Hellwig 		goto out_put_device;
334e959ed9aSChristoph Hellwig 	}
335daaa858bSChristoph Hellwig 
336ee14c674SChristoph Hellwig 	if (sdev->handler) {
337ee14c674SChristoph Hellwig 		if (sdev->handler != scsi_dh)
338daaa858bSChristoph Hellwig 			err = -EBUSY;
339daaa858bSChristoph Hellwig 		goto out_put_device;
340daaa858bSChristoph Hellwig 	}
341daaa858bSChristoph Hellwig 
342daaa858bSChristoph Hellwig 	err = scsi_dh_handler_attach(sdev, scsi_dh);
343daaa858bSChristoph Hellwig 
344daaa858bSChristoph Hellwig out_put_device:
345daaa858bSChristoph Hellwig 	put_device(&sdev->sdev_gendev);
346daaa858bSChristoph Hellwig 	return err;
347daaa858bSChristoph Hellwig }
348daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_attach);
349daaa858bSChristoph Hellwig 
350daaa858bSChristoph Hellwig /*
351daaa858bSChristoph Hellwig  * scsi_dh_attached_handler_name - Get attached device handler's name
352daaa858bSChristoph Hellwig  * @q - Request queue that is associated with the scsi_device
353daaa858bSChristoph Hellwig  *      that may have a device handler attached
354daaa858bSChristoph Hellwig  * @gfp - the GFP mask used in the kmalloc() call when allocating memory
355daaa858bSChristoph Hellwig  *
356daaa858bSChristoph Hellwig  * Returns name of attached handler, NULL if no handler is attached.
357daaa858bSChristoph Hellwig  * Caller must take care to free the returned string.
358daaa858bSChristoph Hellwig  */
scsi_dh_attached_handler_name(struct request_queue * q,gfp_t gfp)359daaa858bSChristoph Hellwig const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
360daaa858bSChristoph Hellwig {
361daaa858bSChristoph Hellwig 	struct scsi_device *sdev;
362daaa858bSChristoph Hellwig 	const char *handler_name = NULL;
363daaa858bSChristoph Hellwig 
364857de6e0SHannes Reinecke 	sdev = scsi_device_from_queue(q);
365daaa858bSChristoph Hellwig 	if (!sdev)
366daaa858bSChristoph Hellwig 		return NULL;
367daaa858bSChristoph Hellwig 
368ee14c674SChristoph Hellwig 	if (sdev->handler)
369ee14c674SChristoph Hellwig 		handler_name = kstrdup(sdev->handler->name, gfp);
370daaa858bSChristoph Hellwig 	put_device(&sdev->sdev_gendev);
371daaa858bSChristoph Hellwig 	return handler_name;
372daaa858bSChristoph Hellwig }
373daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);
374