diff options
Diffstat (limited to 'drivers/scsi/scsi_sysfs.c')
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 180 |
1 files changed, 95 insertions, 85 deletions
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index ede9986d349..daed37df00b 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -190,6 +190,46 @@ show_shost_state(struct class_device *class_dev, char *buf) | |||
190 | 190 | ||
191 | static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state); | 191 | static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state); |
192 | 192 | ||
193 | static ssize_t | ||
194 | show_shost_mode(unsigned int mode, char *buf) | ||
195 | { | ||
196 | ssize_t len = 0; | ||
197 | |||
198 | if (mode & MODE_INITIATOR) | ||
199 | len = sprintf(buf, "%s", "Initiator"); | ||
200 | |||
201 | if (mode & MODE_TARGET) | ||
202 | len += sprintf(buf + len, "%s%s", len ? ", " : "", "Target"); | ||
203 | |||
204 | len += sprintf(buf + len, "\n"); | ||
205 | |||
206 | return len; | ||
207 | } | ||
208 | |||
209 | static ssize_t show_shost_supported_mode(struct class_device *class_dev, char *buf) | ||
210 | { | ||
211 | struct Scsi_Host *shost = class_to_shost(class_dev); | ||
212 | |||
213 | if (shost->hostt->supported_mode == MODE_UNKNOWN) | ||
214 | return snprintf(buf, 20, "unknown\n"); | ||
215 | else | ||
216 | return show_shost_mode(shost->hostt->supported_mode, buf); | ||
217 | } | ||
218 | |||
219 | static CLASS_DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL); | ||
220 | |||
221 | static ssize_t show_shost_active_mode(struct class_device *class_dev, char *buf) | ||
222 | { | ||
223 | struct Scsi_Host *shost = class_to_shost(class_dev); | ||
224 | |||
225 | if (shost->active_mode == MODE_UNKNOWN) | ||
226 | return snprintf(buf, 20, "unknown\n"); | ||
227 | else | ||
228 | return show_shost_mode(shost->active_mode, buf); | ||
229 | } | ||
230 | |||
231 | static CLASS_DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL); | ||
232 | |||
193 | shost_rd_attr(unique_id, "%u\n"); | 233 | shost_rd_attr(unique_id, "%u\n"); |
194 | shost_rd_attr(host_busy, "%hu\n"); | 234 | shost_rd_attr(host_busy, "%hu\n"); |
195 | shost_rd_attr(cmd_per_lun, "%hd\n"); | 235 | shost_rd_attr(cmd_per_lun, "%hd\n"); |
@@ -208,6 +248,8 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = { | |||
208 | &class_device_attr_proc_name, | 248 | &class_device_attr_proc_name, |
209 | &class_device_attr_scan, | 249 | &class_device_attr_scan, |
210 | &class_device_attr_state, | 250 | &class_device_attr_state, |
251 | &class_device_attr_supported_mode, | ||
252 | &class_device_attr_active_mode, | ||
211 | NULL | 253 | NULL |
212 | }; | 254 | }; |
213 | 255 | ||
@@ -571,24 +613,31 @@ sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) | |||
571 | static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL); | 613 | static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL); |
572 | 614 | ||
573 | /* Default template for device attributes. May NOT be modified */ | 615 | /* Default template for device attributes. May NOT be modified */ |
574 | static struct device_attribute *scsi_sysfs_sdev_attrs[] = { | 616 | static struct attribute *scsi_sdev_attrs[] = { |
575 | &dev_attr_device_blocked, | 617 | &dev_attr_device_blocked.attr, |
576 | &dev_attr_queue_depth, | 618 | &dev_attr_type.attr, |
577 | &dev_attr_queue_type, | 619 | &dev_attr_scsi_level.attr, |
578 | &dev_attr_type, | 620 | &dev_attr_vendor.attr, |
579 | &dev_attr_scsi_level, | 621 | &dev_attr_model.attr, |
580 | &dev_attr_vendor, | 622 | &dev_attr_rev.attr, |
581 | &dev_attr_model, | 623 | &dev_attr_rescan.attr, |
582 | &dev_attr_rev, | 624 | &dev_attr_delete.attr, |
583 | &dev_attr_rescan, | 625 | &dev_attr_state.attr, |
584 | &dev_attr_delete, | 626 | &dev_attr_timeout.attr, |
585 | &dev_attr_state, | 627 | &dev_attr_iocounterbits.attr, |
586 | &dev_attr_timeout, | 628 | &dev_attr_iorequest_cnt.attr, |
587 | &dev_attr_iocounterbits, | 629 | &dev_attr_iodone_cnt.attr, |
588 | &dev_attr_iorequest_cnt, | 630 | &dev_attr_ioerr_cnt.attr, |
589 | &dev_attr_iodone_cnt, | 631 | &dev_attr_modalias.attr, |
590 | &dev_attr_ioerr_cnt, | 632 | NULL |
591 | &dev_attr_modalias, | 633 | }; |
634 | |||
635 | static struct attribute_group scsi_sdev_attr_group = { | ||
636 | .attrs = scsi_sdev_attrs, | ||
637 | }; | ||
638 | |||
639 | static struct attribute_group *scsi_sdev_attr_groups[] = { | ||
640 | &scsi_sdev_attr_group, | ||
592 | NULL | 641 | NULL |
593 | }; | 642 | }; |
594 | 643 | ||
@@ -650,56 +699,6 @@ static struct device_attribute sdev_attr_queue_type_rw = | |||
650 | __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, | 699 | __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, |
651 | sdev_store_queue_type_rw); | 700 | sdev_store_queue_type_rw); |
652 | 701 | ||
653 | static struct device_attribute *attr_changed_internally( | ||
654 | struct Scsi_Host *shost, | ||
655 | struct device_attribute * attr) | ||
656 | { | ||
657 | if (!strcmp("queue_depth", attr->attr.name) | ||
658 | && shost->hostt->change_queue_depth) | ||
659 | return &sdev_attr_queue_depth_rw; | ||
660 | else if (!strcmp("queue_type", attr->attr.name) | ||
661 | && shost->hostt->change_queue_type) | ||
662 | return &sdev_attr_queue_type_rw; | ||
663 | return attr; | ||
664 | } | ||
665 | |||
666 | |||
667 | static struct device_attribute *attr_overridden( | ||
668 | struct device_attribute **attrs, | ||
669 | struct device_attribute *attr) | ||
670 | { | ||
671 | int i; | ||
672 | |||
673 | if (!attrs) | ||
674 | return NULL; | ||
675 | for (i = 0; attrs[i]; i++) | ||
676 | if (!strcmp(attrs[i]->attr.name, attr->attr.name)) | ||
677 | return attrs[i]; | ||
678 | return NULL; | ||
679 | } | ||
680 | |||
681 | static int attr_add(struct device *dev, struct device_attribute *attr) | ||
682 | { | ||
683 | struct device_attribute *base_attr; | ||
684 | |||
685 | /* | ||
686 | * Spare the caller from having to copy things it's not interested in. | ||
687 | */ | ||
688 | base_attr = attr_overridden(scsi_sysfs_sdev_attrs, attr); | ||
689 | if (base_attr) { | ||
690 | /* extend permissions */ | ||
691 | attr->attr.mode |= base_attr->attr.mode; | ||
692 | |||
693 | /* override null show/store with default */ | ||
694 | if (!attr->show) | ||
695 | attr->show = base_attr->show; | ||
696 | if (!attr->store) | ||
697 | attr->store = base_attr->store; | ||
698 | } | ||
699 | |||
700 | return device_create_file(dev, attr); | ||
701 | } | ||
702 | |||
703 | /** | 702 | /** |
704 | * scsi_sysfs_add_sdev - add scsi device to sysfs | 703 | * scsi_sysfs_add_sdev - add scsi device to sysfs |
705 | * @sdev: scsi_device to add | 704 | * @sdev: scsi_device to add |
@@ -731,6 +730,24 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
731 | * released by the sdev_class .release */ | 730 | * released by the sdev_class .release */ |
732 | get_device(&sdev->sdev_gendev); | 731 | get_device(&sdev->sdev_gendev); |
733 | 732 | ||
733 | /* create queue files, which may be writable, depending on the host */ | ||
734 | if (sdev->host->hostt->change_queue_depth) | ||
735 | error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw); | ||
736 | else | ||
737 | error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth); | ||
738 | if (error) { | ||
739 | __scsi_remove_device(sdev); | ||
740 | goto out; | ||
741 | } | ||
742 | if (sdev->host->hostt->change_queue_type) | ||
743 | error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw); | ||
744 | else | ||
745 | error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type); | ||
746 | if (error) { | ||
747 | __scsi_remove_device(sdev); | ||
748 | goto out; | ||
749 | } | ||
750 | |||
734 | error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL); | 751 | error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL); |
735 | 752 | ||
736 | if (error) | 753 | if (error) |
@@ -741,9 +758,10 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
741 | * nothing went wrong */ | 758 | * nothing went wrong */ |
742 | error = 0; | 759 | error = 0; |
743 | 760 | ||
761 | /* add additional host specific attributes */ | ||
744 | if (sdev->host->hostt->sdev_attrs) { | 762 | if (sdev->host->hostt->sdev_attrs) { |
745 | for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { | 763 | for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { |
746 | error = attr_add(&sdev->sdev_gendev, | 764 | error = device_create_file(&sdev->sdev_gendev, |
747 | sdev->host->hostt->sdev_attrs[i]); | 765 | sdev->host->hostt->sdev_attrs[i]); |
748 | if (error) { | 766 | if (error) { |
749 | __scsi_remove_device(sdev); | 767 | __scsi_remove_device(sdev); |
@@ -751,20 +769,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
751 | } | 769 | } |
752 | } | 770 | } |
753 | } | 771 | } |
754 | |||
755 | for (i = 0; scsi_sysfs_sdev_attrs[i]; i++) { | ||
756 | if (!attr_overridden(sdev->host->hostt->sdev_attrs, | ||
757 | scsi_sysfs_sdev_attrs[i])) { | ||
758 | struct device_attribute * attr = | ||
759 | attr_changed_internally(sdev->host, | ||
760 | scsi_sysfs_sdev_attrs[i]); | ||
761 | error = device_create_file(&sdev->sdev_gendev, attr); | ||
762 | if (error) { | ||
763 | __scsi_remove_device(sdev); | ||
764 | goto out; | ||
765 | } | ||
766 | } | ||
767 | } | ||
768 | 772 | ||
769 | transport_add_device(&sdev->sdev_gendev); | 773 | transport_add_device(&sdev->sdev_gendev); |
770 | out: | 774 | out: |
@@ -951,6 +955,12 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost) | |||
951 | return 0; | 955 | return 0; |
952 | } | 956 | } |
953 | 957 | ||
958 | static struct device_type scsi_dev_type = { | ||
959 | .name = "scsi_device", | ||
960 | .release = scsi_device_dev_release, | ||
961 | .groups = scsi_sdev_attr_groups, | ||
962 | }; | ||
963 | |||
954 | void scsi_sysfs_device_initialize(struct scsi_device *sdev) | 964 | void scsi_sysfs_device_initialize(struct scsi_device *sdev) |
955 | { | 965 | { |
956 | unsigned long flags; | 966 | unsigned long flags; |
@@ -959,7 +969,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) | |||
959 | 969 | ||
960 | device_initialize(&sdev->sdev_gendev); | 970 | device_initialize(&sdev->sdev_gendev); |
961 | sdev->sdev_gendev.bus = &scsi_bus_type; | 971 | sdev->sdev_gendev.bus = &scsi_bus_type; |
962 | sdev->sdev_gendev.release = scsi_device_dev_release; | 972 | sdev->sdev_gendev.type = &scsi_dev_type; |
963 | sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d", | 973 | sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d", |
964 | sdev->host->host_no, sdev->channel, sdev->id, | 974 | sdev->host->host_no, sdev->channel, sdev->id, |
965 | sdev->lun); | 975 | sdev->lun); |
@@ -980,7 +990,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) | |||
980 | 990 | ||
981 | int scsi_is_sdev_device(const struct device *dev) | 991 | int scsi_is_sdev_device(const struct device *dev) |
982 | { | 992 | { |
983 | return dev->release == scsi_device_dev_release; | 993 | return dev->type == &scsi_dev_type; |
984 | } | 994 | } |
985 | EXPORT_SYMBOL(scsi_is_sdev_device); | 995 | EXPORT_SYMBOL(scsi_is_sdev_device); |
986 | 996 | ||