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