Blame view

drivers/scsi/scsi_dh.c 9.13 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
2
3
4
  /*
   * SCSI device handler infrastruture.
   *
a6a8d9f87   Chandra Seetharaman   [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   Tejun Heo   include cleanup: ...
10
  #include <linux/slab.h>
acf3368ff   Paul Gortmaker   scsi: Fix up file...
11
  #include <linux/module.h>
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
12
  #include <scsi/scsi_dh.h>
daaa858b7   Christoph Hellwig   scsi_dh: move to ...
13
  #include "scsi_priv.h"
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
14
15
16
  
  static DEFINE_SPINLOCK(list_lock);
  static LIST_HEAD(scsi_dh_list);
d95dbff2a   Christoph Hellwig   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   Xose Vazquez Perez   scsi: Replace wro...
24
25
26
  	{"DGC", "RAID",			"emc" },
  	{"DGC", "DISK",			"emc" },
  	{"DGC", "VRAID",		"emc" },
d95dbff2a   Christoph Hellwig   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   Xose Vazquez Perez   scsi: dh: add new...
44
45
  	{"IBM", "3542",			"rdac", },
  	{"IBM", "3552",			"rdac", },
37b37d260   Xose Vazquez Perez   scsi: scsi_dh: re...
46
47
48
49
  	{"SGI", "TP9300",		"rdac", },
  	{"SGI", "TP9400",		"rdac", },
  	{"SGI", "TP9500",		"rdac", },
  	{"SGI", "TP9700",		"rdac", },
d95dbff2a   Christoph Hellwig   scsi_dh: move dev...
50
  	{"SGI", "IS",			"rdac", },
4b3aec2bb   Xose Vazquez Perez   scsi: dh: add new...
51
  	{"STK", "OPENstorage",		"rdac", },
d95dbff2a   Christoph Hellwig   scsi_dh: move dev...
52
  	{"STK", "FLEXLINE 380",		"rdac", },
4b3aec2bb   Xose Vazquez Perez   scsi: dh: add new...
53
  	{"STK", "BladeCtlr",		"rdac", },
d95dbff2a   Christoph Hellwig   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   Xose Vazquez Perez   scsi: core: add n...
63
  	{"LENOVO", "DE_Series",		"rdac", },
e094fd346   Steve Schremmer   scsi: dh: Add Fuj...
64
  	{"FUJITSU", "ETERNUS_AHB",	"rdac", },
d95dbff2a   Christoph Hellwig   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   Christoph Hellwig   dm-mpath, scsi_dh...
84
  static struct scsi_device_handler *__scsi_dh_lookup(const char *name)
a6a8d9f87   Chandra Seetharaman   [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   Hannes Reinecke   [SCSI] scsi_dh: I...
90
  		if (!strncmp(tmp->name, name, strlen(tmp->name))) {
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
91
92
93
94
95
96
97
  			found = tmp;
  			break;
  		}
  	}
  	spin_unlock(&list_lock);
  	return found;
  }
566079c84   Christoph Hellwig   dm-mpath, scsi_dh...
98
99
100
  static struct scsi_device_handler *scsi_dh_lookup(const char *name)
  {
  	struct scsi_device_handler *dh;
2ee5671e3   Johannes Thumshirn   scsi: scsi_dh: Do...
101
102
  	if (!name || strlen(name) == 0)
  		return NULL;
566079c84   Christoph Hellwig   dm-mpath, scsi_dh...
103
104
  	dh = __scsi_dh_lookup(name);
  	if (!dh) {
1378889c5   Paul Mackerras   scsi_dh: Use the ...
105
  		request_module("scsi_dh_%s", name);
566079c84   Christoph Hellwig   dm-mpath, scsi_dh...
106
107
108
109
110
  		dh = __scsi_dh_lookup(name);
  	}
  
  	return dh;
  }
6c3633d08   Hannes Reinecke   [SCSI] scsi_dh: I...
111
  /*
765cbc6da   Hannes Reinecke   [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   Hannes Reinecke   scsi: scsi_dh: Re...
119
  	int error, ret = 0;
765cbc6da   Hannes Reinecke   [SCSI] scsi_dh: I...
120

1f12ffa51   Christoph Hellwig   scsi: device hand...
121
122
  	if (!try_module_get(scsi_dh->module))
  		return -EINVAL;
27c888f0b   Christoph Hellwig   scsi_dh: get modu...
123

ee14c674e   Christoph Hellwig   scsi_dh: kill str...
124
  	error = scsi_dh->attach(sdev);
2a8f7a034   Hannes Reinecke   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   Hannes Reinecke   scsi: scsi_dh: su...
133
134
135
136
  		case SCSI_DH_DEV_UNSUPP:
  		case SCSI_DH_NOSYS:
  			ret = -ENODEV;
  			break;
2a8f7a034   Hannes Reinecke   scsi: scsi_dh: Re...
137
138
139
140
  		default:
  			ret = -EINVAL;
  			break;
  		}
2930f8171   Hannes Reinecke   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   Christoph Hellwig   scsi: device hand...
145
  		module_put(scsi_dh->module);
ee14c674e   Christoph Hellwig   scsi_dh: kill str...
146
147
  	} else
  		sdev->handler = scsi_dh;
1d5203284   Christoph Hellwig   scsi: handle more...
148

2a8f7a034   Hannes Reinecke   scsi: scsi_dh: Re...
149
  	return ret;
765cbc6da   Hannes Reinecke   [SCSI] scsi_dh: I...
150
  }
1bab0de02   Christoph Hellwig   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   Chandra Seetharaman   [SCSI] scsi_dh: R...
156
  {
ee14c674e   Christoph Hellwig   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   Chandra Seetharaman   [SCSI] scsi_dh: R...
161
  }
2930f8171   Hannes Reinecke   scsi: scsi_dh: su...
162
  void scsi_dh_add_device(struct scsi_device *sdev)
4c05ae52f   Hannes Reinecke   [SCSI] scsi_dh: A...
163
  {
d95dbff2a   Christoph Hellwig   scsi_dh: move dev...
164
165
  	struct scsi_device_handler *devinfo = NULL;
  	const char *drv;
4c05ae52f   Hannes Reinecke   [SCSI] scsi_dh: A...
166

d95dbff2a   Christoph Hellwig   scsi_dh: move dev...
167
168
  	drv = scsi_dh_find_driver(sdev);
  	if (drv)
d6a32b980   Christoph Hellwig   scsi_dh: don't tr...
169
  		devinfo = __scsi_dh_lookup(drv);
2930f8171   Hannes Reinecke   scsi: scsi_dh: su...
170
171
172
173
  	/*
  	 * device_handler is optional, so ignore errors
  	 * from scsi_dh_handler_attach()
  	 */
