aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2012-11-30 10:48:59 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-12-03 10:43:58 -0500
commitd99e79ec5574fc556c988f613ed6175f6de66f4a (patch)
tree50657d29de857267b5fe5cacc5b240d0275dc05c /drivers/s390/cio
parent1150f25441a7dad818fa4366d01c45c2fef1cbe8 (diff)
s390/cio: fix pgid reserved check
The check to whom a device is reserved is done by checking the path state of the affected channel paths. If it turns out that one path is flagged as reserved by someone else the whole device is marked as such. However the meaning of the RESVD_ELSE bit is that the addressed device is reserved to a different pathgroup (and not reserved to a different LPAR). If we do this test on a path which is currently not a member of the pathgroup we could erroneously mark the device as reserved to someone else. To fix this collect the reserved state for all potential members of the pathgroup and only mark the device as reserved if all of those potential members have the RESVD_ELSE bit set. Cc: stable@vger.kernel.org Acked-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>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/device_pgid.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 368368fe04b2..908d287f66c1 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -234,7 +234,7 @@ static int pgid_cmp(struct pgid *p1, struct pgid *p2)
234 * Determine pathgroup state from PGID data. 234 * Determine pathgroup state from PGID data.
235 */ 235 */
236static void pgid_analyze(struct ccw_device *cdev, struct pgid **p, 236static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
237 int *mismatch, int *reserved, u8 *reset) 237 int *mismatch, u8 *reserved, u8 *reset)
238{ 238{
239 struct pgid *pgid = &cdev->private->pgid[0]; 239 struct pgid *pgid = &cdev->private->pgid[0];
240 struct pgid *first = NULL; 240 struct pgid *first = NULL;
@@ -248,7 +248,7 @@ static void pgid_analyze(struct ccw_device *cdev, struct pgid **p,
248 if ((cdev->private->pgid_valid_mask & lpm) == 0) 248 if ((cdev->private->pgid_valid_mask & lpm) == 0)
249 continue; 249 continue;
250 if (pgid->inf.ps.state2 == SNID_STATE2_RESVD_ELSE) 250 if (pgid->inf.ps.state2 == SNID_STATE2_RESVD_ELSE)
251 *reserved = 1; 251 *reserved |= lpm;
252 if (pgid_is_reset(pgid)) { 252 if (pgid_is_reset(pgid)) {
253 *reset |= lpm; 253 *reset |= lpm;
254 continue; 254 continue;
@@ -316,14 +316,14 @@ static void snid_done(struct ccw_device *cdev, int rc)
316 struct subchannel *sch = to_subchannel(cdev->dev.parent); 316 struct subchannel *sch = to_subchannel(cdev->dev.parent);
317 struct pgid *pgid; 317 struct pgid *pgid;
318 int mismatch = 0; 318 int mismatch = 0;
319 int reserved = 0; 319 u8 reserved = 0;
320 u8 reset = 0; 320 u8 reset = 0;
321 u8 donepm; 321 u8 donepm;
322 322
323 if (rc) 323 if (rc)
324 goto out; 324 goto out;
325 pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset); 325 pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset);
326 if (reserved) 326 if (reserved == cdev->private->pgid_valid_mask)
327 rc = -EUSERS; 327 rc = -EUSERS;
328 else if (mismatch) 328 else if (mismatch)
329 rc = -EOPNOTSUPP; 329 rc = -EOPNOTSUPP;
@@ -336,7 +336,7 @@ static void snid_done(struct ccw_device *cdev, int rc)
336 } 336 }
337out: 337out:
338 CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x " 338 CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x "
339 "todo=%02x mism=%d rsvd=%d reset=%02x\n", id->ssid, 339 "todo=%02x mism=%d rsvd=%02x reset=%02x\n", id->ssid,
340 id->devno, rc, cdev->private->pgid_valid_mask, sch->vpm, 340 id->devno, rc, cdev->private->pgid_valid_mask, sch->vpm,
341 cdev->private->pgid_todo_mask, mismatch, reserved, reset); 341 cdev->private->pgid_todo_mask, mismatch, reserved, reset);
342 switch (rc) { 342 switch (rc) {