Merge branch 'master' of git://oak/home/sfr/kernels/iseries/work
[powerpc.git] / drivers / s390 / cio / device_fsm.c
index ac6e0c7..dace46f 100644 (file)
@@ -152,7 +152,8 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
                if (cdev->private->iretry) {
                        cdev->private->iretry--;
                        ret = cio_halt(sch);
-                       return (ret == 0) ? -EBUSY : ret;
+                       if (ret != -EBUSY)
+                               return (ret == 0) ? -EBUSY : ret;
                }
                /* halt io unsuccessful. */
                cdev->private->iretry = 255;    /* 255 clear retries. */
@@ -231,10 +232,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
         */
        old_lpm = sch->lpm;
        stsch(sch->schid, &sch->schib);
-       sch->lpm = sch->schib.pmcw.pim &
-               sch->schib.pmcw.pam &
-               sch->schib.pmcw.pom &
-               sch->opm;
+       sch->lpm = sch->schib.pmcw.pam & sch->opm;
        /* Check since device may again have become not operational. */
        if (!sch->schib.pmcw.dnv)
                state = DEV_STATE_NOT_OPER;
@@ -266,12 +264,11 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                        notify = 1;
                }
                /* fill out sense information */
-               cdev->id = (struct ccw_device_id) {
-                       .cu_type   = cdev->private->senseid.cu_type,
-                       .cu_model  = cdev->private->senseid.cu_model,
-                       .dev_type  = cdev->private->senseid.dev_type,
-                       .dev_model = cdev->private->senseid.dev_model,
-               };
+               memset(&cdev->id, 0, sizeof(cdev->id));
+               cdev->id.cu_type   = cdev->private->senseid.cu_type;
+               cdev->id.cu_model  = cdev->private->senseid.cu_model;
+               cdev->id.dev_type  = cdev->private->senseid.dev_type;
+               cdev->id.dev_model = cdev->private->senseid.dev_model;
                if (notify) {
                        cdev->private->state = DEV_STATE_OFFLINE;
                        if (same_dev) {
@@ -455,8 +452,8 @@ ccw_device_sense_pgid_done(struct ccw_device *cdev, int err)
                return;
        }
        /* Start Path Group verification. */
-       sch->vpm = 0;   /* Start with no path groups set. */
        cdev->private->state = DEV_STATE_VERIFY;
+       cdev->private->flags.doverify = 0;
        ccw_device_verify_start(cdev);
 }
 
