[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>
This commit is contained in:
parent
45d7f32c7a
commit
fd0457a6ae
|
@ -208,6 +208,8 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
|
||||||
extern struct ccw_device *ccw_device_probe_console(void);
|
extern struct ccw_device *ccw_device_probe_console(void);
|
||||||
extern int ccw_device_force_console(void);
|
extern int ccw_device_force_console(void);
|
||||||
|
|
||||||
|
int ccw_device_siosl(struct ccw_device *);
|
||||||
|
|
||||||
// FIXME: these have to go
|
// FIXME: these have to go
|
||||||
extern int _ccw_device_get_subchannel_number(struct ccw_device *);
|
extern int _ccw_device_get_subchannel_number(struct ccw_device *);
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "chsc.h"
|
#include "chsc.h"
|
||||||
|
|
||||||
static void *sei_page;
|
static void *sei_page;
|
||||||
|
static DEFINE_SPINLOCK(siosl_lock);
|
||||||
static DEFINE_SPINLOCK(sda_lock);
|
static DEFINE_SPINLOCK(sda_lock);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,6 +49,7 @@ int chsc_error_from_response(int response)
|
||||||
case 0x0007:
|
case 0x0007:
|
||||||
case 0x0008:
|
case 0x0008:
|
||||||
case 0x000a:
|
case 0x000a:
|
||||||
|
case 0x0104:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
case 0x0004:
|
case 0x0004:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -974,3 +976,49 @@ int chsc_sstpi(void *page, void *result, size_t size)
|
||||||
return (rr->response.code == 0x0001) ? 0 : -EIO;
|
return (rr->response.code == 0x0001) ? 0 : -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct chsc_header request;
|
||||||
|
u32 word1;
|
||||||
|
struct subchannel_id sid;
|
||||||
|
u32 word3;
|
||||||
|
struct chsc_header response;
|
||||||
|
u32 word[11];
|
||||||
|
} __attribute__ ((packed)) siosl_area __attribute__ ((__aligned__(PAGE_SIZE)));
|
||||||
|
|
||||||
|
int chsc_siosl(struct subchannel_id schid)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int ccode;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&siosl_lock, flags);
|
||||||
|
memset(&siosl_area, 0, sizeof(siosl_area));
|
||||||
|
siosl_area.request.length = 0x0010;
|
||||||
|
siosl_area.request.code = 0x0046;
|
||||||
|
siosl_area.word1 = 0x80000000;
|
||||||
|
siosl_area.sid = schid;
|
||||||
|
|
||||||
|
ccode = chsc(&siosl_area);
|
||||||
|
if (ccode > 0) {
|
||||||
|
if (ccode == 3)
|
||||||
|
rc = -ENODEV;
|
||||||
|
else
|
||||||
|
rc = -EBUSY;
|
||||||
|
CIO_MSG_EVENT(2, "chsc: chsc failed for 0.%x.%04x (ccode=%d)\n",
|
||||||
|
schid.ssid, schid.sch_no, ccode);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc = chsc_error_from_response(siosl_area.response.code);
|
||||||
|
if (rc)
|
||||||
|
CIO_MSG_EVENT(2, "chsc: siosl failed for 0.%x.%04x (rc=%04x)\n",
|
||||||
|
schid.ssid, schid.sch_no,
|
||||||
|
siosl_area.response.code);
|
||||||
|
else
|
||||||
|
CIO_MSG_EVENT(4, "chsc: siosl succeeded for 0.%x.%04x\n",
|
||||||
|
schid.ssid, schid.sch_no);
|
||||||
|
out:
|
||||||
|
spin_unlock_irqrestore(&siosl_lock, flags);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(chsc_siosl);
|
||||||
|
|
|
@ -80,4 +80,6 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp);
|
||||||
|
|
||||||
int chsc_error_from_response(int response);
|
int chsc_error_from_response(int response);
|
||||||
|
|
||||||
|
int chsc_siosl(struct subchannel_id schid);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "ioasm.h"
|
#include "ioasm.h"
|
||||||
#include "io_sch.h"
|
#include "io_sch.h"
|
||||||
#include "blacklist.h"
|
#include "blacklist.h"
|
||||||
|
#include "chsc.h"
|
||||||
|
|
||||||
static struct timer_list recovery_timer;
|
static struct timer_list recovery_timer;
|
||||||
static DEFINE_SPINLOCK(recovery_lock);
|
static DEFINE_SPINLOCK(recovery_lock);
|
||||||
|
@ -598,6 +599,25 @@ available_show (struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
initiate_logging(struct device *dev, struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct subchannel *sch = to_subchannel(dev);
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = chsc_siosl(sch->schid);
|
||||||
|
if (rc < 0) {
|
||||||
|
pr_warning("Logging for subchannel 0.%x.%04x failed with "
|
||||||
|
"errno=%d\n",
|
||||||
|
sch->schid.ssid, sch->schid.sch_no, rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
pr_notice("Logging for subchannel 0.%x.%04x was triggered\n",
|
||||||
|
sch->schid.ssid, sch->schid.sch_no);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR(chpids, 0444, chpids_show, NULL);
|
static DEVICE_ATTR(chpids, 0444, chpids_show, NULL);
|
||||||
static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL);
|
static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL);
|
||||||
static DEVICE_ATTR(devtype, 0444, devtype_show, NULL);
|
static DEVICE_ATTR(devtype, 0444, devtype_show, NULL);
|
||||||
|
@ -605,10 +625,12 @@ static DEVICE_ATTR(cutype, 0444, cutype_show, NULL);
|
||||||
static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
|
static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
|
||||||
static DEVICE_ATTR(online, 0644, online_show, online_store);
|
static DEVICE_ATTR(online, 0644, online_show, online_store);
|
||||||
static DEVICE_ATTR(availability, 0444, available_show, NULL);
|
static DEVICE_ATTR(availability, 0444, available_show, NULL);
|
||||||
|
static DEVICE_ATTR(logging, 0200, NULL, initiate_logging);
|
||||||
|
|
||||||
static struct attribute *io_subchannel_attrs[] = {
|
static struct attribute *io_subchannel_attrs[] = {
|
||||||
&dev_attr_chpids.attr,
|
&dev_attr_chpids.attr,
|
||||||
&dev_attr_pimpampom.attr,
|
&dev_attr_pimpampom.attr,
|
||||||
|
&dev_attr_logging.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2036,6 +2058,21 @@ void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ccw_device_siosl() - initiate logging
|
||||||
|
* @cdev: ccw device
|
||||||
|
*
|
||||||
|
* This function is used to invoke model-dependent logging within the channel
|
||||||
|
* subsystem.
|
||||||
|
*/
|
||||||
|
int ccw_device_siosl(struct ccw_device *cdev)
|
||||||
|
{
|
||||||
|
struct subchannel *sch = to_subchannel(cdev->dev.parent);
|
||||||
|
|
||||||
|
return chsc_siosl(sch->schid);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ccw_device_siosl);
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
EXPORT_SYMBOL(ccw_device_set_online);
|
EXPORT_SYMBOL(ccw_device_set_online);
|
||||||
EXPORT_SYMBOL(ccw_device_set_offline);
|
EXPORT_SYMBOL(ccw_device_set_offline);
|
||||||
|
|
Loading…
Reference in New Issue