diff options
Diffstat (limited to 'drivers/s390/cio/device_pgid.c')
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 29 |
1 files changed, 18 insertions, 11 deletions
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index aad188e43b4f..6facb5499a65 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -142,7 +142,7 @@ static void spid_do(struct ccw_device *cdev) | |||
142 | u8 fn; | 142 | u8 fn; |
143 | 143 | ||
144 | /* Use next available path that is not already in correct state. */ | 144 | /* Use next available path that is not already in correct state. */ |
145 | req->lpm = lpm_adjust(req->lpm, sch->schib.pmcw.pam & ~sch->vpm); | 145 | req->lpm = lpm_adjust(req->lpm, cdev->private->pgid_todo_mask); |
146 | if (!req->lpm) | 146 | if (!req->lpm) |
147 | goto out_nopath; | 147 | goto out_nopath; |
148 | /* Channel program setup. */ | 148 | /* Channel program setup. */ |
@@ -254,15 +254,15 @@ static void pgid_analyze(struct ccw_device *cdev, struct pgid **p, | |||
254 | *p = first; | 254 | *p = first; |
255 | } | 255 | } |
256 | 256 | ||
257 | static u8 pgid_to_vpm(struct ccw_device *cdev) | 257 | static u8 pgid_to_donepm(struct ccw_device *cdev) |
258 | { | 258 | { |
259 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | 259 | struct subchannel *sch = to_subchannel(cdev->dev.parent); |
260 | struct pgid *pgid; | 260 | struct pgid *pgid; |
261 | int i; | 261 | int i; |
262 | int lpm; | 262 | int lpm; |
263 | u8 vpm = 0; | 263 | u8 donepm = 0; |
264 | 264 | ||
265 | /* Set VPM bits for paths which are already in the target state. */ | 265 | /* Set bits for paths which are already in the target state. */ |
266 | for (i = 0; i < 8; i++) { | 266 | for (i = 0; i < 8; i++) { |
267 | lpm = 0x80 >> i; | 267 | lpm = 0x80 >> i; |
268 | if ((cdev->private->pgid_valid_mask & lpm) == 0) | 268 | if ((cdev->private->pgid_valid_mask & lpm) == 0) |
@@ -282,10 +282,10 @@ static u8 pgid_to_vpm(struct ccw_device *cdev) | |||
282 | if (pgid->inf.ps.state3 != SNID_STATE3_SINGLE_PATH) | 282 | if (pgid->inf.ps.state3 != SNID_STATE3_SINGLE_PATH) |
283 | continue; | 283 | continue; |
284 | } | 284 | } |
285 | vpm |= lpm; | 285 | donepm |= lpm; |
286 | } | 286 | } |
287 | 287 | ||
288 | return vpm; | 288 | return donepm; |
289 | } | 289 | } |
290 | 290 | ||
291 | static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid) | 291 | static void pgid_fill(struct ccw_device *cdev, struct pgid *pgid) |
@@ -307,6 +307,7 @@ static void snid_done(struct ccw_device *cdev, int rc) | |||
307 | int mismatch = 0; | 307 | int mismatch = 0; |
308 | int reserved = 0; | 308 | int reserved = 0; |
309 | int reset = 0; | 309 | int reset = 0; |
310 | u8 donepm; | ||
310 | 311 | ||
311 | if (rc) | 312 | if (rc) |
312 | goto out; | 313 | goto out; |
@@ -316,18 +317,20 @@ static void snid_done(struct ccw_device *cdev, int rc) | |||
316 | else if (mismatch) | 317 | else if (mismatch) |
317 | rc = -EOPNOTSUPP; | 318 | rc = -EOPNOTSUPP; |
318 | else { | 319 | else { |
319 | sch->vpm = pgid_to_vpm(cdev); | 320 | donepm = pgid_to_donepm(cdev); |
321 | sch->vpm = donepm & sch->opm; | ||
322 | cdev->private->pgid_todo_mask &= ~donepm; | ||
320 | pgid_fill(cdev, pgid); | 323 | pgid_fill(cdev, pgid); |
321 | } | 324 | } |
322 | out: | 325 | out: |
323 | CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x " | 326 | CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x " |
324 | "mism=%d rsvd=%d reset=%d\n", id->ssid, id->devno, rc, | 327 | "todo=%02x mism=%d rsvd=%d reset=%d\n", id->ssid, |
325 | cdev->private->pgid_valid_mask, sch->vpm, mismatch, | 328 | id->devno, rc, cdev->private->pgid_valid_mask, sch->vpm, |
326 | reserved, reset); | 329 | cdev->private->pgid_todo_mask, mismatch, reserved, reset); |
327 | switch (rc) { | 330 | switch (rc) { |
328 | case 0: | 331 | case 0: |
329 | /* Anything left to do? */ | 332 | /* Anything left to do? */ |
330 | if (sch->vpm == sch->schib.pmcw.pam) { | 333 | if (cdev->private->pgid_todo_mask == 0) { |
331 | verify_done(cdev, sch->vpm == 0 ? -EACCES : 0); | 334 | verify_done(cdev, sch->vpm == 0 ? -EACCES : 0); |
332 | return; | 335 | return; |
333 | } | 336 | } |
@@ -411,6 +414,7 @@ static void verify_start(struct ccw_device *cdev) | |||
411 | struct ccw_dev_id *devid = &cdev->private->dev_id; | 414 | struct ccw_dev_id *devid = &cdev->private->dev_id; |
412 | 415 | ||
413 | sch->vpm = 0; | 416 | sch->vpm = 0; |
417 | sch->lpm = sch->schib.pmcw.pam; | ||
414 | /* Initialize request data. */ | 418 | /* Initialize request data. */ |
415 | memset(req, 0, sizeof(*req)); | 419 | memset(req, 0, sizeof(*req)); |
416 | req->timeout = PGID_TIMEOUT; | 420 | req->timeout = PGID_TIMEOUT; |
@@ -442,11 +446,14 @@ static void verify_start(struct ccw_device *cdev) | |||
442 | */ | 446 | */ |
443 | void ccw_device_verify_start(struct ccw_device *cdev) | 447 | void ccw_device_verify_start(struct ccw_device *cdev) |
444 | { | 448 | { |
449 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
450 | |||
445 | CIO_TRACE_EVENT(4, "vrfy"); | 451 | CIO_TRACE_EVENT(4, "vrfy"); |
446 | CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); | 452 | CIO_HEX_EVENT(4, &cdev->private->dev_id, sizeof(cdev->private->dev_id)); |
447 | /* Initialize PGID data. */ | 453 | /* Initialize PGID data. */ |
448 | memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid)); | 454 | memset(cdev->private->pgid, 0, sizeof(cdev->private->pgid)); |
449 | cdev->private->pgid_valid_mask = 0; | 455 | cdev->private->pgid_valid_mask = 0; |
456 | cdev->private->pgid_todo_mask = sch->schib.pmcw.pam; | ||
450 | /* | 457 | /* |
451 | * Initialize pathgroup and multipath state with target values. | 458 | * Initialize pathgroup and multipath state with target values. |
452 | * They may change in the course of path verification. | 459 | * They may change in the course of path verification. |