brintos

brintos / linux-shallow public Read only

0
0
Text · 9.1 KiB · 7b56e00 Raw
374 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * SCSI device handler infrastructure.4 *5 * Copyright IBM Corporation, 20076 *      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 16static DEFINE_SPINLOCK(list_lock);17static LIST_HEAD(scsi_dh_list);18 19struct scsi_dh_blist {20	const char *vendor;21	const char *model;22	const char *driver;23};24 25static 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 70static const char *71scsi_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 88static 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 103static 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 device121 * @sdev - SCSI device the device handler should attach to122 * @scsi_dh - The device handler to attach123 */124static 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	} else154		sdev->handler = scsi_dh;155 156	return ret;157}158 159/*160 * scsi_dh_handler_detach - Detach a device handler from a device161 * @sdev - SCSI device the device handler should be detached from162 */163static 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 170void 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 errors180	 * from scsi_dh_handler_attach()181	 */182	if (devinfo)183		(void)scsi_dh_handler_attach(sdev, devinfo);184}185 186void 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 personality194 *      module.195 * @scsi_dh - device handler to be registered.196 *197 * Returns 0 on success, -EBUSY if handler already registered.198 */199int 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}215EXPORT_SYMBOL_GPL(scsi_register_device_handler);216 217/*218 * scsi_unregister_device_handler - register a device handler personality219 *      module.220 * @scsi_dh - device handler to be unregistered.221 *222 * Returns 0 on success, -ENODEV if handler not registered.223 */224int 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}236EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);237 238/*239 * scsi_dh_activate - activate the path associated with the scsi_device240 *      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 be243 *         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 */251int 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 277out_put_device:278	put_device(&sdev->sdev_gendev);279	return err;280 281out_fn:282	if (fn)283		fn(data, err);284	goto out_put_device;285}286EXPORT_SYMBOL_GPL(scsi_dh_activate);287 288/*289 * scsi_dh_set_params - set the parameters for the device as per the290 *      string specified in params.291 * @q - Request queue that is associated with the scsi_device for292 *      which the parameters to be set.293 * @params - parameters in the following format294 *      "no_of_params\0param1\0param2\0param3\0...\0"295 *      for example, string for 2 parameters with value 10 and 21296 *      is specified as "2\010\021\0".297 */298int 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}312EXPORT_SYMBOL_GPL(scsi_dh_set_params);313 314/*315 * scsi_dh_attach - Attach device handler316 * @q - Request queue that is associated with the scsi_device317 *      the handler should be attached to318 * @name - name of the handler to attach319 */320int 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 344out_put_device:345	put_device(&sdev->sdev_gendev);346	return err;347}348EXPORT_SYMBOL_GPL(scsi_dh_attach);349 350/*351 * scsi_dh_attached_handler_name - Get attached device handler's name352 * @q - Request queue that is associated with the scsi_device353 *      that may have a device handler attached354 * @gfp - the GFP mask used in the kmalloc() call when allocating memory355 *356 * Returns name of attached handler, NULL if no handler is attached.357 * Caller must take care to free the returned string.358 */359const 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}373EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);374