[paver] Add support for non-managed NAND partitions.

On several NAND parts, we have NAND partitions managed by a special
skip-block algorithm, rather than an FTL. These do not expose a block
IOCTL interface, but rather a different

Change-Id: Icb6bbdcb151b1127f95509aee55683db52ab80b6
Tested: TODO: Paved ZIRCON-R to a gauss.
diff --git a/system/uapp/disk-pave/device-partitioner.cpp b/system/uapp/disk-pave/device-partitioner.cpp
index 60cb71f..7de2605 100644
--- a/system/uapp/disk-pave/device-partitioner.cpp
+++ b/system/uapp/disk-pave/device-partitioner.cpp
@@ -55,7 +55,8 @@
         return fbl::move(device_partitioner);
     }
 #elif defined(__aarch64__)
-    if (FixedDevicePartitioner::Initialize(&device_partitioner) == ZX_OK) {
+    if ((NandDevicePartitioner::Initialize(&device_partitioner) == ZX_OK) ||
+        (FixedDevicePartitioner::Initialize(&device_partitioner) == ZX_OK)) {
         return fbl::move(device_partitioner);
     }
 #endif
@@ -429,7 +430,7 @@
     }
 
     return gpt_->AddPartition(name, type, minimum_size_bytes,
-                                              optional_reserve_bytes, out_fd);
+                              optional_reserve_bytes, out_fd);
 }
 
 bool EfiDevicePartitioner::FilterZirconPartition(const block_info_t& info,
@@ -546,7 +547,7 @@
         return status;
     }
 
-    gpt_device_t *gpt = gpt_partitioner->GetGpt();
+    gpt_device_t* gpt = gpt_partitioner->GetGpt();
     if (!is_cros(gpt)) {
         return ZX_ERR_NOT_FOUND;
     }
