[S390] cio: introduce parent-initiated device move
[firefly-linux-kernel-4.4.55.git] / drivers / s390 / cio / device_fsm.c
index e728ce447f6ee107e5482886cb0c8f41115cb363..d1e05f44fb6f2b014f9cf4eef4294acd74a2fe3d 100644 (file)
@@ -387,19 +387,35 @@ ccw_device_done(struct ccw_device *cdev, int state)
 
        cdev->private->state = state;
 
-       if (state == DEV_STATE_BOXED) {
+       switch (state) {
+       case DEV_STATE_BOXED:
                CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
                              cdev->private->dev_id.devno, sch->schid.sch_no);
                if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED))
                        ccw_device_schedule_sch_unregister(cdev);
                cdev->private->flags.donotify = 0;
-       }
-       if (state == DEV_STATE_NOT_OPER) {
+               break;
+       case DEV_STATE_NOT_OPER:
                CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n",
                              cdev->private->dev_id.devno, sch->schid.sch_no);
                if (!ccw_device_notify(cdev, CIO_GONE))
                        ccw_device_schedule_sch_unregister(cdev);
+               else
+                       ccw_device_set_disconnected(cdev);
+               cdev->private->flags.donotify = 0;
+               break;
+       case DEV_STATE_DISCONNECTED:
+               CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel "
+                             "%04x\n", cdev->private->dev_id.devno,
+                             sch->schid.sch_no);
+               if (!ccw_device_notify(cdev, CIO_NO_PATH))
+                       ccw_device_schedule_sch_unregister(cdev);
+               else
+                       ccw_device_set_disconnected(cdev);
                cdev->private->flags.donotify = 0;
+               break;
+       default:
+               break;
        }
 
        if (cdev->private->flags.donotify) {
@@ -671,6 +687,10 @@ ccw_device_offline(struct ccw_device *cdev)
                ccw_device_done(cdev, DEV_STATE_NOT_OPER);
                return 0;
        }
+       if (cdev->private->state == DEV_STATE_BOXED) {
+               ccw_device_done(cdev, DEV_STATE_BOXED);
+               return 0;
+       }
        if (ccw_device_is_orphan(cdev)) {
                ccw_device_done(cdev, DEV_STATE_OFFLINE);
                return 0;
@@ -730,11 +750,10 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event)
 static void ccw_device_generic_notoper(struct ccw_device *cdev,
                                       enum dev_event dev_event)
 {
-       struct subchannel *sch;
-
-       ccw_device_set_notoper(cdev);
-       sch = to_subchannel(cdev->dev.parent);
-       css_schedule_eval(sch->schid);
+       if (!ccw_device_notify(cdev, CIO_GONE))
+               ccw_device_schedule_sch_unregister(cdev);
+       else
+               ccw_device_set_disconnected(cdev);
 }
 
 /*
@@ -1053,11 +1072,9 @@ void ccw_device_trigger_reprobe(struct ccw_device *cdev)
 
        /* We should also udate ssd info, but this has to wait. */
        /* Check if this is another device which appeared on the same sch. */
-       if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
-               PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_move_to_orphanage);
-               queue_work(slow_path_wq, &cdev->private->kick_work);
-       } else
+       if (sch->schib.pmcw.dev != cdev->private->dev_id.devno)
+               css_schedule_eval(sch->schid);
+       else
                ccw_device_start_id(cdev, 0);
 }