scsi_dh.c (9346B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * SCSI device handler infrastructure. 4 * 5 * Copyright IBM Corporation, 2007 6 * 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 device 121 * @sdev - SCSI device the device handler should attach to 122 * @scsi_dh - The device handler to attach 123 */ 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 } else 154 sdev->handler = scsi_dh; 155 156 return ret; 157} 158 159/* 160 * scsi_dh_handler_detach - Detach a device handler from a device 161 * @sdev - SCSI device the device handler should be detached from 162 */ 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 errors 180 * 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 personality 194 * 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 personality 219 * 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_device 240 * 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 be 243 * 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 the 290 * string specified in params. 291 * @q - Request queue that is associated with the scsi_device for 292 * which the parameters to be set. 293 * @params - parameters in the following format 294 * "no_of_params\0param1\0param2\0param3\0...\0" 295 * for example, string for 2 parameters with value 10 and 21 296 * 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 handler 316 * @q - Request queue that is associated with the scsi_device 317 * the handler should be attached to 318 * @name - name of the handler to attach 319 */ 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 name 352 * @q - Request queue that is associated with the scsi_device 353 * that may have a device handler attached 354 * @gfp - the GFP mask used in the kmalloc() call when allocating memory 355 * 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);