18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * SCSI device handler infrastruture.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright IBM Corporation, 2007
68c2ecf20Sopenharmony_ci *      Authors:
78c2ecf20Sopenharmony_ci *               Chandra Seetharaman <sekharan@us.ibm.com>
88c2ecf20Sopenharmony_ci *               Mike Anderson <andmike@linux.vnet.ibm.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <scsi/scsi_dh.h>
148c2ecf20Sopenharmony_ci#include "scsi_priv.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(list_lock);
178c2ecf20Sopenharmony_cistatic LIST_HEAD(scsi_dh_list);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistruct scsi_dh_blist {
208c2ecf20Sopenharmony_ci	const char *vendor;
218c2ecf20Sopenharmony_ci	const char *model;
228c2ecf20Sopenharmony_ci	const char *driver;
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic const struct scsi_dh_blist scsi_dh_blist[] = {
268c2ecf20Sopenharmony_ci	{"DGC", "RAID",			"emc" },
278c2ecf20Sopenharmony_ci	{"DGC", "DISK",			"emc" },
288c2ecf20Sopenharmony_ci	{"DGC", "VRAID",		"emc" },
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	{"COMPAQ", "MSA1000 VOLUME",	"hp_sw" },
318c2ecf20Sopenharmony_ci	{"COMPAQ", "HSV110",		"hp_sw" },
328c2ecf20Sopenharmony_ci	{"HP", "HSV100",		"hp_sw"},
338c2ecf20Sopenharmony_ci	{"DEC", "HSG80",		"hp_sw"},
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	{"IBM", "1722",			"rdac", },
368c2ecf20Sopenharmony_ci	{"IBM", "1724",			"rdac", },
378c2ecf20Sopenharmony_ci	{"IBM", "1726",			"rdac", },
388c2ecf20Sopenharmony_ci	{"IBM", "1742",			"rdac", },
398c2ecf20Sopenharmony_ci	{"IBM", "1745",			"rdac", },
408c2ecf20Sopenharmony_ci	{"IBM", "1746",			"rdac", },
418c2ecf20Sopenharmony_ci	{"IBM", "1813",			"rdac", },
428c2ecf20Sopenharmony_ci	{"IBM", "1814",			"rdac", },
438c2ecf20Sopenharmony_ci	{"IBM", "1815",			"rdac", },
448c2ecf20Sopenharmony_ci	{"IBM", "1818",			"rdac", },
458c2ecf20Sopenharmony_ci	{"IBM", "3526",			"rdac", },
468c2ecf20Sopenharmony_ci	{"IBM", "3542",			"rdac", },
478c2ecf20Sopenharmony_ci	{"IBM", "3552",			"rdac", },
488c2ecf20Sopenharmony_ci	{"SGI", "TP9300",		"rdac", },
498c2ecf20Sopenharmony_ci	{"SGI", "TP9400",		"rdac", },
508c2ecf20Sopenharmony_ci	{"SGI", "TP9500",		"rdac", },
518c2ecf20Sopenharmony_ci	{"SGI", "TP9700",		"rdac", },
528c2ecf20Sopenharmony_ci	{"SGI", "IS",			"rdac", },
538c2ecf20Sopenharmony_ci	{"STK", "OPENstorage",		"rdac", },
548c2ecf20Sopenharmony_ci	{"STK", "FLEXLINE 380",		"rdac", },
558c2ecf20Sopenharmony_ci	{"STK", "BladeCtlr",		"rdac", },
568c2ecf20Sopenharmony_ci	{"SUN", "CSM",			"rdac", },
578c2ecf20Sopenharmony_ci	{"SUN", "LCSM100",		"rdac", },
588c2ecf20Sopenharmony_ci	{"SUN", "STK6580_6780",		"rdac", },
598c2ecf20Sopenharmony_ci	{"SUN", "SUN_6180",		"rdac", },
608c2ecf20Sopenharmony_ci	{"SUN", "ArrayStorage",		"rdac", },
618c2ecf20Sopenharmony_ci	{"DELL", "MD3",			"rdac", },
628c2ecf20Sopenharmony_ci	{"NETAPP", "INF-01-00",		"rdac", },
638c2ecf20Sopenharmony_ci	{"LSI", "INF-01-00",		"rdac", },
648c2ecf20Sopenharmony_ci	{"ENGENIO", "INF-01-00",	"rdac", },
658c2ecf20Sopenharmony_ci	{"LENOVO", "DE_Series",		"rdac", },
668c2ecf20Sopenharmony_ci	{"FUJITSU", "ETERNUS_AHB",	"rdac", },
678c2ecf20Sopenharmony_ci	{NULL, NULL,			NULL },
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic const char *
718c2ecf20Sopenharmony_ciscsi_dh_find_driver(struct scsi_device *sdev)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	const struct scsi_dh_blist *b;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (scsi_device_tpgs(sdev))
768c2ecf20Sopenharmony_ci		return "alua";
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	for (b = scsi_dh_blist; b->vendor; b++) {
798c2ecf20Sopenharmony_ci		if (!strncmp(sdev->vendor, b->vendor, strlen(b->vendor)) &&
808c2ecf20Sopenharmony_ci		    !strncmp(sdev->model, b->model, strlen(b->model))) {
818c2ecf20Sopenharmony_ci			return b->driver;
828c2ecf20Sopenharmony_ci		}
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci	return NULL;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic struct scsi_device_handler *__scsi_dh_lookup(const char *name)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct scsi_device_handler *tmp, *found = NULL;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	spin_lock(&list_lock);
938c2ecf20Sopenharmony_ci	list_for_each_entry(tmp, &scsi_dh_list, list) {
948c2ecf20Sopenharmony_ci		if (!strncmp(tmp->name, name, strlen(tmp->name))) {
958c2ecf20Sopenharmony_ci			found = tmp;
968c2ecf20Sopenharmony_ci			break;
978c2ecf20Sopenharmony_ci		}
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci	spin_unlock(&list_lock);
1008c2ecf20Sopenharmony_ci	return found;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic struct scsi_device_handler *scsi_dh_lookup(const char *name)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct scsi_device_handler *dh;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (!name || strlen(name) == 0)
1088c2ecf20Sopenharmony_ci		return NULL;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	dh = __scsi_dh_lookup(name);
1118c2ecf20Sopenharmony_ci	if (!dh) {
1128c2ecf20Sopenharmony_ci		request_module("scsi_dh_%s", name);
1138c2ecf20Sopenharmony_ci		dh = __scsi_dh_lookup(name);
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return dh;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/*
1208c2ecf20Sopenharmony_ci * scsi_dh_handler_attach - Attach a device handler to a device
1218c2ecf20Sopenharmony_ci * @sdev - SCSI device the device handler should attach to
1228c2ecf20Sopenharmony_ci * @scsi_dh - The device handler to attach
1238c2ecf20Sopenharmony_ci */
1248c2ecf20Sopenharmony_cistatic int scsi_dh_handler_attach(struct scsi_device *sdev,
1258c2ecf20Sopenharmony_ci				  struct scsi_device_handler *scsi_dh)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	int error, ret = 0;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (!try_module_get(scsi_dh->module))
1308c2ecf20Sopenharmony_ci		return -EINVAL;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	error = scsi_dh->attach(sdev);
1338c2ecf20Sopenharmony_ci	if (error != SCSI_DH_OK) {
1348c2ecf20Sopenharmony_ci		switch (error) {
1358c2ecf20Sopenharmony_ci		case SCSI_DH_NOMEM:
1368c2ecf20Sopenharmony_ci			ret = -ENOMEM;
1378c2ecf20Sopenharmony_ci			break;
1388c2ecf20Sopenharmony_ci		case SCSI_DH_RES_TEMP_UNAVAIL:
1398c2ecf20Sopenharmony_ci			ret = -EAGAIN;
1408c2ecf20Sopenharmony_ci			break;
1418c2ecf20Sopenharmony_ci		case SCSI_DH_DEV_UNSUPP:
1428c2ecf20Sopenharmony_ci		case SCSI_DH_NOSYS:
1438c2ecf20Sopenharmony_ci			ret = -ENODEV;
1448c2ecf20Sopenharmony_ci			break;
1458c2ecf20Sopenharmony_ci		default:
1468c2ecf20Sopenharmony_ci			ret = -EINVAL;
1478c2ecf20Sopenharmony_ci			break;
1488c2ecf20Sopenharmony_ci		}
1498c2ecf20Sopenharmony_ci		if (ret != -ENODEV)
1508c2ecf20Sopenharmony_ci			sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%d)\n",
1518c2ecf20Sopenharmony_ci				    scsi_dh->name, error);
1528c2ecf20Sopenharmony_ci		module_put(scsi_dh->module);
1538c2ecf20Sopenharmony_ci	} else
1548c2ecf20Sopenharmony_ci		sdev->handler = scsi_dh;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	return ret;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/*
1608c2ecf20Sopenharmony_ci * scsi_dh_handler_detach - Detach a device handler from a device
1618c2ecf20Sopenharmony_ci * @sdev - SCSI device the device handler should be detached from
1628c2ecf20Sopenharmony_ci */
1638c2ecf20Sopenharmony_cistatic void scsi_dh_handler_detach(struct scsi_device *sdev)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	sdev->handler->detach(sdev);
1668c2ecf20Sopenharmony_ci	sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", sdev->handler->name);
1678c2ecf20Sopenharmony_ci	module_put(sdev->handler->module);
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_civoid scsi_dh_add_device(struct scsi_device *sdev)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	struct scsi_device_handler *devinfo = NULL;
1738c2ecf20Sopenharmony_ci	const char *drv;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	drv = scsi_dh_find_driver(sdev);
1768c2ecf20Sopenharmony_ci	if (drv)
1778c2ecf20Sopenharmony_ci		devinfo = __scsi_dh_lookup(drv);
1788c2ecf20Sopenharmony_ci	/*
1798c2ecf20Sopenharmony_ci	 * device_handler is optional, so ignore errors
1808c2ecf20Sopenharmony_ci	 * from scsi_dh_handler_attach()
1818c2ecf20Sopenharmony_ci	 */
1828c2ecf20Sopenharmony_ci	if (devinfo)
1838c2ecf20Sopenharmony_ci		(void)scsi_dh_handler_attach(sdev, devinfo);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_civoid scsi_dh_release_device(struct scsi_device *sdev)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	if (sdev->handler)
1898c2ecf20Sopenharmony_ci		scsi_dh_handler_detach(sdev);
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/*
1938c2ecf20Sopenharmony_ci * scsi_register_device_handler - register a device handler personality
1948c2ecf20Sopenharmony_ci *      module.
1958c2ecf20Sopenharmony_ci * @scsi_dh - device handler to be registered.
1968c2ecf20Sopenharmony_ci *
1978c2ecf20Sopenharmony_ci * Returns 0 on success, -EBUSY if handler already registered.
1988c2ecf20Sopenharmony_ci */
1998c2ecf20Sopenharmony_ciint scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	if (__scsi_dh_lookup(scsi_dh->name))
2028c2ecf20Sopenharmony_ci		return -EBUSY;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if (!scsi_dh->attach || !scsi_dh->detach)
2058c2ecf20Sopenharmony_ci		return -EINVAL;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	spin_lock(&list_lock);
2088c2ecf20Sopenharmony_ci	list_add(&scsi_dh->list, &scsi_dh_list);
2098c2ecf20Sopenharmony_ci	spin_unlock(&list_lock);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	return SCSI_DH_OK;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_register_device_handler);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci/*
2188c2ecf20Sopenharmony_ci * scsi_unregister_device_handler - register a device handler personality
2198c2ecf20Sopenharmony_ci *      module.
2208c2ecf20Sopenharmony_ci * @scsi_dh - device handler to be unregistered.
2218c2ecf20Sopenharmony_ci *
2228c2ecf20Sopenharmony_ci * Returns 0 on success, -ENODEV if handler not registered.
2238c2ecf20Sopenharmony_ci */
2248c2ecf20Sopenharmony_ciint scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	if (!__scsi_dh_lookup(scsi_dh->name))
2278c2ecf20Sopenharmony_ci		return -ENODEV;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	spin_lock(&list_lock);
2308c2ecf20Sopenharmony_ci	list_del(&scsi_dh->list);
2318c2ecf20Sopenharmony_ci	spin_unlock(&list_lock);
2328c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return SCSI_DH_OK;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci/*
2398c2ecf20Sopenharmony_ci * scsi_dh_activate - activate the path associated with the scsi_device
2408c2ecf20Sopenharmony_ci *      corresponding to the given request queue.
2418c2ecf20Sopenharmony_ci *     Returns immediately without waiting for activation to be completed.
2428c2ecf20Sopenharmony_ci * @q    - Request queue that is associated with the scsi_device to be
2438c2ecf20Sopenharmony_ci *         activated.
2448c2ecf20Sopenharmony_ci * @fn   - Function to be called upon completion of the activation.
2458c2ecf20Sopenharmony_ci *         Function fn is called with data (below) and the error code.
2468c2ecf20Sopenharmony_ci *         Function fn may be called from the same calling context. So,
2478c2ecf20Sopenharmony_ci *         do not hold the lock in the caller which may be needed in fn.
2488c2ecf20Sopenharmony_ci * @data - data passed to the function fn upon completion.
2498c2ecf20Sopenharmony_ci *
2508c2ecf20Sopenharmony_ci */
2518c2ecf20Sopenharmony_ciint scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
2548c2ecf20Sopenharmony_ci	int err = SCSI_DH_NOSYS;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	sdev = scsi_device_from_queue(q);
2578c2ecf20Sopenharmony_ci	if (!sdev) {
2588c2ecf20Sopenharmony_ci		if (fn)
2598c2ecf20Sopenharmony_ci			fn(data, err);
2608c2ecf20Sopenharmony_ci		return err;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if (!sdev->handler)
2648c2ecf20Sopenharmony_ci		goto out_fn;
2658c2ecf20Sopenharmony_ci	err = SCSI_DH_NOTCONN;
2668c2ecf20Sopenharmony_ci	if (sdev->sdev_state == SDEV_CANCEL ||
2678c2ecf20Sopenharmony_ci	    sdev->sdev_state == SDEV_DEL)
2688c2ecf20Sopenharmony_ci		goto out_fn;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	err = SCSI_DH_DEV_OFFLINED;
2718c2ecf20Sopenharmony_ci	if (sdev->sdev_state == SDEV_OFFLINE)
2728c2ecf20Sopenharmony_ci		goto out_fn;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (sdev->handler->activate)
2758c2ecf20Sopenharmony_ci		err = sdev->handler->activate(sdev, fn, data);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ciout_put_device:
2788c2ecf20Sopenharmony_ci	put_device(&sdev->sdev_gendev);
2798c2ecf20Sopenharmony_ci	return err;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ciout_fn:
2828c2ecf20Sopenharmony_ci	if (fn)
2838c2ecf20Sopenharmony_ci		fn(data, err);
2848c2ecf20Sopenharmony_ci	goto out_put_device;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_dh_activate);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/*
2898c2ecf20Sopenharmony_ci * scsi_dh_set_params - set the parameters for the device as per the
2908c2ecf20Sopenharmony_ci *      string specified in params.
2918c2ecf20Sopenharmony_ci * @q - Request queue that is associated with the scsi_device for
2928c2ecf20Sopenharmony_ci *      which the parameters to be set.
2938c2ecf20Sopenharmony_ci * @params - parameters in the following format
2948c2ecf20Sopenharmony_ci *      "no_of_params\0param1\0param2\0param3\0...\0"
2958c2ecf20Sopenharmony_ci *      for example, string for 2 parameters with value 10 and 21
2968c2ecf20Sopenharmony_ci *      is specified as "2\010\021\0".
2978c2ecf20Sopenharmony_ci */
2988c2ecf20Sopenharmony_ciint scsi_dh_set_params(struct request_queue *q, const char *params)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
3018c2ecf20Sopenharmony_ci	int err = -SCSI_DH_NOSYS;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	sdev = scsi_device_from_queue(q);
3048c2ecf20Sopenharmony_ci	if (!sdev)
3058c2ecf20Sopenharmony_ci		return err;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (sdev->handler && sdev->handler->set_params)
3088c2ecf20Sopenharmony_ci		err = sdev->handler->set_params(sdev, params);
3098c2ecf20Sopenharmony_ci	put_device(&sdev->sdev_gendev);
3108c2ecf20Sopenharmony_ci	return err;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_dh_set_params);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci/*
3158c2ecf20Sopenharmony_ci * scsi_dh_attach - Attach device handler
3168c2ecf20Sopenharmony_ci * @q - Request queue that is associated with the scsi_device
3178c2ecf20Sopenharmony_ci *      the handler should be attached to
3188c2ecf20Sopenharmony_ci * @name - name of the handler to attach
3198c2ecf20Sopenharmony_ci */
3208c2ecf20Sopenharmony_ciint scsi_dh_attach(struct request_queue *q, const char *name)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
3238c2ecf20Sopenharmony_ci	struct scsi_device_handler *scsi_dh;
3248c2ecf20Sopenharmony_ci	int err = 0;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	sdev = scsi_device_from_queue(q);
3278c2ecf20Sopenharmony_ci	if (!sdev)
3288c2ecf20Sopenharmony_ci		return -ENODEV;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	scsi_dh = scsi_dh_lookup(name);
3318c2ecf20Sopenharmony_ci	if (!scsi_dh) {
3328c2ecf20Sopenharmony_ci		err = -EINVAL;
3338c2ecf20Sopenharmony_ci		goto out_put_device;
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (sdev->handler) {
3378c2ecf20Sopenharmony_ci		if (sdev->handler != scsi_dh)
3388c2ecf20Sopenharmony_ci			err = -EBUSY;
3398c2ecf20Sopenharmony_ci		goto out_put_device;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	err = scsi_dh_handler_attach(sdev, scsi_dh);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ciout_put_device:
3458c2ecf20Sopenharmony_ci	put_device(&sdev->sdev_gendev);
3468c2ecf20Sopenharmony_ci	return err;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_dh_attach);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci/*
3518c2ecf20Sopenharmony_ci * scsi_dh_attached_handler_name - Get attached device handler's name
3528c2ecf20Sopenharmony_ci * @q - Request queue that is associated with the scsi_device
3538c2ecf20Sopenharmony_ci *      that may have a device handler attached
3548c2ecf20Sopenharmony_ci * @gfp - the GFP mask used in the kmalloc() call when allocating memory
3558c2ecf20Sopenharmony_ci *
3568c2ecf20Sopenharmony_ci * Returns name of attached handler, NULL if no handler is attached.
3578c2ecf20Sopenharmony_ci * Caller must take care to free the returned string.
3588c2ecf20Sopenharmony_ci */
3598c2ecf20Sopenharmony_ciconst char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
3628c2ecf20Sopenharmony_ci	const char *handler_name = NULL;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	sdev = scsi_device_from_queue(q);
3658c2ecf20Sopenharmony_ci	if (!sdev)
3668c2ecf20Sopenharmony_ci		return NULL;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	if (sdev->handler)
3698c2ecf20Sopenharmony_ci		handler_name = kstrdup(sdev->handler->name, gfp);
3708c2ecf20Sopenharmony_ci	put_device(&sdev->sdev_gendev);
3718c2ecf20Sopenharmony_ci	return handler_name;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name);
374