linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / s390 / cio / device_fsm.c
index 35e162b..b302779 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
 #include <linux/string.h>
@@ -152,8 +153,7 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
                if (cdev->private->iretry) {
                        cdev->private->iretry--;
                        ret = cio_halt(sch);
-                       if (ret != -EBUSY)
-                               return (ret == 0) ? -EBUSY : ret;
+                       return (ret == 0) ? -EBUSY : ret;
                }
                /* halt io unsuccessful. */
                cdev->private->iretry = 255;    /* 255 clear retries. */
@@ -267,10 +267,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                        notify = 1;
                }
                /* fill out sense information */
-               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;
+               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,
+               };
                if (notify) {
                        cdev->private->state = DEV_STATE_OFFLINE;
                        if (same_dev) {
@@ -334,11 +336,8 @@ ccw_device_oper_notify(void *data)
        if (!ret)
                /* Driver doesn't want device back. */
                ccw_device_do_unreg_rereg((void *)cdev);
-       else {
-               /* Reenable channel measurements, if needed. */
-               cmf_reenable(cdev);
+       else
                wake_up(&cdev->private->wait_q);
-       }
 }
 
 /*
@@ -377,56 +376,6 @@ ccw_device_done(struct ccw_device *cdev, int state)
                put_device (&cdev->dev);
 }
 
-static inline int cmp_pgid(struct pgid *p1, struct pgid *p2)
-{
-       char *c1;
-       char *c2;
-
-       c1 = (char *)p1;
-       c2 = (char *)p2;
-
-       return memcmp(c1 + 1, c2 + 1, sizeof(struct pgid) - 1);
-}
-
-static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
-{
-       int i;
-       int last;
-
-       last = 0;
-       for (i = 0; i < 8; i++) {
-               if (cdev->private->pgid[i].inf.ps.state1 == SNID_STATE1_RESET)
-                       /* No PGID yet */
-                       continue;
-               if (cdev->private->pgid[last].inf.ps.state1 ==
-                   SNID_STATE1_RESET) {
-                       /* First non-zero PGID */
-                       last = i;
-                       continue;
-               }
-               if (cmp_pgid(&cdev->private->pgid[i],
-                            &cdev->private->pgid[last]) == 0)
-                       /* Non-conflicting PGIDs */
-                       continue;
-
-               /* 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->options.pgroup = 0;
-               return;
-       }
-       if (cdev->private->pgid[last].inf.ps.state1 ==
-           SNID_STATE1_RESET)
-               /* No previous pgid found */
-               memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
-                      sizeof(struct pgid));
-       else
-               /* Use existing pgid */
-               memcpy(&cdev->private->pgid[0], &cdev->private->pgid[last],
-                      sizeof(struct pgid));
-}
-
 /*
  * Function called from device_pgid.c after sense path ground has completed.
  */
@@ -437,26 +386,24 @@ ccw_device_sense_pgid_done(struct ccw_device *cdev, int err)
 
        sch = to_subchannel(cdev->dev.parent);
        switch (err) {
-       case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */
-               cdev->private->options.pgroup = 0;
-               break;
-       case 0: /* success */
-       case -EACCES: /* partial success, some paths not operational */
-               /* Check if all pgids are equal or 0. */
-               __ccw_device_get_common_pgid(cdev);
+       case 0:
+               /* Start Path Group verification. */
+               sch->vpm = 0;   /* Start with no path groups set. */
+               cdev->private->state = DEV_STATE_VERIFY;
+               ccw_device_verify_start(cdev);
                break;
        case -ETIME:            /* Sense path group id stopped by timeout. */
        case -EUSERS:           /* device is reserved for someone else. */
                ccw_device_done(cdev, DEV_STATE_BOXED);
-               return;
+               break;
+       case -EOPNOTSUPP: /* path grouping not supported, just set online. */
+               cdev->private->options.pgroup = 0;
+               ccw_device_done(cdev, DEV_STATE_ONLINE);
+               break;
        default:
                ccw_device_done(cdev, DEV_STATE_NOT_OPER);
-               return;
+               break;
        }
