Description: dasdview, fdasd: fix floating point error for unformatted devices
Symptom:     When executed on an unformatted device the tools dasdview and fdasd
             will end with an floating point exception error.
Problem:     The reason for the error lies in the fact that we cannot rely on
             the HDIO_GETGEO ioctl to report a correct number of cylinders and
             so we compute the number of cylinders from the device size.
             However, for unformatted devices the device size is zero and thus
             our computation ends with a floating point exception.
Solution:    To solve this issue read the correct number of cylinders from
             the DASD device characteristics, which can be found in the data
             returned by the BIODASDINFO ioctl.
---
 dasdview/dasdview.c |   22 +++++++--------
 dasdview/dasdview.h |   74 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 fdasd/fdasd.c       |   18 ++++++------
 fdasd/fdasd.h       |   74 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 168 insertions(+), 20 deletions(-)

Index: s390-tools-sles11/dasdview/dasdview.c
===================================================================
--- s390-tools-sles11.orig/dasdview/dasdview.c
+++ s390-tools-sles11/dasdview/dasdview.c
@@ -169,7 +169,7 @@ static void
 dasdview_get_info(dasdview_info_t *info)
 {
 	int fd;
-	u_int64_t device_size;
+	struct dasd_eckd_characteristics *characteristics;
 
 	fd = open(info->device, O_RDONLY);
 	if (fd == -1)
@@ -201,16 +201,6 @@ dasdview_get_info(dasdview_info_t *info)
 		exit(-1);
 	}
 
-	if (ioctl(fd, BLKGETSIZE64, &device_size) != 0) {
-		close(fd);
-		zt_error_print("dasdview: ioctl error\n" \
-			"Could not retrieve device size information.\n");
-		exit(-1);
-	}
-
-	info->hw_cylinders = ((device_size / info->blksize)
-			      / info->geo.sectors) / info->geo.heads;
-
 	/* get disk information */
 	if (ioctl(fd, BIODASDINFO2, &info->dasd_info) == 0) {
 		info->dasd_info_version = 2;
@@ -223,6 +213,16 @@ dasdview_get_info(dasdview_info_t *info)
 			exit(-1);
 		}
 	}
+
+	characteristics = (struct dasd_eckd_characteristics *)
+		&info->dasd_info.characteristics;
+	if (characteristics->no_cyl == LV_COMPAT_CYL &&
+	    characteristics->long_no_cyl)
+		info->hw_cylinders = characteristics->long_no_cyl;
+	else
+		info->hw_cylinders = characteristics->no_cyl;
+
+
 	close(fd);
 }
 
Index: s390-tools-sles11/dasdview/dasdview.h
===================================================================
--- s390-tools-sles11.orig/dasdview/dasdview.h
+++ s390-tools-sles11/dasdview/dasdview.h
@@ -72,6 +72,80 @@ typedef struct dasd_information2_t {
         unsigned int reserved7;       /* reserved for further use ,...          */
 } dasd_information2_t;
 
+struct dasd_eckd_characteristics {
+	unsigned short cu_type;
+	struct {
+		unsigned char support:2;
+		unsigned char async:1;
+		unsigned char reserved:1;
+		unsigned char cache_info:1;
+		unsigned char model:3;
+	} __attribute__ ((packed)) cu_model;
+	unsigned short dev_type;
+	unsigned char dev_model;
+	struct {
+		unsigned char mult_burst:1;
+		unsigned char RT_in_LR:1;
+		unsigned char reserved1:1;
+		unsigned char RD_IN_LR:1;
+		unsigned char reserved2:4;
+		unsigned char reserved3:8;
+		unsigned char defect_wr:1;
+		unsigned char XRC_supported:1;
+		unsigned char reserved4:1;
+		unsigned char striping:1;
+		unsigned char reserved5:4;
+		unsigned char cfw:1;
+		unsigned char reserved6:2;
+		unsigned char cache:1;
+		unsigned char dual_copy:1;
+		unsigned char dfw:1;
+		unsigned char reset_alleg:1;
+		unsigned char sense_down:1;
+	} __attribute__ ((packed)) facilities;
+	unsigned char dev_class;
+	unsigned char unit_type;
+	unsigned short no_cyl;
+	unsigned short trk_per_cyl;
+	unsigned char sec_per_trk;
+	unsigned char byte_per_track[3];
+	unsigned short home_bytes;
+	unsigned char formula;
+	union {
+		struct {
+			unsigned char f1;
+			unsigned short f2;
+			unsigned short f3;
+		} __attribute__ ((packed)) f_0x01;
+		struct {
+			unsigned char f1;
+			unsigned char f2;
+			unsigned char f3;
+			unsigned char f4;
+			unsigned char f5;
+		} __attribute__ ((packed)) f_0x02;
+	} __attribute__ ((packed)) factors;
+	unsigned short first_alt_trk;
+	unsigned short no_alt_trk;
+	unsigned short first_dia_trk;
+	unsigned short no_dia_trk;
+	unsigned short first_sup_trk;
+	unsigned short no_sup_trk;
+	unsigned char MDR_ID;
+	unsigned char OBR_ID;
+	unsigned char director;
+	unsigned char rd_trk_set;
+	unsigned short max_rec_zero;
+	unsigned char reserved1;
+	unsigned char RWANY_in_LR;
+	unsigned char factor6;
+	unsigned char factor7;
+	unsigned char factor8;
+	unsigned char reserved2[3];
+	unsigned char reserved3[6];
+	unsigned int long_no_cyl;
+} __attribute__ ((packed));
+
 /*
  * values to be used for dasd_information2_t.format
  * 0x00: NOT formatted
Index: s390-tools-sles11/fdasd/fdasd.c
===================================================================
--- s390-tools-sles11.orig/fdasd/fdasd.c
+++ s390-tools-sles11/fdasd/fdasd.c
@@ -1963,7 +1963,7 @@ fdasd_get_geometry (fdasd_anchor_t *anc)
         int fd, blksize = 0;
 	dasd_information_t dasd_info;
 	char err_str[ERROR_STRING_SIZE];
-	u_int64_t device_size;
+	struct dasd_eckd_characteristics *characteristics;
 
 	if ((fd = open(options.device,O_RDONLY)) < 0) {
 		snprintf(err_str, ERROR_STRING_SIZE,
@@ -1984,14 +1984,6 @@ fdasd_get_geometry (fdasd_anchor_t *anc)
 			    "Could not retrieve blocksize information.");
 	}
 
-	if (ioctl(fd, BLKGETSIZE64, &device_size) != 0) {
-		close(fd);
-		fdasd_error(anc, unable_to_ioctl,
-			    "Could not retrieve device size information.");
-	}
-
-	anc->hw_cylinders = ((device_size / blksize) / geo.sectors) / geo.heads;
-
 	/* get disk type */
 	if (ioctl(fd, BIODASDINFO, &dasd_info) != 0) {
 	        close(fd);
@@ -1999,6 +1991,14 @@ fdasd_get_geometry (fdasd_anchor_t *anc)
 			    "Could not retrieve disk information.");
 	}
 
