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