-       /* Start Path Group verification. */
-       sch->vpm = 0;   /* Start with no path groups set. */
-       cdev->private->state = DEV_STATE_VERIFY;
-       ccw_device_verify_start(cdev);
 }
 
 /*
@@ -564,10 +511,12 @@ 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.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->irb.scsw = (struct scsw) {
+                               .cc = 1,
+                               .fctl = SCSW_FCTL_START_FUNC,
+                               .actl = SCSW_ACTL_START_PEND,
+                               .stctl = SCSW_STCTL_STATUS_PEND,
+                       };
                        cdev->private->flags.fake_irb = 0;
                        if (cdev->handler)
                                cdev->handler(cdev, cdev->private->intparm,
@@ -611,9 +560,8 @@ ccw_device_online(struct ccw_device *cdev)
        }
        /* Do we want to do path grouping? */
        if (!cdev->private->options.pgroup) {
-               /* Start initial path verification. */
-               cdev->private->state = DEV_STATE_VERIFY;
-               ccw_device_verify_start(cdev);
+               /* No, set state online immediately. */
+               ccw_device_done(cdev, DEV_STATE_ONLINE);
                return 0;
        }
        /* Do a SensePGID first. */
@@ -659,7 +607,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;
        }
@@ -756,6 +703,8 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
 {
        struct subchannel *sch;
 
+       if (!cdev->private->options.pgroup)
+               return;
        if (cdev->private->state == DEV_STATE_W4SENSE) {
                cdev->private->flags.doverify = 1;
                return;
@@ -768,7 +717,6 @@ 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
@@ -801,7 +749,7 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
                        /* Unit check but no sense data. Need basic sense. */
                        if (ccw_device_do_sense(cdev, irb) != 0)
                                goto call_handler_unsol;
-                       memcpy(&cdev->private->irb, irb, sizeof(struct irb));
+                       memcpy(irb, &cdev->private->irb, sizeof(struct irb));
                        cdev->private->state = DEV_STATE_W4SENSE;
                        cdev->private->intparm = 0;
                        return;
@@ -879,17 +827,6 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
                }
                return;
        }
-       /*
-        * Check if a halt or clear has been issued in the meanwhile. If yes,
-        * only deliver the halt/clear interrupt to the device driver as if it
-        * had killed the original request.
-        */
-       if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
-               cdev->private->flags.dosense = 0;
-               memset(&cdev->private->irb, 0, sizeof(struct irb));
-               ccw_device_accumulate_irb(cdev, irb);
-               goto call_handler;
-       }
        /* Add basic sense info to irb. */
        ccw_device_accumulate_basic_sense(cdev, irb);
        if (cdev->private->flags.dosense) {
@@ -897,7 +834,6 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
                ccw_device_do_sense(cdev, irb);
                return;
        }
-call_handler:
        cdev->private->state = DEV_STATE_ONLINE;
        /* Call the handler. */
        if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
@@ -913,8 +849,6 @@ ccw_device_clear_verify(struct ccw_device *cdev, enum dev_event dev_event)
        irb = (struct irb *) __LC_IRB;
        /* Accumulate status. We don't do basic sense. */
        ccw_device_accumulate_irb(cdev, irb);
-       /* Remember to clear irb to avoid residuals. */
-       memset(&cdev->private->irb, 0, sizeof(struct irb));
        /* Try to start delayed device verification. */
        ccw_device_online_verify(cdev, 0);
        /* Note: Don't call handler for cio initiated clear! */
@@ -1045,7 +979,8 @@ static void
 ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event)
 {
        /* When the I/O has terminated, we have to start verification. */
-       cdev->private->flags.doverify = 1;
+       if (cdev->private->options.pgroup)
+               cdev->private->flags.doverify = 1;
 }
 
 static void
@@ -1146,13 +1081,6 @@ ccw_device_change_cmfstate(struct ccw_device *cdev, enum dev_event dev_event)
        dev_fsm_event(cdev, dev_event);
 }
 
-static void ccw_device_update_cmfblock(struct ccw_device *cdev,
-                                      enum dev_event dev_event)
-{
-       cmf_retry_copy_block(cdev);
-       cdev->private->state = DEV_STATE_ONLINE;
-       dev_fsm_event(cdev, dev_event);
-}
 
 static void
 ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event)
@@ -1307,12 +1235,6 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_TIMEOUT]     = ccw_device_change_cmfstate,
                [DEV_EVENT_VERIFY]      = ccw_device_change_cmfstate,
        },
-       [DEV_STATE_CMFUPDATE] = {
-               [DEV_EVENT_NOTOPER]     = ccw_device_update_cmfblock,
-               [DEV_EVENT_INTERRUPT]   = ccw_device_update_cmfblock,
-               [DEV_EVENT_TIMEOUT]     = ccw_device_update_cmfblock,
-               [DEV_EVENT_VERIFY]      = ccw_device_update_cmfblock,
-       },
 };
 
 /*