diff options
Diffstat (limited to 'drivers/s390')
28 files changed, 703 insertions, 168 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/char/raw3270.c b/drivers/s390/char/raw3270.c index 62ddf5202b79..2a4c566456e7 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
@@ -373,7 +373,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
373 | rq->rc = ccw_device_start(rp->cdev, &rq->ccw, | 373 | rq->rc = ccw_device_start(rp->cdev, &rq->ccw, |
374 | (unsigned long) rq, 0, 0); | 374 | (unsigned long) rq, 0, 0); |
375 | if (rq->rc == 0) | 375 | if (rq->rc == 0) |
376 | return; /* Sucessfully restarted. */ | 376 | return; /* Successfully restarted. */ |
377 | break; | 377 | break; |
378 | case RAW3270_IO_STOP: | 378 | case RAW3270_IO_STOP: |
379 | if (!rq) | 379 | if (!rq) |
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index ec88c59842e3..f6d72e1f2a38 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
@@ -196,7 +196,7 @@ __sclp_start_request(struct sclp_req *req) | |||
196 | req->start_count++; | 196 | req->start_count++; |
197 | 197 | ||
198 | if (rc == 0) { | 198 | if (rc == 0) { |
199 | /* Sucessfully started request */ | 199 | /* Successfully started request */ |
200 | req->status = SCLP_REQ_RUNNING; | 200 | req->status = SCLP_REQ_RUNNING; |
201 | sclp_running_state = sclp_running_state_running; | 201 | sclp_running_state = sclp_running_state_running; |
202 | __sclp_set_request_timer(SCLP_RETRY_INTERVAL * HZ, | 202 | __sclp_set_request_timer(SCLP_RETRY_INTERVAL * HZ, |
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.h b/drivers/s390/net/qeth_core.h index b232693378cd..a3ac4456e0b1 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -649,6 +649,7 @@ struct qeth_card_options { | |||
649 | int performance_stats; | 649 | int performance_stats; |
650 | int rx_sg_cb; | 650 | int rx_sg_cb; |
651 | enum qeth_ipa_isolation_modes isolation; | 651 | enum qeth_ipa_isolation_modes isolation; |
652 | int sniffer; | ||
652 | }; | 653 | }; |
653 | 654 | ||
654 | /* | 655 | /* |
@@ -737,6 +738,7 @@ struct qeth_card { | |||
737 | struct qeth_discipline discipline; | 738 | struct qeth_discipline discipline; |
738 | atomic_t force_alloc_skb; | 739 | atomic_t force_alloc_skb; |
739 | struct service_level qeth_service_level; | 740 | struct service_level qeth_service_level; |
741 | struct qdio_ssqd_desc ssqd; | ||
740 | }; | 742 | }; |
741 | 743 | ||
742 | struct qeth_card_list_struct { | 744 | struct qeth_card_list_struct { |
@@ -811,7 +813,8 @@ int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *, | |||
811 | struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *, | 813 | struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *, |
812 | enum qeth_ipa_cmds, enum qeth_prot_versions); | 814 | enum qeth_ipa_cmds, enum qeth_prot_versions); |
813 | int qeth_query_setadapterparms(struct qeth_card *); | 815 | int qeth_query_setadapterparms(struct qeth_card *); |
814 | int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int, const char *); | 816 | int qeth_check_qdio_errors(struct qeth_card *, struct qdio_buffer *, |
817 | unsigned int, const char *); | ||
815 | void qeth_queue_input_buffer(struct qeth_card *, int); | 818 | void qeth_queue_input_buffer(struct qeth_card *, int); |
816 | struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, | 819 | struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, |
817 | struct qdio_buffer *, struct qdio_buffer_element **, int *, | 820 | struct qdio_buffer *, struct qdio_buffer_element **, int *, |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index d34804d5ece1..7d25bdd443cd 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -269,6 +269,7 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt) | |||
269 | card->qdio.init_pool.buf_count = bufcnt; | 269 | card->qdio.init_pool.buf_count = bufcnt; |
270 | return qeth_alloc_buffer_pool(card); | 270 | return qeth_alloc_buffer_pool(card); |
271 | } | 271 | } |
272 | EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool); | ||
272 | 273 | ||
273 | static int qeth_issue_next_read(struct qeth_card *card) | 274 | static int qeth_issue_next_read(struct qeth_card *card) |
274 | { | 275 | { |
@@ -350,8 +351,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, | |||
350 | if (IS_IPA(iob->data)) { | 351 | if (IS_IPA(iob->data)) { |
351 | cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); | 352 | cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); |
352 | if (IS_IPA_REPLY(cmd)) { | 353 | if (IS_IPA_REPLY(cmd)) { |
353 | if (cmd->hdr.command < IPA_CMD_SETCCID || | 354 | if (cmd->hdr.command != IPA_CMD_SETCCID && |
354 | cmd->hdr.command > IPA_CMD_MODCCID) | 355 | cmd->hdr.command != IPA_CMD_DELCCID && |
356 | cmd->hdr.command != IPA_CMD_MODCCID && | ||
357 | cmd->hdr.command != IPA_CMD_SET_DIAG_ASS) | ||
355 | qeth_issue_ipa_msg(cmd, | 358 | qeth_issue_ipa_msg(cmd, |
356 | cmd->hdr.return_code, card); | 359 | cmd->hdr.return_code, card); |
357 | return cmd; | 360 | return cmd; |
@@ -1100,11 +1103,6 @@ static int qeth_setup_card(struct qeth_card *card) | |||
1100 | card->thread_running_mask = 0; | 1103 | card->thread_running_mask = 0; |
1101 | INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread); | 1104 | INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread); |
1102 | INIT_LIST_HEAD(&card->ip_list); | 1105 | INIT_LIST_HEAD(&card->ip_list); |
1103 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); | ||
1104 | if (!card->ip_tbd_list) { | ||
1105 | QETH_DBF_TEXT(SETUP, 0, "iptbdnom"); | ||
1106 | return -ENOMEM; | ||
1107 | } | ||
1108 | INIT_LIST_HEAD(card->ip_tbd_list); | 1106 | INIT_LIST_HEAD(card->ip_tbd_list); |
1109 | INIT_LIST_HEAD(&card->cmd_waiter_list); | 1107 | INIT_LIST_HEAD(&card->cmd_waiter_list); |
1110 | init_waitqueue_head(&card->wait_q); | 1108 | init_waitqueue_head(&card->wait_q); |
@@ -1138,21 +1136,30 @@ static struct qeth_card *qeth_alloc_card(void) | |||
1138 | QETH_DBF_TEXT(SETUP, 2, "alloccrd"); | 1136 | QETH_DBF_TEXT(SETUP, 2, "alloccrd"); |
1139 | card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL); | 1137 | card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL); |
1140 | if (!card) | 1138 | if (!card) |
1141 | return NULL; | 1139 | goto out; |
1142 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 1140 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
1143 | if (qeth_setup_channel(&card->read)) { | 1141 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); |
1144 | kfree(card); | 1142 | if (!card->ip_tbd_list) { |
1145 | return NULL; | 1143 | QETH_DBF_TEXT(SETUP, 0, "iptbdnom"); |
1146 | } | 1144 | goto out_card; |
1147 | if (qeth_setup_channel(&card->write)) { | ||
1148 | qeth_clean_channel(&card->read); | ||
1149 | kfree(card); | ||
1150 | return NULL; | ||
1151 | } | 1145 | } |
1146 | if (qeth_setup_channel(&card->read)) | ||
1147 | goto out_ip; | ||
1148 | if (qeth_setup_channel(&card->write)) | ||
1149 | goto out_channel; | ||
1152 | card->options.layer2 = -1; | 1150 | card->options.layer2 = -1; |
1153 | card->qeth_service_level.seq_print = qeth_core_sl_print; | 1151 | card->qeth_service_level.seq_print = qeth_core_sl_print; |
1154 | register_service_level(&card->qeth_service_level); | 1152 | register_service_level(&card->qeth_service_level); |
1155 | return card; | 1153 | return card; |
1154 | |||
1155 | out_channel: | ||
1156 | qeth_clean_channel(&card->read); | ||
1157 | out_ip: | ||
1158 | kfree(card->ip_tbd_list); | ||
1159 | out_card: | ||
1160 | kfree(card); | ||
1161 | out: | ||
1162 | return NULL; | ||
1156 | } | 1163 | } |
1157 | 1164 | ||
1158 | static int qeth_determine_card_type(struct qeth_card *card) | 1165 | static int qeth_determine_card_type(struct qeth_card *card) |
@@ -1355,26 +1362,29 @@ static int qeth_read_conf_data(struct qeth_card *card, void **buffer, | |||
1355 | return ret; | 1362 | return ret; |
1356 | } | 1363 | } |
1357 | 1364 | ||
1358 | static int qeth_get_unitaddr(struct qeth_card *card) | 1365 | static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd) |
1359 | { | 1366 | { |
1360 | int length; | 1367 | QETH_DBF_TEXT(SETUP, 2, "cfgunit"); |
1361 | char *prcd; | ||
1362 | int rc; | ||
1363 | |||
1364 | QETH_DBF_TEXT(SETUP, 2, "getunit"); | ||
1365 | rc = qeth_read_conf_data(card, (void **) &prcd, &length); | ||
1366 | if (rc) { | ||
1367 | QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n", | ||
1368 | dev_name(&card->gdev->dev), rc); | ||
1369 | return rc; | ||
1370 | } | ||
1371 | card->info.chpid = prcd[30]; | 1368 | card->info.chpid = prcd[30]; |
1372 | card->info.unit_addr2 = prcd[31]; | 1369 | card->info.unit_addr2 = prcd[31]; |
1373 | card->info.cula = prcd[63]; | 1370 | card->info.cula = prcd[63]; |
1374 | card->info.guestlan = ((prcd[0x10] == _ascebc['V']) && | 1371 | card->info.guestlan = ((prcd[0x10] == _ascebc['V']) && |
1375 | (prcd[0x11] == _ascebc['M'])); | 1372 | (prcd[0x11] == _ascebc['M'])); |
1376 | kfree(prcd); | 1373 | } |
1377 | return 0; | 1374 | |
1375 | static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd) | ||
1376 | { | ||
1377 | QETH_DBF_TEXT(SETUP, 2, "cfgblkt"); | ||
1378 | |||
1379 | if (prcd[74] == 0xF0 && prcd[75] == 0xF0 && prcd[76] == 0xF5) { | ||
1380 | card->info.blkt.time_total = 250; | ||
1381 | card->info.blkt.inter_packet = 5; | ||
1382 | card->info.blkt.inter_packet_jumbo = 15; | ||
1383 | } else { | ||
1384 | card->info.blkt.time_total = 0; | ||
1385 | card->info.blkt.inter_packet = 0; | ||
1386 | card->info.blkt.inter_packet_jumbo = 0; | ||
1387 | } | ||
1378 | } | 1388 | } |
1379 | 1389 | ||
1380 | static void qeth_init_tokens(struct qeth_card *card) | 1390 | static void qeth_init_tokens(struct qeth_card *card) |
@@ -2573,8 +2583,8 @@ int qeth_query_setadapterparms(struct qeth_card *card) | |||
2573 | } | 2583 | } |
2574 | EXPORT_SYMBOL_GPL(qeth_query_setadapterparms); | 2584 | EXPORT_SYMBOL_GPL(qeth_query_setadapterparms); |
2575 | 2585 | ||
2576 | int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, | 2586 | int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf, |
2577 | const char *dbftext) | 2587 | unsigned int qdio_error, const char *dbftext) |
2578 | { | 2588 | { |
2579 | if (qdio_error) { | 2589 | if (qdio_error) { |
2580 | QETH_DBF_TEXT(TRACE, 2, dbftext); | 2590 | QETH_DBF_TEXT(TRACE, 2, dbftext); |
@@ -2584,7 +2594,11 @@ int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, | |||
2584 | QETH_DBF_TEXT_(QERR, 2, " F14=%02X", | 2594 | QETH_DBF_TEXT_(QERR, 2, " F14=%02X", |
2585 | buf->element[14].flags & 0xff); | 2595 | buf->element[14].flags & 0xff); |
2586 | QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error); | 2596 | QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error); |
2587 | return 1; | 2597 | if ((buf->element[15].flags & 0xff) == 0x12) { |
2598 | card->stats.rx_dropped++; | ||
2599 | return 0; | ||
2600 | } else | ||
2601 | return 1; | ||
2588 | } | 2602 | } |
2589 | return 0; | 2603 | return 0; |
2590 | } | 2604 | } |
@@ -2667,7 +2681,7 @@ static int qeth_handle_send_error(struct qeth_card *card, | |||
2667 | qdio_err = 1; | 2681 | qdio_err = 1; |
2668 | } | 2682 | } |
2669 | } | 2683 | } |
2670 | qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr"); | 2684 | qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qouterr"); |
2671 | 2685 | ||
2672 | if (!qdio_err) | 2686 | if (!qdio_err) |
2673 | return QETH_SEND_ERROR_NONE; | 2687 | return QETH_SEND_ERROR_NONE; |
@@ -3509,6 +3523,7 @@ void qeth_tx_timeout(struct net_device *dev) | |||
3509 | { | 3523 | { |
3510 | struct qeth_card *card; | 3524 | struct qeth_card *card; |
3511 | 3525 | ||
3526 | QETH_DBF_TEXT(TRACE, 4, "txtimeo"); | ||
3512 | card = dev->ml_priv; | 3527 | card = dev->ml_priv; |
3513 | card->stats.tx_errors++; | 3528 | card->stats.tx_errors++; |
3514 | qeth_schedule_recovery(card); | 3529 | qeth_schedule_recovery(card); |
@@ -3790,9 +3805,6 @@ static int qeth_qdio_establish(struct qeth_card *card) | |||
3790 | init_data.input_handler = card->discipline.input_handler; | 3805 | init_data.input_handler = card->discipline.input_handler; |
3791 | init_data.output_handler = card->discipline.output_handler; | 3806 | init_data.output_handler = card->discipline.output_handler; |
3792 | init_data.int_parm = (unsigned long) card; | 3807 | init_data.int_parm = (unsigned long) card; |
3793 | init_data.flags = QDIO_INBOUND_0COPY_SBALS | | ||
3794 | QDIO_OUTBOUND_0COPY_SBALS | | ||
3795 | QDIO_USE_OUTBOUND_PCIS; | ||
3796 | init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; | 3808 | init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; |
3797 | init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; | 3809 | init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; |
3798 | 3810 | ||
@@ -3847,9 +3859,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev, | |||
3847 | 3859 | ||
3848 | int qeth_core_hardsetup_card(struct qeth_card *card) | 3860 | int qeth_core_hardsetup_card(struct qeth_card *card) |
3849 | { | 3861 | { |
3850 | struct qdio_ssqd_desc *ssqd; | ||
3851 | int retries = 0; | 3862 | int retries = 0; |
3852 | int mpno = 0; | ||
3853 | int rc; | 3863 | int rc; |
3854 | 3864 | ||
3855 | QETH_DBF_TEXT(SETUP, 2, "hrdsetup"); | 3865 | QETH_DBF_TEXT(SETUP, 2, "hrdsetup"); |
@@ -3882,31 +3892,6 @@ retriable: | |||
3882 | else | 3892 | else |
3883 | goto retry; | 3893 | goto retry; |
3884 | } | 3894 | } |
3885 | |||
3886 | rc = qeth_get_unitaddr(card); | ||
3887 | if (rc) { | ||
3888 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | ||
3889 | return rc; | ||
3890 | } | ||
3891 | |||
3892 | ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); | ||
3893 | if (!ssqd) { | ||
3894 | rc = -ENOMEM; | ||
3895 | goto out; | ||
3896 | } | ||
3897 | rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); | ||
3898 | if (rc == 0) | ||
3899 | mpno = ssqd->pcnt; | ||
3900 | kfree(ssqd); | ||
3901 | |||
3902 | if (mpno) | ||
3903 | mpno = min(mpno - 1, QETH_MAX_PORTNO); | ||
3904 | if (card->info.portno > mpno) { | ||
3905 | QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d" | ||
3906 | "\n.", CARD_BUS_ID(card), card->info.portno); | ||
3907 | rc = -ENODEV; | ||
3908 | goto out; | ||
3909 | } | ||
3910 | qeth_init_tokens(card); | 3895 | qeth_init_tokens(card); |
3911 | qeth_init_func_level(card); | 3896 | qeth_init_func_level(card); |
3912 | rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb); | 3897 | rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb); |
@@ -3990,7 +3975,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, | |||
3990 | struct qdio_buffer_element *element = *__element; | 3975 | struct qdio_buffer_element *element = *__element; |
3991 | int offset = *__offset; | 3976 | int offset = *__offset; |
3992 | struct sk_buff *skb = NULL; | 3977 | struct sk_buff *skb = NULL; |
3993 | int skb_len; | 3978 | int skb_len = 0; |
3994 | void *data_ptr; | 3979 | void *data_ptr; |
3995 | int data_len; | 3980 | int data_len; |
3996 | int headroom = 0; | 3981 | int headroom = 0; |
@@ -4009,20 +3994,24 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, | |||
4009 | *hdr = element->addr + offset; | 3994 | *hdr = element->addr + offset; |
4010 | 3995 | ||
4011 | offset += sizeof(struct qeth_hdr); | 3996 | offset += sizeof(struct qeth_hdr); |
4012 | if (card->options.layer2) { | 3997 | switch ((*hdr)->hdr.l2.id) { |
4013 | if (card->info.type == QETH_CARD_TYPE_OSN) { | 3998 | case QETH_HEADER_TYPE_LAYER2: |
4014 | skb_len = (*hdr)->hdr.osn.pdu_length; | 3999 | skb_len = (*hdr)->hdr.l2.pkt_length; |
4015 | headroom = sizeof(struct qeth_hdr); | 4000 | break; |
4016 | } else { | 4001 | case QETH_HEADER_TYPE_LAYER3: |
4017 | skb_len = (*hdr)->hdr.l2.pkt_length; | ||
4018 | } | ||
4019 | } else { | ||
4020 | skb_len = (*hdr)->hdr.l3.length; | 4002 | skb_len = (*hdr)->hdr.l3.length; |
4021 | if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || | 4003 | if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) || |
4022 | (card->info.link_type == QETH_LINK_TYPE_HSTR)) | 4004 | (card->info.link_type == QETH_LINK_TYPE_HSTR)) |
4023 | headroom = TR_HLEN; | 4005 | headroom = TR_HLEN; |
4024 | else | 4006 | else |
4025 | headroom = ETH_HLEN; | 4007 | headroom = ETH_HLEN; |
4008 | break; | ||
4009 | case QETH_HEADER_TYPE_OSN: | ||
4010 | skb_len = (*hdr)->hdr.osn.pdu_length; | ||
4011 | headroom = sizeof(struct qeth_hdr); | ||
4012 | break; | ||
4013 | default: | ||
4014 | break; | ||
4026 | } | 4015 | } |
4027 | 4016 | ||
4028 | if (!skb_len) | 4017 | if (!skb_len) |
@@ -4177,6 +4166,41 @@ void qeth_core_free_discipline(struct qeth_card *card) | |||
4177 | card->discipline.ccwgdriver = NULL; | 4166 | card->discipline.ccwgdriver = NULL; |
4178 | } | 4167 | } |
4179 | 4168 | ||
4169 | static void qeth_determine_capabilities(struct qeth_card *card) | ||
4170 | { | ||
4171 | int rc; | ||
4172 | int length; | ||
4173 | char *prcd; | ||
4174 | |||
4175 | QETH_DBF_TEXT(SETUP, 2, "detcapab"); | ||
4176 | rc = ccw_device_set_online(CARD_DDEV(card)); | ||
4177 | if (rc) { | ||
4178 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); | ||
4179 | goto out; | ||
4180 | } | ||
4181 | |||
4182 | |||
4183 | rc = qeth_read_conf_data(card, (void **) &prcd, &length); | ||
4184 | if (rc) { | ||
4185 | QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n", | ||
4186 | dev_name(&card->gdev->dev), rc); | ||
4187 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | ||
4188 | goto out_offline; | ||
4189 | } | ||
4190 | qeth_configure_unitaddr(card, prcd); | ||
4191 | qeth_configure_blkt_default(card, prcd); | ||
4192 | kfree(prcd); | ||
4193 | |||
4194 | rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); | ||
4195 | if (rc) | ||
4196 | QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); | ||
4197 | |||
4198 | out_offline: | ||
4199 | ccw_device_set_offline(CARD_DDEV(card)); | ||
4200 | out: | ||
4201 | return; | ||
4202 | } | ||
4203 | |||
4180 | static int qeth_core_probe_device(struct ccwgroup_device *gdev) | 4204 | static int qeth_core_probe_device(struct ccwgroup_device *gdev) |
4181 | { | 4205 | { |
4182 | struct qeth_card *card; | 4206 | struct qeth_card *card; |
@@ -4242,6 +4266,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) | |||
4242 | write_lock_irqsave(&qeth_core_card_list.rwlock, flags); | 4266 | write_lock_irqsave(&qeth_core_card_list.rwlock, flags); |
4243 | list_add_tail(&card->list, &qeth_core_card_list.list); | 4267 | list_add_tail(&card->list, &qeth_core_card_list.list); |
4244 | write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); | 4268 | write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags); |
4269 | |||
4270 | qeth_determine_capabilities(card); | ||
4245 | return 0; | 4271 | return 0; |
4246 | 4272 | ||
4247 | err_card: | 4273 | err_card: |
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 1ba51152f667..104a3351e02b 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h | |||
@@ -156,6 +156,8 @@ enum qeth_ipa_return_codes { | |||
156 | IPA_RC_IP_TABLE_FULL = 0x0002, | 156 | IPA_RC_IP_TABLE_FULL = 0x0002, |
157 | IPA_RC_UNKNOWN_ERROR = 0x0003, | 157 | IPA_RC_UNKNOWN_ERROR = 0x0003, |
158 | IPA_RC_UNSUPPORTED_COMMAND = 0x0004, | 158 | IPA_RC_UNSUPPORTED_COMMAND = 0x0004, |
159 | IPA_RC_TRACE_ALREADY_ACTIVE = 0x0005, | ||
160 | IPA_RC_INVALID_FORMAT = 0x0006, | ||
159 | IPA_RC_DUP_IPV6_REMOTE = 0x0008, | 161 | IPA_RC_DUP_IPV6_REMOTE = 0x0008, |
160 | IPA_RC_DUP_IPV6_HOME = 0x0010, | 162 | IPA_RC_DUP_IPV6_HOME = 0x0010, |
161 | IPA_RC_UNREGISTERED_ADDR = 0x0011, | 163 | IPA_RC_UNREGISTERED_ADDR = 0x0011, |
@@ -196,6 +198,11 @@ enum qeth_ipa_return_codes { | |||
196 | IPA_RC_INVALID_IP_VERSION2 = 0xf001, | 198 | IPA_RC_INVALID_IP_VERSION2 = 0xf001, |
197 | IPA_RC_FFFF = 0xffff | 199 | IPA_RC_FFFF = 0xffff |
198 | }; | 200 | }; |
201 | /* for DELIP */ | ||
202 | #define IPA_RC_IP_ADDRESS_NOT_DEFINED IPA_RC_PRIMARY_ALREADY_DEFINED | ||
203 | /* for SET_DIAGNOSTIC_ASSIST */ | ||
204 | #define IPA_RC_INVALID_SUBCMD IPA_RC_IP_TABLE_FULL | ||
205 | #define IPA_RC_HARDWARE_AUTH_ERROR IPA_RC_UNKNOWN_ERROR | ||
199 | 206 | ||
200 | /* IPA function flags; each flag marks availability of respective function */ | 207 | /* IPA function flags; each flag marks availability of respective function */ |
201 | enum qeth_ipa_funcs { | 208 | enum qeth_ipa_funcs { |
@@ -246,6 +253,7 @@ enum qeth_ipa_setadp_cmd { | |||
246 | IPA_SETADP_SET_SNMP_CONTROL = 0x00000200L, | 253 | IPA_SETADP_SET_SNMP_CONTROL = 0x00000200L, |
247 | IPA_SETADP_QUERY_CARD_INFO = 0x00000400L, | 254 | IPA_SETADP_QUERY_CARD_INFO = 0x00000400L, |
248 | IPA_SETADP_SET_PROMISC_MODE = 0x00000800L, | 255 | IPA_SETADP_SET_PROMISC_MODE = 0x00000800L, |
256 | IPA_SETADP_SET_DIAG_ASSIST = 0x00002000L, | ||
249 | IPA_SETADP_SET_ACCESS_CONTROL = 0x00010000L, | 257 | IPA_SETADP_SET_ACCESS_CONTROL = 0x00010000L, |
250 | }; | 258 | }; |
251 | enum qeth_ipa_mac_ops { | 259 | enum qeth_ipa_mac_ops { |
@@ -424,6 +432,40 @@ struct qeth_create_destroy_address { | |||
424 | __u8 unique_id[8]; | 432 | __u8 unique_id[8]; |
425 | } __attribute__ ((packed)); | 433 | } __attribute__ ((packed)); |
426 | 434 | ||
435 | /* SET DIAGNOSTIC ASSIST IPA Command: *************************************/ | ||
436 | |||
437 | enum qeth_diags_cmds { | ||
438 | QETH_DIAGS_CMD_QUERY = 0x0001, | ||
439 | QETH_DIAGS_CMD_TRAP = 0x0002, | ||
440 | QETH_DIAGS_CMD_TRACE = 0x0004, | ||
441 | QETH_DIAGS_CMD_NOLOG = 0x0008, | ||
442 | QETH_DIAGS_CMD_DUMP = 0x0010, | ||
443 | }; | ||
444 | |||
445 | enum qeth_diags_trace_types { | ||
446 | QETH_DIAGS_TYPE_HIPERSOCKET = 0x02, | ||
447 | }; | ||
448 | |||
449 | enum qeth_diags_trace_cmds { | ||
450 | QETH_DIAGS_CMD_TRACE_ENABLE = 0x0001, | ||
451 | QETH_DIAGS_CMD_TRACE_DISABLE = 0x0002, | ||
452 | QETH_DIAGS_CMD_TRACE_MODIFY = 0x0004, | ||
453 | QETH_DIAGS_CMD_TRACE_REPLACE = 0x0008, | ||
454 | QETH_DIAGS_CMD_TRACE_QUERY = 0x0010, | ||
455 | }; | ||
456 | |||
457 | struct qeth_ipacmd_diagass { | ||
458 | __u32 host_tod2; | ||
459 | __u32:32; | ||
460 | __u16 subcmd_len; | ||
461 | __u16:16; | ||
462 | __u32 subcmd; | ||
463 | __u8 type; | ||
464 | __u8 action; | ||
465 | __u16 options; | ||
466 | __u32:32; | ||
467 | } __attribute__ ((packed)); | ||
468 | |||
427 | /* Header for each IPA command */ | 469 | /* Header for each IPA command */ |
428 | struct qeth_ipacmd_hdr { | 470 | struct qeth_ipacmd_hdr { |
429 | __u8 command; | 471 | __u8 command; |
@@ -452,6 +494,7 @@ struct qeth_ipa_cmd { | |||
452 | struct qeth_create_destroy_address create_destroy_addr; | 494 | struct qeth_create_destroy_address create_destroy_addr; |
453 | struct qeth_ipacmd_setadpparms setadapterparms; | 495 | struct qeth_ipacmd_setadpparms setadapterparms; |
454 | struct qeth_set_routing setrtg; | 496 | struct qeth_set_routing setrtg; |
497 | struct qeth_ipacmd_diagass diagass; | ||
455 | } data; | 498 | } data; |
456 | } __attribute__ ((packed)); | 499 | } __attribute__ ((packed)); |
457 | 500 | ||
@@ -469,7 +512,6 @@ enum qeth_ipa_arp_return_codes { | |||
469 | QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008, | 512 | QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008, |
470 | }; | 513 | }; |
471 | 514 | ||
472 | |||
473 | extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc); | 515 | extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc); |
474 | extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd); | 516 | extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd); |
475 | 517 | ||
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 9ff2b36fdc43..88ae4357136a 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c | |||
@@ -118,7 +118,7 @@ static ssize_t qeth_dev_portno_store(struct device *dev, | |||
118 | { | 118 | { |
119 | struct qeth_card *card = dev_get_drvdata(dev); | 119 | struct qeth_card *card = dev_get_drvdata(dev); |
120 | char *tmp; | 120 | char *tmp; |
121 | unsigned int portno; | 121 | unsigned int portno, limit; |
122 | 122 | ||
123 | if (!card) | 123 | if (!card) |
124 | return -EINVAL; | 124 | return -EINVAL; |
@@ -128,9 +128,11 @@ static ssize_t qeth_dev_portno_store(struct device *dev, | |||
128 | return -EPERM; | 128 | return -EPERM; |
129 | 129 | ||
130 | portno = simple_strtoul(buf, &tmp, 16); | 130 | portno = simple_strtoul(buf, &tmp, 16); |
131 | if (portno > QETH_MAX_PORTNO) { | 131 | if (portno > QETH_MAX_PORTNO) |
132 | return -EINVAL; | ||
133 | limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt); | ||
134 | if (portno > limit) | ||
132 | return -EINVAL; | 135 | return -EINVAL; |
133 | } | ||
134 | 136 | ||
135 | card->info.portno = portno; | 137 | card->info.portno = portno; |
136 | return count; | 138 | return count; |
@@ -537,7 +539,7 @@ static ssize_t qeth_dev_blkt_total_store(struct device *dev, | |||
537 | struct qeth_card *card = dev_get_drvdata(dev); | 539 | struct qeth_card *card = dev_get_drvdata(dev); |
538 | 540 | ||
539 | return qeth_dev_blkt_store(card, buf, count, | 541 | return qeth_dev_blkt_store(card, buf, count, |
540 | &card->info.blkt.time_total, 1000); | 542 | &card->info.blkt.time_total, 5000); |
541 | } | 543 | } |
542 | 544 | ||
543 | 545 | ||
@@ -559,7 +561,7 @@ static ssize_t qeth_dev_blkt_inter_store(struct device *dev, | |||
559 | struct qeth_card *card = dev_get_drvdata(dev); | 561 | struct qeth_card *card = dev_get_drvdata(dev); |
560 | 562 | ||
561 | return qeth_dev_blkt_store(card, buf, count, | 563 | return qeth_dev_blkt_store(card, buf, count, |
562 | &card->info.blkt.inter_packet, 100); | 564 | &card->info.blkt.inter_packet, 1000); |
563 | } | 565 | } |
564 | 566 | ||
565 | static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show, | 567 | static DEVICE_ATTR(inter, 0644, qeth_dev_blkt_inter_show, |
@@ -580,7 +582,7 @@ static ssize_t qeth_dev_blkt_inter_jumbo_store(struct device *dev, | |||
580 | struct qeth_card *card = dev_get_drvdata(dev); | 582 | struct qeth_card *card = dev_get_drvdata(dev); |
581 | 583 | ||
582 | return qeth_dev_blkt_store(card, buf, count, | 584 | return qeth_dev_blkt_store(card, buf, count, |
583 | &card->info.blkt.inter_packet_jumbo, 100); | 585 | &card->info.blkt.inter_packet_jumbo, 1000); |
584 | } | 586 | } |
585 | 587 | ||
586 | static DEVICE_ATTR(inter_jumbo, 0644, qeth_dev_blkt_inter_jumbo_show, | 588 | static DEVICE_ATTR(inter_jumbo, 0644, qeth_dev_blkt_inter_jumbo_show, |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 0b763396d5d1..51fde6f2e0b8 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -486,22 +486,14 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, | |||
486 | case IPA_RC_L2_DUP_MAC: | 486 | case IPA_RC_L2_DUP_MAC: |
487 | case IPA_RC_L2_DUP_LAYER3_MAC: | 487 | case IPA_RC_L2_DUP_LAYER3_MAC: |
488 | dev_warn(&card->gdev->dev, | 488 | dev_warn(&card->gdev->dev, |
489 | "MAC address " | 489 | "MAC address %pM already exists\n", |
490 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " | 490 | card->dev->dev_addr); |
491 | "already exists\n", | ||
492 | card->dev->dev_addr[0], card->dev->dev_addr[1], | ||
493 | card->dev->dev_addr[2], card->dev->dev_addr[3], | ||
494 | card->dev->dev_addr[4], card->dev->dev_addr[5]); | ||
495 | break; | 491 | break; |
496 | case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: | 492 | case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP: |
497 | case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: | 493 | case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP: |
498 | dev_warn(&card->gdev->dev, | 494 | dev_warn(&card->gdev->dev, |
499 | "MAC address " | 495 | "MAC address %pM is not authorized\n", |
500 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " | 496 | card->dev->dev_addr); |
501 | "is not authorized\n", | ||
502 | card->dev->dev_addr[0], card->dev->dev_addr[1], | ||
503 | card->dev->dev_addr[2], card->dev->dev_addr[3], | ||
504 | card->dev->dev_addr[4], card->dev->dev_addr[5]); | ||
505 | break; | 497 | break; |
506 | default: | 498 | default: |
507 | break; | 499 | break; |
@@ -512,12 +504,8 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, | |||
512 | memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac, | 504 | memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac, |
513 | OSA_ADDR_LEN); | 505 | OSA_ADDR_LEN); |
514 | dev_info(&card->gdev->dev, | 506 | dev_info(&card->gdev->dev, |
515 | "MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " | 507 | "MAC address %pM successfully registered on device %s\n", |
516 | "successfully registered on device %s\n", | 508 | card->dev->dev_addr, card->dev->name); |
517 | card->dev->dev_addr[0], card->dev->dev_addr[1], | ||
518 | card->dev->dev_addr[2], card->dev->dev_addr[3], | ||
519 | card->dev->dev_addr[4], card->dev->dev_addr[5], | ||
520 | card->dev->name); | ||
521 | } | 509 | } |
522 | return 0; | 510 | return 0; |
523 | } | 511 | } |
@@ -634,7 +622,7 @@ static void qeth_l2_set_multicast_list(struct net_device *dev) | |||
634 | for (dm = dev->mc_list; dm; dm = dm->next) | 622 | for (dm = dev->mc_list; dm; dm = dm->next) |
635 | qeth_l2_add_mc(card, dm->da_addr, 0); | 623 | qeth_l2_add_mc(card, dm->da_addr, 0); |
636 | 624 | ||
637 | list_for_each_entry(ha, &dev->uc.list, list) | 625 | netdev_for_each_uc_addr(ha, dev) |
638 | qeth_l2_add_mc(card, ha->addr, 1); | 626 | qeth_l2_add_mc(card, ha->addr, 1); |
639 | 627 | ||
640 | spin_unlock_bh(&card->mclock); | 628 | spin_unlock_bh(&card->mclock); |
@@ -781,7 +769,8 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev, | |||
781 | index = i % QDIO_MAX_BUFFERS_PER_Q; | 769 | index = i % QDIO_MAX_BUFFERS_PER_Q; |
782 | buffer = &card->qdio.in_q->bufs[index]; | 770 | buffer = &card->qdio.in_q->bufs[index]; |
783 | if (!(qdio_err && | 771 | if (!(qdio_err && |
784 | qeth_check_qdio_errors(buffer->buffer, qdio_err, "qinerr"))) | 772 | qeth_check_qdio_errors(card, buffer->buffer, qdio_err, |
773 | "qinerr"))) | ||
785 | qeth_l2_process_inbound_buffer(card, buffer, index); | 774 | qeth_l2_process_inbound_buffer(card, buffer, index); |
786 | /* clear buffer and give back to hardware */ | 775 | /* clear buffer and give back to hardware */ |
787 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); | 776 | qeth_put_buffer_pool_entry(card, buffer->pool_entry); |
@@ -938,7 +927,6 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
938 | QETH_DBF_TEXT(SETUP, 2, "setonlin"); | 927 | QETH_DBF_TEXT(SETUP, 2, "setonlin"); |
939 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 928 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
940 | 929 | ||
941 | qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); | ||
942 | recover_flag = card->state; | 930 | recover_flag = card->state; |
943 | rc = qeth_core_hardsetup_card(card); | 931 | rc = qeth_core_hardsetup_card(card); |
944 | if (rc) { | 932 | if (rc) { |
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index 321988fa9f7d..8447d233d0b3 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h | |||
@@ -13,6 +13,8 @@ | |||
13 | 13 | ||
14 | #include "qeth_core.h" | 14 | #include "qeth_core.h" |
15 | 15 | ||
16 | #define QETH_SNIFF_AVAIL 0x0008 | ||
17 | |||
16 | struct qeth_ipaddr { | 18 | struct qeth_ipaddr { |
17 | struct list_head entry; | 19 | struct list_head entry; |
18 | enum qeth_ip_types type; | 20 | enum qeth_ip_types type; |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index fd1b6ed3721f..5475834ab916 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -242,6 +242,8 @@ static int __qeth_l3_insert_ip_todo(struct qeth_card *card, | |||
242 | struct qeth_ipaddr *tmp, *t; | 242 | struct qeth_ipaddr *tmp, *t; |
243 | int found = 0; | 243 | int found = 0; |
244 | 244 | ||
245 | if (card->options.sniffer) | ||
246 | return 0; | ||
245 | list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) { | 247 | list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) { |
246 | if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && | 248 | if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && |
247 | (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) | 249 | (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) |
@@ -457,6 +459,8 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) | |||
457 | QETH_DBF_TEXT(TRACE, 2, "sdiplist"); | 459 | QETH_DBF_TEXT(TRACE, 2, "sdiplist"); |
458 | QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *)); | 460 | QETH_DBF_HEX(TRACE, 2, &card, sizeof(void *)); |
459 | 461 | ||
462 | if (card->options.sniffer) | ||
463 | return; | ||
460 | spin_lock_irqsave(&card->ip_lock, flags); | 464 | spin_lock_irqsave(&card->ip_lock, flags); |
461 | tbd_list = card->ip_tbd_list; | 465 | tbd_list = card->ip_tbd_list; |
462 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); | 466 | card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); |
@@ -495,7 +499,7 @@ static void qeth_l3_set_ip_addr_list(struct qeth_card *card) | |||
495 | spin_unlock_irqrestore(&card->ip_lock, flags); | 499 | spin_unlock_irqrestore(&card->ip_lock, flags); |
496 | rc = qeth_l3_deregister_addr_entry(card, addr); | 500 | rc = qeth_l3_deregister_addr_entry(card, addr); |
497 | spin_lock_irqsave(&card->ip_lock, flags); | 501 | spin_lock_irqsave(&card->ip_lock, flags); |
498 | if (!rc || (rc == IPA_RC_PRIMARY_ALREADY_DEFINED)) | 502 | if (!rc || (rc == IPA_RC_IP_ADDRESS_NOT_DEFINED)) |
499 | kfree(addr); | 503 | kfree(addr); |
500 | else | 504 | else |
501 | list_add_tail(&addr->entry, &card->ip_list); | 505 | list_add_tail(&addr->entry, &card->ip_list); |
@@ -513,6 +517,8 @@ static void qeth_l3_clear_ip_list(struct qeth_card *card, int clean, | |||
513 | unsigned long flags; | 517 | unsigned long flags; |
514 | 518 | ||
515 | QETH_DBF_TEXT(TRACE, 4, "clearip"); | 519 | QETH_DBF_TEXT(TRACE, 4, "clearip"); |
520 | if (recover && card->options.sniffer) | ||
521 | return; | ||
516 | spin_lock_irqsave(&card->ip_lock, flags); | 522 | spin_lock_irqsave(&card->ip_lock, flags); |
517 | /* clear todo list */ | 523 | /* clear todo list */ |
518 | list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) { | 524 | list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry) { |
@@ -1674,6 +1680,76 @@ static int qeth_l3_get_unique_id(struct qeth_card *card) | |||
1674 | return rc; | 1680 | return rc; |
1675 | } | 1681 | } |
1676 | 1682 | ||
1683 | static int | ||
1684 | qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply, | ||
1685 | unsigned long data) | ||
1686 | { | ||
1687 | struct qeth_ipa_cmd *cmd; | ||
1688 | __u16 rc; | ||
1689 | |||
1690 | QETH_DBF_TEXT(SETUP, 2, "diastrcb"); | ||
1691 | |||
1692 | cmd = (struct qeth_ipa_cmd *)data; | ||
1693 | rc = cmd->hdr.return_code; | ||
1694 | if (rc) { | ||
1695 | QETH_DBF_TEXT_(TRACE, 2, "dxter%x", rc); | ||
1696 | if (cmd->data.diagass.action == QETH_DIAGS_CMD_TRACE_ENABLE) { | ||
1697 | switch (rc) { | ||
1698 | case IPA_RC_HARDWARE_AUTH_ERROR: | ||
1699 | dev_warn(&card->gdev->dev, "The device is not " | ||
1700 | "authorized to run as a HiperSockets " | ||
1701 | "network traffic analyzer\n"); | ||
1702 | break; | ||
1703 | case IPA_RC_TRACE_ALREADY_ACTIVE: | ||
1704 | dev_warn(&card->gdev->dev, "A HiperSockets " | ||
1705 | "network traffic analyzer is already " | ||
1706 | "active in the HiperSockets LAN\n"); | ||
1707 | break; | ||
1708 | default: | ||
1709 | break; | ||
1710 | } | ||
1711 | } | ||
1712 | return 0; | ||
1713 | } | ||
1714 | |||
1715 | switch (cmd->data.diagass.action) { | ||
1716 | case QETH_DIAGS_CMD_TRACE_QUERY: | ||
1717 | break; | ||
1718 | case QETH_DIAGS_CMD_TRACE_DISABLE: | ||
1719 | card->info.promisc_mode = SET_PROMISC_MODE_OFF; | ||
1720 | dev_info(&card->gdev->dev, "The HiperSockets network traffic " | ||
1721 | "analyzer is deactivated\n"); | ||
1722 | break; | ||
1723 | case QETH_DIAGS_CMD_TRACE_ENABLE: | ||
1724 | card->info.promisc_mode = SET_PROMISC_MODE_ON; | ||
1725 | dev_info(&card->gdev->dev, "The HiperSockets network traffic " | ||
1726 | "analyzer is activated\n"); | ||
1727 | break; | ||
1728 | default: | ||
1729 | QETH_DBF_MESSAGE(2, "Unknown sniffer action (0x%04x) on %s\n", | ||
1730 | cmd->data.diagass.action, QETH_CARD_IFNAME(card)); | ||
1731 | } | ||
1732 | |||
1733 | return 0; | ||
1734 | } | ||
1735 | |||
1736 | static int | ||
1737 | qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd) | ||
1738 | { | ||
1739 | struct qeth_cmd_buffer *iob; | ||
1740 | struct qeth_ipa_cmd *cmd; | ||
1741 | |||
1742 | QETH_DBF_TEXT(SETUP, 2, "diagtrac"); | ||
1743 | |||
1744 | iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0); | ||
1745 | cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); | ||
1746 | cmd->data.diagass.subcmd_len = 16; | ||
1747 | cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE; | ||
1748 | cmd->data.diagass.type = QETH_DIAGS_TYPE_HIPERSOCKET; | ||
1749 | cmd->data.diagass.action = diags_cmd; | ||
1750 | return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL); | ||
1751 | } | ||
1752 | |||
1677 | static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac, | 1753 | static void qeth_l3_get_mac_for_ipm(__u32 ipm, char *mac, |
1678 | struct net_device *dev) | 1754 | struct net_device *dev) |
1679 | { | 1755 | { |
@@ -1951,7 +2027,10 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, | |||
1951 | case QETH_CAST_ANYCAST: | 2027 | case QETH_CAST_ANYCAST: |
1952 | case QETH_CAST_NOCAST: | 2028 | case QETH_CAST_NOCAST: |
1953 | default: | 2029 | default: |
1954 | skb->pkt_type = PACKET_HOST; | 2030 | if (card->options.sniffer) |
2031 | skb->pkt_type = PACKET_OTHERHOST; | ||
2032 | else | ||
2033 | skb->pkt_type = PACKET_HOST; | ||
1955 | memcpy(tg_addr, card->dev->dev_addr, | 2034 | memcpy(tg_addr, card->dev->dev_addr, |
1956 | card->dev->addr_len); | 2035 | card->dev->addr_len); |
1957 | } | 2036 | } |
@@ -2007,7 +2086,6 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
2007 | int offset; | 2086 | int offset; |
2008 | __u16 vlan_tag = 0; | 2087 | __u16 vlan_tag = 0; |
2009 | unsigned int len; | 2088 | unsigned int len; |
2010 | |||
2011 | /* get first element of current buffer */ | 2089 | /* get first element of current buffer */ |
2012 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; | 2090 | element = (struct qdio_buffer_element *)&buf->buffer->element[0]; |
2013 | offset = 0; | 2091 | offset = 0; |
@@ -2026,7 +2104,7 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
2026 | case QETH_HEADER_TYPE_LAYER3: | 2104 | case QETH_HEADER_TYPE_LAYER3: |
2027 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); | 2105 | vlan_tag = qeth_l3_rebuild_skb(card, skb, hdr); |
2028 | len = skb->len; | 2106 | len = skb->len; |
2029 | if (vlan_tag) | 2107 | if (vlan_tag && !card->options.sniffer) |
2030 | if (card->vlangrp) | 2108 | if (card->vlangrp) |
2031 | vlan_hwaccel_rx(skb, card->vlangrp, | 2109 | vlan_hwaccel_rx(skb, card->vlangrp, |
2032 | vlan_tag); | 2110 | vlan_tag); |
@@ -2037,6 +2115,16 @@ static void qeth_l3_process_inbound_buffer(struct qeth_card *card, | |||
2037 | else | 2115 | else |
2038 | netif_rx(skb); | 2116 | netif_rx(skb); |
2039 | break; | 2117 | break; |
2118 | case QETH_HEADER_TYPE_LAYER2: /* for HiperSockets sniffer */ | ||
2119 | skb->pkt_type = PACKET_HOST; | ||
2120 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
2121 | if (card->options.checksum_type == NO_CHECKSUMMING) | ||
2122 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
2123 | else | ||
2124 | skb->ip_summed = CHECKSUM_NONE; | ||
2125 | len = skb->len; | ||
2126 | netif_receive_skb(skb); | ||
2127 | break; | ||
2040 | default: | 2128 | default: |
2041 | dev_kfree_skb_any(skb); | 2129 | dev_kfree_skb_any(skb); |
2042 | QETH_DBF_TEXT(TRACE, 3, "inbunkno"); | 2130 | QETH_DBF_TEXT(TRACE, 3, "inbunkno"); |
@@ -2118,6 +2206,9 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) | |||
2118 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 2206 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
2119 | 2207 | ||
2120 | qeth_set_allowed_threads(card, 0, 1); | 2208 | qeth_set_allowed_threads(card, 0, 1); |
2209 | if (card->options.sniffer && | ||
2210 | (card->info.promisc_mode == SET_PROMISC_MODE_ON)) | ||
2211 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); | ||
2121 | if (card->read.state == CH_STATE_UP && | 2212 | if (card->read.state == CH_STATE_UP && |
2122 | card->write.state == CH_STATE_UP && | 2213 | card->write.state == CH_STATE_UP && |
2123 | (card->state == CARD_STATE_UP)) { | 2214 | (card->state == CARD_STATE_UP)) { |
@@ -2162,6 +2253,36 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) | |||
2162 | return rc; | 2253 | return rc; |
2163 | } | 2254 | } |
2164 | 2255 | ||
2256 | /* | ||
2257 | * test for and Switch promiscuous mode (on or off) | ||
2258 | * either for guestlan or HiperSocket Sniffer | ||
2259 | */ | ||
2260 | static void | ||
2261 | qeth_l3_handle_promisc_mode(struct qeth_card *card) | ||
2262 | { | ||
2263 | struct net_device *dev = card->dev; | ||
2264 | |||
2265 | if (((dev->flags & IFF_PROMISC) && | ||
2266 | (card->info.promisc_mode == SET_PROMISC_MODE_ON)) || | ||
2267 | (!(dev->flags & IFF_PROMISC) && | ||
2268 | (card->info.promisc_mode == SET_PROMISC_MODE_OFF))) | ||
2269 | return; | ||
2270 | |||
2271 | if (card->info.guestlan) { /* Guestlan trace */ | ||
2272 | if (qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) | ||
2273 | qeth_setadp_promisc_mode(card); | ||
2274 | } else if (card->options.sniffer && /* HiperSockets trace */ | ||
2275 | qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) { | ||
2276 | if (dev->flags & IFF_PROMISC) { | ||
2277 | QETH_DBF_TEXT(TRACE, 3, "+promisc"); | ||
2278 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_ENABLE); | ||
2279 | } else { | ||
2280 | QETH_DBF_TEXT(TRACE, 3, "-promisc"); | ||
2281 | qeth_diags_trace(card, QETH_DIAGS_CMD_TRACE_DISABLE); | ||
2282 | } | ||
2283 | } | ||
2284 | } | ||
2285 | |||
2165 | static void qeth_l3_set_multicast_list(struct net_device *dev) | 2286 | static void qeth_l3_set_multicast_list(struct net_device *dev) |
2166 | { | 2287 | { |
2167 | struct qeth_card *card = dev->ml_priv; | 2288 | struct qeth_card *card = dev->ml_priv; |
@@ -2170,15 +2291,17 @@ static void qeth_l3_set_multicast_list(struct net_device *dev) | |||
2170 | if (qeth_threads_running(card, QETH_RECOVER_THREAD) && | 2291 | if (qeth_threads_running(card, QETH_RECOVER_THREAD) && |
2171 | (card->state != CARD_STATE_UP)) | 2292 | (card->state != CARD_STATE_UP)) |
2172 | return; | 2293 | return; |
2173 | qeth_l3_delete_mc_addresses(card); | 2294 | if (!card->options.sniffer) { |
2174 | qeth_l3_add_multicast_ipv4(card); | 2295 | qeth_l3_delete_mc_addresses(card); |
2296 | qeth_l3_add_multicast_ipv4(card); | ||
2175 | #ifdef CONFIG_QETH_IPV6 | 2297 | #ifdef CONFIG_QETH_IPV6 |
2176 | qeth_l3_add_multicast_ipv6(card); | 2298 | qeth_l3_add_multicast_ipv6(card); |
2177 | #endif | 2299 | #endif |
2178 | qeth_l3_set_ip_addr_list(card); | 2300 | qeth_l3_set_ip_addr_list(card); |
2179 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) | 2301 | if (!qeth_adp_supported(card, IPA_SETADP_SET_PROMISC_MODE)) |
2180 | return; | 2302 | return; |
2181 | qeth_setadp_promisc_mode(card); | 2303 | } |
2304 | qeth_l3_handle_promisc_mode(card); | ||
2182 | } | 2305 | } |
2183 | 2306 | ||
2184 | static const char *qeth_l3_arp_get_error_cause(int *rc) | 2307 | static const char *qeth_l3_arp_get_error_cause(int *rc) |
@@ -2778,8 +2901,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2778 | int nr_frags; | 2901 | int nr_frags; |
2779 | 2902 | ||
2780 | if ((card->info.type == QETH_CARD_TYPE_IQD) && | 2903 | if ((card->info.type == QETH_CARD_TYPE_IQD) && |
2781 | (skb->protocol != htons(ETH_P_IPV6)) && | 2904 | (((skb->protocol != htons(ETH_P_IPV6)) && |
2782 | (skb->protocol != htons(ETH_P_IP))) | 2905 | (skb->protocol != htons(ETH_P_IP))) || |
2906 | card->options.sniffer)) | ||
2783 | goto tx_drop; | 2907 | goto tx_drop; |
2784 | 2908 | ||
2785 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { | 2909 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { |
@@ -3155,7 +3279,7 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev, | |||
3155 | index = i % QDIO_MAX_BUFFERS_PER_Q; | 3279 | index = i % QDIO_MAX_BUFFERS_PER_Q; |
3156 | buffer = &card->qdio.in_q->bufs[index]; | 3280 | buffer = &card->qdio.in_q->bufs[index]; |
3157 | if (!(qdio_err && | 3281 | if (!(qdio_err && |
3158 | qeth_check_qdio_errors(buffer->buffer, | 3282 | qeth_check_qdio_errors(card, buffer->buffer, |
3159 | qdio_err, "qinerr"))) | 3283 | qdio_err, "qinerr"))) |
3160 | qeth_l3_process_inbound_buffer(card, buffer, index); | 3284 | qeth_l3_process_inbound_buffer(card, buffer, index); |
3161 | /* clear buffer and give back to hardware */ | 3285 | /* clear buffer and give back to hardware */ |
@@ -3214,8 +3338,6 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3214 | QETH_DBF_TEXT(SETUP, 2, "setonlin"); | 3338 | QETH_DBF_TEXT(SETUP, 2, "setonlin"); |
3215 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); | 3339 | QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); |
3216 | 3340 | ||
3217 | qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1); | ||
3218 | |||
3219 | recover_flag = card->state; | 3341 | recover_flag = card->state; |
3220 | rc = qeth_core_hardsetup_card(card); | 3342 | rc = qeth_core_hardsetup_card(card); |
3221 | if (rc) { | 3343 | if (rc) { |
@@ -3250,20 +3372,22 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3250 | goto out_remove; | 3372 | goto out_remove; |
3251 | } else | 3373 | } else |
3252 | card->lan_online = 1; | 3374 | card->lan_online = 1; |
3253 | qeth_l3_set_large_send(card, card->options.large_send); | ||
3254 | 3375 | ||
3255 | rc = qeth_l3_setadapter_parms(card); | 3376 | rc = qeth_l3_setadapter_parms(card); |
3256 | if (rc) | 3377 | if (rc) |
3257 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | 3378 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); |
3258 | rc = qeth_l3_start_ipassists(card); | 3379 | if (!card->options.sniffer) { |
3259 | if (rc) | 3380 | rc = qeth_l3_start_ipassists(card); |
3260 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); | 3381 | if (rc) |
3261 | rc = qeth_l3_setrouting_v4(card); | 3382 | QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); |
3262 | if (rc) | 3383 | qeth_l3_set_large_send(card, card->options.large_send); |
3263 | QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); | 3384 | rc = qeth_l3_setrouting_v4(card); |
3264 | rc = qeth_l3_setrouting_v6(card); | 3385 | if (rc) |
3265 | if (rc) | 3386 | QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc); |
3266 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | 3387 | rc = qeth_l3_setrouting_v6(card); |
3388 | if (rc) | ||
3389 | QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc); | ||
3390 | } | ||
3267 | netif_tx_disable(card->dev); | 3391 | netif_tx_disable(card->dev); |
3268 | 3392 | ||
3269 | rc = qeth_init_qdio_queues(card); | 3393 | rc = qeth_init_qdio_queues(card); |
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index 3360b0941aa1..3f08b11274ae 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c | |||
@@ -319,6 +319,61 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev, | |||
319 | static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show, | 319 | static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show, |
320 | qeth_l3_dev_checksum_store); | 320 | qeth_l3_dev_checksum_store); |
321 | 321 | ||
322 | static ssize_t qeth_l3_dev_sniffer_show(struct device *dev, | ||
323 | struct device_attribute *attr, char *buf) | ||
324 | { | ||
325 | struct qeth_card *card = dev_get_drvdata(dev); | ||
326 | |||
327 | if (!card) | ||
328 | return -EINVAL; | ||
329 | |||
330 | return sprintf(buf, "%i\n", card->options.sniffer ? 1 : 0); | ||
331 | } | ||
332 | |||
333 | static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, | ||
334 | struct device_attribute *attr, const char *buf, size_t count) | ||
335 | { | ||
336 | struct qeth_card *card = dev_get_drvdata(dev); | ||
337 | int ret; | ||
338 | unsigned long i; | ||
339 | |||
340 | if (!card) | ||
341 | return -EINVAL; | ||
342 | |||
343 | if (card->info.type != QETH_CARD_TYPE_IQD) | ||
344 | return -EPERM; | ||
345 | |||
346 | if ((card->state != CARD_STATE_DOWN) && | ||
347 | (card->state != CARD_STATE_RECOVER)) | ||
348 | return -EPERM; | ||
349 | |||
350 | ret = strict_strtoul(buf, 16, &i); | ||
351 | if (ret) | ||
352 | return -EINVAL; | ||
353 | switch (i) { | ||
354 | case 0: | ||
355 | card->options.sniffer = i; | ||
356 | break; | ||
357 | case 1: | ||
358 | ret = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd); | ||
359 | if (card->ssqd.qdioac2 & QETH_SNIFF_AVAIL) { | ||
360 | card->options.sniffer = i; | ||
361 | if (card->qdio.init_pool.buf_count != | ||
362 | QETH_IN_BUF_COUNT_MAX) | ||
363 | qeth_realloc_buffer_pool(card, | ||
364 | QETH_IN_BUF_COUNT_MAX); | ||
365 | break; | ||
366 | } else | ||
367 | return -EPERM; | ||
368 | default: /* fall through */ | ||
369 | return -EINVAL; | ||
370 | } | ||
371 | return count; | ||
372 | } | ||
373 | |||
374 | static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, | ||
375 | qeth_l3_dev_sniffer_store); | ||
376 | |||
322 | static ssize_t qeth_l3_dev_large_send_show(struct device *dev, | 377 | static ssize_t qeth_l3_dev_large_send_show(struct device *dev, |
323 | struct device_attribute *attr, char *buf) | 378 | struct device_attribute *attr, char *buf) |
324 | { | 379 | { |
@@ -373,6 +428,7 @@ static struct attribute *qeth_l3_device_attrs[] = { | |||
373 | &dev_attr_broadcast_mode.attr, | 428 | &dev_attr_broadcast_mode.attr, |
374 | &dev_attr_canonical_macaddr.attr, | 429 | &dev_attr_canonical_macaddr.attr, |
375 | &dev_attr_checksumming.attr, | 430 | &dev_attr_checksumming.attr, |
431 | &dev_attr_sniffer.attr, | ||
376 | &dev_attr_large_send.attr, | 432 | &dev_attr_large_send.attr, |
377 | NULL, | 433 | NULL, |
378 | }; | 434 | }; |
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 | ||