GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / scsi / scsi_dh.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * SCSI device handler infrastructure.
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);