diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2006-07-12 16:40:19 +0200 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2006-07-12 16:40:19 +0200 |
commit | 7e560814de1972e1bfc780616841d7a0032ca467 (patch) | |
tree | f8d544454b54a0167f757cc945a3e29165f211f8 /drivers/s390/cio/device_fsm.c | |
parent | 5c898ba9d4b6c14fdd367b96e3641c2508b4a4a9 (diff) | |
download | linux-7e560814de1972e1bfc780616841d7a0032ca467.tar.bz2 |
[S390] path grouping and path verifications fixes.
1. Multipath devices for which SetPGID is not supported are not handled well.
Use NOP ccws for path verification (sans path grouping) when SetPGID is not
supported.
2. Check for PGIDs already set with SensePGID on _all_ paths (not just the
first one) and try to find a common one. Moan if no common PGID can be
found (and use NOP verification). If no PGIDs have been set, use the css
global PGID (as before). (Rationale: SetPGID will get a command reject if
the PGID it tries to set does not match the already set PGID.)
3. Immediately before reboot, issue RESET CHANNEL PATH (rcp) on all chpids. This
will remove the old PGIDs. rcp will generate solicited CRWs which can be
savely ignored by the machine check handler (all other actions create
unsolicited CRWs).
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/device_fsm.c')
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 85 |
1 files changed, 68 insertions, 17 deletions
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index cb1af0b6f033..ac6e0c7e43d9 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -378,6 +378,56 @@ 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. */ @@ -388,24 +438,26 @@ ccw_device_sense_pgid_done(struct ccw_device *cdev, int err) sch = to_subchannel(cdev->dev.parent); switch (err) { - 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); + 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); 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); - break; - case -EOPNOTSUPP: /* path grouping not supported, just set online. */ - cdev->private->options.pgroup = 0; - ccw_device_done(cdev, DEV_STATE_ONLINE); - break; + return; default: ccw_device_done(cdev, DEV_STATE_NOT_OPER); - break; + return; } + /* Start Path Group verification. */ + sch->vpm = 0; /* Start with no path groups set. */ + cdev->private->state = DEV_STATE_VERIFY; + ccw_device_verify_start(cdev); } /* @@ -562,8 +614,9 @@ ccw_device_online(struct ccw_device *cdev) } /* Do we want to do path grouping? */ if (!cdev->private->options.pgroup) { - /* No, set state online immediately. */ - ccw_device_done(cdev, DEV_STATE_ONLINE); + /* Start initial path verification. */ + cdev->private->state = DEV_STATE_VERIFY; + ccw_device_verify_start(cdev); return 0; } /* Do a SensePGID first. */ @@ -609,6 +662,7 @@ 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; } @@ -705,8 +759,6 @@ 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; @@ -995,8 +1047,7 @@ 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. */ - if (cdev->private->options.pgroup) - cdev->private->flags.doverify = 1; + cdev->private->flags.doverify = 1; } static void |