From 03fe4c4f11d469f3a33db2a57f6039c7f8c7a612 Mon Sep 17 00:00:00 2001
From: Tim Stoutamore <stout@blunkmicro.com>
Date: Fri, 26 Apr 2019 22:59:12 +0000
Subject: [PATCH] [zircon/ftl] Changed FTL-NDM interface from callbacks to
 direct function calls.

1. Because Google app doesn't require callback interface between the FTL and
   the NDM, removed it to increase clarity and decrease lines of code.
2. Changed some local variables from 'ftl' to 'ftl_cfg' to better differentiate
   between control block handles and temporary configuration structures.
3. Removed ENOMEM definition from 'kernel.h'.
4. Removed FsError() calls from routines in 'fsmem.c' since their callers
   invoke FsError2() if there is an error.
5. Introduced 'ftl_pri.h' (for internal use) and 'ftl_pub.h' (for driver).
   Following check-ins will consolidate other headers into those files.

Change-Id: I6c27dfd24755c5fda1e0cb5ba09e8707ce31b653
---
 zircon/system/ulib/ftl/ftl.h                  |  39 +++
 zircon/system/ulib/ftl/ftl_private.h          |  35 +++
 zircon/system/ulib/ftl/ftln/ftln_init.c       | 109 ++++----
 zircon/system/ulib/ftl/ftln/ftln_intrnl.c     |  20 +-
 zircon/system/ulib/ftl/ftln/ftln_rd.c         |   6 +-
 zircon/system/ulib/ftl/ftln/ftln_util.c       |  11 +-
 zircon/system/ulib/ftl/ftln/ftlnp.h           |  93 +++----
 zircon/system/ulib/ftl/ftln/ndm-driver.cpp    |   2 +-
 zircon/system/ulib/ftl/ftln/volume.cpp        |   1 +
 .../system/ulib/ftl/inc/kprivate/fsdriver.h   |  48 +---
 zircon/system/ulib/ftl/inc/kprivate/ndm.h     |  11 +-
 zircon/system/ulib/ftl/inc/sys.h              |  29 ---
 zircon/system/ulib/ftl/ndm/ndm_init.c         |   6 +-
 zircon/system/ulib/ftl/ndm/ndm_intrnl.c       | 232 ++++++++----------
 zircon/system/ulib/ftl/ndm/ndmp.h             |   2 +-
 zircon/system/ulib/ftl/utils/aalloc.c         |   3 +-
 zircon/system/ulib/ftl/utils/crc32_tbl.c      |   1 +
 zircon/system/ulib/ftl/utils/fsmem.c          |  10 +-
 zircon/system/ulib/ftl/utils/fsys.c           |   4 +-
 zircon/system/ulib/ftl/utils/fsysinit.c       |   2 +
 zircon/system/ulib/ftl/utils/ftl_mc.c         |   4 +-
 .../ulib/ftl/{inc/kprivate => utils}/ftl_mc.h |   0
 zircon/system/ulib/ftl/utils/kernel.h         |   2 -
 23 files changed, 304 insertions(+), 366 deletions(-)
 create mode 100644 zircon/system/ulib/ftl/ftl.h
 create mode 100644 zircon/system/ulib/ftl/ftl_private.h
 rename zircon/system/ulib/ftl/{inc/kprivate => utils}/ftl_mc.h (100%)

