Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: [S390] dasd: tunable missing interrupt handler [S390] dasd: allocate fallback cqr for reserve/release [S390] topology: use default MC domain initializer [S390] initrd: change default load address [S390] cmm, smsgiucv_app: convert sender to uppercase [S390] cmm: add missing __init/__exit annotations [S390] cio: use all available paths for some internal I/O [S390] ccwreq: add ability to use all paths [S390] cio: ccw_device_online_store return -EINVAL in case of missing driver [S390] cio: Log the response from the unit check handler [S390] cio: CHSC SIOSL Support
This commit is contained in:
commit
0d6ffdb8f1
|
@ -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 *);
|
||||||
|
|
||||||
|
|
|
@ -30,8 +30,6 @@ static inline void s390_init_cpu_topology(void)
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SD_MC_INIT SD_CPU_INIT
|
|
||||||
|
|
||||||
#include <asm-generic/topology.h>
|
#include <asm-generic/topology.h>
|
||||||
|
|
||||||
#endif /* _ASM_S390_TOPOLOGY_H */
|
#endif /* _ASM_S390_TOPOLOGY_H */
|
||||||
|
|
|
@ -366,7 +366,7 @@ iplstart:
|
||||||
l %r1,.Lstartup
|
l %r1,.Lstartup
|
||||||
br %r1
|
br %r1
|
||||||
|
|
||||||
.Linitrd:.long _end + 0x400000 # default address of initrd
|
.Linitrd:.long _end # default address of initrd
|
||||||
.Lparm: .long PARMAREA
|
.Lparm: .long PARMAREA
|
||||||
.Lstartup: .long startup
|
.Lstartup: .long startup
|
||||||
.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
|
.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
|
||||||
|
|
|
@ -427,7 +427,7 @@ static struct notifier_block cmm_power_notifier = {
|
||||||
.notifier_call = cmm_power_event,
|
.notifier_call = cmm_power_event,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cmm_init(void)
|
static int __init cmm_init(void)
|
||||||
{
|
{
|
||||||
int rc = -ENOMEM;
|
int rc = -ENOMEM;
|
||||||
|
|
||||||
|
@ -435,6 +435,13 @@ static int cmm_init(void)
|
||||||
if (!cmm_sysctl_header)
|
if (!cmm_sysctl_header)
|
||||||
goto out_sysctl;
|
goto out_sysctl;
|
||||||
#ifdef CONFIG_CMM_IUCV
|
#ifdef CONFIG_CMM_IUCV
|
||||||
|
/* convert sender to uppercase characters */
|
||||||
|
if (sender) {
|
||||||
|
int len = strlen(sender);
|
||||||
|
while (len--)
|
||||||
|
sender[len] = toupper(sender[len]);
|
||||||
|
}
|
||||||
|
|
||||||
rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
|
rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto out_smsg;
|
goto out_smsg;
|
||||||
|
@ -467,7 +474,7 @@ out_sysctl:
|
||||||
}
|
}
|
||||||
module_init(cmm_init);
|
module_init(cmm_init);
|
||||||
|
|
||||||
static void cmm_exit(void)
|
static void __exit cmm_exit(void)
|
||||||
{
|
{
|
||||||
unregister_sysctl_table(cmm_sysctl_header);
|
unregister_sysctl_table(cmm_sysctl_header);
|
||||||
#ifdef CONFIG_CMM_IUCV
|
#ifdef CONFIG_CMM_IUCV
|
||||||
|
|
|
@ -1083,6 +1083,49 @@ dasd_eer_store(struct device *dev, struct device_attribute *attr,
|
||||||
|
|
||||||
static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store);
|
static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* expiration time for default requests
|
||||||
|
*/
|
||||||
|
static ssize_t
|
||||||
|
dasd_expires_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct dasd_device *device;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
device = dasd_device_from_cdev(to_ccwdev(dev));
|
||||||
|
if (IS_ERR(device))
|
||||||
|
return -ENODEV;
|
||||||
|
len = snprintf(buf, PAGE_SIZE, "%lu\n", device->default_expires);
|
||||||
|
dasd_put_device(device);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
dasd_expires_store(struct device *dev, struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct dasd_device *device;
|
||||||
|
unsigned long val;
|
||||||
|
|
||||||
|
device = dasd_device_from_cdev(to_ccwdev(dev));
|
||||||
|
if (IS_ERR(device))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if ((strict_strtoul(buf, 10, &val) != 0) ||
|
||||||
|
(val > DASD_EXPIRES_MAX) || val == 0) {
|
||||||
|
dasd_put_device(device);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val)
|
||||||
|
device->default_expires = val;
|
||||||
|
|
||||||
|
dasd_put_device(device);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store);
|
||||||
|
|
||||||
static struct attribute * dasd_attrs[] = {
|
static struct attribute * dasd_attrs[] = {
|
||||||
&dev_attr_readonly.attr,
|
&dev_attr_readonly.attr,
|
||||||
&dev_attr_discipline.attr,
|
&dev_attr_discipline.attr,
|
||||||
|
@ -1094,6 +1137,7 @@ static struct attribute * dasd_attrs[] = {
|
||||||
&dev_attr_eer_enabled.attr,
|
&dev_attr_eer_enabled.attr,
|
||||||
&dev_attr_erplog.attr,
|
&dev_attr_erplog.attr,
|
||||||
&dev_attr_failfast.attr,
|
&dev_attr_failfast.attr,
|
||||||
|
&dev_attr_expires.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
|
||||||
sizeof(struct dasd_diag_req)) / \
|
sizeof(struct dasd_diag_req)) / \
|
||||||
sizeof(struct dasd_diag_bio)) / 2)
|
sizeof(struct dasd_diag_bio)) / 2)
|
||||||
#define DIAG_MAX_RETRIES 32
|
#define DIAG_MAX_RETRIES 32
|
||||||
#define DIAG_TIMEOUT 50 * HZ
|
#define DIAG_TIMEOUT 50
|
||||||
|
|
||||||
static struct dasd_discipline dasd_diag_discipline;
|
static struct dasd_discipline dasd_diag_discipline;
|
||||||
|
|
||||||
|
@ -360,6 +360,8 @@ dasd_diag_check_device(struct dasd_device *device)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device->default_expires = DIAG_TIMEOUT;
|
||||||
|
|
||||||
/* Figure out position of label block */
|
/* Figure out position of label block */
|
||||||
switch (private->rdc_data.vdev_class) {
|
switch (private->rdc_data.vdev_class) {
|
||||||
case DEV_CLASS_FBA:
|
case DEV_CLASS_FBA:
|
||||||
|
@ -563,7 +565,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
|
||||||
cqr->startdev = memdev;
|
cqr->startdev = memdev;
|
||||||
cqr->memdev = memdev;
|
cqr->memdev = memdev;
|
||||||
cqr->block = block;
|
cqr->block = block;
|
||||||
cqr->expires = DIAG_TIMEOUT;
|
cqr->expires = memdev->default_expires * HZ;
|
||||||
cqr->status = DASD_CQR_FILLED;
|
cqr->status = DASD_CQR_FILLED;
|
||||||
return cqr;
|
return cqr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,14 @@ static struct ccw_driver dasd_eckd_driver; /* see below */
|
||||||
#define INIT_CQR_UNFORMATTED 1
|
#define INIT_CQR_UNFORMATTED 1
|
||||||
#define INIT_CQR_ERROR 2
|
#define INIT_CQR_ERROR 2
|
||||||
|
|
||||||
|
/* emergency request for reserve/release */
|
||||||
|
static struct {
|
||||||
|
struct dasd_ccw_req cqr;
|
||||||
|
struct ccw1 ccw;
|
||||||
|
char data[32];
|
||||||
|
} *dasd_reserve_req;
|
||||||
|
static DEFINE_MUTEX(dasd_reserve_mutex);
|
||||||
|
|
||||||
|
|
||||||
/* initial attempt at a probe function. this can be simplified once
|
/* initial attempt at a probe function. this can be simplified once
|
||||||
* the other detection code is gone */
|
* the other detection code is gone */
|
||||||
|
@ -1107,8 +1115,9 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
|
||||||
struct dasd_eckd_private *private;
|
struct dasd_eckd_private *private;
|
||||||
struct dasd_block *block;
|
struct dasd_block *block;
|
||||||
struct dasd_uid temp_uid;
|
struct dasd_uid temp_uid;
|
||||||
int is_known, rc;
|
int is_known, rc, i;
|
||||||
int readonly;
|
int readonly;
|
||||||
|
unsigned long value;
|
||||||
|
|
||||||
if (!ccw_device_is_pathgroup(device->cdev)) {
|
if (!ccw_device_is_pathgroup(device->cdev)) {
|
||||||
dev_warn(&device->cdev->dev,
|
dev_warn(&device->cdev->dev,
|
||||||
|
@ -1143,6 +1152,18 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_err1;
|
goto out_err1;
|
||||||
|
|
||||||
|
/* set default timeout */
|
||||||
|
device->default_expires = DASD_EXPIRES;
|
||||||
|
if (private->gneq) {
|
||||||
|
value = 1;
|
||||||
|
for (i = 0; i < private->gneq->timeout.value; i++)
|
||||||
|
value = 10 * value;
|
||||||
|
value = value * private->gneq->timeout.number;
|
||||||
|
/* do not accept useless values */
|
||||||
|
if (value != 0 && value <= DASD_EXPIRES_MAX)
|
||||||
|
device->default_expires = value;
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate device unique id */
|
/* Generate device unique id */
|
||||||
rc = dasd_eckd_generate_uid(device);
|
rc = dasd_eckd_generate_uid(device);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -1973,7 +1994,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
|
||||||
cqr->startdev = startdev;
|
cqr->startdev = startdev;
|
||||||
cqr->memdev = startdev;
|
cqr->memdev = startdev;
|
||||||
cqr->block = block;
|
cqr->block = block;
|
||||||
cqr->expires = 5 * 60 * HZ; /* 5 minutes */
|
cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */
|
||||||
cqr->lpm = private->path_data.ppm;
|
cqr->lpm = private->path_data.ppm;
|
||||||
cqr->retries = 256;
|
cqr->retries = 256;
|
||||||
cqr->buildclk = get_clock();
|
cqr->buildclk = get_clock();
|
||||||
|
@ -2150,7 +2171,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
|
||||||
cqr->startdev = startdev;
|
cqr->startdev = startdev;
|
||||||
cqr->memdev = startdev;
|
cqr->memdev = startdev;
|
||||||
cqr->block = block;
|
cqr->block = block;
|
||||||
cqr->expires = 5 * 60 * HZ; /* 5 minutes */
|
cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */
|
||||||
cqr->lpm = private->path_data.ppm;
|
cqr->lpm = private->path_data.ppm;
|
||||||
cqr->retries = 256;
|
cqr->retries = 256;
|
||||||
cqr->buildclk = get_clock();
|
cqr->buildclk = get_clock();
|
||||||
|
@ -2398,7 +2419,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
|
||||||
cqr->startdev = startdev;
|
cqr->startdev = startdev;
|
||||||
cqr->memdev = startdev;
|
cqr->memdev = startdev;
|
||||||
cqr->block = block;
|
cqr->block = block;
|
||||||
cqr->expires = 5 * 60 * HZ; /* 5 minutes */
|
cqr->expires = startdev->default_expires * HZ; /* default 5 minutes */
|
||||||
cqr->lpm = private->path_data.ppm;
|
cqr->lpm = private->path_data.ppm;
|
||||||
cqr->retries = 256;
|
cqr->retries = 256;
|
||||||
cqr->buildclk = get_clock();
|
cqr->buildclk = get_clock();
|
||||||
|
@ -2645,15 +2666,23 @@ dasd_eckd_release(struct dasd_device *device)
|
||||||
struct dasd_ccw_req *cqr;
|
struct dasd_ccw_req *cqr;
|
||||||
int rc;
|
int rc;
|
||||||
struct ccw1 *ccw;
|
struct ccw1 *ccw;
|
||||||
|
int useglobal;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
|
useglobal = 0;
|
||||||
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
|
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
|
||||||
if (IS_ERR(cqr)) {
|
if (IS_ERR(cqr)) {
|
||||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
mutex_lock(&dasd_reserve_mutex);
|
||||||
"Could not allocate initialization request");
|
useglobal = 1;
|
||||||
return PTR_ERR(cqr);
|
cqr = &dasd_reserve_req->cqr;
|
||||||
|
memset(cqr, 0, sizeof(*cqr));
|
||||||
|
memset(&dasd_reserve_req->ccw, 0,
|
||||||
|
sizeof(dasd_reserve_req->ccw));
|
||||||
|
cqr->cpaddr = &dasd_reserve_req->ccw;
|
||||||
|
cqr->data = &dasd_reserve_req->data;
|
||||||
|
cqr->magic = DASD_ECKD_MAGIC;
|
||||||
}
|
}
|
||||||
ccw = cqr->cpaddr;
|
ccw = cqr->cpaddr;
|
||||||
ccw->cmd_code = DASD_ECKD_CCW_RELEASE;
|
ccw->cmd_code = DASD_ECKD_CCW_RELEASE;
|
||||||
|
@ -2671,6 +2700,9 @@ dasd_eckd_release(struct dasd_device *device)
|
||||||
|
|
||||||
rc = dasd_sleep_on_immediatly(cqr);
|
rc = dasd_sleep_on_immediatly(cqr);
|
||||||
|
|
||||||
|
if (useglobal)
|
||||||
|
mutex_unlock(&dasd_reserve_mutex);
|
||||||
|
else
|
||||||
dasd_sfree_request(cqr, cqr->memdev);
|
dasd_sfree_request(cqr, cqr->memdev);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -2687,15 +2719,23 @@ dasd_eckd_reserve(struct dasd_device *device)
|
||||||
struct dasd_ccw_req *cqr;
|
struct dasd_ccw_req *cqr;
|
||||||
int rc;
|
int rc;
|
||||||
struct ccw1 *ccw;
|
struct ccw1 *ccw;
|
||||||
|
int useglobal;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
|
useglobal = 0;
|
||||||
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
|
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
|
||||||
if (IS_ERR(cqr)) {
|
if (IS_ERR(cqr)) {
|
||||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
mutex_lock(&dasd_reserve_mutex);
|
||||||
"Could not allocate initialization request");
|
useglobal = 1;
|
||||||
return PTR_ERR(cqr);
|
cqr = &dasd_reserve_req->cqr;
|
||||||
|
memset(cqr, 0, sizeof(*cqr));
|
||||||
|
memset(&dasd_reserve_req->ccw, 0,
|
||||||
|
sizeof(dasd_reserve_req->ccw));
|
||||||
|
cqr->cpaddr = &dasd_reserve_req->ccw;
|
||||||
|
cqr->data = &dasd_reserve_req->data;
|
||||||
|
cqr->magic = DASD_ECKD_MAGIC;
|
||||||
}
|
}
|
||||||
ccw = cqr->cpaddr;
|
ccw = cqr->cpaddr;
|
||||||
ccw->cmd_code = DASD_ECKD_CCW_RESERVE;
|
ccw->cmd_code = DASD_ECKD_CCW_RESERVE;
|
||||||
|
@ -2713,6 +2753,9 @@ dasd_eckd_reserve(struct dasd_device *device)
|
||||||
|
|
||||||
rc = dasd_sleep_on_immediatly(cqr);
|
rc = dasd_sleep_on_immediatly(cqr);
|
||||||
|
|
||||||
|
if (useglobal)
|
||||||
|
mutex_unlock(&dasd_reserve_mutex);
|
||||||
|
else
|
||||||
dasd_sfree_request(cqr, cqr->memdev);
|
dasd_sfree_request(cqr, cqr->memdev);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -2728,15 +2771,23 @@ dasd_eckd_steal_lock(struct dasd_device *device)
|
||||||
struct dasd_ccw_req *cqr;
|
struct dasd_ccw_req *cqr;
|
||||||
int rc;
|
int rc;
|
||||||
struct ccw1 *ccw;
|
struct ccw1 *ccw;
|
||||||
|
int useglobal;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
|
useglobal = 0;
|
||||||
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
|
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
|
||||||
if (IS_ERR(cqr)) {
|
if (IS_ERR(cqr)) {
|
||||||
DBF_DEV_EVENT(DBF_WARNING, device, "%s",
|
mutex_lock(&dasd_reserve_mutex);
|
||||||
"Could not allocate initialization request");
|
useglobal = 1;
|
||||||
return PTR_ERR(cqr);
|
cqr = &dasd_reserve_req->cqr;
|
||||||
|
memset(cqr, 0, sizeof(*cqr));
|
||||||
|
memset(&dasd_reserve_req->ccw, 0,
|
||||||
|
sizeof(dasd_reserve_req->ccw));
|
||||||
|
cqr->cpaddr = &dasd_reserve_req->ccw;
|
||||||
|
cqr->data = &dasd_reserve_req->data;
|
||||||
|
cqr->magic = DASD_ECKD_MAGIC;
|
||||||
}
|
}
|
||||||
ccw = cqr->cpaddr;
|
ccw = cqr->cpaddr;
|
||||||
ccw->cmd_code = DASD_ECKD_CCW_SLCK;
|
ccw->cmd_code = DASD_ECKD_CCW_SLCK;
|
||||||
|
@ -2754,6 +2805,9 @@ dasd_eckd_steal_lock(struct dasd_device *device)
|
||||||
|
|
||||||
rc = dasd_sleep_on_immediatly(cqr);
|
rc = dasd_sleep_on_immediatly(cqr);
|
||||||
|
|
||||||
|
if (useglobal)
|
||||||
|
mutex_unlock(&dasd_reserve_mutex);
|
||||||
|
else
|
||||||
dasd_sfree_request(cqr, cqr->memdev);
|
dasd_sfree_request(cqr, cqr->memdev);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -3488,10 +3542,15 @@ dasd_eckd_init(void)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ASCEBC(dasd_eckd_discipline.ebcname, 4);
|
ASCEBC(dasd_eckd_discipline.ebcname, 4);
|
||||||
|
dasd_reserve_req = kmalloc(sizeof(*dasd_reserve_req),
|
||||||
|
GFP_KERNEL | GFP_DMA);
|
||||||
|
if (!dasd_reserve_req)
|
||||||
|
return -ENOMEM;
|
||||||
ret = ccw_driver_register(&dasd_eckd_driver);
|
ret = ccw_driver_register(&dasd_eckd_driver);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
wait_for_device_probe();
|
wait_for_device_probe();
|
||||||
|
else
|
||||||
|
kfree(dasd_reserve_req);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3499,6 +3558,7 @@ static void __exit
|
||||||
dasd_eckd_cleanup(void)
|
dasd_eckd_cleanup(void)
|
||||||
{
|
{
|
||||||
ccw_driver_unregister(&dasd_eckd_driver);
|
ccw_driver_unregister(&dasd_eckd_driver);
|
||||||
|
kfree(dasd_reserve_req);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(dasd_eckd_init);
|
module_init(dasd_eckd_init);
|
||||||
|
|
|
@ -320,7 +320,12 @@ struct dasd_gneq {
|
||||||
__u8 identifier:2;
|
__u8 identifier:2;
|
||||||
__u8 reserved:6;
|
__u8 reserved:6;
|
||||||
} __attribute__ ((packed)) flags;
|
} __attribute__ ((packed)) flags;
|
||||||
__u8 reserved[7];
|
__u8 reserved[5];
|
||||||
|
struct {
|
||||||
|
__u8 value:2;
|
||||||
|
__u8 number:6;
|
||||||
|
} __attribute__ ((packed)) timeout;
|
||||||
|
__u8 reserved3;
|
||||||
__u16 subsystemID;
|
__u16 subsystemID;
|
||||||
__u8 reserved2[22];
|
__u8 reserved2[22];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
|
@ -163,6 +163,8 @@ dasd_fba_check_characteristics(struct dasd_device *device)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device->default_expires = DASD_EXPIRES;
|
||||||
|
|
||||||
readonly = dasd_device_is_ro(device);
|
readonly = dasd_device_is_ro(device);
|
||||||
if (readonly)
|
if (readonly)
|
||||||
set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
|
set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
|
||||||
|
@ -370,7 +372,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
|
||||||
cqr->startdev = memdev;
|
cqr->startdev = memdev;
|
||||||
cqr->memdev = memdev;
|
cqr->memdev = memdev;
|
||||||
cqr->block = block;
|
cqr->block = block;
|
||||||
cqr->expires = 5 * 60 * HZ; /* 5 minutes */
|
cqr->expires = memdev->default_expires * HZ; /* default 5 minutes */
|
||||||
cqr->retries = 32;
|
cqr->retries = 32;
|
||||||
cqr->buildclk = get_clock();
|
cqr->buildclk = get_clock();
|
||||||
cqr->status = DASD_CQR_FILLED;
|
cqr->status = DASD_CQR_FILLED;
|
||||||
|
|
|
@ -186,7 +186,7 @@ struct dasd_ccw_req {
|
||||||
|
|
||||||
/* ... and how */
|
/* ... and how */
|
||||||
unsigned long starttime; /* jiffies time of request start */
|
unsigned long starttime; /* jiffies time of request start */
|
||||||
int expires; /* expiration period in jiffies */
|
unsigned long expires; /* expiration period in jiffies */
|
||||||
char lpm; /* logical path mask */
|
char lpm; /* logical path mask */
|
||||||
void *data; /* pointer to data area */
|
void *data; /* pointer to data area */
|
||||||
|
|
||||||
|
@ -224,6 +224,9 @@ struct dasd_ccw_req {
|
||||||
#define DASD_CQR_CLEARED 0x84 /* request was cleared */
|
#define DASD_CQR_CLEARED 0x84 /* request was cleared */
|
||||||
#define DASD_CQR_SUCCESS 0x85 /* request was successful */
|
#define DASD_CQR_SUCCESS 0x85 /* request was successful */
|
||||||
|
|
||||||
|
/* default expiration time*/
|
||||||
|
#define DASD_EXPIRES 300
|
||||||
|
#define DASD_EXPIRES_MAX 40000000
|
||||||
|
|
||||||
/* per dasd_ccw_req flags */
|
/* per dasd_ccw_req flags */
|
||||||
#define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */
|
#define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */
|
||||||
|
@ -404,6 +407,9 @@ struct dasd_device {
|
||||||
|
|
||||||
/* hook for alias management */
|
/* hook for alias management */
|
||||||
struct list_head alias_list;
|
struct list_head alias_list;
|
||||||
|
|
||||||
|
/* default expiration time in s */
|
||||||
|
unsigned long default_expires;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dasd_block {
|
struct dasd_block {
|
||||||
|
|
|
@ -38,9 +38,13 @@ static u16 ccwreq_next_path(struct ccw_device *cdev)
|
||||||
{
|
{
|
||||||
struct ccw_request *req = &cdev->private->req;
|
struct ccw_request *req = &cdev->private->req;
|
||||||
|
|
||||||
|
if (!req->singlepath) {
|
||||||
|
req->mask = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
req->retries = req->maxretries;
|
req->retries = req->maxretries;
|
||||||
req->mask = lpm_adjust(req->mask >>= 1, req->lpm);
|
req->mask = lpm_adjust(req->mask >>= 1, req->lpm);
|
||||||
|
out:
|
||||||
return req->mask;
|
return req->mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,8 +117,12 @@ void ccw_request_start(struct ccw_device *cdev)
|
||||||
{
|
{
|
||||||
struct ccw_request *req = &cdev->private->req;
|
struct ccw_request *req = &cdev->private->req;
|
||||||
|
|
||||||
|
if (req->singlepath) {
|
||||||
/* Try all paths twice to counter link flapping. */
|
/* Try all paths twice to counter link flapping. */
|
||||||
req->mask = 0x8080;
|
req->mask = 0x8080;
|
||||||
|
} else
|
||||||
|
req->mask = req->lpm;
|
||||||
|
|
||||||
req->retries = req->maxretries;
|
req->retries = req->maxretries;
|
||||||
req->mask = lpm_adjust(req->mask, req->lpm);
|
req->mask = lpm_adjust(req->mask, req->lpm);
|
||||||
req->drc = 0;
|
req->drc = 0;
|
||||||
|
@ -182,6 +190,8 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb)
|
||||||
/* Ask the driver what to do */
|
/* Ask the driver what to do */
|
||||||
if (cdev->drv && cdev->drv->uc_handler) {
|
if (cdev->drv && cdev->drv->uc_handler) {
|
||||||
todo = cdev->drv->uc_handler(cdev, lcirb);
|
todo = cdev->drv->uc_handler(cdev, lcirb);
|
||||||
|
CIO_TRACE_EVENT(2, "uc_response");
|
||||||
|
CIO_HEX_EVENT(2, &todo, sizeof(todo));
|
||||||
switch (todo) {
|
switch (todo) {
|
||||||
case UC_TODO_RETRY:
|
case UC_TODO_RETRY:
|
||||||
return IO_STATUS_ERROR;
|
return IO_STATUS_ERROR;
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -486,9 +487,11 @@ static int online_store_handle_offline(struct ccw_device *cdev)
|
||||||
spin_lock_irq(cdev->ccwlock);
|
spin_lock_irq(cdev->ccwlock);
|
||||||
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL);
|
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL);
|
||||||
spin_unlock_irq(cdev->ccwlock);
|
spin_unlock_irq(cdev->ccwlock);
|
||||||
} else if (cdev->online && cdev->drv && cdev->drv->set_offline)
|
|
||||||
return ccw_device_set_offline(cdev);
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
if (cdev->drv && cdev->drv->set_offline)
|
||||||
|
return ccw_device_set_offline(cdev);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int online_store_recog_and_online(struct ccw_device *cdev)
|
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)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
if (cdev->drv && cdev->drv->set_online)
|
if (cdev->drv && cdev->drv->set_online)
|
||||||
ccw_device_set_online(cdev);
|
return ccw_device_set_online(cdev);
|
||||||
return 0;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int online_store_handle_online(struct ccw_device *cdev, int force)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 +627,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 +2060,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);
|
||||||
|
|
|
@ -208,6 +208,7 @@ static void spid_start(struct ccw_device *cdev)
|
||||||
req->timeout = PGID_TIMEOUT;
|
req->timeout = PGID_TIMEOUT;
|
||||||
req->maxretries = PGID_RETRIES;
|
req->maxretries = PGID_RETRIES;
|
||||||
req->lpm = 0x80;
|
req->lpm = 0x80;
|
||||||
|
req->singlepath = 1;
|
||||||
req->callback = spid_callback;
|
req->callback = spid_callback;
|
||||||
spid_do(cdev);
|
spid_do(cdev);
|
||||||
}
|
}
|
||||||
|
@ -420,6 +421,7 @@ static void verify_start(struct ccw_device *cdev)
|
||||||
req->timeout = PGID_TIMEOUT;
|
req->timeout = PGID_TIMEOUT;
|
||||||
req->maxretries = PGID_RETRIES;
|
req->maxretries = PGID_RETRIES;
|
||||||
req->lpm = 0x80;
|
req->lpm = 0x80;
|
||||||
|
req->singlepath = 1;
|
||||||
if (cdev->private->flags.pgroup) {
|
if (cdev->private->flags.pgroup) {
|
||||||
CIO_TRACE_EVENT(4, "snid");
|
CIO_TRACE_EVENT(4, "snid");
|
||||||
CIO_HEX_EVENT(4, devid, sizeof(*devid));
|
CIO_HEX_EVENT(4, devid, sizeof(*devid));
|
||||||
|
@ -507,6 +509,7 @@ void ccw_device_disband_start(struct ccw_device *cdev)
|
||||||
req->timeout = PGID_TIMEOUT;
|
req->timeout = PGID_TIMEOUT;
|
||||||
req->maxretries = PGID_RETRIES;
|
req->maxretries = PGID_RETRIES;
|
||||||
req->lpm = sch->schib.pmcw.pam & sch->opm;
|
req->lpm = sch->schib.pmcw.pam & sch->opm;
|
||||||
|
req->singlepath = 1;
|
||||||
req->callback = disband_callback;
|
req->callback = disband_callback;
|
||||||
fn = SPID_FUNC_DISBAND;
|
fn = SPID_FUNC_DISBAND;
|
||||||
if (cdev->private->flags.mpath)
|
if (cdev->private->flags.mpath)
|
||||||
|
|
|
@ -92,11 +92,12 @@ enum io_status {
|
||||||
* @filter: optional callback to adjust request status based on IRB data
|
* @filter: optional callback to adjust request status based on IRB data
|
||||||
* @callback: final callback
|
* @callback: final callback
|
||||||
* @data: user-defined pointer passed to all callbacks
|
* @data: user-defined pointer passed to all callbacks
|
||||||
|
* @singlepath: if set, use only one path from @lpm per start I/O
|
||||||
|
* @cancel: non-zero if request was cancelled
|
||||||
|
* @done: non-zero if request was finished
|
||||||
* @mask: current path mask
|
* @mask: current path mask
|
||||||
* @retries: current number of retries
|
* @retries: current number of retries
|
||||||
* @drc: delayed return code
|
* @drc: delayed return code
|
||||||
* @cancel: non-zero if request was cancelled
|
|
||||||
* @done: non-zero if request was finished
|
|
||||||
*/
|
*/
|
||||||
struct ccw_request {
|
struct ccw_request {
|
||||||
struct ccw1 *cp;
|
struct ccw1 *cp;
|
||||||
|
@ -108,12 +109,13 @@ struct ccw_request {
|
||||||
enum io_status);
|
enum io_status);
|
||||||
void (*callback)(struct ccw_device *, void *, int);
|
void (*callback)(struct ccw_device *, void *, int);
|
||||||
void *data;
|
void *data;
|
||||||
|
unsigned int singlepath:1;
|
||||||
/* These fields are used internally. */
|
/* These fields are used internally. */
|
||||||
|
unsigned int cancel:1;
|
||||||
|
unsigned int done:1;
|
||||||
u16 mask;
|
u16 mask;
|
||||||
u16 retries;
|
u16 retries;
|
||||||
int drc;
|
int drc;
|
||||||
int cancel:1;
|
|
||||||
int done:1;
|
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -180,6 +180,13 @@ static int __init smsgiucv_app_init(void)
|
||||||
goto fail_put_driver;
|
goto fail_put_driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* convert sender to uppercase characters */
|
||||||
|
if (sender) {
|
||||||
|
int len = strlen(sender);
|
||||||
|
while (len--)
|
||||||
|
sender[len] = toupper(sender[len]);
|
||||||
|
}
|
||||||
|
|
||||||
/* register with the smsgiucv device driver */
|
/* register with the smsgiucv device driver */
|
||||||
rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
|
rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
|
Loading…
Reference in New Issue