diff options
Diffstat (limited to 'drivers/scsi/scsi_sysfs.c')
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 242 |
1 files changed, 143 insertions, 99 deletions
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 8ead24c3453a..074e8cc30955 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -300,7 +300,9 @@ store_shost_eh_deadline(struct device *dev, struct device_attribute *attr, | |||
300 | int ret = -EINVAL; | 300 | int ret = -EINVAL; |
301 | unsigned long deadline, flags; | 301 | unsigned long deadline, flags; |
302 | 302 | ||
303 | if (shost->transportt && shost->transportt->eh_strategy_handler) | 303 | if (shost->transportt && |
304 | (shost->transportt->eh_strategy_handler || | ||
305 | !shost->hostt->eh_host_reset_handler)) | ||
304 | return ret; | 306 | return ret; |
305 | 307 | ||
306 | if (!strncmp(buf, "off", strlen("off"))) | 308 | if (!strncmp(buf, "off", strlen("off"))) |
@@ -383,17 +385,14 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) | |||
383 | { | 385 | { |
384 | struct scsi_device *sdev; | 386 | struct scsi_device *sdev; |
385 | struct device *parent; | 387 | struct device *parent; |
386 | struct scsi_target *starget; | ||
387 | struct list_head *this, *tmp; | 388 | struct list_head *this, *tmp; |
388 | unsigned long flags; | 389 | unsigned long flags; |
389 | 390 | ||
390 | sdev = container_of(work, struct scsi_device, ew.work); | 391 | sdev = container_of(work, struct scsi_device, ew.work); |
391 | 392 | ||
392 | parent = sdev->sdev_gendev.parent; | 393 | parent = sdev->sdev_gendev.parent; |
393 | starget = to_scsi_target(parent); | ||
394 | 394 | ||
395 | spin_lock_irqsave(sdev->host->host_lock, flags); | 395 | spin_lock_irqsave(sdev->host->host_lock, flags); |
396 | starget->reap_ref++; | ||
397 | list_del(&sdev->siblings); | 396 | list_del(&sdev->siblings); |
398 | list_del(&sdev->same_target_siblings); | 397 | list_del(&sdev->same_target_siblings); |
399 | list_del(&sdev->starved_entry); | 398 | list_del(&sdev->starved_entry); |
@@ -413,8 +412,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) | |||
413 | /* NULL queue means the device can't be used */ | 412 | /* NULL queue means the device can't be used */ |
414 | sdev->request_queue = NULL; | 413 | sdev->request_queue = NULL; |
415 | 414 | ||
416 | scsi_target_reap(scsi_target(sdev)); | 415 | kfree(sdev->vpd_pg83); |
417 | 416 | kfree(sdev->vpd_pg80); | |
418 | kfree(sdev->inquiry); | 417 | kfree(sdev->inquiry); |
419 | kfree(sdev); | 418 | kfree(sdev); |
420 | 419 | ||
@@ -579,7 +578,6 @@ static int scsi_sdev_check_buf_bit(const char *buf) | |||
579 | * Create the actual show/store functions and data structures. | 578 | * Create the actual show/store functions and data structures. |
580 | */ | 579 | */ |
581 | sdev_rd_attr (device_blocked, "%d\n"); | 580 | sdev_rd_attr (device_blocked, "%d\n"); |
582 | sdev_rd_attr (queue_depth, "%d\n"); | ||
583 | sdev_rd_attr (device_busy, "%d\n"); | 581 | sdev_rd_attr (device_busy, "%d\n"); |
584 | sdev_rd_attr (type, "%d\n"); | 582 | sdev_rd_attr (type, "%d\n"); |
585 | sdev_rd_attr (scsi_level, "%d\n"); | 583 | sdev_rd_attr (scsi_level, "%d\n"); |
@@ -712,10 +710,64 @@ show_queue_type_field(struct device *dev, struct device_attribute *attr, | |||
712 | return snprintf(buf, 20, "%s\n", name); | 710 | return snprintf(buf, 20, "%s\n", name); |
713 | } | 711 | } |
714 | 712 | ||
715 | static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL); | 713 | static ssize_t |
714 | store_queue_type_field(struct device *dev, struct device_attribute *attr, | ||
715 | const char *buf, size_t count) | ||
716 | { | ||
717 | struct scsi_device *sdev = to_scsi_device(dev); | ||
718 | struct scsi_host_template *sht = sdev->host->hostt; | ||
719 | int tag_type = 0, retval; | ||
720 | int prev_tag_type = scsi_get_tag_type(sdev); | ||
721 | |||
722 | if (!sdev->tagged_supported || !sht->change_queue_type) | ||
723 | return -EINVAL; | ||
724 | |||
725 | if (strncmp(buf, "ordered", 7) == 0) | ||
726 | tag_type = MSG_ORDERED_TAG; | ||
727 | else if (strncmp(buf, "simple", 6) == 0) | ||
728 | tag_type = MSG_SIMPLE_TAG; | ||
729 | else if (strncmp(buf, "none", 4) != 0) | ||
730 | return -EINVAL; | ||
731 | |||
732 | if (tag_type == prev_tag_type) | ||
733 | return count; | ||
734 | |||
735 | retval = sht->change_queue_type(sdev, tag_type); | ||
736 | if (retval < 0) | ||
737 | return retval; | ||
738 | |||
739 | return count; | ||
740 | } | ||
741 | |||
742 | static DEVICE_ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, | ||
743 | store_queue_type_field); | ||
744 | |||
745 | #define sdev_vpd_pg_attr(_page) \ | ||
746 | static ssize_t \ | ||
747 | show_vpd_##_page(struct file *filp, struct kobject *kobj, \ | ||
748 | struct bin_attribute *bin_attr, \ | ||
749 | char *buf, loff_t off, size_t count) \ | ||
750 | { \ | ||
751 | struct device *dev = container_of(kobj, struct device, kobj); \ | ||
752 | struct scsi_device *sdev = to_scsi_device(dev); \ | ||
753 | if (!sdev->vpd_##_page) \ | ||
754 | return -EINVAL; \ | ||
755 | return memory_read_from_buffer(buf, count, &off, \ | ||
756 | sdev->vpd_##_page, \ | ||
757 | sdev->vpd_##_page##_len); \ | ||
758 | } \ | ||
759 | static struct bin_attribute dev_attr_vpd_##_page = { \ | ||
760 | .attr = {.name = __stringify(vpd_##_page), .mode = S_IRUGO }, \ | ||
761 | .size = 0, \ | ||
762 | .read = show_vpd_##_page, \ | ||
763 | }; | ||
764 | |||
765 | sdev_vpd_pg_attr(pg83); | ||
766 | sdev_vpd_pg_attr(pg80); | ||
716 | 767 | ||
717 | static ssize_t | 768 | static ssize_t |
718 | show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf) | 769 | show_iostat_counterbits(struct device *dev, struct device_attribute *attr, |
770 | char *buf) | ||
719 | { | 771 | { |
720 | return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8); | 772 | return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8); |
721 | } | 773 | } |
@@ -786,46 +838,9 @@ DECLARE_EVT(soft_threshold_reached, SOFT_THRESHOLD_REACHED_REPORTED) | |||
786 | DECLARE_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED) | 838 | DECLARE_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED) |
787 | DECLARE_EVT(lun_change_reported, LUN_CHANGE_REPORTED) | 839 | DECLARE_EVT(lun_change_reported, LUN_CHANGE_REPORTED) |
788 | 840 | ||
789 | /* Default template for device attributes. May NOT be modified */ | ||
790 | static struct attribute *scsi_sdev_attrs[] = { | ||
791 | &dev_attr_device_blocked.attr, | ||
792 | &dev_attr_type.attr, | ||
793 | &dev_attr_scsi_level.attr, | ||
794 | &dev_attr_device_busy.attr, | ||
795 | &dev_attr_vendor.attr, | ||
796 | &dev_attr_model.attr, | ||
797 | &dev_attr_rev.attr, | ||
798 | &dev_attr_rescan.attr, | ||
799 | &dev_attr_delete.attr, | ||
800 | &dev_attr_state.attr, | ||
801 | &dev_attr_timeout.attr, | ||
802 | &dev_attr_eh_timeout.attr, | ||
803 | &dev_attr_iocounterbits.attr, | ||
804 | &dev_attr_iorequest_cnt.attr, | ||
805 | &dev_attr_iodone_cnt.attr, | ||
806 | &dev_attr_ioerr_cnt.attr, | ||
807 | &dev_attr_modalias.attr, | ||
808 | REF_EVT(media_change), | ||
809 | REF_EVT(inquiry_change_reported), | ||
810 | REF_EVT(capacity_change_reported), | ||
811 | REF_EVT(soft_threshold_reached), | ||
812 | REF_EVT(mode_parameter_change_reported), | ||
813 | REF_EVT(lun_change_reported), | ||
814 | NULL | ||
815 | }; | ||
816 | |||
817 | static struct attribute_group scsi_sdev_attr_group = { | ||
818 | .attrs = scsi_sdev_attrs, | ||
819 | }; | ||
820 | |||
821 | static const struct attribute_group *scsi_sdev_attr_groups[] = { | ||
822 | &scsi_sdev_attr_group, | ||
823 | NULL | ||
824 | }; | ||
825 | |||
826 | static ssize_t | 841 | static ssize_t |
827 | sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr, | 842 | sdev_store_queue_depth(struct device *dev, struct device_attribute *attr, |
828 | const char *buf, size_t count) | 843 | const char *buf, size_t count) |
829 | { | 844 | { |
830 | int depth, retval; | 845 | int depth, retval; |
831 | struct scsi_device *sdev = to_scsi_device(dev); | 846 | struct scsi_device *sdev = to_scsi_device(dev); |
@@ -848,10 +863,10 @@ sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr, | |||
848 | 863 | ||
849 | return count; | 864 | return count; |
850 | } | 865 | } |
866 | sdev_show_function(queue_depth, "%d\n"); | ||
851 | 867 | ||
852 | static struct device_attribute sdev_attr_queue_depth_rw = | 868 | static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth, |
853 | __ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth, | 869 | sdev_store_queue_depth); |
854 | sdev_store_queue_depth_rw); | ||
855 | 870 | ||
856 | static ssize_t | 871 | static ssize_t |
857 | sdev_show_queue_ramp_up_period(struct device *dev, | 872 | sdev_show_queue_ramp_up_period(struct device *dev, |
@@ -879,40 +894,79 @@ sdev_store_queue_ramp_up_period(struct device *dev, | |||
879 | return period; | 894 | return period; |
880 | } | 895 | } |
881 | 896 | ||
882 | static struct device_attribute sdev_attr_queue_ramp_up_period = | 897 | static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR, |
883 | __ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR, | 898 | sdev_show_queue_ramp_up_period, |
884 | sdev_show_queue_ramp_up_period, | 899 | sdev_store_queue_ramp_up_period); |
885 | sdev_store_queue_ramp_up_period); | ||
886 | 900 | ||
887 | static ssize_t | 901 | static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj, |
888 | sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr, | 902 | struct attribute *attr, int i) |
889 | const char *buf, size_t count) | ||
890 | { | 903 | { |
904 | struct device *dev = container_of(kobj, struct device, kobj); | ||
891 | struct scsi_device *sdev = to_scsi_device(dev); | 905 | struct scsi_device *sdev = to_scsi_device(dev); |
892 | struct scsi_host_template *sht = sdev->host->hostt; | ||
893 | int tag_type = 0, retval; | ||
894 | int prev_tag_type = scsi_get_tag_type(sdev); | ||
895 | 906 | ||
896 | if (!sdev->tagged_supported || !sht->change_queue_type) | ||
897 | return -EINVAL; | ||
898 | 907 | ||
899 | if (strncmp(buf, "ordered", 7) == 0) | 908 | if (attr == &dev_attr_queue_depth.attr && |
900 | tag_type = MSG_ORDERED_TAG; | 909 | !sdev->host->hostt->change_queue_depth) |
901 | else if (strncmp(buf, "simple", 6) == 0) | 910 | return S_IRUGO; |
902 | tag_type = MSG_SIMPLE_TAG; | ||
903 | else if (strncmp(buf, "none", 4) != 0) | ||
904 | return -EINVAL; | ||
905 | 911 | ||
906 | if (tag_type == prev_tag_type) | 912 | if (attr == &dev_attr_queue_ramp_up_period.attr && |
907 | return count; | 913 | !sdev->host->hostt->change_queue_depth) |
914 | return 0; | ||
908 | 915 | ||
909 | retval = sht->change_queue_type(sdev, tag_type); | 916 | if (attr == &dev_attr_queue_type.attr && |
910 | if (retval < 0) | 917 | !sdev->host->hostt->change_queue_type) |
911 | return retval; | 918 | return S_IRUGO; |
912 | 919 | ||
913 | return count; | 920 | return attr->mode; |
914 | } | 921 | } |
915 | 922 | ||
923 | /* Default template for device attributes. May NOT be modified */ | ||
924 | static struct attribute *scsi_sdev_attrs[] = { | ||
925 | &dev_attr_device_blocked.attr, | ||
926 | &dev_attr_type.attr, | ||
927 | &dev_attr_scsi_level.attr, | ||
928 | &dev_attr_device_busy.attr, | ||
929 | &dev_attr_vendor.attr, | ||
930 | &dev_attr_model.attr, | ||
931 | &dev_attr_rev.attr, | ||
932 | &dev_attr_rescan.attr, | ||
933 | &dev_attr_delete.attr, | ||
934 | &dev_attr_state.attr, | ||
935 | &dev_attr_timeout.attr, | ||
936 | &dev_attr_eh_timeout.attr, | ||
937 | &dev_attr_iocounterbits.attr, | ||
938 | &dev_attr_iorequest_cnt.attr, | ||
939 | &dev_attr_iodone_cnt.attr, | ||
940 | &dev_attr_ioerr_cnt.attr, | ||
941 | &dev_attr_modalias.attr, | ||
942 | &dev_attr_queue_depth.attr, | ||
943 | &dev_attr_queue_type.attr, | ||
944 | &dev_attr_queue_ramp_up_period.attr, | ||
945 | REF_EVT(media_change), | ||
946 | REF_EVT(inquiry_change_reported), | ||
947 | REF_EVT(capacity_change_reported), | ||
948 | REF_EVT(soft_threshold_reached), | ||
949 | REF_EVT(mode_parameter_change_reported), | ||
950 | REF_EVT(lun_change_reported), | ||
951 | NULL | ||
952 | }; | ||
953 | |||
954 | static struct bin_attribute *scsi_sdev_bin_attrs[] = { | ||
955 | &dev_attr_vpd_pg83, | ||
956 | &dev_attr_vpd_pg80, | ||
957 | NULL | ||
958 | }; | ||
959 | static struct attribute_group scsi_sdev_attr_group = { | ||
960 | .attrs = scsi_sdev_attrs, | ||
961 | .bin_attrs = scsi_sdev_bin_attrs, | ||
962 | .is_visible = scsi_sdev_attr_is_visible, | ||
963 | }; | ||
964 | |||
965 | static const struct attribute_group *scsi_sdev_attr_groups[] = { | ||
966 | &scsi_sdev_attr_group, | ||
967 | NULL | ||
968 | }; | ||
969 | |||
916 | static int scsi_target_add(struct scsi_target *starget) | 970 | static int scsi_target_add(struct scsi_target *starget) |
917 | { | 971 | { |
918 | int error; | 972 | int error; |
@@ -935,10 +989,6 @@ static int scsi_target_add(struct scsi_target *starget) | |||
935 | return 0; | 989 | return 0; |
936 | } | 990 | } |
937 | 991 | ||
938 | static struct device_attribute sdev_attr_queue_type_rw = | ||
939 | __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, | ||
940 | sdev_store_queue_type_rw); | ||
941 | |||
942 | /** | 992 | /** |
943 | * scsi_sysfs_add_sdev - add scsi device to sysfs | 993 | * scsi_sysfs_add_sdev - add scsi device to sysfs |
944 | * @sdev: scsi_device to add | 994 | * @sdev: scsi_device to add |
@@ -992,25 +1042,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
992 | transport_add_device(&sdev->sdev_gendev); | 1042 | transport_add_device(&sdev->sdev_gendev); |
993 | sdev->is_visible = 1; | 1043 | sdev->is_visible = 1; |
994 | 1044 | ||
995 | /* create queue files, which may be writable, depending on the host */ | ||
996 | if (sdev->host->hostt->change_queue_depth) { | ||
997 | error = device_create_file(&sdev->sdev_gendev, | ||
998 | &sdev_attr_queue_depth_rw); | ||
999 | error = device_create_file(&sdev->sdev_gendev, | ||
1000 | &sdev_attr_queue_ramp_up_period); | ||
1001 | } | ||
1002 | else | ||
1003 | error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth); | ||
1004 | if (error) | ||
1005 | return error; | ||
1006 | |||
1007 | if (sdev->host->hostt->change_queue_type) | ||
1008 | error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw); | ||
1009 | else | ||
1010 | error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type); | ||
1011 | if (error) | ||
1012 | return error; | ||
1013 | |||
1014 | error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL); | 1045 | error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL); |
1015 | 1046 | ||
1016 | if (error) | 1047 | if (error) |
@@ -1060,6 +1091,13 @@ void __scsi_remove_device(struct scsi_device *sdev) | |||
1060 | sdev->host->hostt->slave_destroy(sdev); | 1091 | sdev->host->hostt->slave_destroy(sdev); |
1061 | transport_destroy_device(dev); | 1092 | transport_destroy_device(dev); |
1062 | 1093 | ||
1094 | /* | ||
1095 | * Paired with the kref_get() in scsi_sysfs_initialize(). We have | ||
1096 | * remoed sysfs visibility from the device, so make the target | ||
1097 | * invisible if this was the last device underneath it. | ||
1098 | */ | ||
1099 | scsi_target_reap(scsi_target(sdev)); | ||
1100 | |||
1063 | put_device(dev); | 1101 | put_device(dev); |
1064 | } | 1102 | } |
1065 | 1103 | ||
@@ -1122,7 +1160,7 @@ void scsi_remove_target(struct device *dev) | |||
1122 | continue; | 1160 | continue; |
1123 | if (starget->dev.parent == dev || &starget->dev == dev) { | 1161 | if (starget->dev.parent == dev || &starget->dev == dev) { |
1124 | /* assuming new targets arrive at the end */ | 1162 | /* assuming new targets arrive at the end */ |
1125 | starget->reap_ref++; | 1163 | kref_get(&starget->reap_ref); |
1126 | spin_unlock_irqrestore(shost->host_lock, flags); | 1164 | spin_unlock_irqrestore(shost->host_lock, flags); |
1127 | if (last) | 1165 | if (last) |
1128 | scsi_target_reap(last); | 1166 | scsi_target_reap(last); |
@@ -1206,6 +1244,12 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) | |||
1206 | list_add_tail(&sdev->same_target_siblings, &starget->devices); | 1244 | list_add_tail(&sdev->same_target_siblings, &starget->devices); |
1207 | list_add_tail(&sdev->siblings, &shost->__devices); | 1245 | list_add_tail(&sdev->siblings, &shost->__devices); |
1208 | spin_unlock_irqrestore(shost->host_lock, flags); | 1246 | spin_unlock_irqrestore(shost->host_lock, flags); |
1247 | /* | ||
1248 | * device can now only be removed via __scsi_remove_device() so hold | ||
1249 | * the target. Target will be held in CREATED state until something | ||
1250 | * beneath it becomes visible (in which case it moves to RUNNING) | ||
1251 | */ | ||
1252 | kref_get(&starget->reap_ref); | ||
1209 | } | 1253 | } |
1210 | 1254 | ||
1211 | int scsi_is_sdev_device(const struct device *dev) | 1255 | int scsi_is_sdev_device(const struct device *dev) |