[S390] cio: Issue SenseID per path.
authorCornelia Huck <cornelia.huck@de.ibm.com>
Tue, 4 Dec 2007 15:09:01 +0000 (16:09 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 4 Dec 2007 15:09:57 +0000 (16:09 +0100)
We may receive a unit check for every path when we issue a SenseID.
Unfortunately, the channel subsystem will try on a different path
every time if we use a lpm of 0xff, which will exhaust our retry
counter.

Therefore, revert SenseID to its previous per-path behaviour and
just leave out the suspend multipath reconnect.

Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/cio/device_id.c

index 2f6bf462425e1eb8768b2fa2146be129bda1a9d6..156f3f9786b52e6ddfaeb765c81fec7ff0f77c73 100644 (file)
@@ -113,6 +113,7 @@ __ccw_device_sense_id_start(struct ccw_device *cdev)
 {
        struct subchannel *sch;
        struct ccw1 *ccw;
+       int ret;
 
        sch = to_subchannel(cdev->dev.parent);
        /* Setup sense channel program. */
@@ -124,9 +125,25 @@ __ccw_device_sense_id_start(struct ccw_device *cdev)
 
        /* Reset device status. */
        memset(&cdev->private->irb, 0, sizeof(struct irb));
-       cdev->private->flags.intretry = 0;
 
-       return cio_start(sch, ccw, LPM_ANYPATH);
+       /* Try on every path. */
+       ret = -ENODEV;
+       while (cdev->private->imask != 0) {
+               if ((sch->opm & cdev->private->imask) != 0 &&
+                   cdev->private->iretry > 0) {
+                       cdev->private->iretry--;
+                       /* Reset internal retry indication. */
+                       cdev->private->flags.intretry = 0;
+                       ret = cio_start (sch, cdev->private->iccws,
+                                        cdev->private->imask);
+                       /* ret is 0, -EBUSY, -EACCES or -ENODEV */
+                       if (ret != -EACCES)
+                               return ret;
+               }
+               cdev->private->imask >>= 1;
+               cdev->private->iretry = 5;
+       }
+       return ret;
 }
 
 void
@@ -136,7 +153,8 @@ ccw_device_sense_id_start(struct ccw_device *cdev)
 
        memset (&cdev->private->senseid, 0, sizeof (struct senseid));
        cdev->private->senseid.cu_type = 0xFFFF;
-       cdev->private->iretry = 3;
+       cdev->private->imask = 0x80;
+       cdev->private->iretry = 5;
        ret = __ccw_device_sense_id_start(cdev);
        if (ret && ret != -EBUSY)
                ccw_device_sense_id_done(cdev, ret);
@@ -252,13 +270,14 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
                ccw_device_sense_id_done(cdev, ret);
                break;
        case -EACCES:           /* channel is not operational. */
+               sch->lpm &= ~cdev->private->imask;
+               cdev->private->imask >>= 1;
+               cdev->private->iretry = 5;
+               /* fall through. */
        case -EAGAIN:           /* try again. */
-               cdev->private->iretry--;
-               if (cdev->private->iretry > 0) {
-                       ret = __ccw_device_sense_id_start(cdev);
-                       if (ret == 0 || ret == -EBUSY)
-                               break;
-               }
+               ret = __ccw_device_sense_id_start(cdev);
+               if (ret == 0 || ret == -EBUSY)
+                       break;
                /* fall through. */
        default:                /* Sense ID failed. Try asking VM. */
                if (MACHINE_IS_VM) {