diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/block/dasd.c | 5 | ||||
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 102 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 51 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.h | 46 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 12 | ||||
-rw-r--r-- | drivers/s390/char/tape_3590.c | 22 | ||||
-rw-r--r-- | drivers/s390/char/tape_std.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 30 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.c | 36 | ||||
-rw-r--r-- | drivers/s390/net/qeth_main.c | 1 | ||||
-rw-r--r-- | drivers/s390/s390mach.c | 34 |
11 files changed, 270 insertions, 70 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index a3bfebcf31e..cfb1fff3787 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -315,6 +315,11 @@ dasd_increase_state(struct dasd_device *device) | |||
315 | rc = dasd_state_basic_to_ready(device); | 315 | rc = dasd_state_basic_to_ready(device); |
316 | 316 | ||
317 | if (!rc && | 317 | if (!rc && |
318 | device->state == DASD_STATE_UNFMT && | ||
319 | device->target > DASD_STATE_UNFMT) | ||
320 | rc = -EPERM; | ||
321 | |||
322 | if (!rc && | ||
318 | device->state == DASD_STATE_READY && | 323 | device->state == DASD_STATE_READY && |
319 | device->target >= DASD_STATE_ONLINE) | 324 | device->target >= DASD_STATE_ONLINE) |
320 | rc = dasd_state_ready_to_online(device); | 325 | rc = dasd_state_ready_to_online(device); |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index c1c6f138115..216bc4fba19 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -45,6 +45,7 @@ struct dasd_devmap { | |||
45 | unsigned int devindex; | 45 | unsigned int devindex; |
46 | unsigned short features; | 46 | unsigned short features; |
47 | struct dasd_device *device; | 47 | struct dasd_device *device; |
48 | struct dasd_uid uid; | ||
48 | }; | 49 | }; |
49 | 50 | ||
50 | /* | 51 | /* |
@@ -716,6 +717,68 @@ dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *bu | |||
716 | 717 | ||
717 | static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL); | 718 | static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL); |
718 | 719 | ||
720 | static ssize_t | ||
721 | dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
722 | { | ||
723 | struct dasd_devmap *devmap; | ||
724 | int alias; | ||
725 | |||
726 | devmap = dasd_find_busid(dev->bus_id); | ||
727 | spin_lock(&dasd_devmap_lock); | ||
728 | if (!IS_ERR(devmap)) | ||
729 | alias = devmap->uid.alias; | ||
730 | else | ||
731 | alias = 0; | ||
732 | spin_unlock(&dasd_devmap_lock); | ||
733 | |||
734 | return sprintf(buf, alias ? "1\n" : "0\n"); | ||
735 | } | ||
736 | |||
737 | static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); | ||
738 | |||
739 | static ssize_t | ||
740 | dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
741 | { | ||
742 | struct dasd_devmap *devmap; | ||
743 | char *vendor; | ||
744 | |||
745 | devmap = dasd_find_busid(dev->bus_id); | ||
746 | spin_lock(&dasd_devmap_lock); | ||
747 | if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) | ||
748 | vendor = devmap->uid.vendor; | ||
749 | else | ||
750 | vendor = ""; | ||
751 | spin_unlock(&dasd_devmap_lock); | ||
752 | |||
753 | return snprintf(buf, PAGE_SIZE, "%s\n", vendor); | ||
754 | } | ||
755 | |||
756 | static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); | ||
757 | |||
758 | #define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial */ 14 + 1 +\ | ||
759 | /* SSID */ 4 + 1 + /* unit addr */ 2 + 1) | ||
760 | |||
761 | static ssize_t | ||
762 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
763 | { | ||
764 | struct dasd_devmap *devmap; | ||
765 | char uid[UID_STRLEN]; | ||
766 | |||
767 | devmap = dasd_find_busid(dev->bus_id); | ||
768 | spin_lock(&dasd_devmap_lock); | ||
769 | if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) | ||
770 | snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x", | ||
771 | devmap->uid.vendor, devmap->uid.serial, | ||
772 | devmap->uid.ssid, devmap->uid.unit_addr); | ||
773 | else | ||
774 | uid[0] = 0; | ||
775 | spin_unlock(&dasd_devmap_lock); | ||
776 | |||
777 | return snprintf(buf, PAGE_SIZE, "%s\n", uid); | ||
778 | } | ||
779 | |||
780 | static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); | ||
781 | |||
719 | /* | 782 | /* |
720 | * extended error-reporting | 783 | * extended error-reporting |
721 | */ | 784 | */ |
@@ -759,6 +822,9 @@ static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store); | |||
759 | static struct attribute * dasd_attrs[] = { | 822 | static struct attribute * dasd_attrs[] = { |
760 | &dev_attr_readonly.attr, | 823 | &dev_attr_readonly.attr, |
761 | &dev_attr_discipline.attr, | 824 | &dev_attr_discipline.attr, |
825 | &dev_attr_alias.attr, | ||
826 | &dev_attr_vendor.attr, | ||
827 | &dev_attr_uid.attr, | ||
762 | &dev_attr_use_diag.attr, | 828 | &dev_attr_use_diag.attr, |
763 | &dev_attr_eer_enabled.attr, | 829 | &dev_attr_eer_enabled.attr, |
764 | NULL, | 830 | NULL, |
@@ -768,6 +834,42 @@ static struct attribute_group dasd_attr_group = { | |||
768 | .attrs = dasd_attrs, | 834 | .attrs = dasd_attrs, |
769 | }; | 835 | }; |
770 | 836 | ||
837 | |||
838 | /* | ||
839 | * Return copy of the device unique identifier. | ||
840 | */ | ||
841 | int | ||
842 | dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) | ||
843 | { | ||
844 | struct dasd_devmap *devmap; | ||
845 | |||
846 | devmap = dasd_find_busid(cdev->dev.bus_id); | ||
847 | if (IS_ERR(devmap)) | ||
848 | return PTR_ERR(devmap); | ||
849 | spin_lock(&dasd_devmap_lock); | ||
850 | *uid = devmap->uid; | ||
851 | spin_unlock(&dasd_devmap_lock); | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | /* | ||
856 | * Register the given device unique identifier into devmap struct. | ||
857 | */ | ||
858 | int | ||
859 | dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) | ||
860 | { | ||
861 | struct dasd_devmap *devmap; | ||
862 | |||
863 | devmap = dasd_find_busid(cdev->dev.bus_id); | ||
864 | if (IS_ERR(devmap)) | ||
865 | return PTR_ERR(devmap); | ||
866 | spin_lock(&dasd_devmap_lock); | ||
867 | devmap->uid = *uid; | ||
868 | spin_unlock(&dasd_devmap_lock); | ||
869 | return 0; | ||
870 | } | ||
871 | EXPORT_SYMBOL(dasd_set_uid); | ||
872 | |||
771 | /* | 873 | /* |
772 | * Return value of the specified feature. | 874 | * Return value of the specified feature. |
773 | */ | 875 | */ |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ee09ef33d08..7d5a6cee4bd 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -446,6 +446,39 @@ dasd_eckd_cdl_reclen(int recid) | |||
446 | return LABEL_SIZE; | 446 | return LABEL_SIZE; |
447 | } | 447 | } |
448 | 448 | ||
449 | /* | ||
450 | * Generate device unique id that specifies the physical device. | ||
451 | */ | ||
452 | static int | ||
453 | dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) | ||
454 | { | ||
455 | struct dasd_eckd_private *private; | ||
456 | struct dasd_eckd_confdata *confdata; | ||
457 | |||
458 | private = (struct dasd_eckd_private *) device->private; | ||
459 | if (!private) | ||
460 | return -ENODEV; | ||
461 | confdata = &private->conf_data; | ||
462 | if (!confdata) | ||
463 | return -ENODEV; | ||
464 | |||
465 | memset(uid, 0, sizeof(struct dasd_uid)); | ||
466 | strncpy(uid->vendor, confdata->ned1.HDA_manufacturer, | ||
467 | sizeof(uid->vendor) - 1); | ||
468 | EBCASC(uid->vendor, sizeof(uid->vendor) - 1); | ||
469 | strncpy(uid->serial, confdata->ned1.HDA_location, | ||
470 | sizeof(uid->serial) - 1); | ||
471 | EBCASC(uid->serial, sizeof(uid->serial) - 1); | ||
472 | uid->ssid = confdata->neq.subsystemID; | ||
473 | if (confdata->ned2.sneq.flags == 0x40) { | ||
474 | uid->alias = 1; | ||
475 | uid->unit_addr = confdata->ned2.sneq.base_unit_addr; | ||
476 | } else | ||
477 | uid->unit_addr = confdata->ned1.unit_addr; | ||
478 | |||
479 | return 0; | ||
480 | } | ||
481 | |||
449 | static int | 482 | static int |
450 | dasd_eckd_read_conf(struct dasd_device *device) | 483 | dasd_eckd_read_conf(struct dasd_device *device) |
451 | { | 484 | { |
@@ -507,11 +540,15 @@ dasd_eckd_read_conf(struct dasd_device *device) | |||
507 | return 0; | 540 | return 0; |
508 | } | 541 | } |
509 | 542 | ||
510 | 543 | /* | |
544 | * Check device characteristics. | ||
545 | * If the device is accessible using ECKD discipline, the device is enabled. | ||
546 | */ | ||
511 | static int | 547 | static int |
512 | dasd_eckd_check_characteristics(struct dasd_device *device) | 548 | dasd_eckd_check_characteristics(struct dasd_device *device) |
513 | { | 549 | { |
514 | struct dasd_eckd_private *private; | 550 | struct dasd_eckd_private *private; |
551 | struct dasd_uid uid; | ||
515 | void *rdc_data; | 552 | void *rdc_data; |
516 | int rc; | 553 | int rc; |
517 | 554 | ||
@@ -536,6 +573,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
536 | 573 | ||
537 | /* Read Device Characteristics */ | 574 | /* Read Device Characteristics */ |
538 | rdc_data = (void *) &(private->rdc_data); | 575 | rdc_data = (void *) &(private->rdc_data); |
576 | memset(rdc_data, 0, sizeof(rdc_data)); | ||
539 | rc = read_dev_chars(device->cdev, &rdc_data, 64); | 577 | rc = read_dev_chars(device->cdev, &rdc_data, 64); |
540 | if (rc) { | 578 | if (rc) { |
541 | DEV_MESSAGE(KERN_WARNING, device, | 579 | DEV_MESSAGE(KERN_WARNING, device, |
@@ -556,8 +594,17 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
556 | 594 | ||
557 | /* Read Configuration Data */ | 595 | /* Read Configuration Data */ |
558 | rc = dasd_eckd_read_conf (device); | 596 | rc = dasd_eckd_read_conf (device); |
559 | return rc; | 597 | if (rc) |
598 | return rc; | ||
599 | |||
600 | /* Generate device unique id and register in devmap */ | ||
601 | rc = dasd_eckd_generate_uid(device, &uid); | ||
602 | if (rc) | ||
603 | return rc; | ||
560 | 604 | ||
605 | rc = dasd_set_uid(device->cdev, &uid); | ||
606 | |||
607 | return rc; | ||
561 | } | 608 | } |
562 | 609 | ||
563 | static struct dasd_ccw_req * | 610 | static struct dasd_ccw_req * |
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index ad8524bb7bb..d5734e976e1 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h | |||
@@ -228,26 +228,36 @@ struct dasd_eckd_confdata { | |||
228 | unsigned char HDA_manufacturer[3]; | 228 | unsigned char HDA_manufacturer[3]; |
229 | unsigned char HDA_location[2]; | 229 | unsigned char HDA_location[2]; |
230 | unsigned char HDA_seqno[12]; | 230 | unsigned char HDA_seqno[12]; |
231 | __u16 ID; | 231 | __u8 ID; |
232 | __u8 unit_addr; | ||
232 | } __attribute__ ((packed)) ned1; | 233 | } __attribute__ ((packed)) ned1; |
233 | struct { | 234 | union { |
234 | struct { | 235 | struct { |
235 | unsigned char identifier:2; | 236 | struct { |
236 | unsigned char token_id:1; | 237 | unsigned char identifier:2; |
237 | unsigned char sno_valid:1; | 238 | unsigned char token_id:1; |
238 | unsigned char subst_sno:1; | 239 | unsigned char sno_valid:1; |
239 | unsigned char recNED:1; | 240 | unsigned char subst_sno:1; |
240 | unsigned char emuNED:1; | 241 | unsigned char recNED:1; |
241 | unsigned char reserved:1; | 242 | unsigned char emuNED:1; |
242 | } __attribute__ ((packed)) flags; | 243 | unsigned char reserved:1; |
243 | __u8 descriptor; | 244 | } __attribute__ ((packed)) flags; |
244 | __u8 reserved[2]; | 245 | __u8 descriptor; |
245 | unsigned char dev_type[6]; | 246 | __u8 reserved[2]; |
246 | unsigned char dev_model[3]; | 247 | unsigned char dev_type[6]; |
247 | unsigned char DASD_manufacturer[3]; | 248 | unsigned char dev_model[3]; |
248 | unsigned char DASD_location[2]; | 249 | unsigned char DASD_manufacturer[3]; |
249 | unsigned char DASD_seqno[12]; | 250 | unsigned char DASD_location[2]; |
250 | __u16 ID; | 251 | unsigned char DASD_seqno[12]; |
252 | __u16 ID; | ||
253 | } __attribute__ ((packed)) ned; | ||
254 | struct { | ||
255 | unsigned char flags; /* byte 0 */ | ||
256 | unsigned char res2[7]; /* byte 1- 7 */ | ||
257 | unsigned char sua_flags; /* byte 8 */ | ||
258 | __u8 base_unit_addr; /* byte 9 */ | ||
259 | unsigned char res3[22]; /* byte 10-31 */ | ||
260 | } __attribute__ ((packed)) sneq; | ||
251 | } __attribute__ ((packed)) ned2; | 261 | } __attribute__ ((packed)) ned2; |
252 | struct { | 262 | struct { |
253 | struct { | 263 | struct { |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 4293ba82752..d4b13e300a7 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -268,6 +268,16 @@ struct dasd_discipline { | |||
268 | 268 | ||
269 | extern struct dasd_discipline *dasd_diag_discipline_pointer; | 269 | extern struct dasd_discipline *dasd_diag_discipline_pointer; |
270 | 270 | ||
271 | /* | ||
272 | * Unique identifier for dasd device. | ||
273 | */ | ||
274 | struct dasd_uid { | ||
275 | __u8 alias; | ||
276 | char vendor[4]; | ||
277 | char serial[15]; | ||
278 | __u16 ssid; | ||
279 | __u8 unit_addr; | ||
280 | }; | ||
271 | 281 | ||
272 | /* | 282 | /* |
273 | * Notification numbers for extended error reporting notifications: | 283 | * Notification numbers for extended error reporting notifications: |
@@ -516,6 +526,8 @@ void dasd_devmap_exit(void); | |||
516 | struct dasd_device *dasd_create_device(struct ccw_device *); | 526 | struct dasd_device *dasd_create_device(struct ccw_device *); |
517 | void dasd_delete_device(struct dasd_device *); | 527 | void dasd_delete_device(struct dasd_device *); |
518 | 528 | ||
529 | int dasd_get_uid(struct ccw_device *, struct dasd_uid *); | ||
530 | int dasd_set_uid(struct ccw_device *, struct dasd_uid *); | ||
519 | int dasd_get_feature(struct ccw_device *, int); | 531 | int dasd_get_feature(struct ccw_device *, int); |
520 | int dasd_set_feature(struct ccw_device *, int, int); | 532 | int dasd_set_feature(struct ccw_device *, int, int); |
521 | 533 | ||
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index c3915f60a3a..d71ef1adea5 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c | |||
@@ -230,14 +230,16 @@ tape_3590_read_attmsg(struct tape_device *device) | |||
230 | * These functions are used to schedule follow-up actions from within an | 230 | * These functions are used to schedule follow-up actions from within an |
231 | * interrupt context (like unsolicited interrupts). | 231 | * interrupt context (like unsolicited interrupts). |
232 | */ | 232 | */ |
233 | struct work_handler_data { | ||
234 | struct tape_device *device; | ||
235 | enum tape_op op; | ||
236 | struct work_struct work; | ||
237 | }; | ||
238 | |||
233 | static void | 239 | static void |
234 | tape_3590_work_handler(void *data) | 240 | tape_3590_work_handler(void *data) |
235 | { | 241 | { |
236 | struct { | 242 | struct work_handler_data *p = data; |
237 | struct tape_device *device; | ||
238 | enum tape_op op; | ||
239 | struct work_struct work; | ||
240 | } *p = data; | ||
241 | 243 | ||
242 | switch (p->op) { | 244 | switch (p->op) { |
243 | case TO_MSEN: | 245 | case TO_MSEN: |
@@ -257,11 +259,7 @@ tape_3590_work_handler(void *data) | |||
257 | static int | 259 | static int |
258 | tape_3590_schedule_work(struct tape_device *device, enum tape_op op) | 260 | tape_3590_schedule_work(struct tape_device *device, enum tape_op op) |
259 | { | 261 | { |
260 | struct { | 262 | struct work_handler_data *p; |
261 | struct tape_device *device; | ||
262 | enum tape_op op; | ||
263 | struct work_struct work; | ||
264 | } *p; | ||
265 | 263 | ||
266 | if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL) | 264 | if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL) |
267 | return -ENOMEM; | 265 | return -ENOMEM; |
@@ -316,7 +314,7 @@ tape_3590_bread(struct tape_device *device, struct request *req) | |||
316 | 314 | ||
317 | rq_for_each_bio(bio, req) { | 315 | rq_for_each_bio(bio, req) { |
318 | bio_for_each_segment(bv, bio, i) { | 316 | bio_for_each_segment(bv, bio, i) { |
319 | dst = kmap(bv->bv_page) + bv->bv_offset; | 317 | dst = page_address(bv->bv_page) + bv->bv_offset; |
320 | for (off = 0; off < bv->bv_len; | 318 | for (off = 0; off < bv->bv_len; |
321 | off += TAPEBLOCK_HSEC_SIZE) { | 319 | off += TAPEBLOCK_HSEC_SIZE) { |
322 | ccw->flags = CCW_FLAG_CC; | 320 | ccw->flags = CCW_FLAG_CC; |
@@ -1168,6 +1166,7 @@ tape_3590_setup_device(struct tape_device *device) | |||
1168 | static void | 1166 | static void |
1169 | tape_3590_cleanup_device(struct tape_device *device) | 1167 | tape_3590_cleanup_device(struct tape_device *device) |
1170 | { | 1168 | { |
1169 | flush_scheduled_work(); | ||
1171 | tape_std_unassign(device); | 1170 | tape_std_unassign(device); |
1172 | 1171 | ||
1173 | kfree(device->discdata); | 1172 | kfree(device->discdata); |
@@ -1234,6 +1233,7 @@ static struct tape_discipline tape_discipline_3590 = { | |||
1234 | 1233 | ||
1235 | static struct ccw_device_id tape_3590_ids[] = { | 1234 | static struct ccw_device_id tape_3590_ids[] = { |
1236 | {CCW_DEVICE_DEVTYPE(0x3590, 0, 0x3590, 0), .driver_info = tape_3590}, | 1235 | {CCW_DEVICE_DEVTYPE(0x3590, 0, 0x3590, 0), .driver_info = tape_3590}, |
1236 | {CCW_DEVICE_DEVTYPE(0x3592, 0, 0x3592, 0), .driver_info = tape_3592}, | ||
1237 | { /* end of list */ } | 1237 | { /* end of list */ } |
1238 | }; | 1238 | }; |
1239 | 1239 | ||
diff --git a/drivers/s390/char/tape_std.h b/drivers/s390/char/tape_std.h index 2d311798edf..1fc95235934 100644 --- a/drivers/s390/char/tape_std.h +++ b/drivers/s390/char/tape_std.h | |||
@@ -153,6 +153,7 @@ enum s390_tape_type { | |||
153 | tape_3480, | 153 | tape_3480, |
154 | tape_3490, | 154 | tape_3490, |
155 | tape_3590, | 155 | tape_3590, |
156 | tape_3592, | ||
156 | }; | 157 | }; |
157 | 158 | ||
158 | #endif // _TAPE_STD_H | 159 | #endif // _TAPE_STD_H |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 6412b2c3edd..72187e54dca 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -242,28 +242,10 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) | |||
242 | if (sch->vpm == mask) | 242 | if (sch->vpm == mask) |
243 | goto out_unreg; | 243 | goto out_unreg; |
244 | 244 | ||
245 | if ((sch->schib.scsw.actl & (SCSW_ACTL_CLEAR_PEND | | 245 | if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) && |
246 | SCSW_ACTL_HALT_PEND | | 246 | (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) && |
247 | SCSW_ACTL_START_PEND | | 247 | (sch->schib.pmcw.lpum == mask) && |
248 | SCSW_ACTL_RESUME_PEND)) && | 248 | (sch->vpm == 0)) { |
249 | (sch->schib.pmcw.lpum == mask)) { | ||
250 | int cc = cio_cancel(sch); | ||
251 | |||
252 | if (cc == -ENODEV) | ||
253 | goto out_unreg; | ||
254 | |||
255 | if (cc == -EINVAL) { | ||
256 | cc = cio_clear(sch); | ||
257 | if (cc == -ENODEV) | ||
258 | goto out_unreg; | ||
259 | /* Call handler. */ | ||
260 | if (sch->driver && sch->driver->termination) | ||
261 | sch->driver->termination(&sch->dev); | ||
262 | goto out_unlock; | ||
263 | } | ||
264 | } else if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) && | ||
265 | (sch->schib.scsw.actl & SCSW_ACTL_SCHACT) && | ||
266 | (sch->schib.pmcw.lpum == mask)) { | ||
267 | int cc; | 249 | int cc; |
268 | 250 | ||
269 | cc = cio_clear(sch); | 251 | cc = cio_clear(sch); |
@@ -653,13 +635,13 @@ __chp_add(struct subchannel_id schid, void *data) | |||
653 | if (sch->schib.pmcw.chpid[i] == chp->id) { | 635 | if (sch->schib.pmcw.chpid[i] == chp->id) { |
654 | if (stsch(sch->schid, &sch->schib) != 0) { | 636 | if (stsch(sch->schid, &sch->schib) != 0) { |
655 | /* Endgame. */ | 637 | /* Endgame. */ |
656 | spin_unlock(&sch->lock); | 638 | spin_unlock_irq(&sch->lock); |
657 | return -ENXIO; | 639 | return -ENXIO; |
658 | } | 640 | } |
659 | break; | 641 | break; |
660 | } | 642 | } |
661 | if (i==8) { | 643 | if (i==8) { |
662 | spin_unlock(&sch->lock); | 644 | spin_unlock_irq(&sch->lock); |
663 | return 0; | 645 | return 0; |
664 | } | 646 | } |
665 | sch->lpm = ((sch->schib.pmcw.pim & | 647 | sch->lpm = ((sch->schib.pmcw.pim & |
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 814f9258ce0..96f519281d9 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
39 | #include <linux/proc_fs.h> | 39 | #include <linux/proc_fs.h> |
40 | #include <linux/timer.h> | 40 | #include <linux/timer.h> |
41 | #include <linux/mempool.h> | ||
41 | 42 | ||
42 | #include <asm/ccwdev.h> | 43 | #include <asm/ccwdev.h> |
43 | #include <asm/io.h> | 44 | #include <asm/io.h> |
@@ -80,6 +81,8 @@ static int indicator_used[INDICATORS_PER_CACHELINE]; | |||
80 | static __u32 * volatile indicators; | 81 | static __u32 * volatile indicators; |
81 | static __u32 volatile spare_indicator; | 82 | static __u32 volatile spare_indicator; |
82 | static atomic_t spare_indicator_usecount; | 83 | static atomic_t spare_indicator_usecount; |
84 | #define QDIO_MEMPOOL_SCSSC_ELEMENTS 2 | ||
85 | static mempool_t *qdio_mempool_scssc; | ||
83 | 86 | ||
84 | static debug_info_t *qdio_dbf_setup; | 87 | static debug_info_t *qdio_dbf_setup; |
85 | static debug_info_t *qdio_dbf_sbal; | 88 | static debug_info_t *qdio_dbf_sbal; |
@@ -1637,7 +1640,7 @@ next: | |||
1637 | 1640 | ||
1638 | } | 1641 | } |
1639 | kfree(irq_ptr->qdr); | 1642 | kfree(irq_ptr->qdr); |
1640 | kfree(irq_ptr); | 1643 | free_page((unsigned long) irq_ptr); |
1641 | } | 1644 | } |
1642 | 1645 | ||
1643 | static void | 1646 | static void |
@@ -2304,7 +2307,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr) | |||
2304 | 2307 | ||
2305 | QDIO_DBF_TEXT0(0,setup,"getssqd"); | 2308 | QDIO_DBF_TEXT0(0,setup,"getssqd"); |
2306 | qdioac = 0; | 2309 | qdioac = 0; |
2307 | ssqd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 2310 | ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); |
2308 | if (!ssqd_area) { | 2311 | if (!ssqd_area) { |
2309 | QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \ | 2312 | QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \ |
2310 | "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no); | 2313 | "SIGAs for sch x%x.\n", irq_ptr->schid.sch_no); |
@@ -2364,7 +2367,7 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr) | |||
2364 | out: | 2367 | out: |
2365 | qdio_check_subchannel_qebsm(irq_ptr, qdioac, | 2368 | qdio_check_subchannel_qebsm(irq_ptr, qdioac, |
2366 | ssqd_area->sch_token); | 2369 | ssqd_area->sch_token); |
2367 | free_page ((unsigned long) ssqd_area); | 2370 | mempool_free(ssqd_area, qdio_mempool_scssc); |
2368 | irq_ptr->qdioac = qdioac; | 2371 | irq_ptr->qdioac = qdioac; |
2369 | } | 2372 | } |
2370 | 2373 | ||
@@ -2458,7 +2461,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) | |||
2458 | virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind); | 2461 | virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind); |
2459 | } | 2462 | } |
2460 | 2463 | ||
2461 | scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 2464 | scssc_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); |
2462 | if (!scssc_area) { | 2465 | if (!scssc_area) { |
2463 | QDIO_PRINT_WARN("No memory for setting indicators on " \ | 2466 | QDIO_PRINT_WARN("No memory for setting indicators on " \ |
2464 | "subchannel 0.%x.%x.\n", | 2467 | "subchannel 0.%x.%x.\n", |
@@ -2514,7 +2517,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) | |||
2514 | QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long)); | 2517 | QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long)); |
2515 | result = 0; | 2518 | result = 0; |
2516 | out: | 2519 | out: |
2517 | free_page ((unsigned long) scssc_area); | 2520 | mempool_free(scssc_area, qdio_mempool_scssc); |
2518 | return result; | 2521 | return result; |
2519 | 2522 | ||
2520 | } | 2523 | } |
@@ -2543,7 +2546,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target) | |||
2543 | if (!irq_ptr->is_thinint_irq) | 2546 | if (!irq_ptr->is_thinint_irq) |
2544 | return -ENODEV; | 2547 | return -ENODEV; |
2545 | 2548 | ||
2546 | scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 2549 | scsscf_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC); |
2547 | if (!scsscf_area) { | 2550 | if (!scsscf_area) { |
2548 | QDIO_PRINT_WARN("No memory for setting delay target on " \ | 2551 | QDIO_PRINT_WARN("No memory for setting delay target on " \ |
2549 | "subchannel 0.%x.%x.\n", | 2552 | "subchannel 0.%x.%x.\n", |
@@ -2581,7 +2584,7 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target) | |||
2581 | QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long)); | 2584 | QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long)); |
2582 | result = 0; /* not critical */ | 2585 | result = 0; /* not critical */ |
2583 | out: | 2586 | out: |
2584 | free_page ((unsigned long) scsscf_area); | 2587 | mempool_free(scsscf_area, qdio_mempool_scssc); |
2585 | return result; | 2588 | return result; |
2586 | } | 2589 | } |
2587 | 2590 | ||
@@ -2980,7 +2983,7 @@ qdio_allocate(struct qdio_initialize *init_data) | |||
2980 | qdio_allocate_do_dbf(init_data); | 2983 | qdio_allocate_do_dbf(init_data); |
2981 | 2984 | ||
2982 | /* create irq */ | 2985 | /* create irq */ |
2983 | irq_ptr = kzalloc(sizeof(struct qdio_irq), GFP_KERNEL | GFP_DMA); | 2986 | irq_ptr = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); |
2984 | 2987 | ||
2985 | QDIO_DBF_TEXT0(0,setup,"irq_ptr:"); | 2988 | QDIO_DBF_TEXT0(0,setup,"irq_ptr:"); |
2986 | QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*)); | 2989 | QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*)); |
@@ -2995,7 +2998,7 @@ qdio_allocate(struct qdio_initialize *init_data) | |||
2995 | /* QDR must be in DMA area since CCW data address is only 32 bit */ | 2998 | /* QDR must be in DMA area since CCW data address is only 32 bit */ |
2996 | irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA); | 2999 | irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA); |
2997 | if (!(irq_ptr->qdr)) { | 3000 | if (!(irq_ptr->qdr)) { |
2998 | kfree(irq_ptr); | 3001 | free_page((unsigned long) irq_ptr); |
2999 | QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n"); | 3002 | QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n"); |
3000 | return -ENOMEM; | 3003 | return -ENOMEM; |
3001 | } | 3004 | } |
@@ -3780,6 +3783,16 @@ oom: | |||
3780 | return -ENOMEM; | 3783 | return -ENOMEM; |
3781 | } | 3784 | } |
3782 | 3785 | ||
3786 | static void *qdio_mempool_alloc(gfp_t gfp_mask, void *size) | ||
3787 | { | ||
3788 | return (void *) get_zeroed_page(gfp_mask|GFP_DMA); | ||
3789 | } | ||
3790 | |||
3791 | static void qdio_mempool_free(void *element, void *size) | ||
3792 | { | ||
3793 | free_page((unsigned long) element); | ||
3794 | } | ||
3795 | |||
3783 | static int __init | 3796 | static int __init |
3784 | init_QDIO(void) | 3797 | init_QDIO(void) |
3785 | { | 3798 | { |
@@ -3809,6 +3822,10 @@ init_QDIO(void) | |||
3809 | 3822 | ||
3810 | qdio_add_procfs_entry(); | 3823 | qdio_add_procfs_entry(); |
3811 | 3824 | ||
3825 | qdio_mempool_scssc = mempool_create(QDIO_MEMPOOL_SCSSC_ELEMENTS, | ||
3826 | qdio_mempool_alloc, | ||
3827 | qdio_mempool_free, NULL); | ||
3828 | |||
3812 | if (tiqdio_check_chsc_availability()) | 3829 | if (tiqdio_check_chsc_availability()) |
3813 | QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n"); | 3830 | QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n"); |
3814 | 3831 | ||
@@ -3824,6 +3841,7 @@ cleanup_QDIO(void) | |||
3824 | qdio_remove_procfs_entry(); | 3841 | qdio_remove_procfs_entry(); |
3825 | qdio_release_qdio_memory(); | 3842 | qdio_release_qdio_memory(); |
3826 | qdio_unregister_dbf_views(); | 3843 | qdio_unregister_dbf_views(); |
3844 | mempool_destroy(qdio_mempool_scssc); | ||
3827 | 3845 | ||
3828 | printk("qdio: %s: module removed\n",version); | 3846 | printk("qdio: %s: module removed\n",version); |
3829 | } | 3847 | } |
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index b3c6e790779..cb14642d97a 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c | |||
@@ -8014,7 +8014,6 @@ static int (*qeth_old_arp_constructor) (struct neighbour *); | |||
8014 | 8014 | ||
8015 | static struct neigh_ops arp_direct_ops_template = { | 8015 | static struct neigh_ops arp_direct_ops_template = { |
8016 | .family = AF_INET, | 8016 | .family = AF_INET, |
8017 | .destructor = NULL, | ||
8018 | .solicit = NULL, | 8017 | .solicit = NULL, |
8019 | .error_report = NULL, | 8018 | .error_report = NULL, |
8020 | .output = dev_queue_xmit, | 8019 | .output = dev_queue_xmit, |
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 3bf46660351..f99e55308b3 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <linux/time.h> | ||
16 | 17 | ||
17 | #include <asm/lowcore.h> | 18 | #include <asm/lowcore.h> |
18 | 19 | ||
@@ -362,12 +363,19 @@ s390_revalidate_registers(struct mci *mci) | |||
362 | return kill_task; | 363 | return kill_task; |
363 | } | 364 | } |
364 | 365 | ||
366 | #define MAX_IPD_COUNT 29 | ||
367 | #define MAX_IPD_TIME (5 * 60 * USEC_PER_SEC) /* 5 minutes */ | ||
368 | |||
365 | /* | 369 | /* |
366 | * machine check handler. | 370 | * machine check handler. |
367 | */ | 371 | */ |
368 | void | 372 | void |
369 | s390_do_machine_check(struct pt_regs *regs) | 373 | s390_do_machine_check(struct pt_regs *regs) |
370 | { | 374 | { |
375 | static DEFINE_SPINLOCK(ipd_lock); | ||
376 | static unsigned long long last_ipd; | ||
377 | static int ipd_count; | ||
378 | unsigned long long tmp; | ||
371 | struct mci *mci; | 379 | struct mci *mci; |
372 | struct mcck_struct *mcck; | 380 | struct mcck_struct *mcck; |
373 | int umode; | 381 | int umode; |
@@ -404,11 +412,27 @@ s390_do_machine_check(struct pt_regs *regs) | |||
404 | s390_handle_damage("processing backup machine " | 412 | s390_handle_damage("processing backup machine " |
405 | "check with damage."); | 413 | "check with damage."); |
406 | } | 414 | } |
407 | if (!umode) | 415 | |
408 | s390_handle_damage("processing backup machine " | 416 | /* |
409 | "check in kernel mode."); | 417 | * Nullifying exigent condition, therefore we might |
410 | mcck->kill_task = 1; | 418 | * retry this instruction. |
411 | mcck->mcck_code = *(unsigned long long *) mci; | 419 | */ |
420 | |||
421 | spin_lock(&ipd_lock); | ||
422 | |||
423 | tmp = get_clock(); | ||
424 | |||
425 | if (((tmp - last_ipd) >> 12) < MAX_IPD_TIME) | ||
426 | ipd_count++; | ||
427 | else | ||
428 | ipd_count = 1; | ||
429 | |||
430 | last_ipd = tmp; | ||
431 | |||
432 | if (ipd_count == MAX_IPD_COUNT) | ||
433 | s390_handle_damage("too many ipd retries."); | ||
434 | |||
435 | spin_unlock(&ipd_lock); | ||
412 | } | 436 | } |
413 | else { | 437 | else { |
414 | /* Processing damage -> stopping machine */ | 438 | /* Processing damage -> stopping machine */ |