Subject: [PATCH] storage: add support for EDEV device

From: Nageswara R Sastry <rnsastry@linux.vnet.ibm.com>

Fixed Block Access (FBA) DASDs are mainframe-specific disk devices
which are layed out as a sequence of 512-byte sectors. In contrast
to ECKD DASDs, these disks do not require formatting and resemble
the LBA layout of non-mainframe disks. Despite this resemblance,
the Linux kernel applies special handling during partition detection
for FBA DASDs, resulting in a single, immutable partition being
reported.

While actual FBA DASD hardware is no longer available, the z/VM
hypervisor can simulate FBA DASD disks, backed by either ECKD or
SCSI devices.

This patch adds support for successful installation on FBA DASD
devies (EDEV)

Signed-off-by: Nageswara R Sastry <rnsastry@linux.vnet.ibm.com>
---
 pyanaconda/storage/__init__.py          |    6 ++++--
 pyanaconda/storage/devices.py           |   17 ++++++++++-------
 pyanaconda/storage/formats/disklabel.py |   23 ++++++++++++++++++++++-
 pyanaconda/storage/partitioning.py      |    2 ++
 4 files changed, 38 insertions(+), 10 deletions(-)

--- a/pyanaconda/storage/__init__.py
+++ b/pyanaconda/storage/__init__.py
@@ -841,8 +841,10 @@ class Storage(object):
                         # disk. Still, we need it out of the devicetree.
                         self.devicetree._removeDevice(part, moddisk=False)
 
-        if disk.partitioned and disk.format.partitions:
-            raise ValueError("cannot initialize a disk that has partitions")
+        # Do not remove partition from LDL formatted
+        if not disk.format.isLDL():
+            if disk.partitioned and disk.format.partitions:
+                raise ValueError("cannot initialize a disk that has partitions")
 
         # remove existing formatting from the disk
         destroy_action = ActionDestroyFormat(disk)
--- a/pyanaconda/storage/devices.py
+++ b/pyanaconda/storage/devices.py
@@ -1453,14 +1453,17 @@ class PartitionDevice(StorageDevice):
     def _create(self):
         """ Create the device. """
         log_method_call(self, self.name, status=self.status)
-        self.disk.format.addPartition(self.partedPartition)
 
-        try:
-            self.disk.format.commit()
-        except DiskLabelCommitError:
-            part = self.disk.format.partedDisk.getPartitionByPath(self.path)
-            self.disk.format.removePartition(part)
-            raise
+        # Do not create partition on LDL formatted
+        if not self.disk.format.isLDL():
+            self.disk.format.addPartition(self.partedPartition)
+
+            try:
+                self.disk.format.commit()
+            except DiskLabelCommitError:
+                part = self.disk.format.partedDisk.getPartitionByPath(self.path)
+                self.disk.format.removePartition(part)
+                raise
 
     def _postCreate(self):
         if self.isExtended:
--- a/pyanaconda/storage/formats/disklabel.py
+++ b/pyanaconda/storage/formats/disklabel.py
@@ -142,6 +142,19 @@ class DiskLabel(DeviceFormat):
         log_method_call(self, device=self.device, labelType=self._labelType)
         return parted.freshDisk(device=self.partedDevice, ty=self._labelType)
 
+    def newPartedDisk(self):
+        """ Return a new, empty parted.Disk instance for this device. """
+        log_method_call(self, device=self.device)
+        return parted.newDisk(device=self.partedDevice)
+
+    def isLDL(self):
+       """ Return True for LDL formatted disk. """
+       log_method_call(self, device=self.device)
+       if (self._labelType == "dasd" and self.partedDisk.maxPrimaryPartitionCount == 1):
+           return True
+       else:
+           return False
+
     @property
     def partedDisk(self):
         if not self._partedDisk:
@@ -163,7 +176,13 @@ class DiskLabel(DeviceFormat):
                 # preexisting disklabels if the passed type was wrong
                 self._labelType = self._partedDisk.type
             else:
-                self._partedDisk = self.freshPartedDisk()
+                if (self._labelType == "dasd"):
+                    self._partedDisk = self.newPartedDisk()
+                    # Don't want to break for the normal DASD
+                    if self._partedDisk.maxPrimaryPartitionCount != 1:
+                        self._partedDisk = self.freshPartedDisk()
+                else:
+                    self._partedDisk = self.freshPartedDisk()
 
             # turn off cylinder alignment
             if self._partedDisk.isFlagAvailable(parted.DISK_CYLINDER_ALIGNMENT):
@@ -437,6 +456,8 @@ class DiskLabel(DeviceFormat):
             return 1
         elif self.labelType == "sun":
             return 3
+        elif self.isLDL():
+            return 1
         else:
             return 0
 
--- a/pyanaconda/storage/partitioning.py
+++ b/pyanaconda/storage/partitioning.py
@@ -428,6 +428,8 @@ def getNextPartitionType(disk, no_primar
                 part_type = parted.PARTITION_LOGICAL
     elif extended and logical_count < max_logicals:
         part_type = parted.PARTITION_LOGICAL
+    elif (disk.type == "dasd" and disk.maxPrimaryPartitionCount == 1):
+        part_type = parted.PARTITION_NORMAL
 
     return part_type
 
