diff options
Diffstat (limited to 'drivers/s390/cio/device_fsm.c')
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 411 |
1 files changed, 94 insertions, 317 deletions
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index b9613d7df9ef..ae760658a131 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -229,8 +229,8 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) | |||
229 | 229 | ||
230 | sch = to_subchannel(cdev->dev.parent); | 230 | sch = to_subchannel(cdev->dev.parent); |
231 | 231 | ||
232 | ccw_device_set_timeout(cdev, 0); | 232 | if (cio_disable_subchannel(sch)) |
233 | cio_disable_subchannel(sch); | 233 | state = DEV_STATE_NOT_OPER; |
234 | /* | 234 | /* |
235 | * Now that we tried recognition, we have performed device selection | 235 | * Now that we tried recognition, we have performed device selection |
236 | * through ssch() and the path information is up to date. | 236 | * through ssch() and the path information is up to date. |
@@ -263,22 +263,10 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) | |||
263 | } | 263 | } |
264 | switch (state) { | 264 | switch (state) { |
265 | case DEV_STATE_NOT_OPER: | 265 | case DEV_STATE_NOT_OPER: |
266 | CIO_MSG_EVENT(2, "SenseID : unknown device %04x on " | ||
267 | "subchannel 0.%x.%04x\n", | ||
268 | cdev->private->dev_id.devno, | ||
269 | sch->schid.ssid, sch->schid.sch_no); | ||
270 | break; | 266 | break; |
271 | case DEV_STATE_OFFLINE: | 267 | case DEV_STATE_OFFLINE: |
272 | if (!cdev->online) { | 268 | if (!cdev->online) { |
273 | ccw_device_update_sense_data(cdev); | 269 | ccw_device_update_sense_data(cdev); |
274 | /* Issue device info message. */ | ||
275 | CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " | ||
276 | "CU Type/Mod = %04X/%02X, Dev Type/Mod " | ||
277 | "= %04X/%02X\n", | ||
278 | cdev->private->dev_id.ssid, | ||
279 | cdev->private->dev_id.devno, | ||
280 | cdev->id.cu_type, cdev->id.cu_model, | ||
281 | cdev->id.dev_type, cdev->id.dev_model); | ||
282 | break; | 270 | break; |
283 | } | 271 | } |
284 | cdev->private->state = DEV_STATE_OFFLINE; | 272 | cdev->private->state = DEV_STATE_OFFLINE; |
@@ -289,16 +277,10 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) | |||
289 | wake_up(&cdev->private->wait_q); | 277 | wake_up(&cdev->private->wait_q); |
290 | } else { | 278 | } else { |
291 | ccw_device_update_sense_data(cdev); | 279 | ccw_device_update_sense_data(cdev); |
292 | PREPARE_WORK(&cdev->private->kick_work, | 280 | ccw_device_sched_todo(cdev, CDEV_TODO_REBIND); |
293 | ccw_device_do_unbind_bind); | ||
294 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
295 | } | 281 | } |
296 | return; | 282 | return; |
297 | case DEV_STATE_BOXED: | 283 | case DEV_STATE_BOXED: |
298 | CIO_MSG_EVENT(0, "SenseID : boxed device %04x on " | ||
299 | " subchannel 0.%x.%04x\n", | ||
300 | cdev->private->dev_id.devno, | ||
301 | sch->schid.ssid, sch->schid.sch_no); | ||
302 | if (cdev->id.cu_type != 0) { /* device was recognized before */ | 284 | if (cdev->id.cu_type != 0) { /* device was recognized before */ |
303 | cdev->private->flags.recog_done = 1; | 285 | cdev->private->flags.recog_done = 1; |
304 | cdev->private->state = DEV_STATE_BOXED; | 286 | cdev->private->state = DEV_STATE_BOXED; |
@@ -343,28 +325,16 @@ int ccw_device_notify(struct ccw_device *cdev, int event) | |||
343 | return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0; | 325 | return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0; |
344 | } | 326 | } |
345 | 327 | ||
346 | static void cmf_reenable_delayed(struct work_struct *work) | ||
347 | { | ||
348 | struct ccw_device_private *priv; | ||
349 | struct ccw_device *cdev; | ||
350 | |||
351 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
352 | cdev = priv->cdev; | ||
353 | cmf_reenable(cdev); | ||
354 | } | ||
355 | |||
356 | static void ccw_device_oper_notify(struct ccw_device *cdev) | 328 | static void ccw_device_oper_notify(struct ccw_device *cdev) |
357 | { | 329 | { |
358 | if (ccw_device_notify(cdev, CIO_OPER)) { | 330 | if (ccw_device_notify(cdev, CIO_OPER)) { |
359 | /* Reenable channel measurements, if needed. */ | 331 | /* Reenable channel measurements, if needed. */ |
360 | PREPARE_WORK(&cdev->private->kick_work, cmf_reenable_delayed); | 332 | ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF); |
361 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
362 | return; | 333 | return; |
363 | } | 334 | } |
364 | /* Driver doesn't want device back. */ | 335 | /* Driver doesn't want device back. */ |
365 | ccw_device_set_notoper(cdev); | 336 | ccw_device_set_notoper(cdev); |
366 | PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind); | 337 | ccw_device_sched_todo(cdev, CDEV_TODO_REBIND); |
367 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
368 | } | 338 | } |
369 | 339 | ||
370 | /* | 340 | /* |
@@ -392,14 +362,14 @@ ccw_device_done(struct ccw_device *cdev, int state) | |||
392 | CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n", | 362 | CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n", |
393 | cdev->private->dev_id.devno, sch->schid.sch_no); | 363 | cdev->private->dev_id.devno, sch->schid.sch_no); |
394 | if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED)) | 364 | if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED)) |
395 | ccw_device_schedule_sch_unregister(cdev); | 365 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); |
396 | cdev->private->flags.donotify = 0; | 366 | cdev->private->flags.donotify = 0; |
397 | break; | 367 | break; |
398 | case DEV_STATE_NOT_OPER: | 368 | case DEV_STATE_NOT_OPER: |
399 | CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n", | 369 | CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n", |
400 | cdev->private->dev_id.devno, sch->schid.sch_no); | 370 | cdev->private->dev_id.devno, sch->schid.sch_no); |
401 | if (!ccw_device_notify(cdev, CIO_GONE)) | 371 | if (!ccw_device_notify(cdev, CIO_GONE)) |
402 | ccw_device_schedule_sch_unregister(cdev); | 372 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); |
403 | else | 373 | else |
404 | ccw_device_set_disconnected(cdev); | 374 | ccw_device_set_disconnected(cdev); |
405 | cdev->private->flags.donotify = 0; | 375 | cdev->private->flags.donotify = 0; |
@@ -409,7 +379,7 @@ ccw_device_done(struct ccw_device *cdev, int state) | |||
409 | "%04x\n", cdev->private->dev_id.devno, | 379 | "%04x\n", cdev->private->dev_id.devno, |
410 | sch->schid.sch_no); | 380 | sch->schid.sch_no); |
411 | if (!ccw_device_notify(cdev, CIO_NO_PATH)) | 381 | if (!ccw_device_notify(cdev, CIO_NO_PATH)) |
412 | ccw_device_schedule_sch_unregister(cdev); | 382 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); |
413 | else | 383 | else |
414 | ccw_device_set_disconnected(cdev); | 384 | ccw_device_set_disconnected(cdev); |
415 | cdev->private->flags.donotify = 0; | 385 | cdev->private->flags.donotify = 0; |
@@ -425,107 +395,12 @@ ccw_device_done(struct ccw_device *cdev, int state) | |||
425 | wake_up(&cdev->private->wait_q); | 395 | wake_up(&cdev->private->wait_q); |
426 | } | 396 | } |
427 | 397 | ||
428 | static int cmp_pgid(struct pgid *p1, struct pgid *p2) | ||
429 | { | ||
430 | char *c1; | ||
431 | char *c2; | ||
432 | |||
433 | c1 = (char *)p1; | ||
434 | c2 = (char *)p2; | ||
435 | |||
436 | return memcmp(c1 + 1, c2 + 1, sizeof(struct pgid) - 1); | ||
437 | } | ||
438 | |||
439 | static void __ccw_device_get_common_pgid(struct ccw_device *cdev) | ||
440 | { | ||
441 | int i; | ||
442 | int last; | ||
443 | |||
444 | last = 0; | ||
445 | for (i = 0; i < 8; i++) { | ||
446 | if (cdev->private->pgid[i].inf.ps.state1 == SNID_STATE1_RESET) | ||
447 | /* No PGID yet */ | ||
448 | continue; | ||
449 | if (cdev->private->pgid[last].inf.ps.state1 == | ||
450 | SNID_STATE1_RESET) { | ||
451 | /* First non-zero PGID */ | ||
452 | last = i; | ||
453 | continue; | ||
454 | } | ||
455 | if (cmp_pgid(&cdev->private->pgid[i], | ||
456 | &cdev->private->pgid[last]) == 0) | ||
457 | /* Non-conflicting PGIDs */ | ||
458 | continue; | ||
459 | |||
460 | /* PGID mismatch, can't pathgroup. */ | ||
461 | CIO_MSG_EVENT(0, "SNID - pgid mismatch for device " | ||
462 | "0.%x.%04x, can't pathgroup\n", | ||
463 | cdev->private->dev_id.ssid, | ||
464 | cdev->private->dev_id.devno); | ||
465 | cdev->private->options.pgroup = 0; | ||
466 | return; | ||
467 | } | ||
468 | if (cdev->private->pgid[last].inf.ps.state1 == | ||
469 | SNID_STATE1_RESET) | ||
470 | /* No previous pgid found */ | ||
471 | memcpy(&cdev->private->pgid[0], | ||
472 | &channel_subsystems[0]->global_pgid, | ||
473 | sizeof(struct pgid)); | ||
474 | else | ||
475 | /* Use existing pgid */ | ||
476 | memcpy(&cdev->private->pgid[0], &cdev->private->pgid[last], | ||
477 | sizeof(struct pgid)); | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * Function called from device_pgid.c after sense path ground has completed. | ||
482 | */ | ||
483 | void | ||
484 | ccw_device_sense_pgid_done(struct ccw_device *cdev, int err) | ||
485 | { | ||
486 | struct subchannel *sch; | ||
487 | |||
488 | sch = to_subchannel(cdev->dev.parent); | ||
489 | switch (err) { | ||
490 | case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */ | ||
491 | cdev->private->options.pgroup = 0; | ||
492 | break; | ||
493 | case 0: /* success */ | ||
494 | case -EACCES: /* partial success, some paths not operational */ | ||
495 | /* Check if all pgids are equal or 0. */ | ||
496 | __ccw_device_get_common_pgid(cdev); | ||
497 | break; | ||
498 | case -ETIME: /* Sense path group id stopped by timeout. */ | ||
499 | case -EUSERS: /* device is reserved for someone else. */ | ||
500 | ccw_device_done(cdev, DEV_STATE_BOXED); | ||
501 | return; | ||
502 | default: | ||
503 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | ||
504 | return; | ||
505 | } | ||
506 | /* Start Path Group verification. */ | ||
507 | cdev->private->state = DEV_STATE_VERIFY; | ||
508 | cdev->private->flags.doverify = 0; | ||
509 | ccw_device_verify_start(cdev); | ||
510 | } | ||
511 | |||
512 | /* | 398 | /* |
513 | * Start device recognition. | 399 | * Start device recognition. |
514 | */ | 400 | */ |
515 | int | 401 | void ccw_device_recognition(struct ccw_device *cdev) |
516 | ccw_device_recognition(struct ccw_device *cdev) | ||
517 | { | 402 | { |
518 | struct subchannel *sch; | 403 | struct subchannel *sch = to_subchannel(cdev->dev.parent); |
519 | int ret; | ||
520 | |||
521 | sch = to_subchannel(cdev->dev.parent); | ||
522 | ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); | ||
523 | if (ret != 0) | ||
524 | /* Couldn't enable the subchannel for i/o. Sick device. */ | ||
525 | return ret; | ||
526 | |||
527 | /* After 60s the device recognition is considered to have failed. */ | ||
528 | ccw_device_set_timeout(cdev, 60*HZ); | ||
529 | 404 | ||
530 | /* | 405 | /* |
531 | * We used to start here with a sense pgid to find out whether a device | 406 | * We used to start here with a sense pgid to find out whether a device |
@@ -537,32 +412,33 @@ ccw_device_recognition(struct ccw_device *cdev) | |||
537 | */ | 412 | */ |
538 | cdev->private->flags.recog_done = 0; | 413 | cdev->private->flags.recog_done = 0; |
539 | cdev->private->state = DEV_STATE_SENSE_ID; | 414 | cdev->private->state = DEV_STATE_SENSE_ID; |
415 | if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) { | ||
416 | ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER); | ||
417 | return; | ||
418 | } | ||
540 | ccw_device_sense_id_start(cdev); | 419 | ccw_device_sense_id_start(cdev); |
541 | return 0; | ||
542 | } | 420 | } |
543 | 421 | ||
544 | /* | 422 | /* |
545 | * Handle timeout in device recognition. | 423 | * Handle events for states that use the ccw request infrastructure. |
546 | */ | 424 | */ |
547 | static void | 425 | static void ccw_device_request_event(struct ccw_device *cdev, enum dev_event e) |
548 | ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event) | ||
549 | { | 426 | { |
550 | int ret; | 427 | switch (e) { |
551 | 428 | case DEV_EVENT_NOTOPER: | |
552 | ret = ccw_device_cancel_halt_clear(cdev); | 429 | ccw_request_notoper(cdev); |
553 | switch (ret) { | ||
554 | case 0: | ||
555 | ccw_device_recog_done(cdev, DEV_STATE_BOXED); | ||
556 | break; | 430 | break; |
557 | case -ENODEV: | 431 | case DEV_EVENT_INTERRUPT: |
558 | ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER); | 432 | ccw_request_handler(cdev); |
433 | break; | ||
434 | case DEV_EVENT_TIMEOUT: | ||
435 | ccw_request_timeout(cdev); | ||
559 | break; | 436 | break; |
560 | default: | 437 | default: |
561 | ccw_device_set_timeout(cdev, 3*HZ); | 438 | break; |
562 | } | 439 | } |
563 | } | 440 | } |
564 | 441 | ||
565 | |||
566 | void | 442 | void |
567 | ccw_device_verify_done(struct ccw_device *cdev, int err) | 443 | ccw_device_verify_done(struct ccw_device *cdev, int err) |
568 | { | 444 | { |
@@ -571,21 +447,18 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) | |||
571 | sch = to_subchannel(cdev->dev.parent); | 447 | sch = to_subchannel(cdev->dev.parent); |
572 | /* Update schib - pom may have changed. */ | 448 | /* Update schib - pom may have changed. */ |
573 | if (cio_update_schib(sch)) { | 449 | if (cio_update_schib(sch)) { |
574 | cdev->private->flags.donotify = 0; | 450 | err = -ENODEV; |
575 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | 451 | goto callback; |
576 | return; | ||
577 | } | 452 | } |
578 | /* Update lpm with verified path mask. */ | 453 | /* Update lpm with verified path mask. */ |
579 | sch->lpm = sch->vpm; | 454 | sch->lpm = sch->vpm; |
580 | /* Repeat path verification? */ | 455 | /* Repeat path verification? */ |
581 | if (cdev->private->flags.doverify) { | 456 | if (cdev->private->flags.doverify) { |
582 | cdev->private->flags.doverify = 0; | ||
583 | ccw_device_verify_start(cdev); | 457 | ccw_device_verify_start(cdev); |
584 | return; | 458 | return; |
585 | } | 459 | } |
460 | callback: | ||
586 | switch (err) { | 461 | switch (err) { |
587 | case -EOPNOTSUPP: /* path grouping not supported, just set online. */ | ||
588 | cdev->private->options.pgroup = 0; | ||
589 | case 0: | 462 | case 0: |
590 | ccw_device_done(cdev, DEV_STATE_ONLINE); | 463 | ccw_device_done(cdev, DEV_STATE_ONLINE); |
591 | /* Deliver fake irb to device driver, if needed. */ | 464 | /* Deliver fake irb to device driver, if needed. */ |
@@ -604,18 +477,20 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) | |||
604 | } | 477 | } |
605 | break; | 478 | break; |
606 | case -ETIME: | 479 | case -ETIME: |
480 | case -EUSERS: | ||
607 | /* Reset oper notify indication after verify error. */ | 481 | /* Reset oper notify indication after verify error. */ |
608 | cdev->private->flags.donotify = 0; | 482 | cdev->private->flags.donotify = 0; |
609 | ccw_device_done(cdev, DEV_STATE_BOXED); | 483 | ccw_device_done(cdev, DEV_STATE_BOXED); |
610 | break; | 484 | break; |
485 | case -EACCES: | ||
486 | /* Reset oper notify indication after verify error. */ | ||
487 | cdev->private->flags.donotify = 0; | ||
488 | ccw_device_done(cdev, DEV_STATE_DISCONNECTED); | ||
489 | break; | ||
611 | default: | 490 | default: |
612 | /* Reset oper notify indication after verify error. */ | 491 | /* Reset oper notify indication after verify error. */ |
613 | cdev->private->flags.donotify = 0; | 492 | cdev->private->flags.donotify = 0; |
614 | if (cdev->online) { | 493 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); |
615 | ccw_device_set_timeout(cdev, 0); | ||
616 | dev_fsm_event(cdev, DEV_EVENT_NOTOPER); | ||
617 | } else | ||
618 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | ||
619 | break; | 494 | break; |
620 | } | 495 | } |
621 | } | 496 | } |
@@ -640,17 +515,9 @@ ccw_device_online(struct ccw_device *cdev) | |||
640 | dev_fsm_event(cdev, DEV_EVENT_NOTOPER); | 515 | dev_fsm_event(cdev, DEV_EVENT_NOTOPER); |
641 | return ret; | 516 | return ret; |
642 | } | 517 | } |
643 | /* Do we want to do path grouping? */ | 518 | /* Start initial path verification. */ |
644 | if (!cdev->private->options.pgroup) { | 519 | cdev->private->state = DEV_STATE_VERIFY; |
645 | /* Start initial path verification. */ | 520 | ccw_device_verify_start(cdev); |
646 | cdev->private->state = DEV_STATE_VERIFY; | ||
647 | cdev->private->flags.doverify = 0; | ||
648 | ccw_device_verify_start(cdev); | ||
649 | return 0; | ||
650 | } | ||
651 | /* Do a SensePGID first. */ | ||
652 | cdev->private->state = DEV_STATE_SENSE_PGID; | ||
653 | ccw_device_sense_pgid_start(cdev); | ||
654 | return 0; | 521 | return 0; |
655 | } | 522 | } |
656 | 523 | ||
@@ -666,7 +533,6 @@ ccw_device_disband_done(struct ccw_device *cdev, int err) | |||
666 | break; | 533 | break; |
667 | default: | 534 | default: |
668 | cdev->private->flags.donotify = 0; | 535 | cdev->private->flags.donotify = 0; |
669 | dev_fsm_event(cdev, DEV_EVENT_NOTOPER); | ||
670 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | 536 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); |
671 | break; | 537 | break; |
672 | } | 538 | } |
@@ -703,7 +569,7 @@ ccw_device_offline(struct ccw_device *cdev) | |||
703 | if (cdev->private->state != DEV_STATE_ONLINE) | 569 | if (cdev->private->state != DEV_STATE_ONLINE) |
704 | return -EINVAL; | 570 | return -EINVAL; |
705 | /* Are we doing path grouping? */ | 571 | /* Are we doing path grouping? */ |
706 | if (!cdev->private->options.pgroup) { | 572 | if (!cdev->private->flags.pgroup) { |
707 | /* No, set state offline immediately. */ | 573 | /* No, set state offline immediately. */ |
708 | ccw_device_done(cdev, DEV_STATE_OFFLINE); | 574 | ccw_device_done(cdev, DEV_STATE_OFFLINE); |
709 | return 0; | 575 | return 0; |
@@ -715,43 +581,13 @@ ccw_device_offline(struct ccw_device *cdev) | |||
715 | } | 581 | } |
716 | 582 | ||
717 | /* | 583 | /* |
718 | * Handle timeout in device online/offline process. | ||
719 | */ | ||
720 | static void | ||
721 | ccw_device_onoff_timeout(struct ccw_device *cdev, enum dev_event dev_event) | ||
722 | { | ||
723 | int ret; | ||
724 | |||
725 | ret = ccw_device_cancel_halt_clear(cdev); | ||
726 | switch (ret) { | ||
727 | case 0: | ||
728 | ccw_device_done(cdev, DEV_STATE_BOXED); | ||
729 | break; | ||
730 | case -ENODEV: | ||
731 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | ||
732 | break; | ||
733 | default: | ||
734 | ccw_device_set_timeout(cdev, 3*HZ); | ||
735 | } | ||
736 | } | ||
737 | |||
738 | /* | ||
739 | * Handle not oper event in device recognition. | ||
740 | */ | ||
741 | static void | ||
742 | ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event) | ||
743 | { | ||
744 | ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER); | ||
745 | } | ||
746 | |||
747 | /* | ||
748 | * Handle not operational event in non-special state. | 584 | * Handle not operational event in non-special state. |
749 | */ | 585 | */ |
750 | static void ccw_device_generic_notoper(struct ccw_device *cdev, | 586 | static void ccw_device_generic_notoper(struct ccw_device *cdev, |
751 | enum dev_event dev_event) | 587 | enum dev_event dev_event) |
752 | { | 588 | { |
753 | if (!ccw_device_notify(cdev, CIO_GONE)) | 589 | if (!ccw_device_notify(cdev, CIO_GONE)) |
754 | ccw_device_schedule_sch_unregister(cdev); | 590 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); |
755 | else | 591 | else |
756 | ccw_device_set_disconnected(cdev); | 592 | ccw_device_set_disconnected(cdev); |
757 | } | 593 | } |
@@ -802,11 +638,27 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) | |||
802 | } | 638 | } |
803 | /* Device is idle, we can do the path verification. */ | 639 | /* Device is idle, we can do the path verification. */ |
804 | cdev->private->state = DEV_STATE_VERIFY; | 640 | cdev->private->state = DEV_STATE_VERIFY; |
805 | cdev->private->flags.doverify = 0; | ||
806 | ccw_device_verify_start(cdev); | 641 | ccw_device_verify_start(cdev); |
807 | } | 642 | } |
808 | 643 | ||
809 | /* | 644 | /* |
645 | * Handle path verification event in boxed state. | ||
646 | */ | ||
647 | static void ccw_device_boxed_verify(struct ccw_device *cdev, | ||
648 | enum dev_event dev_event) | ||
649 | { | ||
650 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
651 | |||
652 | if (cdev->online) { | ||
653 | if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) | ||
654 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | ||
655 | else | ||
656 | ccw_device_online_verify(cdev, dev_event); | ||
657 | } else | ||
658 | css_schedule_eval(sch->schid); | ||
659 | } | ||
660 | |||
661 | /* | ||
810 | * Got an interrupt for a normal io (state online). | 662 | * Got an interrupt for a normal io (state online). |
811 | */ | 663 | */ |
812 | static void | 664 | static void |
@@ -904,12 +756,6 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) | |||
904 | */ | 756 | */ |
905 | if (scsw_fctl(&irb->scsw) & | 757 | if (scsw_fctl(&irb->scsw) & |
906 | (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { | 758 | (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { |
907 | /* Retry Basic Sense if requested. */ | ||
908 | if (cdev->private->flags.intretry) { | ||
909 | cdev->private->flags.intretry = 0; | ||
910 | ccw_device_do_sense(cdev, irb); | ||
911 | return; | ||
912 | } | ||
913 | cdev->private->flags.dosense = 0; | 759 | cdev->private->flags.dosense = 0; |
914 | memset(&cdev->private->irb, 0, sizeof(struct irb)); | 760 | memset(&cdev->private->irb, 0, sizeof(struct irb)); |
915 | ccw_device_accumulate_irb(cdev, irb); | 761 | ccw_device_accumulate_irb(cdev, irb); |
@@ -933,21 +779,6 @@ call_handler: | |||
933 | } | 779 | } |
934 | 780 | ||
935 | static void | 781 | static void |
936 | ccw_device_clear_verify(struct ccw_device *cdev, enum dev_event dev_event) | ||
937 | { | ||
938 | struct irb *irb; | ||
939 | |||
940 | irb = (struct irb *) __LC_IRB; | ||
941 | /* Accumulate status. We don't do basic sense. */ | ||
942 | ccw_device_accumulate_irb(cdev, irb); | ||
943 | /* Remember to clear irb to avoid residuals. */ | ||
944 | memset(&cdev->private->irb, 0, sizeof(struct irb)); | ||
945 | /* Try to start delayed device verification. */ | ||
946 | ccw_device_online_verify(cdev, 0); | ||
947 | /* Note: Don't call handler for cio initiated clear! */ | ||
948 | } | ||
949 | |||
950 | static void | ||
951 | ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) | 782 | ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) |
952 | { | 783 | { |
953 | struct subchannel *sch; | 784 | struct subchannel *sch; |
@@ -1004,32 +835,6 @@ ccw_device_delay_verify(struct ccw_device *cdev, enum dev_event dev_event) | |||
1004 | } | 835 | } |
1005 | 836 | ||
1006 | static void | 837 | static void |
1007 | ccw_device_stlck_done(struct ccw_device *cdev, enum dev_event dev_event) | ||
1008 | { | ||
1009 | struct irb *irb; | ||
1010 | |||
1011 | switch (dev_event) { | ||
1012 | case DEV_EVENT_INTERRUPT: | ||
1013 | irb = (struct irb *) __LC_IRB; | ||
1014 | /* Check for unsolicited interrupt. */ | ||
1015 | if ((scsw_stctl(&irb->scsw) == | ||
1016 | (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) && | ||
1017 | (!scsw_cc(&irb->scsw))) | ||
1018 | /* FIXME: we should restart stlck here, but this | ||
1019 | * is extremely unlikely ... */ | ||
1020 | goto out_wakeup; | ||
1021 | |||
1022 | ccw_device_accumulate_irb(cdev, irb); | ||
1023 | /* We don't care about basic sense etc. */ | ||
1024 | break; | ||
1025 | default: /* timeout */ | ||
1026 | break; | ||
1027 | } | ||
1028 | out_wakeup: | ||
1029 | wake_up(&cdev->private->wait_q); | ||
1030 | } | ||
1031 | |||
1032 | static void | ||
1033 | ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) | 838 | ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) |
1034 | { | 839 | { |
1035 | struct subchannel *sch; | 840 | struct subchannel *sch; |
@@ -1038,10 +843,6 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) | |||
1038 | if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0) | 843 | if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0) |
1039 | /* Couldn't enable the subchannel for i/o. Sick device. */ | 844 | /* Couldn't enable the subchannel for i/o. Sick device. */ |
1040 | return; | 845 | return; |
1041 | |||
1042 | /* After 60s the device recognition is considered to have failed. */ | ||
1043 | ccw_device_set_timeout(cdev, 60*HZ); | ||
1044 | |||
1045 | cdev->private->state = DEV_STATE_DISCONNECTED_SENSE_ID; | 846 | cdev->private->state = DEV_STATE_DISCONNECTED_SENSE_ID; |
1046 | ccw_device_sense_id_start(cdev); | 847 | ccw_device_sense_id_start(cdev); |
1047 | } | 848 | } |
@@ -1072,22 +873,20 @@ void ccw_device_trigger_reprobe(struct ccw_device *cdev) | |||
1072 | 873 | ||
1073 | /* We should also udate ssd info, but this has to wait. */ | 874 | /* We should also udate ssd info, but this has to wait. */ |
1074 | /* Check if this is another device which appeared on the same sch. */ | 875 | /* Check if this is another device which appeared on the same sch. */ |
1075 | if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { | 876 | if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) |
1076 | PREPARE_WORK(&cdev->private->kick_work, | 877 | css_schedule_eval(sch->schid); |
1077 | ccw_device_move_to_orphanage); | 878 | else |
1078 | queue_work(slow_path_wq, &cdev->private->kick_work); | ||
1079 | } else | ||
1080 | ccw_device_start_id(cdev, 0); | 879 | ccw_device_start_id(cdev, 0); |
1081 | } | 880 | } |
1082 | 881 | ||
1083 | static void | 882 | static void ccw_device_disabled_irq(struct ccw_device *cdev, |
1084 | ccw_device_offline_irq(struct ccw_device *cdev, enum dev_event dev_event) | 883 | enum dev_event dev_event) |
1085 | { | 884 | { |
1086 | struct subchannel *sch; | 885 | struct subchannel *sch; |
1087 | 886 | ||
1088 | sch = to_subchannel(cdev->dev.parent); | 887 | sch = to_subchannel(cdev->dev.parent); |
1089 | /* | 888 | /* |
1090 | * An interrupt in state offline means a previous disable was not | 889 | * An interrupt in a disabled state means a previous disable was not |
1091 | * successful - should not happen, but we try to disable again. | 890 | * successful - should not happen, but we try to disable again. |
1092 | */ | 891 | */ |
1093 | cio_disable_subchannel(sch); | 892 | cio_disable_subchannel(sch); |
@@ -1113,10 +912,7 @@ static void | |||
1113 | ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event) | 912 | ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event) |
1114 | { | 913 | { |
1115 | ccw_device_set_timeout(cdev, 0); | 914 | ccw_device_set_timeout(cdev, 0); |
1116 | if (dev_event == DEV_EVENT_NOTOPER) | 915 | cdev->private->state = DEV_STATE_NOT_OPER; |
1117 | cdev->private->state = DEV_STATE_NOT_OPER; | ||
1118 | else | ||
1119 | cdev->private->state = DEV_STATE_OFFLINE; | ||
1120 | wake_up(&cdev->private->wait_q); | 916 | wake_up(&cdev->private->wait_q); |
1121 | } | 917 | } |
1122 | 918 | ||
@@ -1126,17 +922,11 @@ ccw_device_quiesce_timeout(struct ccw_device *cdev, enum dev_event dev_event) | |||
1126 | int ret; | 922 | int ret; |
1127 | 923 | ||
1128 | ret = ccw_device_cancel_halt_clear(cdev); | 924 | ret = ccw_device_cancel_halt_clear(cdev); |
1129 | switch (ret) { | 925 | if (ret == -EBUSY) { |
1130 | case 0: | 926 | ccw_device_set_timeout(cdev, HZ/10); |
1131 | cdev->private->state = DEV_STATE_OFFLINE; | 927 | } else { |
1132 | wake_up(&cdev->private->wait_q); | ||
1133 | break; | ||
1134 | case -ENODEV: | ||
1135 | cdev->private->state = DEV_STATE_NOT_OPER; | 928 | cdev->private->state = DEV_STATE_NOT_OPER; |
1136 | wake_up(&cdev->private->wait_q); | 929 | wake_up(&cdev->private->wait_q); |
1137 | break; | ||
1138 | default: | ||
1139 | ccw_device_set_timeout(cdev, HZ/10); | ||
1140 | } | 930 | } |
1141 | } | 931 | } |
1142 | 932 | ||
@@ -1150,50 +940,37 @@ ccw_device_nop(struct ccw_device *cdev, enum dev_event dev_event) | |||
1150 | } | 940 | } |
1151 | 941 | ||
1152 | /* | 942 | /* |
1153 | * Bug operation action. | ||
1154 | */ | ||
1155 | static void | ||
1156 | ccw_device_bug(struct ccw_device *cdev, enum dev_event dev_event) | ||
1157 | { | ||
1158 | CIO_MSG_EVENT(0, "Internal state [%i][%i] not handled for device " | ||
1159 | "0.%x.%04x\n", cdev->private->state, dev_event, | ||
1160 | cdev->private->dev_id.ssid, | ||
1161 | cdev->private->dev_id.devno); | ||
1162 | BUG(); | ||
1163 | } | ||
1164 | |||
1165 | /* | ||
1166 | * device statemachine | 943 | * device statemachine |
1167 | */ | 944 | */ |
1168 | fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { | 945 | fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { |
1169 | [DEV_STATE_NOT_OPER] = { | 946 | [DEV_STATE_NOT_OPER] = { |
1170 | [DEV_EVENT_NOTOPER] = ccw_device_nop, | 947 | [DEV_EVENT_NOTOPER] = ccw_device_nop, |
1171 | [DEV_EVENT_INTERRUPT] = ccw_device_bug, | 948 | [DEV_EVENT_INTERRUPT] = ccw_device_disabled_irq, |
1172 | [DEV_EVENT_TIMEOUT] = ccw_device_nop, | 949 | [DEV_EVENT_TIMEOUT] = ccw_device_nop, |
1173 | [DEV_EVENT_VERIFY] = ccw_device_nop, | 950 | [DEV_EVENT_VERIFY] = ccw_device_nop, |
1174 | }, | 951 | }, |
1175 | [DEV_STATE_SENSE_PGID] = { | 952 | [DEV_STATE_SENSE_PGID] = { |
1176 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, | 953 | [DEV_EVENT_NOTOPER] = ccw_device_request_event, |
1177 | [DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq, | 954 | [DEV_EVENT_INTERRUPT] = ccw_device_request_event, |
1178 | [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, | 955 | [DEV_EVENT_TIMEOUT] = ccw_device_request_event, |
1179 | [DEV_EVENT_VERIFY] = ccw_device_nop, | 956 | [DEV_EVENT_VERIFY] = ccw_device_nop, |
1180 | }, | 957 | }, |
1181 | [DEV_STATE_SENSE_ID] = { | 958 | [DEV_STATE_SENSE_ID] = { |
1182 | [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper, | 959 | [DEV_EVENT_NOTOPER] = ccw_device_request_event, |
1183 | [DEV_EVENT_INTERRUPT] = ccw_device_sense_id_irq, | 960 | [DEV_EVENT_INTERRUPT] = ccw_device_request_event, |
1184 | [DEV_EVENT_TIMEOUT] = ccw_device_recog_timeout, | 961 | [DEV_EVENT_TIMEOUT] = ccw_device_request_event, |
1185 | [DEV_EVENT_VERIFY] = ccw_device_nop, | 962 | [DEV_EVENT_VERIFY] = ccw_device_nop, |
1186 | }, | 963 | }, |
1187 | [DEV_STATE_OFFLINE] = { | 964 | [DEV_STATE_OFFLINE] = { |
1188 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, | 965 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, |
1189 | [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq, | 966 | [DEV_EVENT_INTERRUPT] = ccw_device_disabled_irq, |
1190 | [DEV_EVENT_TIMEOUT] = ccw_device_nop, | 967 | [DEV_EVENT_TIMEOUT] = ccw_device_nop, |
1191 | [DEV_EVENT_VERIFY] = ccw_device_offline_verify, | 968 | [DEV_EVENT_VERIFY] = ccw_device_offline_verify, |
1192 | }, | 969 | }, |
1193 | [DEV_STATE_VERIFY] = { | 970 | [DEV_STATE_VERIFY] = { |
1194 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, | 971 | [DEV_EVENT_NOTOPER] = ccw_device_request_event, |
1195 | [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq, | 972 | [DEV_EVENT_INTERRUPT] = ccw_device_request_event, |
1196 | [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, | 973 | [DEV_EVENT_TIMEOUT] = ccw_device_request_event, |
1197 | [DEV_EVENT_VERIFY] = ccw_device_delay_verify, | 974 | [DEV_EVENT_VERIFY] = ccw_device_delay_verify, |
1198 | }, | 975 | }, |
1199 | [DEV_STATE_ONLINE] = { | 976 | [DEV_STATE_ONLINE] = { |
@@ -1209,24 +986,18 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { | |||
1209 | [DEV_EVENT_VERIFY] = ccw_device_online_verify, | 986 | [DEV_EVENT_VERIFY] = ccw_device_online_verify, |
1210 | }, | 987 | }, |
1211 | [DEV_STATE_DISBAND_PGID] = { | 988 | [DEV_STATE_DISBAND_PGID] = { |
1212 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, | 989 | [DEV_EVENT_NOTOPER] = ccw_device_request_event, |
1213 | [DEV_EVENT_INTERRUPT] = ccw_device_disband_irq, | 990 | [DEV_EVENT_INTERRUPT] = ccw_device_request_event, |
1214 | [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout, | 991 | [DEV_EVENT_TIMEOUT] = ccw_device_request_event, |
1215 | [DEV_EVENT_VERIFY] = ccw_device_nop, | 992 | [DEV_EVENT_VERIFY] = ccw_device_nop, |
1216 | }, | 993 | }, |
1217 | [DEV_STATE_BOXED] = { | 994 | [DEV_STATE_BOXED] = { |
1218 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, | 995 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, |
1219 | [DEV_EVENT_INTERRUPT] = ccw_device_stlck_done, | 996 | [DEV_EVENT_INTERRUPT] = ccw_device_nop, |
1220 | [DEV_EVENT_TIMEOUT] = ccw_device_stlck_done, | ||
1221 | [DEV_EVENT_VERIFY] = ccw_device_nop, | ||
1222 | }, | ||
1223 | /* states to wait for i/o completion before doing something */ | ||
1224 | [DEV_STATE_CLEAR_VERIFY] = { | ||
1225 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, | ||
1226 | [DEV_EVENT_INTERRUPT] = ccw_device_clear_verify, | ||
1227 | [DEV_EVENT_TIMEOUT] = ccw_device_nop, | 997 | [DEV_EVENT_TIMEOUT] = ccw_device_nop, |
1228 | [DEV_EVENT_VERIFY] = ccw_device_nop, | 998 | [DEV_EVENT_VERIFY] = ccw_device_boxed_verify, |
1229 | }, | 999 | }, |
1000 | /* states to wait for i/o completion before doing something */ | ||
1230 | [DEV_STATE_TIMEOUT_KILL] = { | 1001 | [DEV_STATE_TIMEOUT_KILL] = { |
1231 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, | 1002 | [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, |
1232 | [DEV_EVENT_INTERRUPT] = ccw_device_killing_irq, | 1003 | [DEV_EVENT_INTERRUPT] = ccw_device_killing_irq, |
@@ -1243,13 +1014,13 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { | |||
1243 | [DEV_STATE_DISCONNECTED] = { | 1014 | [DEV_STATE_DISCONNECTED] = { |
1244 | [DEV_EVENT_NOTOPER] = ccw_device_nop, | 1015 | [DEV_EVENT_NOTOPER] = ccw_device_nop, |
1245 | [DEV_EVENT_INTERRUPT] = ccw_device_start_id, | 1016 | [DEV_EVENT_INTERRUPT] = ccw_device_start_id, |
1246 | [DEV_EVENT_TIMEOUT] = ccw_device_bug, | 1017 | [DEV_EVENT_TIMEOUT] = ccw_device_nop, |
1247 | [DEV_EVENT_VERIFY] = ccw_device_start_id, | 1018 | [DEV_EVENT_VERIFY] = ccw_device_start_id, |
1248 | }, | 1019 | }, |
1249 | [DEV_STATE_DISCONNECTED_SENSE_ID] = { | 1020 | [DEV_STATE_DISCONNECTED_SENSE_ID] = { |
1250 | [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper, | 1021 | [DEV_EVENT_NOTOPER] = ccw_device_request_event, |
1251 | [DEV_EVENT_INTERRUPT] = ccw_device_sense_id_irq, | 1022 | [DEV_EVENT_INTERRUPT] = ccw_device_request_event, |
1252 | [DEV_EVENT_TIMEOUT] = ccw_device_recog_timeout, | 1023 | [DEV_EVENT_TIMEOUT] = ccw_device_request_event, |
1253 | [DEV_EVENT_VERIFY] = ccw_device_nop, | 1024 | [DEV_EVENT_VERIFY] = ccw_device_nop, |
1254 | }, | 1025 | }, |
1255 | [DEV_STATE_CMFCHANGE] = { | 1026 | [DEV_STATE_CMFCHANGE] = { |
@@ -1264,6 +1035,12 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { | |||
1264 | [DEV_EVENT_TIMEOUT] = ccw_device_update_cmfblock, | 1035 | [DEV_EVENT_TIMEOUT] = ccw_device_update_cmfblock, |
1265 | [DEV_EVENT_VERIFY] = ccw_device_update_cmfblock, | 1036 | [DEV_EVENT_VERIFY] = ccw_device_update_cmfblock, |
1266 | }, | 1037 | }, |
1038 | [DEV_STATE_STEAL_LOCK] = { | ||
1039 | [DEV_EVENT_NOTOPER] = ccw_device_request_event, | ||
1040 | [DEV_EVENT_INTERRUPT] = ccw_device_request_event, | ||
1041 | [DEV_EVENT_TIMEOUT] = ccw_device_request_event, | ||
1042 | [DEV_EVENT_VERIFY] = ccw_device_nop, | ||
1043 | }, | ||
1267 | }; | 1044 | }; |
1268 | 1045 | ||
1269 | EXPORT_SYMBOL_GPL(ccw_device_set_timeout); | 1046 | EXPORT_SYMBOL_GPL(ccw_device_set_timeout); |