Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3112

kernel-2.6.18-194.11.1.el5.src.rpm

From: Hans-Joachim Picht <hpicht@redhat.com>
Date: Fri, 4 Apr 2008 19:49:11 +0200
Subject: [s390] dasd: diff z/VM minidisks need a unique UID
Message-id: 20080404174911.GC9759@redhat.com
O-Subject: [RHEL5 U3 PATCH 3/7] s390 - dasd: Different z/VM minidisks on the same real device have the same UID
Bugzilla: 440402
RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com>

Description
============

UIDs are generated based on information about the real device.
Therefore two minidisks defined on the same real device have the same UID.

With the PTF for APAR VM64273 (bugfix for the hypervisor), z/VM provides
a unique  identifier that allows to distinguish between virtual
disks on the same real device.

This patch adds the identifier to the UID. To benefit from this patch,
the corresponding z/VM PTF has to be installed.

Running a kernel which contains this patch without having  the z/VM support
will not cause any problems, but lead to the same behavior as before.

Bugzilla
=========

BZ 440402
https://bugzilla.redhat.com/show_bug.cgi?id=440402

Upstream status of the patch:
=============================

This patch will be posted upstream in the next merge window.
I'll reply to this message as soon as we have a git commit id

Test status:
============
Kernel with patch was built and successfully tested

Please ACK.

With best regards,

Hans

diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 0fd1c13..27f2e0a 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -872,7 +872,8 @@ dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
 static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL);
 
 #define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial    */ 14 + 1 +\
-		     /* SSID   */ 4 + 1 + /* unit addr */ 2 + 1)
+		     /* SSID   */ 4 + 1 + /* unit addr */ 2 + 1 +\
+		     /* vduit  */ 32 + 1)
 
 static ssize_t
 dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -882,11 +883,17 @@ dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
 
 	devmap = dasd_find_busid(dev->bus_id);
 	spin_lock(&dasd_devmap_lock);
-	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
-		snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
-			 devmap->uid.vendor, devmap->uid.serial,
-			 devmap->uid.ssid, devmap->uid.unit_addr);
-	else
+	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) {
+		if (strlen(devmap->uid.vduit) > 0)
+			snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x.%s",
+				 devmap->uid.vendor, devmap->uid.serial,
+				 devmap->uid.ssid, devmap->uid.unit_addr,
+				 devmap->uid.vduit);
+		else
+			snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
+				 devmap->uid.vendor, devmap->uid.serial,
+				 devmap->uid.ssid, devmap->uid.unit_addr);
+	} else
 		uid[0] = 0;
 	spin_unlock(&dasd_devmap_lock);
 
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 97de22b..802eb41 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -52,9 +52,15 @@ MODULE_LICENSE("GPL");
 
 static struct dasd_discipline dasd_eckd_discipline;
 
