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