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