aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/block/dasd.c36
-rw-r--r--drivers/s390/block/dasd_3990_erp.c4
-rw-r--r--drivers/s390/block/dasd_devmap.c13
-rw-r--r--drivers/s390/block/dasd_diag.c6
-rw-r--r--drivers/s390/block/dasd_eckd.c27
-rw-r--r--drivers/s390/block/dasd_fba.c10
-rw-r--r--drivers/s390/block/dasd_genhd.c3
-rw-r--r--drivers/s390/block/dasd_int.h7
-rw-r--r--drivers/s390/block/dasd_ioctl.c6
-rw-r--r--drivers/s390/cio/device.c5
-rw-r--r--drivers/s390/cio/qdio_debug.c1
-rw-r--r--drivers/s390/cio/qdio_main.c3
-rw-r--r--drivers/s390/net/Kconfig10
-rw-r--r--drivers/s390/net/Makefile1
-rw-r--r--drivers/s390/net/qeth_core_main.c3
-rw-r--r--drivers/s390/net/smsgiucv.c15
-rw-r--r--drivers/s390/net/smsgiucv.h8
-rw-r--r--drivers/s390/net/smsgiucv_app.c211
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c2
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
2217out: 2225out:
@@ -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 */
2305int 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}
2326EXPORT_SYMBOL_GPL(dasd_device_is_ro);
2327
2292static void dasd_generic_auto_online(void *data, async_cookie_t cookie) 2328static 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
1196out_err3: 1202out_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);
2927out: 2934out:
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
440void dasd_put_device_wake(struct dasd_device *); 444void dasd_put_device_wake(struct dasd_device *);
441 445
@@ -609,6 +613,9 @@ char *dasd_get_sense(struct irb *);
609void dasd_device_set_stop_bits(struct dasd_device *, int); 613void dasd_device_set_stop_bits(struct dasd_device *, int);
610void dasd_device_remove_stop_bits(struct dasd_device *, int); 614void dasd_device_remove_stop_bits(struct dasd_device *, int);
611 615
616int dasd_device_is_ro(struct dasd_device *);
617
618
612/* externals in dasd_devmap.c */ 619/* externals in dasd_devmap.c */
613extern int dasd_max_devindex; 620extern int dasd_max_devindex;
614extern int dasd_probeonly; 621extern 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)
764static void io_subchannel_register(struct ccw_device *cdev) 764static 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);
820out_err: 821out_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
46config 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
46config CLAW 56config 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
6obj-$(CONFIG_CTCM) += ctcm.o fsm.o 6obj-$(CONFIG_CTCM) += ctcm.o fsm.o
7obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o 7obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
8obj-$(CONFIG_SMSGIUCV) += smsgiucv.o 8obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
9obj-$(CONFIG_SMSGIUCV_EVENT) += smsgiucv_app.o
9obj-$(CONFIG_LCS) += lcs.o 10obj-$(CONFIG_LCS) += lcs.o
10obj-$(CONFIG_CLAW) += claw.o 11obj-$(CONFIG_CLAW) += claw.o
11qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o 12qeth-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
32struct smsg_callback { 32struct 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
39MODULE_AUTHOR 39MODULE_AUTHOR
@@ -100,8 +100,8 @@ static void smsg_message_pending(struct iucv_path *path,
100 kfree(buffer); 100 kfree(buffer);
101} 101}
102 102
103int smsg_register_callback(char *prefix, 103int 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
120void smsg_unregister_callback(char *prefix, 120void 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
177static struct device_driver smsg_driver = { 178static 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
8int smsg_register_callback(char *, void (*)(char *, char *)); 8#define SMSGIUCV_DRV_NAME "SMSGIUCV"
9void smsg_unregister_callback(char *, void (*)(char *, char *)); 9
10int smsg_register_callback(const char *,
11 void (*)(const char *, char *));
12void 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. */
41static char *sender;
42module_param(sender, charp, 0400);
43MODULE_PARM_DESC(sender, "z/VM user ID from which CP SMSGs are accepted");
44
45/* SMSG device representation */
46static struct device *smsg_app_dev;
47
48/* list element for queuing received messages for delivery */
49struct smsg_app_event {
50 struct list_head list;
51 char *buf;
52 char *envp[4];
53};
54
55/* queue for outgoing uevents */
56static LIST_HEAD(smsg_event_queue);
57static DEFINE_SPINLOCK(smsg_event_queue_lock);
58
59static void smsg_app_event_free(struct smsg_app_event *ev)
60{
61 kfree(ev->buf);
62 kfree(ev);
63}
64
65static 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
95static 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}
117static DECLARE_WORK(smsg_event_work, smsg_event_work_fn);
118
119static 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
149static 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;
190fail_put_driver:
191 put_driver(smsgiucv_drv);
192 return rc;
193}
194module_init(smsgiucv_app_init);
195
196static 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}
207module_exit(smsgiucv_app_exit);
208
209MODULE_LICENSE("GPL v2");
210MODULE_DESCRIPTION("Deliver z/VM CP SMSG as uevents");
211MODULE_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