aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/css.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /drivers/s390/cio/css.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/s390/cio/css.c')
-rw-r--r--drivers/s390/cio/css.c152
1 files changed, 129 insertions, 23 deletions
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 91c25706fa83..511649115bd7 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -18,6 +18,7 @@
18#include <linux/list.h> 18#include <linux/list.h>
19#include <linux/reboot.h> 19#include <linux/reboot.h>
20#include <linux/suspend.h> 20#include <linux/suspend.h>
21#include <linux/proc_fs.h>
21#include <asm/isc.h> 22#include <asm/isc.h>
22#include <asm/crw.h> 23#include <asm/crw.h>
23 24
@@ -133,6 +134,8 @@ out:
133 return rc; 134 return rc;
134} 135}
135 136
137static void css_sch_todo(struct work_struct *work);
138
136static struct subchannel * 139static struct subchannel *
137css_alloc_subchannel(struct subchannel_id schid) 140css_alloc_subchannel(struct subchannel_id schid)
138{ 141{
@@ -147,6 +150,7 @@ css_alloc_subchannel(struct subchannel_id schid)
147 kfree(sch); 150 kfree(sch);
148 return ERR_PTR(ret); 151 return ERR_PTR(ret);
149 } 152 }
153 INIT_WORK(&sch->todo_work, css_sch_todo);
150 return sch; 154 return sch;
151} 155}
152 156
@@ -190,6 +194,51 @@ void css_sch_device_unregister(struct subchannel *sch)
190} 194}
191EXPORT_SYMBOL_GPL(css_sch_device_unregister); 195EXPORT_SYMBOL_GPL(css_sch_device_unregister);
192 196
197static void css_sch_todo(struct work_struct *work)
198{
199 struct subchannel *sch;
200 enum sch_todo todo;
201
202 sch = container_of(work, struct subchannel, todo_work);
203 /* Find out todo. */
204 spin_lock_irq(sch->lock);
205 todo = sch->todo;
206 CIO_MSG_EVENT(4, "sch_todo: sch=0.%x.%04x, todo=%d\n", sch->schid.ssid,
207 sch->schid.sch_no, todo);
208 sch->todo = SCH_TODO_NOTHING;
209 spin_unlock_irq(sch->lock);
210 /* Perform todo. */
211 if (todo == SCH_TODO_UNREG)
212 css_sch_device_unregister(sch);
213 /* Release workqueue ref. */
214 put_device(&sch->dev);
215}
216
217/**
218 * css_sched_sch_todo - schedule a subchannel operation
219 * @sch: subchannel
220 * @todo: todo
221 *
222 * Schedule the operation identified by @todo to be performed on the slow path
223 * workqueue. Do nothing if another operation with higher priority is already
224 * scheduled. Needs to be called with subchannel lock held.
225 */
226void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo)
227{
228 CIO_MSG_EVENT(4, "sch_todo: sched sch=0.%x.%04x todo=%d\n",
229 sch->schid.ssid, sch->schid.sch_no, todo);
230 if (sch->todo >= todo)
231 return;
232 /* Get workqueue ref. */
233 if (!get_device(&sch->dev))
234 return;
235 sch->todo = todo;
236 if (!queue_work(cio_work_q, &sch->todo_work)) {
237 /* Already queued, release workqueue ref. */
238 put_device(&sch->dev);
239 }
240}
241
193static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw) 242static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw)
194{ 243{
195 int i; 244 int i;
@@ -376,8 +425,8 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
376 /* Unusable - ignore. */ 425 /* Unusable - ignore. */
377 return 0; 426 return 0;
378 } 427 }
379 CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, unknown, " 428 CIO_MSG_EVENT(4, "event: sch 0.%x.%04x, new\n", schid.ssid,
380 "slow path.\n", schid.ssid, schid.sch_no, CIO_OPER); 429 schid.sch_no);
381 430
382 return css_probe_device(schid); 431 return css_probe_device(schid);
383} 432}
@@ -394,6 +443,10 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
394 "Got subchannel machine check but " 443 "Got subchannel machine check but "
395 "no sch_event handler provided.\n"); 444 "no sch_event handler provided.\n");
396 } 445 }
446 if (ret != 0 && ret != -EAGAIN) {
447 CIO_MSG_EVENT(2, "eval: sch 0.%x.%04x, rc=%d\n",
448 sch->schid.ssid, sch->schid.sch_no, ret);
449 }
397 return ret; 450 return ret;
398} 451}
399 452
@@ -491,7 +544,7 @@ static void css_slow_path_func(struct work_struct *unused)
491} 544}
492 545
493static DECLARE_WORK(slow_path_work, css_slow_path_func); 546static DECLARE_WORK(slow_path_work, css_slow_path_func);
494struct workqueue_struct *slow_path_wq; 547struct workqueue_struct *cio_work_q;
495 548
496void css_schedule_eval(struct subchannel_id schid) 549void css_schedule_eval(struct subchannel_id schid)
497{ 550{
@@ -500,7 +553,7 @@ void css_schedule_eval(struct subchannel_id schid)
500 spin_lock_irqsave(&slow_subchannel_lock, flags); 553 spin_lock_irqsave(&slow_subchannel_lock, flags);
501 idset_sch_add(slow_subchannel_set, schid); 554 idset_sch_add(slow_subchannel_set, schid);
502 atomic_set(&css_eval_scheduled, 1); 555 atomic_set(&css_eval_scheduled, 1);
503 queue_work(slow_path_wq, &slow_path_work); 556 queue_work(cio_work_q, &slow_path_work);
504 spin_unlock_irqrestore(&slow_subchannel_lock, flags); 557 spin_unlock_irqrestore(&slow_subchannel_lock, flags);
505} 558}
506 559
@@ -511,7 +564,7 @@ void css_schedule_eval_all(void)
511 spin_lock_irqsave(&slow_subchannel_lock, flags); 564 spin_lock_irqsave(&slow_subchannel_lock, flags);
512 idset_fill(slow_subchannel_set); 565 idset_fill(slow_subchannel_set);
513 atomic_set(&css_eval_scheduled, 1); 566 atomic_set(&css_eval_scheduled, 1);
514 queue_work(slow_path_wq, &slow_path_work); 567 queue_work(cio_work_q, &slow_path_work);
515 spin_unlock_irqrestore(&slow_subchannel_lock, flags); 568 spin_unlock_irqrestore(&slow_subchannel_lock, flags);
516} 569}
517 570
@@ -542,14 +595,14 @@ void css_schedule_eval_all_unreg(void)
542 spin_lock_irqsave(&slow_subchannel_lock, flags); 595 spin_lock_irqsave(&slow_subchannel_lock, flags);
543 idset_add_set(slow_subchannel_set, unreg_set); 596 idset_add_set(slow_subchannel_set, unreg_set);
544 atomic_set(&css_eval_scheduled, 1); 597 atomic_set(&css_eval_scheduled, 1);
545 queue_work(slow_path_wq, &slow_path_work); 598 queue_work(cio_work_q, &slow_path_work);
546 spin_unlock_irqrestore(&slow_subchannel_lock, flags); 599 spin_unlock_irqrestore(&slow_subchannel_lock, flags);
547 idset_free(unreg_set); 600 idset_free(unreg_set);
548} 601}
549 602
550void css_wait_for_slow_path(void) 603void css_wait_for_slow_path(void)
551{ 604{
552 flush_workqueue(slow_path_wq); 605 flush_workqueue(cio_work_q);
553} 606}
554 607
555/* Schedule reprobing of all unregistered subchannels. */ 608/* Schedule reprobing of all unregistered subchannels. */
@@ -684,6 +737,7 @@ static int __init setup_css(int nr)
684 css->pseudo_subchannel->dev.parent = &css->device; 737 css->pseudo_subchannel->dev.parent = &css->device;
685 css->pseudo_subchannel->dev.release = css_subchannel_release; 738 css->pseudo_subchannel->dev.release = css_subchannel_release;
686 dev_set_name(&css->pseudo_subchannel->dev, "defunct"); 739 dev_set_name(&css->pseudo_subchannel->dev, "defunct");
740 mutex_init(&css->pseudo_subchannel->reg_mutex);
687 ret = cio_create_sch_lock(css->pseudo_subchannel); 741 ret = cio_create_sch_lock(css->pseudo_subchannel);
688 if (ret) { 742 if (ret) {
689 kfree(css->pseudo_subchannel); 743 kfree(css->pseudo_subchannel);
@@ -816,15 +870,10 @@ static int __init css_bus_init(void)
816 870
817 /* Try to enable MSS. */ 871 /* Try to enable MSS. */
818 ret = chsc_enable_facility(CHSC_SDA_OC_MSS); 872 ret = chsc_enable_facility(CHSC_SDA_OC_MSS);
819 switch (ret) { 873 if (ret)
820 case 0: /* Success. */
821 max_ssid = __MAX_SSID;
822 break;
823 case -ENOMEM:
824 goto out;
825 default:
826 max_ssid = 0; 874 max_ssid = 0;
827 } 875 else /* Success. */
876 max_ssid = __MAX_SSID;
828 877
829 ret = slow_subchannel_init(); 878 ret = slow_subchannel_init();
830 if (ret) 879 if (ret)
@@ -939,12 +988,21 @@ static int __init channel_subsystem_init(void)
939 ret = css_bus_init(); 988 ret = css_bus_init();
940 if (ret) 989 if (ret)
941 return ret; 990 return ret;
942 991 cio_work_q = create_singlethread_workqueue("cio");
992 if (!cio_work_q) {
993 ret = -ENOMEM;
994 goto out_bus;
995 }
943 ret = io_subchannel_init(); 996 ret = io_subchannel_init();
944 if (ret) 997 if (ret)
945 css_bus_cleanup(); 998 goto out_wq;
946 999
947 return ret; 1000 return ret;
1001out_wq:
1002 destroy_workqueue(cio_work_q);
1003out_bus:
1004 css_bus_cleanup();
1005 return ret;
948} 1006}
949subsys_initcall(channel_subsystem_init); 1007subsys_initcall(channel_subsystem_init);
950 1008
@@ -953,10 +1011,25 @@ static int css_settle(struct device_driver *drv, void *unused)
953 struct css_driver *cssdrv = to_cssdriver(drv); 1011 struct css_driver *cssdrv = to_cssdriver(drv);
954 1012
955 if (cssdrv->settle) 1013 if (cssdrv->settle)
956 cssdrv->settle(); 1014 return cssdrv->settle();
957 return 0; 1015 return 0;
958} 1016}
959 1017
1018int css_complete_work(void)
1019{
1020 int ret;
1021
1022 /* Wait for the evaluation of subchannels to finish. */
1023 ret = wait_event_interruptible(css_eval_wq,
1024 atomic_read(&css_eval_scheduled) == 0);
1025 if (ret)
1026 return -EINTR;
1027 flush_workqueue(cio_work_q);
1028 /* Wait for the subchannel type specific initialization to finish */
1029 return bus_for_each_drv(&css_bus_type, NULL, NULL, css_settle);
1030}
1031
1032
960/* 1033/*
961 * Wait for the initialization of devices to finish, to make sure we are 1034 * Wait for the initialization of devices to finish, to make sure we are
962 * done with our setup if the search for the root device starts. 1035 * done with our setup if the search for the root device starts.
@@ -965,13 +1038,46 @@ static int __init channel_subsystem_init_sync(void)
965{ 1038{
966 /* Start initial subchannel evaluation. */ 1039 /* Start initial subchannel evaluation. */
967 css_schedule_eval_all(); 1040 css_schedule_eval_all();
968 /* Wait for the evaluation of subchannels to finish. */ 1041 css_complete_work();
969 wait_event(css_eval_wq, atomic_read(&css_eval_scheduled) == 0); 1042 return 0;
970 /* Wait for the subchannel type specific initialization to finish */
971 return bus_for_each_drv(&css_bus_type, NULL, NULL, css_settle);
972} 1043}
973subsys_initcall_sync(channel_subsystem_init_sync); 1044subsys_initcall_sync(channel_subsystem_init_sync);
974 1045
1046void channel_subsystem_reinit(void)
1047{
1048 chsc_enable_facility(CHSC_SDA_OC_MSS);
1049}
1050
1051#ifdef CONFIG_PROC_FS
1052static ssize_t cio_settle_write(struct file *file, const char __user *buf,
1053 size_t count, loff_t *ppos)
1054{
1055 int ret;
1056
1057 /* Handle pending CRW's. */
1058 crw_wait_for_channel_report();
1059 ret = css_complete_work();
1060
1061 return ret ? ret : count;
1062}
1063
1064static const struct file_operations cio_settle_proc_fops = {
1065 .write = cio_settle_write,
1066};
1067
1068static int __init cio_settle_init(void)
1069{
1070 struct proc_dir_entry *entry;
1071
1072 entry = proc_create("cio_settle", S_IWUSR, NULL,
1073 &cio_settle_proc_fops);
1074 if (!entry)
1075 return -ENOMEM;
1076 return 0;
1077}
1078device_initcall(cio_settle_init);
1079#endif /*CONFIG_PROC_FS*/
1080
975int sch_is_pseudo_sch(struct subchannel *sch) 1081int sch_is_pseudo_sch(struct subchannel *sch)
976{ 1082{
977 return sch == to_css(sch->dev.parent)->pseudo_subchannel; 1083 return sch == to_css(sch->dev.parent)->pseudo_subchannel;
@@ -1095,7 +1201,7 @@ static int css_pm_restore(struct device *dev)
1095 return drv->restore ? drv->restore(sch) : 0; 1201 return drv->restore ? drv->restore(sch) : 0;
1096} 1202}
1097 1203
1098static struct dev_pm_ops css_pm_ops = { 1204static const struct dev_pm_ops css_pm_ops = {
1099 .prepare = css_pm_prepare, 1205 .prepare = css_pm_prepare,
1100 .complete = css_pm_complete, 1206 .complete = css_pm_complete,
1101 .freeze = css_pm_freeze, 1207 .freeze = css_pm_freeze,