diff options
Diffstat (limited to 'drivers/s390')
-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 |
19 files changed, 330 insertions, 41 deletions
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 | ||