diff options
Diffstat (limited to 'drivers/s390/cio/device_fsm.c')
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 09c7672eb3f3..eed14572fc3b 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -186,15 +186,14 @@ ccw_device_handle_oper(struct ccw_device *cdev) | |||
186 | /* | 186 | /* |
187 | * Check if cu type and device type still match. If | 187 | * Check if cu type and device type still match. If |
188 | * not, it is certainly another device and we have to | 188 | * not, it is certainly another device and we have to |
189 | * de- and re-register. Also check here for non-matching devno. | 189 | * de- and re-register. |
190 | */ | 190 | */ |
191 | if (cdev->id.cu_type != cdev->private->senseid.cu_type || | 191 | if (cdev->id.cu_type != cdev->private->senseid.cu_type || |
192 | cdev->id.cu_model != cdev->private->senseid.cu_model || | 192 | cdev->id.cu_model != cdev->private->senseid.cu_model || |
193 | cdev->id.dev_type != cdev->private->senseid.dev_type || | 193 | cdev->id.dev_type != cdev->private->senseid.dev_type || |
194 | cdev->id.dev_model != cdev->private->senseid.dev_model || | 194 | cdev->id.dev_model != cdev->private->senseid.dev_model) { |
195 | cdev->private->dev_id.devno != sch->schib.pmcw.dev) { | ||
196 | PREPARE_WORK(&cdev->private->kick_work, | 195 | PREPARE_WORK(&cdev->private->kick_work, |
197 | ccw_device_do_unreg_rereg, cdev); | 196 | ccw_device_do_unreg_rereg); |
198 | queue_work(ccw_device_work, &cdev->private->kick_work); | 197 | queue_work(ccw_device_work, &cdev->private->kick_work); |
199 | return 0; | 198 | return 0; |
200 | } | 199 | } |
@@ -329,19 +328,21 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err) | |||
329 | } | 328 | } |
330 | 329 | ||
331 | static void | 330 | static void |
332 | ccw_device_oper_notify(void *data) | 331 | ccw_device_oper_notify(struct work_struct *work) |
333 | { | 332 | { |
333 | struct ccw_device_private *priv; | ||
334 | struct ccw_device *cdev; | 334 | struct ccw_device *cdev; |
335 | struct subchannel *sch; | 335 | struct subchannel *sch; |
336 | int ret; | 336 | int ret; |
337 | 337 | ||
338 | cdev = data; | 338 | priv = container_of(work, struct ccw_device_private, kick_work); |
339 | cdev = priv->cdev; | ||
339 | sch = to_subchannel(cdev->dev.parent); | 340 | sch = to_subchannel(cdev->dev.parent); |
340 | ret = (sch->driver && sch->driver->notify) ? | 341 | ret = (sch->driver && sch->driver->notify) ? |
341 | sch->driver->notify(&sch->dev, CIO_OPER) : 0; | 342 | sch->driver->notify(&sch->dev, CIO_OPER) : 0; |
342 | if (!ret) | 343 | if (!ret) |
343 | /* Driver doesn't want device back. */ | 344 | /* Driver doesn't want device back. */ |
344 | ccw_device_do_unreg_rereg(cdev); | 345 | ccw_device_do_unreg_rereg(work); |
345 | else { | 346 | else { |
346 | /* Reenable channel measurements, if needed. */ | 347 | /* Reenable channel measurements, if needed. */ |
347 | cmf_reenable(cdev); | 348 | cmf_reenable(cdev); |
@@ -377,8 +378,7 @@ ccw_device_done(struct ccw_device *cdev, int state) | |||
377 | 378 | ||
378 | if (cdev->private->flags.donotify) { | 379 | if (cdev->private->flags.donotify) { |
379 | cdev->private->flags.donotify = 0; | 380 | cdev->private->flags.donotify = 0; |
380 | PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify, | 381 | PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify); |
381 | cdev); | ||
382 | queue_work(ccw_device_notify_work, &cdev->private->kick_work); | 382 | queue_work(ccw_device_notify_work, &cdev->private->kick_work); |
383 | } | 383 | } |
384 | wake_up(&cdev->private->wait_q); | 384 | wake_up(&cdev->private->wait_q); |
@@ -528,13 +528,15 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event) | |||
528 | 528 | ||
529 | 529 | ||
530 | static void | 530 | static void |
531 | ccw_device_nopath_notify(void *data) | 531 | ccw_device_nopath_notify(struct work_struct *work) |
532 | { | 532 | { |
533 | struct ccw_device_private *priv; | ||
533 | struct ccw_device *cdev; | 534 | struct ccw_device *cdev; |
534 | struct subchannel *sch; | 535 | struct subchannel *sch; |
535 | int ret; | 536 | int ret; |
536 | 537 | ||
537 | cdev = data; | 538 | priv = container_of(work, struct ccw_device_private, kick_work); |
539 | cdev = priv->cdev; | ||
538 | sch = to_subchannel(cdev->dev.parent); | 540 | sch = to_subchannel(cdev->dev.parent); |
539 | /* Extra sanity. */ | 541 | /* Extra sanity. */ |
540 | if (sch->lpm) | 542 | if (sch->lpm) |
@@ -547,8 +549,7 @@ ccw_device_nopath_notify(void *data) | |||
547 | cio_disable_subchannel(sch); | 549 | cio_disable_subchannel(sch); |
548 | if (get_device(&cdev->dev)) { | 550 | if (get_device(&cdev->dev)) { |
549 | PREPARE_WORK(&cdev->private->kick_work, | 551 | PREPARE_WORK(&cdev->private->kick_work, |
550 | ccw_device_call_sch_unregister, | 552 | ccw_device_call_sch_unregister); |
551 | cdev); | ||
552 | queue_work(ccw_device_work, | 553 | queue_work(ccw_device_work, |
553 | &cdev->private->kick_work); | 554 | &cdev->private->kick_work); |
554 | } else | 555 | } else |
@@ -607,7 +608,7 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) | |||
607 | /* Reset oper notify indication after verify error. */ | 608 | /* Reset oper notify indication after verify error. */ |
608 | cdev->private->flags.donotify = 0; | 609 | cdev->private->flags.donotify = 0; |
609 | PREPARE_WORK(&cdev->private->kick_work, | 610 | PREPARE_WORK(&cdev->private->kick_work, |
610 | ccw_device_nopath_notify, cdev); | 611 | ccw_device_nopath_notify); |
611 | queue_work(ccw_device_notify_work, &cdev->private->kick_work); | 612 | queue_work(ccw_device_notify_work, &cdev->private->kick_work); |
612 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | 613 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); |
613 | break; | 614 | break; |
@@ -674,6 +675,10 @@ ccw_device_offline(struct ccw_device *cdev) | |||
674 | { | 675 | { |
675 | struct subchannel *sch; | 676 | struct subchannel *sch; |
676 | 677 | ||
678 | if (ccw_device_is_orphan(cdev)) { | ||
679 | ccw_device_done(cdev, DEV_STATE_OFFLINE); | ||
680 | return 0; | ||
681 | } | ||
677 | sch = to_subchannel(cdev->dev.parent); | 682 | sch = to_subchannel(cdev->dev.parent); |
678 | if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv) | 683 | if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv) |
679 | return -ENODEV; | 684 | return -ENODEV; |
@@ -738,7 +743,7 @@ ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event) | |||
738 | sch = to_subchannel(cdev->dev.parent); | 743 | sch = to_subchannel(cdev->dev.parent); |
739 | if (get_device(&cdev->dev)) { | 744 | if (get_device(&cdev->dev)) { |
740 | PREPARE_WORK(&cdev->private->kick_work, | 745 | PREPARE_WORK(&cdev->private->kick_work, |
741 | ccw_device_call_sch_unregister, cdev); | 746 | ccw_device_call_sch_unregister); |
742 | queue_work(ccw_device_work, &cdev->private->kick_work); | 747 | queue_work(ccw_device_work, &cdev->private->kick_work); |
743 | } | 748 | } |
744 | wake_up(&cdev->private->wait_q); | 749 | wake_up(&cdev->private->wait_q); |
@@ -769,7 +774,7 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) | |||
769 | } | 774 | } |
770 | if (get_device(&cdev->dev)) { | 775 | if (get_device(&cdev->dev)) { |
771 | PREPARE_WORK(&cdev->private->kick_work, | 776 | PREPARE_WORK(&cdev->private->kick_work, |
772 | ccw_device_call_sch_unregister, cdev); | 777 | ccw_device_call_sch_unregister); |
773 | queue_work(ccw_device_work, &cdev->private->kick_work); | 778 | queue_work(ccw_device_work, &cdev->private->kick_work); |
774 | } | 779 | } |
775 | wake_up(&cdev->private->wait_q); | 780 | wake_up(&cdev->private->wait_q); |
@@ -874,7 +879,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) | |||
874 | sch = to_subchannel(cdev->dev.parent); | 879 | sch = to_subchannel(cdev->dev.parent); |
875 | if (!sch->lpm) { | 880 | if (!sch->lpm) { |
876 | PREPARE_WORK(&cdev->private->kick_work, | 881 | PREPARE_WORK(&cdev->private->kick_work, |
877 | ccw_device_nopath_notify, cdev); | 882 | ccw_device_nopath_notify); |
878 | queue_work(ccw_device_notify_work, | 883 | queue_work(ccw_device_notify_work, |
879 | &cdev->private->kick_work); | 884 | &cdev->private->kick_work); |
880 | } else | 885 | } else |
@@ -969,7 +974,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) | |||
969 | ERR_PTR(-EIO)); | 974 | ERR_PTR(-EIO)); |
970 | if (!sch->lpm) { | 975 | if (!sch->lpm) { |
971 | PREPARE_WORK(&cdev->private->kick_work, | 976 | PREPARE_WORK(&cdev->private->kick_work, |
972 | ccw_device_nopath_notify, cdev); | 977 | ccw_device_nopath_notify); |
973 | queue_work(ccw_device_notify_work, &cdev->private->kick_work); | 978 | queue_work(ccw_device_notify_work, &cdev->private->kick_work); |
974 | } else if (cdev->private->flags.doverify) | 979 | } else if (cdev->private->flags.doverify) |
975 | /* Start delayed path verification. */ | 980 | /* Start delayed path verification. */ |
@@ -992,7 +997,7 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) | |||
992 | sch = to_subchannel(cdev->dev.parent); | 997 | sch = to_subchannel(cdev->dev.parent); |
993 | if (!sch->lpm) { | 998 | if (!sch->lpm) { |
994 | PREPARE_WORK(&cdev->private->kick_work, | 999 | PREPARE_WORK(&cdev->private->kick_work, |
995 | ccw_device_nopath_notify, cdev); | 1000 | ccw_device_nopath_notify); |
996 | queue_work(ccw_device_notify_work, | 1001 | queue_work(ccw_device_notify_work, |
997 | &cdev->private->kick_work); | 1002 | &cdev->private->kick_work); |
998 | } else | 1003 | } else |
@@ -1021,7 +1026,7 @@ void device_kill_io(struct subchannel *sch) | |||
1021 | if (ret == -ENODEV) { | 1026 | if (ret == -ENODEV) { |
1022 | if (!sch->lpm) { | 1027 | if (!sch->lpm) { |
1023 | PREPARE_WORK(&cdev->private->kick_work, | 1028 | PREPARE_WORK(&cdev->private->kick_work, |
1024 | ccw_device_nopath_notify, cdev); | 1029 | ccw_device_nopath_notify); |
1025 | queue_work(ccw_device_notify_work, | 1030 | queue_work(ccw_device_notify_work, |
1026 | &cdev->private->kick_work); | 1031 | &cdev->private->kick_work); |
1027 | } else | 1032 | } else |
@@ -1033,7 +1038,7 @@ void device_kill_io(struct subchannel *sch) | |||
1033 | ERR_PTR(-EIO)); | 1038 | ERR_PTR(-EIO)); |
1034 | if (!sch->lpm) { | 1039 | if (!sch->lpm) { |
1035 | PREPARE_WORK(&cdev->private->kick_work, | 1040 | PREPARE_WORK(&cdev->private->kick_work, |
1036 | ccw_device_nopath_notify, cdev); | 1041 | ccw_device_nopath_notify); |
1037 | queue_work(ccw_device_notify_work, &cdev->private->kick_work); | 1042 | queue_work(ccw_device_notify_work, &cdev->private->kick_work); |
1038 | } else | 1043 | } else |
1039 | /* Start delayed path verification. */ | 1044 | /* Start delayed path verification. */ |
@@ -1104,7 +1109,8 @@ device_trigger_reprobe(struct subchannel *sch) | |||
1104 | /* Update some values. */ | 1109 | /* Update some values. */ |
1105 | if (stsch(sch->schid, &sch->schib)) | 1110 | if (stsch(sch->schid, &sch->schib)) |
1106 | return; | 1111 | return; |
1107 | 1112 | if (!sch->schib.pmcw.dnv) | |
1113 | return; | ||
1108 | /* | 1114 | /* |
1109 | * The pim, pam, pom values may not be accurate, but they are the best | 1115 | * The pim, pam, pom values may not be accurate, but they are the best |
1110 | * we have before performing device selection :/ | 1116 | * we have before performing device selection :/ |
@@ -1118,7 +1124,13 @@ device_trigger_reprobe(struct subchannel *sch) | |||
1118 | sch->schib.pmcw.mp = 1; | 1124 | sch->schib.pmcw.mp = 1; |
1119 | sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; | 1125 | sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; |
1120 | /* We should also udate ssd info, but this has to wait. */ | 1126 | /* We should also udate ssd info, but this has to wait. */ |
1121 | ccw_device_start_id(cdev, 0); | 1127 | /* Check if this is another device which appeared on the same sch. */ |
1128 | if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { | ||
1129 | PREPARE_WORK(&cdev->private->kick_work, | ||
1130 | ccw_device_move_to_orphanage); | ||
1131 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
1132 | } else | ||
1133 | ccw_device_start_id(cdev, 0); | ||
1122 | } | 1134 | } |
1123 | 1135 | ||
1124 | static void | 1136 | static void |