aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/cio/chsc.c7
-rw-r--r--drivers/s390/cio/cio.h5
-rw-r--r--drivers/s390/cio/css.c104
-rw-r--r--drivers/s390/cio/device.c4
-rw-r--r--drivers/s390/cio/device_fsm.c30
-rw-r--r--drivers/s390/cio/device_ops.c20
-rw-r--r--drivers/s390/cio/io_sch.h5
-rw-r--r--drivers/s390/crypto/ap_bus.c2
8 files changed, 111 insertions, 66 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 75c3f1f8fd43..a84631a7391d 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -529,10 +529,7 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data)
529int chsc_chp_vary(struct chp_id chpid, int on) 529int chsc_chp_vary(struct chp_id chpid, int on)
530{ 530{
531 struct channel_path *chp = chpid_to_chp(chpid); 531 struct channel_path *chp = chpid_to_chp(chpid);
532 struct chp_link link;
533 532
534 memset(&link, 0, sizeof(struct chp_link));
535 link.chpid = chpid;
536 /* Wait until previous actions have settled. */ 533 /* Wait until previous actions have settled. */
537 css_wait_for_slow_path(); 534 css_wait_for_slow_path();
538 /* 535 /*
@@ -542,10 +539,10 @@ int chsc_chp_vary(struct chp_id chpid, int on)
542 /* Try to update the channel path descritor. */ 539 /* Try to update the channel path descritor. */
543 chsc_determine_base_channel_path_desc(chpid, &chp->desc); 540 chsc_determine_base_channel_path_desc(chpid, &chp->desc);
544 for_each_subchannel_staged(s390_subchannel_vary_chpid_on, 541 for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
545 __s390_vary_chpid_on, &link); 542 __s390_vary_chpid_on, &chpid);
546 } else 543 } else
547 for_each_subchannel_staged(s390_subchannel_vary_chpid_off, 544 for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
548 NULL, &link); 545 NULL, &chpid);
549 546
550 return 0; 547 return 0;
551} 548}
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 155a82bcb9e5..4a1ff5c2eb88 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -68,8 +68,13 @@ struct schib {
68 __u8 mda[4]; /* model dependent area */ 68 __u8 mda[4]; /* model dependent area */
69} __attribute__ ((packed,aligned(4))); 69} __attribute__ ((packed,aligned(4)));
70 70
71/*
72 * When rescheduled, todo's with higher values will overwrite those
73 * with lower values.
74 */
71enum sch_todo { 75enum sch_todo {
72 SCH_TODO_NOTHING, 76 SCH_TODO_NOTHING,
77 SCH_TODO_EVAL,
73 SCH_TODO_UNREG, 78 SCH_TODO_UNREG,
74}; 79};
75 80
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 92d7324acb1c..21908e67bf67 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -195,51 +195,6 @@ void css_sch_device_unregister(struct subchannel *sch)
195} 195}
196EXPORT_SYMBOL_GPL(css_sch_device_unregister); 196EXPORT_SYMBOL_GPL(css_sch_device_unregister);
197 197
198static void css_sch_todo(struct work_struct *work)
199{
200 struct subchannel *sch;
201 enum sch_todo todo;
202
203 sch = container_of(work, struct subchannel, todo_work);
204 /* Find out todo. */
205 spin_lock_irq(sch->lock);
206 todo = sch->todo;
207 CIO_MSG_EVENT(4, "sch_todo: sch=0.%x.%04x, todo=%d\n", sch->schid.ssid,
208 sch->schid.sch_no, todo);
209 sch->todo = SCH_TODO_NOTHING;
210 spin_unlock_irq(sch->lock);
211 /* Perform todo. */
212 if (todo == SCH_TODO_UNREG)
213 css_sch_device_unregister(sch);
214 /* Release workqueue ref. */
215 put_device(&sch->dev);
216}
217
218/**
219 * css_sched_sch_todo - schedule a subchannel operation
220 * @sch: subchannel
221 * @todo: todo
222 *
223 * Schedule the operation identified by @todo to be performed on the slow path
224 * workqueue. Do nothing if another operation with higher priority is already
225 * scheduled. Needs to be called with subchannel lock held.
226 */
227void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo)
228{
229 CIO_MSG_EVENT(4, "sch_todo: sched sch=0.%x.%04x todo=%d\n",
230 sch->schid.ssid, sch->schid.sch_no, todo);
231 if (sch->todo >= todo)
232 return;
233 /* Get workqueue ref. */
234 if (!get_device(&sch->dev))
235 return;
236 sch->todo = todo;
237 if (!queue_work(cio_work_q, &sch->todo_work)) {
238 /* Already queued, release workqueue ref. */
239 put_device(&sch->dev);
240 }
241}
242
243static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw) 198static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw)
244{ 199{
245 int i; 200 int i;
@@ -466,6 +421,65 @@ static void css_evaluate_subchannel(struct subchannel_id schid, int slow)
466 css_schedule_eval(schid); 421 css_schedule_eval(schid);
467} 422}
468 423
424/**
425 * css_sched_sch_todo - schedule a subchannel operation
426 * @sch: subchannel
427 * @todo: todo
428 *
429 * Schedule the operation identified by @todo to be performed on the slow path
430 * workqueue. Do nothing if another operation with higher priority is already
431 * scheduled. Needs to be called with subchannel lock held.
432 */
433void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo)
434{
435 CIO_MSG_EVENT(4, "sch_todo: sched sch=0.%x.%04x todo=%d\n",
436 sch->schid.ssid, sch->schid.sch_no, todo);
437 if (sch->todo >= todo)
438 return;
439 /* Get workqueue ref. */
440 if (!get_device(&sch->dev))
441 return;
442 sch->todo = todo;
443 if (!queue_work(cio_work_q, &sch->todo_work)) {
444 /* Already queued, release workqueue ref. */
445 put_device(&sch->dev);
446 }
447}
448
449static void css_sch_todo(struct work_struct *work)
450{
451 struct subchannel *sch;
452 enum sch_todo todo;
453 int ret;
454
455 sch = container_of(work, struct subchannel, todo_work);
456 /* Find out todo. */
457 spin_lock_irq(sch->lock);
458 todo = sch->todo;
459 CIO_MSG_EVENT(4, "sch_todo: sch=0.%x.%04x, todo=%d\n", sch->schid.ssid,
460 sch->schid.sch_no, todo);
461 sch->todo = SCH_TODO_NOTHING;
462 spin_unlock_irq(sch->lock);
463 /* Perform todo. */
464 switch (todo) {
465 case SCH_TODO_NOTHING:
466 break;
467 case SCH_TODO_EVAL:
468 ret = css_evaluate_known_subchannel(sch, 1);
469 if (ret == -EAGAIN) {
470 spin_lock_irq(sch->lock);
471 css_sched_sch_todo(sch, todo);
472 spin_unlock_irq(sch->lock);
473 }
474 break;
475 case SCH_TODO_UNREG:
476 css_sch_device_unregister(sch);
477 break;
478 }
479 /* Release workqueue ref. */
480 put_device(&sch->dev);
481}
482
469static struct idset *slow_subchannel_set; 483static struct idset *slow_subchannel_set;
470static spinlock_t slow_subchannel_lock; 484static spinlock_t slow_subchannel_lock;
471static wait_queue_head_t css_eval_wq; 485static wait_queue_head_t css_eval_wq;
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index d734f4a0ecac..47269858ecb6 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1868,9 +1868,9 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev)
1868 */ 1868 */
1869 cdev->private->flags.resuming = 1; 1869 cdev->private->flags.resuming = 1;
1870 cdev->private->path_new_mask = LPM_ANYPATH; 1870 cdev->private->path_new_mask = LPM_ANYPATH;
1871 css_schedule_eval(sch->schid); 1871 css_sched_sch_todo(sch, SCH_TODO_EVAL);
1872 spin_unlock_irq(sch->lock); 1872 spin_unlock_irq(sch->lock);
1873 css_complete_work(); 1873 css_wait_for_slow_path();
1874 1874
1875 /* cdev may have been moved to a different subchannel. */ 1875 /* cdev may have been moved to a different subchannel. */
1876 sch = to_subchannel(cdev->dev.parent); 1876 sch = to_subchannel(cdev->dev.parent);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 52c233fa2b12..1b853513c891 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -496,8 +496,26 @@ static void ccw_device_reset_path_events(struct ccw_device *cdev)
496 cdev->private->pgid_reset_mask = 0; 496 cdev->private->pgid_reset_mask = 0;
497} 497}
498 498
499void 499static void create_fake_irb(struct irb *irb, int type)
500ccw_device_verify_done(struct ccw_device *cdev, int err) 500{
501 memset(irb, 0, sizeof(*irb));
502 if (type == FAKE_CMD_IRB) {
503 struct cmd_scsw *scsw = &irb->scsw.cmd;
504 scsw->cc = 1;
505 scsw->fctl = SCSW_FCTL_START_FUNC;
506 scsw->actl = SCSW_ACTL_START_PEND;
507 scsw->stctl = SCSW_STCTL_STATUS_PEND;
508 } else if (type == FAKE_TM_IRB) {
509 struct tm_scsw *scsw = &irb->scsw.tm;
510 scsw->x = 1;
511 scsw->cc = 1;
512 scsw->fctl = SCSW_FCTL_START_FUNC;
513 scsw->actl = SCSW_ACTL_START_PEND;
514 scsw->stctl = SCSW_STCTL_STATUS_PEND;
515 }
516}
517
518void ccw_device_verify_done(struct ccw_device *cdev, int err)
501{ 519{
502 struct subchannel *sch; 520 struct subchannel *sch;
503 521
@@ -520,12 +538,8 @@ callback:
520 ccw_device_done(cdev, DEV_STATE_ONLINE); 538 ccw_device_done(cdev, DEV_STATE_ONLINE);
521 /* Deliver fake irb to device driver, if needed. */ 539 /* Deliver fake irb to device driver, if needed. */
522 if (cdev->private->flags.fake_irb) { 540 if (cdev->private->flags.fake_irb) {
523 memset(&cdev->private->irb, 0, sizeof(struct irb)); 541 create_fake_irb(&cdev->private->irb,
524 cdev->private->irb.scsw.cmd.cc = 1; 542 cdev->private->flags.fake_irb);
525 cdev->private->irb.scsw.cmd.fctl = SCSW_FCTL_START_FUNC;
526 cdev->private->irb.scsw.cmd.actl = SCSW_ACTL_START_PEND;
527 cdev->private->irb.scsw.cmd.stctl =
528 SCSW_STCTL_STATUS_PEND;
529 cdev->private->flags.fake_irb = 0; 543 cdev->private->flags.fake_irb = 0;
530 if (cdev->handler) 544 if (cdev->handler)
531 cdev->handler(cdev, cdev->private->intparm, 545 cdev->handler(cdev, cdev->private->intparm,
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index f98698d5735e..ec7fb6d3b479 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -198,7 +198,7 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
198 if (cdev->private->state == DEV_STATE_VERIFY) { 198 if (cdev->private->state == DEV_STATE_VERIFY) {
199 /* Remember to fake irb when finished. */ 199 /* Remember to fake irb when finished. */
200 if (!cdev->private->flags.fake_irb) { 200 if (!cdev->private->flags.fake_irb) {
201 cdev->private->flags.fake_irb = 1; 201 cdev->private->flags.fake_irb = FAKE_CMD_IRB;
202 cdev->private->intparm = intparm; 202 cdev->private->intparm = intparm;
203 return 0; 203 return 0;
204 } else 204 } else
@@ -213,9 +213,9 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
213 ret = cio_set_options (sch, flags); 213 ret = cio_set_options (sch, flags);
214 if (ret) 214 if (ret)
215 return ret; 215 return ret;
216 /* Adjust requested path mask to excluded varied off paths. */ 216 /* Adjust requested path mask to exclude unusable paths. */
217 if (lpm) { 217 if (lpm) {
218 lpm &= sch->opm; 218 lpm &= sch->lpm;
219 if (lpm == 0) 219 if (lpm == 0)
220 return -EACCES; 220 return -EACCES;
221 } 221 }
@@ -605,11 +605,21 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
605 sch = to_subchannel(cdev->dev.parent); 605 sch = to_subchannel(cdev->dev.parent);
606 if (!sch->schib.pmcw.ena) 606 if (!sch->schib.pmcw.ena)
607 return -EINVAL; 607 return -EINVAL;
608 if (cdev->private->state == DEV_STATE_VERIFY) {
609 /* Remember to fake irb when finished. */
610 if (!cdev->private->flags.fake_irb) {
611 cdev->private->flags.fake_irb = FAKE_TM_IRB;
612 cdev->private->intparm = intparm;
613 return 0;
614 } else
615 /* There's already a fake I/O around. */
616 return -EBUSY;
617 }
608 if (cdev->private->state != DEV_STATE_ONLINE) 618 if (cdev->private->state != DEV_STATE_ONLINE)
609 return -EIO; 619 return -EIO;
610 /* Adjust requested path mask to excluded varied off paths. */ 620 /* Adjust requested path mask to exclude unusable paths. */
611 if (lpm) { 621 if (lpm) {
612 lpm &= sch->opm; 622 lpm &= sch->lpm;
613 if (lpm == 0) 623 if (lpm == 0)
614 return -EACCES; 624 return -EACCES;
615 } 625 }
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index 2ebb492a5c17..76253dfcc1be 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -111,6 +111,9 @@ enum cdev_todo {
111 CDEV_TODO_UNREG_EVAL, 111 CDEV_TODO_UNREG_EVAL,
112}; 112};
113 113
114#define FAKE_CMD_IRB 1
115#define FAKE_TM_IRB 2
116
114struct ccw_device_private { 117struct ccw_device_private {
115 struct ccw_device *cdev; 118 struct ccw_device *cdev;
116 struct subchannel *sch; 119 struct subchannel *sch;
@@ -138,7 +141,7 @@ struct ccw_device_private {
138 unsigned int doverify:1; /* delayed path verification */ 141 unsigned int doverify:1; /* delayed path verification */
139 unsigned int donotify:1; /* call notify function */ 142 unsigned int donotify:1; /* call notify function */
140 unsigned int recog_done:1; /* dev. recog. complete */ 143 unsigned int recog_done:1; /* dev. recog. complete */
141 unsigned int fake_irb:1; /* deliver faked irb */ 144 unsigned int fake_irb:2; /* deliver faked irb */
142 unsigned int resuming:1; /* recognition while resume */ 145 unsigned int resuming:1; /* recognition while resume */
143 unsigned int pgroup:1; /* pathgroup is set up */ 146 unsigned int pgroup:1; /* pathgroup is set up */
144 unsigned int mpath:1; /* multipathing is set up */ 147 unsigned int mpath:1; /* multipathing is set up */
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index ec94f049e995..96bbe9d12a79 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -1552,6 +1552,8 @@ static void ap_reset(struct ap_device *ap_dev)
1552 rc = ap_init_queue(ap_dev->qid); 1552 rc = ap_init_queue(ap_dev->qid);
1553 if (rc == -ENODEV) 1553 if (rc == -ENODEV)
1554 ap_dev->unregistered = 1; 1554 ap_dev->unregistered = 1;
1555 else
1556 __ap_schedule_poll_timer();
1555} 1557}
1556 1558
1557static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags) 1559static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags)