diff options
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 34 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/cio.h | 3 | ||||
-rw-r--r-- | drivers/s390/cio/cmf.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 36 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 4 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 14 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 85 | ||||
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 122 | ||||
-rw-r--r-- | drivers/s390/cio/device_status.c | 7 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.c | 2 |
12 files changed, 253 insertions, 64 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index c7319a07ba35..f26a2ee3aad8 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -319,7 +319,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const | |||
319 | if (!try_module_get(gdrv->owner)) | 319 | if (!try_module_get(gdrv->owner)) |
320 | return -EINVAL; | 320 | return -EINVAL; |
321 | 321 | ||
322 | value = simple_strtoul(buf, 0, 0); | 322 | value = simple_strtoul(buf, NULL, 0); |
323 | ret = count; | 323 | ret = count; |
324 | if (value == 1) | 324 | if (value == 1) |
325 | ccwgroup_set_online(gdev); | 325 | ccwgroup_set_online(gdev); |
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 | ||
1467 | static 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 | |||
1482 | static 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 | |||
1492 | void 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 | ||
1468 | static int __init | 1502 | static int __init |
1469 | chsc_alloc_sei_area(void) | 1503 | chsc_alloc_sei_area(void) |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 6fec90eab00e..89320c1ad825 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -519,6 +519,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
519 | memset(sch, 0, sizeof(struct subchannel)); | 519 | memset(sch, 0, sizeof(struct subchannel)); |
520 | 520 | ||
521 | spin_lock_init(&sch->lock); | 521 | spin_lock_init(&sch->lock); |
522 | mutex_init(&sch->reg_mutex); | ||
522 | 523 | ||
523 | /* Set a name for the subchannel */ | 524 | /* Set a name for the subchannel */ |
524 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid, | 525 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid, |
@@ -797,7 +798,7 @@ struct subchannel * | |||
797 | cio_get_console_subchannel(void) | 798 | cio_get_console_subchannel(void) |
798 | { | 799 | { |
799 | if (!console_subchannel_in_use) | 800 | if (!console_subchannel_in_use) |
800 | return 0; | 801 | return NULL; |
801 | return &console_subchannel; | 802 | return &console_subchannel; |
802 | } | 803 | } |
803 | 804 | ||
@@ -875,5 +876,6 @@ void | |||
875 | reipl(unsigned long devno) | 876 | reipl(unsigned long devno) |
876 | { | 877 | { |
877 | clear_all_subchannels(); | 878 | clear_all_subchannels(); |
879 | cio_reset_channel_paths(); | ||
878 | do_reipl(devno); | 880 | do_reipl(devno); |
879 | } | 881 | } |
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 0ca987344e07..4541c1af4b66 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define S390_CIO_H | 2 | #define S390_CIO_H |
3 | 3 | ||
4 | #include "schid.h" | 4 | #include "schid.h" |
5 | #include <linux/mutex.h> | ||
5 | 6 | ||
6 | /* | 7 | /* |
7 | * where we put the ssd info | 8 | * where we put the ssd info |
@@ -87,7 +88,7 @@ struct orb { | |||
87 | struct subchannel { | 88 | struct subchannel { |
88 | struct subchannel_id schid; | 89 | struct subchannel_id schid; |
89 | spinlock_t lock; /* subchannel lock */ | 90 | spinlock_t lock; /* subchannel lock */ |
90 | 91 | struct mutex reg_mutex; | |
91 | enum { | 92 | enum { |
92 | SUBCHANNEL_TYPE_IO = 0, | 93 | SUBCHANNEL_TYPE_IO = 0, |
93 | SUBCHANNEL_TYPE_CHSC = 1, | 94 | SUBCHANNEL_TYPE_CHSC = 1, |
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 1c3e8e9012b0..0df3af1f08de 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c | |||
@@ -1140,7 +1140,7 @@ static struct attribute *cmf_attributes[] = { | |||
1140 | &dev_attr_avg_device_disconnect_time.attr, | 1140 | &dev_attr_avg_device_disconnect_time.attr, |
1141 | &dev_attr_avg_control_unit_queuing_time.attr, | 1141 | &dev_attr_avg_control_unit_queuing_time.attr, |
1142 | &dev_attr_avg_device_active_only_time.attr, | 1142 | &dev_attr_avg_device_active_only_time.attr, |
1143 | 0, | 1143 | NULL, |
1144 | }; | 1144 | }; |
1145 | 1145 | ||
1146 | static struct attribute_group cmf_attr_group = { | 1146 | static struct attribute_group cmf_attr_group = { |
@@ -1160,7 +1160,7 @@ static struct attribute *cmf_attributes_ext[] = { | |||
1160 | &dev_attr_avg_device_active_only_time.attr, | 1160 | &dev_attr_avg_device_active_only_time.attr, |
1161 | &dev_attr_avg_device_busy_time.attr, | 1161 | &dev_attr_avg_device_busy_time.attr, |
1162 | &dev_attr_avg_initial_command_response_time.attr, | 1162 | &dev_attr_avg_initial_command_response_time.attr, |
1163 | 0, | 1163 | NULL, |
1164 | }; | 1164 | }; |
1165 | 1165 | ||
1166 | static struct attribute_group cmf_attr_group_ext = { | 1166 | static struct attribute_group cmf_attr_group_ext = { |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 1d3be80797f8..13eeea3d547f 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -108,6 +108,24 @@ css_subchannel_release(struct device *dev) | |||
108 | 108 | ||
109 | extern int css_get_ssd_info(struct subchannel *sch); | 109 | extern int css_get_ssd_info(struct subchannel *sch); |
110 | 110 | ||
111 | |||
112 | int css_sch_device_register(struct subchannel *sch) | ||
113 | { | ||
114 | int ret; | ||
115 | |||
116 | mutex_lock(&sch->reg_mutex); | ||
117 | ret = device_register(&sch->dev); | ||
118 | mutex_unlock(&sch->reg_mutex); | ||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | void css_sch_device_unregister(struct subchannel *sch) | ||
123 | { | ||
124 | mutex_lock(&sch->reg_mutex); | ||
125 | device_unregister(&sch->dev); | ||
126 | mutex_unlock(&sch->reg_mutex); | ||
127 | } | ||
128 | |||
111 | static int | 129 | static int |
112 | css_register_subchannel(struct subchannel *sch) | 130 | css_register_subchannel(struct subchannel *sch) |
113 | { | 131 | { |
@@ -119,7 +137,7 @@ css_register_subchannel(struct subchannel *sch) | |||
119 | sch->dev.release = &css_subchannel_release; | 137 | sch->dev.release = &css_subchannel_release; |
120 | 138 | ||
121 | /* make it known to the system */ | 139 | /* make it known to the system */ |
122 | ret = device_register(&sch->dev); | 140 | ret = css_sch_device_register(sch); |
123 | if (ret) | 141 | if (ret) |
124 | printk (KERN_WARNING "%s: could not register %s\n", | 142 | printk (KERN_WARNING "%s: could not register %s\n", |
125 | __func__, sch->dev.bus_id); | 143 | __func__, sch->dev.bus_id); |
@@ -250,7 +268,7 @@ css_evaluate_subchannel(struct subchannel_id schid, int slow) | |||
250 | * The device will be killed automatically. | 268 | * The device will be killed automatically. |
251 | */ | 269 | */ |
252 | cio_disable_subchannel(sch); | 270 | cio_disable_subchannel(sch); |
253 | device_unregister(&sch->dev); | 271 | css_sch_device_unregister(sch); |
254 | /* Reset intparm to zeroes. */ | 272 | /* Reset intparm to zeroes. */ |
255 | sch->schib.pmcw.intparm = 0; | 273 | sch->schib.pmcw.intparm = 0; |
256 | cio_modify(sch); | 274 | cio_modify(sch); |
@@ -264,7 +282,7 @@ css_evaluate_subchannel(struct subchannel_id schid, int slow) | |||
264 | * away in any case. | 282 | * away in any case. |
265 | */ | 283 | */ |
266 | if (!disc) { | 284 | if (!disc) { |
267 | device_unregister(&sch->dev); | 285 | css_sch_device_unregister(sch); |
268 | /* Reset intparm to zeroes. */ | 286 | /* Reset intparm to zeroes. */ |
269 | sch->schib.pmcw.intparm = 0; | 287 | sch->schib.pmcw.intparm = 0; |
270 | cio_modify(sch); | 288 | cio_modify(sch); |
@@ -605,9 +623,13 @@ init_channel_subsystem (void) | |||
605 | ret = device_register(&css[i]->device); | 623 | ret = device_register(&css[i]->device); |
606 | if (ret) | 624 | if (ret) |
607 | goto out_free; | 625 | goto out_free; |
608 | if (css_characteristics_avail && css_chsc_characteristics.secm) | 626 | if (css_characteristics_avail && |
609 | device_create_file(&css[i]->device, | 627 | css_chsc_characteristics.secm) { |
610 | &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 | } | ||
611 | } | 633 | } |
612 | css_init_done = 1; | 634 | css_init_done = 1; |
613 | 635 | ||
@@ -615,6 +637,8 @@ init_channel_subsystem (void) | |||
615 | 637 | ||
616 | for_each_subchannel(__init_channel_subsystem, NULL); | 638 | for_each_subchannel(__init_channel_subsystem, NULL); |
617 | return 0; | 639 | return 0; |
640 | out_device: | ||
641 | device_unregister(&css[i]->device); | ||
618 | out_free: | 642 | out_free: |
619 | kfree(css[i]); | 643 | kfree(css[i]); |
620 | out_unregister: | 644 | out_unregister: |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index e210f89a2449..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; |
@@ -136,6 +136,8 @@ extern struct bus_type css_bus_type; | |||
136 | extern struct css_driver io_subchannel_driver; | 136 | extern struct css_driver io_subchannel_driver; |
137 | 137 | ||
138 | extern int css_probe_device(struct subchannel_id); | 138 | extern int css_probe_device(struct subchannel_id); |
139 | extern int css_sch_device_register(struct subchannel *); | ||
140 | extern void css_sch_device_unregister(struct subchannel *); | ||
139 | extern struct subchannel * get_subchannel_by_schid(struct subchannel_id); | 141 | extern struct subchannel * get_subchannel_by_schid(struct subchannel_id); |
140 | extern int css_init_done; | 142 | extern int css_init_done; |
141 | extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); | 143 | extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 67f0de6aed33..585fa04233c3 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -100,7 +100,7 @@ ccw_uevent (struct device *dev, char **envp, int num_envp, | |||
100 | if ((buffer_size - length <= 0) || (i >= num_envp)) | 100 | if ((buffer_size - length <= 0) || (i >= num_envp)) |
101 | return -ENOMEM; | 101 | return -ENOMEM; |
102 | 102 | ||
103 | envp[i] = 0; | 103 | envp[i] = NULL; |
104 | 104 | ||
105 | return 0; | 105 | return 0; |
106 | } | 106 | } |
@@ -280,7 +280,7 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) | |||
280 | * 'throw away device'. | 280 | * 'throw away device'. |
281 | */ | 281 | */ |
282 | sch = to_subchannel(cdev->dev.parent); | 282 | sch = to_subchannel(cdev->dev.parent); |
283 | device_unregister(&sch->dev); | 283 | css_sch_device_unregister(sch); |
284 | /* Reset intparm to zeroes. */ | 284 | /* Reset intparm to zeroes. */ |
285 | sch->schib.pmcw.intparm = 0; | 285 | sch->schib.pmcw.intparm = 0; |
286 | cio_modify(sch); | 286 | cio_modify(sch); |
@@ -625,7 +625,7 @@ ccw_device_do_unreg_rereg(void *data) | |||
625 | other_sch->schib.pmcw.intparm = 0; | 625 | other_sch->schib.pmcw.intparm = 0; |
626 | cio_modify(other_sch); | 626 | cio_modify(other_sch); |
627 | } | 627 | } |
628 | device_unregister(&other_sch->dev); | 628 | css_sch_device_unregister(other_sch); |
629 | } | 629 | } |
630 | } | 630 | } |
631 | /* Update ssd info here. */ | 631 | /* Update ssd info here. */ |
@@ -709,7 +709,7 @@ ccw_device_call_sch_unregister(void *data) | |||
709 | struct subchannel *sch; | 709 | struct subchannel *sch; |
710 | 710 | ||
711 | sch = to_subchannel(cdev->dev.parent); | 711 | sch = to_subchannel(cdev->dev.parent); |
712 | device_unregister(&sch->dev); | 712 | css_sch_device_unregister(sch); |
713 | /* Reset intparm to zeroes. */ | 713 | /* Reset intparm to zeroes. */ |
714 | sch->schib.pmcw.intparm = 0; | 714 | sch->schib.pmcw.intparm = 0; |
715 | cio_modify(sch); | 715 | cio_modify(sch); |
@@ -1057,7 +1057,7 @@ get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id) | |||
1057 | __ccwdev_check_busid); | 1057 | __ccwdev_check_busid); |
1058 | put_driver(drv); | 1058 | put_driver(drv); |
1059 | 1059 | ||
1060 | return dev ? to_ccwdev(dev) : 0; | 1060 | return dev ? to_ccwdev(dev) : NULL; |
1061 | } | 1061 | } |
1062 | 1062 | ||
1063 | /************************** device driver handling ************************/ | 1063 | /************************** device driver handling ************************/ |
@@ -1082,7 +1082,7 @@ ccw_device_probe (struct device *dev) | |||
1082 | ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; | 1082 | ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV; |
1083 | 1083 | ||
1084 | if (ret) { | 1084 | if (ret) { |
1085 | cdev->drv = 0; | 1085 | cdev->drv = NULL; |
1086 | return ret; | 1086 | return ret; |
1087 | } | 1087 | } |
1088 | 1088 | ||
@@ -1113,7 +1113,7 @@ ccw_device_remove (struct device *dev) | |||
1113 | ret, cdev->dev.bus_id); | 1113 | ret, cdev->dev.bus_id); |
1114 | } | 1114 | } |
1115 | ccw_device_set_timeout(cdev, 0); | 1115 | ccw_device_set_timeout(cdev, 0); |
1116 | cdev->drv = 0; | 1116 | cdev->drv = NULL; |
1117 | return 0; | 1117 | return 0; |
1118 | } | 1118 | } |
1119 | 1119 | ||
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 | ||
381 | static 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 | |||
392 | static 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 | |||
995 | ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event) | 1047 | ccw_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 | ||
1002 | static void | 1053 | static 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 | */ | ||
255 | static 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 | */ | ||
337 | static 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 | |||
285 | static void | 356 | static 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/cio/qdio.c b/drivers/s390/cio/qdio.c index b70039af70d6..7c93a8798d23 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
@@ -2735,7 +2735,7 @@ qdio_free(struct ccw_device *cdev) | |||
2735 | QDIO_DBF_TEXT1(0,trace,dbf_text); | 2735 | QDIO_DBF_TEXT1(0,trace,dbf_text); |
2736 | QDIO_DBF_TEXT0(0,setup,dbf_text); | 2736 | QDIO_DBF_TEXT0(0,setup,dbf_text); |
2737 | 2737 | ||
2738 | cdev->private->qdio_data = 0; | 2738 | cdev->private->qdio_data = NULL; |
2739 | 2739 | ||
2740 | up(&irq_ptr->setting_up_sema); | 2740 | up(&irq_ptr->setting_up_sema); |
2741 | 2741 | ||