]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/s390/cio/device_fsm.c
Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
[linux-2.6-omap-h63xx.git] / drivers / s390 / cio / device_fsm.c
index 35e162ba6d54a7cfbd6afd988fc2a432db43f0fc..de3d0857db9fb83b3526a5d0557876d35dc2b154 100644 (file)
@@ -59,18 +59,6 @@ device_set_disconnected(struct subchannel *sch)
        cdev->private->state = DEV_STATE_DISCONNECTED;
 }
 
-void
-device_set_waiting(struct subchannel *sch)
-{
-       struct ccw_device *cdev;
-
-       if (!sch->dev.driver_data)
-               return;
-       cdev = sch->dev.driver_data;
-       ccw_device_set_timeout(cdev, 10*HZ);
-       cdev->private->state = DEV_STATE_WAIT4IO;
-}
-
 /*
  * Timeout function. It just triggers a DEV_EVENT_TIMEOUT.
  */
@@ -183,9 +171,9 @@ ccw_device_handle_oper(struct ccw_device *cdev)
            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 ||
-           cdev->private->devno != sch->schib.pmcw.dev) {
+           cdev->private->dev_id.devno != sch->schib.pmcw.dev) {
                PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_do_unreg_rereg, (void *)cdev);
+                            ccw_device_do_unreg_rereg, cdev);
                queue_work(ccw_device_work, &cdev->private->kick_work);
                return 0;
        }
@@ -232,10 +220,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;
@@ -258,7 +243,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
        case DEV_STATE_NOT_OPER:
                CIO_DEBUG(KERN_WARNING, 2,
                          "SenseID : unknown device %04x on subchannel "
-                         "0.%x.%04x\n", cdev->private->devno,
+                         "0.%x.%04x\n", cdev->private->dev_id.devno,
                          sch->schid.ssid, sch->schid.sch_no);
                break;
        case DEV_STATE_OFFLINE:
@@ -267,6 +252,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                        notify = 1;
                }
                /* fill out sense information */
+               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;
@@ -284,14 +270,15 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                CIO_DEBUG(KERN_INFO, 2, "SenseID : device 0.%x.%04x reports: "
                          "CU  Type/Mod = %04X/%02X, Dev Type/Mod = "
                          "%04X/%02X\n",
-                         cdev->private->ssid, cdev->private->devno,
+                         cdev->private->dev_id.ssid,
+                         cdev->private->dev_id.devno,
                          cdev->id.cu_type, cdev->id.cu_model,
                          cdev->id.dev_type, cdev->id.dev_model);
                break;
        case DEV_STATE_BOXED:
                CIO_DEBUG(KERN_WARNING, 2,
                          "SenseID : boxed device %04x on subchannel "
-                         "0.%x.%04x\n", cdev->private->devno,
+                         "0.%x.%04x\n", cdev->private->dev_id.devno,
                          sch->schid.ssid, sch->schid.sch_no);
                break;
        }
@@ -327,13 +314,13 @@ ccw_device_oper_notify(void *data)
        struct subchannel *sch;
        int ret;
 
-       cdev = (struct ccw_device *)data;
+       cdev = data;
        sch = to_subchannel(cdev->dev.parent);
        ret = (sch->driver && sch->driver->notify) ?
                sch->driver->notify(&sch->dev, CIO_OPER) : 0;
        if (!ret)
                /* Driver doesn't want device back. */
-               ccw_device_do_unreg_rereg((void *)cdev);
+               ccw_device_do_unreg_rereg(cdev);
        else {
                /* Reenable channel measurements, if needed. */
                cmf_reenable(cdev);
@@ -351,6 +338,8 @@ ccw_device_done(struct ccw_device *cdev, int state)
 
        sch = to_subchannel(cdev->dev.parent);
 
+       ccw_device_set_timeout(cdev, 0);
+
        if (state != DEV_STATE_ONLINE)
                cio_disable_subchannel(sch);
 
@@ -363,12 +352,12 @@ ccw_device_done(struct ccw_device *cdev, int state)
        if (state == DEV_STATE_BOXED)
                CIO_DEBUG(KERN_WARNING, 2,
                          "Boxed device %04x on subchannel %04x\n",
-                         cdev->private->devno, sch->schid.sch_no);
+                         cdev->private->dev_id.devno, sch->schid.sch_no);
 
        if (cdev->private->flags.donotify) {
                cdev->private->flags.donotify = 0;
                PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify,
-                            (void *)cdev);
+                            cdev);
                queue_work(ccw_device_notify_work, &cdev->private->kick_work);
        }
        wake_up(&cdev->private->wait_q);
