diff options
Diffstat (limited to 'drivers/s390/cio/css.c')
-rw-r--r-- | drivers/s390/cio/css.c | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 26cf2f5ae2e7..4c81d890791e 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -91,9 +91,9 @@ css_free_subchannel(struct subchannel *sch) | |||
91 | /* Reset intparm to zeroes. */ | 91 | /* Reset intparm to zeroes. */ |
92 | sch->schib.pmcw.intparm = 0; | 92 | sch->schib.pmcw.intparm = 0; |
93 | cio_modify(sch); | 93 | cio_modify(sch); |
94 | kfree(sch->lock); | ||
94 | kfree(sch); | 95 | kfree(sch); |
95 | } | 96 | } |
96 | |||
97 | } | 97 | } |
98 | 98 | ||
99 | static void | 99 | static void |
@@ -102,8 +102,10 @@ css_subchannel_release(struct device *dev) | |||
102 | struct subchannel *sch; | 102 | struct subchannel *sch; |
103 | 103 | ||
104 | sch = to_subchannel(dev); | 104 | sch = to_subchannel(dev); |
105 | if (!cio_is_console(sch->schid)) | 105 | if (!cio_is_console(sch->schid)) { |
106 | kfree(sch->lock); | ||
106 | kfree(sch); | 107 | kfree(sch); |
108 | } | ||
107 | } | 109 | } |
108 | 110 | ||
109 | extern int css_get_ssd_info(struct subchannel *sch); | 111 | extern int css_get_ssd_info(struct subchannel *sch); |
@@ -135,14 +137,16 @@ css_register_subchannel(struct subchannel *sch) | |||
135 | sch->dev.parent = &css[0]->device; | 137 | sch->dev.parent = &css[0]->device; |
136 | sch->dev.bus = &css_bus_type; | 138 | sch->dev.bus = &css_bus_type; |
137 | sch->dev.release = &css_subchannel_release; | 139 | sch->dev.release = &css_subchannel_release; |
138 | 140 | sch->dev.groups = subch_attr_groups; | |
141 | |||
139 | /* make it known to the system */ | 142 | /* make it known to the system */ |
140 | ret = css_sch_device_register(sch); | 143 | ret = css_sch_device_register(sch); |
141 | if (ret) | 144 | if (ret) { |
142 | printk (KERN_WARNING "%s: could not register %s\n", | 145 | printk (KERN_WARNING "%s: could not register %s\n", |
143 | __func__, sch->dev.bus_id); | 146 | __func__, sch->dev.bus_id); |
144 | else | 147 | return ret; |
145 | css_get_ssd_info(sch); | 148 | } |
149 | css_get_ssd_info(sch); | ||
146 | return ret; | 150 | return ret; |
147 | } | 151 | } |
148 | 152 | ||
@@ -201,18 +205,18 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) | |||
201 | unsigned long flags; | 205 | unsigned long flags; |
202 | enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action; | 206 | enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action; |
203 | 207 | ||
204 | spin_lock_irqsave(&sch->lock, flags); | 208 | spin_lock_irqsave(sch->lock, flags); |
205 | disc = device_is_disconnected(sch); | 209 | disc = device_is_disconnected(sch); |
206 | if (disc && slow) { | 210 | if (disc && slow) { |
207 | /* Disconnected devices are evaluated directly only.*/ | 211 | /* Disconnected devices are evaluated directly only.*/ |
208 | spin_unlock_irqrestore(&sch->lock, flags); | 212 | spin_unlock_irqrestore(sch->lock, flags); |
209 | return 0; | 213 | return 0; |
210 | } | 214 | } |
211 | /* No interrupt after machine check - kill pending timers. */ | 215 | /* No interrupt after machine check - kill pending timers. */ |
212 | device_kill_pending_timer(sch); | 216 | device_kill_pending_timer(sch); |
213 | if (!disc && !slow) { | 217 | if (!disc && !slow) { |
214 | /* Non-disconnected devices are evaluated on the slow path. */ | 218 | /* Non-disconnected devices are evaluated on the slow path. */ |
215 | spin_unlock_irqrestore(&sch->lock, flags); | 219 | spin_unlock_irqrestore(sch->lock, flags); |
216 | return -EAGAIN; | 220 | return -EAGAIN; |
217 | } | 221 | } |
218 | event = css_get_subchannel_status(sch); | 222 | event = css_get_subchannel_status(sch); |
@@ -237,9 +241,9 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) | |||
237 | /* Ask driver what to do with device. */ | 241 | /* Ask driver what to do with device. */ |
238 | action = UNREGISTER; | 242 | action = UNREGISTER; |
239 | if (sch->driver && sch->driver->notify) { | 243 | if (sch->driver && sch->driver->notify) { |
240 | spin_unlock_irqrestore(&sch->lock, flags); | 244 | spin_unlock_irqrestore(sch->lock, flags); |
241 | ret = sch->driver->notify(&sch->dev, event); | 245 | ret = sch->driver->notify(&sch->dev, event); |
242 | spin_lock_irqsave(&sch->lock, flags); | 246 | spin_lock_irqsave(sch->lock, flags); |
243 | if (ret) | 247 | if (ret) |
244 | action = NONE; | 248 | action = NONE; |
245 | } | 249 | } |
@@ -264,9 +268,9 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) | |||
264 | case UNREGISTER: | 268 | case UNREGISTER: |
265 | case UNREGISTER_PROBE: | 269 | case UNREGISTER_PROBE: |
266 | /* Unregister device (will use subchannel lock). */ | 270 | /* Unregister device (will use subchannel lock). */ |
267 | spin_unlock_irqrestore(&sch->lock, flags); | 271 | spin_unlock_irqrestore(sch->lock, flags); |
268 | css_sch_device_unregister(sch); | 272 | css_sch_device_unregister(sch); |
269 | spin_lock_irqsave(&sch->lock, flags); | 273 | spin_lock_irqsave(sch->lock, flags); |
270 | 274 | ||
271 | /* Reset intparm to zeroes. */ | 275 | /* Reset intparm to zeroes. */ |
272 | sch->schib.pmcw.intparm = 0; | 276 | sch->schib.pmcw.intparm = 0; |
@@ -278,7 +282,7 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) | |||
278 | default: | 282 | default: |
279 | break; | 283 | break; |
280 | } | 284 | } |
281 | spin_unlock_irqrestore(&sch->lock, flags); | 285 | spin_unlock_irqrestore(sch->lock, flags); |
282 | /* Probe if necessary. */ | 286 | /* Probe if necessary. */ |
283 | if (action == UNREGISTER_PROBE) | 287 | if (action == UNREGISTER_PROBE) |
284 | ret = css_probe_device(sch->schid); | 288 | ret = css_probe_device(sch->schid); |
@@ -573,12 +577,24 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, | |||
573 | 577 | ||
574 | static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store); | 578 | static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store); |
575 | 579 | ||
576 | static inline void __init | 580 | static inline int __init setup_css(int nr) |
577 | setup_css(int nr) | ||
578 | { | 581 | { |
579 | u32 tod_high; | 582 | u32 tod_high; |
583 | int ret; | ||
580 | 584 | ||
581 | memset(css[nr], 0, sizeof(struct channel_subsystem)); | 585 | memset(css[nr], 0, sizeof(struct channel_subsystem)); |
586 | css[nr]->pseudo_subchannel = | ||
587 | kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL); | ||
588 | if (!css[nr]->pseudo_subchannel) | ||
589 | return -ENOMEM; | ||
590 | css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device; | ||
591 | css[nr]->pseudo_subchannel->dev.release = css_subchannel_release; | ||
592 | sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct"); | ||
593 | ret = cio_create_sch_lock(css[nr]->pseudo_subchannel); | ||
594 | if (ret) { | ||
595 | kfree(css[nr]->pseudo_subchannel); | ||
596 | return ret; | ||
597 | } | ||
582 | mutex_init(&css[nr]->mutex); | 598 | mutex_init(&css[nr]->mutex); |
583 | css[nr]->valid = 1; | 599 | css[nr]->valid = 1; |
584 | css[nr]->cssid = nr; | 600 | css[nr]->cssid = nr; |
@@ -586,6 +602,7 @@ setup_css(int nr) | |||
586 | css[nr]->device.release = channel_subsystem_release; | 602 | css[nr]->device.release = channel_subsystem_release; |
587 | tod_high = (u32) (get_clock() >> 32); | 603 | tod_high = (u32) (get_clock() >> 32); |
588 | css_generate_pgid(css[nr], tod_high); | 604 | css_generate_pgid(css[nr], tod_high); |
605 | return 0; | ||
589 | } | 606 | } |
590 | 607 | ||
591 | /* | 608 | /* |
@@ -622,10 +639,12 @@ init_channel_subsystem (void) | |||
622 | ret = -ENOMEM; | 639 | ret = -ENOMEM; |
623 | goto out_unregister; | 640 | goto out_unregister; |
624 | } | 641 | } |
625 | setup_css(i); | 642 | ret = setup_css(i); |
626 | ret = device_register(&css[i]->device); | ||
627 | if (ret) | 643 | if (ret) |
628 | goto out_free; | 644 | goto out_free; |
645 | ret = device_register(&css[i]->device); | ||
646 | if (ret) | ||
647 | goto out_free_all; | ||
629 | if (css_characteristics_avail && | 648 | if (css_characteristics_avail && |
630 | css_chsc_characteristics.secm) { | 649 | css_chsc_characteristics.secm) { |
631 | ret = device_create_file(&css[i]->device, | 650 | ret = device_create_file(&css[i]->device, |
@@ -633,6 +652,9 @@ init_channel_subsystem (void) | |||
633 | if (ret) | 652 | if (ret) |
634 | goto out_device; | 653 | goto out_device; |
635 | } | 654 | } |
655 | ret = device_register(&css[i]->pseudo_subchannel->dev); | ||
656 | if (ret) | ||
657 | goto out_file; | ||
636 | } | 658 | } |
637 | css_init_done = 1; | 659 | css_init_done = 1; |
638 | 660 | ||
@@ -640,13 +662,19 @@ init_channel_subsystem (void) | |||
640 | 662 | ||
641 | for_each_subchannel(__init_channel_subsystem, NULL); | 663 | for_each_subchannel(__init_channel_subsystem, NULL); |
642 | return 0; | 664 | return 0; |
665 | out_file: | ||
666 | device_remove_file(&css[i]->device, &dev_attr_cm_enable); | ||
643 | out_device: | 667 | out_device: |
644 | device_unregister(&css[i]->device); | 668 | device_unregister(&css[i]->device); |
669 | out_free_all: | ||
670 | kfree(css[i]->pseudo_subchannel->lock); | ||
671 | kfree(css[i]->pseudo_subchannel); | ||
645 | out_free: | 672 | out_free: |
646 | kfree(css[i]); | 673 | kfree(css[i]); |
647 | out_unregister: | 674 | out_unregister: |
648 | while (i > 0) { | 675 | while (i > 0) { |
649 | i--; | 676 | i--; |
677 | device_unregister(&css[i]->pseudo_subchannel->dev); | ||
650 | if (css_characteristics_avail && css_chsc_characteristics.secm) | 678 | if (css_characteristics_avail && css_chsc_characteristics.secm) |
651 | device_remove_file(&css[i]->device, | 679 | device_remove_file(&css[i]->device, |
652 | &dev_attr_cm_enable); | 680 | &dev_attr_cm_enable); |
@@ -658,6 +686,11 @@ out: | |||
658 | return ret; | 686 | return ret; |
659 | } | 687 | } |
660 | 688 | ||
689 | int sch_is_pseudo_sch(struct subchannel *sch) | ||
690 | { | ||
691 | return sch == to_css(sch->dev.parent)->pseudo_subchannel; | ||
692 | } | ||
693 | |||
661 | /* | 694 | /* |
662 | * find a driver for a subchannel. They identify by the subchannel | 695 | * find a driver for a subchannel. They identify by the subchannel |
663 | * type with the exception that the console subchannel driver has its own | 696 | * type with the exception that the console subchannel driver has its own |