aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/css.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/css.c')
-rw-r--r--drivers/s390/cio/css.c69
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
99static void 99static 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
109extern int css_get_ssd_info(struct subchannel *sch); 111extern 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
574static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store); 578static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);
575 579
576static inline void __init 580static inline int __init setup_css(int nr)
577setup_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;
665out_file:
666 device_remove_file(&css[i]->device, &dev_attr_cm_enable);
643out_device: 667out_device:
644 device_unregister(&css[i]->device); 668 device_unregister(&css[i]->device);
669out_free_all:
670 kfree(css[i]->pseudo_subchannel->lock);
671 kfree(css[i]->pseudo_subchannel);
645out_free: 672out_free:
646 kfree(css[i]); 673 kfree(css[i]);
647out_unregister: 674out_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
689int 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