diff options
-rw-r--r-- | drivers/s390/cio/css.c | 13 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 107 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 3 |
4 files changed, 78 insertions, 47 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 26cf2f5ae2e7..55895c83d499 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -135,14 +135,19 @@ css_register_subchannel(struct subchannel *sch) | |||
135 | sch->dev.parent = &css[0]->device; | 135 | sch->dev.parent = &css[0]->device; |
136 | sch->dev.bus = &css_bus_type; | 136 | sch->dev.bus = &css_bus_type; |
137 | sch->dev.release = &css_subchannel_release; | 137 | sch->dev.release = &css_subchannel_release; |
138 | 138 | ||
139 | /* make it known to the system */ | 139 | /* make it known to the system */ |
140 | ret = css_sch_device_register(sch); | 140 | ret = css_sch_device_register(sch); |
141 | if (ret) | 141 | if (ret) { |
142 | printk (KERN_WARNING "%s: could not register %s\n", | 142 | printk (KERN_WARNING "%s: could not register %s\n", |
143 | __func__, sch->dev.bus_id); | 143 | __func__, sch->dev.bus_id); |
144 | else | 144 | return ret; |
145 | css_get_ssd_info(sch); | 145 | } |
146 | css_get_ssd_info(sch); | ||
147 | ret = subchannel_add_files(&sch->dev); | ||
148 | if (ret) | ||
149 | printk(KERN_WARNING "%s: could not add attributes to %s\n", | ||
150 | __func__, sch->dev.bus_id); | ||
146 | return ret; | 151 | return ret; |
147 | } | 152 | } |
148 | 153 | ||
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index dfd5462f993f..ac845c1ebf83 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -189,4 +189,6 @@ extern int need_rescan; | |||
189 | 189 | ||
190 | extern struct workqueue_struct *slow_path_wq; | 190 | extern struct workqueue_struct *slow_path_wq; |
191 | extern struct work_struct slow_path_work; | 191 | extern struct work_struct slow_path_work; |
192 | |||
193 | int subchannel_add_files (struct device *); | ||
192 | #endif | 194 | #endif |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 0f604621de40..e644fd6905ee 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -294,6 +294,18 @@ online_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
294 | return sprintf(buf, cdev->online ? "1\n" : "0\n"); | 294 | return sprintf(buf, cdev->online ? "1\n" : "0\n"); |
295 | } | 295 | } |
296 | 296 | ||
297 | static void ccw_device_unregister(struct work_struct *work) | ||
298 | { | ||
299 | struct ccw_device_private *priv; | ||
300 | struct ccw_device *cdev; | ||
301 | |||
302 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
303 | cdev = priv->cdev; | ||
304 | if (test_and_clear_bit(1, &cdev->private->registered)) | ||
305 | device_unregister(&cdev->dev); | ||
306 | put_device(&cdev->dev); | ||
307 | } | ||
308 | |||
297 | static void | 309 | static void |
298 | ccw_device_remove_disconnected(struct ccw_device *cdev) | 310 | ccw_device_remove_disconnected(struct ccw_device *cdev) |
299 | { | 311 | { |
@@ -498,8 +510,7 @@ static struct attribute_group subch_attr_group = { | |||
498 | .attrs = subch_attrs, | 510 | .attrs = subch_attrs, |
499 | }; | 511 | }; |
500 | 512 | ||
501 | static inline int | 513 | int subchannel_add_files (struct device *dev) |
502 | subchannel_add_files (struct device *dev) | ||
503 | { | 514 | { |
504 | return sysfs_create_group(&dev->kobj, &subch_attr_group); | 515 | return sysfs_create_group(&dev->kobj, &subch_attr_group); |
505 | } | 516 | } |
@@ -676,6 +687,55 @@ ccw_device_release(struct device *dev) | |||
676 | kfree(cdev); | 687 | kfree(cdev); |
677 | } | 688 | } |
678 | 689 | ||
690 | static struct ccw_device * io_subchannel_allocate_dev(struct subchannel *sch) | ||
691 | { | ||
692 | struct ccw_device *cdev; | ||
693 | |||
694 | cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); | ||
695 | if (cdev) { | ||
696 | cdev->private = kzalloc(sizeof(struct ccw_device_private), | ||
697 | GFP_KERNEL | GFP_DMA); | ||
698 | if (cdev->private) | ||
699 | return cdev; | ||
700 | } | ||
701 | kfree(cdev); | ||
702 | return ERR_PTR(-ENOMEM); | ||
703 | } | ||
704 | |||
705 | static int io_subchannel_initialize_dev(struct subchannel *sch, | ||
706 | struct ccw_device *cdev) | ||
707 | { | ||
708 | cdev->private->cdev = cdev; | ||
709 | atomic_set(&cdev->private->onoff, 0); | ||
710 | cdev->dev.parent = &sch->dev; | ||
711 | cdev->dev.release = ccw_device_release; | ||
712 | INIT_LIST_HEAD(&cdev->private->kick_work.entry); | ||
713 | /* Do first half of device_register. */ | ||
714 | device_initialize(&cdev->dev); | ||
715 | if (!get_device(&sch->dev)) { | ||
716 | if (cdev->dev.release) | ||
717 | cdev->dev.release(&cdev->dev); | ||
718 | return -ENODEV; | ||
719 | } | ||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | static struct ccw_device * io_subchannel_create_ccwdev(struct subchannel *sch) | ||
724 | { | ||
725 | struct ccw_device *cdev; | ||
726 | int ret; | ||
727 | |||
728 | cdev = io_subchannel_allocate_dev(sch); | ||
729 | if (!IS_ERR(cdev)) { | ||
730 | ret = io_subchannel_initialize_dev(sch, cdev); | ||
731 | if (ret) { | ||
732 | kfree(cdev); | ||
733 | cdev = ERR_PTR(ret); | ||
734 | } | ||
735 | } | ||
736 | return cdev; | ||
737 | } | ||
738 | |||
679 | /* | 739 | /* |
680 | * Register recognized device. | 740 | * Register recognized device. |
681 | */ | 741 | */ |
@@ -724,11 +784,6 @@ io_subchannel_register(struct work_struct *work) | |||
724 | wake_up(&ccw_device_init_wq); | 784 | wake_up(&ccw_device_init_wq); |
725 | return; | 785 | return; |
726 | } | 786 | } |
727 | |||
728 | ret = subchannel_add_files(cdev->dev.parent); | ||
729 | if (ret) | ||
730 | printk(KERN_WARNING "%s: could not add attributes to %s\n", | ||
731 | __func__, sch->dev.bus_id); | ||
732 | put_device(&cdev->dev); | 787 | put_device(&cdev->dev); |
733 | out: | 788 | out: |
734 | cdev->private->flags.recog_done = 1; | 789 | cdev->private->flags.recog_done = 1; |
@@ -851,7 +906,6 @@ io_subchannel_probe (struct subchannel *sch) | |||
851 | cdev = sch->dev.driver_data; | 906 | cdev = sch->dev.driver_data; |
852 | device_initialize(&cdev->dev); | 907 | device_initialize(&cdev->dev); |
853 | ccw_device_register(cdev); | 908 | ccw_device_register(cdev); |
854 | subchannel_add_files(&sch->dev); | ||
855 | /* | 909 | /* |
856 | * Check if the device is already online. If it is | 910 | * Check if the device is already online. If it is |
857 | * the reference count needs to be corrected | 911 | * the reference count needs to be corrected |
@@ -864,28 +918,9 @@ io_subchannel_probe (struct subchannel *sch) | |||
864 | get_device(&cdev->dev); | 918 | get_device(&cdev->dev); |
865 | return 0; | 919 | return 0; |
866 | } | 920 | } |
867 | cdev = kzalloc (sizeof(*cdev), GFP_KERNEL); | 921 | cdev = io_subchannel_create_ccwdev(sch); |
868 | if (!cdev) | 922 | if (IS_ERR(cdev)) |
869 | return -ENOMEM; | 923 | return PTR_ERR(cdev); |
870 | cdev->private = kzalloc(sizeof(struct ccw_device_private), | ||
871 | GFP_KERNEL | GFP_DMA); | ||
872 | if (!cdev->private) { | ||
873 | kfree(cdev); | ||
874 | return -ENOMEM; | ||
875 | } | ||
876 | cdev->private->cdev = cdev; | ||
877 | atomic_set(&cdev->private->onoff, 0); | ||
878 | cdev->dev.parent = &sch->dev; | ||
879 | cdev->dev.release = ccw_device_release; | ||
880 | INIT_LIST_HEAD(&cdev->private->kick_work.entry); | ||
881 | /* Do first half of device_register. */ | ||
882 | device_initialize(&cdev->dev); | ||
883 | |||
884 | if (!get_device(&sch->dev)) { | ||
885 | if (cdev->dev.release) | ||
886 | cdev->dev.release(&cdev->dev); | ||
887 | return -ENODEV; | ||
888 | } | ||
889 | 924 | ||
890 | rc = io_subchannel_recog(cdev, sch); | 925 | rc = io_subchannel_recog(cdev, sch); |
891 | if (rc) { | 926 | if (rc) { |
@@ -899,18 +934,6 @@ io_subchannel_probe (struct subchannel *sch) | |||
899 | return rc; | 934 | return rc; |
900 | } | 935 | } |
901 | 936 | ||
902 | static void ccw_device_unregister(struct work_struct *work) | ||
903 | { | ||
904 | struct ccw_device_private *priv; | ||
905 | struct ccw_device *cdev; | ||
906 | |||
907 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
908 | cdev = priv->cdev; | ||
909 | if (test_and_clear_bit(1, &cdev->private->registered)) | ||
910 | device_unregister(&cdev->dev); | ||
911 | put_device(&cdev->dev); | ||
912 | } | ||
913 | |||
914 | static int | 937 | static int |
915 | io_subchannel_remove (struct subchannel *sch) | 938 | io_subchannel_remove (struct subchannel *sch) |
916 | { | 939 | { |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 0f0301ce37fe..a487fb0e7d3d 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -1106,7 +1106,8 @@ device_trigger_reprobe(struct subchannel *sch) | |||
1106 | /* Update some values. */ | 1106 | /* Update some values. */ |
1107 | if (stsch(sch->schid, &sch->schib)) | 1107 | if (stsch(sch->schid, &sch->schib)) |
1108 | return; | 1108 | return; |
1109 | 1109 | if (!sch->schib.pmcw.dnv) | |
1110 | return; | ||
1110 | /* | 1111 | /* |
1111 | * The pim, pam, pom values may not be accurate, but they are the best | 1112 | * The pim, pam, pom values may not be accurate, but they are the best |
1112 | * we have before performing device selection :/ | 1113 | * we have before performing device selection :/ |