Linux Audio

Check our new training course

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