+#define CONF_BYTES 256
+
 struct dasd_eckd_private {
 	struct dasd_eckd_characteristics rdc_data;
-	struct dasd_eckd_confdata conf_data;
+	u8 conf_data[CONF_BYTES];
+	struct dasd_ned *ned;
+	struct dasd_sneq *sneq;
+	struct vd_sneq *vdsneq;
+	struct dasd_gneq *gneq;
 	struct dasd_eckd_path path_data;
 	struct eckd_count count_area[5];
 	int init_cqr_status;
@@ -458,32 +464,144 @@ static int
 dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
 {
 	struct dasd_eckd_private *private;
-	struct dasd_eckd_confdata *confdata;
+	int count;
 
 	private = (struct dasd_eckd_private *) device->private;
 	if (!private)
 		return -ENODEV;
-	confdata = &private->conf_data;
-	if (!confdata)
+	if (!private->ned || !private->gneq)
 		return -ENODEV;
 
 	memset(uid, 0, sizeof(struct dasd_uid));
-	memcpy(uid->vendor, confdata->ned1.HDA_manufacturer,
+	memcpy(uid->vendor, private->ned->HDA_manufacturer,
 	       sizeof(uid->vendor) - 1);
 	EBCASC(uid->vendor, sizeof(uid->vendor) - 1);
-	memcpy(uid->serial, confdata->ned1.HDA_location,
+	memcpy(uid->serial, private->ned->HDA_location,
 	       sizeof(uid->serial) - 1);
 	EBCASC(uid->serial, sizeof(uid->serial) - 1);
-	uid->ssid = confdata->neq.subsystemID;
-	if (confdata->ned2.sneq.flags == 0x40) {
+	uid->ssid = private->gneq->subsystemID;
+	/* ckeck if device is base PAV alias */
+	if (private->sneq && (private->sneq->sua_flags == 2)) {
 		uid->alias = 1;
-		uid->unit_addr = confdata->ned2.sneq.base_unit_addr;
+		uid->unit_addr = private->sneq->base_unit_addr;
 	} else
-		uid->unit_addr = confdata->ned1.unit_addr;
+		uid->unit_addr = private->ned->unit_addr;
+	if (private->vdsneq)
+		for (count = 0; count < 16; count++)
+			sprintf(uid->vduit+2*count, "%02x",
+				private->vdsneq->uit[count]);
+	return 0;
+}
+
+static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
+						    void *rcd_buffer,
+						    struct ciw *ciw, __u8 lpm)
+{
+	struct dasd_ccw_req *cqr;
+	struct ccw1 *ccw;
+
+	cqr = dasd_smalloc_request("ECKD", 1 /* RCD */, ciw->count, device);
+
+	if (IS_ERR(cqr)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "Could not allocate RCD request");
+		return cqr;
+	}
+
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = ciw->cmd;
+	ccw->cda = (__u32)(addr_t)rcd_buffer;
+	ccw->count = ciw->count;
+
+	cqr->device = device;
+	cqr->expires = 10*HZ;
+	cqr->lpm = lpm;
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+	cqr->retries = 2;
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+	return cqr;
+}
+
+static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
+				   void **rcd_buffer,
+				   int *rcd_buffer_size, __u8 lpm)
+{
+	struct ciw *ciw;
+	char *rcd_buf = NULL;
+	int ret;
+	struct dasd_ccw_req *cqr;
+
+	/*
+	 * scan for RCD command in extended SenseID data
+	 */
+	ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD);
+	if (!ciw || ciw->cmd == 0) {
+		ret = -EOPNOTSUPP;
+		goto out_error;
+	}
+	rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
+	if (!rcd_buf) {
+		ret = -ENOMEM;
+		goto out_error;
+	}
+
+	/*
+	 * buffer has to start with EBCDIC "V1.0" to show
+	 * support for virtual device SNEQ
+	 */
+	rcd_buf[0] = 0xE5;
+	rcd_buf[1] = 0xF1;
+	rcd_buf[2] = 0x4B;
+	rcd_buf[3] = 0xF0;
 
+	cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm);
+	if (IS_ERR(cqr)) {
+		ret =  PTR_ERR(cqr);
+		goto out_error;
+	}
+	ret = dasd_sleep_on(cqr);
+	/*
+	 * on success we update the user input parms
+	 */
+	dasd_sfree_request(cqr, cqr->device);
+	if (ret)
+		goto out_error;
+
+	*rcd_buffer_size = ciw->count;
+	*rcd_buffer = rcd_buf;
 	return 0;
+out_error:
+	kfree(rcd_buf);
+	*rcd_buffer = NULL;
+	*rcd_buffer_size = 0;
+	return ret;
 }
 
