s390/cio: dont abort verification after missing irq
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Mon, 28 Jan 2013 18:29:43 +0000 (19:29 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 14 Feb 2013 14:55:07 +0000 (15:55 +0100)
Do not abort path verification when waiting for an interrupt timed out.
Use path_noirq_mask to keep track of the paths used for this (also
maintain a path_notoper_mask for debugging purposes). If the timeout
happend to be during an operation where we query or alter the state of
path groups set the pgid_unknown flag.

With this change we allow usage of devices which have such ill-behaved
paths (if at least one path is operational).

Reviewed-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/cio/device_pgid.c
drivers/s390/cio/io_sch.h

index 908d287f66c13c1b1f41daf6bdb7b15bdd6d845f..6f2987d8da998358d62867dbc3f2eea7deeb397e 100644 (file)
@@ -102,10 +102,20 @@ static void nop_callback(struct ccw_device *cdev, void *data, int rc)
        struct subchannel *sch = to_subchannel(cdev->dev.parent);
        struct ccw_request *req = &cdev->private->req;
 
-       if (rc == 0)
+       switch (rc) {
+       case 0:
                sch->vpm |= req->lpm;
-       else if (rc != -EACCES)
+               break;
+       case -ETIME:
+               cdev->private->path_noirq_mask |= req->lpm;
+               break;
+       case -EACCES:
+               cdev->private->path_notoper_mask |= req->lpm;
+               break;
+       default:
                goto err;
+       }
+       /* Continue on the next path. */
        req->lpm >>= 1;
        nop_do(cdev);
        return;
@@ -174,7 +184,12 @@ static void spid_callback(struct ccw_device *cdev, void *data, int rc)
        case 0:
                sch->vpm |= req->lpm & sch->opm;
                break;
+       case -ETIME:
+               cdev->private->flags.pgid_unknown = 1;
+               cdev->private->path_noirq_mask |= req->lpm;
+               break;
        case -EACCES:
+               cdev->private->path_notoper_mask |= req->lpm;
                break;
        case -EOPNOTSUPP:
                if (cdev->private->flags.mpath) {
@@ -404,10 +419,21 @@ static void snid_callback(struct ccw_device *cdev, void *data, int rc)
 {
        struct ccw_request *req = &cdev->private->req;
 
-       if (rc == 0)
+       switch (rc) {
+       case 0:
                cdev->private->pgid_valid_mask |= req->lpm;
-       else if (rc != -EACCES)
+               break;
+       case -ETIME:
+               cdev->private->flags.pgid_unknown = 1;
+               cdev->private->path_noirq_mask |= req->lpm;
+               break;
+       case -EACCES:
+               cdev->private->path_notoper_mask |= req->lpm;
+               break;
+       default:
                goto err;
+       }
+       /* Continue on the next path. */
        req->lpm >>= 1;
        snid_do(cdev);
        return;
@@ -427,6 +453,13 @@ static void verify_start(struct ccw_device *cdev)
 
        sch->vpm = 0;
        sch->lpm = sch->schib.pmcw.pam;
+
+       /* Initialize PGID data. */
+       memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
+       cdev->private->pgid_valid_mask = 0;
+       cdev->private->pgid_todo_mask = sch->schib.pmcw.pam;
+       cdev->private->path_notoper_mask = 0;
+
        /* Initialize request data. */
        memset(req, 0, sizeof(*req));
        req->timeout    = PGID_TIMEOUT;
@@ -459,14 +492,8 @@ static void verify_start(struct ccw_device *cdev)
  */
 void ccw_device_verify_start(struct ccw_device *cdev)
 {
-       struct subchannel *sch = to_subchannel(cdev->dev.parent);
-
        CIO_TRACE_EVENT(4, "vrfy");
        CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id));
-       /* Initialize PGID data. */
-       memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid));
-       cdev->private->pgid_valid_mask = 0;
-       cdev->private->pgid_todo_mask = sch->schib.pmcw.pam;
        /*
         * Initialize pathgroup and multipath state with target values.
         * They may change in the course of path verification.
@@ -474,6 +501,7 @@ void ccw_device_verify_start(struct ccw_device *cdev)
        cdev->private->flags.pgroup = cdev->private->options.pgroup;
        cdev->private->flags.mpath = cdev->private->options.mpath;
        cdev->private->flags.doverify = 0;
+       cdev->private->path_noirq_mask = 0;
        verify_start(cdev);
 }
 
index 76253dfcc1be86a18eba7ac7ea4d6f53c134bc7e..b108f4a5c7dd33aef5d20d9e5a5074a31ac8514e 100644 (file)
@@ -126,6 +126,10 @@ struct ccw_device_private {
        u8 pgid_valid_mask;     /* mask of valid PGIDs */
        u8 pgid_todo_mask;      /* mask of PGIDs to be adjusted */
        u8 pgid_reset_mask;     /* mask of PGIDs which were reset */
+       u8 path_noirq_mask;     /* mask of paths for which no irq was
+                                  received */
+       u8 path_notoper_mask;   /* mask of paths which were found
+                                  not operable */
        u8 path_gone_mask;      /* mask of paths, that became unavailable */
        u8 path_new_mask;       /* mask of paths, that became available */
        struct {
@@ -145,6 +149,7 @@ struct ccw_device_private {
                unsigned int resuming:1;    /* recognition while resume */
                unsigned int pgroup:1;      /* pathgroup is set up */
                unsigned int mpath:1;       /* multipathing is set up */
+               unsigned int pgid_unknown:1;/* unknown pgid state */
                unsigned int initialized:1; /* set if initial reference held */
        } __attribute__((packed)) flags;
        unsigned long intparm;  /* user interruption parameter */