@@ -556,7 +553,19 @@ ccw_device_nopath_notify(void *data)
 void
 ccw_device_verify_done(struct ccw_device *cdev, int err)
 {
-       cdev->private->flags.doverify = 0;
+       struct subchannel *sch;
+
+       sch = to_subchannel(cdev->dev.parent);
+       /* Update schib - pom may have changed. */
+       stsch(sch->schid, &sch->schib);
+       /* Update lpm with verified path mask. */
+       sch->lpm = sch->vpm;
+       /* Repeat path verification? */
+       if (cdev->private->flags.doverify) {
+               cdev->private->flags.doverify = 0;
+               ccw_device_verify_start(cdev);
+               return;
+       }
        switch (err) {
        case -EOPNOTSUPP: /* path grouping not supported, just set online. */
                cdev->private->options.pgroup = 0;
@@ -565,12 +574,10 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
                /* Deliver fake irb to device driver, if needed. */
                if (cdev->private->flags.fake_irb) {
                        memset(&cdev->private->irb, 0, sizeof(struct irb));
-                       cdev->private->irb.scsw = (struct scsw) {
-                               .cc = 1,
-                               .fctl = SCSW_FCTL_START_FUNC,
-                               .actl = SCSW_ACTL_START_PEND,
-                               .stctl = SCSW_STCTL_STATUS_PEND,
-                       };
+                       cdev->private->irb.scsw.cc = 1;
+                       cdev->private->irb.scsw.fctl = SCSW_FCTL_START_FUNC;
+                       cdev->private->irb.scsw.actl = SCSW_ACTL_START_PEND;
+                       cdev->private->irb.scsw.stctl = SCSW_STCTL_STATUS_PEND;
                        cdev->private->flags.fake_irb = 0;
                        if (cdev->handler)
                                cdev->handler(cdev, cdev->private->intparm,
@@ -616,6 +623,7 @@ ccw_device_online(struct ccw_device *cdev)
        if (!cdev->private->options.pgroup) {
                /* Start initial path verification. */
                cdev->private->state = DEV_STATE_VERIFY;
+               cdev->private->flags.doverify = 0;
                ccw_device_verify_start(cdev);
                return 0;
        }
@@ -662,7 +670,6 @@ ccw_device_offline(struct ccw_device *cdev)
        /* Are we doing path grouping? */
        if (!cdev->private->options.pgroup) {
                /* No, set state offline immediately. */
-               sch->vpm = 0;
                ccw_device_done(cdev, DEV_STATE_OFFLINE);
                return 0;
        }
@@ -771,6 +778,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
        stsch(sch->schid, &sch->schib);
 
        if (sch->schib.scsw.actl != 0 ||
+           (sch->schib.scsw.stctl & SCSW_STCTL_STATUS_PEND) ||
            (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
                /*
                 * No final status yet or final status not yet delivered
@@ -782,6 +790,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
        }
        /* Device is idle, we can do the path verification. */
        cdev->private->state = DEV_STATE_VERIFY;
+       cdev->private->flags.doverify = 0;
        ccw_device_verify_start(cdev);
 }
 
@@ -1044,9 +1053,9 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
 }
 
 static void
-ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event)
+ccw_device_delay_verify(struct ccw_device *cdev, enum dev_event dev_event)
 {
-       /* When the I/O has terminated, we have to start verification. */
+       /* Start verification after current task finished. */
        cdev->private->flags.doverify = 1;
 }
 
@@ -1112,10 +1121,7 @@ device_trigger_reprobe(struct subchannel *sch)
         * The pim, pam, pom values may not be accurate, but they are the best
         * we have before performing device selection :/
         */
-       sch->lpm = sch->schib.pmcw.pim &
-               sch->schib.pmcw.pam &
-               sch->schib.pmcw.pom &
-               sch->opm;
+       sch->lpm = sch->schib.pmcw.pam & sch->opm;
        /* Re-set some bits in the pmcw that were lost. */
        sch->schib.pmcw.isc = 3;
        sch->schib.pmcw.csense = 1;
@@ -1239,7 +1245,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_verify_irq,
                [DEV_EVENT_TIMEOUT]     = ccw_device_onoff_timeout,
-               [DEV_EVENT_VERIFY]      = ccw_device_nop,
+               [DEV_EVENT_VERIFY]      = ccw_device_delay_verify,
        },
        [DEV_STATE_ONLINE] = {
                [DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
@@ -1282,7 +1288,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
                [DEV_EVENT_INTERRUPT]   = ccw_device_wait4io_irq,
                [DEV_EVENT_TIMEOUT]     = ccw_device_wait4io_timeout,
-               [DEV_EVENT_VERIFY]      = ccw_device_wait4io_verify,
+               [DEV_EVENT_VERIFY]      = ccw_device_delay_verify,
        },
        [DEV_STATE_QUIESCE] = {
                [DEV_EVENT_NOTOPER]     = ccw_device_quiesce_done,
@@ -1295,7 +1301,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_NOTOPER]     = ccw_device_nop,
                [DEV_EVENT_INTERRUPT]   = ccw_device_start_id,
                [DEV_EVENT_TIMEOUT]     = ccw_device_bug,
-               [DEV_EVENT_VERIFY]      = ccw_device_nop,
+               [DEV_EVENT_VERIFY]      = ccw_device_start_id,
        },
        [DEV_STATE_DISCONNECTED_SENSE_ID] = {
                [DEV_EVENT_NOTOPER]     = ccw_device_recog_notoper,