diff options
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/ccwreq.c | 16 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 48 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 47 | ||||
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 3 | ||||
-rw-r--r-- | drivers/s390/cio/io_sch.h | 10 |
6 files changed, 115 insertions, 11 deletions
diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c index 7f206ed44fdf..d15f8b4d78bd 100644 --- a/drivers/s390/cio/ccwreq.c +++ b/drivers/s390/cio/ccwreq.c | |||
@@ -38,9 +38,13 @@ static u16 ccwreq_next_path(struct ccw_device *cdev) | |||
38 | { | 38 | { |
39 | struct ccw_request *req = &cdev->private->req; | 39 | struct ccw_request *req = &cdev->private->req; |
40 | 40 | ||
41 | if (!req->singlepath) { | ||
42 | req->mask = 0; | ||
43 | goto out; | ||
44 | } | ||
41 | req->retries = req->maxretries; | 45 | req->retries = req->maxretries; |
42 | req->mask = lpm_adjust(req->mask >>= 1, req->lpm); | 46 | req->mask = lpm_adjust(req->mask >>= 1, req->lpm); |
43 | 47 | out: | |
44 | return req->mask; | 48 | return req->mask; |
45 | } | 49 | } |
46 | 50 | ||
@@ -113,8 +117,12 @@ void ccw_request_start(struct ccw_device *cdev) | |||
113 | { | 117 | { |
114 | struct ccw_request *req = &cdev->private->req; | 118 | struct ccw_request *req = &cdev->private->req; |
115 | 119 | ||
116 | /* Try all paths twice to counter link flapping. */ | 120 | if (req->singlepath) { |
117 | req->mask = 0x8080; | 121 | /* Try all paths twice to counter link flapping. */ |
122 | req->mask = 0x8080; | ||
123 | } else | ||
124 | req->mask = req->lpm; | ||
125 | |||
118 | req->retries = req->maxretries; | 126 | req->retries = req->maxretries; |
119 | req->mask = lpm_adjust(req->mask, req->lpm); | 127 | req->mask = lpm_adjust(req->mask, req->lpm); |
120 | req->drc = 0; | 128 | req->drc = 0; |
@@ -182,6 +190,8 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) | |||
182 | /* Ask the driver what to do */ | 190 | /* Ask the driver what to do */ |
183 | if (cdev->drv && cdev->drv->uc_handler) { | 191 | if (cdev->drv && cdev->drv->uc_handler) { |
184 | todo = cdev->drv->uc_handler(cdev, lcirb); | 192 | todo = cdev->drv->uc_handler(cdev, lcirb); |
193 | CIO_TRACE_EVENT(2, "uc_response"); | ||
194 | CIO_HEX_EVENT(2, &todo, sizeof(todo)); | ||
185 | switch (todo) { | 195 | switch (todo) { |
186 | case UC_TODO_RETRY: | 196 | case UC_TODO_RETRY: |
187 | return IO_STATUS_ERROR; | 197 | return IO_STATUS_ERROR; |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 407d0e9adfaf..4cbb1a6ca33c 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "chsc.h" | 29 | #include "chsc.h" |
30 | 30 | ||
31 | static void *sei_page; | 31 | static void *sei_page; |
32 | static DEFINE_SPINLOCK(siosl_lock); | ||
32 | static DEFINE_SPINLOCK(sda_lock); | 33 | static DEFINE_SPINLOCK(sda_lock); |
33 | 34 | ||
34 | /** | 35 | /** |
@@ -48,6 +49,7 @@ int chsc_error_from_response(int response) | |||
48 | case 0x0007: | 49 | case 0x0007: |
49 | case 0x0008: | 50 | case 0x0008: |
50 | case 0x000a: | 51 | case 0x000a: |
52 | case 0x0104: | ||
51 | return -EINVAL; | 53 | return -EINVAL; |
52 | case 0x0004: | 54 | case 0x0004: |
53 | return -EOPNOTSUPP; | 55 | return -EOPNOTSUPP; |
@@ -974,3 +976,49 @@ int chsc_sstpi(void *page, void *result, size_t size) | |||
974 | return (rr->response.code == 0x0001) ? 0 : -EIO; | 976 | return (rr->response.code == 0x0001) ? 0 : -EIO; |
975 | } | 977 | } |
976 | 978 | ||
979 | static struct { | ||
980 | struct chsc_header request; | ||
981 | u32 word1; | ||
982 | struct subchannel_id sid; | ||
983 | u32 word3; | ||
984 | struct chsc_header response; | ||
985 | u32 word[11]; | ||
986 | } __attribute__ ((packed)) siosl_area __attribute__ ((__aligned__(PAGE_SIZE))); | ||
987 | |||
988 | int chsc_siosl(struct subchannel_id schid) | ||
989 | { | ||
990 | unsigned long flags; | ||
991 | int ccode; | ||
992 | int rc; | ||
993 | |||
994 | spin_lock_irqsave(&siosl_lock, flags); | ||
995 | memset(&siosl_area, 0, sizeof(siosl_area)); | ||
996 | siosl_area.request.length = 0x0010; | ||
997 | siosl_area.request.code = 0x0046; | ||
998 | siosl_area.word1 = 0x80000000; | ||
999 | siosl_area.sid = schid; | ||
1000 | |||
1001 | ccode = chsc(&siosl_area); | ||
1002 | if (ccode > 0) { | ||
1003 | if (ccode == 3) | ||
1004 | rc = -ENODEV; | ||
1005 | else | ||
1006 | rc = -EBUSY; | ||
1007 | CIO_MSG_EVENT(2, "chsc: chsc failed for 0.%x.%04x (ccode=%d)\n", | ||
1008 | schid.ssid, schid.sch_no, ccode); | ||
1009 | goto out; | ||
1010 | } | ||
1011 | rc = chsc_error_from_response(siosl_area.response.code); | ||
1012 | if (rc) | ||
1013 | CIO_MSG_EVENT(2, "chsc: siosl failed for 0.%x.%04x (rc=%04x)\n", | ||
1014 | schid.ssid, schid.sch_no, | ||
1015 | siosl_area.response.code); | ||
1016 | else | ||
1017 | CIO_MSG_EVENT(4, "chsc: siosl succeeded for 0.%x.%04x\n", | ||
1018 | schid.ssid, schid.sch_no); | ||
1019 | out: | ||
1020 | spin_unlock_irqrestore(&siosl_lock, flags); | ||
1021 | |||
1022 | return rc; | ||
1023 | } | ||
1024 | EXPORT_SYMBOL_GPL(chsc_siosl); | ||
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 37aa611d4ac5..5453013f094b 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -80,4 +80,6 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp); | |||
80 | 80 | ||
81 | int chsc_error_from_response(int response); | 81 | int chsc_error_from_response(int response); |
82 | 82 | ||
83 | int chsc_siosl(struct subchannel_id schid); | ||
84 | |||
83 | #endif | 85 | #endif |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 6d229f3523a0..51bd3687d163 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "ioasm.h" | 36 | #include "ioasm.h" |
37 | #include "io_sch.h" | 37 | #include "io_sch.h" |
38 | #include "blacklist.h" | 38 | #include "blacklist.h" |
39 | #include "chsc.h" | ||
39 | 40 | ||
40 | static struct timer_list recovery_timer; | 41 | static struct timer_list recovery_timer; |
41 | static DEFINE_SPINLOCK(recovery_lock); | 42 | static DEFINE_SPINLOCK(recovery_lock); |
@@ -486,9 +487,11 @@ static int online_store_handle_offline(struct ccw_device *cdev) | |||
486 | spin_lock_irq(cdev->ccwlock); | 487 | spin_lock_irq(cdev->ccwlock); |
487 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL); | 488 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL); |
488 | spin_unlock_irq(cdev->ccwlock); | 489 | spin_unlock_irq(cdev->ccwlock); |
489 | } else if (cdev->online && cdev->drv && cdev->drv->set_offline) | 490 | return 0; |
491 | } | ||
492 | if (cdev->drv && cdev->drv->set_offline) | ||
490 | return ccw_device_set_offline(cdev); | 493 | return ccw_device_set_offline(cdev); |
491 | return 0; | 494 | return -EINVAL; |
492 | } | 495 | } |
493 | 496 | ||
494 | static int online_store_recog_and_online(struct ccw_device *cdev) | 497 | static int online_store_recog_and_online(struct ccw_device *cdev) |
@@ -505,8 +508,8 @@ static int online_store_recog_and_online(struct ccw_device *cdev) | |||
505 | return -EAGAIN; | 508 | return -EAGAIN; |
506 | } | 509 | } |
507 | if (cdev->drv && cdev->drv->set_online) | 510 | if (cdev->drv && cdev->drv->set_online) |
508 | ccw_device_set_online(cdev); | 511 | return ccw_device_set_online(cdev); |
509 | return 0; | 512 | return -EINVAL; |
510 | } | 513 | } |
511 | 514 | ||
512 | static int online_store_handle_online(struct ccw_device *cdev, int force) | 515 | static int online_store_handle_online(struct ccw_device *cdev, int force) |
@@ -598,6 +601,25 @@ available_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
598 | } | 601 | } |
599 | } | 602 | } |
600 | 603 | ||
604 | static ssize_t | ||
605 | initiate_logging(struct device *dev, struct device_attribute *attr, | ||
606 | const char *buf, size_t count) | ||
607 | { | ||
608 | struct subchannel *sch = to_subchannel(dev); | ||
609 | int rc; | ||
610 | |||
611 | rc = chsc_siosl(sch->schid); | ||
612 | if (rc < 0) { | ||
613 | pr_warning("Logging for subchannel 0.%x.%04x failed with " | ||
614 | "errno=%d\n", | ||
615 | sch->schid.ssid, sch->schid.sch_no, rc); | ||
616 | return rc; | ||
617 | } | ||
618 | pr_notice("Logging for subchannel 0.%x.%04x was triggered\n", | ||
619 | sch->schid.ssid, sch->schid.sch_no); | ||
620 | return count; | ||
621 | } | ||
622 | |||
601 | static DEVICE_ATTR(chpids, 0444, chpids_show, NULL); | 623 | static DEVICE_ATTR(chpids, 0444, chpids_show, NULL); |
602 | static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL); | 624 | static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL); |
603 | static DEVICE_ATTR(devtype, 0444, devtype_show, NULL); | 625 | static DEVICE_ATTR(devtype, 0444, devtype_show, NULL); |
@@ -605,10 +627,12 @@ static DEVICE_ATTR(cutype, 0444, cutype_show, NULL); | |||
605 | static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); | 627 | static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); |
606 | static DEVICE_ATTR(online, 0644, online_show, online_store); | 628 | static DEVICE_ATTR(online, 0644, online_show, online_store); |
607 | static DEVICE_ATTR(availability, 0444, available_show, NULL); | 629 | static DEVICE_ATTR(availability, 0444, available_show, NULL); |
630 | static DEVICE_ATTR(logging, 0200, NULL, initiate_logging); | ||
608 | 631 | ||
609 | static struct attribute *io_subchannel_attrs[] = { | 632 | static struct attribute *io_subchannel_attrs[] = { |
610 | &dev_attr_chpids.attr, | 633 | &dev_attr_chpids.attr, |
611 | &dev_attr_pimpampom.attr, | 634 | &dev_attr_pimpampom.attr, |
635 | &dev_attr_logging.attr, | ||
612 | NULL, | 636 | NULL, |
613 | }; | 637 | }; |
614 | 638 | ||
@@ -2036,6 +2060,21 @@ void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo) | |||
2036 | } | 2060 | } |
2037 | } | 2061 | } |
2038 | 2062 | ||
2063 | /** | ||
2064 | * ccw_device_siosl() - initiate logging | ||
2065 | * @cdev: ccw device | ||
2066 | * | ||
2067 | * This function is used to invoke model-dependent logging within the channel | ||
2068 | * subsystem. | ||
2069 | */ | ||
2070 | int ccw_device_siosl(struct ccw_device *cdev) | ||
2071 | { | ||
2072 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
2073 | |||
2074 | return chsc_siosl(sch->schid); | ||
2075 | } | ||
2076 | EXPORT_SYMBOL_GPL(ccw_device_siosl); | ||
2077 | |||
2039 | MODULE_LICENSE("GPL"); | 2078 | MODULE_LICENSE("GPL"); |
2040 | EXPORT_SYMBOL(ccw_device_set_online); | 2079 | EXPORT_SYMBOL(ccw_device_set_online); |
2041 | EXPORT_SYMBOL(ccw_device_set_offline); | 2080 | EXPORT_SYMBOL(ccw_device_set_offline); |
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 6facb5499a65..82a5ad0d63f6 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -208,6 +208,7 @@ static void spid_start(struct ccw_device *cdev) | |||
208 | req->timeout = PGID_TIMEOUT; | 208 | req->timeout = PGID_TIMEOUT; |
209 | req->maxretries = PGID_RETRIES; | 209 | req->maxretries = PGID_RETRIES; |
210 | req->lpm = 0x80; | 210 | req->lpm = 0x80; |
211 | req->singlepath = 1; | ||
211 | req->callback = spid_callback; | 212 | req->callback = spid_callback; |
212 | spid_do(cdev); | 213 | spid_do(cdev); |
213 | } | 214 | } |
@@ -420,6 +421,7 @@ static void verify_start(struct ccw_device *cdev) | |||
420 | req->timeout = PGID_TIMEOUT; | 421 | req->timeout = PGID_TIMEOUT; |
421 | req->maxretries = PGID_RETRIES; | 422 | req->maxretries = PGID_RETRIES; |
422 | req->lpm = 0x80; | 423 | req->lpm = 0x80; |
424 | req->singlepath = 1; | ||
423 | if (cdev->private->flags.pgroup) { | 425 | if (cdev->private->flags.pgroup) { |
424 | CIO_TRACE_EVENT(4, "snid"); | 426 | CIO_TRACE_EVENT(4, "snid"); |
425 | CIO_HEX_EVENT(4, devid, sizeof(*devid)); | 427 | CIO_HEX_EVENT(4, devid, sizeof(*devid)); |
@@ -507,6 +509,7 @@ void ccw_device_disband_start(struct ccw_device *cdev) | |||
507 | req->timeout = PGID_TIMEOUT; | 509 | req->timeout = PGID_TIMEOUT; |
508 | req->maxretries = PGID_RETRIES; | 510 | req->maxretries = PGID_RETRIES; |
509 | req->lpm = sch->schib.pmcw.pam & sch->opm; | 511 | req->lpm = sch->schib.pmcw.pam & sch->opm; |
512 | req->singlepath = 1; | ||
510 | req->callback = disband_callback; | 513 | req->callback = disband_callback; |
511 | fn = SPID_FUNC_DISBAND; | 514 | fn = SPID_FUNC_DISBAND; |
512 | if (cdev->private->flags.mpath) | 515 | if (cdev->private->flags.mpath) |
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index b9ce712a7f25..469ef93f2302 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h | |||
@@ -92,11 +92,12 @@ enum io_status { | |||
92 | * @filter: optional callback to adjust request status based on IRB data | 92 | * @filter: optional callback to adjust request status based on IRB data |
93 | * @callback: final callback | 93 | * @callback: final callback |
94 | * @data: user-defined pointer passed to all callbacks | 94 | * @data: user-defined pointer passed to all callbacks |
95 | * @singlepath: if set, use only one path from @lpm per start I/O | ||
96 | * @cancel: non-zero if request was cancelled | ||
97 | * @done: non-zero if request was finished | ||
95 | * @mask: current path mask | 98 | * @mask: current path mask |
96 | * @retries: current number of retries | 99 | * @retries: current number of retries |
97 | * @drc: delayed return code | 100 | * @drc: delayed return code |
98 | * @cancel: non-zero if request was cancelled | ||
99 | * @done: non-zero if request was finished | ||
100 | */ | 101 | */ |
101 | struct ccw_request { | 102 | struct ccw_request { |
102 | struct ccw1 *cp; | 103 | struct ccw1 *cp; |
@@ -108,12 +109,13 @@ struct ccw_request { | |||
108 | enum io_status); | 109 | enum io_status); |
109 | void (*callback)(struct ccw_device *, void *, int); | 110 | void (*callback)(struct ccw_device *, void *, int); |
110 | void *data; | 111 | void *data; |
112 | unsigned int singlepath:1; | ||
111 | /* These fields are used internally. */ | 113 | /* These fields are used internally. */ |
114 | unsigned int cancel:1; | ||
115 | unsigned int done:1; | ||
112 | u16 mask; | 116 | u16 mask; |
113 | u16 retries; | 117 | u16 retries; |
114 | int drc; | 118 | int drc; |
115 | int cancel:1; | ||
116 | int done:1; | ||
117 | } __attribute__((packed)); | 119 | } __attribute__((packed)); |
118 | 120 | ||
119 | /* | 121 | /* |