aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd_eckd.c
diff options
context:
space:
mode:
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