aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/ccwreq.c16
-rw-r--r--drivers/s390/cio/chsc.c48
-rw-r--r--drivers/s390/cio/chsc.h2
-rw-r--r--drivers/s390/cio/device.c47
-rw-r--r--drivers/s390/cio/device_pgid.c3
-rw-r--r--drivers/s390/cio/io_sch.h10
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 47out:
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
31static void *sei_page; 31static void *sei_page;
32static DEFINE_SPINLOCK(siosl_lock);
32static DEFINE_SPINLOCK(sda_lock); 33static 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
979static 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
988int 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);
1019out:
1020 spin_unlock_irqrestore(&siosl_lock, flags);
1021
1022 return rc;
1023}
1024EXPORT_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
81int chsc_error_from_response(int response); 81int chsc_error_from_response(int response);
82 82
83int 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
40static struct timer_list recovery_timer; 41static struct timer_list recovery_timer;
41static DEFINE_SPINLOCK(recovery_lock); 42static 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
494static int online_store_recog_and_online(struct ccw_device *cdev) 497static 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
512static int online_store_handle_online(struct ccw_device *cdev, int force) 515static 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
604static ssize_t
605initiate_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
601static DEVICE_ATTR(chpids, 0444, chpids_show, NULL); 623static DEVICE_ATTR(chpids, 0444, chpids_show, NULL);
602static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL); 624static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL);
603static DEVICE_ATTR(devtype, 0444, devtype_show, NULL); 625static DEVICE_ATTR(devtype, 0444, devtype_show, NULL);
@@ -605,10 +627,12 @@ static DEVICE_ATTR(cutype, 0444, cutype_show, NULL);
605static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); 627static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
606static DEVICE_ATTR(online, 0644, online_show, online_store); 628static DEVICE_ATTR(online, 0644, online_show, online_store);
607static DEVICE_ATTR(availability, 0444, available_show, NULL); 629static DEVICE_ATTR(availability, 0444, available_show, NULL);
630static DEVICE_ATTR(logging, 0200, NULL, initiate_logging);
608 631
609static struct attribute *io_subchannel_attrs[] = { 632static 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 */
2070int 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}
2076EXPORT_SYMBOL_GPL(ccw_device_siosl);
2077
2039MODULE_LICENSE("GPL"); 2078MODULE_LICENSE("GPL");
2040EXPORT_SYMBOL(ccw_device_set_online); 2079EXPORT_SYMBOL(ccw_device_set_online);
2041EXPORT_SYMBOL(ccw_device_set_offline); 2080EXPORT_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 */
101struct ccw_request { 102struct 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/*