diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/chsc.c | 7 | ||||
-rw-r--r-- | drivers/s390/cio/cio.h | 5 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 104 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 30 | ||||
-rw-r--r-- | drivers/s390/cio/device_ops.c | 20 | ||||
-rw-r--r-- | drivers/s390/cio/io_sch.h | 5 | ||||
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 2 |
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) | |||
529 | int chsc_chp_vary(struct chp_id chpid, int on) | 529 | int 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 | */ | ||
71 | enum sch_todo { | 75 | enum 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 | } |
196 | EXPORT_SYMBOL_GPL(css_sch_device_unregister); | 196 | EXPORT_SYMBOL_GPL(css_sch_device_unregister); |
197 | 197 | ||
198 | static 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 | */ | ||
227 | void 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 | |||
243 | static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw) | 198 | static 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 | */ | ||
433 | void 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 | |||
449 | static 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 | |||
469 | static struct idset *slow_subchannel_set; | 483 | static struct idset *slow_subchannel_set; |
470 | static spinlock_t slow_subchannel_lock; | 484 | static spinlock_t slow_subchannel_lock; |
471 | static wait_queue_head_t css_eval_wq; | 485 | static 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 | ||
499 | void | 499 | static void create_fake_irb(struct irb *irb, int type) |
500 | ccw_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 | |||
518 | void 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 | |||
114 | struct ccw_device_private { | 117 | struct 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 | ||
1557 | static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags) | 1559 | static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags) |