aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd_eckd.c
diff options
context:
space:
mode:
authorStefan Weinhuber <wein@de.ibm.com>2008-08-01 10:39:09 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-08-01 10:39:29 -0400
commit4abb08c24b5fa7b6ad0807c07077f0f216f6788b (patch)
treeeb907a86ecb4ac1171972460e8440f6815a7a037 /drivers/s390/block/dasd_eckd.c
parentc2bb4e5d497823437f0a11d342024ccdc6ff5b0d (diff)
[S390] dasd: Add support for enhanced VM UID
When z/VM provides two virtual devices (minidisks) that reside on the same real device, both will receive the configuration data from the real device and thus get the same uid. To fix this problem, z/VM provides an additional configuration data record that allows to distinguish between minidisks. z/VM APAR VM64273 needs be installed so this fix has an effect. Signed-off-by: Stefan Weinhuber <wein@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r--drivers/s390/block/dasd_eckd.c147
1 files changed, 112 insertions, 35 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 3590fdb5b2fd..773b3fe275b2 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -313,8 +313,8 @@ static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,
313 memset(pfxdata, 0, sizeof(*pfxdata)); 313 memset(pfxdata, 0, sizeof(*pfxdata));
314 /* prefix data */ 314 /* prefix data */
315 pfxdata->format = 0; 315 pfxdata->format = 0;
316 pfxdata->base_address = basepriv->conf_data.ned1.unit_addr; 316 pfxdata->base_address = basepriv->ned->unit_addr;
317 pfxdata->base_lss = basepriv->conf_data.ned1.ID; 317 pfxdata->base_lss = basepriv->ned->ID;
318 pfxdata->validity.define_extend = 1; 318 pfxdata->validity.define_extend = 1;
319 319
320 /* private uid is kept up to date, conf_data may be outdated */ 320 /* private uid is kept up to date, conf_data may be outdated */
@@ -536,36 +536,40 @@ dasd_eckd_cdl_reclen(int recid)
536/* 536/*
537 * Generate device unique id that specifies the physical device. 537 * Generate device unique id that specifies the physical device.
538 */ 538 */
539static int 539static int dasd_eckd_generate_uid(struct dasd_device *device,
540dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) 540 struct dasd_uid *uid)
541{ 541{
542 struct dasd_eckd_private *private; 542 struct dasd_eckd_private *private;
543 struct dasd_eckd_confdata *confdata; 543 int count;
544 544
545 private = (struct dasd_eckd_private *) device->private; 545 private = (struct dasd_eckd_private *) device->private;
546 if (!private) 546 if (!private)
547 return -ENODEV; 547 return -ENODEV;
548 confdata = &private->conf_data; 548 if (!private->ned || !private->gneq)
549 if (!confdata)
550 return -ENODEV; 549 return -ENODEV;
551 550
552 memset(uid, 0, sizeof(struct dasd_uid)); 551 memset(uid, 0, sizeof(struct dasd_uid));
553 memcpy(uid->vendor, confdata->ned1.HDA_manufacturer, 552 memcpy(uid->vendor, private->ned->HDA_manufacturer,
554 sizeof(uid->vendor) - 1); 553 sizeof(uid->vendor) - 1);
555 EBCASC(uid->vendor, sizeof(uid->vendor) - 1); 554 EBCASC(uid->vendor, sizeof(uid->vendor) - 1);
556 memcpy(uid->serial, confdata->ned1.HDA_location, 555 memcpy(uid->serial, private->ned->HDA_location,
557 sizeof(uid->serial) - 1); 556 sizeof(uid->serial) - 1);
558 EBCASC(uid->serial, sizeof(uid->serial) - 1); 557 EBCASC(uid->serial, sizeof(uid->serial) - 1);
559 uid->ssid = confdata->neq.subsystemID; 558 uid->ssid = private->gneq->subsystemID;
560 uid->real_unit_addr = confdata->ned1.unit_addr; 559 uid->real_unit_addr = private->ned->unit_addr;;
561 if (confdata->ned2.sneq.flags == 0x40 && 560 if (private->sneq) {
562 confdata->ned2.sneq.format == 0x0001) { 561 uid->type = private->sneq->sua_flags;
563 uid->type = confdata->ned2.sneq.sua_flags;
564 if (uid->type == UA_BASE_PAV_ALIAS) 562 if (uid->type == UA_BASE_PAV_ALIAS)
565 uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr; 563 uid->base_unit_addr = private->sneq->base_unit_addr;
566 } else { 564 } else {
567 uid->type = UA_BASE_DEVICE; 565 uid->type = UA_BASE_DEVICE;
568 } 566 }
567 if (private->vdsneq) {
568 for (count = 0; count < 16; count++) {
569 sprintf(uid->vduit+2*count, "%02x",
570 private->vdsneq->uit[count]);
571 }
572 }
569 return 0; 573 return 0;
570} 574}
571 575
@@ -623,6 +627,15 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
623 ret = -ENOMEM; 627 ret = -ENOMEM;
624 goto out_error; 628 goto out_error;
625 } 629 }
630
631 /*
632 * buffer has to start with EBCDIC "V1.0" to show
633 * support for virtual device SNEQ
634 */
635 rcd_buf[0] = 0xE5;
636 rcd_buf[1] = 0xF1;
637 rcd_buf[2] = 0x4B;
638 rcd_buf[3] = 0xF0;
626 cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm); 639 cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm);
627 if (IS_ERR(cqr)) { 640 if (IS_ERR(cqr)) {
628 ret = PTR_ERR(cqr); 641 ret = PTR_ERR(cqr);
@@ -646,8 +659,62 @@ out_error:
646 return ret; 659 return ret;
647} 660}
648 661
649static int 662static int dasd_eckd_identify_conf_parts(struct dasd_eckd_private *private)
650dasd_eckd_read_conf(struct dasd_device *device) 663{
664
665 struct dasd_sneq *sneq;
666 int i, count;
667
668 private->ned = NULL;
669 private->sneq = NULL;
670 private->vdsneq = NULL;
671 private->gneq = NULL;
672 count = private->conf_len / sizeof(struct dasd_sneq);
673 sneq = (struct dasd_sneq *)private->conf_data;
674 for (i = 0; i < count; ++i) {
675 if (sneq->flags.identifier == 1 && sneq->format == 1)
676 private->sneq = sneq;
677 else if (sneq->flags.identifier == 1 && sneq->format == 4)
678 private->vdsneq = (struct vd_sneq *)sneq;
679 else if (sneq->flags.identifier == 2)
680 private->gneq = (struct dasd_gneq *)sneq;
681 else if (sneq->flags.identifier == 3 && sneq->res1 == 1)
682 private->ned = (struct dasd_ned *)sneq;
683 sneq++;
684 }
685 if (!private->ned || !private->gneq) {
686 private->ned = NULL;
687 private->sneq = NULL;
688 private->vdsneq = NULL;
689 private->gneq = NULL;
690 return -EINVAL;
691 }
692 return 0;
693
694};
695
696static unsigned char dasd_eckd_path_access(void *conf_data, int conf_len)
697{
698 struct dasd_gneq *gneq;
699 int i, count, found;
700
701 count = conf_len / sizeof(*gneq);
702 gneq = (struct dasd_gneq *)conf_data;
703 found = 0;
704 for (i = 0; i < count; ++i) {
705 if (gneq->flags.identifier == 2) {
706 found = 1;
707 break;
708 }
709 gneq++;
710 }
711 if (found)
712 return ((char *)gneq)[18] & 0x07;
713 else
714 return 0;
715}
716
717static int dasd_eckd_read_conf(struct dasd_device *device)
651{ 718{
652 void *conf_data; 719 void *conf_data;
653 int conf_len, conf_data_saved; 720 int conf_len, conf_data_saved;
@@ -661,7 +728,6 @@ dasd_eckd_read_conf(struct dasd_device *device)
661 path_data->opm = ccw_device_get_path_mask(device->cdev); 728 path_data->opm = ccw_device_get_path_mask(device->cdev);
662 lpm = 0x80; 729 lpm = 0x80;
663 conf_data_saved = 0; 730 conf_data_saved = 0;
664
665 /* get configuration data per operational path */ 731 /* get configuration data per operational path */
666 for (lpm = 0x80; lpm; lpm>>= 1) { 732 for (lpm = 0x80; lpm; lpm>>= 1) {
667 if (lpm & path_data->opm){ 733 if (lpm & path_data->opm){
@@ -678,22 +744,20 @@ dasd_eckd_read_conf(struct dasd_device *device)
678 "data retrieved"); 744 "data retrieved");
679 continue; /* no error */ 745 continue; /* no error */
680 } 746 }
681 if (conf_len != sizeof(struct dasd_eckd_confdata)) {
682 MESSAGE(KERN_WARNING,
683 "sizes of configuration data mismatch"
684 "%d (read) vs %ld (expected)",
685 conf_len,
686 sizeof(struct dasd_eckd_confdata));
687 kfree(conf_data);
688 continue; /* no error */
689 }
690 /* save first valid configuration data */ 747 /* save first valid configuration data */
691 if (!conf_data_saved){ 748 if (!conf_data_saved) {
692 memcpy(&private->conf_data, conf_data, 749 kfree(private->conf_data);
693 sizeof(struct dasd_eckd_confdata)); 750 private->conf_data = conf_data;
751 private->conf_len = conf_len;
752 if (dasd_eckd_identify_conf_parts(private)) {
753 private->conf_data = NULL;
754 private->conf_len = 0;
755 kfree(conf_data);
756 continue;
757 }
694 conf_data_saved++; 758 conf_data_saved++;
695 } 759 }
696 switch (((char *)conf_data)[242] & 0x07){ 760 switch (dasd_eckd_path_access(conf_data, conf_len)) {
697 case 0x02: 761 case 0x02:
698 path_data->npm |= lpm; 762 path_data->npm |= lpm;
699 break; 763 break;
@@ -701,7 +765,8 @@ dasd_eckd_read_conf(struct dasd_device *device)
701 path_data->ppm |= lpm; 765 path_data->ppm |= lpm;
702 break; 766 break;
703 } 767 }
704 kfree(conf_data); 768 if (conf_data != private->conf_data)
769 kfree(conf_data);
705 } 770 }
706 } 771 }
707 return 0; 772 return 0;
@@ -952,6 +1017,7 @@ out_err2:
952 dasd_free_block(device->block); 1017 dasd_free_block(device->block);
953 device->block = NULL; 1018 device->block = NULL;
954out_err1: 1019out_err1:
1020 kfree(private->conf_data);
955 kfree(device->private); 1021 kfree(device->private);
956 device->private = NULL; 1022 device->private = NULL;
957 return rc; 1023 return rc;
@@ -959,7 +1025,17 @@ out_err1:
959 1025
960static void dasd_eckd_uncheck_device(struct dasd_device *device) 1026static void dasd_eckd_uncheck_device(struct dasd_device *device)
961{ 1027{
1028 struct dasd_eckd_private *private;
1029
1030 private = (struct dasd_eckd_private *) device->private;
962 dasd_alias_disconnect_device_from_lcu(device); 1031 dasd_alias_disconnect_device_from_lcu(device);
1032 private->ned = NULL;
1033 private->sneq = NULL;
1034 private->vdsneq = NULL;
1035 private->gneq = NULL;
1036 private->conf_len = 0;
1037 kfree(private->conf_data);
1038 private->conf_data = NULL;
963} 1039}
964 1040
965static struct dasd_ccw_req * 1041static struct dasd_ccw_req *
@@ -1746,9 +1822,10 @@ dasd_eckd_fill_info(struct dasd_device * device,
1746 info->characteristics_size = sizeof(struct dasd_eckd_characteristics); 1822 info->characteristics_size = sizeof(struct dasd_eckd_characteristics);
1747 memcpy(info->characteristics, &private->rdc_data, 1823 memcpy(info->characteristics, &private->rdc_data,
1748 sizeof(struct dasd_eckd_characteristics)); 1824 sizeof(struct dasd_eckd_characteristics));
1749 info->confdata_size = sizeof(struct dasd_eckd_confdata); 1825 info->confdata_size = min((unsigned long)private->conf_len,
1750 memcpy(info->configuration_data, &private->conf_data, 1826 sizeof(info->configuration_data));
1751 sizeof(struct dasd_eckd_confdata)); 1827 memcpy(info->configuration_data, private->conf_data,
1828 info->confdata_size);
1752 return 0; 1829 return 0;
1753} 1830}
1754 1831