aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCornelia Huck <cornelia.huck@de.ibm.com>2006-07-12 10:40:19 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2006-07-12 10:40:19 -0400
commit7e560814de1972e1bfc780616841d7a0032ca467 (patch)
treef8d544454b54a0167f757cc945a3e29165f211f8
parent5c898ba9d4b6c14fdd367b96e3641c2508b4a4a9 (diff)
[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>
-rw-r--r--arch/s390/kernel/machine_kexec.c1
-rw-r--r--drivers/s390/cio/chsc.c34
-rw-r--r--drivers/s390/cio/cio.c1
-rw-r--r--drivers/s390/cio/css.c12
-rw-r--r--drivers/s390/cio/css.h2
-rw-r--r--drivers/s390/cio/device_fsm.c85
-rw-r--r--drivers/s390/cio/device_pgid.c122
-rw-r--r--drivers/s390/cio/device_status.c7
-rw-r--r--drivers/s390/s390mach.c10
-rw-r--r--include/asm-s390/cio.h2
10 files changed, 228 insertions, 48 deletions
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index fbde6a915264..60b1ea9f946b 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -63,6 +63,7 @@ NORET_TYPE void
63machine_kexec(struct kimage *image) 63machine_kexec(struct kimage *image)
64{ 64{
65 clear_all_subchannels(); 65 clear_all_subchannels();
66 cio_reset_channel_paths();
66 67
67 /* Disable lowcore protection */ 68 /* Disable lowcore protection */
68 ctl_clear_bit(0,28); 69 ctl_clear_bit(0,28);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index a01f3bba4a7b..61ce3f1d5228 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -1464,6 +1464,40 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no)
1464 return desc; 1464 return desc;
1465} 1465}
1466 1466
1467static int reset_channel_path(struct channel_path *chp)
1468{
1469 int cc;
1470
1471 cc = rchp(chp->id);
1472 switch (cc) {
1473 case 0:
1474 return 0;
1475 case 2:
1476 return -EBUSY;
1477 default:
1478 return -ENODEV;
1479 }
1480}
1481
1482static void reset_channel_paths_css(struct channel_subsystem *css)
1483{
1484 int i;
1485
1486 for (i = 0; i <= __MAX_CHPID; i++) {
1487 if (css->chps[i])
1488 reset_channel_path(css->chps[i]);
1489 }
1490}
1491
1492void cio_reset_channel_paths(void)
1493{
1494 int i;
1495
1496 for (i = 0; i <= __MAX_CSSID; i++) {
1497 if (css[i] && css[i]->valid)
1498 reset_channel_paths_css(css[i]);
1499 }
1500}
1467 1501
1468static int __init 1502static int __init
1469chsc_alloc_sei_area(void) 1503chsc_alloc_sei_area(void)
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index f27b2b866f5a..e36ca27f5777 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -876,5 +876,6 @@ void
876reipl(unsigned long devno) 876reipl(unsigned long devno)
877{ 877{
878 clear_all_subchannels(); 878 clear_all_subchannels();
879 cio_reset_channel_paths();
879 do_reipl(devno); 880 do_reipl(devno);
880} 881}
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index a09deea5d687..13eeea3d547f 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -623,9 +623,13 @@ init_channel_subsystem (void)
623 ret = device_register(&css[i]->device); 623 ret = device_register(&css[i]->device);
624 if (ret) 624 if (ret)
625 goto out_free; 625 goto out_free;
626 if (css_characteristics_avail && css_chsc_characteristics.secm) 626 if (css_characteristics_avail &&
627 device_create_file(&css[i]->device, 627 css_chsc_characteristics.secm) {
628 &dev_attr_cm_enable); 628 ret = device_create_file(&css[i]->device,
629 &dev_attr_cm_enable);
630 if (ret)
631 goto out_device;
632 }
629 } 633 }
630 css_init_done = 1; 634 css_init_done = 1;
631 635
@@ -633,6 +637,8 @@ init_channel_subsystem (void)
633 637
634 for_each_subchannel(__init_channel_subsystem, NULL); 638 for_each_subchannel(__init_channel_subsystem, NULL);
635 return 0; 639 return 0;
640out_device:
641 device_unregister(&css[i]->device);
636out_free: 642out_free:
637 kfree(css[i]); 643 kfree(css[i]);
638out_unregister: 644out_unregister:
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 15f7f7cb0ec2..8aabb4adeb5f 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -100,7 +100,7 @@ struct ccw_device_private {
100 struct qdio_irq *qdio_data; 100 struct qdio_irq *qdio_data;
101 struct irb irb; /* device status */ 101 struct irb irb; /* device status */
102 struct senseid senseid; /* SenseID info */ 102 struct senseid senseid; /* SenseID info */
103 struct pgid pgid; /* path group ID */ 103 struct pgid pgid[8]; /* path group IDs per chpid*/
104 struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ 104 struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */
105 struct work_struct kick_work; 105 struct work_struct kick_work;
106 wait_queue_head_t wait_q; 106 wait_queue_head_t wait_q;
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)
378 put_device (&cdev->dev); 378 put_device (&cdev->dev);
379} 379}
380 380
381static inline int cmp_pgid(struct pgid *p1, struct pgid *p2)
382{
383 char *c1;
384 char *c2;
385
386 c1 = (char *)p1;
387 c2 = (char *)p2;
388
389 return memcmp(c1 + 1, c2 + 1, sizeof(struct pgid) - 1);
390}
391
392static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
393{
394 int i;
395 int last;
396
397 last = 0;
398 for (i = 0; i < 8; i++) {
399 if (cdev->private->pgid[i].inf.ps.state1 == SNID_STATE1_RESET)
400 /* No PGID yet */
401 continue;
402 if (cdev->private->pgid[last].inf.ps.state1 ==
403 SNID_STATE1_RESET) {
404 /* First non-zero PGID */
405 last = i;
406 continue;
407 }
408 if (cmp_pgid(&cdev->private->pgid[i],
409 &cdev->private->pgid[last]) == 0)
410 /* Non-conflicting PGIDs */
411 continue;
412
413 /* PGID mismatch, can't pathgroup. */
414 CIO_MSG_EVENT(0, "SNID - pgid mismatch for device "
415 "0.%x.%04x, can't pathgroup\n",
416 cdev->private->ssid, cdev->private->devno);
417 cdev->private->options.pgroup = 0;
418 return;
419 }
420 if (cdev->private->pgid[last].inf.ps.state1 ==
421 SNID_STATE1_RESET)
422 /* No previous pgid found */
423 memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
424 sizeof(struct pgid));
425 else
426 /* Use existing pgid */
427 memcpy(&cdev->private->pgid[0], &cdev->private->pgid[last],
428 sizeof(struct pgid));
429}
430
381/* 431/*
382 * Function called from device_pgid.c after sense path ground has completed. 432 * Function called from device_pgid.c after sense path ground has completed.
383 */ 433 */
@@ -388,24 +438,26 @@ ccw_device_sense_pgid_done(struct ccw_device *cdev, int err)
388 438
389 sch = to_subchannel(cdev->dev.parent); 439 sch = to_subchannel(cdev->dev.parent);
390 switch (err) { 440 switch (err) {
391 case 0: 441 case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */
392 /* Start Path Group verification. */ 442 cdev->private->options.pgroup = 0;
393 sch->vpm = 0; /* Start with no path groups set. */ 443 break;
394 cdev->private->state = DEV_STATE_VERIFY; 444 case 0: /* success */
395 ccw_device_verify_start(cdev); 445 case -EACCES: /* partial success, some paths not operational */
446 /* Check if all pgids are equal or 0. */
447 __ccw_device_get_common_pgid(cdev);
396 break; 448 break;
397 case -ETIME: /* Sense path group id stopped by timeout. */ 449 case -ETIME: /* Sense path group id stopped by timeout. */
398 case -EUSERS: /* device is reserved for someone else. */ 450 case -EUSERS: /* device is reserved for someone else. */
399 ccw_device_done(cdev, DEV_STATE_BOXED); 451 ccw_device_done(cdev, DEV_STATE_BOXED);
400 break; 452 return;
401 case -EOPNOTSUPP: /* path grouping not supported, just set online. */
402 cdev->private->options.pgroup = 0;
403 ccw_device_done(cdev, DEV_STATE_ONLINE);
404 break;
405 default: 453 default:
406 ccw_device_done(cdev, DEV_STATE_NOT_OPER); 454 ccw_device_done(cdev, DEV_STATE_NOT_OPER);
407 break; 455 return;
408 } 456 }
457 /* Start Path Group verification. */
458 sch->vpm = 0; /* Start with no path groups set. */
459 cdev->private->state = DEV_STATE_VERIFY;
460 ccw_device_verify_start(cdev);
409} 461}
410 462
411/* 463/*
@@ -562,8 +614,9 @@ ccw_device_online(struct ccw_device *cdev)
562 } 614 }
563 /* Do we want to do path grouping? */ 615 /* Do we want to do path grouping? */
564 if (!cdev->private->options.pgroup) { 616 if (!cdev->private->options.pgroup) {
565 /* No, set state online immediately. */ 617 /* Start initial path verification. */
566 ccw_device_done(cdev, DEV_STATE_ONLINE); 618 cdev->private->state = DEV_STATE_VERIFY;
619 ccw_device_verify_start(cdev);
567 return 0; 620 return 0;
568 } 621 }
569 /* Do a SensePGID first. */ 622 /* Do a SensePGID first. */
@@ -609,6 +662,7 @@ ccw_device_offline(struct ccw_device *cdev)
609 /* Are we doing path grouping? */ 662 /* Are we doing path grouping? */
610 if (!cdev->private->options.pgroup) { 663 if (!cdev->private->options.pgroup) {
611 /* No, set state offline immediately. */ 664 /* No, set state offline immediately. */
665 sch->vpm = 0;
612 ccw_device_done(cdev, DEV_STATE_OFFLINE); 666 ccw_device_done(cdev, DEV_STATE_OFFLINE);
613 return 0; 667 return 0;
614 } 668 }
@@ -705,8 +759,6 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
705{ 759{
706 struct subchannel *sch; 760 struct subchannel *sch;
707 761
708 if (!cdev->private->options.pgroup)
709 return;
710 if (cdev->private->state == DEV_STATE_W4SENSE) { 762 if (cdev->private->state == DEV_STATE_W4SENSE) {
711 cdev->private->flags.doverify = 1; 763 cdev->private->flags.doverify = 1;
712 return; 764 return;
@@ -995,8 +1047,7 @@ static void
995ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event) 1047ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event)
996{ 1048{
997 /* When the I/O has terminated, we have to start verification. */ 1049 /* When the I/O has terminated, we have to start verification. */
998 if (cdev->private->options.pgroup) 1050 cdev->private->flags.doverify = 1;
999 cdev->private->flags.doverify = 1;
1000} 1051}
1001 1052
1002static void 1053static void
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 54cb64ed0786..32610fd8868e 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -33,12 +33,17 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
33 struct subchannel *sch; 33 struct subchannel *sch;
34 struct ccw1 *ccw; 34 struct ccw1 *ccw;
35 int ret; 35 int ret;
36 int i;
36 37
37 sch = to_subchannel(cdev->dev.parent); 38 sch = to_subchannel(cdev->dev.parent);
39 /* Return if we already checked on all paths. */
40 if (cdev->private->imask == 0)
41 return (sch->lpm == 0) ? -ENODEV : -EACCES;
42 i = 8 - ffs(cdev->private->imask);
43
38 /* Setup sense path group id channel program. */ 44 /* Setup sense path group id channel program. */
39 ccw = cdev->private->iccws; 45 ccw = cdev->private->iccws;
40 ccw->cmd_code = CCW_CMD_SENSE_PGID; 46 ccw->cmd_code = CCW_CMD_SENSE_PGID;
41 ccw->cda = (__u32) __pa (&cdev->private->pgid);
42 ccw->count = sizeof (struct pgid); 47 ccw->count = sizeof (struct pgid);
43 ccw->flags = CCW_FLAG_SLI; 48 ccw->flags = CCW_FLAG_SLI;
44 49
@@ -48,6 +53,7 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
48 ret = -ENODEV; 53 ret = -ENODEV;
49 while (cdev->private->imask != 0) { 54 while (cdev->private->imask != 0) {
50 /* Try every path multiple times. */ 55 /* Try every path multiple times. */
56 ccw->cda = (__u32) __pa (&cdev->private->pgid[i]);
51 if (cdev->private->iretry > 0) { 57 if (cdev->private->iretry > 0) {
52 cdev->private->iretry--; 58 cdev->private->iretry--;
53 ret = cio_start (sch, cdev->private->iccws, 59 ret = cio_start (sch, cdev->private->iccws,
@@ -64,7 +70,9 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
64 } 70 }
65 cdev->private->imask >>= 1; 71 cdev->private->imask >>= 1;
66 cdev->private->iretry = 5; 72 cdev->private->iretry = 5;
73 i++;
67 } 74 }
75
68 return ret; 76 return ret;
69} 77}
70 78
@@ -76,7 +84,7 @@ ccw_device_sense_pgid_start(struct ccw_device *cdev)
76 cdev->private->state = DEV_STATE_SENSE_PGID; 84 cdev->private->state = DEV_STATE_SENSE_PGID;
77 cdev->private->imask = 0x80; 85 cdev->private->imask = 0x80;
78 cdev->private->iretry = 5; 86 cdev->private->iretry = 5;
79 memset (&cdev->private->pgid, 0, sizeof (struct pgid)); 87 memset (&cdev->private->pgid, 0, sizeof (cdev->private->pgid));
80 ret = __ccw_device_sense_pgid_start(cdev); 88 ret = __ccw_device_sense_pgid_start(cdev);
81 if (ret && ret != -EBUSY) 89 if (ret && ret != -EBUSY)
82 ccw_device_sense_pgid_done(cdev, ret); 90 ccw_device_sense_pgid_done(cdev, ret);
@@ -91,6 +99,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
91{ 99{
92 struct subchannel *sch; 100 struct subchannel *sch;
93 struct irb *irb; 101 struct irb *irb;
102 int i;
94 103
95 sch = to_subchannel(cdev->dev.parent); 104 sch = to_subchannel(cdev->dev.parent);
96 irb = &cdev->private->irb; 105 irb = &cdev->private->irb;
@@ -124,7 +133,8 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
124 sch->schid.sch_no, sch->orb.lpm); 133 sch->schid.sch_no, sch->orb.lpm);
125 return -EACCES; 134 return -EACCES;
126 } 135 }
127 if (cdev->private->pgid.inf.ps.state2 == SNID_STATE2_RESVD_ELSE) { 136 i = 8 - ffs(cdev->private->imask);
137 if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
128 CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x " 138 CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x "
129 "is reserved by someone else\n", 139 "is reserved by someone else\n",
130 cdev->private->devno, sch->schid.ssid, 140 cdev->private->devno, sch->schid.ssid,
@@ -162,12 +172,6 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
162 memset(&cdev->private->irb, 0, sizeof(struct irb)); 172 memset(&cdev->private->irb, 0, sizeof(struct irb));
163 switch (ret) { 173 switch (ret) {
164 /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */ 174 /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */
165 case 0: /* Sense Path Group ID successful. */
166 if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET)
167 memcpy(&cdev->private->pgid, &css[0]->global_pgid,
168 sizeof(struct pgid));
169 ccw_device_sense_pgid_done(cdev, 0);
170 break;
171 case -EOPNOTSUPP: /* Sense Path Group ID not supported */ 175 case -EOPNOTSUPP: /* Sense Path Group ID not supported */
172 ccw_device_sense_pgid_done(cdev, -EOPNOTSUPP); 176 ccw_device_sense_pgid_done(cdev, -EOPNOTSUPP);
173 break; 177 break;
@@ -176,13 +180,15 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
176 break; 180 break;
177 case -EACCES: /* channel is not operational. */ 181 case -EACCES: /* channel is not operational. */
178 sch->lpm &= ~cdev->private->imask; 182 sch->lpm &= ~cdev->private->imask;
183 /* Fall through. */
184 case 0: /* Sense Path Group ID successful. */
179 cdev->private->imask >>= 1; 185 cdev->private->imask >>= 1;
180 cdev->private->iretry = 5; 186 cdev->private->iretry = 5;
181 /* Fall through. */ 187 /* Fall through. */
182 case -EAGAIN: /* Try again. */ 188 case -EAGAIN: /* Try again. */
183 ret = __ccw_device_sense_pgid_start(cdev); 189 ret = __ccw_device_sense_pgid_start(cdev);
184 if (ret != 0 && ret != -EBUSY) 190 if (ret != 0 && ret != -EBUSY)
185 ccw_device_sense_pgid_done(cdev, -ENODEV); 191 ccw_device_sense_pgid_done(cdev, ret);
186 break; 192 break;
187 case -EUSERS: /* device is reserved for someone else. */ 193 case -EUSERS: /* device is reserved for someone else. */
188 ccw_device_sense_pgid_done(cdev, -EUSERS); 194 ccw_device_sense_pgid_done(cdev, -EUSERS);
@@ -203,20 +209,20 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
203 sch = to_subchannel(cdev->dev.parent); 209 sch = to_subchannel(cdev->dev.parent);
204 210
205 /* Setup sense path group id channel program. */ 211 /* Setup sense path group id channel program. */
206 cdev->private->pgid.inf.fc = func; 212 cdev->private->pgid[0].inf.fc = func;
207 ccw = cdev->private->iccws; 213 ccw = cdev->private->iccws;
208 if (!cdev->private->flags.pgid_single) { 214 if (!cdev->private->flags.pgid_single) {
209 cdev->private->pgid.inf.fc |= SPID_FUNC_MULTI_PATH; 215 cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH;
210 ccw->cmd_code = CCW_CMD_SUSPEND_RECONN; 216 ccw->cmd_code = CCW_CMD_SUSPEND_RECONN;
211 ccw->cda = 0; 217 ccw->cda = 0;
212 ccw->count = 0; 218 ccw->count = 0;
213 ccw->flags = CCW_FLAG_SLI | CCW_FLAG_CC; 219 ccw->flags = CCW_FLAG_SLI | CCW_FLAG_CC;
214 ccw++; 220 ccw++;
215 } else 221 } else
216 cdev->private->pgid.inf.fc |= SPID_FUNC_SINGLE_PATH; 222 cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH;
217 223
218 ccw->cmd_code = CCW_CMD_SET_PGID; 224 ccw->cmd_code = CCW_CMD_SET_PGID;
219 ccw->cda = (__u32) __pa (&cdev->private->pgid); 225 ccw->cda = (__u32) __pa (&cdev->private->pgid[0]);
220 ccw->count = sizeof (struct pgid); 226 ccw->count = sizeof (struct pgid);
221 ccw->flags = CCW_FLAG_SLI; 227 ccw->flags = CCW_FLAG_SLI;
222 228
@@ -244,6 +250,48 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
244} 250}
245 251
246/* 252/*
253 * Helper function to send a nop ccw down a path.
254 */
255static int __ccw_device_do_nop(struct ccw_device *cdev)
256{
257 struct subchannel *sch;
258 struct ccw1 *ccw;
259 int ret;
260
261 sch = to_subchannel(cdev->dev.parent);
262
263 /* Setup nop channel program. */
264 ccw = cdev->private->iccws;
265 ccw->cmd_code = CCW_CMD_NOOP;
266 ccw->cda = 0;
267 ccw->count = 0;
268 ccw->flags = CCW_FLAG_SLI;
269
270 /* Reset device status. */
271 memset(&cdev->private->irb, 0, sizeof(struct irb));
272
273 /* Try multiple times. */
274 ret = -ENODEV;
275 if (cdev->private->iretry > 0) {
276 cdev->private->iretry--;
277 ret = cio_start (sch, cdev->private->iccws,
278 cdev->private->imask);
279 /* ret is 0, -EBUSY, -EACCES or -ENODEV */
280 if ((ret != -EACCES) && (ret != -ENODEV))
281 return ret;
282 }
283 /* nop command failed on this path. Switch it off. */
284 sch->lpm &= ~cdev->private->imask;
285 sch->vpm &= ~cdev->private->imask;
286 CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel "
287 "0.%x.%04x, lpm %02X, became 'not operational'\n",
288 cdev->private->devno, sch->schid.ssid,
289 sch->schid.sch_no, cdev->private->imask);
290 return ret;
291}
292
293
294/*
247 * Called from interrupt context to check if a valid answer 295 * Called from interrupt context to check if a valid answer
248 * to Set Path Group ID was received. 296 * to Set Path Group ID was received.
249 */ 297 */
@@ -282,6 +330,29 @@ __ccw_device_check_pgid(struct ccw_device *cdev)
282 return 0; 330 return 0;
283} 331}
284 332
333/*
334 * Called from interrupt context to check the path status after a nop has
335 * been send.
336 */
337static int __ccw_device_check_nop(struct ccw_device *cdev)
338{
339 struct subchannel *sch;
340 struct irb *irb;
341
342 sch = to_subchannel(cdev->dev.parent);
343 irb = &cdev->private->irb;
344 if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC))
345 return -ETIME;
346 if (irb->scsw.cc == 3) {
347 CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x,"
348 " lpm %02X, became 'not operational'\n",
349 cdev->private->devno, sch->schid.ssid,
350 sch->schid.sch_no, cdev->private->imask);
351 return -EACCES;
352 }
353 return 0;
354}
355
285static void 356static void
286__ccw_device_verify_start(struct ccw_device *cdev) 357__ccw_device_verify_start(struct ccw_device *cdev)
287{ 358{
@@ -296,9 +367,12 @@ __ccw_device_verify_start(struct ccw_device *cdev)
296 if ((sch->vpm & imask) != (sch->lpm & imask)) 367 if ((sch->vpm & imask) != (sch->lpm & imask))
297 break; 368 break;
298 cdev->private->imask = imask; 369 cdev->private->imask = imask;
299 func = (sch->vpm & imask) ? 370 if (cdev->private->options.pgroup) {
300 SPID_FUNC_RESIGN : SPID_FUNC_ESTABLISH; 371 func = (sch->vpm & imask) ?
301 ret = __ccw_device_do_pgid(cdev, func); 372 SPID_FUNC_RESIGN : SPID_FUNC_ESTABLISH;
373 ret = __ccw_device_do_pgid(cdev, func);
374 } else
375 ret = __ccw_device_do_nop(cdev);
302 if (ret == 0 || ret == -EBUSY) 376 if (ret == 0 || ret == -EBUSY)
303 return; 377 return;
304 cdev->private->iretry = 5; 378 cdev->private->iretry = 5;
@@ -327,7 +401,10 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
327 if (ccw_device_accumulate_and_sense(cdev, irb) != 0) 401 if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
328 return; 402 return;
329 sch = to_subchannel(cdev->dev.parent); 403 sch = to_subchannel(cdev->dev.parent);
330 ret = __ccw_device_check_pgid(cdev); 404 if (cdev->private->options.pgroup)
405 ret = __ccw_device_check_pgid(cdev);
406 else
407 ret = __ccw_device_check_nop(cdev);
331 memset(&cdev->private->irb, 0, sizeof(struct irb)); 408 memset(&cdev->private->irb, 0, sizeof(struct irb));
332 switch (ret) { 409 switch (ret) {
333 /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */ 410 /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
@@ -345,11 +422,10 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
345 * One of those strange devices which claim to be able 422 * One of those strange devices which claim to be able
346 * to do multipathing but not for Set Path Group ID. 423 * to do multipathing but not for Set Path Group ID.
347 */ 424 */
348 if (cdev->private->flags.pgid_single) { 425 if (cdev->private->flags.pgid_single)
349 ccw_device_verify_done(cdev, -EOPNOTSUPP); 426 cdev->private->options.pgroup = 0;
350 break; 427 else
351 } 428 cdev->private->flags.pgid_single = 1;
352 cdev->private->flags.pgid_single = 1;
353 /* fall through. */ 429 /* fall through. */
354 case -EAGAIN: /* Try again. */ 430 case -EAGAIN: /* Try again. */
355 __ccw_device_verify_start(cdev); 431 __ccw_device_verify_start(cdev);
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index 14bef2c179bf..caf148d5caad 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -67,8 +67,7 @@ ccw_device_path_notoper(struct ccw_device *cdev)
67 sch->schib.pmcw.pnom); 67 sch->schib.pmcw.pnom);
68 68
69 sch->lpm &= ~sch->schib.pmcw.pnom; 69 sch->lpm &= ~sch->schib.pmcw.pnom;
70 if (cdev->private->options.pgroup) 70 cdev->private->flags.doverify = 1;
71 cdev->private->flags.doverify = 1;
72} 71}
73 72
74/* 73/*
@@ -180,7 +179,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
180 cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth; 179 cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth;
181 /* Copy path verification required flag. */ 180 /* Copy path verification required flag. */
182 cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf; 181 cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf;
183 if (irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup) 182 if (irb->esw.esw0.erw.pvrf)
184 cdev->private->flags.doverify = 1; 183 cdev->private->flags.doverify = 1;
185 /* Copy concurrent sense bit. */ 184 /* Copy concurrent sense bit. */
186 cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons; 185 cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons;
@@ -354,7 +353,7 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb)
354 } 353 }
355 /* Check if path verification is required. */ 354 /* Check if path verification is required. */
356 if (ccw_device_accumulate_esw_valid(irb) && 355 if (ccw_device_accumulate_esw_valid(irb) &&
357 irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup) 356 irb->esw.esw0.erw.pvrf)
358 cdev->private->flags.doverify = 1; 357 cdev->private->flags.doverify = 1;
359} 358}
360 359
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index ffb3677e354f..5399c5d99b81 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -111,6 +111,16 @@ repeat:
111 break; 111 break;
112 case CRW_RSC_CPATH: 112 case CRW_RSC_CPATH:
113 pr_debug("source is channel path %02X\n", crw[0].rsid); 113 pr_debug("source is channel path %02X\n", crw[0].rsid);
114 /*
115 * Check for solicited machine checks. These are
116 * created by reset channel path and need not be
117 * reported to the common I/O layer.
118 */
119 if (crw[chain].slct) {
120 DBG(KERN_INFO"solicited machine check for "
121 "channel path %02X\n", crw[0].rsid);
122 break;
123 }
114 switch (crw[0].erc) { 124 switch (crw[0].erc) {
115 case CRW_ERC_IPARM: /* Path has come. */ 125 case CRW_ERC_IPARM: /* Path has come. */
116 ret = chp_process_crw(crw[0].rsid, 1); 126 ret = chp_process_crw(crw[0].rsid, 1);
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
index 2b1619306351..28fdd6e2b8ba 100644
--- a/include/asm-s390/cio.h
+++ b/include/asm-s390/cio.h
@@ -276,6 +276,8 @@ extern void wait_cons_dev(void);
276 276
277extern void clear_all_subchannels(void); 277extern void clear_all_subchannels(void);
278 278
279extern void cio_reset_channel_paths(void);
280
279extern void css_schedule_reprobe(void); 281extern void css_schedule_reprobe(void);
280 282
281#endif 283#endif