+	characteristics =
+		(struct dasd_eckd_characteristics *) &dasd_info.characteristics;
+	if (characteristics->no_cyl == LV_COMPAT_CYL &&
+	    characteristics->long_no_cyl)
+		anc->hw_cylinders = characteristics->long_no_cyl;
+	else
+		anc->hw_cylinders = characteristics->no_cyl;
+
 	close(fd);
 
 	if (strncmp(dasd_info.type, "ECKD", 4) != 0) {
Index: s390-tools-sles11/fdasd/fdasd.h
===================================================================
--- s390-tools-sles11.orig/fdasd/fdasd.h
+++ s390-tools-sles11/fdasd/fdasd.h
@@ -43,6 +43,80 @@ typedef struct dasd_information_t {
         char configuration_data[256]; /* from read_configuration_data        */
 } dasd_information_t;
 
+struct dasd_eckd_characteristics {
+	unsigned short cu_type;
+	struct {
+		unsigned char support:2;
+		unsigned char async:1;
+		unsigned char reserved:1;
+		unsigned char cache_info:1;
+		unsigned char model:3;
+	} __attribute__ ((packed)) cu_model;
+	unsigned short dev_type;
+	unsigned char dev_model;
+	struct {
+		unsigned char mult_burst:1;
+		unsigned char RT_in_LR:1;
+		unsigned char reserved1:1;
+		unsigned char RD_IN_LR:1;
+		unsigned char reserved2:4;
+		unsigned char reserved3:8;
+		unsigned char defect_wr:1;
+		unsigned char XRC_supported:1;
+		unsigned char reserved4:1;
+		unsigned char striping:1;
+		unsigned char reserved5:4;
+		unsigned char cfw:1;
+		unsigned char reserved6:2;
+		unsigned char cache:1;
+		unsigned char dual_copy:1;
+		unsigned char dfw:1;
+		unsigned char reset_alleg:1;
+		unsigned char sense_down:1;
+	} __attribute__ ((packed)) facilities;
+	unsigned char dev_class;
+	unsigned char unit_type;
+	unsigned short no_cyl;
+	unsigned short trk_per_cyl;
+	unsigned char sec_per_trk;
+	unsigned char byte_per_track[3];
+	unsigned short home_bytes;
+	unsigned char formula;
+	union {
+		struct {
+			unsigned char f1;
+			unsigned short f2;
+			unsigned short f3;
+		} __attribute__ ((packed)) f_0x01;
+		struct {
+			unsigned char f1;
+			unsigned char f2;
+			unsigned char f3;
+			unsigned char f4;
+			unsigned char f5;
+		} __attribute__ ((packed)) f_0x02;
+	} __attribute__ ((packed)) factors;
+	unsigned short first_alt_trk;
+	unsigned short no_alt_trk;
+	unsigned short first_dia_trk;
+	unsigned short no_dia_trk;
+	unsigned short first_sup_trk;
+	unsigned short no_sup_trk;
+	unsigned char MDR_ID;
+	unsigned char OBR_ID;
+	unsigned char director;
+	unsigned char rd_trk_set;
+	unsigned short max_rec_zero;
+	unsigned char reserved1;
+	unsigned char RWANY_in_LR;
+	unsigned char factor6;
+	unsigned char factor7;
+	unsigned char factor8;
+	unsigned char reserved2[3];
+	unsigned char reserved3[6];
+	unsigned int long_no_cyl;
+} __attribute__ ((packed));
+
 /* Get information on a dasd device (enhanced) */
 #define BIODASDINFO   _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
 
