11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2daaa858bSChristoph Hellwig /* 3daaa858bSChristoph Hellwig * SCSI device handler infrastruture. 4daaa858bSChristoph Hellwig * 5daaa858bSChristoph Hellwig * Copyright IBM Corporation, 2007 6daaa858bSChristoph Hellwig * Authors: 7daaa858bSChristoph Hellwig * Chandra Seetharaman <sekharan@us.ibm.com> 8daaa858bSChristoph Hellwig * Mike Anderson <andmike@linux.vnet.ibm.com> 9daaa858bSChristoph Hellwig */ 10daaa858bSChristoph Hellwig 11daaa858bSChristoph Hellwig #include <linux/slab.h> 12daaa858bSChristoph Hellwig #include <linux/module.h> 13daaa858bSChristoph Hellwig #include <scsi/scsi_dh.h> 14daaa858bSChristoph Hellwig #include "scsi_priv.h" 15daaa858bSChristoph Hellwig 16daaa858bSChristoph Hellwig static DEFINE_SPINLOCK(list_lock); 17daaa858bSChristoph Hellwig static LIST_HEAD(scsi_dh_list); 18daaa858bSChristoph Hellwig 19d95dbff2SChristoph Hellwig struct scsi_dh_blist { 20d95dbff2SChristoph Hellwig const char *vendor; 21d95dbff2SChristoph Hellwig const char *model; 22d95dbff2SChristoph Hellwig const char *driver; 23d95dbff2SChristoph Hellwig }; 24d95dbff2SChristoph Hellwig 25d95dbff2SChristoph Hellwig static const struct scsi_dh_blist scsi_dh_blist[] = { 260ba43a81SXose Vazquez Perez {"DGC", "RAID", "emc" }, 270ba43a81SXose Vazquez Perez {"DGC", "DISK", "emc" }, 280ba43a81SXose Vazquez Perez {"DGC", "VRAID", "emc" }, 29d95dbff2SChristoph Hellwig 30d95dbff2SChristoph Hellwig {"COMPAQ", "MSA1000 VOLUME", "hp_sw" }, 31d95dbff2SChristoph Hellwig {"COMPAQ", "HSV110", "hp_sw" }, 32d95dbff2SChristoph Hellwig {"HP", "HSV100", "hp_sw"}, 33d95dbff2SChristoph Hellwig {"DEC", "HSG80", "hp_sw"}, 34d95dbff2SChristoph Hellwig 35d95dbff2SChristoph Hellwig {"IBM", "1722", "rdac", }, 36d95dbff2SChristoph Hellwig {"IBM", "1724", "rdac", }, 37d95dbff2SChristoph Hellwig {"IBM", "1726", "rdac", }, 38d95dbff2SChristoph Hellwig {"IBM", "1742", "rdac", }, 39d95dbff2SChristoph Hellwig {"IBM", "1745", "rdac", }, 40d95dbff2SChristoph Hellwig {"IBM", "1746", "rdac", }, 41d95dbff2SChristoph Hellwig {"IBM", "1813", "rdac", }, 42d95dbff2SChristoph Hellwig {"IBM", "1814", "rdac", }, 43d95dbff2SChristoph Hellwig {"IBM", "1815", "rdac", }, 44d95dbff2SChristoph Hellwig {"IBM", "1818", "rdac", }, 45d95dbff2SChristoph Hellwig {"IBM", "3526", "rdac", }, 464b3aec2bSXose Vazquez Perez {"IBM", "3542", "rdac", }, 474b3aec2bSXose Vazquez Perez {"IBM", "3552", "rdac", }, 4837b37d26SXose Vazquez Perez {"SGI", "TP9300", "rdac", }, 4937b37d26SXose Vazquez Perez {"SGI", "TP9400", "rdac", }, 5037b37d26SXose Vazquez Perez {"SGI", "TP9500", "rdac", }, 5137b37d26SXose Vazquez Perez {"SGI", "TP9700", "rdac", }, 52d95dbff2SChristoph Hellwig {"SGI", "IS", "rdac", }, 534b3aec2bSXose Vazquez Perez {"STK", "OPENstorage", "rdac", }, 54d95dbff2SChristoph Hellwig {"STK", "FLEXLINE 380", "rdac", }, 554b3aec2bSXose Vazquez Perez {"STK", "BladeCtlr", "rdac", }, 56d95dbff2SChristoph Hellwig {"SUN", "CSM", "rdac", }, 57d95dbff2SChristoph Hellwig {"SUN", "LCSM100", "rdac", }, 58d95dbff2SChristoph Hellwig {"SUN", "STK6580_6780", "rdac", }, 59d95dbff2SChristoph Hellwig {"SUN", "SUN_6180", "rdac", }, 60d95dbff2SChristoph Hellwig {"SUN", "ArrayStorage", "rdac", }, 61d95dbff2SChristoph Hellwig {"DELL", "MD3", "rdac", }, 62d95dbff2SChristoph Hellwig {"NETAPP", "INF-01-00", "rdac", }, 63d95dbff2SChristoph Hellwig {"LSI", "INF-01-00", "rdac", }, 64d95dbff2SChristoph Hellwig {"ENGENIO", "INF-01-00", "rdac", }, 651cb1d2c6SXose Vazquez Perez {"LENOVO", "DE_Series", "rdac", }, 66e094fd34SSteve Schremmer {"FUJITSU", "ETERNUS_AHB", "rdac", }, 67d95dbff2SChristoph Hellwig {NULL, NULL, NULL }, 68d95dbff2SChristoph Hellwig }; 69d95dbff2SChristoph Hellwig 70d95dbff2SChristoph Hellwig static const char * 71d95dbff2SChristoph Hellwig scsi_dh_find_driver(struct scsi_device *sdev) 72d95dbff2SChristoph Hellwig { 73d95dbff2SChristoph Hellwig const struct scsi_dh_blist *b; 74d95dbff2SChristoph Hellwig 75d95dbff2SChristoph Hellwig if (scsi_device_tpgs(sdev)) 76d95dbff2SChristoph Hellwig return "alua"; 77d95dbff2SChristoph Hellwig 78d95dbff2SChristoph Hellwig for (b = scsi_dh_blist; b->vendor; b++) { 79d95dbff2SChristoph Hellwig if (!strncmp(sdev->vendor, b->vendor, strlen(b->vendor)) && 80d95dbff2SChristoph Hellwig !strncmp(sdev->model, b->model, strlen(b->model))) { 81d95dbff2SChristoph Hellwig return b->driver; 82d95dbff2SChristoph Hellwig } 83d95dbff2SChristoph Hellwig } 84d95dbff2SChristoph Hellwig return NULL; 85d95dbff2SChristoph Hellwig } 86d95dbff2SChristoph Hellwig 87d95dbff2SChristoph Hellwig 88daaa858bSChristoph Hellwig static struct scsi_device_handler *__scsi_dh_lookup(const char *name) 89daaa858bSChristoph Hellwig { 90daaa858bSChristoph Hellwig struct scsi_device_handler *tmp, *found = NULL; 91daaa858bSChristoph Hellwig 92daaa858bSChristoph Hellwig spin_lock(&list_lock); 93daaa858bSChristoph Hellwig list_for_each_entry(tmp, &scsi_dh_list, list) { 94daaa858bSChristoph Hellwig if (!strncmp(tmp->name, name, strlen(tmp->name))) { 95daaa858bSChristoph Hellwig found = tmp; 96daaa858bSChristoph Hellwig break; 97daaa858bSChristoph Hellwig } 98daaa858bSChristoph Hellwig } 99daaa858bSChristoph Hellwig spin_unlock(&list_lock); 100daaa858bSChristoph Hellwig return found; 101daaa858bSChristoph Hellwig } 102daaa858bSChristoph Hellwig 103daaa858bSChristoph Hellwig static struct scsi_device_handler *scsi_dh_lookup(const char *name) 104daaa858bSChristoph Hellwig { 105daaa858bSChristoph Hellwig struct scsi_device_handler *dh; 106daaa858bSChristoph Hellwig 1072ee5671eSJohannes Thumshirn if (!name || strlen(name) == 0) 1082ee5671eSJohannes Thumshirn return NULL; 1092ee5671eSJohannes Thumshirn 110daaa858bSChristoph Hellwig dh = __scsi_dh_lookup(name); 111daaa858bSChristoph Hellwig if (!dh) { 1121378889cSPaul Mackerras request_module("scsi_dh_%s", name); 113daaa858bSChristoph Hellwig dh = __scsi_dh_lookup(name); 114daaa858bSChristoph Hellwig } 115daaa858bSChristoph Hellwig 116daaa858bSChristoph Hellwig return dh; 117daaa858bSChristoph Hellwig } 118daaa858bSChristoph Hellwig 119daaa858bSChristoph Hellwig /* 120daaa858bSChristoph Hellwig * scsi_dh_handler_attach - Attach a device handler to a device 121daaa858bSChristoph Hellwig * @sdev - SCSI device the device handler should attach to 122daaa858bSChristoph Hellwig * @scsi_dh - The device handler to attach 123daaa858bSChristoph Hellwig */ 124daaa858bSChristoph Hellwig static int scsi_dh_handler_attach(struct scsi_device *sdev, 125daaa858bSChristoph Hellwig struct scsi_device_handler *scsi_dh) 126daaa858bSChristoph Hellwig { 1272a8f7a03SHannes Reinecke int error, ret = 0; 128daaa858bSChristoph Hellwig 129daaa858bSChristoph Hellwig if (!try_module_get(scsi_dh->module)) 130daaa858bSChristoph Hellwig return -EINVAL; 131daaa858bSChristoph Hellwig 132ee14c674SChristoph Hellwig error = scsi_dh->attach(sdev); 1332a8f7a03SHannes Reinecke if (error != SCSI_DH_OK) { 1342a8f7a03SHannes Reinecke switch (error) { 1352a8f7a03SHannes Reinecke case SCSI_DH_NOMEM: 1362a8f7a03SHannes Reinecke ret = -ENOMEM; 1372a8f7a03SHannes Reinecke break; 1382a8f7a03SHannes Reinecke case SCSI_DH_RES_TEMP_UNAVAIL: 1392a8f7a03SHannes Reinecke ret = -EAGAIN; 1402a8f7a03SHannes Reinecke break; 1412930f817SHannes Reinecke case SCSI_DH_DEV_UNSUPP: 1422930f817SHannes Reinecke case SCSI_DH_NOSYS: 1432930f817SHannes Reinecke ret = -ENODEV; 1442930f817SHannes Reinecke break; 1452a8f7a03SHannes Reinecke default: 1462a8f7a03SHannes Reinecke ret = -EINVAL; 1472a8f7a03SHannes Reinecke break; 1482a8f7a03SHannes Reinecke } 1492930f817SHannes Reinecke if (ret != -ENODEV) 150ee14c674SChristoph Hellwig sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%d)\n", 151ee14c674SChristoph Hellwig scsi_dh->name, error); 152daaa858bSChristoph Hellwig module_put(scsi_dh->module); 153ee14c674SChristoph Hellwig } else 154ee14c674SChristoph Hellwig sdev->handler = scsi_dh; 155daaa858bSChristoph Hellwig 1562a8f7a03SHannes Reinecke return ret; 157daaa858bSChristoph Hellwig } 158daaa858bSChristoph Hellwig 159daaa858bSChristoph Hellwig /* 160daaa858bSChristoph Hellwig * scsi_dh_handler_detach - Detach a device handler from a device 161daaa858bSChristoph Hellwig * @sdev - SCSI device the device handler should be detached from 162daaa858bSChristoph Hellwig */ 163daaa858bSChristoph Hellwig static void scsi_dh_handler_detach(struct scsi_device *sdev) 164daaa858bSChristoph Hellwig { 165ee14c674SChristoph Hellwig sdev->handler->detach(sdev); 166ee14c674SChristoph Hellwig sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", sdev->handler->name); 167ee14c674SChristoph Hellwig module_put(sdev->handler->module); 168daaa858bSChristoph Hellwig } 169daaa858bSChristoph Hellwig 1702930f817SHannes Reinecke void scsi_dh_add_device(struct scsi_device *sdev) 171daaa858bSChristoph Hellwig { 172d95dbff2SChristoph Hellwig struct scsi_device_handler *devinfo = NULL; 173d95dbff2SChristoph Hellwig const char *drv; 174daaa858bSChristoph Hellwig 175d95dbff2SChristoph Hellwig drv = scsi_dh_find_driver(sdev); 176d95dbff2SChristoph Hellwig if (drv) 177d6a32b98SChristoph Hellwig devinfo = __scsi_dh_lookup(drv); 1782930f817SHannes Reinecke /* 1792930f817SHannes Reinecke * device_handler is optional, so ignore errors 1802930f817SHannes Reinecke * from scsi_dh_handler_attach() 1812930f817SHannes Reinecke */ 182daaa858bSChristoph Hellwig if (devinfo) 1832930f817SHannes Reinecke (void)scsi_dh_handler_attach(sdev, devinfo); 184daaa858bSChristoph Hellwig } 185daaa858bSChristoph Hellwig 18623695e41SJunichi Nomura void scsi_dh_release_device(struct scsi_device *sdev) 187daaa858bSChristoph Hellwig { 188ee14c674SChristoph Hellwig if (sdev->handler) 189daaa858bSChristoph Hellwig scsi_dh_handler_detach(sdev); 19023695e41SJunichi Nomura } 19123695e41SJunichi Nomura 192daaa858bSChristoph Hellwig /* 193daaa858bSChristoph Hellwig * scsi_register_device_handler - register a device handler personality 194daaa858bSChristoph Hellwig * module. 195daaa858bSChristoph Hellwig * @scsi_dh - device handler to be registered. 196daaa858bSChristoph Hellwig * 197daaa858bSChristoph Hellwig * Returns 0 on success, -EBUSY if handler already registered. 198daaa858bSChristoph Hellwig */ 199daaa858bSChristoph Hellwig int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) 200daaa858bSChristoph Hellwig { 201daaa858bSChristoph Hellwig if (__scsi_dh_lookup(scsi_dh->name)) 202daaa858bSChristoph Hellwig return -EBUSY; 203daaa858bSChristoph Hellwig 204daaa858bSChristoph Hellwig if (!scsi_dh->attach || !scsi_dh->detach) 205daaa858bSChristoph Hellwig return -EINVAL; 206daaa858bSChristoph Hellwig 207daaa858bSChristoph Hellwig spin_lock(&list_lock); 208daaa858bSChristoph Hellwig list_add(&scsi_dh->list, &scsi_dh_list); 209daaa858bSChristoph Hellwig spin_unlock(&list_lock); 210daaa858bSChristoph Hellwig 211daaa858bSChristoph Hellwig printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name); 212daaa858bSChristoph Hellwig 213daaa858bSChristoph Hellwig return SCSI_DH_OK; 214daaa858bSChristoph Hellwig } 215daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_register_device_handler); 216daaa858bSChristoph Hellwig 217daaa858bSChristoph Hellwig /* 218daaa858bSChristoph Hellwig * scsi_unregister_device_handler - register a device handler personality 219daaa858bSChristoph Hellwig * module. 220daaa858bSChristoph Hellwig * @scsi_dh - device handler to be unregistered. 221daaa858bSChristoph Hellwig * 222daaa858bSChristoph Hellwig * Returns 0 on success, -ENODEV if handler not registered. 223daaa858bSChristoph Hellwig */ 224daaa858bSChristoph Hellwig int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) 225daaa858bSChristoph Hellwig { 226daaa858bSChristoph Hellwig if (!__scsi_dh_lookup(scsi_dh->name)) 227daaa858bSChristoph Hellwig return -ENODEV; 228daaa858bSChristoph Hellwig 229daaa858bSChristoph Hellwig spin_lock(&list_lock); 230daaa858bSChristoph Hellwig list_del(&scsi_dh->list); 231daaa858bSChristoph Hellwig spin_unlock(&list_lock); 232daaa858bSChristoph Hellwig printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name); 233daaa858bSChristoph Hellwig 234daaa858bSChristoph Hellwig return SCSI_DH_OK; 235daaa858bSChristoph Hellwig } 236daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); 237daaa858bSChristoph Hellwig 238daaa858bSChristoph Hellwig /* 239daaa858bSChristoph Hellwig * scsi_dh_activate - activate the path associated with the scsi_device 240daaa858bSChristoph Hellwig * corresponding to the given request queue. 241daaa858bSChristoph Hellwig * Returns immediately without waiting for activation to be completed. 242daaa858bSChristoph Hellwig * @q - Request queue that is associated with the scsi_device to be 243daaa858bSChristoph Hellwig * activated. 244daaa858bSChristoph Hellwig * @fn - Function to be called upon completion of the activation. 245daaa858bSChristoph Hellwig * Function fn is called with data (below) and the error code. 246daaa858bSChristoph Hellwig * Function fn may be called from the same calling context. So, 247daaa858bSChristoph Hellwig * do not hold the lock in the caller which may be needed in fn. 248daaa858bSChristoph Hellwig * @data - data passed to the function fn upon completion. 249daaa858bSChristoph Hellwig * 250daaa858bSChristoph Hellwig */ 251daaa858bSChristoph Hellwig int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) 252daaa858bSChristoph Hellwig { 253daaa858bSChristoph Hellwig struct scsi_device *sdev; 254e959ed9aSChristoph Hellwig int err = SCSI_DH_NOSYS; 255daaa858bSChristoph Hellwig 256857de6e0SHannes Reinecke sdev = scsi_device_from_queue(q); 257daaa858bSChristoph Hellwig if (!sdev) { 258daaa858bSChristoph Hellwig if (fn) 259daaa858bSChristoph Hellwig fn(data, err); 260daaa858bSChristoph Hellwig return err; 261daaa858bSChristoph Hellwig } 262daaa858bSChristoph Hellwig 263e959ed9aSChristoph Hellwig if (!sdev->handler) 264e959ed9aSChristoph Hellwig goto out_fn; 265710105fdSHannes Reinecke err = SCSI_DH_NOTCONN; 266e959ed9aSChristoph Hellwig if (sdev->sdev_state == SDEV_CANCEL || 267daaa858bSChristoph Hellwig sdev->sdev_state == SDEV_DEL) 268e959ed9aSChristoph Hellwig goto out_fn; 269daaa858bSChristoph Hellwig 270e959ed9aSChristoph Hellwig err = SCSI_DH_DEV_OFFLINED; 271e959ed9aSChristoph Hellwig if (sdev->sdev_state == SDEV_OFFLINE) 272e959ed9aSChristoph Hellwig goto out_fn; 273daaa858bSChristoph Hellwig 274ee14c674SChristoph Hellwig if (sdev->handler->activate) 275ee14c674SChristoph Hellwig err = sdev->handler->activate(sdev, fn, data); 276e959ed9aSChristoph Hellwig 277e959ed9aSChristoph Hellwig out_put_device: 278e959ed9aSChristoph Hellwig put_device(&sdev->sdev_gendev); 279daaa858bSChristoph Hellwig return err; 280e959ed9aSChristoph Hellwig 281e959ed9aSChristoph Hellwig out_fn: 282e959ed9aSChristoph Hellwig if (fn) 283e959ed9aSChristoph Hellwig fn(data, err); 284e959ed9aSChristoph Hellwig goto out_put_device; 285daaa858bSChristoph Hellwig } 286daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_activate); 287daaa858bSChristoph Hellwig 288daaa858bSChristoph Hellwig /* 289daaa858bSChristoph Hellwig * scsi_dh_set_params - set the parameters for the device as per the 290daaa858bSChristoph Hellwig * string specified in params. 291daaa858bSChristoph Hellwig * @q - Request queue that is associated with the scsi_device for 292daaa858bSChristoph Hellwig * which the parameters to be set. 293daaa858bSChristoph Hellwig * @params - parameters in the following format 294daaa858bSChristoph Hellwig * "no_of_params\0param1\0param2\0param3\0...\0" 295daaa858bSChristoph Hellwig * for example, string for 2 parameters with value 10 and 21 296daaa858bSChristoph Hellwig * is specified as "2\010\021\0". 297daaa858bSChristoph Hellwig */ 298daaa858bSChristoph Hellwig int scsi_dh_set_params(struct request_queue *q, const char *params) 299daaa858bSChristoph Hellwig { 300daaa858bSChristoph Hellwig struct scsi_device *sdev; 301e959ed9aSChristoph Hellwig int err = -SCSI_DH_NOSYS; 302daaa858bSChristoph Hellwig 303857de6e0SHannes Reinecke sdev = scsi_device_from_queue(q); 304e959ed9aSChristoph Hellwig if (!sdev) 305daaa858bSChristoph Hellwig return err; 306e959ed9aSChristoph Hellwig 307e959ed9aSChristoph Hellwig if (sdev->handler && sdev->handler->set_params) 308ee14c674SChristoph Hellwig err = sdev->handler->set_params(sdev, params); 309daaa858bSChristoph Hellwig put_device(&sdev->sdev_gendev); 310daaa858bSChristoph Hellwig return err; 311daaa858bSChristoph Hellwig } 312daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_set_params); 313daaa858bSChristoph Hellwig 314daaa858bSChristoph Hellwig /* 315daaa858bSChristoph Hellwig * scsi_dh_attach - Attach device handler 316daaa858bSChristoph Hellwig * @q - Request queue that is associated with the scsi_device 317daaa858bSChristoph Hellwig * the handler should be attached to 318daaa858bSChristoph Hellwig * @name - name of the handler to attach 319daaa858bSChristoph Hellwig */ 320daaa858bSChristoph Hellwig int scsi_dh_attach(struct request_queue *q, const char *name) 321daaa858bSChristoph Hellwig { 322daaa858bSChristoph Hellwig struct scsi_device *sdev; 323daaa858bSChristoph Hellwig struct scsi_device_handler *scsi_dh; 324daaa858bSChristoph Hellwig int err = 0; 325daaa858bSChristoph Hellwig 326857de6e0SHannes Reinecke sdev = scsi_device_from_queue(q); 327e959ed9aSChristoph Hellwig if (!sdev) 328e959ed9aSChristoph Hellwig return -ENODEV; 329e959ed9aSChristoph Hellwig 330daaa858bSChristoph Hellwig scsi_dh = scsi_dh_lookup(name); 331e959ed9aSChristoph Hellwig if (!scsi_dh) { 332e959ed9aSChristoph Hellwig err = -EINVAL; 333e959ed9aSChristoph Hellwig goto out_put_device; 334e959ed9aSChristoph Hellwig } 335daaa858bSChristoph Hellwig 336ee14c674SChristoph Hellwig if (sdev->handler) { 337ee14c674SChristoph Hellwig if (sdev->handler != scsi_dh) 338daaa858bSChristoph Hellwig err = -EBUSY; 339daaa858bSChristoph Hellwig goto out_put_device; 340daaa858bSChristoph Hellwig } 341daaa858bSChristoph Hellwig 342daaa858bSChristoph Hellwig err = scsi_dh_handler_attach(sdev, scsi_dh); 343daaa858bSChristoph Hellwig 344daaa858bSChristoph Hellwig out_put_device: 345daaa858bSChristoph Hellwig put_device(&sdev->sdev_gendev); 346daaa858bSChristoph Hellwig return err; 347daaa858bSChristoph Hellwig } 348daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_attach); 349daaa858bSChristoph Hellwig 350daaa858bSChristoph Hellwig /* 351daaa858bSChristoph Hellwig * scsi_dh_attached_handler_name - Get attached device handler's name 352daaa858bSChristoph Hellwig * @q - Request queue that is associated with the scsi_device 353daaa858bSChristoph Hellwig * that may have a device handler attached 354daaa858bSChristoph Hellwig * @gfp - the GFP mask used in the kmalloc() call when allocating memory 355daaa858bSChristoph Hellwig * 356daaa858bSChristoph Hellwig * Returns name of attached handler, NULL if no handler is attached. 357daaa858bSChristoph Hellwig * Caller must take care to free the returned string. 358daaa858bSChristoph Hellwig */ 359daaa858bSChristoph Hellwig const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) 360daaa858bSChristoph Hellwig { 361daaa858bSChristoph Hellwig struct scsi_device *sdev; 362daaa858bSChristoph Hellwig const char *handler_name = NULL; 363daaa858bSChristoph Hellwig 364857de6e0SHannes Reinecke sdev = scsi_device_from_queue(q); 365daaa858bSChristoph Hellwig if (!sdev) 366daaa858bSChristoph Hellwig return NULL; 367daaa858bSChristoph Hellwig 368ee14c674SChristoph Hellwig if (sdev->handler) 369ee14c674SChristoph Hellwig handler_name = kstrdup(sdev->handler->name, gfp); 370daaa858bSChristoph Hellwig put_device(&sdev->sdev_gendev); 371daaa858bSChristoph Hellwig return handler_name; 372daaa858bSChristoph Hellwig } 373daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name); 374