diff options
| -rw-r--r-- | arch/s390/include/asm/qdio.h | 7 | ||||
| -rw-r--r-- | arch/s390/kernel/time.c | 10 | ||||
| -rw-r--r-- | arch/s390/lib/Makefile | 3 | ||||
| -rw-r--r-- | arch/s390/mm/cmm.c | 2 | ||||
| -rw-r--r-- | drivers/char/hvc_iucv.c | 6 | ||||
| -rw-r--r-- | drivers/s390/block/dasd.c | 36 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_3990_erp.c | 4 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_devmap.c | 13 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_diag.c | 6 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_eckd.c | 27 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_fba.c | 10 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_genhd.c | 3 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_int.h | 7 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_ioctl.c | 6 | ||||
| -rw-r--r-- | drivers/s390/cio/device.c | 5 | ||||
| -rw-r--r-- | drivers/s390/cio/qdio_debug.c | 1 | ||||
| -rw-r--r-- | drivers/s390/cio/qdio_main.c | 3 | ||||
| -rw-r--r-- | drivers/s390/net/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/s390/net/Makefile | 1 | ||||
| -rw-r--r-- | drivers/s390/net/qeth_core_main.c | 3 | ||||
| -rw-r--r-- | drivers/s390/net/smsgiucv.c | 15 | ||||
| -rw-r--r-- | drivers/s390/net/smsgiucv.h | 8 | ||||
| -rw-r--r-- | drivers/s390/net/smsgiucv_app.c | 211 | ||||
| -rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 2 |
24 files changed, 342 insertions, 57 deletions
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index c666bfe5e984..9b04b1102bbc 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h | |||
| @@ -321,11 +321,6 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, | |||
| 321 | #define QDIO_ERROR_ACTIVATE_CHECK_CONDITION 0x40 | 321 | #define QDIO_ERROR_ACTIVATE_CHECK_CONDITION 0x40 |
| 322 | #define QDIO_ERROR_SLSB_STATE 0x80 | 322 | #define QDIO_ERROR_SLSB_STATE 0x80 |
| 323 | 323 | ||
| 324 | /* for qdio_initialize */ | ||
| 325 | #define QDIO_INBOUND_0COPY_SBALS 0x01 | ||
| 326 | #define QDIO_OUTBOUND_0COPY_SBALS 0x02 | ||
| 327 | #define QDIO_USE_OUTBOUND_PCIS 0x04 | ||
| 328 | |||
| 329 | /* for qdio_cleanup */ | 324 | /* for qdio_cleanup */ |
| 330 | #define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01 | 325 | #define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01 |
| 331 | #define QDIO_FLAG_CLEANUP_USING_HALT 0x02 | 326 | #define QDIO_FLAG_CLEANUP_USING_HALT 0x02 |
| @@ -344,7 +339,6 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, | |||
| 344 | * @input_handler: handler to be called for input queues | 339 | * @input_handler: handler to be called for input queues |
| 345 | * @output_handler: handler to be called for output queues | 340 | * @output_handler: handler to be called for output queues |
| 346 | * @int_parm: interruption parameter | 341 | * @int_parm: interruption parameter |
| 347 | * @flags: initialization flags | ||
| 348 | * @input_sbal_addr_array: address of no_input_qs * 128 pointers | 342 | * @input_sbal_addr_array: address of no_input_qs * 128 pointers |
| 349 | * @output_sbal_addr_array: address of no_output_qs * 128 pointers | 343 | * @output_sbal_addr_array: address of no_output_qs * 128 pointers |
| 350 | */ | 344 | */ |
| @@ -361,7 +355,6 @@ struct qdio_initialize { | |||
| 361 | qdio_handler_t *input_handler; | 355 | qdio_handler_t *input_handler; |
| 362 | qdio_handler_t *output_handler; | 356 | qdio_handler_t *output_handler; |
| 363 | unsigned long int_parm; | 357 | unsigned long int_parm; |
| 364 | unsigned long flags; | ||
| 365 | void **input_sbal_addr_array; | 358 | void **input_sbal_addr_array; |
| 366 | void **output_sbal_addr_array; | 359 | void **output_sbal_addr_array; |
| 367 | }; | 360 | }; |
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index a8f93f1705ad..8b22e7f316bb 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
| @@ -73,15 +73,15 @@ unsigned long long monotonic_clock(void) | |||
| 73 | } | 73 | } |
| 74 | EXPORT_SYMBOL(monotonic_clock); | 74 | EXPORT_SYMBOL(monotonic_clock); |
| 75 | 75 | ||
| 76 | void tod_to_timeval(__u64 todval, struct timespec *xtime) | 76 | void tod_to_timeval(__u64 todval, struct timespec *xt) |
| 77 | { | 77 | { |
| 78 | unsigned long long sec; | 78 | unsigned long long sec; |
| 79 | 79 | ||
| 80 | sec = todval >> 12; | 80 | sec = todval >> 12; |
| 81 | do_div(sec, 1000000); | 81 | do_div(sec, 1000000); |
| 82 | xtime->tv_sec = sec; | 82 | xt->tv_sec = sec; |
| 83 | todval -= (sec * 1000000) << 12; | 83 | todval -= (sec * 1000000) << 12; |
| 84 | xtime->tv_nsec = ((todval * 1000) >> 12); | 84 | xt->tv_nsec = ((todval * 1000) >> 12); |
| 85 | } | 85 | } |
| 86 | EXPORT_SYMBOL(tod_to_timeval); | 86 | EXPORT_SYMBOL(tod_to_timeval); |
| 87 | 87 | ||
| @@ -216,8 +216,8 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock, | |||
| 216 | ++vdso_data->tb_update_count; | 216 | ++vdso_data->tb_update_count; |
| 217 | smp_wmb(); | 217 | smp_wmb(); |
| 218 | vdso_data->xtime_tod_stamp = clock->cycle_last; | 218 | vdso_data->xtime_tod_stamp = clock->cycle_last; |
| 219 | vdso_data->xtime_clock_sec = xtime.tv_sec; | 219 | vdso_data->xtime_clock_sec = wall_time->tv_sec; |
| 220 | vdso_data->xtime_clock_nsec = xtime.tv_nsec; | 220 | vdso_data->xtime_clock_nsec = wall_time->tv_nsec; |
| 221 | vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec; | 221 | vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec; |
| 222 | vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec; | 222 | vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec; |
| 223 | smp_wmb(); | 223 | smp_wmb(); |
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index cd54a1c352af..761ab8b56afc 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile | |||
| @@ -2,7 +2,8 @@ | |||
| 2 | # Makefile for s390-specific library files.. | 2 | # Makefile for s390-specific library files.. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | lib-y += delay.o string.o uaccess_std.o uaccess_pt.o usercopy.o | 5 | lib-y += delay.o string.o uaccess_std.o uaccess_pt.o |
| 6 | obj-y += usercopy.o | ||
| 6 | obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o | 7 | obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o |
| 7 | lib-$(CONFIG_64BIT) += uaccess_mvcos.o | 8 | lib-$(CONFIG_64BIT) += uaccess_mvcos.o |
| 8 | lib-$(CONFIG_SMP) += spinlock.o | 9 | lib-$(CONFIG_SMP) += spinlock.o |
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index 76a3637b88e0..f16bd04e39e9 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c | |||
| @@ -374,7 +374,7 @@ static struct ctl_table cmm_dir_table[] = { | |||
| 374 | #ifdef CONFIG_CMM_IUCV | 374 | #ifdef CONFIG_CMM_IUCV |
| 375 | #define SMSG_PREFIX "CMM" | 375 | #define SMSG_PREFIX "CMM" |
| 376 | static void | 376 | static void |
| 377 | cmm_smsg_target(char *from, char *msg) | 377 | cmm_smsg_target(const char *from, char *msg) |
| 378 | { | 378 | { |
| 379 | long nr, seconds; | 379 | long nr, seconds; |
| 380 | 380 | ||
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 21681a81cc35..37b0542a4eeb 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c | |||
| @@ -139,6 +139,8 @@ struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) | |||
| 139 | * | 139 | * |
| 140 | * This function allocates a new struct iucv_tty_buffer element and, optionally, | 140 | * This function allocates a new struct iucv_tty_buffer element and, optionally, |
| 141 | * allocates an internal data buffer with the specified size @size. | 141 | * allocates an internal data buffer with the specified size @size. |
| 142 | * The internal data buffer is always allocated with GFP_DMA which is | ||
| 143 | * required for receiving and sending data with IUCV. | ||
| 142 | * Note: The total message size arises from the internal buffer size and the | 144 | * Note: The total message size arises from the internal buffer size and the |
| 143 | * members of the iucv_tty_msg structure. | 145 | * members of the iucv_tty_msg structure. |
| 144 | * The function returns NULL if memory allocation has failed. | 146 | * The function returns NULL if memory allocation has failed. |
| @@ -154,7 +156,7 @@ static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags) | |||
| 154 | 156 | ||
| 155 | if (size > 0) { | 157 | if (size > 0) { |
| 156 | bufp->msg.length = MSG_SIZE(size); | 158 | bufp->msg.length = MSG_SIZE(size); |
| 157 | bufp->mbuf = kmalloc(bufp->msg.length, flags); | 159 | bufp->mbuf = kmalloc(bufp->msg.length, flags | GFP_DMA); |
| 158 | if (!bufp->mbuf) { | 160 | if (!bufp->mbuf) { |
| 159 | mempool_free(bufp, hvc_iucv_mempool); | 161 | mempool_free(bufp, hvc_iucv_mempool); |
| 160 | return NULL; | 162 | return NULL; |
| @@ -237,7 +239,7 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv, | |||
| 237 | if (!rb->mbuf) { /* message not yet received ... */ | 239 | if (!rb->mbuf) { /* message not yet received ... */ |
| 238 | /* allocate mem to store msg data; if no memory is available | 240 | /* allocate mem to store msg data; if no memory is available |
| 239 | * then leave the buffer on the list and re-try later */ | 241 | * then leave the buffer on the list and re-try later */ |
| 240 | rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC); | 242 | rb->mbuf = kmalloc(rb->msg.length, GFP_ATOMIC | GFP_DMA); |
| 241 | if (!rb->mbuf) | 243 | if (!rb->mbuf) |
| 242 | return -ENOMEM; | 244 | return -ENOMEM; |
| 243 | 245 | ||
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4951aa82e9f5..bbea90baf98f 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <asm/ebcdic.h> | 26 | #include <asm/ebcdic.h> |
| 27 | #include <asm/idals.h> | 27 | #include <asm/idals.h> |
| 28 | #include <asm/itcw.h> | 28 | #include <asm/itcw.h> |
| 29 | #include <asm/diag.h> | ||
| 29 | 30 | ||
| 30 | /* This is ugly... */ | 31 | /* This is ugly... */ |
| 31 | #define PRINTK_HEADER "dasd:" | 32 | #define PRINTK_HEADER "dasd:" |
| @@ -2212,6 +2213,13 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) | |||
| 2212 | goto out; | 2213 | goto out; |
| 2213 | } | 2214 | } |
| 2214 | 2215 | ||
| 2216 | if ((mode & FMODE_WRITE) && | ||
| 2217 | (test_bit(DASD_FLAG_DEVICE_RO, &base->flags) || | ||
| 2218 | (base->features & DASD_FEATURE_READONLY))) { | ||
| 2219 | rc = -EROFS; | ||
| 2220 | goto out; | ||
| 2221 | } | ||
| 2222 | |||
| 2215 | return 0; | 2223 | return 0; |
| 2216 | 2224 | ||
| 2217 | out: | 2225 | out: |
| @@ -2289,6 +2297,34 @@ dasd_exit(void) | |||
| 2289 | * SECTION: common functions for ccw_driver use | 2297 | * SECTION: common functions for ccw_driver use |
| 2290 | */ | 2298 | */ |
| 2291 | 2299 | ||
| 2300 | /* | ||
| 2301 | * Is the device read-only? | ||
| 2302 | * Note that this function does not report the setting of the | ||
| 2303 | * readonly device attribute, but how it is configured in z/VM. | ||
| 2304 | */ | ||
| 2305 | int dasd_device_is_ro(struct dasd_device *device) | ||
| 2306 | { | ||
| 2307 | struct ccw_dev_id dev_id; | ||
| 2308 | struct diag210 diag_data; | ||
| 2309 | int rc; | ||
| 2310 | |||
| 2311 | if (!MACHINE_IS_VM) | ||
| 2312 | return 0; | ||
| 2313 | ccw_device_get_id(device->cdev, &dev_id); | ||
| 2314 | memset(&diag_data, 0, sizeof(diag_data)); | ||
| 2315 | diag_data.vrdcdvno = dev_id.devno; | ||
| 2316 | diag_data.vrdclen = sizeof(diag_data); | ||
| 2317 | rc = diag210(&diag_data); | ||
| 2318 | if (rc == 0 || rc == 2) { | ||
| 2319 | return diag_data.vrdcvfla & 0x80; | ||
| 2320 | } else { | ||
| 2321 | DBF_EVENT(DBF_WARNING, "diag210 failed for dev=%04x with rc=%d", | ||
| 2322 | dev_id.devno, rc); | ||
| 2323 | return 0; | ||
| 2324 | } | ||
| 2325 | } | ||
| 2326 | EXPORT_SYMBOL_GPL(dasd_device_is_ro); | ||
| 2327 | |||
| 2292 | static void dasd_generic_auto_online(void *data, async_cookie_t cookie) | 2328 | static void dasd_generic_auto_online(void *data, async_cookie_t cookie) |
| 2293 | { | 2329 | { |
| 2294 | struct ccw_device *cdev = data; | 2330 | struct ccw_device *cdev = data; |
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 44796ba4eb9b..51224f76b980 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c | |||
| @@ -1045,6 +1045,10 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense) | |||
| 1045 | 1045 | ||
| 1046 | erp->retries = 5; | 1046 | erp->retries = 5; |
| 1047 | 1047 | ||
| 1048 | } else if (sense[1] & SNS1_WRITE_INHIBITED) { | ||
| 1049 | dev_err(&device->cdev->dev, "An I/O request was rejected" | ||
| 1050 | " because writing is inhibited\n"); | ||
| 1051 | erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); | ||
| 1048 | } else { | 1052 | } else { |
| 1049 | /* fatal error - set status to FAILED | 1053 | /* fatal error - set status to FAILED |
| 1050 | internal error 09 - Command Reject */ | 1054 | internal error 09 - Command Reject */ |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index d49766f3b940..8e23919c8704 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
| @@ -742,6 +742,7 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, | |||
| 742 | const char *buf, size_t count) | 742 | const char *buf, size_t count) |
| 743 | { | 743 | { |
| 744 | struct dasd_devmap *devmap; | 744 | struct dasd_devmap *devmap; |
| 745 | struct dasd_device *device; | ||
| 745 | int val; | 746 | int val; |
| 746 | char *endp; | 747 | char *endp; |
| 747 | 748 | ||
| @@ -758,12 +759,14 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, | |||
| 758 | devmap->features |= DASD_FEATURE_READONLY; | 759 | devmap->features |= DASD_FEATURE_READONLY; |
| 759 | else | 760 | else |
| 760 | devmap->features &= ~DASD_FEATURE_READONLY; | 761 | devmap->features &= ~DASD_FEATURE_READONLY; |
| 761 | if (devmap->device) | 762 | device = devmap->device; |
| 762 | devmap->device->features = devmap->features; | 763 | if (device) { |
| 763 | if (devmap->device && devmap->device->block | 764 | device->features = devmap->features; |
| 764 | && devmap->device->block->gdp) | 765 | val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags); |
| 765 | set_disk_ro(devmap->device->block->gdp, val); | 766 | } |
| 766 | spin_unlock(&dasd_devmap_lock); | 767 | spin_unlock(&dasd_devmap_lock); |
| 768 | if (device && device->block && device->block->gdp) | ||
| 769 | set_disk_ro(device->block->gdp, val); | ||
| 767 | return count; | 770 | return count; |
| 768 | } | 771 | } |
| 769 | 772 | ||
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 6e14863f5c70..687f323cdc38 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c | |||
| @@ -145,12 +145,10 @@ dasd_diag_erp(struct dasd_device *device) | |||
| 145 | mdsk_term_io(device); | 145 | mdsk_term_io(device); |
| 146 | rc = mdsk_init_io(device, device->block->bp_block, 0, NULL); | 146 | rc = mdsk_init_io(device, device->block->bp_block, 0, NULL); |
| 147 | if (rc == 4) { | 147 | if (rc == 4) { |
| 148 | if (!(device->features & DASD_FEATURE_READONLY)) { | 148 | if (!(test_and_set_bit(DASD_FLAG_DEVICE_RO, &device->flags))) |
| 149 | pr_warning("%s: The access mode of a DIAG device " | 149 | pr_warning("%s: The access mode of a DIAG device " |
| 150 | "changed to read-only\n", | 150 | "changed to read-only\n", |
| 151 | dev_name(&device->cdev->dev)); | 151 | dev_name(&device->cdev->dev)); |
| 152 | device->features |= DASD_FEATURE_READONLY; | ||
| 153 | } | ||
| 154 | rc = 0; | 152 | rc = 0; |
| 155 | } | 153 | } |
| 156 | if (rc) | 154 | if (rc) |
| @@ -449,7 +447,7 @@ dasd_diag_check_device(struct dasd_device *device) | |||
| 449 | rc = -EIO; | 447 | rc = -EIO; |
| 450 | } else { | 448 | } else { |
| 451 | if (rc == 4) | 449 | if (rc == 4) |
| 452 | device->features |= DASD_FEATURE_READONLY; | 450 | set_bit(DASD_FLAG_DEVICE_RO, &device->flags); |
| 453 | pr_info("%s: New DASD with %ld byte/block, total size %ld " | 451 | pr_info("%s: New DASD with %ld byte/block, total size %ld " |
| 454 | "KB%s\n", dev_name(&device->cdev->dev), | 452 | "KB%s\n", dev_name(&device->cdev->dev), |
| 455 | (unsigned long) block->bp_block, | 453 | (unsigned long) block->bp_block, |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 1cca21aafaba..01f4e7a34aa8 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -1089,6 +1089,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
| 1089 | struct dasd_eckd_private *private; | 1089 | struct dasd_eckd_private *private; |
| 1090 | struct dasd_block *block; | 1090 | struct dasd_block *block; |
| 1091 | int is_known, rc; | 1091 | int is_known, rc; |
| 1092 | int readonly; | ||
| 1092 | 1093 | ||
| 1093 | if (!ccw_device_is_pathgroup(device->cdev)) { | 1094 | if (!ccw_device_is_pathgroup(device->cdev)) { |
| 1094 | dev_warn(&device->cdev->dev, | 1095 | dev_warn(&device->cdev->dev, |
| @@ -1182,15 +1183,20 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
| 1182 | else | 1183 | else |
| 1183 | private->real_cyl = private->rdc_data.no_cyl; | 1184 | private->real_cyl = private->rdc_data.no_cyl; |
| 1184 | 1185 | ||
| 1186 | readonly = dasd_device_is_ro(device); | ||
| 1187 | if (readonly) | ||
| 1188 | set_bit(DASD_FLAG_DEVICE_RO, &device->flags); | ||
| 1189 | |||
| 1185 | dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) " | 1190 | dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) " |
| 1186 | "with %d cylinders, %d heads, %d sectors\n", | 1191 | "with %d cylinders, %d heads, %d sectors%s\n", |
| 1187 | private->rdc_data.dev_type, | 1192 | private->rdc_data.dev_type, |
| 1188 | private->rdc_data.dev_model, | 1193 | private->rdc_data.dev_model, |
| 1189 | private->rdc_data.cu_type, | 1194 | private->rdc_data.cu_type, |
| 1190 | private->rdc_data.cu_model.model, | 1195 | private->rdc_data.cu_model.model, |
| 1191 | private->real_cyl, | 1196 | private->real_cyl, |
| 1192 | private->rdc_data.trk_per_cyl, | 1197 | private->rdc_data.trk_per_cyl, |
| 1193 | private->rdc_data.sec_per_trk); | 1198 | private->rdc_data.sec_per_trk, |
| 1199 | readonly ? ", read-only device" : ""); | ||
| 1194 | return 0; | 1200 | return 0; |
| 1195 | 1201 | ||
| 1196 | out_err3: | 1202 | out_err3: |
| @@ -2839,8 +2845,13 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp) | |||
| 2839 | char *psf_data, *rssd_result; | 2845 | char *psf_data, *rssd_result; |
| 2840 | struct dasd_ccw_req *cqr; | 2846 | struct dasd_ccw_req *cqr; |
| 2841 | struct ccw1 *ccw; | 2847 | struct ccw1 *ccw; |
| 2848 | char psf0, psf1; | ||
| 2842 | int rc; | 2849 | int rc; |
| 2843 | 2850 | ||
| 2851 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) | ||
| 2852 | return -EACCES; | ||
| 2853 | psf0 = psf1 = 0; | ||
| 2854 | |||
| 2844 | /* Copy parms from caller */ | 2855 | /* Copy parms from caller */ |
| 2845 | rc = -EFAULT; | 2856 | rc = -EFAULT; |
| 2846 | if (copy_from_user(&usrparm, argp, sizeof(usrparm))) | 2857 | if (copy_from_user(&usrparm, argp, sizeof(usrparm))) |
| @@ -2869,12 +2880,8 @@ static int dasd_symm_io(struct dasd_device *device, void __user *argp) | |||
| 2869 | (void __user *)(unsigned long) usrparm.psf_data, | 2880 | (void __user *)(unsigned long) usrparm.psf_data, |
| 2870 | usrparm.psf_data_len)) | 2881 | usrparm.psf_data_len)) |
| 2871 | goto out_free; | 2882 | goto out_free; |
| 2872 | 2883 | psf0 = psf_data[0]; | |
| 2873 | /* sanity check on syscall header */ | 2884 | psf1 = psf_data[1]; |
| 2874 | if (psf_data[0] != 0x17 && psf_data[1] != 0xce) { | ||
| 2875 | rc = -EINVAL; | ||
| 2876 | goto out_free; | ||
| 2877 | } | ||
| 2878 | 2885 | ||
| 2879 | /* setup CCWs for PSF + RSSD */ | 2886 | /* setup CCWs for PSF + RSSD */ |
| 2880 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 , 0, device); | 2887 | cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 2 , 0, device); |
| @@ -2925,7 +2932,9 @@ out_free: | |||
| 2925 | kfree(rssd_result); | 2932 | kfree(rssd_result); |
| 2926 | kfree(psf_data); | 2933 | kfree(psf_data); |
| 2927 | out: | 2934 | out: |
| 2928 | DBF_DEV_EVENT(DBF_WARNING, device, "Symmetrix ioctl: rc=%d", rc); | 2935 | DBF_DEV_EVENT(DBF_WARNING, device, |
| 2936 | "Symmetrix ioctl (0x%02x 0x%02x): rc=%d", | ||
| 2937 | (int) psf0, (int) psf1, rc); | ||
| 2929 | return rc; | 2938 | return rc; |
| 2930 | } | 2939 | } |
| 2931 | 2940 | ||
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 0f152444ac77..37282b90eecc 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
| @@ -124,6 +124,7 @@ dasd_fba_check_characteristics(struct dasd_device *device) | |||
| 124 | struct dasd_fba_private *private; | 124 | struct dasd_fba_private *private; |
| 125 | struct ccw_device *cdev = device->cdev; | 125 | struct ccw_device *cdev = device->cdev; |
| 126 | int rc; | 126 | int rc; |
| 127 | int readonly; | ||
| 127 | 128 | ||
| 128 | private = (struct dasd_fba_private *) device->private; | 129 | private = (struct dasd_fba_private *) device->private; |
| 129 | if (!private) { | 130 | if (!private) { |
| @@ -162,16 +163,21 @@ dasd_fba_check_characteristics(struct dasd_device *device) | |||
| 162 | return rc; | 163 | return rc; |
| 163 | } | 164 | } |
| 164 | 165 | ||
| 166 | readonly = dasd_device_is_ro(device); | ||
| 167 | if (readonly) | ||
| 168 | set_bit(DASD_FLAG_DEVICE_RO, &device->flags); | ||
| 169 | |||
| 165 | dev_info(&device->cdev->dev, | 170 | dev_info(&device->cdev->dev, |
| 166 | "New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB " | 171 | "New FBA DASD %04X/%02X (CU %04X/%02X) with %d MB " |
| 167 | "and %d B/blk\n", | 172 | "and %d B/blk%s\n", |
| 168 | cdev->id.dev_type, | 173 | cdev->id.dev_type, |
| 169 | cdev->id.dev_model, | 174 | cdev->id.dev_model, |
| 170 | cdev->id.cu_type, | 175 | cdev->id.cu_type, |
| 171 | cdev->id.cu_model, | 176 | cdev->id.cu_model, |
| 172 | ((private->rdc_data.blk_bdsa * | 177 | ((private->rdc_data.blk_bdsa * |
| 173 | (private->rdc_data.blk_size >> 9)) >> 11), | 178 | (private->rdc_data.blk_size >> 9)) >> 11), |
| 174 | private->rdc_data.blk_size); | 179 | private->rdc_data.blk_size, |
| 180 | readonly ? ", read-only device" : ""); | ||
| 175 | return 0; | 181 | return 0; |
| 176 | } | 182 | } |
| 177 | 183 | ||
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 94f92a1247f2..30a1ca3d08b7 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c | |||
| @@ -70,7 +70,8 @@ int dasd_gendisk_alloc(struct dasd_block *block) | |||
| 70 | } | 70 | } |
| 71 | len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26)); | 71 | len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26)); |
| 72 | 72 | ||
| 73 | if (block->base->features & DASD_FEATURE_READONLY) | 73 | if (base->features & DASD_FEATURE_READONLY || |
| 74 | test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) | ||
| 74 | set_disk_ro(gdp, 1); | 75 | set_disk_ro(gdp, 1); |
| 75 | gdp->private_data = block; | 76 | gdp->private_data = block; |
| 76 | gdp->queue = block->request_queue; | 77 | gdp->queue = block->request_queue; |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index ed73ce550822..a91d4a97d4f2 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
| @@ -436,6 +436,10 @@ struct dasd_block { | |||
| 436 | #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ | 436 | #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ |
| 437 | #define DASD_FLAG_EER_SNSS 4 /* A SNSS is required */ | 437 | #define DASD_FLAG_EER_SNSS 4 /* A SNSS is required */ |
| 438 | #define DASD_FLAG_EER_IN_USE 5 /* A SNSS request is running */ | 438 | #define DASD_FLAG_EER_IN_USE 5 /* A SNSS request is running */ |
| 439 | #define DASD_FLAG_DEVICE_RO 6 /* The device itself is read-only. Don't | ||
| 440 | * confuse this with the user specified | ||
| 441 | * read-only feature. | ||
| 442 | */ | ||
| 439 | 443 | ||
| 440 | void dasd_put_device_wake(struct dasd_device *); | 444 | void dasd_put_device_wake(struct dasd_device *); |
| 441 | 445 | ||
| @@ -609,6 +613,9 @@ char *dasd_get_sense(struct irb *); | |||
| 609 | void dasd_device_set_stop_bits(struct dasd_device *, int); | 613 | void dasd_device_set_stop_bits(struct dasd_device *, int); |
| 610 | void dasd_device_remove_stop_bits(struct dasd_device *, int); | 614 | void dasd_device_remove_stop_bits(struct dasd_device *, int); |
| 611 | 615 | ||
| 616 | int dasd_device_is_ro(struct dasd_device *); | ||
| 617 | |||
| 618 | |||
| 612 | /* externals in dasd_devmap.c */ | 619 | /* externals in dasd_devmap.c */ |
| 613 | extern int dasd_max_devindex; | 620 | extern int dasd_max_devindex; |
| 614 | extern int dasd_probeonly; | 621 | extern int dasd_probeonly; |
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 7039d9cf0fb4..3479f8158a1b 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c | |||
| @@ -199,7 +199,8 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp) | |||
| 199 | if (!argp) | 199 | if (!argp) |
| 200 | return -EINVAL; | 200 | return -EINVAL; |
| 201 | 201 | ||
| 202 | if (block->base->features & DASD_FEATURE_READONLY) | 202 | if (block->base->features & DASD_FEATURE_READONLY || |
| 203 | test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) | ||
| 203 | return -EROFS; | 204 | return -EROFS; |
| 204 | if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) | 205 | if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) |
| 205 | return -EFAULT; | 206 | return -EFAULT; |
| @@ -349,7 +350,8 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) | |||
| 349 | return -EINVAL; | 350 | return -EINVAL; |
| 350 | if (get_user(intval, (int __user *)argp)) | 351 | if (get_user(intval, (int __user *)argp)) |
| 351 | return -EFAULT; | 352 | return -EFAULT; |
| 352 | 353 | if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) | |
| 354 | return -EROFS; | ||
| 353 | set_disk_ro(bdev->bd_disk, intval); | 355 | set_disk_ro(bdev->bd_disk, intval); |
| 354 | return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); | 356 | return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); |
| 355 | } | 357 | } |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index c6abb75c4615..6d229f3523a0 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
| @@ -764,7 +764,7 @@ static void sch_create_and_recog_new_device(struct subchannel *sch) | |||
| 764 | static void io_subchannel_register(struct ccw_device *cdev) | 764 | static void io_subchannel_register(struct ccw_device *cdev) |
| 765 | { | 765 | { |
| 766 | struct subchannel *sch; | 766 | struct subchannel *sch; |
| 767 | int ret; | 767 | int ret, adjust_init_count = 1; |
| 768 | unsigned long flags; | 768 | unsigned long flags; |
| 769 | 769 | ||
| 770 | sch = to_subchannel(cdev->dev.parent); | 770 | sch = to_subchannel(cdev->dev.parent); |
| @@ -793,6 +793,7 @@ static void io_subchannel_register(struct ccw_device *cdev) | |||
| 793 | cdev->private->dev_id.ssid, | 793 | cdev->private->dev_id.ssid, |
| 794 | cdev->private->dev_id.devno); | 794 | cdev->private->dev_id.devno); |
| 795 | } | 795 | } |
| 796 | adjust_init_count = 0; | ||
| 796 | goto out; | 797 | goto out; |
| 797 | } | 798 | } |
| 798 | /* | 799 | /* |
| @@ -818,7 +819,7 @@ out: | |||
| 818 | cdev->private->flags.recog_done = 1; | 819 | cdev->private->flags.recog_done = 1; |
| 819 | wake_up(&cdev->private->wait_q); | 820 | wake_up(&cdev->private->wait_q); |
| 820 | out_err: | 821 | out_err: |
| 821 | if (atomic_dec_and_test(&ccw_device_init_count)) | 822 | if (adjust_init_count && atomic_dec_and_test(&ccw_device_init_count)) |
| 822 | wake_up(&ccw_device_init_wq); | 823 | wake_up(&ccw_device_init_wq); |
| 823 | } | 824 | } |
| 824 | 825 | ||
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index c94eb2a0fa2e..6ce83f56d537 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c | |||
| @@ -33,7 +33,6 @@ void qdio_allocate_dbf(struct qdio_initialize *init_data, | |||
| 33 | DBF_HEX(&init_data->input_handler, sizeof(void *)); | 33 | DBF_HEX(&init_data->input_handler, sizeof(void *)); |
| 34 | DBF_HEX(&init_data->output_handler, sizeof(void *)); | 34 | DBF_HEX(&init_data->output_handler, sizeof(void *)); |
| 35 | DBF_HEX(&init_data->int_parm, sizeof(long)); | 35 | DBF_HEX(&init_data->int_parm, sizeof(long)); |
| 36 | DBF_HEX(&init_data->flags, sizeof(long)); | ||
| 37 | DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *)); | 36 | DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *)); |
| 38 | DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *)); | 37 | DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *)); |
| 39 | DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); | 38 | DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 232ef047ba34..4f8f74311778 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
| @@ -588,10 +588,11 @@ static void qdio_kick_handler(struct qdio_q *q) | |||
| 588 | if (q->is_input_q) { | 588 | if (q->is_input_q) { |
| 589 | qperf_inc(q, inbound_handler); | 589 | qperf_inc(q, inbound_handler); |
| 590 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%02x c:%02x", start, count); | 590 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%02x c:%02x", start, count); |
| 591 | } else | 591 | } else { |
| 592 | qperf_inc(q, outbound_handler); | 592 | qperf_inc(q, outbound_handler); |
| 593 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x", | 593 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x", |
| 594 | start, count); | 594 | start, count); |
| 595 | } | ||
| 595 | 596 | ||
| 596 | q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, | 597 | q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count, |
| 597 | q->irq_ptr->int_parm); | 598 | q->irq_ptr->int_parm); |
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index cb909a5b5047..977bb4d4ed15 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig | |||
| @@ -43,6 +43,16 @@ config SMSGIUCV | |||
| 43 | Select this option if you want to be able to receive SMSG messages | 43 | Select this option if you want to be able to receive SMSG messages |
| 44 | from other VM guest systems. | 44 | from other VM guest systems. |
| 45 | 45 | ||
| 46 | config SMSGIUCV_EVENT | ||
| 47 | tristate "Deliver IUCV special messages as uevents (VM only)" | ||
| 48 | depends on SMSGIUCV | ||
| 49 | help | ||
| 50 | Select this option to deliver CP special messages (SMSGs) as | ||
| 51 | uevents. The driver handles only those special messages that | ||
| 52 | start with "APP". | ||
| 53 | |||
| 54 | To compile as a module, choose M. The module name is "smsgiucv_app". | ||
| 55 | |||
| 46 | config CLAW | 56 | config CLAW |
| 47 | tristate "CLAW device support" | 57 | tristate "CLAW device support" |
| 48 | depends on CCW && NETDEVICES | 58 | depends on CCW && NETDEVICES |
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 6cab5a62f99e..4dfe8c1092da 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile | |||
| @@ -6,6 +6,7 @@ ctcm-y += ctcm_main.o ctcm_fsms.o ctcm_mpc.o ctcm_sysfs.o ctcm_dbug.o | |||
| 6 | obj-$(CONFIG_CTCM) += ctcm.o fsm.o | 6 | obj-$(CONFIG_CTCM) += ctcm.o fsm.o |
| 7 | obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o | 7 | obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o |
| 8 | obj-$(CONFIG_SMSGIUCV) += smsgiucv.o | 8 | obj-$(CONFIG_SMSGIUCV) += smsgiucv.o |
| 9 | obj-$(CONFIG_SMSGIUCV_EVENT) += smsgiucv_app.o | ||
| 9 | obj-$(CONFIG_LCS) += lcs.o | 10 | obj-$(CONFIG_LCS) += lcs.o |
| 10 | obj-$(CONFIG_CLAW) += claw.o | 11 | obj-$(CONFIG_CLAW) += claw.o |
| 11 | qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o | 12 | qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index fa8a519218ac..7d25bdd443cd 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
| @@ -3805,9 +3805,6 @@ static int qeth_qdio_establish(struct qeth_card *card) | |||
| 3805 | init_data.input_handler = card->discipline.input_handler; | 3805 | init_data.input_handler = card->discipline.input_handler; |
| 3806 | init_data.output_handler = card->discipline.output_handler; | 3806 | init_data.output_handler = card->discipline.output_handler; |
| 3807 | init_data.int_parm = (unsigned long) card; | 3807 | init_data.int_parm = (unsigned long) card; |
| 3808 | init_data.flags = QDIO_INBOUND_0COPY_SBALS | | ||
| 3809 | QDIO_OUTBOUND_0COPY_SBALS | | ||
| 3810 | QDIO_USE_OUTBOUND_PCIS; | ||
| 3811 | init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; | 3808 | init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; |
| 3812 | init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; | 3809 | init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; |
| 3813 | 3810 | ||
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 67f2485d2372..ecef1edee701 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c | |||
| @@ -31,9 +31,9 @@ | |||
| 31 | 31 | ||
| 32 | struct smsg_callback { | 32 | struct smsg_callback { |
| 33 | struct list_head list; | 33 | struct list_head list; |
| 34 | char *prefix; | 34 | const char *prefix; |
| 35 | int len; | 35 | int len; |
| 36 | void (*callback)(char *from, char *str); | 36 | void (*callback)(const char *from, char *str); |
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | MODULE_AUTHOR | 39 | MODULE_AUTHOR |
| @@ -100,8 +100,8 @@ static void smsg_message_pending(struct iucv_path *path, | |||
| 100 | kfree(buffer); | 100 | kfree(buffer); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | int smsg_register_callback(char *prefix, | 103 | int smsg_register_callback(const char *prefix, |
| 104 | void (*callback)(char *from, char *str)) | 104 | void (*callback)(const char *from, char *str)) |
| 105 | { | 105 | { |
| 106 | struct smsg_callback *cb; | 106 | struct smsg_callback *cb; |
| 107 | 107 | ||
| @@ -117,8 +117,9 @@ int smsg_register_callback(char *prefix, | |||
| 117 | return 0; | 117 | return 0; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | void smsg_unregister_callback(char *prefix, | 120 | void smsg_unregister_callback(const char *prefix, |
| 121 | void (*callback)(char *from, char *str)) | 121 | void (*callback)(const char *from, |
| 122 | char *str)) | ||
| 122 | { | 123 | { |
| 123 | struct smsg_callback *cb, *tmp; | 124 | struct smsg_callback *cb, *tmp; |
| 124 | 125 | ||
| @@ -176,7 +177,7 @@ static const struct dev_pm_ops smsg_pm_ops = { | |||
| 176 | 177 | ||
| 177 | static struct device_driver smsg_driver = { | 178 | static struct device_driver smsg_driver = { |
| 178 | .owner = THIS_MODULE, | 179 | .owner = THIS_MODULE, |
| 179 | .name = "SMSGIUCV", | 180 | .name = SMSGIUCV_DRV_NAME, |
| 180 | .bus = &iucv_bus, | 181 | .bus = &iucv_bus, |
| 181 | .pm = &smsg_pm_ops, | 182 | .pm = &smsg_pm_ops, |
| 182 | }; | 183 | }; |
diff --git a/drivers/s390/net/smsgiucv.h b/drivers/s390/net/smsgiucv.h index 67f5d4f8378d..149a1151608d 100644 --- a/drivers/s390/net/smsgiucv.h +++ b/drivers/s390/net/smsgiucv.h | |||
| @@ -5,6 +5,10 @@ | |||
| 5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) | 5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | int smsg_register_callback(char *, void (*)(char *, char *)); | 8 | #define SMSGIUCV_DRV_NAME "SMSGIUCV" |
| 9 | void smsg_unregister_callback(char *, void (*)(char *, char *)); | 9 | |
| 10 | int smsg_register_callback(const char *, | ||
| 11 | void (*)(const char *, char *)); | ||
| 12 | void smsg_unregister_callback(const char *, | ||
| 13 | void (*)(const char *, char *)); | ||
| 10 | 14 | ||
diff --git a/drivers/s390/net/smsgiucv_app.c b/drivers/s390/net/smsgiucv_app.c new file mode 100644 index 000000000000..91579dc6a2b0 --- /dev/null +++ b/drivers/s390/net/smsgiucv_app.c | |||
| @@ -0,0 +1,211 @@ | |||
| 1 | /* | ||
| 2 | * Deliver z/VM CP special messages (SMSG) as uevents. | ||
| 3 | * | ||
| 4 | * The driver registers for z/VM CP special messages with the | ||
| 5 | * "APP" prefix. Incoming messages are delivered to user space | ||
| 6 | * as uevents. | ||
| 7 | * | ||
| 8 | * Copyright IBM Corp. 2010 | ||
| 9 | * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | #define KMSG_COMPONENT "smsgiucv_app" | ||
| 13 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
| 14 | |||
| 15 | #include <linux/ctype.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/list.h> | ||
| 19 | #include <linux/kobject.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/spinlock.h> | ||
| 22 | #include <linux/workqueue.h> | ||
| 23 | #include <net/iucv/iucv.h> | ||
| 24 | #include "smsgiucv.h" | ||
| 25 | |||
| 26 | /* prefix used for SMSG registration */ | ||
| 27 | #define SMSG_PREFIX "APP" | ||
| 28 | |||
| 29 | /* SMSG related uevent environment variables */ | ||
| 30 | #define ENV_SENDER_STR "SMSG_SENDER=" | ||
| 31 | #define ENV_SENDER_LEN (strlen(ENV_SENDER_STR) + 8 + 1) | ||
| 32 | #define ENV_PREFIX_STR "SMSG_ID=" | ||
| 33 | #define ENV_PREFIX_LEN (strlen(ENV_PREFIX_STR) + \ | ||
| 34 | strlen(SMSG_PREFIX) + 1) | ||
| 35 | #define ENV_TEXT_STR "SMSG_TEXT=" | ||
| 36 | #define ENV_TEXT_LEN(msg) (strlen(ENV_TEXT_STR) + strlen((msg)) + 1) | ||
| 37 | |||
| 38 | /* z/VM user ID which is permitted to send SMSGs | ||
| 39 | * If the value is undefined or empty (""), special messages are | ||
| 40 | * accepted from any z/VM user ID. */ | ||
| 41 | static char *sender; | ||
| 42 | module_param(sender, charp, 0400); | ||
| 43 | MODULE_PARM_DESC(sender, "z/VM user ID from which CP SMSGs are accepted"); | ||
| 44 | |||
| 45 | /* SMSG device representation */ | ||
| 46 | static struct device *smsg_app_dev; | ||
| 47 | |||
| 48 | /* list element for queuing received messages for delivery */ | ||
| 49 | struct smsg_app_event { | ||
| 50 | struct list_head list; | ||
| 51 | char *buf; | ||
| 52 | char *envp[4]; | ||
| 53 | }; | ||
| 54 | |||
| 55 | /* queue for outgoing uevents */ | ||
| 56 | static LIST_HEAD(smsg_event_queue); | ||
| 57 | static DEFINE_SPINLOCK(smsg_event_queue_lock); | ||
| 58 | |||
| 59 | static void smsg_app_event_free(struct smsg_app_event *ev) | ||
| 60 | { | ||
| 61 | kfree(ev->buf); | ||
| 62 | kfree(ev); | ||
| 63 | } | ||
| 64 | |||
| 65 | static struct smsg_app_event *smsg_app_event_alloc(const char *from, | ||
| 66 | const char *msg) | ||
| 67 | { | ||
| 68 | struct smsg_app_event *ev; | ||
| 69 | |||
| 70 | ev = kzalloc(sizeof(*ev), GFP_ATOMIC); | ||
| 71 | if (!ev) | ||
| 72 | return NULL; | ||
| 73 | |||
| 74 | ev->buf = kzalloc(ENV_SENDER_LEN + ENV_PREFIX_LEN + | ||
| 75 | ENV_TEXT_LEN(msg), GFP_ATOMIC); | ||
| 76 | if (!ev->buf) { | ||
| 77 | kfree(ev); | ||
| 78 | return NULL; | ||
| 79 | } | ||
| 80 | |||
| 81 | /* setting up environment pointers into buf */ | ||
| 82 | ev->envp[0] = ev->buf; | ||
| 83 | ev->envp[1] = ev->envp[0] + ENV_SENDER_LEN; | ||
| 84 | ev->envp[2] = ev->envp[1] + ENV_PREFIX_LEN; | ||
| 85 | ev->envp[3] = NULL; | ||
| 86 | |||
| 87 | /* setting up environment: sender, prefix name, and message text */ | ||
| 88 | snprintf(ev->envp[0], ENV_SENDER_LEN, ENV_SENDER_STR "%s", from); | ||
| 89 | snprintf(ev->envp[1], ENV_PREFIX_LEN, ENV_PREFIX_STR "%s", SMSG_PREFIX); | ||
| 90 | snprintf(ev->envp[2], ENV_TEXT_LEN(msg), ENV_TEXT_STR "%s", msg); | ||
| 91 | |||
| 92 | return ev; | ||
| 93 | } | ||
| 94 | |||
| 95 | static void smsg_event_work_fn(struct work_struct *work) | ||
| 96 | { | ||
| 97 | LIST_HEAD(event_queue); | ||
| 98 | struct smsg_app_event *p, *n; | ||
| 99 | struct device *dev; | ||
| 100 | |||
| 101 | dev = get_device(smsg_app_dev); | ||
| 102 | if (!dev) | ||
| 103 | return; | ||
| 104 | |||
| 105 | spin_lock_bh(&smsg_event_queue_lock); | ||
| 106 | list_splice_init(&smsg_event_queue, &event_queue); | ||
| 107 | spin_unlock_bh(&smsg_event_queue_lock); | ||
| 108 | |||
| 109 | list_for_each_entry_safe(p, n, &event_queue, list) { | ||
| 110 | list_del(&p->list); | ||
| 111 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, p->envp); | ||
| 112 | smsg_app_event_free(p); | ||
| 113 | } | ||
| 114 | |||
| 115 | put_device(dev); | ||
| 116 | } | ||
| 117 | static DECLARE_WORK(smsg_event_work, smsg_event_work_fn); | ||
| 118 | |||
| 119 | static void smsg_app_callback(const char *from, char *msg) | ||
| 120 | { | ||
| 121 | struct smsg_app_event *se; | ||
| 122 | |||
| 123 | /* check if the originating z/VM user ID matches | ||
| 124 | * the configured sender. */ | ||
| 125 | if (sender && strlen(sender) > 0 && strcmp(from, sender) != 0) | ||
| 126 | return; | ||
| 127 | |||
| 128 | /* get start of message text (skip prefix and leading blanks) */ | ||
| 129 | msg += strlen(SMSG_PREFIX); | ||
| 130 | while (*msg && isspace(*msg)) | ||
| 131 | msg++; | ||
| 132 | if (*msg == '\0') | ||
| 133 | return; | ||
| 134 | |||
| 135 | /* allocate event list element and its environment */ | ||
| 136 | se = smsg_app_event_alloc(from, msg); | ||
| 137 | if (!se) | ||
| 138 | return; | ||
| 139 | |||
| 140 | /* queue event and schedule work function */ | ||
| 141 | spin_lock(&smsg_event_queue_lock); | ||
| 142 | list_add_tail(&se->list, &smsg_event_queue); | ||
| 143 | spin_unlock(&smsg_event_queue_lock); | ||
| 144 | |||
| 145 | schedule_work(&smsg_event_work); | ||
| 146 | return; | ||
| 147 | } | ||
| 148 | |||
| 149 | static int __init smsgiucv_app_init(void) | ||
| 150 | { | ||
| 151 | struct device_driver *smsgiucv_drv; | ||
| 152 | int rc; | ||
| 153 | |||
| 154 | if (!MACHINE_IS_VM) | ||
| 155 | return -ENODEV; | ||
| 156 | |||
| 157 | smsg_app_dev = kzalloc(sizeof(*smsg_app_dev), GFP_KERNEL); | ||
| 158 | if (!smsg_app_dev) | ||
| 159 | return -ENOMEM; | ||
| 160 | |||
| 161 | smsgiucv_drv = driver_find(SMSGIUCV_DRV_NAME, &iucv_bus); | ||
| 162 | if (!smsgiucv_drv) { | ||
| 163 | kfree(smsg_app_dev); | ||
| 164 | return -ENODEV; | ||
| 165 | } | ||
| 166 | |||
| 167 | rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT); | ||
| 168 | if (rc) { | ||
| 169 | kfree(smsg_app_dev); | ||
| 170 | goto fail_put_driver; | ||
| 171 | } | ||
| 172 | smsg_app_dev->bus = &iucv_bus; | ||
| 173 | smsg_app_dev->parent = iucv_root; | ||
| 174 | smsg_app_dev->release = (void (*)(struct device *)) kfree; | ||
| 175 | smsg_app_dev->driver = smsgiucv_drv; | ||
| 176 | rc = device_register(smsg_app_dev); | ||
| 177 | if (rc) { | ||
| 178 | put_device(smsg_app_dev); | ||
| 179 | goto fail_put_driver; | ||
| 180 | } | ||
| 181 | |||
| 182 | /* register with the smsgiucv device driver */ | ||
| 183 | rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback); | ||
| 184 | if (rc) { | ||
| 185 | device_unregister(smsg_app_dev); | ||
| 186 | goto fail_put_driver; | ||
| 187 | } | ||
| 188 | |||
| 189 | rc = 0; | ||
| 190 | fail_put_driver: | ||
| 191 | put_driver(smsgiucv_drv); | ||
| 192 | return rc; | ||
| 193 | } | ||
| 194 | module_init(smsgiucv_app_init); | ||
| 195 | |||
| 196 | static void __exit smsgiucv_app_exit(void) | ||
| 197 | { | ||
| 198 | /* unregister callback */ | ||
| 199 | smsg_unregister_callback(SMSG_PREFIX, smsg_app_callback); | ||
| 200 | |||
| 201 | /* cancel pending work and flush any queued event work */ | ||
| 202 | cancel_work_sync(&smsg_event_work); | ||
| 203 | smsg_event_work_fn(&smsg_event_work); | ||
| 204 | |||
| 205 | device_unregister(smsg_app_dev); | ||
| 206 | } | ||
| 207 | module_exit(smsgiucv_app_exit); | ||
| 208 | |||
| 209 | MODULE_LICENSE("GPL v2"); | ||
| 210 | MODULE_DESCRIPTION("Deliver z/VM CP SMSG as uevents"); | ||
| 211 | MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>"); | ||
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 71b97ff77cf0..6479273a3094 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c | |||
| @@ -319,8 +319,6 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, | |||
| 319 | id->input_handler = zfcp_qdio_int_resp; | 319 | id->input_handler = zfcp_qdio_int_resp; |
| 320 | id->output_handler = zfcp_qdio_int_req; | 320 | id->output_handler = zfcp_qdio_int_req; |
| 321 | id->int_parm = (unsigned long) qdio; | 321 | id->int_parm = (unsigned long) qdio; |
| 322 | id->flags = QDIO_INBOUND_0COPY_SBALS | | ||
| 323 | QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS; | ||
| 324 | id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal); | 322 | id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal); |
| 325 | id->output_sbal_addr_array = (void **) (qdio->req_q.sbal); | 323 | id->output_sbal_addr_array = (void **) (qdio->req_q.sbal); |
| 326 | 324 | ||
