1daaa858bSChristoph Hellwig /* 2daaa858bSChristoph Hellwig * SCSI device handler infrastruture. 3daaa858bSChristoph Hellwig * 4daaa858bSChristoph Hellwig * This program is free software; you can redistribute it and/or modify it 5daaa858bSChristoph Hellwig * under the terms of the GNU General Public License as published by the 6daaa858bSChristoph Hellwig * Free Software Foundation; either version 2 of the License, or (at your 7daaa858bSChristoph Hellwig * option) any later version. 8daaa858bSChristoph Hellwig * 9daaa858bSChristoph Hellwig * This program is distributed in the hope that it will be useful, but 10daaa858bSChristoph Hellwig * WITHOUT ANY WARRANTY; without even the implied warranty of 11daaa858bSChristoph Hellwig * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12daaa858bSChristoph Hellwig * General Public License for more details. 13daaa858bSChristoph Hellwig * 14daaa858bSChristoph Hellwig * You should have received a copy of the GNU General Public License along 15daaa858bSChristoph Hellwig * with this program; if not, write to the Free Software Foundation, Inc., 16daaa858bSChristoph Hellwig * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17daaa858bSChristoph Hellwig * 18daaa858bSChristoph Hellwig * Copyright IBM Corporation, 2007 19daaa858bSChristoph Hellwig * Authors: 20daaa858bSChristoph Hellwig * Chandra Seetharaman <sekharan@us.ibm.com> 21daaa858bSChristoph Hellwig * Mike Anderson <andmike@linux.vnet.ibm.com> 22daaa858bSChristoph Hellwig */ 23daaa858bSChristoph Hellwig 24daaa858bSChristoph Hellwig #include <linux/slab.h> 25daaa858bSChristoph Hellwig #include <linux/module.h> 26daaa858bSChristoph Hellwig #include <scsi/scsi_dh.h> 27daaa858bSChristoph Hellwig #include "scsi_priv.h" 28daaa858bSChristoph Hellwig 29daaa858bSChristoph Hellwig static DEFINE_SPINLOCK(list_lock); 30daaa858bSChristoph Hellwig static LIST_HEAD(scsi_dh_list); 31daaa858bSChristoph Hellwig 32daaa858bSChristoph Hellwig static struct scsi_device_handler *__scsi_dh_lookup(const char *name) 33daaa858bSChristoph Hellwig { 34daaa858bSChristoph Hellwig struct scsi_device_handler *tmp, *found = NULL; 35daaa858bSChristoph Hellwig 36daaa858bSChristoph Hellwig spin_lock(&list_lock); 37daaa858bSChristoph Hellwig list_for_each_entry(tmp, &scsi_dh_list, list) { 38daaa858bSChristoph Hellwig if (!strncmp(tmp->name, name, strlen(tmp->name))) { 39daaa858bSChristoph Hellwig found = tmp; 40daaa858bSChristoph Hellwig break; 41daaa858bSChristoph Hellwig } 42daaa858bSChristoph Hellwig } 43daaa858bSChristoph Hellwig spin_unlock(&list_lock); 44daaa858bSChristoph Hellwig return found; 45daaa858bSChristoph Hellwig } 46daaa858bSChristoph Hellwig 47daaa858bSChristoph Hellwig static struct scsi_device_handler *scsi_dh_lookup(const char *name) 48daaa858bSChristoph Hellwig { 49daaa858bSChristoph Hellwig struct scsi_device_handler *dh; 50daaa858bSChristoph Hellwig 51daaa858bSChristoph Hellwig dh = __scsi_dh_lookup(name); 52daaa858bSChristoph Hellwig if (!dh) { 53daaa858bSChristoph Hellwig request_module(name); 54daaa858bSChristoph Hellwig dh = __scsi_dh_lookup(name); 55daaa858bSChristoph Hellwig } 56daaa858bSChristoph Hellwig 57daaa858bSChristoph Hellwig return dh; 58daaa858bSChristoph Hellwig } 59daaa858bSChristoph Hellwig 60daaa858bSChristoph Hellwig /* 61daaa858bSChristoph Hellwig * device_handler_match_function - Match a device handler to a device 62daaa858bSChristoph Hellwig * @sdev - SCSI device to be tested 63daaa858bSChristoph Hellwig * 64daaa858bSChristoph Hellwig * Tests @sdev against the match function of all registered device_handler. 65daaa858bSChristoph Hellwig * Returns the found device handler or NULL if not found. 66daaa858bSChristoph Hellwig */ 67daaa858bSChristoph Hellwig static struct scsi_device_handler * 68daaa858bSChristoph Hellwig device_handler_match_function(struct scsi_device *sdev) 69daaa858bSChristoph Hellwig { 70daaa858bSChristoph Hellwig struct scsi_device_handler *tmp_dh, *found_dh = NULL; 71daaa858bSChristoph Hellwig 72daaa858bSChristoph Hellwig spin_lock(&list_lock); 73daaa858bSChristoph Hellwig list_for_each_entry(tmp_dh, &scsi_dh_list, list) { 74daaa858bSChristoph Hellwig if (tmp_dh->match && tmp_dh->match(sdev)) { 75daaa858bSChristoph Hellwig found_dh = tmp_dh; 76daaa858bSChristoph Hellwig break; 77daaa858bSChristoph Hellwig } 78daaa858bSChristoph Hellwig } 79daaa858bSChristoph Hellwig spin_unlock(&list_lock); 80daaa858bSChristoph Hellwig return found_dh; 81daaa858bSChristoph Hellwig } 82daaa858bSChristoph Hellwig 83daaa858bSChristoph Hellwig /* 84daaa858bSChristoph Hellwig * device_handler_match - Attach a device handler to a device 85daaa858bSChristoph Hellwig * @scsi_dh - The device handler to match against or NULL 86daaa858bSChristoph Hellwig * @sdev - SCSI device to be tested against @scsi_dh 87daaa858bSChristoph Hellwig * 88daaa858bSChristoph Hellwig * Tests @sdev against the device handler @scsi_dh or against 89daaa858bSChristoph Hellwig * all registered device_handler if @scsi_dh == NULL. 90daaa858bSChristoph Hellwig * Returns the found device handler or NULL if not found. 91daaa858bSChristoph Hellwig */ 92daaa858bSChristoph Hellwig static struct scsi_device_handler * 93daaa858bSChristoph Hellwig device_handler_match(struct scsi_device_handler *scsi_dh, 94daaa858bSChristoph Hellwig struct scsi_device *sdev) 95daaa858bSChristoph Hellwig { 96daaa858bSChristoph Hellwig struct scsi_device_handler *found_dh; 97daaa858bSChristoph Hellwig 98daaa858bSChristoph Hellwig found_dh = device_handler_match_function(sdev); 99daaa858bSChristoph Hellwig 100daaa858bSChristoph Hellwig if (scsi_dh && found_dh != scsi_dh) 101daaa858bSChristoph Hellwig found_dh = NULL; 102daaa858bSChristoph Hellwig 103daaa858bSChristoph Hellwig return found_dh; 104daaa858bSChristoph Hellwig } 105daaa858bSChristoph Hellwig 106daaa858bSChristoph Hellwig /* 107daaa858bSChristoph Hellwig * scsi_dh_handler_attach - Attach a device handler to a device 108daaa858bSChristoph Hellwig * @sdev - SCSI device the device handler should attach to 109daaa858bSChristoph Hellwig * @scsi_dh - The device handler to attach 110daaa858bSChristoph Hellwig */ 111daaa858bSChristoph Hellwig static int scsi_dh_handler_attach(struct scsi_device *sdev, 112daaa858bSChristoph Hellwig struct scsi_device_handler *scsi_dh) 113daaa858bSChristoph Hellwig { 114daaa858bSChristoph Hellwig struct scsi_dh_data *d; 115daaa858bSChristoph Hellwig 116daaa858bSChristoph Hellwig if (!try_module_get(scsi_dh->module)) 117daaa858bSChristoph Hellwig return -EINVAL; 118daaa858bSChristoph Hellwig 119daaa858bSChristoph Hellwig d = scsi_dh->attach(sdev); 120daaa858bSChristoph Hellwig if (IS_ERR(d)) { 121daaa858bSChristoph Hellwig sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%ld)\n", 122daaa858bSChristoph Hellwig scsi_dh->name, PTR_ERR(d)); 123daaa858bSChristoph Hellwig module_put(scsi_dh->module); 124daaa858bSChristoph Hellwig return PTR_ERR(d); 125daaa858bSChristoph Hellwig } 126daaa858bSChristoph Hellwig 127daaa858bSChristoph Hellwig d->scsi_dh = scsi_dh; 128daaa858bSChristoph Hellwig d->sdev = sdev; 129daaa858bSChristoph Hellwig 130daaa858bSChristoph Hellwig spin_lock_irq(sdev->request_queue->queue_lock); 131daaa858bSChristoph Hellwig sdev->scsi_dh_data = d; 132daaa858bSChristoph Hellwig spin_unlock_irq(sdev->request_queue->queue_lock); 133daaa858bSChristoph Hellwig return 0; 134daaa858bSChristoph Hellwig } 135daaa858bSChristoph Hellwig 136daaa858bSChristoph Hellwig /* 137daaa858bSChristoph Hellwig * scsi_dh_handler_detach - Detach a device handler from a device 138daaa858bSChristoph Hellwig * @sdev - SCSI device the device handler should be detached from 139daaa858bSChristoph Hellwig */ 140daaa858bSChristoph Hellwig static void scsi_dh_handler_detach(struct scsi_device *sdev) 141daaa858bSChristoph Hellwig { 142daaa858bSChristoph Hellwig struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; 143daaa858bSChristoph Hellwig struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh; 144daaa858bSChristoph Hellwig 145daaa858bSChristoph Hellwig scsi_dh->detach(sdev); 146daaa858bSChristoph Hellwig 147daaa858bSChristoph Hellwig spin_lock_irq(sdev->request_queue->queue_lock); 148daaa858bSChristoph Hellwig sdev->scsi_dh_data = NULL; 149daaa858bSChristoph Hellwig spin_unlock_irq(sdev->request_queue->queue_lock); 150daaa858bSChristoph Hellwig 151daaa858bSChristoph Hellwig sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name); 152daaa858bSChristoph Hellwig module_put(scsi_dh->module); 153daaa858bSChristoph Hellwig } 154daaa858bSChristoph Hellwig 155daaa858bSChristoph Hellwig /* 156daaa858bSChristoph Hellwig * Functions for sysfs attribute 'dh_state' 157daaa858bSChristoph Hellwig */ 158daaa858bSChristoph Hellwig static ssize_t 159daaa858bSChristoph Hellwig store_dh_state(struct device *dev, struct device_attribute *attr, 160daaa858bSChristoph Hellwig const char *buf, size_t count) 161daaa858bSChristoph Hellwig { 162daaa858bSChristoph Hellwig struct scsi_device *sdev = to_scsi_device(dev); 163daaa858bSChristoph Hellwig struct scsi_device_handler *scsi_dh; 164daaa858bSChristoph Hellwig int err = -EINVAL; 165daaa858bSChristoph Hellwig 166daaa858bSChristoph Hellwig if (sdev->sdev_state == SDEV_CANCEL || 167daaa858bSChristoph Hellwig sdev->sdev_state == SDEV_DEL) 168daaa858bSChristoph Hellwig return -ENODEV; 169daaa858bSChristoph Hellwig 170daaa858bSChristoph Hellwig if (!sdev->scsi_dh_data) { 171daaa858bSChristoph Hellwig /* 172daaa858bSChristoph Hellwig * Attach to a device handler 173daaa858bSChristoph Hellwig */ 174daaa858bSChristoph Hellwig scsi_dh = scsi_dh_lookup(buf); 175daaa858bSChristoph Hellwig if (!scsi_dh) 176daaa858bSChristoph Hellwig return err; 177daaa858bSChristoph Hellwig err = scsi_dh_handler_attach(sdev, scsi_dh); 178daaa858bSChristoph Hellwig } else { 179daaa858bSChristoph Hellwig scsi_dh = sdev->scsi_dh_data->scsi_dh; 180daaa858bSChristoph Hellwig if (!strncmp(buf, "detach", 6)) { 181daaa858bSChristoph Hellwig /* 182daaa858bSChristoph Hellwig * Detach from a device handler 183daaa858bSChristoph Hellwig */ 184daaa858bSChristoph Hellwig scsi_dh_handler_detach(sdev); 185daaa858bSChristoph Hellwig err = 0; 186daaa858bSChristoph Hellwig } else if (!strncmp(buf, "activate", 8)) { 187daaa858bSChristoph Hellwig /* 188daaa858bSChristoph Hellwig * Activate a device handler 189daaa858bSChristoph Hellwig */ 190daaa858bSChristoph Hellwig if (scsi_dh->activate) 191daaa858bSChristoph Hellwig err = scsi_dh->activate(sdev, NULL, NULL); 192daaa858bSChristoph Hellwig else 193daaa858bSChristoph Hellwig err = 0; 194daaa858bSChristoph Hellwig } 195daaa858bSChristoph Hellwig } 196daaa858bSChristoph Hellwig 197daaa858bSChristoph Hellwig return err<0?err:count; 198daaa858bSChristoph Hellwig } 199daaa858bSChristoph Hellwig 200daaa858bSChristoph Hellwig static ssize_t 201daaa858bSChristoph Hellwig show_dh_state(struct device *dev, struct device_attribute *attr, char *buf) 202daaa858bSChristoph Hellwig { 203daaa858bSChristoph Hellwig struct scsi_device *sdev = to_scsi_device(dev); 204daaa858bSChristoph Hellwig 205daaa858bSChristoph Hellwig if (!sdev->scsi_dh_data) 206daaa858bSChristoph Hellwig return snprintf(buf, 20, "detached\n"); 207daaa858bSChristoph Hellwig 208daaa858bSChristoph Hellwig return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name); 209daaa858bSChristoph Hellwig } 210daaa858bSChristoph Hellwig 211daaa858bSChristoph Hellwig static struct device_attribute scsi_dh_state_attr = 212daaa858bSChristoph Hellwig __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state, 213daaa858bSChristoph Hellwig store_dh_state); 214daaa858bSChristoph Hellwig 215daaa858bSChristoph Hellwig /* 216daaa858bSChristoph Hellwig * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh 217daaa858bSChristoph Hellwig */ 218daaa858bSChristoph Hellwig static int scsi_dh_sysfs_attr_add(struct device *dev, void *data) 219daaa858bSChristoph Hellwig { 220daaa858bSChristoph Hellwig struct scsi_device *sdev; 221daaa858bSChristoph Hellwig int err; 222daaa858bSChristoph Hellwig 223daaa858bSChristoph Hellwig if (!scsi_is_sdev_device(dev)) 224daaa858bSChristoph Hellwig return 0; 225daaa858bSChristoph Hellwig 226daaa858bSChristoph Hellwig sdev = to_scsi_device(dev); 227daaa858bSChristoph Hellwig 228daaa858bSChristoph Hellwig err = device_create_file(&sdev->sdev_gendev, 229daaa858bSChristoph Hellwig &scsi_dh_state_attr); 230daaa858bSChristoph Hellwig 231daaa858bSChristoph Hellwig return 0; 232daaa858bSChristoph Hellwig } 233daaa858bSChristoph Hellwig 234daaa858bSChristoph Hellwig /* 235daaa858bSChristoph Hellwig * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh 236daaa858bSChristoph Hellwig */ 237daaa858bSChristoph Hellwig static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data) 238daaa858bSChristoph Hellwig { 239daaa858bSChristoph Hellwig struct scsi_device *sdev; 240daaa858bSChristoph Hellwig 241daaa858bSChristoph Hellwig if (!scsi_is_sdev_device(dev)) 242daaa858bSChristoph Hellwig return 0; 243daaa858bSChristoph Hellwig 244daaa858bSChristoph Hellwig sdev = to_scsi_device(dev); 245daaa858bSChristoph Hellwig 246daaa858bSChristoph Hellwig device_remove_file(&sdev->sdev_gendev, 247daaa858bSChristoph Hellwig &scsi_dh_state_attr); 248daaa858bSChristoph Hellwig 249daaa858bSChristoph Hellwig return 0; 250daaa858bSChristoph Hellwig } 251daaa858bSChristoph Hellwig 252daaa858bSChristoph Hellwig /* 253daaa858bSChristoph Hellwig * scsi_dh_notifier - notifier chain callback 254daaa858bSChristoph Hellwig */ 255daaa858bSChristoph Hellwig static int scsi_dh_notifier(struct notifier_block *nb, 256daaa858bSChristoph Hellwig unsigned long action, void *data) 257daaa858bSChristoph Hellwig { 258daaa858bSChristoph Hellwig struct device *dev = data; 259daaa858bSChristoph Hellwig struct scsi_device *sdev; 260daaa858bSChristoph Hellwig int err = 0; 261daaa858bSChristoph Hellwig struct scsi_device_handler *devinfo = NULL; 262daaa858bSChristoph Hellwig 263daaa858bSChristoph Hellwig if (!scsi_is_sdev_device(dev)) 264daaa858bSChristoph Hellwig return 0; 265daaa858bSChristoph Hellwig 266daaa858bSChristoph Hellwig sdev = to_scsi_device(dev); 267daaa858bSChristoph Hellwig 268daaa858bSChristoph Hellwig if (action == BUS_NOTIFY_ADD_DEVICE) { 269daaa858bSChristoph Hellwig err = device_create_file(dev, &scsi_dh_state_attr); 270daaa858bSChristoph Hellwig /* don't care about err */ 271daaa858bSChristoph Hellwig devinfo = device_handler_match(NULL, sdev); 272daaa858bSChristoph Hellwig if (devinfo) 273daaa858bSChristoph Hellwig err = scsi_dh_handler_attach(sdev, devinfo); 274daaa858bSChristoph Hellwig } else if (action == BUS_NOTIFY_DEL_DEVICE) { 275daaa858bSChristoph Hellwig device_remove_file(dev, &scsi_dh_state_attr); 276daaa858bSChristoph Hellwig if (sdev->scsi_dh_data) 277daaa858bSChristoph Hellwig scsi_dh_handler_detach(sdev); 278daaa858bSChristoph Hellwig } 279daaa858bSChristoph Hellwig return err; 280daaa858bSChristoph Hellwig } 281daaa858bSChristoph Hellwig 282daaa858bSChristoph Hellwig /* 283daaa858bSChristoph Hellwig * scsi_dh_notifier_add - Callback for scsi_register_device_handler 284daaa858bSChristoph Hellwig */ 285daaa858bSChristoph Hellwig static int scsi_dh_notifier_add(struct device *dev, void *data) 286daaa858bSChristoph Hellwig { 287daaa858bSChristoph Hellwig struct scsi_device_handler *scsi_dh = data; 288daaa858bSChristoph Hellwig struct scsi_device *sdev; 289daaa858bSChristoph Hellwig 290daaa858bSChristoph Hellwig if (!scsi_is_sdev_device(dev)) 291daaa858bSChristoph Hellwig return 0; 292daaa858bSChristoph Hellwig 293daaa858bSChristoph Hellwig if (!get_device(dev)) 294daaa858bSChristoph Hellwig return 0; 295daaa858bSChristoph Hellwig 296daaa858bSChristoph Hellwig sdev = to_scsi_device(dev); 297daaa858bSChristoph Hellwig 298daaa858bSChristoph Hellwig if (device_handler_match(scsi_dh, sdev)) 299daaa858bSChristoph Hellwig scsi_dh_handler_attach(sdev, scsi_dh); 300daaa858bSChristoph Hellwig 301daaa858bSChristoph Hellwig put_device(dev); 302daaa858bSChristoph Hellwig 303daaa858bSChristoph Hellwig return 0; 304daaa858bSChristoph Hellwig } 305daaa858bSChristoph Hellwig 306daaa858bSChristoph Hellwig /* 307daaa858bSChristoph Hellwig * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler 308daaa858bSChristoph Hellwig */ 309daaa858bSChristoph Hellwig static int scsi_dh_notifier_remove(struct device *dev, void *data) 310daaa858bSChristoph Hellwig { 311daaa858bSChristoph Hellwig struct scsi_device_handler *scsi_dh = data; 312daaa858bSChristoph Hellwig struct scsi_device *sdev; 313daaa858bSChristoph Hellwig 314daaa858bSChristoph Hellwig if (!scsi_is_sdev_device(dev)) 315daaa858bSChristoph Hellwig return 0; 316daaa858bSChristoph Hellwig 317daaa858bSChristoph Hellwig if (!get_device(dev)) 318daaa858bSChristoph Hellwig return 0; 319daaa858bSChristoph Hellwig 320daaa858bSChristoph Hellwig sdev = to_scsi_device(dev); 321daaa858bSChristoph Hellwig 322daaa858bSChristoph Hellwig if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh == scsi_dh) 323daaa858bSChristoph Hellwig scsi_dh_handler_detach(sdev); 324daaa858bSChristoph Hellwig 325daaa858bSChristoph Hellwig put_device(dev); 326daaa858bSChristoph Hellwig 327daaa858bSChristoph Hellwig return 0; 328daaa858bSChristoph Hellwig } 329daaa858bSChristoph Hellwig 330daaa858bSChristoph Hellwig /* 331daaa858bSChristoph Hellwig * scsi_register_device_handler - register a device handler personality 332daaa858bSChristoph Hellwig * module. 333daaa858bSChristoph Hellwig * @scsi_dh - device handler to be registered. 334daaa858bSChristoph Hellwig * 335daaa858bSChristoph Hellwig * Returns 0 on success, -EBUSY if handler already registered. 336daaa858bSChristoph Hellwig */ 337daaa858bSChristoph Hellwig int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) 338daaa858bSChristoph Hellwig { 339daaa858bSChristoph Hellwig if (__scsi_dh_lookup(scsi_dh->name)) 340daaa858bSChristoph Hellwig return -EBUSY; 341daaa858bSChristoph Hellwig 342daaa858bSChristoph Hellwig if (!scsi_dh->attach || !scsi_dh->detach) 343daaa858bSChristoph Hellwig return -EINVAL; 344daaa858bSChristoph Hellwig 345daaa858bSChristoph Hellwig spin_lock(&list_lock); 346daaa858bSChristoph Hellwig list_add(&scsi_dh->list, &scsi_dh_list); 347daaa858bSChristoph Hellwig spin_unlock(&list_lock); 348daaa858bSChristoph Hellwig 349daaa858bSChristoph Hellwig bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); 350daaa858bSChristoph Hellwig printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name); 351daaa858bSChristoph Hellwig 352daaa858bSChristoph Hellwig return SCSI_DH_OK; 353daaa858bSChristoph Hellwig } 354daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_register_device_handler); 355daaa858bSChristoph Hellwig 356daaa858bSChristoph Hellwig /* 357daaa858bSChristoph Hellwig * scsi_unregister_device_handler - register a device handler personality 358daaa858bSChristoph Hellwig * module. 359daaa858bSChristoph Hellwig * @scsi_dh - device handler to be unregistered. 360daaa858bSChristoph Hellwig * 361daaa858bSChristoph Hellwig * Returns 0 on success, -ENODEV if handler not registered. 362daaa858bSChristoph Hellwig */ 363daaa858bSChristoph Hellwig int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) 364daaa858bSChristoph Hellwig { 365daaa858bSChristoph Hellwig 366daaa858bSChristoph Hellwig if (!__scsi_dh_lookup(scsi_dh->name)) 367daaa858bSChristoph Hellwig return -ENODEV; 368daaa858bSChristoph Hellwig 369daaa858bSChristoph Hellwig bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, 370daaa858bSChristoph Hellwig scsi_dh_notifier_remove); 371daaa858bSChristoph Hellwig 372daaa858bSChristoph Hellwig spin_lock(&list_lock); 373daaa858bSChristoph Hellwig list_del(&scsi_dh->list); 374daaa858bSChristoph Hellwig spin_unlock(&list_lock); 375daaa858bSChristoph Hellwig printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name); 376daaa858bSChristoph Hellwig 377daaa858bSChristoph Hellwig return SCSI_DH_OK; 378daaa858bSChristoph Hellwig } 379daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); 380daaa858bSChristoph Hellwig 381daaa858bSChristoph Hellwig /* 382daaa858bSChristoph Hellwig * scsi_dh_activate - activate the path associated with the scsi_device 383daaa858bSChristoph Hellwig * corresponding to the given request queue. 384daaa858bSChristoph Hellwig * Returns immediately without waiting for activation to be completed. 385daaa858bSChristoph Hellwig * @q - Request queue that is associated with the scsi_device to be 386daaa858bSChristoph Hellwig * activated. 387daaa858bSChristoph Hellwig * @fn - Function to be called upon completion of the activation. 388daaa858bSChristoph Hellwig * Function fn is called with data (below) and the error code. 389daaa858bSChristoph Hellwig * Function fn may be called from the same calling context. So, 390daaa858bSChristoph Hellwig * do not hold the lock in the caller which may be needed in fn. 391daaa858bSChristoph Hellwig * @data - data passed to the function fn upon completion. 392daaa858bSChristoph Hellwig * 393daaa858bSChristoph Hellwig */ 394daaa858bSChristoph Hellwig int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) 395daaa858bSChristoph Hellwig { 396daaa858bSChristoph Hellwig int err = 0; 397daaa858bSChristoph Hellwig unsigned long flags; 398daaa858bSChristoph Hellwig struct scsi_device *sdev; 399daaa858bSChristoph Hellwig struct scsi_device_handler *scsi_dh = NULL; 400daaa858bSChristoph Hellwig struct device *dev = NULL; 401daaa858bSChristoph Hellwig 402daaa858bSChristoph Hellwig spin_lock_irqsave(q->queue_lock, flags); 403daaa858bSChristoph Hellwig sdev = q->queuedata; 404daaa858bSChristoph Hellwig if (!sdev) { 405daaa858bSChristoph Hellwig spin_unlock_irqrestore(q->queue_lock, flags); 406daaa858bSChristoph Hellwig err = SCSI_DH_NOSYS; 407daaa858bSChristoph Hellwig if (fn) 408daaa858bSChristoph Hellwig fn(data, err); 409daaa858bSChristoph Hellwig return err; 410daaa858bSChristoph Hellwig } 411daaa858bSChristoph Hellwig 412daaa858bSChristoph Hellwig if (sdev->scsi_dh_data) 413daaa858bSChristoph Hellwig scsi_dh = sdev->scsi_dh_data->scsi_dh; 414daaa858bSChristoph Hellwig dev = get_device(&sdev->sdev_gendev); 415daaa858bSChristoph Hellwig if (!scsi_dh || !dev || 416daaa858bSChristoph Hellwig sdev->sdev_state == SDEV_CANCEL || 417daaa858bSChristoph Hellwig sdev->sdev_state == SDEV_DEL) 418daaa858bSChristoph Hellwig err = SCSI_DH_NOSYS; 419daaa858bSChristoph Hellwig if (sdev->sdev_state == SDEV_OFFLINE) 420daaa858bSChristoph Hellwig err = SCSI_DH_DEV_OFFLINED; 421daaa858bSChristoph Hellwig spin_unlock_irqrestore(q->queue_lock, flags); 422daaa858bSChristoph Hellwig 423daaa858bSChristoph Hellwig if (err) { 424daaa858bSChristoph Hellwig if (fn) 425daaa858bSChristoph Hellwig fn(data, err); 426daaa858bSChristoph Hellwig goto out; 427daaa858bSChristoph Hellwig } 428daaa858bSChristoph Hellwig 429daaa858bSChristoph Hellwig if (scsi_dh->activate) 430daaa858bSChristoph Hellwig err = scsi_dh->activate(sdev, fn, data); 431daaa858bSChristoph Hellwig out: 432daaa858bSChristoph Hellwig put_device(dev); 433daaa858bSChristoph Hellwig return err; 434daaa858bSChristoph Hellwig } 435daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_activate); 436daaa858bSChristoph Hellwig 437daaa858bSChristoph Hellwig /* 438daaa858bSChristoph Hellwig * scsi_dh_set_params - set the parameters for the device as per the 439daaa858bSChristoph Hellwig * string specified in params. 440daaa858bSChristoph Hellwig * @q - Request queue that is associated with the scsi_device for 441daaa858bSChristoph Hellwig * which the parameters to be set. 442daaa858bSChristoph Hellwig * @params - parameters in the following format 443daaa858bSChristoph Hellwig * "no_of_params\0param1\0param2\0param3\0...\0" 444daaa858bSChristoph Hellwig * for example, string for 2 parameters with value 10 and 21 445daaa858bSChristoph Hellwig * is specified as "2\010\021\0". 446daaa858bSChristoph Hellwig */ 447daaa858bSChristoph Hellwig int scsi_dh_set_params(struct request_queue *q, const char *params) 448daaa858bSChristoph Hellwig { 449daaa858bSChristoph Hellwig int err = -SCSI_DH_NOSYS; 450daaa858bSChristoph Hellwig unsigned long flags; 451daaa858bSChristoph Hellwig struct scsi_device *sdev; 452daaa858bSChristoph Hellwig struct scsi_device_handler *scsi_dh = NULL; 453daaa858bSChristoph Hellwig 454daaa858bSChristoph Hellwig spin_lock_irqsave(q->queue_lock, flags); 455daaa858bSChristoph Hellwig sdev = q->queuedata; 456daaa858bSChristoph Hellwig if (sdev && sdev->scsi_dh_data) 457daaa858bSChristoph Hellwig scsi_dh = sdev->scsi_dh_data->scsi_dh; 458daaa858bSChristoph Hellwig if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev)) 459daaa858bSChristoph Hellwig err = 0; 460daaa858bSChristoph Hellwig spin_unlock_irqrestore(q->queue_lock, flags); 461daaa858bSChristoph Hellwig 462daaa858bSChristoph Hellwig if (err) 463daaa858bSChristoph Hellwig return err; 464daaa858bSChristoph Hellwig err = scsi_dh->set_params(sdev, params); 465daaa858bSChristoph Hellwig put_device(&sdev->sdev_gendev); 466daaa858bSChristoph Hellwig return err; 467daaa858bSChristoph Hellwig } 468daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_set_params); 469daaa858bSChristoph Hellwig 470daaa858bSChristoph Hellwig /* 471daaa858bSChristoph Hellwig * scsi_dh_attach - Attach device handler 472daaa858bSChristoph Hellwig * @q - Request queue that is associated with the scsi_device 473daaa858bSChristoph Hellwig * the handler should be attached to 474daaa858bSChristoph Hellwig * @name - name of the handler to attach 475daaa858bSChristoph Hellwig */ 476daaa858bSChristoph Hellwig int scsi_dh_attach(struct request_queue *q, const char *name) 477daaa858bSChristoph Hellwig { 478daaa858bSChristoph Hellwig unsigned long flags; 479daaa858bSChristoph Hellwig struct scsi_device *sdev; 480daaa858bSChristoph Hellwig struct scsi_device_handler *scsi_dh; 481daaa858bSChristoph Hellwig int err = 0; 482daaa858bSChristoph Hellwig 483daaa858bSChristoph Hellwig scsi_dh = scsi_dh_lookup(name); 484daaa858bSChristoph Hellwig if (!scsi_dh) 485daaa858bSChristoph Hellwig return -EINVAL; 486daaa858bSChristoph Hellwig 487daaa858bSChristoph Hellwig spin_lock_irqsave(q->queue_lock, flags); 488daaa858bSChristoph Hellwig sdev = q->queuedata; 489daaa858bSChristoph Hellwig if (!sdev || !get_device(&sdev->sdev_gendev)) 490daaa858bSChristoph Hellwig err = -ENODEV; 491daaa858bSChristoph Hellwig spin_unlock_irqrestore(q->queue_lock, flags); 492daaa858bSChristoph Hellwig 493daaa858bSChristoph Hellwig if (err) 494daaa858bSChristoph Hellwig return err; 495daaa858bSChristoph Hellwig 496daaa858bSChristoph Hellwig if (sdev->scsi_dh_data) { 497daaa858bSChristoph Hellwig if (sdev->scsi_dh_data->scsi_dh != scsi_dh) 498daaa858bSChristoph Hellwig err = -EBUSY; 499daaa858bSChristoph Hellwig goto out_put_device; 500daaa858bSChristoph Hellwig } 501daaa858bSChristoph Hellwig 502daaa858bSChristoph Hellwig err = scsi_dh_handler_attach(sdev, scsi_dh); 503daaa858bSChristoph Hellwig 504daaa858bSChristoph Hellwig out_put_device: 505daaa858bSChristoph Hellwig put_device(&sdev->sdev_gendev); 506daaa858bSChristoph Hellwig return err; 507daaa858bSChristoph Hellwig } 508daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_attach); 509daaa858bSChristoph Hellwig 510daaa858bSChristoph Hellwig /* 511daaa858bSChristoph Hellwig * scsi_dh_attached_handler_name - Get attached device handler's name 512daaa858bSChristoph Hellwig * @q - Request queue that is associated with the scsi_device 513daaa858bSChristoph Hellwig * that may have a device handler attached 514daaa858bSChristoph Hellwig * @gfp - the GFP mask used in the kmalloc() call when allocating memory 515daaa858bSChristoph Hellwig * 516daaa858bSChristoph Hellwig * Returns name of attached handler, NULL if no handler is attached. 517daaa858bSChristoph Hellwig * Caller must take care to free the returned string. 518daaa858bSChristoph Hellwig */ 519daaa858bSChristoph Hellwig const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) 520daaa858bSChristoph Hellwig { 521daaa858bSChristoph Hellwig unsigned long flags; 522daaa858bSChristoph Hellwig struct scsi_device *sdev; 523daaa858bSChristoph Hellwig const char *handler_name = NULL; 524daaa858bSChristoph Hellwig 525daaa858bSChristoph Hellwig spin_lock_irqsave(q->queue_lock, flags); 526daaa858bSChristoph Hellwig sdev = q->queuedata; 527daaa858bSChristoph Hellwig if (!sdev || !get_device(&sdev->sdev_gendev)) 528daaa858bSChristoph Hellwig sdev = NULL; 529daaa858bSChristoph Hellwig spin_unlock_irqrestore(q->queue_lock, flags); 530daaa858bSChristoph Hellwig 531daaa858bSChristoph Hellwig if (!sdev) 532daaa858bSChristoph Hellwig return NULL; 533daaa858bSChristoph Hellwig 534daaa858bSChristoph Hellwig if (sdev->scsi_dh_data) 535daaa858bSChristoph Hellwig handler_name = kstrdup(sdev->scsi_dh_data->scsi_dh->name, gfp); 536daaa858bSChristoph Hellwig 537daaa858bSChristoph Hellwig put_device(&sdev->sdev_gendev); 538daaa858bSChristoph Hellwig return handler_name; 539daaa858bSChristoph Hellwig } 540daaa858bSChristoph Hellwig EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name); 541daaa858bSChristoph Hellwig 542daaa858bSChristoph Hellwig static struct notifier_block scsi_dh_nb = { 543daaa858bSChristoph Hellwig .notifier_call = scsi_dh_notifier 544daaa858bSChristoph Hellwig }; 545daaa858bSChristoph Hellwig 546daaa858bSChristoph Hellwig static int __init scsi_dh_init(void) 547daaa858bSChristoph Hellwig { 548daaa858bSChristoph Hellwig int r; 549daaa858bSChristoph Hellwig 550daaa858bSChristoph Hellwig r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb); 551daaa858bSChristoph Hellwig 552daaa858bSChristoph Hellwig if (!r) 553daaa858bSChristoph Hellwig bus_for_each_dev(&scsi_bus_type, NULL, NULL, 554daaa858bSChristoph Hellwig scsi_dh_sysfs_attr_add); 555daaa858bSChristoph Hellwig 556daaa858bSChristoph Hellwig return r; 557daaa858bSChristoph Hellwig } 558daaa858bSChristoph Hellwig 559daaa858bSChristoph Hellwig static void __exit scsi_dh_exit(void) 560daaa858bSChristoph Hellwig { 561daaa858bSChristoph Hellwig bus_for_each_dev(&scsi_bus_type, NULL, NULL, 562daaa858bSChristoph Hellwig scsi_dh_sysfs_attr_remove); 563daaa858bSChristoph Hellwig bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb); 564daaa858bSChristoph Hellwig } 565daaa858bSChristoph Hellwig 566daaa858bSChristoph Hellwig module_init(scsi_dh_init); 567daaa858bSChristoph Hellwig module_exit(scsi_dh_exit); 568daaa858bSChristoph Hellwig 569daaa858bSChristoph Hellwig MODULE_DESCRIPTION("SCSI device handler"); 570daaa858bSChristoph Hellwig MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>"); 571daaa858bSChristoph Hellwig MODULE_LICENSE("GPL"); 572