xref: /openbmc/linux/drivers/scsi/scsi_dh.c (revision d9fd5a71)
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 	{"FUJITSU", "ETERNUS_AHB",	"rdac", },
67 	{NULL, NULL,			NULL },
68 };
69 
70 static const char *
71 scsi_dh_find_driver(struct scsi_device *sdev)
72 {
73 	const struct scsi_dh_blist *b;
74 
75 	if (scsi_device_tpgs(sdev))
76 		return "alua";
77 
78 	for (b = scsi_dh_blist; b->vendor; b++) {
79 		if (!strncmp(sdev->vendor, b->vendor, strlen(b->vendor)) &&
80 		    !strncmp(sdev->model, b->model, strlen(b->model))) {
81 			return b->driver;
82 		}
83 	}
84 	return NULL;
85 }
86 
87 
88 static struct scsi_device_handler *__scsi_dh_lookup(const char *name)
89 {
90 	struct scsi_device_handler *tmp, *found = NULL;
91 
92 	spin_lock(&list_lock);
93 	list_for_each_entry(tmp, &scsi_dh_list, list) {
94 		if (!strncmp(tmp->name, name, strlen(tmp->name))) {
95 			found = tmp;
96 			break;
97 		}
98 	}
99 	spin_unlock(&list_lock);
100 	return found;
101 }
102 
103 static struct scsi_device_handler *scsi_dh_lookup(const char *name)
104 {
105 	struct scsi_device_handler *dh;
106 
107 	if (!name || strlen(name) == 0)
108 		return NULL;
109 
110 	dh = __scsi_dh_lookup(name);
111 	if (!dh) {
112 		request_module("scsi_dh_%s", name);
113 		dh = __scsi_dh_lookup(name);
114 	}
115 
116 	return dh;
117 }
118 
119 /*
120  * scsi_dh_handler_attach - Attach a device handler to a device
121  * @sdev - SCSI device the device handler should attach to
122  * @scsi_dh - The device handler to attach
123  */
124 static int scsi_dh_handler_attach(struct scsi_device *sdev,
125 				  struct scsi_device_handler *scsi_dh)
126 {
127 	int error, ret = 0;
128 
129 	if (!try_module_get(scsi_dh->module))
130 		return -EINVAL;
131 
132 	error = scsi_dh->attach(sdev);
133 	if (error != SCSI_DH_OK) {
134 		switch (error) {
135 		case SCSI_DH_NOMEM:
136 			ret = -ENOMEM;
137 			break;
138 		case SCSI_DH_RES_TEMP_UNAVAIL:
139 			ret = -EAGAIN;
140 			break;
141 		case SCSI_DH_DEV_UNSUPP:
142 		case SCSI_DH_NOSYS:
143 			ret = -ENODEV;
144 			break;
145 		default:
146 			ret = -EINVAL;
147 			break;
148 		}
149 		if (ret != -ENODEV)
150 			sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%d)\n",
151 				    scsi_dh->name, error);
152 		module_put(scsi_dh->module);
153 	} else
154 		sdev->handler = scsi_dh;
155 
156 	return ret;
157 }
158 
159 /*
160  * scsi_dh_handler_detach - Detach a device handler from a device
161  * @sdev - SCSI device the device handler should be detached from
162  */
163 static void scsi_dh_handler_detach(struct scsi_device *sdev)
164 {
165 	sdev->handler->detach(sdev);
166 	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", sdev->handler->name);
167 	module_put(sdev->handler->module);
168 }
169 
170 void scsi_dh_add_device(struct scsi_device *sdev)
171 {
172 	struct scsi_device_handler *devinfo = NULL;
173 	const char *drv;
174 
175 	drv = scsi_dh_find_driver(sdev);
176 	if (drv)
177 		devinfo = __scsi_dh_lookup(drv);
178 	/*
179 	 * device_handler is optional, so ignore errors
180 	 * from scsi_dh_handler_attach()
181 	 */
182 	if (devinfo)
183 		(void)scsi_dh_handler_attach(sdev, devinfo);
184 }
185 
186 void scsi_dh_release_device(struct scsi_device *sdev)
187 {
188 	if (sdev->handler)
189 		scsi_dh_handler_detach(sdev);
190 }
191 
192 /*
193  * scsi_register_device_handler - register a device handler personality
194  *      module.
195  * @scsi_dh - device handler to be registered.
196  *
197  * Returns 0 on success, -EBUSY if handler already registered.
198  */
199 int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
200 {
201 	if (__scsi_dh_lookup(scsi_dh->name))
202 		return -EBUSY;
203 
204 	if (!scsi_dh->attach || !scsi_dh->detach)
205 		return -EINVAL;
206 
207 	spin_lock(&list_lock);
208 	list_add(&scsi_dh->list, &scsi_dh_list);
209 	spin_unlock(&list_lock);
210 
211 	printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
212 
213 	return SCSI_DH_OK;
214 }
215 EXPORT_SYMBOL_GPL(scsi_register_device_handler);
216 
217 /*
218  * scsi_unregister_device_handler - register a device handler personality
219  *      module.
220  * @scsi_dh - device handler to be unregistered.
221  *
222  * Returns 0 on success, -ENODEV if handler not registered.
223  */
224 int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
225 {
226 	if (!__scsi_dh_lookup(scsi_dh->name))
227 		return -ENODEV;
228 
229 	spin_lock(&list_lock);
230 	list_del(&scsi_dh->list);
231 	spin_unlock(&list_lock);
232 	printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
233 
234 	return SCSI_DH_OK;
235 }
236 EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
237 
238 /*
239  * scsi_dh_activate - activate the path associated with the scsi_device
240  *      corresponding to the given request queue.
241  *     Returns immediately without waiting for activation to be completed.
242  * @q    - Request queue that is associated with the scsi_device to be
243  *         activated.
244  * @fn   - Function to be called upon completion of the activation.
245  *         Function fn is called with data (below) and the error code.
246  *         Function fn may be called from the same calling context. So,
247  *         do not hold the lock in the caller which may be needed in fn.
248  * @data - data passed to the function fn upon completion.
249  *
250  */
251 int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
252 {
253 	struct scsi_device *sdev;
254 	int err = SCSI_DH_NOSYS;
255 
256 	sdev = scsi_device_from_queue(q);
257 	if (!sdev) {
258 		if (fn)
259 			fn(data, err);
260 		return err;
261 	}
262 
263 	if (!sdev->handler)
264 		goto out_fn;
265 	err = SCSI_DH_NOTCONN;
266 	if (sdev->sdev_state == SDEV_CANCEL ||
267 	    sdev->sdev_state == SDEV_DEL)
268 		goto out_fn;
269 
270 	err = SCSI_DH_DEV_OFFLINED;
271 	if (sdev->sdev_state == SDEV_OFFLINE)
272 		goto out_fn;
273 
274 	if (sdev->handler->activate)
275 		err = sdev->handler->activate(sdev, fn, data);
276 
277 out_put_device:
278 	put_device(&sdev->sdev_gendev);
279 	return err;
280 
281 out_fn:
282 	if (fn)
283 		fn(data, err);
284 	goto out_put_device;
285 }
286 EXPORT_SYMBOL_GPL(scsi_dh_activate);
287 
288 /*
289  * scsi_dh_set_params - set the parameters for the device as per the
290  *      string specified in params.
291  * @q - Request queue that is associated with the scsi_device for
292  *      which the parameters to be set.
293  * @params - parameters in the following format
294  *      "no_of_params\0param1\0param2\0param3\0...\0"
295  *      for example, string for 2 parameters with value 10 and 21
296  *      is specified as "2\010\021\0".
297  */
298 int scsi_dh_set_params(struct request_queue *q, const char *params)
299 {
300 	struct scsi_device *sdev;
301 	int err = -SCSI_DH_NOSYS;
302 
303 	sdev = scsi_device_from_queue(q);
304 	if (!sdev)
305 		return err;
306 
307 	if (sdev->handler && sdev->handler->set_params)
308 		err = sdev->handler->set_params(sdev, params);
309 	put_device(&sdev->sdev_gendev);
310 	return err;
311 }
312 EXPORT_SYMBOL_GPL(scsi_dh_set_params);
313 
314 /*
315  * scsi_dh_attach - Attach device handler
316  * @q - Request queue that is associated with the scsi_device
317  *      the handler should be attached to
318  * @name - name of the handler to attach
319  */
320 int scsi_dh_attach(struct request_queue *q, const char *name)
321 {
322 	struct scsi_device *sdev;
323 	struct scsi_device_handler *scsi_dh;
324 	int err = 0;
325 
326 	sdev = scsi_device_from_queue(q);
327 	if (!sdev)
328 		return -ENODEV;
329 
330 	scsi_dh = scsi_dh_lookup(name);
331 	if (!scsi_dh) {
332 		err = -EINVAL;
333 		goto out_put_device;
334 	}
335 
336 	if (sdev->handler) {
337 		if (sdev->handler != scsi_dh)
338 			err = -EBUSY;
339 		goto out_put_device;
340 	}
341 
342 	err = scsi_dh_handler_attach(sdev, scsi_dh);
343 
344 out_put_device:
345 	put_device(&sdev->sdev_gendev);
346 	return err;
347 }
348 EXPORT_SYMBOL_GPL(scsi_dh_attach);
349 
350 /*
351  * scsi_dh_attached_handler_name - Get attached device handler's name
352  * @q - Request queue that is associated with the scsi_device
353  *      that may have a device handler attached
354  * @gfp - the GFP mask used in the kmalloc() call when allocating memory
355  *
356  * Returns name of attached handler, NULL if no handler is attached.
357  * Caller must take care to free the returned string.
358  */
359 const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
360 {
361 	struct scsi_device *sdev;
362 	const char *handler_name = NULL;
363 
364 	sdev = scsi_device_from_queue(q);
365 	if (!sdev)
366 		return NULL;
367 
368 	if (sdev->handler)
369 		handler_name = kstrdup(sdev->handler->name, gfp);
370 	put_device(&sdev->sdev_gendev);
371 	return handler_name;
372 }
373 EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);
374