diff options
| -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 |
4 files changed, 191 insertions, 20 deletions
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index c1c6f1381150..216bc4fba199 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 ee09ef33d08d..7d5a6cee4bd8 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 ad8524bb7bb3..d5734e976e1c 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 4293ba827523..d4b13e300a76 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 | ||