@@ -412,7 +401,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
                /* PGID mismatch, can't pathgroup. */
                CIO_MSG_EVENT(0, "SNID - pgid mismatch for device "
                              "0.%x.%04x, can't pathgroup\n",
-                             cdev->private->ssid, cdev->private->devno);
+                             cdev->private->dev_id.ssid,
+                             cdev->private->dev_id.devno);
                cdev->private->options.pgroup = 0;
                return;
        }
@@ -454,8 +444,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);
 }
 
@@ -523,7 +513,7 @@ ccw_device_nopath_notify(void *data)
        struct subchannel *sch;
        int ret;
 
-       cdev = (struct ccw_device *)data;
+       cdev = data;
        sch = to_subchannel(cdev->dev.parent);
        /* Extra sanity. */
        if (sch->lpm)
@@ -537,7 +527,7 @@ ccw_device_nopath_notify(void *data)
                        if (get_device(&cdev->dev)) {
                                PREPARE_WORK(&cdev->private->kick_work,
                                             ccw_device_call_sch_unregister,
-                                            (void *)cdev);
+                                            cdev);
                                queue_work(ccw_device_work,
                                           &cdev->private->kick_work);
                        } else
@@ -555,7 +545,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;
@@ -576,11 +578,15 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
                }
                break;
        case -ETIME:
+               /* Reset oper notify indication after verify error. */
+               cdev->private->flags.donotify = 0;
                ccw_device_done(cdev, DEV_STATE_BOXED);
                break;
        default:
+               /* Reset oper notify indication after verify error. */
+               cdev->private->flags.donotify = 0;
                PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_nopath_notify, (void *)cdev);
+                            ccw_device_nopath_notify, cdev);
                queue_work(ccw_device_notify_work, &cdev->private->kick_work);
                ccw_device_done(cdev, DEV_STATE_NOT_OPER);
                break;
@@ -613,6 +619,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;
        }
@@ -659,7 +666,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;
        }
@@ -711,7 +717,7 @@ ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event)
        sch = to_subchannel(cdev->dev.parent);
        if (get_device(&cdev->dev)) {
                PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_call_sch_unregister, (void *)cdev);
+                            ccw_device_call_sch_unregister, cdev);
                queue_work(ccw_device_work, &cdev->private->kick_work);
        }
        wake_up(&cdev->private->wait_q);
@@ -742,7 +748,7 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
        }
        if (get_device(&cdev->dev)) {
                PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_call_sch_unregister, (void *)cdev);
+                            ccw_device_call_sch_unregister, cdev);
                queue_work(ccw_device_work, &cdev->private->kick_work);
        }
        wake_up(&cdev->private->wait_q);
@@ -780,6 +786,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);
 }
 
@@ -846,7 +853,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
                sch = to_subchannel(cdev->dev.parent);
                if (!sch->lpm) {
                        PREPARE_WORK(&cdev->private->kick_work,
-                                    ccw_device_nopath_notify, (void *)cdev);
+                                    ccw_device_nopath_notify, cdev);
                        queue_work(ccw_device_notify_work,
                                   &cdev->private->kick_work);
                } else
@@ -872,7 +879,8 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
                        /* Basic sense hasn't started. Try again. */
                        ccw_device_do_sense(cdev, irb);
                else {
-                       printk("Huh? %s(%s): unsolicited interrupt...\n",
+                       printk(KERN_INFO "Huh? %s(%s): unsolicited "
+                              "interrupt...\n",
                               __FUNCTION__, cdev->dev.bus_id);
                        if (cdev->handler)
                                cdev->handler (cdev, 0, irb);
@@ -931,10 +939,10 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
        cdev->private->state = DEV_STATE_ONLINE;
        if (cdev->handler)
                cdev->handler(cdev, cdev->private->intparm,
-                             ERR_PTR(-ETIMEDOUT));
+                             ERR_PTR(-EIO));
        if (!sch->lpm) {
                PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_nopath_notify, (void *)cdev);
+                            ccw_device_nopath_notify, cdev);
                queue_work(ccw_device_notify_work, &cdev->private->kick_work);
        } else if (cdev->private->flags.doverify)
                /* Start delayed path verification. */