+static void dasd_identify_conf_parts(struct dasd_eckd_private *private)
+{
+	struct dasd_sneq *sneq;
+	int i, count;
+
+	private->ned = NULL;
+	private->sneq = NULL;
+	private->vdsneq = NULL;
+	private->gneq = NULL;
+	count = CONF_BYTES / sizeof(struct dasd_sneq);
+	sneq = (struct dasd_sneq *)&private->conf_data;
+	for (i = 0; i < count; i++) {
+		if (sneq->flags.identifier == 1 && sneq->format == 1)
+			private->sneq = sneq;
+		else if (sneq->flags.identifier == 1 && sneq->format == 4)
+			private->vdsneq = (struct vd_sneq *)sneq;
+		else if (sneq->flags.identifier == 2)
+			private->gneq = (struct dasd_gneq *)sneq;
+		else if (sneq->flags.identifier == 3 && sneq->res1 == 1)
+			private->ned = (struct dasd_ned *)sneq;
+		sneq++;
+	}
+};
+
 static int
 dasd_eckd_read_conf(struct dasd_device *device)
 {
@@ -499,11 +617,10 @@ dasd_eckd_read_conf(struct dasd_device *device)
 	path_data->opm = ccw_device_get_path_mask(device->cdev);
 	lpm = 0x80;
 	conf_data_saved = 0;
-
 	/* get configuration data per operational path */
 	for (lpm = 0x80; lpm; lpm>>= 1) {
 		if (lpm & path_data->opm){
-			rc = read_conf_data_lpm(device->cdev, &conf_data,
+			rc = dasd_eckd_read_conf_lpm(device, &conf_data,
 						&conf_len, lpm);
 			if (rc && rc != -EOPNOTSUPP) {	/* -EOPNOTSUPP is ok */
 				MESSAGE(KERN_WARNING,
@@ -516,20 +633,20 @@ dasd_eckd_read_conf(struct dasd_device *device)
 					"data retrieved");
 				continue;	/* no errror */
 			}
-			if (conf_len != sizeof (struct dasd_eckd_confdata)) {
+			if (conf_len != CONF_BYTES) {
 				MESSAGE(KERN_WARNING,
 					"sizes of configuration data mismatch"
-					"%d (read) vs %ld (expected)",
-					conf_len,
-					sizeof (struct dasd_eckd_confdata));
+					"%d (read) vs %d (expected)",
+					conf_len, CONF_BYTES);
 				kfree(conf_data);
 				continue;	/* no errror */
 			}
 			/* save first valid configuration data */
-			if (!conf_data_saved){
+			if (!conf_data_saved) {
 				memcpy(&private->conf_data, conf_data,
-				       sizeof (struct dasd_eckd_confdata));
+				       conf_len);
 				conf_data_saved++;
+				dasd_identify_conf_parts(private);
 			}
 			switch (((char *)conf_data)[242] & 0x07){
 			case 0x02:
@@ -1342,9 +1459,9 @@ dasd_eckd_fill_info(struct dasd_device * device,
 	info->characteristics_size = sizeof(struct dasd_eckd_characteristics);
 	memcpy(info->characteristics, &private->rdc_data,
 	       sizeof(struct dasd_eckd_characteristics));
-	info->confdata_size = sizeof (struct dasd_eckd_confdata);
-	memcpy(info->configuration_data, &private->conf_data,
-	       sizeof (struct dasd_eckd_confdata));
+	info->confdata_size = CONF_BYTES;
+	memcpy(info->configuration_data, private->conf_data,
+	       info->confdata_size);
 	return 0;
 }
 
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 712ff16..47267c9 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -210,131 +210,61 @@ struct dasd_eckd_characteristics {
 	__u8 reserved3[10];
 } __attribute__ ((packed));
 
-struct dasd_eckd_confdata {
+struct dasd_ned {
 	struct {
-		struct {
-			unsigned char identifier:2;
-			unsigned char token_id:1;
-			unsigned char sno_valid:1;
-			unsigned char subst_sno:1;
-			unsigned char recNED:1;
-			unsigned char emuNED:1;
-			unsigned char reserved:1;
-		} __attribute__ ((packed)) flags;
-		__u8 descriptor;
-		__u8 dev_class;
-		__u8 reserved;
-		unsigned char dev_type[6];
-		unsigned char dev_model[3];
-		unsigned char HDA_manufacturer[3];
-		unsigned char HDA_location[2];
-		unsigned char HDA_seqno[12];
-		__u8 ID;
-		__u8 unit_addr;
-	} __attribute__ ((packed)) ned1;
-	union {
-		struct {
-			struct {
-				unsigned char identifier:2;
-				unsigned char token_id:1;
-				unsigned char sno_valid:1;
-				unsigned char subst_sno:1;
-				unsigned char recNED:1;
-				unsigned char emuNED:1;
-				unsigned char reserved:1;
-			} __attribute__ ((packed)) flags;
-			__u8 descriptor;
-			__u8 reserved[2];
-			unsigned char dev_type[6];
-			unsigned char dev_model[3];
-			unsigned char DASD_manufacturer[3];
-			unsigned char DASD_location[2];
-			unsigned char DASD_seqno[12];
-			__u16 ID;
-		} __attribute__ ((packed)) ned;
-		struct {
-			unsigned char flags;            /* byte  0    */
-			unsigned char res2[7];          /* byte  1- 7 */
-			unsigned char sua_flags;	/* byte  8    */
-			__u8 base_unit_addr;            /* byte  9    */
-			unsigned char res3[22];	        /* byte 10-31 */
-		} __attribute__ ((packed)) sneq;
-	} __attribute__ ((packed)) ned2;
+		__u8 identifier:2;
+		__u8 token_id:1;
+		__u8 sno_valid:1;
+		__u8 subst_sno:1;
+		__u8 recNED:1;
+		__u8 emuNED:1;
+		__u8 reserved:1;
+	} __attribute__ ((packed)) flags;
+	__u8 descriptor;
+	__u8 dev_class;
+	__u8 reserved;
+	__u8 dev_type[6];
+	__u8 dev_model[3];
+	__u8 HDA_manufacturer[3];
+	__u8 HDA_location[2];
+	__u8 HDA_seqno[12];
+	__u8 ID;
+	__u8 unit_addr;
+} __attribute__ ((packed));
+
+struct dasd_sneq {
 	struct {
-		struct {
-			unsigned char identifier:2;
-			unsigned char token_id:1;
-			unsigned char sno_valid:1;
-			unsigned char subst_sno:1;
-			unsigned char recNED:1;
-			unsigned char emuNED:1;
-			unsigned char reserved:1;
-		} __attribute__ ((packed)) flags;
-		__u8 descriptor;
-		__u8 reserved[2];
-		unsigned char cont_type[6];
-		unsigned char cont_model[3];
-		unsigned char cont_manufacturer[3];
-		unsigned char cont_location[2];
-		unsigned char cont_seqno[12];
-		__u16 ID;
-	} __attribute__ ((packed)) ned3;
+		__u8 identifier:2;
+		__u8 reserved:6;
+	} __attribute__ ((packed)) flags;
+	__u8 res1;
+	__u16 format;
+	__u8 res2[4];		/* byte  4- 7 */
+	__u8 sua_flags;		/* byte  8    */
+	__u8 base_unit_addr;	/* byte  9    */
+	__u8 res3[22];		/* byte 10-31 */
+} __attribute__ ((packed));
+
+struct vd_sneq {
 	struct {
-		struct {
-			unsigned char identifier:2;
-			unsigned char token_id:1;
-			unsigned char sno_valid:1;
-			unsigned char subst_sno:1;
-			unsigned char recNED:1;
-			unsigned char emuNED:1;
-			unsigned char reserved:1;
-		} __attribute__ ((packed)) flags;
-		__u8 descriptor;
-		__u8 reserved[2];
-		unsigned char cont_type[6];
-		unsigned char empty[3];
-		unsigned char cont_manufacturer[3];
-		unsigned char cont_location[2];
-		unsigned char cont_seqno[12];
-		__u16 ID;
-	} __attribute__ ((packed)) ned4;
-	unsigned char ned5[32];
-	unsigned char ned6[32];
-	unsigned char ned7[32];
+		__u8 identifier:2;
+		__u8 reserved:6;
+	} __attribute__ ((packed)) flags;
+	__u8 res1;
+	__u16 format;
+	__u8 res2[4];   /* byte  4- 7 */
+	__u8 uit[16];	/* byte  8-23 */
+	__u8 res3[8];	/* byte 24-31 */
+} __attribute__ ((packed));
+
+struct dasd_gneq {
 	struct {
-		struct {
-			unsigned char identifier:2;
-			unsigned char reserved:6;
-		} __attribute__ ((packed)) flags;
-		__u8 selector;
-		__u16 interfaceID;
-		__u32 reserved;
-		__u16 subsystemID;
-		struct {
-			unsigned char sp0:1;
-			unsigned char sp1:1;
-			unsigned char reserved:5;
-			unsigned char scluster:1;
-		} __attribute__ ((packed)) spathID;
-		__u8 unit_address;
-		__u8 dev_ID;
-		__u8 dev_address;
-		__u8 adapterID;
-		__u16 link_address;
-		struct {
-			unsigned char parallel:1;
-			unsigned char escon:1;
-			unsigned char reserved:1;
-			unsigned char ficon:1;
-			unsigned char reserved2:4;
-		} __attribute__ ((packed)) protocol_type;
-		struct {
-			unsigned char PID_in_236:1;
-			unsigned char reserved:7;
-		} __attribute__ ((packed)) format_flags;
-		__u8 log_dev_address;
-		unsigned char reserved2[12];
-	} __attribute__ ((packed)) neq;
+		__u8 identifier:2;
+		__u8 reserved:6;
+	} __attribute__ ((packed)) flags;
+	__u8 reserved[7];
+	__u16 subsystemID;
+	__u8 reserved2[22];
 } __attribute__ ((packed));
 
 struct dasd_eckd_path {
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index e94481f..3ade79d 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -272,6 +272,7 @@ struct dasd_uid {
 	char serial[15];
 	__u16 ssid;
 	__u8 unit_addr;
+	char vduit[33];
 };
 
 /*