diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-10 14:01:26 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-10 14:01:26 -0700 |
commit | 0d6ffdb8f151a2b685c7b45bde7ab2d49fc1bb00 (patch) | |
tree | 1768c906e87750dc897a2f113e335886d9b906e8 | |
parent | 7233e392760b3493095d3d5885cb15e44493d74a (diff) | |
parent | 7c8faa86290c1a2607d6b768a0b874ec392a5c2a (diff) |
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
-rw-r--r-- | arch/s390/include/asm/ccwdev.h | 2 | ||||
-rw-r--r-- | arch/s390/include/asm/topology.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/head.S | 2 | ||||
-rw-r--r-- | arch/s390/mm/cmm.c | 11 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 44 | ||||
-rw-r--r-- | drivers/s390/block/dasd_diag.c | 6 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 94 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.h | 7 | ||||
-rw-r--r-- | drivers/s390/block/dasd_fba.c | 4 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 8 | ||||
-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 | ||||
-rw-r--r-- | drivers/s390/net/smsgiucv_app.c | 7 |
17 files changed, 275 insertions, 38 deletions
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index 1c0030f9b89..f3ba0fa98de 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h @@ -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 int ccw_device_force_console(void); +int ccw_device_siosl(struct ccw_device *); + // FIXME: these have to go extern int _ccw_device_get_subchannel_number(struct ccw_device *); diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index dc8a67297d0..831bd033ea7 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h @@ -30,8 +30,6 @@ static inline void s390_init_cpu_topology(void) }; #endif -#define SD_MC_INIT SD_CPU_INIT - #include <asm-generic/topology.h> #endif /* _ASM_S390_TOPOLOGY_H */ diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 51838ad42d5..db1696e210a 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -366,7 +366,7 @@ iplstart: l %r1,.Lstartup br %r1 -.Linitrd:.long _end + 0x400000 # default address of initrd +.Linitrd:.long _end # default address of initrd .Lparm: .long PARMAREA .Lstartup: .long startup .Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40 diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index eb6a2ef5f82..a9550dca3e4 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -427,7 +427,7 @@ static struct notifier_block cmm_power_notifier = { .notifier_call = cmm_power_event, }; -static int cmm_init(void) +static int __init cmm_init(void) { int rc = -ENOMEM; @@ -435,6 +435,13 @@ static int cmm_init(void) if (!cmm_sysctl_header) goto out_sysctl; #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); if (rc < 0) goto out_smsg; @@ -467,7 +474,7 @@ out_sysctl: } module_init(cmm_init); -static void cmm_exit(void) +static void __exit cmm_exit(void) { unregister_sysctl_table(cmm_sysctl_header); #ifdef CONFIG_CMM_IUCV diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index bed7b4634cc..8d41f3ed38d 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -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); +/* + * 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[] = { &dev_attr_readonly.attr, &dev_attr_discipline.attr, @@ -1094,6 +1137,7 @@ static struct attribute * dasd_attrs[] = { &dev_attr_eer_enabled.attr, &dev_attr_erplog.attr, &dev_attr_failfast.attr, + &dev_attr_expires.attr, NULL, }; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 687f323cdc3..2b3bc3ec054 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -43,7 +43,7 @@ MODULE_LICENSE("GPL"); sizeof(struct dasd_diag_req)) / \ sizeof(struct dasd_diag_bio)) / 2) #define DIAG_MAX_RETRIES 32 -#define DIAG_TIMEOUT 50 * HZ +#define DIAG_TIMEOUT 50 static struct dasd_discipline dasd_diag_discipline; @@ -360,6 +360,8 @@ dasd_diag_check_device(struct dasd_device *device) goto out; } + device->default_expires = DIAG_TIMEOUT; + /* Figure out position of label block */ switch (private->rdc_data.vdev_class) { 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->memdev = memdev; cqr->block = block; - cqr->expires = DIAG_TIMEOUT; + cqr->expires = memdev->default_expires * HZ; cqr->status = DASD_CQR_FILLED; return cqr; } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ab84da5592e..66360c24bd4 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -82,6 +82,14 @@ static struct ccw_driver dasd_eckd_driver; /* see below */ #define INIT_CQR_UNFORMATTED 1 #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 * 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_block *block; struct dasd_uid temp_uid; - int is_known, rc; + int is_known, rc, i; int readonly; + unsigned long value; if (!ccw_device_is_pathgroup(device->cdev)) { dev_warn(&device->cdev->dev, @@ -1143,6 +1152,18 @@ dasd_eckd_check_characteristics(struct dasd_device *device) if (rc) 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 */ rc = dasd_eckd_generate_uid(device); if (rc) @@ -1973,7 +1994,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( cqr->startdev = startdev; cqr->memdev = startdev; 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->retries = 256; cqr->buildclk = get_clock(); @@ -2150,7 +2171,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( cqr->startdev = startdev; cqr->memdev = startdev; 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->retries = 256; cqr->buildclk = get_clock(); @@ -2398,7 +2419,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( cqr->startdev = startdev; cqr->memdev = startdev; 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->retries = 256; cqr->buildclk = get_clock(); @@ -2645,15 +2666,23 @@ dasd_eckd_release(struct dasd_device *device) struct dasd_ccw_req *cqr; int rc; struct ccw1 *ccw; + int useglobal; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + useglobal = 0; cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "Could not allocate initialization request"); - return PTR_ERR(cqr); + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + 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->cmd_code = DASD_ECKD_CCW_RELEASE; @@ -2671,7 +2700,10 @@ dasd_eckd_release(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->memdev); + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -2687,15 +2719,23 @@ dasd_eckd_reserve(struct dasd_device *device) struct dasd_ccw_req *cqr; int rc; struct ccw1 *ccw; + int useglobal; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + useglobal = 0; cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "Could not allocate initialization request"); - return PTR_ERR(cqr); + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + 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->cmd_code = DASD_ECKD_CCW_RESERVE; @@ -2713,7 +2753,10 @@ dasd_eckd_reserve(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->memdev); + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -2728,15 +2771,23 @@ dasd_eckd_steal_lock(struct dasd_device *device) struct dasd_ccw_req *cqr; int rc; struct ccw1 *ccw; + int useglobal; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + useglobal = 0; cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "Could not allocate initialization request"); - return PTR_ERR(cqr); + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + 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->cmd_code = DASD_ECKD_CCW_SLCK; @@ -2754,7 +2805,10 @@ dasd_eckd_steal_lock(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->memdev); + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -3488,10 +3542,15 @@ dasd_eckd_init(void) int ret; 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); if (!ret) wait_for_device_probe(); - + else + kfree(dasd_reserve_req); return ret; } @@ -3499,6 +3558,7 @@ static void __exit dasd_eckd_cleanup(void) { ccw_driver_unregister(&dasd_eckd_driver); + kfree(dasd_reserve_req); } module_init(dasd_eckd_init); diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index dd6385a5af1..0eb49655a6c 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -320,7 +320,12 @@ struct dasd_gneq { __u8 identifier:2; __u8 reserved:6; } __attribute__ ((packed)) flags; - __u8 reserved[7]; + __u8 reserved[5]; + struct { + __u8 value:2; + __u8 number:6; + } __attribute__ ((packed)) timeout; + __u8 reserved3; __u16 subsystemID; __u8 reserved2[22]; } __attribute__ ((packed)); diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 37282b90eec..bec5486e0e6 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -163,6 +163,8 @@ dasd_fba_check_characteristics(struct dasd_device *device) return rc; } + device->default_expires = DASD_EXPIRES; + readonly = dasd_device_is_ro(device); if (readonly) 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->memdev = memdev; cqr->block = block; - cqr->expires = 5 * 60 * HZ; /* 5 minutes */ + cqr->expires = memdev->default_expires * HZ; /* default 5 minutes */ cqr->retries = 32; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 49b431d135e..500678d7116 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -186,7 +186,7 @@ struct dasd_ccw_req { /* ... and how */ 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 */ 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_SUCCESS 0x85 /* request was successful */ +/* default expiration time*/ +#define DASD_EXPIRES 300 +#define DASD_EXPIRES_MAX 40000000 /* per dasd_ccw_req flags */ #define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ @@ -404,6 +407,9 @@ struct dasd_device { /* hook for alias management */ struct list_head alias_list; + + /* default expiration time in s */ + unsigned long default_expires; }; struct dasd_block { diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c index 7f206ed44fd..d15f8b4d78b 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) { struct ccw_request *req = &cdev->private->req; + if (!req->singlepath) { + req->mask = 0; + goto out; + } req->retries = req->maxretries; req->mask = lpm_adjust(req->mask >>= 1, req->lpm); - +out: return req->mask; } @@ -113,8 +117,12 @@ void ccw_request_start(struct ccw_device *cdev) { struct ccw_request *req = &cdev->private->req; - /* Try all paths twice to counter link flapping. */ - req->mask = 0x8080; + if (req->singlepath) { + /* Try all paths twice to counter link flapping. */ + req->mask = 0x8080; + } else + req->mask = req->lpm; + req->retries = req->maxretries; req->mask = lpm_adjust(req->mask, req->lpm); 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 */ if (cdev->drv && cdev->drv->uc_handler) { todo = cdev->drv->uc_handler(cdev, lcirb); + CIO_TRACE_EVENT(2, "uc_response"); + CIO_HEX_EVENT(2, &todo, sizeof(todo)); switch (todo) { case UC_TODO_RETRY: return IO_STATUS_ERROR; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 407d0e9adfa..4cbb1a6ca33 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -29,6 +29,7 @@ #include "chsc.h" static void *sei_page; +static DEFINE_SPINLOCK(siosl_lock); static DEFINE_SPINLOCK(sda_lock); /** @@ -48,6 +49,7 @@ int chsc_error_from_response(int response) case 0x0007: case 0x0008: case 0x000a: + case 0x0104: return -EINVAL; case 0x0004: return -EOPNOTSUPP; @@ -974,3 +976,49 @@ int chsc_sstpi(void *page, void *result, size_t size) 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); diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 37aa611d4ac..5453013f094 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); int chsc_error_from_response(int response); +int chsc_siosl(struct subchannel_id schid); + #endif diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 6d229f3523a..51bd3687d16 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -36,6 +36,7 @@ #include "ioasm.h" #include "io_sch.h" #include "blacklist.h" +#include "chsc.h" static struct timer_list recovery_timer; static DEFINE_SPINLOCK(recovery_lock); @@ -486,9 +487,11 @@ static int online_store_handle_offline(struct ccw_device *cdev) spin_lock_irq(cdev->ccwlock); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG_EVAL); spin_unlock_irq(cdev->ccwlock); - } else if (cdev->online && cdev->drv && cdev->drv->set_offline) + return 0; + } + if (cdev->drv && cdev->drv->set_offline) return ccw_device_set_offline(cdev); - return 0; + return -EINVAL; } 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; } if (cdev->drv && cdev->drv->set_online) - ccw_device_set_online(cdev); - return 0; + return ccw_device_set_online(cdev); + return -EINVAL; } 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(pimpampom, 0444, pimpampom_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(online, 0644, online_show, online_store); static DEVICE_ATTR(availability, 0444, available_show, NULL); +static DEVICE_ATTR(logging, 0200, NULL, initiate_logging); static struct attribute *io_subchannel_attrs[] = { &dev_attr_chpids.attr, &dev_attr_pimpampom.attr, + &dev_attr_logging.attr, 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"); EXPORT_SYMBOL(ccw_device_set_online); EXPORT_SYMBOL(ccw_device_set_offline); diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 6facb5499a6..82a5ad0d63f 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) req->timeout = PGID_TIMEOUT; req->maxretries = PGID_RETRIES; req->lpm = 0x80; + req->singlepath = 1; req->callback = spid_callback; spid_do(cdev); } @@ -420,6 +421,7 @@ static void verify_start(struct ccw_device *cdev) req->timeout = PGID_TIMEOUT; req->maxretries = PGID_RETRIES; req->lpm = 0x80; + req->singlepath = 1; if (cdev->private->flags.pgroup) { CIO_TRACE_EVENT(4, "snid"); 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->maxretries = PGID_RETRIES; req->lpm = sch->schib.pmcw.pam & sch->opm; + req->singlepath = 1; req->callback = disband_callback; fn = SPID_FUNC_DISBAND; if (cdev->private->flags.mpath) diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index b9ce712a7f2..469ef93f230 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -92,11 +92,12 @@ enum io_status { * @filter: optional callback to adjust request status based on IRB data * @callback: final callback * @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 * @retries: current number of retries * @drc: delayed return code - * @cancel: non-zero if request was cancelled - * @done: non-zero if request was finished */ struct ccw_request { struct ccw1 *cp; @@ -108,12 +109,13 @@ struct ccw_request { enum io_status); void (*callback)(struct ccw_device *, void *, int); void *data; + unsigned int singlepath:1; /* These fields are used internally. */ + unsigned int cancel:1; + unsigned int done:1; u16 mask; u16 retries; int drc; - int cancel:1; - int done:1; } __attribute__((packed)); /* diff --git a/drivers/s390/net/smsgiucv_app.c b/drivers/s390/net/smsgiucv_app.c index 13768879020..4d2ea400042 100644 --- a/drivers/s390/net/smsgiucv_app.c +++ b/drivers/s390/net/smsgiucv_app.c @@ -180,6 +180,13 @@ static int __init smsgiucv_app_init(void) 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 */ rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback); if (rc) { |