@@ -600,7 +601,7 @@
         return ZX_ERR_NOT_SUPPORTED;
     }
     return gpt_->AddPartition(name, type, minimum_size_bytes,
-                                              optional_reserve_bytes, out_fd);
+                              optional_reserve_bytes, out_fd);
 }
 
 zx_status_t CrosDevicePartitioner::FindPartition(Partition partition_type,
@@ -729,7 +730,7 @@
 }
 
 /*====================================================*
- *                    NON-GPT                         *
+ *               FIXED PARTITION MAP                  *
  *====================================================*/
 
 zx_status_t FixedDevicePartitioner::Initialize(fbl::unique_ptr<DevicePartitioner>* partitioner) {
@@ -739,7 +740,7 @@
 }
 
 zx_status_t FixedDevicePartitioner::FindPartition(Partition partition_type,
-                                                    fbl::unique_fd* out_fd) const {
+                                                  fbl::unique_fd* out_fd) const {
     uint8_t type[GPT_GUID_LEN];
 
     switch (partition_type) {
@@ -776,7 +777,7 @@
 }
 
 zx_status_t FixedDevicePartitioner::GetBlockInfo(const fbl::unique_fd& block_fd,
-                                                   block_info_t* block_info) const {
+                                                 block_info_t* block_info) const {
     ssize_t r;
     if ((r = ioctl_block_get_info(block_fd.get(), block_info) < 0)) {
         return ZX_ERR_IO;
@@ -784,4 +785,65 @@
     return ZX_OK;
 }
 
+/*====================================================*
+ *                   NAND SPECIFIC                    *
+ *====================================================*/
+
+zx_status_t NandDevicePartitioner::Initialize(fbl::unique_ptr<DevicePartitioner>* partitioner) {
+    return ZX_ERR_NOT_SUPPORTED;
+    // TODO: Check if this is a NAND part.
+#if 0
+    LOG("Successfully intitialized NandDevicePartitioner Device Partitioner\n");
+    *partitioner = fbl::move(WrapUnique(new NandDevicePartitioner));
+#endif
+}
+
+zx_status_t NandDevicePartitioner::FindPartition(Partition partition_type,
+                                                 fbl::unique_fd* out_fd) const {
+    uint8_t type[GPT_GUID_LEN];
+
+    switch (partition_type) {
+    case Partition::kZirconA: {
+        const uint8_t zircon_a_type[GPT_GUID_LEN] = GUID_ZIRCON_A_VALUE;
+        memcpy(type, zircon_a_type, GPT_GUID_LEN);
+        break;
+    }
+    case Partition::kZirconB: {
+        const uint8_t zircon_b_type[GPT_GUID_LEN] = GUID_ZIRCON_B_VALUE;
+        memcpy(type, zircon_b_type, GPT_GUID_LEN);
+        break;
+    }
+    case Partition::kZirconR: {
+        const uint8_t zircon_r_type[GPT_GUID_LEN] = GUID_ZIRCON_R_VALUE;
+        memcpy(type, zircon_r_type, GPT_GUID_LEN);
+        break;
+    }
+    case Partition::kFuchsiaVolumeManager: {
+        const uint8_t fvm_type[GPT_GUID_LEN] = GUID_FVM_VALUE;
+        memcpy(type, fvm_type, GPT_GUID_LEN);
+        out_fd->reset(open_partition(nullptr, type, ZX_SEC(5), nullptr));
+        if (!out_fd) {
+            return ZX_ERR_NOT_FOUND;
+        }
+        return ZX_OK;
+    }
+    default:
+        ERROR("partition_type is invalid!\n");
+        return ZX_ERR_NOT_SUPPORTED;
+    }
+
+    // TODO: Find skip-block partition.
+    return ZX_ERR_NOT_SUPPORTED;
+}
+
+zx_status_t NandDevicePartitioner::GetBlockInfo(const fbl::unique_fd& block_fd,
+                                                block_info_t* block_info) const {
+    skip_block_partition_info_t info;
+    ssize_t r;
+    if ((r = ioctl_skip_block_get_info(block_fd.get(), block_info) < 0)) {
+        return ZX_ERR_IO;
+    }
+    return ZX_OK;
+}
+
 } // namespace paver
diff --git a/system/uapp/disk-pave/device-partitioner.h b/system/uapp/disk-pave/device-partitioner.h
index af630b9..122a10b 100644
--- a/system/uapp/disk-pave/device-partitioner.h
+++ b/system/uapp/disk-pave/device-partitioner.h
@@ -207,4 +207,33 @@
     FixedDevicePartitioner() {}
 };
 
+// DevicePartitioner implementation for devices which have fixed partition maps, but do no expose a
+// block device interface. Instead they expose devices with skip-block IOCTL interfaces. Like the
+// FixedDevicePartitioner, it will not attempt to write a partition map of any kind to the device.
+// Assumes standardized partition layout structure (e.g. ZIRCON-A, ZIRCON-B,
+// ZIRCON-R).
+class NandDevicePartitioner : public DevicePartitioner {
+public:
+    static zx_status_t Initialize(fbl::unique_ptr<DevicePartitioner>* partitioner);
+
+    bool IsCros() const override { return false; }
+
+    zx_status_t AddPartition(Partition partition_type, fbl::unique_fd* out_fd) override {
+        return ZX_ERR_NOT_SUPPORTED;
+    }
+
+    zx_status_t FindPartition(Partition partition_type, fbl::unique_fd* out_fd) const override;
+
+    zx_status_t FinalizePartition(Partition unused) override { return ZX_OK; }
+
+    zx_status_t WipePartitions(const fbl::Vector<Partition>& partitions) override {
+        return ZX_ERR_NOT_SUPPORTED;
+    }
+
+    zx_status_t GetBlockInfo(const fbl::unique_fd& block_fd,
+                             block_info_t* block_info) const override;
+
+private:
+    NandDevicePartitioner() {}
+};
 } // namespace paver