diff options
Diffstat (limited to 'drivers/scsi/scsi_sysfs.c')
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 142 |
1 files changed, 75 insertions, 67 deletions
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 67bb20ed45d2..049103f1d16f 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include "scsi_priv.h" | 21 | #include "scsi_priv.h" |
22 | #include "scsi_logging.h" | 22 | #include "scsi_logging.h" |
23 | 23 | ||
24 | static struct device_type scsi_dev_type; | ||
25 | |||
24 | static const struct { | 26 | static const struct { |
25 | enum scsi_device_state value; | 27 | enum scsi_device_state value; |
26 | char *name; | 28 | char *name; |
@@ -249,18 +251,27 @@ shost_rd_attr(sg_tablesize, "%hu\n"); | |||
249 | shost_rd_attr(unchecked_isa_dma, "%d\n"); | 251 | shost_rd_attr(unchecked_isa_dma, "%d\n"); |
250 | shost_rd_attr2(proc_name, hostt->proc_name, "%s\n"); | 252 | shost_rd_attr2(proc_name, hostt->proc_name, "%s\n"); |
251 | 253 | ||
252 | static struct device_attribute *scsi_sysfs_shost_attrs[] = { | 254 | static struct attribute *scsi_sysfs_shost_attrs[] = { |
253 | &dev_attr_unique_id, | 255 | &dev_attr_unique_id.attr, |
254 | &dev_attr_host_busy, | 256 | &dev_attr_host_busy.attr, |
255 | &dev_attr_cmd_per_lun, | 257 | &dev_attr_cmd_per_lun.attr, |
256 | &dev_attr_can_queue, | 258 | &dev_attr_can_queue.attr, |
257 | &dev_attr_sg_tablesize, | 259 | &dev_attr_sg_tablesize.attr, |
258 | &dev_attr_unchecked_isa_dma, | 260 | &dev_attr_unchecked_isa_dma.attr, |
259 | &dev_attr_proc_name, | 261 | &dev_attr_proc_name.attr, |
260 | &dev_attr_scan, | 262 | &dev_attr_scan.attr, |
261 | &dev_attr_hstate, | 263 | &dev_attr_hstate.attr, |
262 | &dev_attr_supported_mode, | 264 | &dev_attr_supported_mode.attr, |
263 | &dev_attr_active_mode, | 265 | &dev_attr_active_mode.attr, |
266 | NULL | ||
267 | }; | ||
268 | |||
269 | struct attribute_group scsi_shost_attr_group = { | ||
270 | .attrs = scsi_sysfs_shost_attrs, | ||
271 | }; | ||
272 | |||
273 | struct attribute_group *scsi_sysfs_shost_attr_groups[] = { | ||
274 | &scsi_shost_attr_group, | ||
264 | NULL | 275 | NULL |
265 | }; | 276 | }; |
266 | 277 | ||
@@ -335,7 +346,12 @@ static struct class sdev_class = { | |||
335 | /* all probing is done in the individual ->probe routines */ | 346 | /* all probing is done in the individual ->probe routines */ |
336 | static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) | 347 | static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) |
337 | { | 348 | { |
338 | struct scsi_device *sdp = to_scsi_device(dev); | 349 | struct scsi_device *sdp; |
350 | |||
351 | if (dev->type != &scsi_dev_type) | ||
352 | return 0; | ||
353 | |||
354 | sdp = to_scsi_device(dev); | ||
339 | if (sdp->no_uld_attach) | 355 | if (sdp->no_uld_attach) |
340 | return 0; | 356 | return 0; |
341 | return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; | 357 | return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; |
@@ -351,10 +367,16 @@ static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
351 | 367 | ||
352 | static int scsi_bus_suspend(struct device * dev, pm_message_t state) | 368 | static int scsi_bus_suspend(struct device * dev, pm_message_t state) |
353 | { | 369 | { |
354 | struct device_driver *drv = dev->driver; | 370 | struct device_driver *drv; |
355 | struct scsi_device *sdev = to_scsi_device(dev); | 371 | struct scsi_device *sdev; |
356 | int err; | 372 | int err; |
357 | 373 | ||
374 | if (dev->type != &scsi_dev_type) | ||
375 | return 0; | ||
376 | |||
377 | drv = dev->driver; | ||
378 | sdev = to_scsi_device(dev); | ||
379 | |||
358 | err = scsi_device_quiesce(sdev); | 380 | err = scsi_device_quiesce(sdev); |
359 | if (err) | 381 | if (err) |
360 | return err; | 382 | return err; |
@@ -370,10 +392,16 @@ static int scsi_bus_suspend(struct device * dev, pm_message_t state) | |||
370 | 392 | ||
371 | static int scsi_bus_resume(struct device * dev) | 393 | static int scsi_bus_resume(struct device * dev) |
372 | { | 394 | { |
373 | struct device_driver *drv = dev->driver; | 395 | struct device_driver *drv; |
374 | struct scsi_device *sdev = to_scsi_device(dev); | 396 | struct scsi_device *sdev; |
375 | int err = 0; | 397 | int err = 0; |
376 | 398 | ||
399 | if (dev->type != &scsi_dev_type) | ||
400 | return 0; | ||
401 | |||
402 | drv = dev->driver; | ||
403 | sdev = to_scsi_device(dev); | ||
404 | |||
377 | if (drv && drv->resume) | 405 | if (drv && drv->resume) |
378 | err = drv->resume(dev); | 406 | err = drv->resume(dev); |
379 | 407 | ||
@@ -781,6 +809,27 @@ sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr, | |||
781 | return count; | 809 | return count; |
782 | } | 810 | } |
783 | 811 | ||
812 | static int scsi_target_add(struct scsi_target *starget) | ||
813 | { | ||
814 | int error; | ||
815 | |||
816 | if (starget->state != STARGET_CREATED) | ||
817 | return 0; | ||
818 | |||
819 | error = device_add(&starget->dev); | ||
820 | if (error) { | ||
821 | dev_err(&starget->dev, "target device_add failed, error %d\n", error); | ||
822 | get_device(&starget->dev); | ||
823 | scsi_target_reap(starget); | ||
824 | put_device(&starget->dev); | ||
825 | return error; | ||
826 | } | ||
827 | transport_add_device(&starget->dev); | ||
828 | starget->state = STARGET_RUNNING; | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
784 | static struct device_attribute sdev_attr_queue_type_rw = | 833 | static struct device_attribute sdev_attr_queue_type_rw = |
785 | __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, | 834 | __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, |
786 | sdev_store_queue_type_rw); | 835 | sdev_store_queue_type_rw); |
@@ -796,10 +845,16 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
796 | { | 845 | { |
797 | int error, i; | 846 | int error, i; |
798 | struct request_queue *rq = sdev->request_queue; | 847 | struct request_queue *rq = sdev->request_queue; |
848 | struct scsi_target *starget = sdev->sdev_target; | ||
799 | 849 | ||
800 | if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0) | 850 | if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0) |
801 | return error; | 851 | return error; |
802 | 852 | ||
853 | error = scsi_target_add(starget); | ||
854 | if (error) | ||
855 | return error; | ||
856 | |||
857 | transport_configure_device(&starget->dev); | ||
803 | error = device_add(&sdev->sdev_gendev); | 858 | error = device_add(&sdev->sdev_gendev); |
804 | if (error) { | 859 | if (error) { |
805 | put_device(sdev->sdev_gendev.parent); | 860 | put_device(sdev->sdev_gendev.parent); |
@@ -834,7 +889,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
834 | goto out; | 889 | goto out; |
835 | } | 890 | } |
836 | 891 | ||
837 | error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL); | 892 | error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL); |
838 | 893 | ||
839 | if (error) | 894 | if (error) |
840 | sdev_printk(KERN_INFO, sdev, | 895 | sdev_printk(KERN_INFO, sdev, |
@@ -971,44 +1026,6 @@ int scsi_register_interface(struct class_interface *intf) | |||
971 | } | 1026 | } |
972 | EXPORT_SYMBOL(scsi_register_interface); | 1027 | EXPORT_SYMBOL(scsi_register_interface); |
973 | 1028 | ||
974 | |||
975 | static struct device_attribute *class_attr_overridden( | ||
976 | struct device_attribute **attrs, | ||
977 | struct device_attribute *attr) | ||
978 | { | ||
979 | int i; | ||
980 | |||
981 | if (!attrs) | ||
982 | return NULL; | ||
983 | for (i = 0; attrs[i]; i++) | ||
984 | if (!strcmp(attrs[i]->attr.name, attr->attr.name)) | ||
985 | return attrs[i]; | ||
986 | return NULL; | ||
987 | } | ||
988 | |||
989 | static int class_attr_add(struct device *classdev, | ||
990 | struct device_attribute *attr) | ||
991 | { | ||
992 | struct device_attribute *base_attr; | ||
993 | |||
994 | /* | ||
995 | * Spare the caller from having to copy things it's not interested in. | ||
996 | */ | ||
997 | base_attr = class_attr_overridden(scsi_sysfs_shost_attrs, attr); | ||
998 | if (base_attr) { | ||
999 | /* extend permissions */ | ||
1000 | attr->attr.mode |= base_attr->attr.mode; | ||
1001 | |||
1002 | /* override null show/store with default */ | ||
1003 | if (!attr->show) | ||
1004 | attr->show = base_attr->show; | ||
1005 | if (!attr->store) | ||
1006 | attr->store = base_attr->store; | ||
1007 | } | ||
1008 | |||
1009 | return device_create_file(classdev, attr); | ||
1010 | } | ||
1011 | |||
1012 | /** | 1029 | /** |
1013 | * scsi_sysfs_add_host - add scsi host to subsystem | 1030 | * scsi_sysfs_add_host - add scsi host to subsystem |
1014 | * @shost: scsi host struct to add to subsystem | 1031 | * @shost: scsi host struct to add to subsystem |
@@ -1018,20 +1035,11 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost) | |||
1018 | { | 1035 | { |
1019 | int error, i; | 1036 | int error, i; |
1020 | 1037 | ||
1038 | /* add host specific attributes */ | ||
1021 | if (shost->hostt->shost_attrs) { | 1039 | if (shost->hostt->shost_attrs) { |
1022 | for (i = 0; shost->hostt->shost_attrs[i]; i++) { | 1040 | for (i = 0; shost->hostt->shost_attrs[i]; i++) { |
1023 | error = class_attr_add(&shost->shost_dev, | ||
1024 | shost->hostt->shost_attrs[i]); | ||
1025 | if (error) | ||
1026 | return error; | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | for (i = 0; scsi_sysfs_shost_attrs[i]; i++) { | ||
1031 | if (!class_attr_overridden(shost->hostt->shost_attrs, | ||
1032 | scsi_sysfs_shost_attrs[i])) { | ||
1033 | error = device_create_file(&shost->shost_dev, | 1041 | error = device_create_file(&shost->shost_dev, |
1034 | scsi_sysfs_shost_attrs[i]); | 1042 | shost->hostt->shost_attrs[i]); |
1035 | if (error) | 1043 | if (error) |
1036 | return error; | 1044 | return error; |
1037 | } | 1045 | } |