086b91d05   Christoph Hellwig   scsi_dh: integrat...
174
  	if (devinfo)
2930f8171   Hannes Reinecke   scsi: scsi_dh: su...
175
  		(void)scsi_dh_handler_attach(sdev, devinfo);
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
176
  }
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
177

23695e41a   Junichi Nomura   scsi_dh: fix use-...
178
  void scsi_dh_release_device(struct scsi_device *sdev)
765cbc6da   Hannes Reinecke   [SCSI] scsi_dh: I...
179
  {
ee14c674e   Christoph Hellwig   scsi_dh: kill str...
180
  	if (sdev->handler)
1bab0de02   Christoph Hellwig   dm-mpath, scsi_dh...
181
  		scsi_dh_handler_detach(sdev);
23695e41a   Junichi Nomura   scsi_dh: fix use-...
182
  }
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
183
  /*
765cbc6da   Hannes Reinecke   [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   Christoph Hellwig   dm-mpath, scsi_dh...
192
  	if (__scsi_dh_lookup(scsi_dh->name))
765cbc6da   Hannes Reinecke   [SCSI] scsi_dh: I...
193
  		return -EBUSY;
1f12ffa51   Christoph Hellwig   scsi: device hand...
194
195
  	if (!scsi_dh->attach || !scsi_dh->detach)
  		return -EINVAL;
765cbc6da   Hannes Reinecke   [SCSI] scsi_dh: I...
196
197
198
  	spin_lock(&list_lock);
  	list_add(&scsi_dh->list, &scsi_dh_list);
  	spin_unlock(&list_lock);
940d7faa4   Peter Jones   [SCSI] scsi_dh: U...
199

765cbc6da   Hannes Reinecke   [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   Chandra Seetharaman   [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   Christoph Hellwig   dm-mpath, scsi_dh...
216
  	if (!__scsi_dh_lookup(scsi_dh->name))
765cbc6da   Hannes Reinecke   [SCSI] scsi_dh: I...
217
  		return -ENODEV;
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
218

a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
219
220
221
  	spin_lock(&list_lock);
  	list_del(&scsi_dh->list);
  	spin_unlock(&list_lock);
765cbc6da   Hannes Reinecke   [SCSI] scsi_dh: I...
222
223
  	printk(KERN_INFO "%s: device handler unregistered
  ", scsi_dh->name);
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
224

765cbc6da   Hannes Reinecke   [SCSI] scsi_dh: I...
225
  	return SCSI_DH_OK;
a6a8d9f87   Chandra Seetharaman   [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   Chandra Seetharaman   [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   Chandra Seetharaman   [SCSI] scsi_dh: a...
241
   */
3ae31f6a7   Chandra Seetharaman   [SCSI] scsi_dh: C...
242
  int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