@@ -957,7 +965,7 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event)
                sch = to_subchannel(cdev->dev.parent);
                if (!sch->lpm) {
                        PREPARE_WORK(&cdev->private->kick_work,
-                                    ccw_device_nopath_notify, (void *)cdev);
+                                    ccw_device_nopath_notify, cdev);
                        queue_work(ccw_device_notify_work,
                                   &cdev->private->kick_work);
                } else
@@ -968,51 +976,15 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event)
        cdev->private->state = DEV_STATE_ONLINE;
        if (cdev->handler)
                cdev->handler(cdev, cdev->private->intparm,
-                             ERR_PTR(-ETIMEDOUT));
+                             ERR_PTR(-EIO));
 }
 
-static void
-ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event)
-{
-       struct irb *irb;
-       struct subchannel *sch;
-
-       irb = (struct irb *) __LC_IRB;
-       /*
-        * Accumulate status and find out if a basic sense is needed.
-        * This is fine since we have already adapted the lpm.
-        */
-       ccw_device_accumulate_irb(cdev, irb);
-       if (cdev->private->flags.dosense) {
-               if (ccw_device_do_sense(cdev, irb) == 0) {
-                       cdev->private->state = DEV_STATE_W4SENSE;
-               }
-               return;
-       }
-
-       /* Iff device is idle, reset timeout. */
-       sch = to_subchannel(cdev->dev.parent);
-       if (!stsch(sch->schid, &sch->schib))
-               if (sch->schib.scsw.actl == 0)
-                       ccw_device_set_timeout(cdev, 0);
-       /* Call the handler. */
-       ccw_device_call_handler(cdev);
-       if (!sch->lpm) {
-               PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_nopath_notify, (void *)cdev);
-               queue_work(ccw_device_notify_work, &cdev->private->kick_work);
-       } else if (cdev->private->flags.doverify)
-               ccw_device_online_verify(cdev, 0);
-}
-
-static void
-ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
+void device_kill_io(struct subchannel *sch)
 {
        int ret;
-       struct subchannel *sch;
+       struct ccw_device *cdev;
 
-       sch = to_subchannel(cdev->dev.parent);
-       ccw_device_set_timeout(cdev, 0);
+       cdev = sch->dev.driver_data;
        ret = ccw_device_cancel_halt_clear(cdev);
        if (ret == -EBUSY) {
                ccw_device_set_timeout(cdev, 3*HZ);
@@ -1022,7 +994,7 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
        if (ret == -ENODEV) {
                if (!sch->lpm) {
                        PREPARE_WORK(&cdev->private->kick_work,
-                                    ccw_device_nopath_notify, (void *)cdev);
+                                    ccw_device_nopath_notify, cdev);
                        queue_work(ccw_device_notify_work,
                                   &cdev->private->kick_work);
                } else
@@ -1031,20 +1003,20 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
        }
        if (cdev->handler)
                cdev->handler(cdev, cdev->private->intparm,
-                             ERR_PTR(-ETIMEDOUT));
+                             ERR_PTR(-EIO));
        if (!sch->lpm) {
                PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_nopath_notify, (void *)cdev);
+                            ccw_device_nopath_notify, cdev);
                queue_work(ccw_device_notify_work, &cdev->private->kick_work);
-       } else if (cdev->private->flags.doverify)
+       } else
                /* Start delayed path verification. */
                ccw_device_online_verify(cdev, 0);
 }
 
 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;
 }
 
@@ -1110,10 +1082,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;
@@ -1237,7 +1206,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,
@@ -1276,12 +1245,6 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_TIMEOUT]     = ccw_device_killing_timeout,
                [DEV_EVENT_VERIFY]      = ccw_device_nop, //FIXME
        },
-       [DEV_STATE_WAIT4IO] = {
-               [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_STATE_QUIESCE] = {
                [DEV_EVENT_NOTOPER]     = ccw_device_quiesce_done,
                [DEV_EVENT_INTERRUPT]   = ccw_device_quiesce_done,
@@ -1293,7 +1256,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,