diff options
| -rw-r--r-- | drivers/scsi/Makefile | 1 | ||||
| -rw-r--r-- | drivers/scsi/device_handler/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/scsi/device_handler/Makefile | 1 | ||||
| -rw-r--r-- | drivers/scsi/scsi_dh.c | 183 | ||||
| -rw-r--r-- | drivers/scsi/scsi_priv.h | 9 | ||||
| -rw-r--r-- | drivers/scsi/scsi_sysfs.c | 10 | ||||
| -rw-r--r-- | include/scsi/scsi_dh.h | 2 |
7 files changed, 34 insertions, 174 deletions
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 471d08791766..1a8c9b53fafa 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
| @@ -172,6 +172,7 @@ scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o | |||
| 172 | scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o | 172 | scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o |
| 173 | scsi_mod-y += scsi_trace.o scsi_logging.o | 173 | scsi_mod-y += scsi_trace.o scsi_logging.o |
| 174 | scsi_mod-$(CONFIG_PM) += scsi_pm.o | 174 | scsi_mod-$(CONFIG_PM) += scsi_pm.o |
| 175 | scsi_mod-$(CONFIG_SCSI_DH) += scsi_dh.o | ||
| 175 | 176 | ||
| 176 | hv_storvsc-y := storvsc_drv.o | 177 | hv_storvsc-y := storvsc_drv.o |
| 177 | 178 | ||
diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig index 69abd0ad48e2..e5647d59224f 100644 --- a/drivers/scsi/device_handler/Kconfig +++ b/drivers/scsi/device_handler/Kconfig | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | menuconfig SCSI_DH | 5 | menuconfig SCSI_DH |
| 6 | tristate "SCSI Device Handlers" | 6 | bool "SCSI Device Handlers" |
| 7 | depends on SCSI | 7 | depends on SCSI |
| 8 | default n | 8 | default n |
| 9 | help | 9 | help |
diff --git a/drivers/scsi/device_handler/Makefile b/drivers/scsi/device_handler/Makefile index e1d2ea083e15..09866c50fbb4 100644 --- a/drivers/scsi/device_handler/Makefile +++ b/drivers/scsi/device_handler/Makefile | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # | 1 | # |
| 2 | # SCSI Device Handler | 2 | # SCSI Device Handler |
| 3 | # | 3 | # |
| 4 | obj-$(CONFIG_SCSI_DH) += scsi_dh.o | ||
| 5 | obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o | 4 | obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o |
| 6 | obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o | 5 | obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o |
| 7 | obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o | 6 | obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o |
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 3de9b6767be4..f0dfdccc060e 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c | |||
| @@ -57,15 +57,8 @@ static struct scsi_device_handler *scsi_dh_lookup(const char *name) | |||
| 57 | return dh; | 57 | return dh; |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | /* | ||
| 61 | * device_handler_match_function - Match a device handler to a device | ||
| 62 | * @sdev - SCSI device to be tested | ||
| 63 | * | ||
| 64 | * Tests @sdev against the match function of all registered device_handler. | ||
| 65 | * Returns the found device handler or NULL if not found. | ||
| 66 | */ | ||
| 67 | static struct scsi_device_handler * | 60 | static struct scsi_device_handler * |
| 68 | device_handler_match_function(struct scsi_device *sdev) | 61 | device_handler_match(struct scsi_device *sdev) |
| 69 | { | 62 | { |
| 70 | struct scsi_device_handler *tmp_dh, *found_dh = NULL; | 63 | struct scsi_device_handler *tmp_dh, *found_dh = NULL; |
| 71 | 64 | ||
| @@ -81,29 +74,6 @@ device_handler_match_function(struct scsi_device *sdev) | |||
| 81 | } | 74 | } |
| 82 | 75 | ||
| 83 | /* | 76 | /* |
| 84 | * device_handler_match - Attach a device handler to a device | ||
| 85 | * @scsi_dh - The device handler to match against or NULL | ||
| 86 | * @sdev - SCSI device to be tested against @scsi_dh | ||
| 87 | * | ||
| 88 | * Tests @sdev against the device handler @scsi_dh or against | ||
| 89 | * all registered device_handler if @scsi_dh == NULL. | ||
| 90 | * Returns the found device handler or NULL if not found. | ||
| 91 | */ | ||
| 92 | static struct scsi_device_handler * | ||
| 93 | device_handler_match(struct scsi_device_handler *scsi_dh, | ||
| 94 | struct scsi_device *sdev) | ||
| 95 | { | ||
| 96 | struct scsi_device_handler *found_dh; | ||
| 97 | |||
| 98 | found_dh = device_handler_match_function(sdev); | ||
| 99 | |||
| 100 | if (scsi_dh && found_dh != scsi_dh) | ||
| 101 | found_dh = NULL; | ||
| 102 | |||
| 103 | return found_dh; | ||
| 104 | } | ||
| 105 | |||
| 106 | /* | ||
| 107 | * scsi_dh_handler_attach - Attach a device handler to a device | 77 | * scsi_dh_handler_attach - Attach a device handler to a device |
| 108 | * @sdev - SCSI device the device handler should attach to | 78 | * @sdev - SCSI device the device handler should attach to |
| 109 | * @scsi_dh - The device handler to attach | 79 | * @scsi_dh - The device handler to attach |
| @@ -212,119 +182,26 @@ static struct device_attribute scsi_dh_state_attr = | |||
| 212 | __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state, | 182 | __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state, |
| 213 | store_dh_state); | 183 | store_dh_state); |
| 214 | 184 | ||
| 215 | /* | 185 | int scsi_dh_add_device(struct scsi_device *sdev) |
| 216 | * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh | ||
| 217 | */ | ||
| 218 | static int scsi_dh_sysfs_attr_add(struct device *dev, void *data) | ||
| 219 | { | 186 | { |
| 220 | struct scsi_device *sdev; | 187 | struct scsi_device_handler *devinfo; |
| 221 | int err; | 188 | int err; |
| 222 | 189 | ||
| 223 | if (!scsi_is_sdev_device(dev)) | 190 | err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr); |
| 224 | return 0; | 191 | if (err) |
| 225 | 192 | return err; | |
| 226 | sdev = to_scsi_device(dev); | ||
| 227 | |||
| 228 | err = device_create_file(&sdev->sdev_gendev, | ||
| 229 | &scsi_dh_state_attr); | ||
| 230 | |||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | /* | ||
| 235 | * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh | ||
| 236 | */ | ||
| 237 | static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data) | ||
| 238 | { | ||
| 239 | struct scsi_device *sdev; | ||
| 240 | |||
| 241 | if (!scsi_is_sdev_device(dev)) | ||
| 242 | return 0; | ||
| 243 | |||
| 244 | sdev = to_scsi_device(dev); | ||
| 245 | |||
| 246 | device_remove_file(&sdev->sdev_gendev, | ||
| 247 | &scsi_dh_state_attr); | ||
| 248 | |||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | 193 | ||
| 252 | /* | 194 | devinfo = device_handler_match(sdev); |
| 253 | * scsi_dh_notifier - notifier chain callback | 195 | if (devinfo) |
| 254 | */ | 196 | err = scsi_dh_handler_attach(sdev, devinfo); |
| 255 | static int scsi_dh_notifier(struct notifier_block *nb, | ||
| 256 | unsigned long action, void *data) | ||
| 257 | { | ||
| 258 | struct device *dev = data; | ||
| 259 | struct scsi_device *sdev; | ||
| 260 | int err = 0; | ||
| 261 | struct scsi_device_handler *devinfo = NULL; | ||
| 262 | |||
| 263 | if (!scsi_is_sdev_device(dev)) | ||
| 264 | return 0; | ||
| 265 | |||
| 266 | sdev = to_scsi_device(dev); | ||
| 267 | |||
| 268 | if (action == BUS_NOTIFY_ADD_DEVICE) { | ||
| 269 | err = device_create_file(dev, &scsi_dh_state_attr); | ||
| 270 | /* don't care about err */ | ||
| 271 | devinfo = device_handler_match(NULL, sdev); | ||
| 272 | if (devinfo) | ||
| 273 | err = scsi_dh_handler_attach(sdev, devinfo); | ||
| 274 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | ||
| 275 | device_remove_file(dev, &scsi_dh_state_attr); | ||
| 276 | if (sdev->scsi_dh_data) | ||
| 277 | scsi_dh_handler_detach(sdev); | ||
| 278 | } | ||
| 279 | return err; | 197 | return err; |
| 280 | } | 198 | } |
| 281 | 199 | ||
| 282 | /* | 200 | void scsi_dh_remove_device(struct scsi_device *sdev) |
| 283 | * scsi_dh_notifier_add - Callback for scsi_register_device_handler | ||
| 284 | */ | ||
| 285 | static int scsi_dh_notifier_add(struct device *dev, void *data) | ||
| 286 | { | 201 | { |
| 287 | struct scsi_device_handler *scsi_dh = data; | 202 | if (sdev->scsi_dh_data) |
| 288 | struct scsi_device *sdev; | ||
| 289 | |||
| 290 | if (!scsi_is_sdev_device(dev)) | ||
| 291 | return 0; | ||
| 292 | |||
| 293 | if (!get_device(dev)) | ||
| 294 | return 0; | ||
| 295 | |||
| 296 | sdev = to_scsi_device(dev); | ||
| 297 | |||
| 298 | if (device_handler_match(scsi_dh, sdev)) | ||
| 299 | scsi_dh_handler_attach(sdev, scsi_dh); | ||
| 300 | |||
| 301 | put_device(dev); | ||
| 302 | |||
| 303 | return 0; | ||
| 304 | } | ||
| 305 | |||
| 306 | /* | ||
| 307 | * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler | ||
| 308 | */ | ||
| 309 | static int scsi_dh_notifier_remove(struct device *dev, void *data) | ||
| 310 | { | ||
| 311 | struct scsi_device_handler *scsi_dh = data; | ||
| 312 | struct scsi_device *sdev; | ||
| 313 | |||
| 314 | if (!scsi_is_sdev_device(dev)) | ||
| 315 | return 0; | ||
| 316 | |||
| 317 | if (!get_device(dev)) | ||
| 318 | return 0; | ||
| 319 | |||
| 320 | sdev = to_scsi_device(dev); | ||
| 321 | |||
| 322 | if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh == scsi_dh) | ||
| 323 | scsi_dh_handler_detach(sdev); | 203 | scsi_dh_handler_detach(sdev); |
| 324 | 204 | device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr); | |
| 325 | put_device(dev); | ||
| 326 | |||
| 327 | return 0; | ||
| 328 | } | 205 | } |
| 329 | 206 | ||
| 330 | /* | 207 | /* |
| @@ -346,7 +223,6 @@ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) | |||
| 346 | list_add(&scsi_dh->list, &scsi_dh_list); | 223 | list_add(&scsi_dh->list, &scsi_dh_list); |
| 347 | spin_unlock(&list_lock); | 224 | spin_unlock(&list_lock); |
| 348 | 225 | ||
| 349 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); | ||
| 350 | printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name); | 226 | printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name); |
| 351 | 227 | ||
| 352 | return SCSI_DH_OK; | 228 | return SCSI_DH_OK; |
| @@ -362,13 +238,9 @@ EXPORT_SYMBOL_GPL(scsi_register_device_handler); | |||
| 362 | */ | 238 | */ |
| 363 | int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) | 239 | int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) |
| 364 | { | 240 | { |
| 365 | |||
| 366 | if (!__scsi_dh_lookup(scsi_dh->name)) | 241 | if (!__scsi_dh_lookup(scsi_dh->name)) |
| 367 | return -ENODEV; | 242 | return -ENODEV; |
| 368 | 243 | ||
| 369 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, | ||
| 370 | scsi_dh_notifier_remove); | ||
| 371 | |||
| 372 | spin_lock(&list_lock); | 244 | spin_lock(&list_lock); |
| 373 | list_del(&scsi_dh->list); | 245 | list_del(&scsi_dh->list); |
| 374 | spin_unlock(&list_lock); | 246 | spin_unlock(&list_lock); |
| @@ -538,34 +410,3 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) | |||
| 538 | return handler_name; | 410 | return handler_name; |
| 539 | } | 411 | } |
| 540 | EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name); | 412 | EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name); |
| 541 | |||
| 542 | static struct notifier_block scsi_dh_nb = { | ||
| 543 | .notifier_call = scsi_dh_notifier | ||
| 544 | }; | ||
| 545 | |||
| 546 | static int __init scsi_dh_init(void) | ||
| 547 | { | ||
| 548 | int r; | ||
| 549 | |||
| 550 | r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb); | ||
| 551 | |||
| 552 | if (!r) | ||
| 553 | bus_for_each_dev(&scsi_bus_type, NULL, NULL, | ||
| 554 | scsi_dh_sysfs_attr_add); | ||
| 555 | |||
| 556 | return r; | ||
| 557 | } | ||
| 558 | |||
| 559 | static void __exit scsi_dh_exit(void) | ||
| 560 | { | ||
| 561 | bus_for_each_dev(&scsi_bus_type, NULL, NULL, | ||
| 562 | scsi_dh_sysfs_attr_remove); | ||
| 563 | bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb); | ||
| 564 | } | ||
| 565 | |||
| 566 | module_init(scsi_dh_init); | ||
| 567 | module_exit(scsi_dh_exit); | ||
| 568 | |||
| 569 | MODULE_DESCRIPTION("SCSI device handler"); | ||
| 570 | MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>"); | ||
| 571 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index e3902fc66278..644bb7339b55 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h | |||
| @@ -170,6 +170,15 @@ static inline void scsi_autopm_put_host(struct Scsi_Host *h) {} | |||
| 170 | extern struct async_domain scsi_sd_pm_domain; | 170 | extern struct async_domain scsi_sd_pm_domain; |
| 171 | extern struct async_domain scsi_sd_probe_domain; | 171 | extern struct async_domain scsi_sd_probe_domain; |
| 172 | 172 | ||
| 173 | /* scsi_dh.c */ | ||
| 174 | #ifdef CONFIG_SCSI_DH | ||
| 175 | int scsi_dh_add_device(struct scsi_device *sdev); | ||
| 176 | void scsi_dh_remove_device(struct scsi_device *sdev); | ||
| 177 | #else | ||
| 178 | static inline int scsi_dh_add_device(struct scsi_device *sdev) { return 0; } | ||
| 179 | static inline void scsi_dh_remove_device(struct scsi_device *sdev) { } | ||
| 180 | #endif | ||
| 181 | |||
| 173 | /* | 182 | /* |
| 174 | * internal scsi timeout functions: for use by mid-layer and transport | 183 | * internal scsi timeout functions: for use by mid-layer and transport |
| 175 | * classes. | 184 | * classes. |
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 9ad41168d26d..b333389f248f 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
| @@ -1030,11 +1030,20 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
| 1030 | "failed to add device: %d\n", error); | 1030 | "failed to add device: %d\n", error); |
| 1031 | return error; | 1031 | return error; |
| 1032 | } | 1032 | } |
| 1033 | |||
| 1034 | error = scsi_dh_add_device(sdev); | ||
| 1035 | if (error) { | ||
| 1036 | sdev_printk(KERN_INFO, sdev, | ||
| 1037 | "failed to add device handler: %d\n", error); | ||
| 1038 | return error; | ||
| 1039 | } | ||
| 1040 | |||
| 1033 | device_enable_async_suspend(&sdev->sdev_dev); | 1041 | device_enable_async_suspend(&sdev->sdev_dev); |
| 1034 | error = device_add(&sdev->sdev_dev); | 1042 | error = device_add(&sdev->sdev_dev); |
| 1035 | if (error) { | 1043 | if (error) { |
| 1036 | sdev_printk(KERN_INFO, sdev, | 1044 | sdev_printk(KERN_INFO, sdev, |
| 1037 | "failed to add class device: %d\n", error); | 1045 | "failed to add class device: %d\n", error); |
| 1046 | scsi_dh_remove_device(sdev); | ||
| 1038 | device_del(&sdev->sdev_gendev); | 1047 | device_del(&sdev->sdev_gendev); |
| 1039 | return error; | 1048 | return error; |
| 1040 | } | 1049 | } |
| @@ -1074,6 +1083,7 @@ void __scsi_remove_device(struct scsi_device *sdev) | |||
| 1074 | bsg_unregister_queue(sdev->request_queue); | 1083 | bsg_unregister_queue(sdev->request_queue); |
| 1075 | device_unregister(&sdev->sdev_dev); | 1084 | device_unregister(&sdev->sdev_dev); |
| 1076 | transport_remove_device(dev); | 1085 | transport_remove_device(dev); |
| 1086 | scsi_dh_remove_device(sdev); | ||
| 1077 | device_del(dev); | 1087 | device_del(dev); |
| 1078 | } else | 1088 | } else |
| 1079 | put_device(&sdev->sdev_dev); | 1089 | put_device(&sdev->sdev_dev); |
diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h index 966b921135b5..3a37b4c45997 100644 --- a/include/scsi/scsi_dh.h +++ b/include/scsi/scsi_dh.h | |||
| @@ -55,7 +55,7 @@ enum { | |||
| 55 | SCSI_DH_NOSYS, | 55 | SCSI_DH_NOSYS, |
| 56 | SCSI_DH_DRIVER_MAX, | 56 | SCSI_DH_DRIVER_MAX, |
| 57 | }; | 57 | }; |
| 58 | #if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE) | 58 | #ifdef CONFIG_SCSI_DH |
| 59 | extern int scsi_dh_activate(struct request_queue *, activate_complete, void *); | 59 | extern int scsi_dh_activate(struct request_queue *, activate_complete, void *); |
| 60 | extern int scsi_dh_attach(struct request_queue *, const char *); | 60 | extern int scsi_dh_attach(struct request_queue *, const char *); |
| 61 | extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t); | 61 | extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t); |