243
  {
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
244
  	struct scsi_device *sdev;
e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
245
  	int err = SCSI_DH_NOSYS;
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
246

857de6e00   Hannes Reinecke   scsi: use 'scsi_d...
247
  	sdev = scsi_device_from_queue(q);
a18a920c7   Moger, Babu   [SCSI] scsi_dh: c...
248
  	if (!sdev) {
a18a920c7   Moger, Babu   [SCSI] scsi_dh: c...
249
250
251
252
  		if (fn)
  			fn(data, err);
  		return err;
  	}
e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
253
254
  	if (!sdev->handler)
  		goto out_fn;
710105fda   Hannes Reinecke   scsi_dh: return S...
255
  	err = SCSI_DH_NOTCONN;
e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
256
  	if (sdev->sdev_state == SDEV_CANCEL ||
db422318c   Menny Hamburger   [SCSI] scsi_dh: p...
257
  	    sdev->sdev_state == SDEV_DEL)
e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
258
  		goto out_fn;
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
259

e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
260
261
262
  	err = SCSI_DH_DEV_OFFLINED;
  	if (sdev->sdev_state == SDEV_OFFLINE)
  		goto out_fn;
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
263

ee14c674e   Christoph Hellwig   scsi_dh: kill str...
264
265
  	if (sdev->handler->activate)
  		err = sdev->handler->activate(sdev, fn, data);
e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
266
267
268
  
  out_put_device:
  	put_device(&sdev->sdev_gendev);
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
269
  	return err;
e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
270
271
272
273
274
  
  out_fn:
  	if (fn)
  		fn(data, err);
  	goto out_put_device;
a6a8d9f87   Chandra Seetharaman   [SCSI] scsi_dh: a...
275
276
277
278
  }
  EXPORT_SYMBOL_GPL(scsi_dh_activate);
  
  /*
18ee70c9d   Chandra Seetharaman   [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   Chandra Seetharaman   [SCSI] scsi_dh: a...
290
  	struct scsi_device *sdev;
e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
291
  	int err = -SCSI_DH_NOSYS;
18ee70c9d   Chandra Seetharaman   [SCSI] scsi_dh: a...
292

857de6e00   Hannes Reinecke   scsi: use 'scsi_d...
293
  	sdev = scsi_device_from_queue(q);
e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
294
  	if (!sdev)
18ee70c9d   Chandra Seetharaman   [SCSI] scsi_dh: a...
295
  		return err;
e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
296
297
298
  
  	if (sdev->handler && sdev->handler->set_params)
  		err = sdev->handler->set_params(sdev, params);
18ee70c9d   Chandra Seetharaman   [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   Hannes Reinecke   [SCSI] scsi_dh: F...
305
   * scsi_dh_attach - Attach device handler
7e8a74b17   Mike Snitzer   [SCSI] scsi_dh: a...
306
307
   * @q - Request queue that is associated with the scsi_device
   *      the handler should be attached to
ae11b1b36   Hannes Reinecke   [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   Hannes Reinecke   [SCSI] scsi_dh: a...
312
313
314
  	struct scsi_device *sdev;
  	struct scsi_device_handler *scsi_dh;
  	int err = 0;
857de6e00   Hannes Reinecke   scsi: use 'scsi_d...
315
  	sdev = scsi_device_from_queue(q);
e959ed9a4   Christoph Hellwig   scsi_dh: add a co...
316
317
  	if (!sdev)
  		return -ENODEV;
ae11b1b36   Hannes Reinecke   [SCSI] scsi_dh: a...
318

e959ed9a4   Christoph Hellwig   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   Hannes Reinecke   [SCSI] scsi_dh: a...
324

ee14c674e   Christoph Hellwig   scsi_dh: kill str...
325
326
  	if (sdev->handler) {
  		if (sdev->handler != scsi_dh)
1bab0de02   Christoph Hellwig   dm-mpath, scsi_dh...
327
328
  			err = -EBUSY;
  		goto out_put_device;
ae11b1b36   Hannes Reinecke   [SCSI] scsi_dh: a...
329
  	}
1bab0de02   Christoph Hellwig   dm-mpath, scsi_dh...
330
331
332
333
  
  	err = scsi_dh_handler_attach(sdev, scsi_dh);
  
  out_put_device:
ae11b1b36   Hannes Reinecke   [SCSI] scsi_dh: a...
334
  	put_device(&sdev->sdev_gendev);
1bab0de02   Christoph Hellwig   dm-mpath, scsi_dh...
335
  	return err;
ae11b1b36   Hannes Reinecke   [SCSI] scsi_dh: a...
336
  }
1bab0de02   Christoph Hellwig   dm-mpath, scsi_dh...
337
  EXPORT_SYMBOL_GPL(scsi_dh_attach);
ae11b1b36   Hannes Reinecke   [SCSI] scsi_dh: a...
338

7e8a74b17   Mike Snitzer   [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   Mike Snitzer   [SCSI] scsi_dh: a...
350
351
  	struct scsi_device *sdev;
  	const char *handler_name = NULL;
857de6e00   Hannes Reinecke   scsi: use 'scsi_d...
352
  	sdev = scsi_device_from_queue(q);
7e8a74b17   Mike Snitzer   [SCSI] scsi_dh: a...
353
354
  	if (!sdev)
  		return NULL;
ee14c674e   Christoph Hellwig   scsi_dh: kill str...
355
356
  	if (sdev->handler)
  		handler_name = kstrdup(sdev->handler->name, gfp);
7e8a74b17   Mike Snitzer   [SCSI] scsi_dh: a...
357
358
359
360
  	put_device(&sdev->sdev_gendev);
  	return handler_name;
  }
  EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);