diff --git a/zircon/system/ulib/ftl/ftl.h b/zircon/system/ulib/ftl/ftl.h
new file mode 100644
index 00000000000..2e3dd9c6097
--- /dev/null
+++ b/zircon/system/ulib/ftl/ftl.h
@@ -0,0 +1,39 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <stdint.h>    // For fixed width types.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// Type Declarations.
+//
+
+// NDM Control Block
+typedef struct ndm* NDM;
+typedef const struct ndm* CNDM;
+
+// FTL Interface Structure
+typedef struct XfsVol {
+    // Driver functions
+    int (*write_pages)(const void* buf, uint32_t page0, int cnt, void* vol);
+    int (*read_pages)(void* buf, uint32_t page0, int cnt, void* vol);
+    int (*report)(void *vol, uint32_t msg, ...);
+
+    const char* name;       // volume name
+    uint32_t flags;         // option flags
+    uint32_t num_pages;     // number of pages in volume
+    uint32_t page_size;     // page size in bytes
+    void* vol;              // driver's volume pointer
+    void* ftl_volume;       // ftl layer (block device) volume
+} XfsVol;
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/zircon/system/ulib/ftl/ftl_private.h b/zircon/system/ulib/ftl/ftl_private.h
new file mode 100644
index 00000000000..742e875db5b
--- /dev/null
+++ b/zircon/system/ulib/ftl/ftl_private.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <ftl.h>   // For API definition.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// Symbol Definitions.
+//
+#define ui8 uint8_t
+
+//
+// Function Prototypes.
+//
+
+// TargetNDM interface to TargetFTL
+int ndmEraseBlock(uint32_t pn, NDM ndm);
+int ndmReadPages(uint32_t pn0, uint32_t count, ui8* buf, ui8* spare, NDM ndm);
+int ndmReadSpare(uint32_t vpn, ui8* spare, NDM ndm);
+int ndmWritePages(uint32_t pn0, uint32_t cnt, const ui8* buf, ui8* spare, NDM ndm);
+int ndmWritePage(uint32_t vpn, const ui8* buf, ui8* spare, NDM ndm);
+int ndmTransferPage(uint32_t old_vpn, uint32_t new_vpn, ui8* buf, ui8* spare, NDM ndm);
+int ndmCheckPage(uint32_t pn, ui8* data, ui8* spare, NDM ndm);
+uint32_t ndmPairOffset(uint32_t page_offset, CNDM ndm);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/zircon/system/ulib/ftl/ftln/ftln_init.c b/zircon/system/ulib/ftl/ftln/ftln_init.c
index f22b1995712..9754559f657 100644
--- a/zircon/system/ulib/ftl/ftln/ftln_init.c
+++ b/zircon/system/ulib/ftl/ftln/ftln_init.c
@@ -91,7 +91,7 @@ static int map_page_check(FTLN ftl, ui32 apn, int process) {
 
     // Call driver validity check. Return -1 if error.
     ++ftl->stats.page_check;
-    status = ftl->page_check(apn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
+    status = ndmCheckPage(apn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
     if (status < 0)
         return FtlnFatErr(ftl);
 
@@ -140,23 +140,17 @@ static int map_page_check(FTLN ftl, ui32 apn, int process) {
 
                     // Process each elist page, from last to first.
                     for (;;) {
-                        //---------------------------------------------------------
                         // Verify and apply elist page. Return if page invalid.
-                        //---------------------------------------------------------
                         status = proc_elist(ftl);
                         if (status != NDM_PAGE_VALID)
                             return status;
 
-                        //---------------------------------------------------------
                         // If first (perhaps only) page was processed, finished!
-                        //---------------------------------------------------------
                         if (apn == ap0)
                             break;
 
-                        //---------------------------------------------------------
                         // Move to next written page in backwards direction. If
                         // MLC flash, move to page whose pair has higher offset.
-                        //---------------------------------------------------------
 #if INC_FTL_NDM_SLC
                         --apn;
 #else
@@ -170,29 +164,21 @@ static int map_page_check(FTLN ftl, ui32 apn, int process) {
                         }
 #endif
 
-                        //---------------------------------------------------------
                         // Call driver to read/check next page. Return -1 if error.
-                        //---------------------------------------------------------
                         ++ftl->stats.page_check;
-                        status = ftl->page_check(apn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
+                        status = ndmCheckPage(apn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
                         if (status < 0)
                             return FtlnFatErr(ftl);
 
-                        //---------------------------------------------------------
                         // If page is erased or invalid, return its status.
-                        //---------------------------------------------------------
                         if (status != NDM_PAGE_VALID)
                             return status;
 
-                        //---------------------------------------------------------
                         // Verify the metadata version is correct.
-                        //---------------------------------------------------------
                         if (RD32_LE(&ppns[0]) != FTLN_META_VER1)
                             return NDM_PAGE_INVALID;
 
-                        //---------------------------------------------------------
                         // Verify the metadata type is correct.
-                        //---------------------------------------------------------
                         if (RD32_LE(&ppns[1]) != ERASED_LIST)
                             return NDM_PAGE_INVALID;
                     }
@@ -294,7 +280,7 @@ static int build_map(FTLN ftl) {
             else {
                 // Read page's spare area.
                 ++ftl->stats.read_spare;
-                status = ftl->read_spare(pn, ftl->spare_buf, ftl->ndm);
+                status = ndmReadSpare(pn, ftl->spare_buf, ftl->ndm);
 
                 // Return if fatal error.
                 if (status == -2) {
@@ -309,11 +295,11 @@ static int build_map(FTLN ftl) {
 
             // If first page, retrieve block count. Otherwise compare with
             // block count of block's already-checked-valid first page.
-            if (po == 0)
+            if (po == 0) {
                 bc = GET_SA_BC(ftl->spare_buf);
-            else if (bc != GET_SA_BC(ftl->spare_buf)) {
+            } else if (bc != GET_SA_BC(ftl->spare_buf)) {
 #if FTLN_DEBUG > 1
-                printf("build_ma: b = %u, po = %u, i_bc = %u vs 0_bc = %u\n", b, po,
+                printf("build_map: b = %u, po = %u, i_bc = %u vs 0_bc = %u\n", b, po,
                        GET_SA_BC(ftl->spare_buf), bc);
 #endif
 
@@ -332,7 +318,7 @@ static int build_map(FTLN ftl) {
             mpn = GET_SA_VPN(ftl->spare_buf);
             if (mpn > ftl->num_map_pgs) {
 #if FTLN_DEBUG > 1
-                printf("build_ma: b = %u, po = %u, mpn = %u, max = %u\n", b, po, mpn,
+                printf("build_map: b = %u, po = %u, mpn = %u, max = %u\n", b, po, mpn,
                        ftl->num_map_pgs);
 #endif
 
@@ -361,7 +347,7 @@ static int build_map(FTLN ftl) {
                     INC_USED(ftl->bdata[b]);
                 }
 #if FTLN_DEBUG > 1
-                printf("build_ma: mpn = %u, old_pn = %d, new_pn = %u\n", mpn, ftl->mpns[mpn],
+                printf("build_map: mpn = %u, old_pn = %d, new_pn = %u\n", mpn, ftl->mpns[mpn],
                        b * ftl->pgs_per_blk + po);
 #endif
 
@@ -533,7 +519,7 @@ static int format_status(FTLN ftl) {
 
         // Read spare area for first page. Return -1 if fatal error.
         ++ftl->stats.read_spare;
-        rc = ftl->read_spare(pn, ftl->spare_buf, ftl->ndm);
+        rc = ndmReadSpare(pn, ftl->spare_buf, ftl->ndm);
         if (rc == -2)
             return FtlnFatErr(ftl);
 
@@ -565,7 +551,7 @@ static int format_status(FTLN ftl) {
 
                         // Read spare area for higher page. Return -1 if fatal error.
                         ++ftl->stats.read_spare;
-                        rc = ftl->read_spare(pn + n, ftl->spare_buf, ftl->ndm);
+                        rc = ndmReadSpare(pn + n, ftl->spare_buf, ftl->ndm);
                         if (rc == -2)
                             return FtlnFatErr(ftl);
 
@@ -602,7 +588,7 @@ static int format_status(FTLN ftl) {
 #endif
             // Call driver validity check. Return -1 if error.
             ++ftl->stats.page_check;
-            rc = ftl->page_check(pn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
+            rc = ndmCheckPage(pn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
             if (rc < 0)
                 return FtlnFatErr(ftl);
 
@@ -624,7 +610,7 @@ static int format_status(FTLN ftl) {
 
                 // Read spare data. Return if fatal error. Skip if ECC error.
                 ++ftl->stats.read_spare;
-                rc = ftl->read_spare(pn + n, ftl->spare_buf, ftl->ndm);
+                rc = ndmReadSpare(pn + n, ftl->spare_buf, ftl->ndm);
                 if (rc == -2)
                     return FtlnFatErr(ftl);
                 if (rc)
@@ -642,7 +628,7 @@ static int format_status(FTLN ftl) {
 #endif
                     // Read and check the copy-end page. Return -1 if error.
                     ++ftl->stats.page_check;
-                    rc = ftl->page_check(pn + n, ftl->main_buf, ftl->spare_buf, ftl->ndm);
+                    rc = ndmCheckPage(pn + n, ftl->main_buf, ftl->spare_buf, ftl->ndm);
                     if (rc < 0)
                         return FtlnFatErr(ftl);
 
@@ -819,7 +805,7 @@ static int copy_end_mark(CFTLN ftl, ui32 b) {
     SET_SA_WC(0, ftl->spare_buf);
 
     // Write page that marks the end of a volume resume copy block.
-    return ftl->write_page(pn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
+    return ndmWritePage(pn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
 }
 
 // resume_copy: Copy one volume block
@@ -842,7 +828,7 @@ static int resume_copy(FTLN ftl, ui32 src_b, ui32 dst_b, ui32 bc) {
     for (po = 0; po <= ftl->resume_po; ++po) {
         // Read source page's spare area.
         ++ftl->stats.read_spare;
-        rc = ftl->read_spare(src_pg0 + po, ftl->spare_buf, ftl->ndm);
+        rc = ndmReadSpare(src_pg0 + po, ftl->spare_buf, ftl->ndm);
 
         // Return -1 if fatal error, skip page if ECC error on spare read.
         if (rc) {
@@ -865,8 +851,10 @@ static int resume_copy(FTLN ftl, ui32 src_b, ui32 dst_b, ui32 bc) {
 
         // Invoke page transfer routine. If error, return -1.
         ++ftl->stats.transfer_page;
-        if (ftl->xfer_page(src_pg0 + po, dst_pg0 + po, ftl->main_buf, ftl->spare_buf, ftl->ndm))
+        if (ndmTransferPage(src_pg0 + po, dst_pg0 + po, ftl->main_buf,
+                            ftl->spare_buf, ftl->ndm)) {
             return FtlnFatErr(ftl);
+        }
     }
 
     // Return success.
@@ -1133,31 +1121,31 @@ static int rd_map_pg(void* vol, ui32 mpn, void* buf, int* unmapped) {
 
 // FtlnAddVol: Create a new FTL volume
 //
-//      Inputs: ftl_dvr = pointer to FTL NDM driver control block
+//      Inputs: ftl_cfg = pointer to FTL configuration structure
 //              xfs = pointer to FTL interface structure
 //
 //     Returns: -1 if error, 0 for success.
 //
-int FtlnAddVol(FtlNdmVol* ftl_dvr, XfsVol* xfs) {
+int FtlnAddVol(FtlNdmVol* ftl_cfg, XfsVol* xfs) {
     ui32 n, vol_blks;
     ui8* buf;
     FTLN ftl;
 
     // If number of blocks less than 7, FTL-NDM cannot work.
-    if (ftl_dvr->num_blocks < 7) {
+    if (ftl_cfg->num_blocks < 7) {
         FsError2(FTL_CFG_ERR, EINVAL);
         return -1;
     }
 
     // Ensure FTL flags are valid.
-    if (ftl_dvr->flags & ~(FSF_EXTRA_FREE | FSF_READ_WEAR_LIMIT | FSF_READ_ONLY_INIT)) {
+    if (ftl_cfg->flags & ~(FSF_EXTRA_FREE | FSF_READ_WEAR_LIMIT | FSF_READ_ONLY_INIT)) {
         FsError2(FTL_CFG_ERR, EINVAL);
         return -1;
     }
 
 #if CACHE_LINE_SIZE
     // Ensure driver page size is a multiple of the CPU cache line size.
-    if (ftl_dvr->page_size % CACHE_LINE_SIZE) {
+    if (ftl_cfg->page_size % CACHE_LINE_SIZE) {
         FsError2(FTL_CFG_ERR, EINVAL);
         return -1;
     }
@@ -1165,8 +1153,8 @@ int FtlnAddVol(FtlNdmVol* ftl_dvr, XfsVol* xfs) {
 
     // Ensure physical page size is a multiple of FAT sector size and
     // not bigger than the device block size.
-    if (ftl_dvr->page_size % FAT_SECT_SZ || ftl_dvr->page_size == 0 ||
-        ftl_dvr->page_size > ftl_dvr->block_size) {
+    if (ftl_cfg->page_size % FAT_SECT_SZ || ftl_cfg->page_size == 0 ||
+        ftl_cfg->page_size > ftl_cfg->block_size) {
         FsError2(FTL_CFG_ERR, EINVAL);
         return -1;
     }
@@ -1181,17 +1169,16 @@ int FtlnAddVol(FtlNdmVol* ftl_dvr, XfsVol* xfs) {
     Ftln = ftl;
 #endif
 
-    // Set all FTL driver dependent variables.
-    ftl->num_blks = ftl_dvr->num_blocks;
-    ftl->page_size = ftl_dvr->page_size;
-    ftl->eb_size = ftl_dvr->eb_size;
-    ftl->block_size = ftl_dvr->block_size;
+    // Initialize the FTL control block.
+    ftl->num_blks = ftl_cfg->num_blocks;
+    ftl->page_size = ftl_cfg->page_size;
+    ftl->eb_size = ftl_cfg->eb_size;
+    ftl->block_size = ftl_cfg->block_size;
     ftl->pgs_per_blk = ftl->block_size / ftl->page_size;
     ftl->num_pages = ftl->pgs_per_blk * ftl->num_blks;
-    ftl->start_pn = ftl_dvr->start_page;
-    ftl->ndm = ftl_dvr->ndm;
-    ftl->type = ftl_dvr->type;
-    ftl->flags = ftl_dvr->flags;
+    ftl->start_pn = ftl_cfg->start_page;
+    ftl->ndm = ftl_cfg->ndm;
+    ftl->flags = ftl_cfg->flags;
     strcpy(ftl->vol_name, xfs->name);
 
     // Ensure pages per block doesn't exceed alloted metadata field width.
@@ -1207,18 +1194,6 @@ int FtlnAddVol(FtlNdmVol* ftl_dvr, XfsVol* xfs) {
     }
 #endif
 
-    // Copy the NDM interface functions.
-    ftl->write_page = ftl_dvr->write_data_and_spare;
-    ftl->write_pages = ftl_dvr->write_pages;
-    ftl->read_spare = ftl_dvr->read_spare;
-    ftl->read_pages = ftl_dvr->read_pages;
-    ftl->page_check = ftl_dvr->page_check;
-    ftl->xfer_page = ftl_dvr->transfer_page;
-    ftl->erase_block = ftl_dvr->erase_block;
-#if INC_FTL_NDM_MLC
-    ftl->pair_offset = ftl_dvr->pair_offset;
-#endif
-
     // Compute how many volume pages are mapped by a single map page.
     ftl->mappings_per_mpg = ftl->page_size / FTLN_PN_SZ;
 
@@ -1283,8 +1258,8 @@ int FtlnAddVol(FtlNdmVol* ftl_dvr, XfsVol* xfs) {
     // 2%. Increasing number of map pages makes recycles more efficient
     // because the ratio of used to dirty pages is lower in map blocks.
     ftl->num_vpages = vol_blks * ftl->pgs_per_blk;
-    n = ftl_dvr->extra_free;
-    if (FLAG_IS_CLR(ftl_dvr->flags, FSF_EXTRA_FREE) || n < 2 || n > 50)
+    n = ftl_cfg->extra_free;
+    if (FLAG_IS_CLR(ftl_cfg->flags, FSF_EXTRA_FREE) || n < 2 || n > 50)
         n = 2;
     n = (n * ftl->num_vpages) / 100;
     if (n == 0)
@@ -1340,25 +1315,25 @@ int FtlnAddVol(FtlNdmVol* ftl_dvr, XfsVol* xfs) {
 
     // For SLC devices, adjust driver cached MPNs if too big or zero.
 #if INC_FTL_NDM_SLC
-    if (ftl->num_map_pgs < ftl_dvr->cached_map_pages || ftl_dvr->cached_map_pages == 0)
-        ftl_dvr->cached_map_pages = ftl->num_map_pgs;
+    if (ftl->num_map_pgs < ftl_cfg->cached_map_pages || ftl_cfg->cached_map_pages == 0)
+        ftl_cfg->cached_map_pages = ftl->num_map_pgs;
 
 #else
 
     // For MLC devices, cache all map pages so that no map write occurs
     // due to cache preemption.
-    ftl_dvr->cached_map_pages = ftl->num_map_pgs;
+    ftl_cfg->cached_map_pages = ftl->num_map_pgs;
 #endif
 
     // Allocate map page cache for new volume.
-    ftl->map_cache = ftlmcNew(ftl, ftl_dvr->cached_map_pages, FtlnMapWr, rd_map_pg, ftl->page_size);
+    ftl->map_cache = ftlmcNew(ftl, ftl_cfg->cached_map_pages, FtlnMapWr, rd_map_pg, ftl->page_size);
     if (ftl->map_cache == NULL)
         goto FtlnAddV_err;
 
     // Set block read wear limit.
-    if (FLAG_IS_SET(ftl_dvr->flags, FSF_READ_WEAR_LIMIT))
-        ftl->max_rc = ftl_dvr->read_wear_limit;
-    else {
+    if (FLAG_IS_SET(ftl_cfg->flags, FSF_READ_WEAR_LIMIT)) {
+        ftl->max_rc = ftl_cfg->read_wear_limit;
+    } else {
 #if INC_FTL_NDM_SLC
         ftl->max_rc = SLC_NAND_RC_LIMIT;
 #else
diff --git a/zircon/system/ulib/ftl/ftln/ftln_intrnl.c b/zircon/system/ulib/ftl/ftln/ftln_intrnl.c
index a522ed8a5db..dcd0dab02ee 100644
--- a/zircon/system/ulib/ftl/ftln/ftln_intrnl.c
+++ b/zircon/system/ulib/ftl/ftln/ftln_intrnl.c
@@ -250,13 +250,13 @@ static int wr_vol_page(FTLN ftl, ui32 vpn, void* buf, ui32 old_ppn) {
     // If page data in buffer, write it. Returns 0 or -2.
     if (buf) {
         ++ftl->stats.write_page;
-        rc = ftl->write_page(ftl->start_pn + ppn, buf, ftl->spare_buf, ftl->ndm);
+        rc = ndmWritePage(ftl->start_pn + ppn, buf, ftl->spare_buf, ftl->ndm);
 
     // Else invoke page transfer routine. Returns 0, -2, or 1.
     } else {
         ++ftl->stats.transfer_page;
-        rc = ftl->xfer_page(ftl->start_pn + old_ppn, ftl->start_pn + ppn, ftl->main_buf,
-                            ftl->spare_buf, ftl->ndm);
+        rc = ndmTransferPage(ftl->start_pn + old_ppn, ftl->start_pn + ppn,
+                             ftl->main_buf, ftl->spare_buf, ftl->ndm);
     }
 
     // Return -1 for any error. Any write error is fatal.
@@ -566,7 +566,7 @@ static int recycle_vblk(FTLN ftl, ui32 recycle_b) {
 
         // Read page's spare area.
         ++ftl->stats.read_spare;
-        rc = ftl->read_spare(ftl->start_pn + pn, ftl->spare_buf, ftl->ndm);
+        rc = ndmReadSpare(ftl->start_pn + pn, ftl->spare_buf, ftl->ndm);
 
         // Return -1 if fatal error, skip page if ECC error on spare read.
         if (rc) {
@@ -670,8 +670,8 @@ static int flush_pending_writes(FTLN ftl, StagedWr* staged) {
 
     // Issue driver multi-page write request. Return -1 if error.
     ftl->stats.write_page += staged->cnt;
-    if (ftl->write_pages(ftl->start_pn + staged->ppn0, staged->cnt, staged->buf,
-                         ftl->spare_buf, ftl->ndm)) {
+    if (ndmWritePages(ftl->start_pn + staged->ppn0, staged->cnt, staged->buf,
+                      ftl->spare_buf, ftl->ndm)) {
         return FtlnFatErr(ftl);
     }
 
@@ -886,7 +886,7 @@ int FtlnRecycleMapBlk(FTLN ftl, ui32 recycle_b) {
 
         // Read page's spare area. Return -1 if fatal I/O error.
         ++ftl->stats.read_spare;
-        rc = ftl->read_spare(ftl->start_pn + pn, ftl->spare_buf, ftl->ndm);
+        rc = ndmReadSpare(ftl->start_pn + pn, ftl->spare_buf, ftl->ndm);
         if (rc == -2)
             return FtlnFatErr(ftl);
 
@@ -1178,13 +1178,13 @@ int FtlnMapWr(void* vol, ui32 mpn, void* buf) {
     // If page data in buffer, invoke write_page().
     if (buf) {
         ++ftl->stats.write_page;
-        status = ftl->write_page(ftl->start_pn + pn, buf, ftl->spare_buf, ftl->ndm);
+        status = ndmWritePage(ftl->start_pn + pn, buf, ftl->spare_buf, ftl->ndm);
 
     // Else source data is in flash. Invoke page transfer routine.
     } else {
         ++ftl->stats.transfer_page;
-        status = ftl->xfer_page(ftl->start_pn + old_pn, ftl->start_pn + pn, ftl->main_buf,
-                                ftl->spare_buf, ftl->ndm);
+        status = ndmTransferPage(ftl->start_pn + old_pn, ftl->start_pn + pn,
+                                 ftl->main_buf, ftl->spare_buf, ftl->ndm);
     }
 
     // I/O or ECC decode error is fatal.
diff --git a/zircon/system/ulib/ftl/ftln/ftln_rd.c b/zircon/system/ulib/ftl/ftln/ftln_rd.c
index 15b61b0c84f..70a0912ea2f 100644
--- a/zircon/system/ulib/ftl/ftln/ftln_rd.c
+++ b/zircon/system/ulib/ftl/ftln/ftln_rd.c
@@ -27,8 +27,8 @@ static int flush_pending_reads(FTLN ftl, StagedRd* staged) {
 
     // Issue pending reads.
     ftl->stats.read_page += staged->run_cnt;
-    status = ftl->read_pages(ftl->start_pn + staged->ppn0, staged->run_cnt, staged->buf,
-                             ftl->spare_buf, ftl->ndm);
+    status = ndmReadPages(ftl->start_pn + staged->ppn0, staged->run_cnt, staged->buf,
+                          ftl->spare_buf, ftl->ndm);
 
     // Adjust data buffer pointer.
     staged->buf += staged->run_cnt * ftl->page_size;
@@ -183,7 +183,7 @@ int FtlnRdPage(FTLN ftl, ui32 ppn, void* rd_buf) {
 
     // Read page from flash. If error, set errno/fatal flag/return -1.
     ++ftl->stats.read_page;
-    status = ftl->read_pages(ftl->start_pn + ppn, 1, rd_buf, ftl->spare_buf, ftl->ndm);
+    status = ndmReadPages(ftl->start_pn + ppn, 1, rd_buf, ftl->spare_buf, ftl->ndm);
     if (status < 0)
         return FtlnFatErr(ftl);
 
diff --git a/zircon/system/ulib/ftl/ftln/ftln_util.c b/zircon/system/ulib/ftl/ftln/ftln_util.c
index 4197c7cd198..6b1f132ce00 100644
--- a/zircon/system/ulib/ftl/ftln/ftln_util.c
+++ b/zircon/system/ulib/ftl/ftln/ftln_util.c
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ftlnp.h"
+#include <stdarg.h>
+#include <string.h>
 
-#include <strings.h>
+#include "ftlnp.h"
 
 // Local Function Definitions
 
@@ -386,7 +387,7 @@ int FtlnReport(void* vol, ui32 msg, ...) {
 
             // Set TargetFTL-NDM driver call counts and reset internal ones.
             buf->xfs.drvr_stats.ftl.ndm = ftl->stats;
-            bzero(&ftl->stats, sizeof(ftl_ndm_stats));
+            memset(&ftl->stats, 0, sizeof(ftl_ndm_stats));
 
             // Return success.
             return 0;
@@ -462,7 +463,7 @@ int FtlnEraseBlk(FTLN ftl, ui32 b) {
 
     // Call driver to erase block. Return -1 if error.
     ++ftl->stats.erase_block;
-    if (ftl->erase_block(ftl->start_pn + b * ftl->pgs_per_blk, ftl->ndm))
+    if (ndmEraseBlock(ftl->start_pn + b * ftl->pgs_per_blk, ftl->ndm))
         return FtlnFatErr(ftl);
 
     // Increment block wear count and possibly adjust highest.
@@ -622,7 +623,7 @@ void FtlnDecUsed(FTLN ftl, ui32 pn, ui32 vpn) {
 #if FTLN_DEBUG
     // Read page spare area and assert VPNs match.
     ++ftl->stats.read_spare;
-    PfAssert(ftl->read_spare(ftl->start_pn + pn, ftl->spare_buf, ftl->ndm) >= 0);
+    PfAssert(ndmReadSpare(ftl->start_pn + pn, ftl->spare_buf, ftl->ndm) >= 0);
     PfAssert(GET_SA_VPN(ftl->spare_buf) == vpn);
 #endif
 } //lint !e818
diff --git a/zircon/system/ulib/ftl/ftln/ftlnp.h b/zircon/system/ulib/ftl/ftln/ftlnp.h
index 8389072af5d..044472087d2 100644
--- a/zircon/system/ulib/ftl/ftln/ftlnp.h
+++ b/zircon/system/ulib/ftl/ftln/ftlnp.h
@@ -8,10 +8,10 @@
 
 #include <errno.h>
 #include <string.h>
-#include <sys.h>
+#include <ftl_private.h>
 #include <fsprivate.h>
 #include <kprivate/ndm.h>
-#include <kprivate/ftl_mc.h>
+#include <ftl_mc.h>
 
 //
 // Configuration.
@@ -164,68 +164,55 @@
 typedef struct ftln* FTLN;
 typedef const struct ftln* CFTLN;
 struct ftln {
-    CircLink link; // volume list link
-
-    // Driver Functions
-    int (*write_page)(ui32 pn, const void* data, void* spare, void* ndm);
-    int (*read_spare)(ui32 pn, void* spare, void* ndm);
-    int (*read_pages)(ui32 start_pn, ui32 count, void* data, void* spare, void* ndm);
-    int (*write_pages)(ui32 start_pn, ui32 count, const void* data, void* spare, void* ndm);
-    int (*page_check)(ui32 pn, ui8* data, ui8* spare, void* ndm);
-    int (*xfer_page)(ui32 old_pn, ui32 new_pn, ui8* data, ui8* spare, void* ndm);
-    int (*erase_block)(ui32 pn, void* ndm);
-#if INC_FTL_NDM_MLC
-    ui32 (*pair_offset)(ui32 page_offset, void* ndm);
-#endif
+    CircLink link;          // volume list link
 
     // Driver Dependent Variables
-    ui32 num_pages;   // total number of pages
-    ui32 pgs_per_blk; // number of pages in a block
-    ui32 block_size;  // block size in bytes
-    ui32 num_blks;    // number of blocks
-    ui32 page_size;   // page size in bytes
-    ui32 start_pn;    // first page on device for volume
-    void* ndm;        // pointer to NDM this FTL belongs to
+    ui32 num_pages;         // total number of pages
+    ui32 pgs_per_blk;       // number of pages in a block
+    ui32 block_size;        // block size in bytes
+    ui32 num_blks;          // number of blocks
+    ui32 page_size;         // page size in bytes
+    ui32 start_pn;          // first page on device for volume
+    void* ndm;              // pointer to NDM this FTL belongs to
 
-    ui32 flags; // holds various FTL flags
-    ui32* bdata;     // block metadata: flags and counts
-    ui8* blk_wc_lag; // amount block erase counts lag 'high_wc'
-    ui32* mpns;      // array holding phy page # of map pages
+    ui32 flags;             // holds various FTL flags
+    ui32* bdata;            // block metadata: flags and counts
+    ui8* blk_wc_lag;        // amount block erase counts lag 'high_wc'
+    ui32* mpns;             // array holding phy page # of map pages
 
-    FTLMC* map_cache;      // handle to map page cache
-    ui32 free_vpn;         // next free page for volume page write
-    ui32 free_mpn;         // next free page for map page write
-    ui32 mappings_per_mpg; // number of phys page numbers per map page
-    ui32 num_vpages;       // number of volume pages
-    ui32 num_free_blks;    // number of free blocks
-    ui32 num_map_pgs;      // number of pages holding map data
-    ui32 high_wc;          // highest block wear count
-    ui32 high_bc;          // highest map block write count
-    ui32 max_rc;           // per block read wear limit
-    ui32 max_rc_blk;       // if not -1, # of block w/high read cnt
-    ui32 high_bc_mblk;     // last map block
-    ui32 high_bc_mblk_po;  // used page offset on last map block
-    ui32 resume_vblk;      // vblk in interrupted recycle recovery
-    ui32 resume_tblk;      // tmp blk for interrupted recycle recovery
-    ui32 resume_po;        // resume vblk's highest used page offset
+    FTLMC* map_cache;       // handle to map page cache
+    ui32 free_vpn;          // next free page for volume page write
+    ui32 free_mpn;          // next free page for map page write
+    ui32 mappings_per_mpg;  // number of phys page numbers per map page
+    ui32 num_vpages;        // number of volume pages
+    ui32 num_free_blks;     // number of free blocks
+    ui32 num_map_pgs;       // number of pages holding map data
+    ui32 high_wc;           // highest block wear count
+    ui32 high_bc;           // highest map block write count
+    ui32 max_rc;            // per block read wear limit
+    ui32 max_rc_blk;        // if not -1, # of block w/high read cnt
+    ui32 high_bc_mblk;      // last map block
+    ui32 high_bc_mblk_po;   // used page offset on last map block
+    ui32 resume_vblk;       // vblk in interrupted recycle recovery
+    ui32 resume_tblk;       // tmp blk for interrupted recycle recovery
+    ui32 resume_po;         // resume vblk's highest used page offset
 #if INC_ELIST
-    ui32 elist_blk; // if valid, # of block holding erased list
+    ui32 elist_blk;         // if valid, # of block holding erased list
 #endif
-    ftl_ndm_stats stats; // driver call counts
+    ftl_ndm_stats stats;    // driver call counts
 
-    ui8* main_buf; // NAND main page buffer
-    ui8* spare_buf; // spare buffer for single/multi-pg access
+    ui8* main_buf;          // NAND main page buffer
+    ui8* spare_buf;         // spare buffer for single/multi-pg access
 
-    ui8 type;           // type of NAND - SLC or MLC
-    ui8 eb_size;        // spare area size in bytes
-    ui8 copy_end_found; // vblk resume copy-end mark found
-    ui8 deferment;      // # of recycles before applying wear limit
+    ui8 eb_size;            // spare area size in bytes
+    ui8 copy_end_found;     // vblk resume copy-end mark found
+    ui8 deferment;          // # of recycles before applying wear limit
 #if FTLN_DEBUG
-    ui8 max_wc_lag;  // maximum observed lag below hi wear count
-    ui8 max_wc_over; // # of times max WC (0xFF) was exceeded
+    ui8 max_wc_lag;         // maximum observed lag below hi wear count
+    ui8 max_wc_over;        // # of times max WC (0xFF) was exceeded
 #endif
 #if FS_ASSERT
-    ui8 assert_no_recycle; // test no recycle changes physical page #
+    ui8 assert_no_recycle;  // test no recycle changes physical page #
 #endif
     char vol_name[FILENAME_MAX]; // volume name
 };
diff --git a/zircon/system/ulib/ftl/ftln/ndm-driver.cpp b/zircon/system/ulib/ftl/ftln/ndm-driver.cpp
index ce322331de3..507bd12d1a9 100644
--- a/zircon/system/ulib/ftl/ftln/ndm-driver.cpp
+++ b/zircon/system/ulib/ftl/ftln/ndm-driver.cpp
@@ -6,7 +6,7 @@
 
 #include <zircon/assert.h>
 
-#include "kprivate/fsdriver.h"
+#include <ftl_private.h>
 #include "kprivate/fsprivate.h"
 #include "kprivate/ndm.h"
 #include "posix.h"
diff --git a/zircon/system/ulib/ftl/ftln/volume.cpp b/zircon/system/ulib/ftl/ftln/volume.cpp
index 7d7c1453527..e534505815d 100644
--- a/zircon/system/ulib/ftl/ftln/volume.cpp
+++ b/zircon/system/ulib/ftl/ftln/volume.cpp
@@ -5,6 +5,7 @@
 #include <lib/ftl/volume.h>
 #include <zircon/assert.h>
 
+#include <ftl_private.h>
 #include "kprivate/ndm.h"
 #include "posix.h"
 
diff --git a/zircon/system/ulib/ftl/inc/kprivate/fsdriver.h b/zircon/system/ulib/ftl/inc/kprivate/fsdriver.h
index 6f659d6443b..2da63349a3e 100644
--- a/zircon/system/ulib/ftl/inc/kprivate/fsdriver.h
+++ b/zircon/system/ulib/ftl/inc/kprivate/fsdriver.h
@@ -61,46 +61,18 @@ void AssertError(int line, const char* file);
 /* Type Definitions                                                    */
 /***********************************************************************/
 
-// XFS structure holding all driver information
-typedef struct XfsVol {
-    // Driver functions
-    int (*write_pages)(const void* buf, ui32 frst_pg, int cnt, void* vol);
-    int (*read_pages)(void* buf, ui32 frst_pg, int cnt, void* vol);
-    int (*report)(void* vol, ui32 msg, ...);
-
-    const char* name;       // volume name
-    ui32 flags;             // option flags
-    ui32 num_pages;         // number of pages in volume
-    ui32 page_size;         // page size in bytes
-    void* vol;              // driver's volume pointer
-    void* ftl_volume;       // ftl layer (block device) volume
-} XfsVol;
-
 // FTL NDM structure holding all driver information
 typedef struct {
-    ui32 block_size;       // size of a block in bytes
-    ui32 num_blocks;       // total number of blocks
-    ui32 page_size;        // flash page data size in bytes
-    ui32 eb_size;          // flash page spare size in bytes
-    ui32 start_page;       // volume first page on flash
-    ui32 cached_map_pages; // number of map pages to be cached
-    ui32 extra_free;      // volume percentage left unused
-    ui32 read_wear_limit; // device read-wear limit
-    void* ndm;            // driver's NDM pointer
-    ui32 flags;           // option flags
-    ui32 type;            // device type
-
-    // Driver functions:
-    int (*write_data_and_spare)(ui32 pn, const void* data, void* spare, void* ndm);
-    int (*write_pages)(ui32 start_pn, ui32 count, const void* data, void* spare, void* ndm);
-    int (*read_spare)(ui32 pn, void* spare, void* ndm);
-    int (*read_pages)(ui32 start_pn, ui32 count, void* data, void* spare, void* ndm);
-    int (*page_check)(ui32 pn, ui8* data, ui8* spare, void* ndm);
-    int (*transfer_page)(ui32 old_pn, ui32 new_pn, ui8* data, ui8* spare, void* ndm);
-    int (*erase_block)(ui32 pn, void* ndm);
-#if INC_FTL_NDM_MLC
-    ui32 (*pair_offset)(ui32 page_offset, void* ndm);
-#endif
+    ui32 block_size;        // size of a block in bytes
+    ui32 num_blocks;        // total number of blocks
+    ui32 page_size;         // flash page data size in bytes
+    ui32 eb_size;           // flash page spare size in bytes
+    ui32 start_page;        // volume first page on flash
+    ui32 cached_map_pages;  // number of map pages to be cached
+    ui32 extra_free;        // volume percentage left unused
+    ui32 read_wear_limit;   // device read-wear limit
+    void* ndm;              // driver's NDM pointer
+    ui32 flags;             // option flags
 } FtlNdmVol;
 
 // FS Report Events
diff --git a/zircon/system/ulib/ftl/inc/kprivate/ndm.h b/zircon/system/ulib/ftl/inc/kprivate/ndm.h
index 792c8d3780f..7dbfcde93b7 100644
--- a/zircon/system/ulib/ftl/inc/kprivate/ndm.h
+++ b/zircon/system/ulib/ftl/inc/kprivate/ndm.h
@@ -68,7 +68,7 @@ typedef struct {
     ui32 is_block_bad;    // number of is_block_bad() calls
 } NdmDvrStats;
 
-// Driver Interface Structure
+// TargetNDM Configuration Structure
 typedef struct {
     ui32 num_blocks;     // total number of blocks on device
     ui32 max_bad_blocks; // maximum number of bad blocks
@@ -103,10 +103,6 @@ typedef struct {
 #endif
 } NDMDrvr;
 
-// NDM Control Block
-typedef struct ndm* NDM;
-typedef const struct ndm* CNDM;
-
 /***********************************************************************/
 /* Functions Prototypes                                                */
 /***********************************************************************/
@@ -128,11 +124,6 @@ int ndmSavePartitionTable(NDM ndm);
 int ndmDelVols(CNDM ndm);
 int ndmDelVol(CNDM ndm, ui32 part_num);
 
-// User Volume API
-int ndmEraseBlock(ui32 pn, void* ndm_ptr);
-int ndmReadPages(ui32 start_pn, ui32 count, void* data, void* spare, void* ndm_ptr);
-int ndmWritePages(ui32 start_pn, ui32 count, const void* data, void* spare, void* ndm_ptr);
-
 // FTL Volume API
 int ndmAddVolFTL(NDM ndm, ui32 part_no, FtlNdmVol* ftl, XfsVol* xfs);
 
diff --git a/zircon/system/ulib/ftl/inc/sys.h b/zircon/system/ulib/ftl/inc/sys.h
index 91ae7a1dfe3..67887992dde 100644
--- a/zircon/system/ulib/ftl/inc/sys.h
+++ b/zircon/system/ulib/ftl/inc/sys.h
@@ -8,38 +8,9 @@
 extern "C" {
 #endif
 
-#include <stdio.h>
-#include <stdarg.h>
 #include <stdlib.h>
-#include <time.h>
 #include <targetos.h>
 
-/***********************************************************************/
-/* Symbol Definitions                                                  */
-/***********************************************************************/
-#define VERBOSE 1
-
-/***********************************************************************/
-/* Definitions related to reading/writing NVRAM memory.                */
-/***********************************************************************/
-int NvRead(const char* name, void* data, int type);
-int NvReadBin(const char* name, void* data, int len);
-int NvReadStr(const char* name, void* data, int maxlen);
-int NvWrite(const char* name, const void* data, int type);
-int NvWriteBin(const char* name, const void* data, int len);
-int NvReadBinSize(const char* name);
-#define NV_BYTE 0
-#define NV_SHORT 1
-#define NV_LONG 2
-#define NV_STRING 3
-#define NV_IP_ADDR 4
-#define NV_ETH_ADDR 5
-#define NV_ERR_LOG 6
-#define NV_IP6_ADDR 7
-#define NV_BINARY 8
-int NvDelete(const char* name, int type);
-void NvSave(void);
-
 void free_clear(void* alloc_ptr_addr);
 
 // Cache Line-Aligned Allocation/Deallocation Routines
diff --git a/zircon/system/ulib/ftl/ndm/ndm_init.c b/zircon/system/ulib/ftl/ndm/ndm_init.c
index e87040a7085..7aaa52e3684 100644
--- a/zircon/system/ulib/ftl/ndm/ndm_init.c
+++ b/zircon/system/ulib/ftl/ndm/ndm_init.c
@@ -1153,10 +1153,9 @@ NDM ndmAddDev(const NDMDrvr* dvr) {
     if (FLAG_IS_SET(dvr->flags, FSF_TRANSFER_PAGE)) {
         ndm->dev_ndm = ndm->dev;
         ndm->xfr_page = dvr->transfer_page;
-    }
 
     // Else use internal read-page/write-page substitute.
-    else {
+    } else {
         ndm->dev_ndm = ndm;
         ndm->xfr_page = ndm_xfr_page;
     }
@@ -1167,9 +1166,6 @@ NDM ndmAddDev(const NDMDrvr* dvr) {
         ndm->write_pages = dvr->write_pages;
     }
 
-    // Set the device type.
-    ndm->dev_type = dvr->type;
-
     // Initialize the NDM.
     if (init_ndm(ndm))
         goto ndmAddDe_err;
diff --git a/zircon/system/ulib/ftl/ndm/ndm_intrnl.c b/zircon/system/ulib/ftl/ndm/ndm_intrnl.c
index a0e0b23258e..a3e8919c034 100644
--- a/zircon/system/ulib/ftl/ndm/ndm_intrnl.c
+++ b/zircon/system/ulib/ftl/ndm/ndm_intrnl.c
@@ -165,11 +165,10 @@ static int wr_ctrl_page(NDM ndm, ui32 cpc, ui32* curr_pnp, ui32* badblkp) {
         if (rc == -2) {
             FsError2(NDM_EIO, EIO);
             return rc;
-        }
 
         // Else bad block caused write failure, output block number and
         // return bad block indication.
-        else {
+        } else {
             PfAssert(rc == -1);
 #if NDM_DEBUG
             printf("wr_ctrl_page: bad block for #%u at page #%u\n", cpc, cpn);
@@ -688,8 +687,7 @@ static ui32 get_pbn(NDM ndm, ui32 vbn, int reason) {
     if (reason == WR_MAPPING) {
         ndm->last_wr_pbn = bn;
         ndm->last_wr_vbn = vbn;
-    } else // reason == RD_MAPPING
-    {
+    } else { // reason == RD_MAPPING
         ndm->last_rd_pbn = bn;
         ndm->last_rd_vbn = vbn;
     }
@@ -701,15 +699,15 @@ static ui32 get_pbn(NDM ndm, ui32 vbn, int reason) {
 //  write_page: Write a page to flash for FTL
 //
 //      Inputs: ndm = pointer to NDM control block
-//              pn = virtual page number
+//              vpn = virtual page number
 //              buf = pointer to main page buffer array
 //              spare = pointer to spare page buffer array
 //              action = NDM_NONE, NDM_ECC, or NDM_ECC_VAL
 //
 //     Returns: 0 on success, -2 on fatal error
 //
-static int write_page(NDM ndm, ui32 vpn, const ui8* data, ui8* spare, int action) {
-    ui32 vbn, bn, pn;
+static int write_page(NDM ndm, uint32_t vpn, const ui8* buf, ui8* spare, int action) {
+    uint32_t vbn, bn, pn;
     int rc;
 
     // Compute the virtual block number and check for error.
@@ -730,7 +728,7 @@ static int write_page(NDM ndm, ui32 vpn, const ui8* data, ui8* spare, int action
         pn = bn * ndm->pgs_per_blk + vpn % ndm->pgs_per_blk;
 
         // Call TargetNDM driver to write the page.
-        rc = ndm->write_page(pn, data, spare, action, ndm->dev);
+        rc = ndm->write_page(pn, buf, spare, action, ndm->dev);
 
         // Return 0 if successful.
         if (rc == 0)
@@ -751,21 +749,72 @@ static int write_page(NDM ndm, ui32 vpn, const ui8* data, ui8* spare, int action
     }
 } //lint !e818
 
-//   ftl_wr_pg: FTL driver function - write page (data + spare)
+//   read_page:  FTL driver function - read page (data only)
+//
+//      Inputs: vpn = virtual page number
+//              buf = pointer to buffer to copy data to
+//              ndm = NDM control block handle
+//
+//     Returns: 0 on success, -1 on uncorrectable ECC error, -2 on
+//              permanent fatal error, 1 if block page belongs to
+//              needs to be recycled
+//
+static int read_page(ui32 vpn, void* buf, NDM ndm) {
+    ui32 vbn, bn, pn;
+    int status;
+
+    // Compute the virtual block number based on virtual page number.
+    vbn = vpn / ndm->pgs_per_blk;
+    if (vbn >= ndm->num_vblks) {
+        FsError2(NDM_ASSERT, EINVAL);
+        return -2;
+    }
+
+    // Grab exclusive access to TargetNDM internals.
+    semPend(ndm->sem, WAIT_FOREVER);
+
+    // Get the physical block number from virtual one.
+    bn = get_pbn(ndm, vbn, RD_MAPPING);
+    if (bn == (ui32)-1) {
+        semPostBin(ndm->sem);
+        return -2;
+    }
+
+    // Compute physical page number.
+    pn = bn * ndm->pgs_per_blk + vpn % ndm->pgs_per_blk;
+
+    // Read decode page data.
+    status = ndm->read_page(pn, buf, ndm->spare_buf, ndm->dev);
+
+    // Release exclusive access to TargetNDM internals.
+    semPostBin(ndm->sem);
+
+    // If error, set errno. Return status.
+    if (status) {
+        if (status == -1)
+            FsError2(NDM_RD_ECC_FAIL, EINVAL);
+        else if (status == -2)
+            FsError2(NDM_EIO, EIO);
+    }
+    return status;
+}
+
+// Global Function Definitions
+
+//   ndmWritePage: FTL driver function - write page (data + spare)
 //
 //      Inputs: vpn = virtual page number
 //              data = pointer to buffer containing data to write
 //              spare = pointer to buffer containing spare bytes
-//              ndm_ptr = NDM control block handle
+//              ndm = NDM control block handle
 //
 //     Returns: 0 on success, -2 on fatal error
 //
-static int ftl_wr_pg(ui32 vpn, const void* data, void* spare, void* ndm_ptr) {
+int ndmWritePage(uint32_t vpn, const ui8* data, ui8* spare, NDM ndm) {
     int action, status;
-    NDM ndm = ndm_ptr;
 
     // If volume block, just ECC, else request validity checks too.
-    if (RD32_LE(&((ui8*)spare)[5]) == (ui32)-1)
+    if (RD32_LE(&spare[5]) == (ui32)-1)
         action = NDM_ECC;
     else
         action = NDM_ECC_VAL;
@@ -781,18 +830,17 @@ static int ftl_wr_pg(ui32 vpn, const void* data, void* spare, void* ndm_ptr) {
     return status;
 } //lint !e818
 
-// ftl_rd_spare: FTL driver function - read/decode page spare area
+// ndmReadSpare: FTL driver function - read/decode page spare area
 //
 //      Inputs: vpn = virtual page number
 //              spare = buffer to read sparea area into
-//              ndm_ptr = NDM control block handle
+//              ndm = NDM control block handle
 //
 //     Returns: 0 on success, -1 on ECC error, -2 on fatal error, 1 if
 //              block page belongs to needs to be recycled
 //
-static int ftl_rd_spare(ui32 vpn, void* spare, void* ndm_ptr) {
-    ui32 vbn, bn, pn;
-    NDM ndm = ndm_ptr;
+int ndmReadSpare(uint32_t vpn, ui8* spare, NDM ndm) {
+    uint32_t vbn, bn, pn;
     int status;
 
     // Compute virtual block number. Return -2 if out-of-range.
@@ -825,19 +873,18 @@ static int ftl_rd_spare(ui32 vpn, void* spare, void* ndm_ptr) {
     return status;
 }
 
-// ftl_check_pg: FTL driver function - determine status of a page
+// ndmCheckPage: FTL driver function - determine status of a page
 //
 //      Inputs: vpn = virtual page number
 //              data = buffer that will hold page data
 //              spare = buffer that will hold page spare
-//              ndm_ptr = NDM control block handle
+//              ndm = NDM control block handle
 //
 //     Returns: -1 if error, else NDM_PAGE_ERASED (0), NDM_PAGE_VALID
 //              (1), or NDM_PAGE_INVALID (2)
 //
-static int ftl_check_pg(ui32 vpn, ui8* data, ui8* spare, void* ndm_ptr) {
-    NDM ndm = ndm_ptr;
-    ui32 vbn, bn, pn;
+int ndmCheckPage(uint32_t vpn, ui8* data, ui8* spare, NDM ndm) {
+    uint32_t vbn, bn, pn;
     int status;
 
     // Compute the virtual block number.
@@ -869,71 +916,19 @@ static int ftl_check_pg(ui32 vpn, ui8* data, ui8* spare, void* ndm_ptr) {
     return status;
 }
 
-//   read_page:  FTL driver function - read page (data only)
-//
-//      Inputs: vpn = virtual page number
-//              buf = pointer to buffer to copy data to
-//              ndm_ptr = NDM control block handle
-//
-//     Returns: 0 on success, -1 on uncorrectable ECC error, -2 on
-//              permanent fatal error, 1 if block page belongs to
-//              needs to be recycled
-//
-static int read_page(ui32 vpn, void* buf, void* ndm_ptr) {
-    NDM ndm = ndm_ptr;
-    ui32 vbn, bn, pn;
-    int status;
-
-    // Compute the virtual block number based on virtual page number.
-    vbn = vpn / ndm->pgs_per_blk;
-    if (vbn >= ndm->num_vblks) {
-        FsError2(NDM_ASSERT, EINVAL);
-        return -2;
-    }
-
-    // Grab exclusive access to TargetNDM internals.
-    semPend(ndm->sem, WAIT_FOREVER);
-
-    // Get the physical block number from virtual one.
-    bn = get_pbn(ndm, vbn, RD_MAPPING);
-    if (bn == (ui32)-1) {
-        semPostBin(ndm->sem);
-        return -2;
-    }
-
-    // Compute physical page number.
-    pn = bn * ndm->pgs_per_blk + vpn % ndm->pgs_per_blk;
-
-    // Read decode page data.
-    status = ndm->read_page(pn, buf, ndm->spare_buf, ndm->dev);
-
-    // Release exclusive access to TargetNDM internals.
-    semPostBin(ndm->sem);
-
-    // If error, set errno. Return status.
-    if (status) {
-        if (status == -1)
-            FsError2(NDM_RD_ECC_FAIL, EINVAL);
-        else if (status == -2)
-            FsError2(NDM_EIO, EIO);
-    }
-    return status;
-}
-
-// ftl_xfr_page: FTL driver function - transfer a page
+// ndmTransferPage: FTL driver function - transfer a page
 //
 //      Inputs: old_vpn = old virtual page number
 //              new_vpn = new virtual page number
 //              buf = temporary buffer for swapping main page data
 //              spare = buffer holding new page's spare data
-//              ndm_ptr = NDM control block handle
+//              ndm = NDM control block handle
 //
 //     Returns: 0 on success, -2 on fatal error, 1 on ECC decode error
 //
-static int ftl_xfr_page(ui32 old_vpn, ui32 new_vpn, ui8* buf, ui8* spare, void* ndm_ptr) {
-    ui32 old_vbn, new_vbn, old_bn, new_bn, old_pn, new_pn;
+int ndmTransferPage(uint32_t old_vpn, uint32_t new_vpn, ui8* buf, ui8* spare, NDM ndm) {
+    uint32_t old_vbn, new_vbn, old_bn, new_bn, old_pn, new_pn;
     int status, action;
-    NDM ndm = ndm_ptr;
 
     // Grab exclusive access to TargetNDM internals.
     semPend(ndm->sem, WAIT_FOREVER);
@@ -1004,23 +999,19 @@ static int ftl_xfr_page(ui32 old_vpn, ui32 new_vpn, ui8* buf, ui8* spare, void*
 } //lint !e818
 
 #if INC_FTL_NDM_MLC
-// pair_offset: FTL driver function (MLC NAND) - pair offset
+// ndmPairOffset: FTL driver function (MLC NAND) - pair offset
 //
 //      Inputs: page_offset = page offset within block
-//              ndm_ptr = NDM control block handle
+//              ndm = NDM control block handle
 //
 //     Returns: Pair page offset within block if any, page offset
 //              otherwise
 //
-static ui32 pair_offset(ui32 page_offset, void* ndm_ptr) {
-    NDM ndm = ndm_ptr;
-
+uint32_t ndmPairOffset(uint32_t page_offset, CNDM ndm) {
     return ndm->pair_offset(page_offset, ndm->dev);
 }
 #endif // INC_FTL_NDM_MLC
 
-// Global Function Definitions
-
 // ndmMarkBadBlock: Mark virtual block bad and do bad block recovery
 //
 //      Inputs: ndm = pointer to NDM control block
@@ -1296,12 +1287,12 @@ ui32 ndmGetNumVBlocks(CNDM ndm) {
 //
 //      Inputs: ndm = pointer to NDM control block
 //              part_num = NDM partition number
-//              ftl = pointer to FTL config structure
+//              ftl_cfg = pointer to FTL config structure
 //              xfs = XFS volume information
 //
 //     Returns: 0 on success, -1 on error
 //
-int ndmAddVolFTL(NDM ndm, ui32 part_num, FtlNdmVol* ftl, XfsVol* xfs) {
+int ndmAddVolFTL(NDM ndm, ui32 part_num, FtlNdmVol* ftl_cfg, XfsVol* xfs) {
     NDMPartition* part;
 
     // Check partition number.
@@ -1313,32 +1304,17 @@ int ndmAddVolFTL(NDM ndm, ui32 part_num, FtlNdmVol* ftl, XfsVol* xfs) {
     if (part->first_block + part->num_blocks > ndm->num_vblks)
         return FsError2(NDM_CFG_ERR, ENOSPC);
 
-    // Set the fields dependent on flash geometry.
-    ftl->page_size = ndm->page_size;
-    ftl->eb_size = ndm->eb_size;
-    ftl->block_size = ndm->block_size;
-
-    // Set up the non-customizable part of the FTL/XFS drivers.
-    ftl->ndm = ndm;
-    ftl->start_page = part->first_block * ndm->pgs_per_blk;
-    ftl->num_blocks = part->num_blocks;
-    ftl->type = ndm->dev_type;
+    // Assign the NDM-supplied configuration.
+    ftl_cfg->page_size = ndm->page_size;
+    ftl_cfg->eb_size = ndm->eb_size;
+    ftl_cfg->block_size = ndm->block_size;
+    ftl_cfg->ndm = ndm;
+    ftl_cfg->start_page = part->first_block * ndm->pgs_per_blk;
+    ftl_cfg->num_blocks = part->num_blocks;
     xfs->name = part->name;
 
-    // Provide the TargetNDM lower-level interface to TargetFTL-NDM.
-    ftl->erase_block = ndmEraseBlock;
-    ftl->write_data_and_spare = ftl_wr_pg;
-    ftl->write_pages = ndmWritePages;
-    ftl->read_spare = ftl_rd_spare;
-    ftl->read_pages = ndmReadPages;
-    ftl->page_check = ftl_check_pg;
-    ftl->transfer_page = ftl_xfr_page;
-#if INC_FTL_NDM_MLC
-    ftl->pair_offset = pair_offset;
-#endif
-
     // Add an FTL to this partition. Return status.
-    return FtlnAddVol(ftl, xfs);
+    return FtlnAddVol(ftl_cfg, xfs);
 }
 
 // ndmReadPages: FTL driver function - read multiple consecutive
@@ -1346,20 +1322,19 @@ int ndmAddVolFTL(NDM ndm, ui32 part_num, FtlNdmVol* ftl, XfsVol* xfs) {
 //
 //      Inputs: vpn = starting virtual page number
 //              count = number of consecutive virtual pages to read
-//              data = pointer to buffer to copy main page data to
+//              buf = pointer to buffer to copy main page data to
 //              spare = points to array of page spare data sets
-//              ndm_ptr = NDM control block handle
+//              ndm = NDM control block handle
 //
 //     Returns: -2 on fatal error, -1 on error, 0 on success, 1 if
 //              block needs to be recycled
 //
-int ndmReadPages(ui32 vpn, ui32 count, void* data, void* spare, void* ndm_ptr) {
-    NDM ndm = ndm_ptr;
+int ndmReadPages(uint32_t vpn, uint32_t count, ui8* buf, ui8* spare, NDM ndm) {
     int status;
 
     // If NDM driver supplies read_pages(), use it.
     if (ndm->read_pages) {
-        ui32 vbn, bn, pn;
+        uint32_t vbn, bn, pn;
 
         // Compute the virtual block number based on virtual page number.
         vbn = vpn / ndm->pgs_per_blk;
@@ -1382,7 +1357,7 @@ int ndmReadPages(ui32 vpn, ui32 count, void* data, void* spare, void* ndm_ptr) {
         pn = bn * ndm->pgs_per_blk + vpn % ndm->pgs_per_blk;
 
         // Read pages.
-        status = ndm->read_pages(pn, count, data, spare, ndm->dev);
+        status = ndm->read_pages(pn, count, buf, spare, ndm->dev);
 
         // Release exclusive access to NDM and return status.
         semPostBin(ndm->sem);
@@ -1391,14 +1366,13 @@ int ndmReadPages(ui32 vpn, ui32 count, void* data, void* spare, void* ndm_ptr) {
 
     // Else loop over all pages, reading one at a time.
     else {
-        ui32 i;
+        uint32_t i;
         int rd_status;
-        ui8* buf = data;
 
         // Loop over virtual pages.
         for (status = 0, i = 0; i < count; ++i, ++vpn, buf += ndm->page_size) {
             // Issue current page read request.
-            rd_status = read_page(vpn, buf, ndm_ptr);
+            rd_status = read_page(vpn, buf, ndm);
 
             // If error, return.
             if (rd_status < 0)
@@ -1421,13 +1395,12 @@ int ndmReadPages(ui32 vpn, ui32 count, void* data, void* spare, void* ndm_ptr) {
 //              count = number of consecutive virtual pages to write
 //              data = points to array of page main data sets
 //              spare = points to array of page spare data sets
-//              ndm_ptr = NDM control block handle
+//              ndm = NDM control block handle
 //
 //     Returns: -1 on error, 0 on success
 //
-int ndmWritePages(ui32 vpn, ui32 count, const void* data, void* spare, void* ndm_ptr) {
+int ndmWritePages(uint32_t vpn, uint32_t count, const ui8* data, ui8* spare, NDM ndm) {
     int action, rc = 0;
-    NDM ndm = ndm_ptr;
 
     // Ensure all writes are to the same virtual block.
     PfAssert(count);
@@ -1444,7 +1417,7 @@ int ndmWritePages(ui32 vpn, ui32 count, const void* data, void* spare, void* ndm
 
     // If NDM driver supplies write_pages(), use it.
     if (ndm->write_pages) {
-        ui32 vbn;
+        uint32_t vbn;
 
         // Compute the virtual block number based on virtual page number.
         vbn = vpn / ndm->pgs_per_blk;
@@ -1455,11 +1428,11 @@ int ndmWritePages(ui32 vpn, ui32 count, const void* data, void* spare, void* ndm
 
         // Writing to flash until success or failure other than bad block.
         for (;;) {
-            ui32 bn, pn;
+            uint32_t bn, pn;
 
             // Get the physical block number from virtual one.
             bn = get_pbn(ndm, vbn, WR_MAPPING);
-            if (bn == (ui32)-1) {
+            if (bn == (uint32_t)-1) {
                 rc = -1;
                 break;
             }
@@ -1489,7 +1462,7 @@ int ndmWritePages(ui32 vpn, ui32 count, const void* data, void* spare, void* ndm
 
     // Else loop over all pages, writing one at a time.
     else {
-        ui32 past = vpn + count;
+        uint32_t past = vpn + count;
         const ui8* curr_data = data;
         ui8* curr_spare = spare;
 
@@ -1634,12 +1607,11 @@ int ndmWritePartition(NDM ndm, const NDMPartition* part, ui32 part_num, const ch
 // ndmEraseBlock: Erase a block
 //
 //      Inputs: vpn = base virtual page for block to be erased
-//              ndm_ptr = NDM control block handle
+//              ndm = NDM control block handle
 //
 //     Returns: 0 on success, -1 on fatal error
 //
-int ndmEraseBlock(ui32 vpn, void* ndm_ptr) {
-    NDM ndm = ndm_ptr;
+int ndmEraseBlock(ui32 vpn, NDM ndm) {
     ui32 vbn, bn, pn;
     int status;
 
diff --git a/zircon/system/ulib/ftl/ndm/ndmp.h b/zircon/system/ulib/ftl/ndm/ndmp.h
index 5e0a408fc66..d3600473a05 100644
--- a/zircon/system/ulib/ftl/ndm/ndmp.h
+++ b/zircon/system/ulib/ftl/ndm/ndmp.h
@@ -11,6 +11,7 @@
 #include <stdio.h>
 #include <errno.h>
 
+#include <ftl_private.h>
 #include <sys.h>
 #include <kprivate/ndm.h>
 
@@ -131,7 +132,6 @@ struct ndm {
     ui32 pgs_per_blk;  // number of pages in a block
     ui32 page_size;    // page size in bytes
     ui8 eb_size;       // spare area size in bytes
-    ui8 dev_type;      // NAND device type
 };
 
 //
diff --git a/zircon/system/ulib/ftl/utils/aalloc.c b/zircon/system/ulib/ftl/utils/aalloc.c
index 3441ec93470..aa4e1008f94 100644
--- a/zircon/system/ulib/ftl/utils/aalloc.c
+++ b/zircon/system/ulib/ftl/utils/aalloc.c
@@ -6,9 +6,10 @@
 #include <stdlib.h>
 #include <sys.h>
 #include <bsp.h>
+#include <ftl_private.h>
 
 #ifndef CACHE_LINE_SIZE
-#error bsp.h must define CACHE_LINE_SIZE
+#error CACHE_LINE_SIZE is undefined
 #endif
 
 // Free allocated memory and clear pointer to it.
diff --git a/zircon/system/ulib/ftl/utils/crc32_tbl.c b/zircon/system/ulib/ftl/utils/crc32_tbl.c
index 313d9ce77d6..712e05007d5 100644
--- a/zircon/system/ulib/ftl/utils/crc32_tbl.c
+++ b/zircon/system/ulib/ftl/utils/crc32_tbl.c
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <sys.h>
+#include <ftl_private.h>
 
 // CRC Lookup Table.
 const ui32 Crc32Tbl[256] = {
diff --git a/zircon/system/ulib/ftl/utils/fsmem.c b/zircon/system/ulib/ftl/utils/fsmem.c
index a137cf71338..fccdd9fdfde 100644
--- a/zircon/system/ulib/ftl/utils/fsmem.c
+++ b/zircon/system/ulib/ftl/utils/fsmem.c
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <fsprivate.h>
 #include <stdlib.h>
+
+#include <ftl_private.h>
+#include <fsprivate.h>
 #include <sys.h>
 
 // Wrapper for malloc()
 void* FsMalloc(size_t size) {
     void* mem = malloc(size);
-    if (mem == NULL)
-        FsError(ENOMEM);
 
     return mem;
 }
@@ -18,8 +18,6 @@ void* FsMalloc(size_t size) {
 // Wrapper for calloc()
 void* FsCalloc(size_t nitems, size_t size) {
     void* mem = calloc(nitems, size);
-    if (mem == NULL)
-        FsError(ENOMEM);
 
     return mem;
 }
@@ -27,8 +25,6 @@ void* FsCalloc(size_t nitems, size_t size) {
 // Wrapper for aalloc()
 void* FsAalloc(size_t size) {
     void* mem = aalloc(size);
-    if (mem == NULL)
-        FsError(ENOMEM);
 
     return mem;
 }
diff --git a/zircon/system/ulib/ftl/utils/fsys.c b/zircon/system/ulib/ftl/utils/fsys.c
index 657beefbb2b..496bd312ba8 100644
--- a/zircon/system/ulib/ftl/utils/fsys.c
+++ b/zircon/system/ulib/ftl/utils/fsys.c
@@ -2,11 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <sys.h>
+#include <ftl_private.h>
 #include <kprivate/fsprivate.h>
 
-#include <string.h>
-
 // Lookup for number of bits in half byte.
 const ui8 NumberOnes[] = {
     //0 1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
diff --git a/zircon/system/ulib/ftl/utils/fsysinit.c b/zircon/system/ulib/ftl/utils/fsysinit.c
index eb54ea1dccd..c4c75f175fe 100644
--- a/zircon/system/ulib/ftl/utils/fsysinit.c
+++ b/zircon/system/ulib/ftl/utils/fsysinit.c
@@ -6,6 +6,7 @@
 #include <stdio.h>
 
 #include "kernel.h"
+#include <ftl_private.h>
 #include "fsprivate.h"
 
 #include <lib/backtrace-request/backtrace-request.h>
@@ -38,5 +39,6 @@ int FtlInit(void) {
     FileSysSem = semCreate("fsys sem", 1, OS_FIFO);
     if (FileSysSem == NULL)
         return -1;
+
     return 0;
 }
diff --git a/zircon/system/ulib/ftl/utils/ftl_mc.c b/zircon/system/ulib/ftl/utils/ftl_mc.c
index 4653b220c34..46b3a105f4b 100644
--- a/zircon/system/ulib/ftl/utils/ftl_mc.c
+++ b/zircon/system/ulib/ftl/utils/ftl_mc.c
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include <sys.h>
-#include "ftl_mc.h"
+
+#include <ftl_private.h>
+#include <ftl_mc.h>
 #include <fsprivate.h>
 
 // Configuration
diff --git a/zircon/system/ulib/ftl/inc/kprivate/ftl_mc.h b/zircon/system/ulib/ftl/utils/ftl_mc.h
similarity index 100%
rename from zircon/system/ulib/ftl/inc/kprivate/ftl_mc.h
rename to zircon/system/ulib/ftl/utils/ftl_mc.h
diff --git a/zircon/system/ulib/ftl/utils/kernel.h b/zircon/system/ulib/ftl/utils/kernel.h
index e2fa97750f6..005ac3201b5 100644
--- a/zircon/system/ulib/ftl/utils/kernel.h
+++ b/zircon/system/ulib/ftl/utils/kernel.h
@@ -25,8 +25,6 @@ void semDelete(SEM* semp);
 void semPostBin(SEM sem);
 int semPend(SEM sem, int wait_opt);
 
-#define ENOMEM 12 // out of memory
-
 #ifdef __cplusplus
 }
 #endif
-- 
GitLab