aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
diff options
context:
space:
mode:
authorMichael Ernst <mernst@de.ibm.com>2010-08-09 12:12:50 -0400
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-08-09 12:12:53 -0400
commitfd0457a6ae52141718a15652fb80d867e1bf1d10 (patch)
tree5bbc54259c2ddfbf96a2be728e8d971fdb7f2039 /drivers/s390/cio
parent45d7f32c7a43cbb9592886d38190e379e2eb2226 (diff)
[S390] cio: CHSC SIOSL Support
A Linux interface for the CHSC command store-I/O-operation-status-and-initiate-logging (SIOSL). Model-dependent logging within the channel subsystem can be invoked via a helper function or a writable subchannel device attribute. Signed-off-by: Michael Ernst <mernst@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/chsc.c48
-rw-r--r--drivers/s390/cio/chsc.h2
-rw-r--r--drivers/s390/cio/device.c37
3 files changed, 87 insertions, 0 deletions
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..75acec3b2d6b 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);
@@ -598,6 +599,25 @@ available_show (struct device *dev, struct device_attribute *attr, char *buf)
598 } 599 }
599} 600}
600 601
602static ssize_t
603initiate_logging(struct device *dev, struct device_attribute *attr,
604 const char *buf, size_t count)
605{
606 struct subchannel *sch = to_subchannel(dev);
607 int rc;
608
609 rc = chsc_siosl(sch->schid);
610 if (rc < 0) {
611 pr_warning("Logging for subchannel 0.%x.%04x failed with "
612 "errno=%d\n",
613 sch->schid.ssid, sch->schid.sch_no, rc);
614 return rc;
615 }
616 pr_notice("Logging for subchannel 0.%x.%04x was triggered\n",
617 sch->schid.ssid, sch->schid.sch_no);
618 return count;
619}
620
601static DEVICE_ATTR(chpids, 0444, chpids_show, NULL); 621static DEVICE_ATTR(chpids, 0444, chpids_show, NULL);
602static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL); 622static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL);
603static DEVICE_ATTR(devtype, 0444, devtype_show, NULL); 623static DEVICE_ATTR(devtype, 0444, devtype_show, NULL);
@@ -605,10 +625,12 @@ static DEVICE_ATTR(cutype, 0444, cutype_show, NULL);
605static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); 625static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
606static DEVICE_ATTR(online, 0644, online_show, online_store); 626static DEVICE_ATTR(online, 0644, online_show, online_store);
607static DEVICE_ATTR(availability, 0444, available_show, NULL); 627static DEVICE_ATTR(availability, 0444, available_show, NULL);
628static DEVICE_ATTR(logging, 0200, NULL, initiate_logging);
608 629
609static struct attribute *io_subchannel_attrs[] = { 630static struct attribute *io_subchannel_attrs[] = {
610 &dev_attr_chpids.attr, 631 &dev_attr_chpids.attr,
611 &dev_attr_pimpampom.attr, 632 &dev_attr_pimpampom.attr,
633 &dev_attr_logging.attr,
612 NULL, 634 NULL,
613}; 635};
614 636
@@ -2036,6 +2058,21 @@ void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo)
2036 } 2058 }
2037} 2059}
2038 2060
2061/**
2062 * ccw_device_siosl() - initiate logging
2063 * @cdev: ccw device
2064 *
2065 * This function is used to invoke model-dependent logging within the channel
2066 * subsystem.
2067 */
2068int ccw_device_siosl(struct ccw_device *cdev)
2069{
2070 struct subchannel *sch = to_subchannel(cdev->dev.parent);
2071
2072 return chsc_siosl(sch->schid);
2073}
2074EXPORT_SYMBOL_GPL(ccw_device_siosl);
2075
2039MODULE_LICENSE("GPL"); 2076MODULE_LICENSE("GPL");
2040EXPORT_SYMBOL(ccw_device_set_online); 2077EXPORT_SYMBOL(ccw_device_set_online);
2041EXPORT_SYMBOL(ccw_device_set_offline); 2078EXPORT_SYMBOL(ccw_device_set_offline);