vboot: Remove FTS code

flash_ts driver (from Android) was pulled to support Sonic. But now we
go a different route, this CL is to drop the FTS code.

BUG=chromium:436597
BRANCH=none
TEST=unittest

Change-Id: I86d6273f9f5f642b504ccb6a76e005cda12d0e78
Reviewed-on: https://chromium-review.googlesource.com/231896
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Commit-Queue: Nam Nguyen <namnguyen@chromium.org>
Tested-by: Nam Nguyen <namnguyen@chromium.org>
diff --git a/Makefile b/Makefile
index b1f5cbe..2427c83 100644
--- a/Makefile
+++ b/Makefile
@@ -270,7 +270,6 @@
 	firmware/lib/cgptlib/cgptlib.c \
 	firmware/lib/cgptlib/cgptlib_internal.c \
 	firmware/lib/cgptlib/crc32.c \
-	firmware/lib/cgptlib/mtdlib.c \
 	firmware/lib/gpt_misc.c \
 	firmware/lib/utility_string.c \
 	firmware/lib/vboot_api_kernel.c \
@@ -362,9 +361,6 @@
 	cgpt/cgpt_repair.c \
 	cgpt/cgpt_prioritize.c \
 	cgpt/cgpt_common.c \
-	cgpt/flash_ts.c \
-	cgpt/flash_ts_drv.c \
-	firmware/lib/cgptlib/mtdlib.c \
 	futility/dump_kernel_config_lib.c \
 	host/arch/${ARCH}/lib/crossystem_arch.c \
 	host/lib/crossystem.c \
@@ -391,11 +387,8 @@
 	cgpt/cgpt_common.c \
 	cgpt/cgpt_create.c \
 	cgpt/cgpt_prioritize.c \
-	cgpt/flash_ts.c \
-	cgpt/flash_ts_drv.c \
 	firmware/lib/cgptlib/cgptlib_internal.c \
 	firmware/lib/cgptlib/crc32.c \
-	firmware/lib/cgptlib/mtdlib.c \
 	firmware/lib/crc8.c \
 	firmware/lib/tpm_lite/tlcl.c \
 	firmware/lib/utility_string.c \
@@ -423,11 +416,8 @@
 	cgpt/cgpt_common.c \
 	cgpt/cgpt_create.c \
 	cgpt/cgpt_prioritize.c \
-	cgpt/flash_ts.c \
-	cgpt/flash_ts_drv.c \
 	firmware/lib/cgptlib/cgptlib_internal.c \
 	firmware/lib/cgptlib/crc32.c \
-	firmware/lib/cgptlib/mtdlib.c \
 	firmware/lib/utility_string.c \
 	firmware/stub/utility_stub.c \
 	futility/dump_kernel_config_lib.c
@@ -457,9 +447,7 @@
 	cgpt/cmd_legacy.c \
 	cgpt/cmd_prioritize.c \
 	cgpt/cmd_repair.c \
-	cgpt/cmd_show.c \
-	cgpt/flash_ts.c \
-	cgpt/flash_ts_drv.c
+	cgpt/cmd_show.c
 
 CGPT_OBJS = ${CGPT_SRCS:%.c=${BUILD}/%.o}
 ALL_OBJS += ${CGPT_OBJS}
@@ -996,10 +984,6 @@
 ${BUILD}/tests/vboot_common2_tests: LDLIBS += ${CRYPTO_LIBS}
 ${BUILD}/tests/vboot_common3_tests: LDLIBS += ${CRYPTO_LIBS}
 
-${BUILD}/tests/cgptlib_test: OBJS += \
-	${BUILD}/firmware/lib/cgptlib/mtdlib_unused.o
-${BUILD}/tests/cgptlib_test: ${BUILD}/firmware/lib/cgptlib/mtdlib_unused.o
-
 ${BUILD}/utility/bmpblk_utility: LD = ${CXX}
 ${BUILD}/utility/bmpblk_utility: LDLIBS = -llzma -lyaml
 
diff --git a/cgpt/cgpt.c b/cgpt/cgpt.c
index ccf7318..3809200 100644
--- a/cgpt/cgpt.c
+++ b/cgpt/cgpt.c
@@ -52,45 +52,6 @@
   printf("\nFor more detailed usage, use %s COMMAND -h\n\n", progname);
 }
 
-static int is_pow2(size_t v) {
-  return v && (v & (v - 1)) == 0;
-}
-
-static int parse_nand_option(const char *arg) {
-  int bytes_per_page, pages_per_block, fts_block_offset, fts_block_size;
-
-  if ('=' != arg[0])
-    return -1;
-
-  arg++;
-  bytes_per_page = atoi(arg);
-  arg = strchr(arg, ',');
-  if (!arg)
-    return -1;
-
-  arg++;
-  pages_per_block = atoi(arg);
-  arg = strchr(arg, ',');
-  if (!arg)
-    return -1;
-
-  arg++;
-  fts_block_offset = atoi(arg);
-  arg = strchr(arg, ',');
-  if (!arg)
-    return -1;
-
-  arg++;
-  fts_block_size = atoi(arg);
-  if (fts_block_size == 0 || !is_pow2(pages_per_block) ||
-      !is_pow2(bytes_per_page) || bytes_per_page < 512) {
-    return -1;
-  }
-  EnableNandImage(bytes_per_page, pages_per_block, fts_block_offset,
-                  fts_block_size);
-  return 0;
-}
-
 int main(int argc, char *argv[]) {
   int i;
   int match_count = 0;
@@ -103,25 +64,6 @@
   else
     progname = argv[0];
 
-
-  for (i = 1; i < argc; ++i) {
-    if (0 == strncmp(argv[i], "-N", 2)) {
-      if (!parse_nand_option(argv[i] + 2)) {
-        int j;
-
-        // Remove it form the list.
-        for (j = i; j < argc - 1; j++)
-          argv[j] = argv[j + 1];
-        argc--;
-        break;
-      }
-      // Bad nand config.
-      printf("Nand option must fit: -N=<bytes_per_page>,<pages_per_block>,"
-             "<block_offset_of_partition>,<block_size_of_partition>\n");
-      return CGPT_FAILED;
-    }
-  }
-
   if (argc < 2) {
     Usage();
     return CGPT_FAILED;
diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h
index bb3438a..ff9e106 100644
--- a/cgpt/cgpt.h
+++ b/cgpt/cgpt.h
@@ -13,7 +13,6 @@
 #include "cgpt_endian.h"
 #include "cgptlib.h"
 #include "gpt.h"
-#include "mtdlib.h"
 
 struct legacy_partition {
   uint8_t  status;
@@ -43,23 +42,11 @@
 // Handle to the drive storing the GPT.
 struct drive {
   uint64_t size;    /* total size (in bytes) */
-  int is_mtd;
   GptData gpt;
-  MtdData mtd;
   struct pmbr pmbr;
   int fd;       /* file descriptor */
 };
 
-struct nand_layout {
-  int enabled;
-  int use_host_ioctl; /* Use ioctl() on /dev/fts to read/write. */
-  int bytes_per_page, pages_per_block, fts_block_offset, fts_block_size;
-};
-
-/* Write a NAND/MTD image instead of GPT. */
-void EnableNandImage(int bytes_per_page, int pages_per_block,
-                     int fts_block_offset, int fts_block_size);
-
 // Opens a block device or file, loads raw GPT data from it.
 // 'mode' should be O_RDONLY or O_RDWR.
 // If 'drive_size' is 0, both the partitions and GPT structs reside on the same
@@ -156,11 +143,9 @@
 int SupportedType(const char *name, Guid *type);
 void PrintTypes(void);
 void EntryDetails(GptEntry *entry, uint32_t index, int raw);
-void MtdEntryDetails(MtdDiskPartition *entry, uint32_t index, int raw);
 
 uint32_t GetNumberOfEntries(const struct drive *drive);
 GptEntry *GetEntry(GptData *gpt, int secondary, uint32_t entry_index);
-MtdDiskPartition *MtdGetEntry(MtdData *mtd, int secondary, uint32_t index);
 
 void SetPriority(struct drive *drive, int secondary, uint32_t entry_index,
                  int priority);
@@ -184,8 +169,6 @@
 
 int IsUnused(struct drive *drive, int secondary, uint32_t index);
 int IsKernel(struct drive *drive, int secondary, uint32_t index);
-int LookupMtdTypeForGuid(const Guid *type);
-const Guid *LookupGuidForMtdType(int type);
 
 // Optional. Applications that need this must provide an implementation.
 //
diff --git a/cgpt/cgpt_add.c b/cgpt/cgpt_add.c
index 9bbc3fb..d6b3cab 100644
--- a/cgpt/cgpt_add.c
+++ b/cgpt/cgpt_add.c
@@ -95,32 +95,6 @@
   return 0;
 }
 
-static int MtdSetEntryAttributes(struct drive *drive,
-                                 uint32_t index,
-                                 CgptAddParams *params) {
-  MtdDiskPartition *entry;
-
-  entry = MtdGetEntry(&drive->mtd, PRIMARY, index);
-  if (params->set_begin) {
-    uint64_t start = params->begin * drive->mtd.sector_bytes;
-    memcpy(&entry->starting_offset, &start, sizeof(params->begin));
-  }
-  if (params->set_size) {
-    uint64_t start;
-    uint64_t end;
-    MtdGetPartitionSize(entry, &start, NULL, NULL);
-    end = start + params->size * drive->mtd.sector_bytes - 1;
-    memcpy(&entry->ending_offset, &end, sizeof(end));
-  }
-  if (params->set_type)
-    MtdSetEntryType(entry, LookupMtdTypeForGuid(&params->type_guid));
-  if (params->label) {
-    strncpy(entry->label, params->label, sizeof(entry->label));
-  }
-
-  return 0;
-}
-
 // This is an internal helper function which assumes no NULL args are passed.
 // It sets the given attribute values for a single entry at the given index.
 static int SetEntryAttributes(struct drive *drive,
@@ -153,26 +127,20 @@
 }
 
 static int CgptCheckAddValidity(struct drive *drive) {
-  if (drive->is_mtd) {
-    if (drive->mtd.primary.crc32 != MtdHeaderCrc(&drive->mtd.primary)) {
-      Error("MTD header CRC is invalid\n");
-      return -1;
-    }
-  } else {
-    int gpt_retval;
-    if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive->gpt))) {
-      Error("GptSanityCheck() returned %d: %s\n",
-            gpt_retval, GptError(gpt_retval));
-      return -1;
-    }
-
-    if (((drive->gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
-        ((drive->gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
-      Error("one of the GPT header/entries is invalid.\n"
-            "please run 'cgpt repair' before adding anything.\n");
-      return -1;
-    }
+  int gpt_retval;
+  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive->gpt))) {
+    Error("GptSanityCheck() returned %d: %s\n",
+          gpt_retval, GptError(gpt_retval));
+    return -1;
   }
+
+  if (((drive->gpt.valid_headers & MASK_BOTH) != MASK_BOTH) ||
+      ((drive->gpt.valid_entries & MASK_BOTH) != MASK_BOTH)) {
+    Error("one of the GPT header/entries is invalid.\n"
+          "please run 'cgpt repair' before adding anything.\n");
+    return -1;
+  }
+
   return 0;
 }
 
@@ -264,10 +232,6 @@
       Error("either partition or unique_id must be specified\n");
       goto bad;
     }
-    if (drive.is_mtd) {
-      Error("MTD partitions cannot be specified by unique_id\n");
-      goto bad;
-    }
     for (index = 0; index < max_part; index++) {
       GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
       if (GuidEqual(&entry->unique, &params->unique_guid)) {
@@ -282,22 +246,13 @@
   }
   index = params->partition - 1;
 
-  if(drive.is_mtd) {
-    MtdDiskPartition *entry = MtdGetEntry(&drive.mtd, PRIMARY, index);
-    const Guid *guid = LookupGuidForMtdType(MtdGetEntryType(entry));
-    memcpy(&params->type_guid, guid, sizeof(params->type_guid));
-    memset(&params->unique_guid, 0, sizeof(params->unique_guid));
-    MtdGetPartitionSizeInSectors(entry, &params->begin, NULL, &params->size);
-    params->raw_value = entry->flags;
-  } else {
-    // GPT-specific code
-    GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
-    params->begin = entry->starting_lba;
-    params->size =  entry->ending_lba - entry->starting_lba + 1;
-    memcpy(&params->type_guid, &entry->type, sizeof(Guid));
-    memcpy(&params->unique_guid, &entry->unique, sizeof(Guid));
-    params->raw_value = entry->attrs.fields.gpt_att;
-  }
+  // GPT-specific code
+  GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
+  params->begin = entry->starting_lba;
+  params->size =  entry->ending_lba - entry->starting_lba + 1;
+  memcpy(&params->type_guid, &entry->type, sizeof(Guid));
+  memcpy(&params->unique_guid, &entry->unique, sizeof(Guid));
+  params->raw_value = entry->attrs.fields.gpt_att;
 
   params->successful = GetSuccessful(&drive, PRIMARY, index);
   params->tries = GetTries(&drive, PRIMARY, index);
@@ -338,22 +293,6 @@
   return 0;
 }
 
-static int MtdAdd(struct drive *drive, CgptAddParams *params, uint32_t index) {
-  MtdDiskPartition *entry, backup;
-  entry = MtdGetEntry(&drive->mtd, PRIMARY, index);
-  memcpy(&backup, entry, sizeof(backup));
-
-  if (SetEntryAttributes(drive, index, params) ||
-      MtdSetEntryAttributes(drive, index, params)) {
-    memcpy(entry, &backup, sizeof(*entry));
-    return -1;
-  }
-
-  UpdateAllEntries(drive);
-
-  return 0;
-}
-
 int CgptAdd(CgptAddParams *params) {
   struct drive drive;
   uint32_t index;
@@ -373,13 +312,8 @@
     goto bad;
   }
 
-  if (drive.is_mtd) {
-    if (MtdAdd(&drive, params, index))
-      goto bad;
-  } else {
-    if (GptAdd(&drive, params, index))
-      goto bad;
-  }
+  if (GptAdd(&drive, params, index))
+    goto bad;
 
   // Write it all out.
   return DriveClose(&drive, 1);
diff --git a/cgpt/cgpt_boot.c b/cgpt/cgpt_boot.c
index 928210b..f432396 100644
--- a/cgpt/cgpt_boot.c
+++ b/cgpt/cgpt_boot.c
@@ -79,15 +79,6 @@
     return CGPT_FAILED;
   }
 
-  if (drive.is_mtd) {
-    /* This command manipulates the legacy MBR sector present at the beginning
-     * of the GPT structures, and so doesn't apply to MTD drives.
-     */
-    Error("'boot' command unsupported in MTD mode\n");
-    retval = CGPT_FAILED;
-    goto done;
-  }
-
   if (CGPT_OK != ReadPMBR(&drive)) {
     Error("Unable to read PMBR\n");
     goto done;
diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c
index 1e7b5ab..1438dfb 100644
--- a/cgpt/cgpt_common.c
+++ b/cgpt/cgpt_common.c
@@ -25,24 +25,11 @@
 #include "cgpt.h"
 #include "cgptlib_internal.h"
 #include "crc32.h"
-#include "flash_ts.h"
-#include "flash_ts_api.h"
 #include "vboot_host.h"
 
 static const char kErrorTag[] = "ERROR";
 static const char kWarningTag[] = "WARNING";
 
-struct nand_layout nand;
-
-void EnableNandImage(int bytes_per_page, int pages_per_block,
-                     int fts_block_offset, int fts_block_size) {
-  nand.enabled = 1;
-  nand.bytes_per_page = bytes_per_page;
-  nand.pages_per_block = pages_per_block;
-  nand.fts_block_offset = fts_block_offset;
-  nand.fts_block_size = fts_block_size;
-}
-
 static void LogToStderr(const char *tag, const char *format, va_list ap) {
   fprintf(stderr, "%s: ", tag);
   vfprintf(stderr, format, ap);
@@ -156,161 +143,6 @@
   return CGPT_OK;
 }
 
-static int get_hex_char_value(char ch) {
-  if (ch >= '0' && ch <= '9') {
-    return ch - '0';
-  }
-  if (ch >= 'a' && ch <= 'f') {
-    return ch - 'a' + 10;
-  }
-  if (ch >= 'A' && ch <= 'F') {
-    return ch - 'A' + 10;
-  }
-  return -1;
-}
-
-static int TryInitMtd(const char *dev) {
-  static int already_inited = 0;
-  if (already_inited)
-    return nand.use_host_ioctl;
-
-  already_inited = 1;
-
-  /* If we're running on the live system, we can just use /dev/fts and not
-   * actually need the specific parameters. This needs to be accessed via
-   * ioctl and not normal I/O.
-   */
-  if (!strcmp(dev, FTS_DEVICE) && !access(FTS_DEVICE, R_OK | W_OK)) {
-    nand.enabled = 1;
-    nand.use_host_ioctl = 1;
-    return 1;
-  }
-  return 0;
-}
-
-int FlashGet(const char *key, uint8_t *data, uint32_t *bufsz) {
-  char *hex = (char*)malloc(*bufsz * 2);
-  char *read;
-  uint32_t written = 0;
-
-  if (nand.use_host_ioctl) {
-    struct flash_ts_io_req req;
-    strncpy(req.key, key, sizeof(req.key));
-    int fd = open(FTS_DEVICE, O_RDWR);
-    if (fd < 0)
-      return -1;
-    if (ioctl(fd, FLASH_TS_IO_GET, &req))
-      return -1;
-    strncpy(hex, req.val, *bufsz * 2);
-    close(fd);
-  } else {
-    flash_ts_get(key, hex, *bufsz * 2);
-  }
-
-  /* Hex -> binary */
-  for (read = hex; read < hex + *bufsz * 2 && *read != '\0'; read += 2) {
-    int c0, c1;
-    c0 = get_hex_char_value(read[0]);
-    c1 = get_hex_char_value(read[1]);
-    if (c0 < 0 || c1 < 0) {
-      free(hex);
-      return -1;
-    }
-
-    data[written++] = (c0 << 4) + c1;
-  }
-  *bufsz = written;
-  free(hex);
-  return 0;
-}
-
-int FlashSet(const char *key, const uint8_t *data, uint32_t bufsz) {
-  char *hex = (char*)malloc(bufsz * 2 + 1);
-  const char *hex_chars = "0123456789ABCDEF";
-  int ret;
-  uint32_t i;
-
-  /* Binary -> hex, we need some encoding because FTS only stores C strings */
-  for (i = 0; i < bufsz; i++) {
-    hex[i * 2] = hex_chars[data[i] >> 4];
-    hex[i * 2 + 1] = hex_chars[data[i] & 0xF];
-  }
-  /* Buffer must be NUL-terminated. */
-  hex[bufsz * 2] = '\0';
-  if (nand.use_host_ioctl) {
-    struct flash_ts_io_req req;
-    strncpy(req.key, key, sizeof(req.key));
-    strncpy(req.val, hex, sizeof(req.val));
-    free(hex);
-    int fd = open(FTS_DEVICE, O_RDWR);
-    if (fd < 0)
-      return -1;
-    if (ioctl(fd, FLASH_TS_IO_SET, &req))
-      return -1;
-    close(fd);
-    return 0;
-  }
-  ret = flash_ts_set(key, hex);
-  free(hex);
-  return ret;
-}
-
-int MtdLoad(struct drive *drive, int sector_bytes) {
-  int ret;
-  uint32_t sz;
-  MtdData *mtd = &drive->mtd;
-
-  mtd->sector_bytes = sector_bytes;
-  mtd->drive_sectors = drive->size / mtd->sector_bytes;
-
-  if (!nand.use_host_ioctl) {
-    ret = flash_ts_init(mtd->fts_block_offset,
-                        mtd->fts_block_size,
-                        mtd->flash_page_bytes,
-                        mtd->flash_block_bytes,
-                        mtd->sector_bytes, /* Needed for Load() and Save() */
-                        drive);
-    if (ret)
-      return ret;
-  }
-
-  memset(&mtd->primary, 0, sizeof(mtd->primary));
-  sz = sizeof(mtd->primary);
-  ret = FlashGet(MTD_DRIVE_SIGNATURE, (uint8_t *)&mtd->primary, &sz);
-  if (ret)
-    return ret;
-
-  /* Read less than expected */
-  if (sz < MTD_DRIVE_V1_SIZE)
-    memset(&mtd->primary, 0, sizeof(mtd->primary));
-
-  if (nand.use_host_ioctl) {
-    /* If we are using /dev/fts, we can't stat() the size, so re-use
-     * our internal value to set it.
-     */
-    drive->size = mtd->primary.last_offset + 1;
-    mtd->drive_sectors = drive->size / mtd->sector_bytes;
-  }
-
-  mtd->current_kernel = -1;
-  mtd->current_priority = 0;
-  mtd->modified = 0;
-  return 0;
-}
-
-int MtdSave(struct drive *drive) {
-  MtdData *mtd = &drive->mtd;
-
-  if (!mtd->modified)
-    return 0;
-
-  mtd->primary.crc32 = 0;
-  mtd->primary.crc32 = Crc32(&mtd->primary, MTD_DRIVE_V1_SIZE);
-
-  return FlashSet(MTD_DRIVE_SIGNATURE, (uint8_t *)&mtd->primary,
-                  sizeof(mtd->primary));
-}
-
 static int GptLoad(struct drive *drive, uint32_t sector_bytes) {
   drive->gpt.sector_bytes = sector_bytes;
   if (drive->size % drive->gpt.sector_bytes) {
@@ -446,7 +278,6 @@
 int DriveOpen(const char *drive_path, struct drive *drive, int mode,
               uint64_t drive_size) {
   uint32_t sector_bytes;
-  int is_mtd = nand.enabled;
 
   require(drive_path);
   require(drive);
@@ -455,47 +286,32 @@
   memset(drive, 0, sizeof(struct drive));
   drive->gpt.stored_on_device = GPT_STORED_ON_DEVICE;
 
-  if (TryInitMtd(drive_path)) {
-    is_mtd = 1;
-    sector_bytes = 512;  /* bytes */
-  } else {
-    drive->fd = open(drive_path, mode | O_LARGEFILE | O_NOFOLLOW);
-    if (drive->fd == -1) {
-      Error("Can't open %s: %s\n", drive_path, strerror(errno));
-      return CGPT_FAILED;
-    }
-
-    sector_bytes = 512;
-    uint64_t gpt_drive_size;
-    if (ObtainDriveSize(drive->fd, &gpt_drive_size, &sector_bytes) != 0) {
-      Error("Can't get drive size and bytes per sector for %s: %s\n",
-            drive_path, strerror(errno));
-      goto error_close;
-    }
-
-    drive->gpt.gpt_drive_sectors = gpt_drive_size / sector_bytes;
-    if (drive_size == 0) {
-      drive->size = gpt_drive_size;
-      drive->gpt.stored_on_device = GPT_STORED_ON_DEVICE;
-    } else {
-      drive->size = drive_size;
-      drive->gpt.stored_on_device = GPT_STORED_OFF_DEVICE;
-    }
+  drive->fd = open(drive_path, mode | O_LARGEFILE | O_NOFOLLOW);
+  if (drive->fd == -1) {
+    Error("Can't open %s: %s\n", drive_path, strerror(errno));
+    return CGPT_FAILED;
   }
-  drive->is_mtd = is_mtd;
 
-  if (is_mtd) {
-    drive->mtd.fts_block_offset = nand.fts_block_offset;
-    drive->mtd.fts_block_size = nand.fts_block_size;
-    drive->mtd.flash_page_bytes = nand.bytes_per_page;
-    drive->mtd.flash_block_bytes = nand.pages_per_block * nand.bytes_per_page;
-    if (MtdLoad(drive, sector_bytes)) {
-      goto error_close;
-    }
+  sector_bytes = 512;
+  uint64_t gpt_drive_size;
+  if (ObtainDriveSize(drive->fd, &gpt_drive_size, &sector_bytes) != 0) {
+    Error("Can't get drive size and bytes per sector for %s: %s\n",
+          drive_path, strerror(errno));
+    goto error_close;
+  }
+
+  drive->gpt.gpt_drive_sectors = gpt_drive_size / sector_bytes;
+  if (drive_size == 0) {
+    drive->size = gpt_drive_size;
+    drive->gpt.stored_on_device = GPT_STORED_ON_DEVICE;
   } else {
-    if (GptLoad(drive, sector_bytes)) {
-      goto error_close;
-    }
+    drive->size = drive_size;
+    drive->gpt.stored_on_device = GPT_STORED_OFF_DEVICE;
+  }
+
+
+  if (GptLoad(drive, sector_bytes)) {
+    goto error_close;
   }
 
   // We just load the data. Caller must validate it.
@@ -511,14 +327,8 @@
   int errors = 0;
 
   if (update_as_needed) {
-    if (drive->is_mtd) {
-      if (MtdSave(drive)) {
+    if (GptSave(drive)) {
         errors++;
-      }
-    } else {
-      if (GptSave(drive)) {
-        errors++;
-      }
     }
   }
 
@@ -816,44 +626,16 @@
   const Guid *type;
   char *name;
   char *description;
-  int mtd_type;
 } supported_types[] = {
-  {&guid_chromeos_firmware, "firmware", "ChromeOS firmware",
-    MTD_PARTITION_TYPE_CHROMEOS_FIRMWARE},
-  {&guid_chromeos_kernel, "kernel", "ChromeOS kernel",
-    MTD_PARTITION_TYPE_CHROMEOS_KERNEL},
-  {&guid_chromeos_rootfs, "rootfs", "ChromeOS rootfs",
-    MTD_PARTITION_TYPE_CHROMEOS_ROOTFS},
-  {&guid_linux_data, "data", "Linux data",
-    MTD_PARTITION_TYPE_LINUX_DATA},
-  {&guid_chromeos_reserved, "reserved", "ChromeOS reserved",
-    MTD_PARTITION_TYPE_CHROMEOS_RESERVED},
-  {&guid_efi, "efi", "EFI System Partition",
-    MTD_PARTITION_TYPE_EFI},
-  {&guid_unused, "unused", "Unused (nonexistent) partition",
-    MTD_PARTITION_TYPE_UNUSED},
+  {&guid_chromeos_firmware, "firmware", "ChromeOS firmware"},
+  {&guid_chromeos_kernel, "kernel", "ChromeOS kernel"},
+  {&guid_chromeos_rootfs, "rootfs", "ChromeOS rootfs"},
+  {&guid_linux_data, "data", "Linux data"},
+  {&guid_chromeos_reserved, "reserved", "ChromeOS reserved"},
+  {&guid_efi, "efi", "EFI System Partition"},
+  {&guid_unused, "unused", "Unused (nonexistent) partition"},
 };
 
-int LookupMtdTypeForGuid(const Guid *type) {
-  int i;
-  for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
-    if (!memcmp(type, supported_types[i].type, sizeof(Guid))) {
-      return supported_types[i].mtd_type;
-    }
-  }
-  return MTD_PARTITION_TYPE_OTHER;
-}
-
-const Guid *LookupGuidForMtdType(int type) {
-  int i;
-  for (i = 0; i < ARRAY_COUNT(supported_types); ++i) {
-    if (supported_types[i].mtd_type == type) {
-      return supported_types[i].type;
-    }
-  }
-  return NULL;
-}
-
 /* Resolves human-readable GPT type.
  * Returns CGPT_OK if found.
  * Returns CGPT_FAILED if no known type found. */
@@ -899,9 +681,6 @@
 }
 
 uint32_t GetNumberOfEntries(const struct drive *drive) {
-  if (drive->is_mtd)
-    return MTD_MAX_PARTITIONS;
-
   GptHeader *header = GetGptHeader(&drive->gpt);
   if (!header)
     return 0;
@@ -933,130 +712,74 @@
   return (GptEntry*)(&entries[stride * entry_index]);
 }
 
-MtdDiskPartition* MtdGetEntry(MtdData *mtd, int secondary, uint32_t index) {
-  if (index >= MTD_MAX_PARTITIONS)
-    return NULL;
-  return &mtd->primary.partitions[index];
-}
-
 void SetPriority(struct drive *drive, int secondary, uint32_t entry_index,
                  int priority) {
   require(priority >= 0 && priority <= CGPT_ATTRIBUTE_MAX_PRIORITY);
-  if (drive->is_mtd) {
-    MtdDiskPartition *e = MtdGetEntry(&drive->mtd, secondary, entry_index);
-    MtdSetEntryPriority(e, priority);
-  } else {
-    GptEntry *entry;
-    entry = GetEntry(&drive->gpt, secondary, entry_index);
-    SetEntryPriority(entry, priority);
-  }
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  SetEntryPriority(entry, priority);
 }
 
 int GetPriority(struct drive *drive, int secondary, uint32_t entry_index) {
-  if (drive->is_mtd) {
-    MtdDiskPartition *e = MtdGetEntry(&drive->mtd, secondary, entry_index);
-    return MtdGetEntryPriority(e);
-  } else {
-    GptEntry *entry;
-    entry = GetEntry(&drive->gpt, secondary, entry_index);
-    return GetEntryPriority(entry);
-  }
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  return GetEntryPriority(entry);
 }
 
 void SetTries(struct drive *drive, int secondary, uint32_t entry_index,
               int tries) {
   require(tries >= 0 && tries <= CGPT_ATTRIBUTE_MAX_TRIES);
-  if (drive->is_mtd) {
-    MtdDiskPartition *e = MtdGetEntry(&drive->mtd, secondary, entry_index);
-    MtdSetEntryTries(e, tries);
-  } else {
-    GptEntry *entry;
-    entry = GetEntry(&drive->gpt, secondary, entry_index);
-    SetEntryTries(entry, tries);
-  }
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  SetEntryTries(entry, tries);
 }
 
 int GetTries(struct drive *drive, int secondary, uint32_t entry_index) {
-  if (drive->is_mtd) {
-    MtdDiskPartition *e = MtdGetEntry(&drive->mtd, secondary, entry_index);
-    return MtdGetEntryTries(e);
-  } else {
-    GptEntry *entry;
-    entry = GetEntry(&drive->gpt, secondary, entry_index);
-    return GetEntryTries(entry);
-  }
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  return GetEntryTries(entry);
 }
 
 void SetSuccessful(struct drive *drive, int secondary, uint32_t entry_index,
                    int success) {
   require(success >= 0 && success <= CGPT_ATTRIBUTE_MAX_SUCCESSFUL);
-  if (drive->is_mtd) {
-    MtdDiskPartition *e = MtdGetEntry(&drive->mtd, secondary, entry_index);
-    MtdSetEntrySuccessful(e, success);
-  } else {
-    GptEntry *entry;
-    entry = GetEntry(&drive->gpt, secondary, entry_index);
-    SetEntrySuccessful(entry, success);
-  }
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  SetEntrySuccessful(entry, success);
 }
 
 int GetSuccessful(struct drive *drive, int secondary, uint32_t entry_index) {
-  if (drive->is_mtd) {
-    MtdDiskPartition *e = MtdGetEntry(&drive->mtd, secondary, entry_index);
-    return MtdGetEntrySuccessful(e);
-  } else {
-    GptEntry *entry;
-    entry = GetEntry(&drive->gpt, secondary, entry_index);
-    return GetEntrySuccessful(entry);
-  }
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  return GetEntrySuccessful(entry);
 }
 
 void SetRaw(struct drive *drive, int secondary, uint32_t entry_index,
             uint32_t raw) {
-  if (drive->is_mtd) {
-    MtdDiskPartition *e = MtdGetEntry(&drive->mtd, secondary, entry_index);
-    e->flags = raw;
-  } else {
-    GptEntry *entry;
-    entry = GetEntry(&drive->gpt, secondary, entry_index);
-    entry->attrs.fields.gpt_att = (uint16_t)raw;
-  }
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, entry_index);
+  entry->attrs.fields.gpt_att = (uint16_t)raw;
 }
 
 void UpdateAllEntries(struct drive *drive) {
-  if (drive->is_mtd) {
-    drive->mtd.modified = 1;
-    drive->mtd.primary.crc32 = MtdHeaderCrc(&drive->mtd.primary);
-  } else {
-    RepairEntries(&drive->gpt, MASK_PRIMARY);
-    RepairHeader(&drive->gpt, MASK_PRIMARY);
+  RepairEntries(&drive->gpt, MASK_PRIMARY);
+  RepairHeader(&drive->gpt, MASK_PRIMARY);
 
-    drive->gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
-                           GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
-    UpdateCrc(&drive->gpt);
-  }
+  drive->gpt.modified |= (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1 |
+                          GPT_MODIFIED_HEADER2 | GPT_MODIFIED_ENTRIES2);
+  UpdateCrc(&drive->gpt);
 }
 
 int IsUnused(struct drive *drive, int secondary, uint32_t index) {
-  if (drive->is_mtd) {
-    MtdDiskPartition *e = MtdGetEntry(&drive->mtd, secondary, index);
-    return MtdGetEntryType(e) == MTD_PARTITION_TYPE_UNUSED;
-  } else {
-    GptEntry *entry;
-    entry = GetEntry(&drive->gpt, secondary, index);
-    return GuidIsZero(&entry->type);
-  }
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, index);
+  return GuidIsZero(&entry->type);
 }
 
 int IsKernel(struct drive *drive, int secondary, uint32_t index) {
-  if (drive->is_mtd) {
-    MtdDiskPartition *e = MtdGetEntry(&drive->mtd, secondary, index);
-    return MtdGetEntryType(e) == MTD_PARTITION_TYPE_CHROMEOS_KERNEL;
-  } else {
-    GptEntry *entry;
-    entry = GetEntry(&drive->gpt, secondary, index);
-    return GuidEqual(&entry->type, &guid_chromeos_kernel);
-  }
+  GptEntry *entry;
+  entry = GetEntry(&drive->gpt, secondary, index);
+  return GuidEqual(&entry->type, &guid_chromeos_kernel);
 }
 
 
diff --git a/cgpt/cgpt_create.c b/cgpt/cgpt_create.c
index 18e2f51..298e2ae 100644
--- a/cgpt/cgpt_create.c
+++ b/cgpt/cgpt_create.c
@@ -88,31 +88,6 @@
   return 0;
 }
 
-static int MtdCreate(struct drive *drive, CgptCreateParams *params) {
-  MtdDiskLayout *h = &drive->mtd.primary;
-  memset(h, 0, sizeof(*h));
-  drive->mtd.modified = 1;
-
-  if (!params->zap) {
-    // Prep basic parameters
-    memcpy(h->signature, MTD_DRIVE_SIGNATURE, sizeof(h->signature));
-    h->size = sizeof(*h);
-    h->first_offset = 0;
-    h->last_offset = (drive->mtd.drive_sectors * drive->mtd.sector_bytes) - 1;
-    h->crc32 = MtdHeaderCrc(h);
-  }
-  if (params->size) {
-    h->last_offset = params->size - 1;
-    drive->size = params->size;
-    drive->mtd.drive_sectors = drive->size / drive->mtd.sector_bytes;
-  } else if (!drive->mtd.drive_sectors) {
-    Error("MTD create with params->size == 0 && drive->mtd.drive_sectors == 0");
-    return -1;
-  }
-
-  return 0;
-}
-
 int CgptCreate(CgptCreateParams *params) {
   struct drive drive;
 
@@ -123,13 +98,8 @@
                            params->drive_size))
     return CGPT_FAILED;
 
-  if (drive.is_mtd) {
-    if (MtdCreate(&drive, params))
-      goto bad;
-  } else {
-    if (GptCreate(&drive, params))
-      goto bad;
-  }
+  if (GptCreate(&drive, params))
+    goto bad;
 
   // Write it all out
   return DriveClose(&drive, 1);
diff --git a/cgpt/cgpt_find.c b/cgpt/cgpt_find.c
index 7d9ec8d..c319304 100644
--- a/cgpt/cgpt_find.c
+++ b/cgpt/cgpt_find.c
@@ -83,20 +83,6 @@
     EntryDetails(entry, partnum - 1, params->numeric);
 }
 
-// This needs to handle /dev/mmcblk0 -> /dev/mmcblk0p3, /dev/sda -> /dev/sda3
-static void mtd_showmatch(CgptFindParams *params, char *filename,
-                           int partnum, MtdDiskPartition *entry) {
-  char * format = "%s%d\n";
-  if (strncmp("/dev/mmcblk", filename, 11) == 0)
-    format = "%sp%d\n";
-  if (params->numeric)
-    printf("%d\n", partnum);
-  else
-    printf(format, filename, partnum);
-  if (params->verbose > 0)
-    MtdEntryDetails(entry, partnum - 1, params->numeric);
-}
-
 // This returns true if a GPT partition matches the search criteria. If a match
 // isn't found (or if the file doesn't contain a GPT), it returns false. The
 // filename and partition number that matched is left in a global, since we
@@ -144,69 +130,6 @@
   return retval;
 }
 
-static int mtd_match_type_to_guid(const MtdDiskPartition *e, const Guid *guid) {
-  return LookupMtdTypeForGuid(guid) == MtdGetEntryType(e);
-}
-
-static int mtd_match_content(CgptFindParams *params, struct drive *drive,
-                             MtdDiskPartition *entry) {
-  uint64_t start, part_size;
-
-  if (!params->matchlen)
-    return 1;
-
-  // Ensure that the region we want to match against is inside the partition.
-  MtdGetPartitionSize(entry, &start, NULL, &part_size);
-  if (params->matchoffset + params->matchlen > part_size) {
-    return 0;
-  }
-
-  // Read the partition data.
-  if (!FillBuffer(params,
-                  drive->fd,
-                  start + params->matchoffset,
-                  params->matchlen)) {
-    Error("unable to read partition data\n");
-    return 0;
-  }
-
-  // Compare it
-  if (0 == memcmp(params->matchbuf, params->comparebuf, params->matchlen)) {
-    return 1;
-  }
-
-  // Nope.
-  return 0;
-}
-
-static int mtd_search(CgptFindParams *params, struct drive *drive,
-                      char *filename) {
-  int i;
-  int retval = 0;
-  for (i = 0; i < GetNumberOfEntries(drive); ++i) {
-    MtdDiskPartition *e = MtdGetEntry(&drive->mtd, ANY_VALID, i);
-
-    if (IsUnused(drive, ANY_VALID, i))
-      continue;
-
-    int found = 0;
-
-    // Only searches by type are possible right now
-    if (params->set_type && mtd_match_type_to_guid(e, &params->type_guid)) {
-      found = 1;
-    }
-
-    if (found && mtd_match_content(params, drive, e)) {
-      params->hits++;
-      retval++;
-      mtd_showmatch(params, filename, i+1, e);
-      if (!params->match_partnum)
-        params->match_partnum = i+1;
-    }
-  }
-  return retval;
-}
-
 static int do_search(CgptFindParams *params, char *fileName) {
   int retval;
   struct drive drive;
@@ -214,11 +137,7 @@
   if (CGPT_OK != DriveOpen(fileName, &drive, O_RDONLY, params->drive_size))
     return 0;
 
-  if (drive.is_mtd) {
-    retval = mtd_search(params, &drive, fileName);
-  } else {
-    retval = gpt_search(params, &drive, fileName);
-  }
+  retval = gpt_search(params, &drive, fileName);
 
   (void) DriveClose(&drive, 0);
 
diff --git a/cgpt/cgpt_legacy.c b/cgpt/cgpt_legacy.c
index 0760769..b758212 100644
--- a/cgpt/cgpt_legacy.c
+++ b/cgpt/cgpt_legacy.c
@@ -19,13 +19,6 @@
                            params->drive_size))
     return CGPT_FAILED;
 
-  if (drive.is_mtd) {
-    // This command requires GPT mode.
-    Error("'legacy' command unsupported in MTD mode\n");
-    DriveClose(&drive, 0);
-    return CGPT_FAILED;
-  }
-
   h1 = (GptHeader *)drive.gpt.primary_header;
   h2 = (GptHeader *)drive.gpt.secondary_header;
   if (params->efipart) {
diff --git a/cgpt/cgpt_prioritize.c b/cgpt/cgpt_prioritize.c
index 019638d..2bfc484 100644
--- a/cgpt/cgpt_prioritize.c
+++ b/cgpt/cgpt_prioritize.c
@@ -110,17 +110,10 @@
                            params->drive_size))
     return CGPT_FAILED;
 
-  if (drive.is_mtd) {
-    if (drive.mtd.primary.crc32 != MtdHeaderCrc(&drive.mtd.primary)) {
-      Error("MTD header crc failure\n");
-      return CGPT_FAILED;
-    }
-  } else {
-    if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
-      Error("GptSanityCheck() returned %d: %s\n",
-            gpt_retval, GptError(gpt_retval));
-      return CGPT_FAILED;
-    }
+  if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
+    Error("GptSanityCheck() returned %d: %s\n",
+          gpt_retval, GptError(gpt_retval));
+    return CGPT_FAILED;
   }
 
   max_part = GetNumberOfEntries(&drive);
diff --git a/cgpt/cgpt_repair.c b/cgpt/cgpt_repair.c
index 9889902..1880ea5 100644
--- a/cgpt/cgpt_repair.c
+++ b/cgpt/cgpt_repair.c
@@ -19,12 +19,6 @@
                            params->drive_size))
     return CGPT_FAILED;
 
-  if (drive.is_mtd) {
-    // Nothing to do
-    DriveClose(&drive, 0);
-    return 0;
-  }
-
   int gpt_retval = GptSanityCheck(&drive.gpt);
   if (params->verbose)
     printf("GptSanityCheck() returned %d: %s\n",
diff --git a/cgpt/cgpt_show.c b/cgpt/cgpt_show.c
index 32d62d3..68a185c 100644
--- a/cgpt/cgpt_show.c
+++ b/cgpt/cgpt_show.c
@@ -66,20 +66,6 @@
   printf("\n");
 }
 
-static void MtdHeaderDetails(MtdDiskLayout *header, const char *indent,
-			     int raw) {
-  PrintSignature(indent, (char*)header->signature, sizeof(header->signature),
-    raw);
-
-  printf("%sSize: %d\n", indent, header->size);
-  printf("%sCRC: 0x%08x %s\n", indent, header->crc32,
-         (MtdHeaderCrc(header) != header->crc32) ? "(INVALID)" : "");
-  printf("%sFirst offset: %llu\n", indent,
-    (unsigned long long)header->first_offset);
-  printf("%sLast offset: %llu\n", indent,
-    (unsigned long long)header->last_offset);
-}
-
 static void HeaderDetails(GptHeader *header, GptEntry *entries,
                           const char *indent, int raw) {
   PrintSignature(indent, header->signature, sizeof(header->signature), raw);
@@ -110,45 +96,6 @@
          );
 }
 
-void MtdEntryDetails(MtdDiskPartition *entry, uint32_t index, int raw) {
-  const Guid *guid = LookupGuidForMtdType(MtdGetEntryType(entry));
-  char type[256];
-  char contents[256];
-  char name[sizeof(entry->label) + 1];
-  uint64_t start, size;
-  if (guid) {
-    ResolveType(guid, type);
-  } else {
-    snprintf(type, sizeof(type), "MTD partition type %d",
-             MtdGetEntryType(entry));
-  }
-
-  MtdGetPartitionSizeInSectors(entry, &start, NULL, &size);
-
-  // Provide a NUL if we are at maximum size.
-  name[sizeof(name)-1] = '\0';
-  memcpy(name, entry->label, sizeof(entry->label));
-  require(snprintf(contents, sizeof(contents),
-                   "Label: \"%s\"", name) < sizeof(contents));
-
-  printf(PARTITION_FMT, (int)start, (int)size, index+1, contents);
-  printf(PARTITION_MORE, "Type: ", type);
-
-  if (raw && MtdGetEntryType(entry) == MTD_PARTITION_TYPE_CHROMEOS_KERNEL) {
-    int tries = MtdGetEntryTries(entry);
-    int successful = MtdGetEntrySuccessful(entry);
-    int priority = MtdGetEntryPriority(entry);
-    require(snprintf(contents, sizeof(contents),
-                     "priority=%d tries=%d successful=%d",
-                     priority, tries, successful) < sizeof(contents));
-    printf(PARTITION_MORE, "Attr: ", contents);
-  } else {
-    require(snprintf(contents, sizeof(contents),
-                     "[%x]", entry->flags) < sizeof(contents));
-    printf(PARTITION_MORE, "Attr: ", contents);
-  }
-}
-
 void EntryDetails(GptEntry *entry, uint32_t index, int raw) {
   char contents[256];                   // scratch buffer for formatting output
   uint8_t label[GPT_PARTNAME_LEN];
@@ -194,18 +141,6 @@
   }
 }
 
-void MtdEntriesDetails(struct drive *drive, int secondary, int raw) {
-  uint32_t i;
-
-  for (i = 0; i < GetNumberOfEntries(drive); ++i) {
-    MtdDiskPartition *entry;
-    entry = MtdGetEntry(&drive->mtd, secondary, i);
-    if (IsUnused(drive, secondary, i))
-      continue;
-    MtdEntryDetails(entry, i, raw);
-  }
-}
-
 void EntriesDetails(struct drive *drive, const int secondary, int raw) {
   uint32_t i;
 
@@ -220,87 +155,6 @@
   }
 }
 
-int MtdShow(struct drive *drive, CgptShowParams *params) {
-  if (params->partition) {                      // show single partition
-    if (params->partition > GetNumberOfEntries(drive)) {
-      Error("invalid partition number: %d\n", params->partition);
-      return CGPT_FAILED;
-    }
-
-    uint32_t index = params->partition - 1;
-    MtdDiskPartition *entry = MtdGetEntry(&drive->mtd, ANY_VALID, index);
-    char buf[256];                      // scratch buffer for string conversion
-    const Guid *guid;
-    uint64_t start, size;
-
-    MtdGetPartitionSizeInSectors(entry, &start, NULL, &size);
-
-    if (params->single_item) {
-      switch(params->single_item) {
-      case 'b':
-        printf("%u\n", (int)start);
-        break;
-      case 's':
-        printf("%u\n", (int)size);
-        break;
-      case 't':
-        guid = LookupGuidForMtdType(MtdGetEntryType(entry));
-        GuidToStr(guid, buf, sizeof(buf));
-        printf("%s\n", buf);
-        break;
-      case 'S':
-        printf("%d\n", GetSuccessful(drive, ANY_VALID, index));
-        break;
-      case 'T':
-        printf("%d\n", GetTries(drive, ANY_VALID, index));
-        break;
-      case 'P':
-        printf("%d\n", GetPriority(drive, ANY_VALID, index));
-        break;
-      case 'A':
-        printf("0x%x\n", entry->flags);
-        break;
-      }
-    } else {
-      printf(TITLE_FMT, "start", "size", "part", "contents");
-      MtdEntryDetails(entry, index, params->numeric);
-    }
-  } else if (params->quick) {                   // show all partitions, quickly
-    uint32_t i;
-    char type[GUID_STRLEN];
-
-    for (i = 0; i < GetNumberOfEntries(drive); ++i) {
-      MtdDiskPartition *entry = MtdGetEntry(&drive->mtd, ANY_VALID, i);
-      const Guid *guid = LookupGuidForMtdType(MtdGetEntryType(entry));
-      uint64_t start, size;
-
-      MtdGetPartitionSizeInSectors(entry, &start, NULL, &size);
-
-      if (IsUnused(drive, ANY_VALID, i))
-        continue;
-
-      if (!params->numeric && guid) {
-        ResolveType(guid, type);
-      } else {
-        snprintf(type, sizeof(type), "MTD partition type %d",
-                 MtdGetEntryType(entry));
-      }
-      printf(PARTITION_FMT, (int)start, (int)size, i+1, type);
-    }
-  } else {                              // show all partitions
-    if (params->debug || params->verbose) {
-      char indent[64];
-
-      require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
-      MtdHeaderDetails(&drive->mtd.primary, indent, 0);
-    }
-    printf(TITLE_FMT, "start", "size", "part", "contents");
-    MtdEntriesDetails(drive, PRIMARY, params->numeric);
-  }
-
-  return CGPT_OK;
-}
-
 static int GptShow(struct drive *drive, CgptShowParams *params) {
   int gpt_retval;
   if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive->gpt))) {
@@ -486,13 +340,8 @@
                            params->drive_size))
     return CGPT_FAILED;
 
-  if (drive.is_mtd) {
-    if (MtdShow(&drive, params))
-      return CGPT_FAILED;
-  } else {
-    if (GptShow(&drive, params))
-      return CGPT_FAILED;
-  }
+  if (GptShow(&drive, params))
+    return CGPT_FAILED;
 
   DriveClose(&drive, 0);
   return CGPT_OK;
diff --git a/cgpt/cmd_create.c b/cgpt/cmd_create.c
index 47137bd..34f59cb 100644
--- a/cgpt/cmd_create.c
+++ b/cgpt/cmd_create.c
@@ -19,7 +19,6 @@
          "                 default 0, meaning partitions and GPT structs are\n"
          "                 both on DRIVE\n"
          "  -z           Zero the sectors of the GPT table and entries\n"
-         "  -s NUM       Size (in bytes) of the disk (MTD only)\n"
          "  -p NUM       Size (in blocks) of the disk to pad between the\n"
          "                 primary GPT header and its entries, default 0\n"
          "\n", progname);
@@ -34,7 +33,7 @@
   char *e = 0;
 
   opterr = 0;                     // quiet, you
-  while ((c=getopt(argc, argv, ":hzs:p:D:")) != -1)
+  while ((c=getopt(argc, argv, ":hzp:D:")) != -1)
   {
     switch (c)
     {
@@ -49,9 +48,6 @@
     case 'z':
       params.zap = 1;
       break;
-    case 's':
-      params.size = strtoull(optarg, &e, 0);
-      break;
     case 'p':
       params.padding = strtoull(optarg, &e, 0);
       if (!*optarg || (e && *e))
diff --git a/cgpt/flash_ts.c b/cgpt/flash_ts.c
deleted file mode 100644
index f37c4ac..0000000
--- a/cgpt/flash_ts.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/* *** THIS CODE HAS NOT BEEN SECURITY REVIEWED ***
- * It lives in the firmware directory because that's where it needs to go
- * eventually, but at the moment it is used only by usermode tools.
- * Security review must be completed before this code is used in the
- * firmware.
- * See issue 246680
- */
-
-#include "flash_ts.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "utility.h"
-
-// These match the linux driver
-#define FLASH_TS_MAGIC    0x53542a46
-
-#define FLASH_TS_HEADER_SIZE 16
-#define FLASH_TS_MAX_SIZE 16384
-#define FLASH_TS_MAX_ELEMENT_SIZE (FLASH_TS_MAX_SIZE - FLASH_TS_HEADER_SIZE)
-
-typedef struct {
-  uint32_t magic;
-  uint32_t crc;
-  uint32_t length;
-  uint32_t version;
-  char data[FLASH_TS_MAX_ELEMENT_SIZE];
-} __attribute__((packed)) flash_ts;
-
-typedef struct {
-  size_t start_block; // Partition start offset (in erase blocks)
-  size_t end_block;   // Partition end offset (in erase blocks)
-  size_t chunk_size;  // Minimum element size
-  size_t pages_per_block, chunks_per_block, pages_per_chunk;
-  nand_geom nand;
-
-  size_t cached_block;
-  size_t current_block;
-
-  flash_ts current;
-  flash_ts temp;
-} flash_ts_state;
-
-
-static flash_ts_state state;
-
-size_t pow2(size_t x) {
-  size_t v = 1;
-  while (v < x)
-    v <<= 1;
-  return v;
-}
-
-static inline uint32_t flash_ts_crc(const flash_ts *cache)
-{
-  const unsigned char *p;
-  uint32_t crc = 0;
-  size_t len;
-
-  /* skip magic and crc fields */
-  len = cache->length + 2 * sizeof(uint32_t);
-  p = (const unsigned char*)&cache->length;
-
-  while (len--) {
-    int i;
-
-    crc ^= *p++;
-    for (i = 0; i < 8; i++)
-      crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
-  }
-  return crc ^ ~0;
-}
-
-static inline int flash_ts_check_crc(const flash_ts *ts) {
-  return ts->crc == flash_ts_crc(ts);
-}
-
-static int is_blank(const void *ptr, size_t sz) {
-  const unsigned char *p = (const unsigned char*)ptr;
-  const unsigned char *end = p + sz;
-  while (p < end)
-    if (*p++ != 0xff)
-      return 0;
-  return 1;
-}
-
-static int is_pow2(size_t v) {
-  return v && (v & (v - 1)) == 0;
-}
-
-/* Scan the entire partition to find the latest version */
-static void flash_ts_scan_partition(flash_ts_state *ts) {
-  size_t block;
-
-  for (block = ts->start_block; block < ts->end_block; block++) {
-    if (!nand_is_bad_block(&ts->nand, block)) {
-      size_t chunk;
-      size_t page_base = block * ts->pages_per_block;
-
-      for (chunk = 0; chunk < ts->chunks_per_block;
-           chunk++, page_base += ts->pages_per_chunk) {
-        if (nand_read_page(&ts->nand, page_base,
-                            &ts->temp, sizeof(ts->temp))) {
-          continue;
-        }
-        if (ts->temp.magic != FLASH_TS_MAGIC ||
-            ts->temp.version <= ts->current.version ||
-            !flash_ts_check_crc(&ts->temp)) {
-          if (is_blank(&ts->temp, sizeof(ts->temp))) {
-            // Since we only write sequentially, a blank chunk means no more
-            // data in this block.
-            break;
-          }
-          continue;
-        }
-
-        // It's good & newer than our current version
-        VBDEBUG(("Found good version %d\n", ts->temp.version));
-        ts->current_block = block;
-        Memcpy(&ts->current, &ts->temp, sizeof(ts->current));
-      }
-    }
-  }
-}
-
-static char *flash_ts_search(flash_ts *ts, const char *key) {
-  char *str = &ts->data[0];
-  size_t keylen = strlen(key);
-
-  while(*str && str + keylen < &ts->data[ts->length]) {
-    // Format: name=value\0name2=value2\0 ... keyn=valuen\0\0
-    if (!Memcmp(str, key, keylen) && str[keylen] == '=') {
-      return &str[keylen + 1];
-    } else {
-      str += strlen(str) + 1; // Skip to next key
-    }
-  }
-  return NULL;
-}
-
-static int flash_ts_find_writeable_chunk(flash_ts_state *ts, uint32_t block) {
-  uint32_t page_base = block * ts->pages_per_block;
-  uint32_t page_end = (block + 1) * ts->pages_per_block;
-
-  for(; page_base < page_end; page_base += ts->pages_per_chunk) {
-    if(!nand_read_page(&ts->nand, page_base,
-       &ts->temp, sizeof(ts->temp))) {
-      if (is_blank(&ts->temp, sizeof(ts->temp)))
-        return page_base;
-    }
-  }
-
-  return -1;
-}
-
-static int in_range(const flash_ts_state *ts, uint32_t block) {
-  return block >= ts->start_block && block < ts->end_block;
-}
-
-static int flash_try_write(flash_ts_state *ts, uint32_t page) {
-  return nand_write_page(&ts->nand, page, &ts->current, sizeof(ts->current)) ||
-         nand_read_page(&ts->nand, page, &ts->temp, sizeof(ts->temp)) ||
-         Memcmp(&ts->current, &ts->temp, sizeof(ts->current));
-}
-
-
-static int flash_ts_find_writeable_spot(flash_ts_state *ts,
-                                        uint32_t *page_ofs) {
-  uint32_t block;
-  if (in_range(ts, ts->cached_block)) {
-    // We have a starting position to scan from
-    block = ts->cached_block;
-  } else {
-    block = ts->start_block;
-    VBDEBUG(("Cached block not in range - starting from %u\n", block));
-  }
-  for (; block < ts->end_block; block++) {
-    int chunk;
-    if (nand_is_bad_block(&ts->nand, block)) {
-      VBDEBUG(("Skipping bad block %u\n", block));
-      continue;
-    }
-
-    chunk = flash_ts_find_writeable_chunk(ts, block);
-    if (chunk < 0) {
-      VBDEBUG(("No free chunks in block %u\n", block));
-      continue;
-    }
-
-    VBDEBUG(("Free chunk %d in block %u\n", chunk, block));
-    *page_ofs = chunk;
-    ts->cached_block = block;
-    return 0;
-  }
-  return -1;
-}
-
-static int flash_try_erase(flash_ts_state *ts, int block) {
-  return nand_is_bad_block(&ts->nand, block) ||
-         nand_erase_block(&ts->nand, block);
-}
-
-static int flash_erase_any_block(flash_ts_state *ts, uint32_t hint) {
-  uint32_t block;
-  for (block = hint; block < ts->end_block; block++) {
-    if (!flash_try_erase(ts, block)) {
-      ts->cached_block = block;
-      VBDEBUG(("Erased block %u\n", block));
-      return 0;
-    }
-  }
-
-  if (hint > ts->end_block)
-    hint = ts->end_block;
-
-  for (block = ts->start_block; block < hint; block++) {
-    if (!flash_try_erase(ts, block)) {
-      ts->cached_block = block;
-      VBDEBUG(("Erased block %u\n", block));
-      return 0;
-    }
-  }
-  return -1;
-}
-
-static int flash_ts_write(flash_ts_state *ts) {
-  int passes = 3;
-  uint32_t page;
-
-
-  ts->cached_block = ts->current_block;
-  ts->current.version++;
-  ts->current.crc = flash_ts_crc(&ts->current);
-  VBDEBUG(("flash_ts_write() - %u bytes, crc %08X\n",
-          ts->current.length, ts->current.crc));
-
-  while(passes--) {
-    if (flash_ts_find_writeable_spot(ts, &page)) {
-      if (ts->cached_block == ts->end_block) {
-        uint32_t block;
-
-        // Partition full!
-        // Erase a block to get some space
-        if (in_range(ts, ts->current_block) &&
-            ts->current_block != ts->end_block - 1) {
-          // We don't want to overwrite our good copy if we can avoid it.
-          block = ts->current_block + 1;
-        } else {
-          block = ts->start_block;
-        }
-        VBDEBUG(("Partition full - begin erasing from block %u\n", block));
-
-        // Erase block, and try again.
-        if (flash_erase_any_block(ts, block)) {
-          // Failed to erase anything, so abort.
-          VBDEBUG(("All erases failed, aborting\n"));
-          return -ENOMEM;
-        }
-        continue;
-      } else {
-        // Try again, re-scan everything.
-        ts->cached_block = ts->end_block;
-        continue;
-      }
-    }
-
-    if (flash_try_write(ts, page)) {
-      // Write failure, or read-back failure, try again with the next block.
-      VBDEBUG(("Write failure, retry\n"));
-      ts->cached_block++;
-      continue;
-    }
-
-    VBDEBUG(("Successfully written v%u @ %u\n", ts->current.version, page));
-    ts->current_block = ts->cached_block;
-    return 0;
-  }
-
-  VBDEBUG(("Out of tries\n"));
-  return -EAGAIN;
-}
-
-// Set value, returns 0 on success
-int flash_ts_set(const char *key, const char *value) {
-  flash_ts *ts = &state.current;
-  char *at;
-  size_t keylen = strlen(key);
-  size_t value_len = strlen(value);
-
-  if (keylen == 0) {
-    VBDEBUG(("0-length key - illegal\n"));
-    return -1;
-  }
-
-  if (strchr(key, '=')) {
-    VBDEBUG(("key contains '=' - illegal\n"));
-    return -1;
-  }
-
-  Memcpy(&state.temp, &state.current, sizeof(state.temp));
-
-  at = flash_ts_search(ts, key);
-  if (at) {
-    size_t old_value_len;
-
-    // Already exists
-    if (!strcmp(at, value)) {
-      // No change
-      VBDEBUG(("Values are the same, not writing\n"));
-      return 0;
-    }
-
-    old_value_len = strlen(at);
-    if (value_len == old_value_len) {
-      // Overwrite it
-      Memcpy(at, value, value_len);
-      VBDEBUG(("Values are the same length, overwrite\n"));
-    } else {
-      // Remove it
-      // if value_len == 0, then we're done
-      // if value_len != old_value_len, then we do the append below
-      char *src = at - (keylen + 1);
-      char *end = &ts->data[ts->length];
-      char *from = at + old_value_len + 1;
-
-      VBDEBUG(("Delete old value\n"));
-      memmove(src, from, end - from);
-      ts->length -= (from-src);
-      ts->data[ts->length - 1] = '\0';
-      at = NULL; // Enter the append branch below
-    }
-  } else if (value_len == 0) {
-    // Removing non-existent entry
-    return 0;
-  }
-
-  if (!at && value_len > 0) {
-    // Append it
-
-    if (ts->length + keylen + 1 + value_len + 1 > FLASH_TS_MAX_ELEMENT_SIZE) {
-      // Not enough space, restore previous
-      VBDEBUG(("Not enough space to write %d data bytes\n", (int)value_len));
-      Memcpy(&state.current, &state.temp, sizeof(state.temp));
-      return -1;
-    }
-
-    VBDEBUG(("Append new value\n"));
-    at = &ts->data[ts->length - 1];
-    strcpy(at, key);
-    at[keylen] = '=';
-    strcpy(at + keylen + 1, value);
-    ts->length += keylen + 1 + value_len + 1;
-    ts->data[ts->length-1] = '\0';
-  }
-
-  return flash_ts_write(&state);
-}
-
-void flash_ts_get(const char *key, char *value, unsigned int size) {
-  flash_ts_state *ts = &state;
-  const char *at;
-
-  at = flash_ts_search(&ts->current, key);
-  if (at) {
-    strncpy(value, at, size);
-  } else {
-    *value = '\0';
-  }
-}
-
-int flash_ts_init(unsigned int start_block, unsigned int blocks,
-                  unsigned int szofpg, unsigned int szofblk,
-                  unsigned int szofsector, void *user) {
-  flash_ts_state *ts = &state;
-
-  if (!is_pow2(szofpg) || !is_pow2(szofblk) || !is_pow2(szofsector) ||
-      szofsector > szofpg || szofpg > szofblk || blocks == 0)
-    return -ENODEV;
-
-  Memset(ts, 0, sizeof(*ts));
-
-  // Page <= chunk <= block
-  // Page is minimum writable unit
-  // Chunk is actual write unit
-  // Block is erase unit
-  ts->start_block = start_block;
-  ts->end_block = start_block + blocks;
-  ts->pages_per_block = szofblk / szofpg;
-
-  ts->nand.user = user;
-  ts->nand.szofpg = szofpg;
-  ts->nand.szofblk = szofblk;
-  ts->nand.szofsector = szofsector;
-
-  // Calculate our write size, this mirrors the linux driver's logic
-  ts->chunk_size = pow2((sizeof(flash_ts) + szofpg - 1) & ~(szofpg - 1));
-  if (!is_pow2(ts->chunk_size))
-    return -ENODEV;
-
-  ts->pages_per_chunk = ts->chunk_size / szofpg;
-  if (ts->pages_per_chunk == 0 || ts->chunk_size > szofblk)
-    return -ENODEV;
-
-  ts->chunks_per_block = szofblk / ts->chunk_size;
-
-  ts->current.version = 0;
-  ts->current.length = 1;
-  ts->current.magic = FLASH_TS_MAGIC;
-  ts->current.crc = flash_ts_crc(&ts->current);
-  ts->current.data[0] = '\0';
-  ts->current_block = ts->end_block;
-
-  flash_ts_scan_partition(ts);
-
-  return 0;
-}
diff --git a/cgpt/flash_ts.h b/cgpt/flash_ts.h
deleted file mode 100644
index e5771bb..0000000
--- a/cgpt/flash_ts.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef _FLASH_TS_H
-#define _FLASH_TS_H
-
-typedef struct {
-  unsigned int szofpg; /* Erase unit */
-  unsigned int szofblk; /* Write unit */
-  unsigned int szofsector; /* Sector size used by the rest of cgpt */
-  void *user;
-} nand_geom;
-
-int flash_ts_init(unsigned int start_block, unsigned int blocks,
-                  unsigned int szofpg, unsigned int szofblk,
-                  unsigned int szofsector, void *user);
-
-/* Get/set value, returns 0 on success */
-int flash_ts_set(const char *key, const char *value);
-void flash_ts_get(const char *key, char *value, unsigned int size);
-
-/* Get value as an integer, if missing/invalid return 'default_value' */
-int flash_ts_get_int(const char *key, int default_value);
-
-
-/* These must be implemented outside the driver. */
-int nand_read_page(const nand_geom *nand, int page, void *buf, int size);
-int nand_write_page(const nand_geom *nand, int page, const void *buf, int size);
-int nand_erase_block(const nand_geom *nand, int block);
-int nand_is_bad_block(const nand_geom *nand, int block);
-
-
-
-#endif  /* _FLASH_TS_H */
diff --git a/cgpt/flash_ts_api.h b/cgpt/flash_ts_api.h
deleted file mode 100644
index 47264a4..0000000
--- a/cgpt/flash_ts_api.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#ifndef _LINUX_FLASH_TS_H_
-#define _LINUX_FLASH_TS_H_
-
-#include <asm/ioctl.h>
-#include <asm/types.h>
-
-#define FLASH_TS_MAX_KEY_SIZE 64
-#define FLASH_TS_MAX_VAL_SIZE 2048
-
-struct flash_ts_io_req {
-  char key[FLASH_TS_MAX_KEY_SIZE];
-  char val[FLASH_TS_MAX_VAL_SIZE];
-};
-
-#define FLASH_TS_IO_MAGIC    0xFE
-#define FLASH_TS_IO_SET      _IOW(FLASH_TS_IO_MAGIC, 0, struct flash_ts_io_req)
-#define FLASH_TS_IO_GET      _IOWR(FLASH_TS_IO_MAGIC, 1, struct flash_ts_io_req)
-
-#define FTS_DEVICE           "/dev/fts"
-
-#endif  /* _LINUX_FLASH_TS_H_ */
diff --git a/cgpt/flash_ts_drv.c b/cgpt/flash_ts_drv.c
deleted file mode 100644
index 4709b37..0000000
--- a/cgpt/flash_ts_drv.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Utility for ChromeOS-specific GPT partitions, Please see corresponding .c
- * files for more details.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "flash_ts.h"
-#include "cgpt.h"
-
-inline int page_to_sector(const nand_geom *nand, int page) {
-  return page * (nand->szofpg / nand->szofsector);
-}
-
-int nand_read_page(const nand_geom *nand, int page, void *buf, int size) {
-  uint8_t *page_buff;
-
-  if (Load((struct drive *)nand->user, &page_buff,
-           page_to_sector(nand, page), nand->szofsector,
-           (size + nand->szofsector - 1) / nand->szofsector)) {
-
-    // page may be not erased. return default data.
-    memset(buf, 0xff, size);
-    return 0;
-  }
-  memcpy(buf, page_buff, size);
-  free(page_buff);
-  return 0;
-}
-
-int nand_write_page(const nand_geom *nand,
-                    int page, const void *buf, int buf_size) {
-  void *page_buff;
-  int ret;
-  int sectors = (buf_size + nand->szofsector - 1) / nand->szofsector;
-  int size = nand->szofsector * sectors;
-
-  page_buff  = malloc(size);
-  if (!page_buff)
-    return -1;
-
-  memset(page_buff, 0xff, size);
-  memcpy(page_buff, buf, buf_size);
-
-  ret = Save((struct drive *)nand->user, page_buff, page_to_sector(nand, page),
-             nand->szofsector, sectors);
-  free(page_buff);
-  return ret;
-}
-
-int nand_erase_block(const nand_geom *nand, int block) {
-  int sector = block * (nand->szofblk / nand->szofsector);
-  int res;
-  void *erase_buff = malloc(nand->szofblk);
-  if (!erase_buff)
-    return -1;
-
-  memset(erase_buff, 0xff, nand->szofblk);
-  res = Save((struct drive *)nand->user, erase_buff, sector,
-             nand->szofsector, nand->szofblk / nand->szofsector);
-  free(erase_buff);
-  return res;
-}
-
-int nand_is_bad_block(const nand_geom *nand, int block) {
-  return 0;
-}
diff --git a/firmware/lib/cgptlib/include/mtdlib.h b/firmware/lib/cgptlib/include/mtdlib.h
deleted file mode 100644
index 916c9fa..0000000
--- a/firmware/lib/cgptlib/include/mtdlib.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef VBOOT_REFERENCE_MTDLIB_H_
-#define VBOOT_REFERENCE_MTDLIB_H_
-
-#include "cgptlib.h"
-#include "sysincludes.h"
-
-
-#define MTD_DRIVE_SIGNATURE "CrOSPart" /* This must be exactly 8 chars */
-
-/*
- * Bit definitions and masks for MTD attributes.
- *
- * 13-16 -- partition number
- *  9-12 -- partition type
- *    8  -- success
- *  7-4  -- tries
- *  3-0  -- priority
- */
-#define MTD_ATTRIBUTE_PRIORITY_OFFSET (0)
-#define MTD_ATTRIBUTE_MAX_PRIORITY (15UL)
-#define MTD_ATTRIBUTE_PRIORITY_MASK (MTD_ATTRIBUTE_MAX_PRIORITY << \
-                                     MTD_ATTRIBUTE_PRIORITY_OFFSET)
-
-#define MTD_ATTRIBUTE_TRIES_OFFSET (4)
-#define MTD_ATTRIBUTE_MAX_TRIES (15UL)
-#define MTD_ATTRIBUTE_TRIES_MASK (MTD_ATTRIBUTE_MAX_TRIES << \
-                                  MTD_ATTRIBUTE_TRIES_OFFSET)
-
-#define MTD_ATTRIBUTE_SUCCESSFUL_OFFSET (8)
-#define MTD_ATTRIBUTE_MAX_SUCCESSFUL (1UL)
-#define MTD_ATTRIBUTE_SUCCESSFUL_MASK (MTD_ATTRIBUTE_MAX_SUCCESSFUL << \
-                                       MTD_ATTRIBUTE_SUCCESSFUL_OFFSET)
-
-#define MTD_ATTRIBUTE_TYPE_OFFSET (9)
-#define MTD_ATTRIBUTE_MAX_TYPE (15UL)
-#define MTD_ATTRIBUTE_TYPE_MASK (MTD_ATTRIBUTE_MAX_TYPE << \
-                                 MTD_ATTRIBUTE_TYPE_OFFSET)
-
-#define MTD_ATTRIBUTE_NUMBER_OFFSET (13)
-#define MTD_ATTRIBUTE_MAX_NUMBER (15UL)
-#define MTD_ATTRIBUTE_NUMBER_MASK (MTD_ATTRIBUTE_MAX_NUMBER << \
-                                   MTD_ATTRIBUTE_NUMBER_OFFSET)
-
-
-#define MTD_PARTITION_TYPE_UNUSED             0
-#define MTD_PARTITION_TYPE_CHROMEOS_KERNEL    1
-#define MTD_PARTITION_TYPE_CHROMEOS_FIRMWARE  2
-#define MTD_PARTITION_TYPE_CHROMEOS_ROOTFS    3
-#define MTD_PARTITION_TYPE_CHROMEOS_RESERVED  4
-#define MTD_PARTITION_TYPE_CHROMEOS_FLAGSTORE 5
-#define MTD_PARTITION_TYPE_LINUX_DATA         6
-#define MTD_PARTITION_TYPE_EFI                7
-#define MTD_PARTITION_TYPE_OTHER              8
-
-/* This is mostly arbitrary at the moment, but gives a little room to expand. */
-#define MTD_MAX_PARTITIONS 16
-
-
-
-typedef struct {
-  uint64_t starting_offset;
-  uint64_t ending_offset;
-  uint32_t flags;
-
-  /* 28 characters is a balance between GPT parity and size constraints, at
-   * current sizes this table occupies 10% of the FTS data store.
-   */
-  char label[28];
-} __attribute__((packed)) MtdDiskPartition;
-
-typedef struct {
-  unsigned char signature[8];
-  /* For compatibility, this is only ever the CRC of the first
-   * MTD_DRIVE_V1_SIZE bytes. Further extensions must include their own CRCs,
-   * so older FW can boot newer layouts if we expand in the future.
-   */
-  uint32_t crc32;
-  uint32_t size;
-  uint64_t first_offset;
-  uint64_t last_offset;
-  MtdDiskPartition partitions[MTD_MAX_PARTITIONS];
-} __attribute__((packed)) MtdDiskLayout;
-
-#define MTD_DRIVE_V1_SIZE (32 + 16*48)
-
-#define MTDENTRY_EXPECTED_SIZE (48)
-#define MTDLAYOUT_EXPECTED_SIZE (32 + 16 * MTDENTRY_EXPECTED_SIZE)
-
-
-typedef struct {
-  /* Specifies the flash geometry, in erase blocks & write pages */
-  uint32_t flash_block_bytes;
-  uint32_t flash_page_bytes;
-
-  /* Location, in blocks, of FTS partition */
-  uint32_t fts_block_offset;
-  /* Size, in blocks, of FTS partition */
-  uint32_t fts_block_size;
-
-  /* Size of a LBA sector, in bytes */
-  uint32_t sector_bytes;
-  /* Size of drive in LBA sectors, in sectors */
-  uint64_t drive_sectors;
-
-  /*
-   * The current chromeos kernel index in partition table.  -1 means not
-   * found on drive.
-   */
-  int current_kernel;
-  int current_priority;
-
-  /* If set, the flags partition has been modified and needs to be flushed */
-  int modified;
-
-  /* Internal variables */
-  MtdDiskLayout primary;
-} MtdData;
-
-
-/* APIs are documented in cgptlib.h & cgptlib_internal.h */
-int MtdGetEntryPriority(const MtdDiskPartition *e);
-int MtdGetEntryTries(const MtdDiskPartition *e);
-int MtdGetEntrySuccessful(const MtdDiskPartition *e);
-int MtdGetEntryType(const MtdDiskPartition *e);
-void MtdSetEntrySuccessful(MtdDiskPartition *e, int successful) ;
-void MtdSetEntryPriority(MtdDiskPartition *e, int priority);
-void MtdSetEntryTries(MtdDiskPartition *e, int tries);
-void MtdSetEntryType(MtdDiskPartition *e, int type);
-
-void MtdGetPartitionSize(const MtdDiskPartition *e,
-                         uint64_t *start, uint64_t *end, uint64_t *size);
-
-void MtdGetPartitionSizeInSectors(const MtdDiskPartition *e, uint64_t *start,
-                                  uint64_t *end, uint64_t *size);
-
-int MtdGptInit(MtdData *mtd);
-uint32_t MtdHeaderCrc(MtdDiskLayout *h);
-
-#endif
-
diff --git a/firmware/lib/cgptlib/include/mtdlib_unused.h b/firmware/lib/cgptlib/include/mtdlib_unused.h
deleted file mode 100644
index f331dec..0000000
--- a/firmware/lib/cgptlib/include/mtdlib_unused.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef VBOOT_REFERENCE_MTDLIB_UNUSED_H_
-#define VBOOT_REFERENCE_MTDLIB_UNUSED_H_
-
-int MtdIsKernelEntry(const MtdDiskPartition *e);
-void MtdModified(MtdData *mtd);
-int MtdIsPartitionValid(const MtdDiskPartition *part);
-int MtdCheckParameters(MtdData *disk);
-int MtdCheckEntries(MtdDiskPartition *entries, MtdDiskLayout *h);
-int MtdSanityCheck(MtdData *disk);
-int MtdInit(MtdData *mtd);
-int MtdNextKernelEntry(MtdData *mtd, uint64_t *start_sector, uint64_t *size);
-int MtdUpdateKernelEntry(MtdData *mtd, uint32_t update_type);
-
-#endif	/* VBOOT_REFERENCE_MTDLIB_UNUSED_H_ */
diff --git a/firmware/lib/cgptlib/mtdlib.c b/firmware/lib/cgptlib/mtdlib.c
deleted file mode 100644
index 9866252..0000000
--- a/firmware/lib/cgptlib/mtdlib.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "mtdlib.h"
-
-#include "cgptlib.h"
-#include "cgptlib_internal.h"
-#include "crc32.h"
-#include "utility.h"
-#include "vboot_api.h"
-
-const int kSectorShift = 9; /* 512 bytes / sector. */
-
-int MtdGetEntryPriority(const MtdDiskPartition *e) {
-  return ((e->flags & MTD_ATTRIBUTE_PRIORITY_MASK) >>
-          MTD_ATTRIBUTE_PRIORITY_OFFSET);
-}
-
-int MtdGetEntryTries(const MtdDiskPartition *e) {
-  return ((e->flags & MTD_ATTRIBUTE_TRIES_MASK) >>
-          MTD_ATTRIBUTE_TRIES_OFFSET);
-}
-
-int MtdGetEntrySuccessful(const MtdDiskPartition *e) {
-  return ((e->flags & MTD_ATTRIBUTE_SUCCESSFUL_MASK) >>
-          MTD_ATTRIBUTE_SUCCESSFUL_OFFSET);
-}
-
-int MtdGetEntryType(const MtdDiskPartition *e) {
-  return ((e->flags & MTD_ATTRIBUTE_TYPE_MASK) >> MTD_ATTRIBUTE_TYPE_OFFSET);
-}
-
-static void SetBitfield(MtdDiskPartition *e,
-                        uint32_t offset, uint32_t mask, uint32_t v) {
-  e->flags = (e->flags & ~mask) | ((v << offset) & mask);
-}
-void MtdSetEntrySuccessful(MtdDiskPartition *e, int successful) {
-  SetBitfield(e, MTD_ATTRIBUTE_SUCCESSFUL_OFFSET,
-              MTD_ATTRIBUTE_SUCCESSFUL_MASK, successful);
-}
-void MtdSetEntryPriority(MtdDiskPartition *e, int priority) {
-  SetBitfield(e, MTD_ATTRIBUTE_PRIORITY_OFFSET, MTD_ATTRIBUTE_PRIORITY_MASK,
-              priority);
-}
-void MtdSetEntryTries(MtdDiskPartition *e, int tries) {
-  SetBitfield(e, MTD_ATTRIBUTE_TRIES_OFFSET, MTD_ATTRIBUTE_TRIES_MASK, tries);
-}
-void MtdSetEntryType(MtdDiskPartition *e, int type) {
-  SetBitfield(e, MTD_ATTRIBUTE_TYPE_OFFSET, MTD_ATTRIBUTE_TYPE_MASK, type);
-}
-
-uint32_t MtdHeaderCrc(MtdDiskLayout *h) {
-  uint32_t crc32, original_crc32;
-
-  /* Original CRC is calculated with the CRC field 0. */
-  original_crc32 = h->crc32;
-  h->crc32 = 0;
-  crc32 = Crc32((const uint8_t *)h, h->size);
-  h->crc32 = original_crc32;
-
-  return crc32;
-}
-
-void MtdGetPartitionSize(const MtdDiskPartition *e,
-                         uint64_t *start, uint64_t *end, uint64_t *size) {
-  uint64_t start_tmp, end_tmp;
-  if (!start)
-    start = &start_tmp;
-  if (!end)
-    end = &end_tmp;
-
-  Memcpy(start, &e->starting_offset, sizeof(e->starting_offset));
-  Memcpy(end, &e->ending_offset, sizeof(e->ending_offset));
-  if (size) {
-    *size = *end - *start + 1;
-  }
-}
-
-void MtdGetPartitionSizeInSectors(const MtdDiskPartition *e, uint64_t *start,
-                                  uint64_t *end, uint64_t *size) {
-  MtdGetPartitionSize(e, start, end, size);
-  if (start)
-    *start >>= kSectorShift;
-  if (end)
-    *end >>= kSectorShift;
-  if (size)
-    *size >>= kSectorShift;
-}
-
-
-
diff --git a/firmware/lib/cgptlib/mtdlib_unused.c b/firmware/lib/cgptlib/mtdlib_unused.c
deleted file mode 100644
index bf28500..0000000
--- a/firmware/lib/cgptlib/mtdlib_unused.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "mtdlib.h"
-#include "mtdlib_unused.h"
-
-#include "cgptlib.h"
-#include "cgptlib_internal.h"
-#include "crc32.h"
-#include "utility.h"
-#include "vboot_api.h"
-
-int MtdIsKernelEntry(const MtdDiskPartition *e) {
-  return MtdGetEntryType(e) == MTD_PARTITION_TYPE_CHROMEOS_KERNEL;
-}
-
-void MtdModified(MtdData *mtd) {
-  mtd->modified = 1;
-  mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
-}
-
-int MtdIsPartitionValid(const MtdDiskPartition *part) {
-  return MtdGetEntryType(part) != 0;
-}
-
-int MtdCheckParameters(MtdData *disk) {
-  if (disk->sector_bytes != 512) {
-    return GPT_ERROR_INVALID_SECTOR_SIZE;
-  }
-
-  /* At minimum, the disk must consist of at least one erase block */
-  if (disk->drive_sectors < disk->flash_block_bytes / disk->sector_bytes) {
-    return GPT_ERROR_INVALID_SECTOR_NUMBER;
-  }
-
-  /* Write pages must be an integer multiple of sector size */
-  if (disk->flash_page_bytes == 0 ||
-      disk->flash_page_bytes % disk->sector_bytes != 0) {
-    return GPT_ERROR_INVALID_FLASH_GEOMETRY;
-  }
-
-  /* Erase blocks must be an integer multiple of write pages */
-  if (disk->flash_block_bytes == 0 ||
-      disk->flash_block_bytes % disk->flash_page_bytes != 0) {
-    return GPT_ERROR_INVALID_FLASH_GEOMETRY;
-  }
-
-  /* Without a FTS region, why are you using MTD? */
-  if (disk->fts_block_size == 0) {
-    return GPT_ERROR_INVALID_FLASH_GEOMETRY;
-  }
-  return GPT_SUCCESS;
-}
-
-
-int MtdCheckEntries(MtdDiskPartition *entries, MtdDiskLayout *h) {
-  uint32_t i, j;
-
-  for (i = 0; i < MTD_MAX_PARTITIONS; i++) {
-    for (j = 0; j < MTD_MAX_PARTITIONS; j++) {
-      if (i != j) {
-        MtdDiskPartition *entry = entries + i;
-        MtdDiskPartition *e2 = entries + j;
-        uint64_t start, end;
-        uint64_t other_start, other_end;
-
-        if (!MtdIsPartitionValid(entry) || !MtdIsPartitionValid(e2))
-          continue;
-
-        MtdGetPartitionSize(entry, &start, &end, NULL);
-        MtdGetPartitionSize(e2, &other_start, &other_end, NULL);
-
-        if((start == 0 && end == 0) ||
-           (other_start == 0 && other_end == 0)) {
-          continue;
-        }
-
-        if (end > h->last_offset) {
-          return GPT_ERROR_OUT_OF_REGION;
-        }
-        if (start < h->first_offset) {
-          return GPT_ERROR_OUT_OF_REGION;
-        }
-        if (start > end) {
-          return GPT_ERROR_OUT_OF_REGION;
-        }
-
-        if ((start >= other_start) &&
-            (start <= other_end)) {
-          return GPT_ERROR_START_LBA_OVERLAP;
-        }
-        if ((end >= other_start) &&
-            (end <= other_end)) {
-          return GPT_ERROR_END_LBA_OVERLAP;
-        }
-      }
-    }
-  }
-  return GPT_SUCCESS;
-}
-
-int MtdSanityCheck(MtdData *disk) {
-  MtdDiskLayout *h = &disk->primary;
-  int ret;
-
-  ret = MtdCheckParameters(disk);
-  if(GPT_SUCCESS != ret)
-    return ret;
-
-  if (Memcmp(disk->primary.signature, MTD_DRIVE_SIGNATURE,
-              sizeof(disk->primary.signature))) {
-    return GPT_ERROR_INVALID_HEADERS;
-  }
-
-  if (disk->primary.first_offset > disk->primary.last_offset ||
-      disk->primary.last_offset > disk->drive_sectors * disk->sector_bytes) {
-    return GPT_ERROR_INVALID_SECTOR_NUMBER;
-  }
-
-  if (h->crc32 != MtdHeaderCrc(h)) {
-    return GPT_ERROR_CRC_CORRUPTED;
-  }
-  if (h->size < MTD_DRIVE_V1_SIZE) {
-    return GPT_ERROR_INVALID_HEADERS;
-  }
-  return MtdCheckEntries(h->partitions, h);
-}
-
-
-int MtdInit(MtdData *mtd) {
-  int ret;
-
-  mtd->modified = 0;
-  mtd->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
-  mtd->current_priority = 999;
-
-  ret = MtdSanityCheck(mtd);
-  if (GPT_SUCCESS != ret) {
-    VBDEBUG(("MtdInit() failed sanity check\n"));
-    return ret;
-  }
-
-  return GPT_SUCCESS;
-}
-
-int MtdNextKernelEntry(MtdData *mtd, uint64_t *start_sector, uint64_t *size)
-{
-  MtdDiskLayout *header = &mtd->primary;
-  MtdDiskPartition *entries = header->partitions;
-  MtdDiskPartition *e;
-  int new_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
-  int new_prio = 0;
-  uint32_t i;
-
-  /*
-   * If we already found a kernel, continue the scan at the current
-   * kernel's priority, in case there is another kernel with the same
-   * priority.
-   */
-  if (mtd->current_kernel != CGPT_KERNEL_ENTRY_NOT_FOUND) {
-    for (i = mtd->current_kernel + 1;
-         i < MTD_MAX_PARTITIONS; i++) {
-      e = entries + i;
-      if (!MtdIsKernelEntry(e))
-        continue;
-      VBDEBUG(("MtdNextKernelEntry looking at same prio "
-         "partition %d\n", i+1));
-      VBDEBUG(("MtdNextKernelEntry s%d t%d p%d\n",
-         MtdGetEntrySuccessful(e), MtdGetEntryTries(e),
-         MtdGetEntryPriority(e)));
-      if (!(MtdGetEntrySuccessful(e) || MtdGetEntryTries(e)))
-        continue;
-      if (MtdGetEntryPriority(e) == mtd->current_priority) {
-        MtdGetPartitionSizeInSectors(e, start_sector, NULL, size);
-        mtd->current_kernel = i;
-        VBDEBUG(("MtdNextKernelEntry likes it\n"));
-        return GPT_SUCCESS;
-      }
-    }
-  }
-
-  /*
-   * We're still here, so scan for the remaining kernel with the highest
-   * priority less than the previous attempt.
-   */
-  for (i = 0, e = entries; i < MTD_MAX_PARTITIONS; i++, e++) {
-    int current_prio = MtdGetEntryPriority(e);
-    if (!MtdIsKernelEntry(e))
-      continue;
-    VBDEBUG(("MtdNextKernelEntry looking at new prio "
-       "partition %d\n", i+1));
-    VBDEBUG(("MtdNextKernelEntry s%d t%d p%d\n",
-       MtdGetEntrySuccessful(e), MtdGetEntryTries(e),
-       MtdGetEntryPriority(e)));
-    if (!(MtdGetEntrySuccessful(e) || MtdGetEntryTries(e)))
-      continue;
-    if (current_prio >= mtd->current_priority) {
-      /* Already returned this kernel in a previous call */
-      continue;
-    }
-    if (current_prio > new_prio) {
-      new_kernel = i;
-      new_prio = current_prio;
-    }
-  }
-
-  /*
-   * Save what we found.  Note that if we didn't find a new kernel,
-   * new_prio will still be -1, so future calls to this function will
-   * also fail.
-   */
-  mtd->current_kernel = new_kernel;
-  mtd->current_priority = new_prio;
-
-  if (CGPT_KERNEL_ENTRY_NOT_FOUND == new_kernel) {
-    VBDEBUG(("MtdNextKernelEntry no more kernels\n"));
-    return GPT_ERROR_NO_VALID_KERNEL;
-  }
-
-  VBDEBUG(("MtdNextKernelEntry likes partition %d\n", new_kernel + 1));
-  e = entries + new_kernel;
-  MtdGetPartitionSizeInSectors(e, start_sector, NULL, size);
-
-  return GPT_SUCCESS;
-}
-
-
-int MtdUpdateKernelEntry(MtdData *mtd, uint32_t update_type)
-{
-  MtdDiskLayout *header = &mtd->primary;
-  MtdDiskPartition *entries = header->partitions;
-  MtdDiskPartition *e = entries + mtd->current_kernel;
-  int modified = 0;
-
-  if (mtd->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND)
-    return GPT_ERROR_INVALID_UPDATE_TYPE;
-  if (!MtdIsKernelEntry(e))
-    return GPT_ERROR_INVALID_UPDATE_TYPE;
-
-  switch (update_type) {
-  case GPT_UPDATE_ENTRY_TRY: {
-    /* Used up a try */
-    int tries;
-    if (MtdGetEntrySuccessful(e)) {
-      /*
-       * Successfully booted this partition, so tries field
-       * is ignored.
-       */
-      return GPT_SUCCESS;
-    }
-    tries = MtdGetEntryTries(e);
-    if (tries > 1) {
-      /* Still have tries left */
-      modified = 1;
-      MtdSetEntryTries(e, tries - 1);
-      break;
-    }
-    /* Out of tries, so drop through and mark partition bad. */
-  }
-  case GPT_UPDATE_ENTRY_BAD: {
-    /* Giving up on this partition entirely. */
-    if (!MtdGetEntrySuccessful(e)) {
-      /*
-       * Only clear tries and priority if the successful bit
-       * is not set.
-       */
-      modified = 1;
-      MtdSetEntryTries(e, 0);
-      MtdSetEntryPriority(e, 0);
-    }
-    break;
-  }
-  default:
-    return GPT_ERROR_INVALID_UPDATE_TYPE;
-  }
-
-  if (modified) {
-    MtdModified(mtd);
-  }
-
-  return GPT_SUCCESS;
-}
diff --git a/host/include/cgpt_params.h b/host/include/cgpt_params.h
index e10d15e..e7ac732 100644
--- a/host/include/cgpt_params.h
+++ b/host/include/cgpt_params.h
@@ -17,7 +17,6 @@
   char *drive_name;
   uint64_t drive_size;
   int zap;
-  uint64_t size;
   uint64_t padding;
 } CgptCreateParams;
 
diff --git a/tests/cgptlib_test.c b/tests/cgptlib_test.c
index fc166fd..fd5cda1 100644
--- a/tests/cgptlib_test.c
+++ b/tests/cgptlib_test.c
@@ -7,14 +7,11 @@
 #include <string.h>
 
 #include "../cgpt/cgpt.h"
-#include "../cgpt/flash_ts.h"
 #include "cgptlib_internal.h"
 #include "cgptlib_test.h"
 #include "crc32.h"
 #include "crc32_test.h"
 #include "gpt.h"
-#include "mtdlib.h"
-#include "mtdlib_unused.h"
 #include "test_common.h"
 #define _STUB_IMPLEMENTATION_
 #include "utility.h"
@@ -55,11 +52,6 @@
 const char *progname = "CGPT-TEST";
 const char *command = "TEST";
 
-// Ramdisk for flash ts testing.
-static uint8_t *nand_drive = NULL;
-static uint32_t nand_drive_sz;
-static uint8_t *nand_bad_block_map = NULL;
-
 /*
  * Copy a random-for-this-program-only Guid into the dest. The num parameter
  * completely determines the Guid.
@@ -142,13 +134,6 @@
 	return &gpt;
 }
 
-static MtdData *GetEmptyMtdData() {
-	static MtdData mtd;
-	Memset(&mtd, 0, sizeof(mtd));
-	mtd.current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
-	return &mtd;
-}
-
 /*
  * Fill in most of fields and creates the layout described in the top of this
  * file. Before calling this function, primary/secondary header/entries must
@@ -215,50 +200,6 @@
 	RefreshCrc32(gpt);
 }
 
-static void BuildTestMtdData(MtdData *mtd) {
-	MtdDiskPartition *partitions;
-
-	mtd->sector_bytes = DEFAULT_SECTOR_SIZE;
-	mtd->drive_sectors = DEFAULT_DRIVE_SECTORS;
-	mtd->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
-	mtd->modified = 0;
-	Memset(&mtd->primary, 0, sizeof(mtd->primary));
-
-	Memcpy(mtd->primary.signature, MTD_DRIVE_SIGNATURE,
-		sizeof(mtd->primary.signature));
-	mtd->primary.first_offset = 32 * DEFAULT_SECTOR_SIZE;
-	mtd->primary.last_offset = DEFAULT_DRIVE_SECTORS * DEFAULT_SECTOR_SIZE - 1;
-	mtd->primary.size = MTD_DRIVE_V1_SIZE;
-
-	/* These values are not used directly by the library, but they are checked */
-	mtd->flash_page_bytes = mtd->sector_bytes * 8;
-	mtd->flash_block_bytes = mtd->flash_page_bytes * 8;
-	mtd->fts_block_offset = 1;
-	mtd->fts_block_size = 1;
-
-	partitions = &mtd->primary.partitions[0];
-	partitions[0].starting_offset = 34 * DEFAULT_SECTOR_SIZE;
-	partitions[0].ending_offset = 134 * DEFAULT_SECTOR_SIZE - 1;
-	partitions[0].flags =
-		MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
-	partitions[1].starting_offset = 134 * DEFAULT_SECTOR_SIZE;
-	partitions[1].ending_offset = 233 * DEFAULT_SECTOR_SIZE - 1;
-	partitions[1].flags =
-		MTD_PARTITION_TYPE_CHROMEOS_ROOTFS << MTD_ATTRIBUTE_TYPE_OFFSET;
-	partitions[2].starting_offset = 234 * DEFAULT_SECTOR_SIZE;
-	partitions[2].ending_offset = 332 * DEFAULT_SECTOR_SIZE - 1;
-	partitions[2].flags =
-		MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
-	partitions[3].starting_offset = 334 * DEFAULT_SECTOR_SIZE;
-	partitions[3].ending_offset = 431 * DEFAULT_SECTOR_SIZE - 1;
-	partitions[3].flags =
-		MTD_PARTITION_TYPE_CHROMEOS_ROOTFS << MTD_ATTRIBUTE_TYPE_OFFSET;
-
-	mtd->primary.crc32 = 0;
-	mtd->primary.crc32 = Crc32(&mtd->primary, MTD_DRIVE_V1_SIZE);
-}
-
-
 /*
  * Test if the structures are the expected size; if this fails, struct packing
  * is not working properly.
@@ -269,8 +210,6 @@
 	EXPECT(GUID_EXPECTED_SIZE == sizeof(Guid));
 	EXPECT(GPTHEADER_EXPECTED_SIZE == sizeof(GptHeader));
 	EXPECT(GPTENTRY_EXPECTED_SIZE == sizeof(GptEntry));
-	EXPECT(MTDENTRY_EXPECTED_SIZE == sizeof(MtdDiskPartition));
-	EXPECT(MTDLAYOUT_EXPECTED_SIZE == sizeof(MtdDiskLayout));
 	return TEST_OK;
 }
 
@@ -288,26 +227,15 @@
 	return TEST_OK;
 }
 
-static int TestBuildTestMtdData() {
-	MtdData *mtd = GetEmptyMtdData();
-
-	BuildTestMtdData(mtd);
-	EXPECT(GPT_SUCCESS == MtdInit(mtd));
-	return TEST_OK;
-}
-
 /*
  * Test if wrong sector_bytes or drive_sectors is detected by GptInit().
  * Currently we only support 512 bytes per sector.  In the future, we may
  * support other sizes.  A too small drive_sectors should be rejected by
  * GptInit().
- * For MtdInit(), additionally test various flash geometries to verify
- * that only valid ones are accepted.
  */
 static int ParameterTests(void)
 {
 	GptData *gpt;
-	MtdData *mtd;
 	struct {
 		uint32_t sector_bytes;
 		uint64_t drive_sectors;
@@ -321,32 +249,6 @@
 		 GPT_ENTRIES_SECTORS * 2, GPT_SUCCESS},
 		{4096, DEFAULT_DRIVE_SECTORS, GPT_ERROR_INVALID_SECTOR_SIZE},
 	};
-	struct {
-		uint32_t sector_bytes;
-		uint32_t drive_sectors;
-		uint32_t flash_page_bytes;
-		uint32_t flash_block_bytes;
-		int expected_retval;
-	} mtdcases[] = {
-		{512, DEFAULT_DRIVE_SECTORS, 8*512,
-			8*512, GPT_SUCCESS},
-		{510, DEFAULT_DRIVE_SECTORS, 8*512,
-			8*512, GPT_ERROR_INVALID_SECTOR_SIZE},
-		{512, DEFAULT_DRIVE_SECTORS, 8*512,
-			8*512, GPT_SUCCESS},
-		{512, DEFAULT_DRIVE_SECTORS, 512,
-			8*512, GPT_SUCCESS},
-		{512, DEFAULT_DRIVE_SECTORS, 8*512,
-			10*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
-		{512, DEFAULT_DRIVE_SECTORS, 3*512,
-			9*512, GPT_SUCCESS},
-		{512, DEFAULT_DRIVE_SECTORS, 8*512,
-			6*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
-		{512, DEFAULT_DRIVE_SECTORS, 256,
-			6*512, GPT_ERROR_INVALID_FLASH_GEOMETRY},
-		{512, DEFAULT_DRIVE_SECTORS, 512,
-			6*512 + 256, GPT_ERROR_INVALID_FLASH_GEOMETRY},
-	};
 	int i;
 
 	gpt = GetEmptyGptData();
@@ -357,19 +259,6 @@
 		EXPECT(cases[i].expected_retval == CheckParameters(gpt));
 	}
 
-	mtd = GetEmptyMtdData();
-	for (i = 0; i < ARRAY_SIZE(cases); ++i) {
-		BuildTestMtdData(mtd);
-		mtd->sector_bytes = mtdcases[i].sector_bytes;
-		mtd->drive_sectors = mtdcases[i].drive_sectors;
-		mtd->flash_block_bytes = mtdcases[i].flash_block_bytes;
-		mtd->flash_page_bytes = mtdcases[i].flash_page_bytes;
-		if(mtdcases[i].expected_retval != MtdCheckParameters(mtd)) {
-			printf("i=%d\n",i);
-		}
-		EXPECT(mtdcases[i].expected_retval == MtdCheckParameters(mtd));
-	}
-
 	return TEST_OK;
 }
 
@@ -811,9 +700,6 @@
 	GptData *gpt = GetEmptyGptData();
 	GptHeader *h1 = (GptHeader *)gpt->primary_header;
 	GptEntry *e1 = (GptEntry *)(gpt->primary_entries);
-	MtdData *mtd = GetEmptyMtdData();
-	MtdDiskLayout *mh = &mtd->primary;
-	MtdDiskPartition *me = mh->partitions;
 
 	/* error case: entry.StartingLBA < header.FirstUsableLBA */
 	BuildTestGptData(gpt);
@@ -821,35 +707,18 @@
 	RefreshCrc32(gpt);
 	EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
 
-	BuildTestMtdData(mtd);
-	if (mh->first_offset > 0) {
-		me[0].starting_offset = mh->first_offset - 1;
-		mh->crc32 = MtdHeaderCrc(mh);
-		EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
-	}
-
 	/* error case: entry.EndingLBA > header.LastUsableLBA */
 	BuildTestGptData(gpt);
 	e1[2].ending_lba = h1->last_usable_lba + 1;
 	RefreshCrc32(gpt);
 	EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
 
-	BuildTestMtdData(mtd);
-	me[0].ending_offset = mh->last_offset + 1;
-	mh->crc32 = MtdHeaderCrc(mh);
-	EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
-
 	/* error case: entry.StartingLBA > entry.EndingLBA */
 	BuildTestGptData(gpt);
 	e1[3].starting_lba = e1[3].ending_lba + 1;
 	RefreshCrc32(gpt);
 	EXPECT(GPT_ERROR_OUT_OF_REGION == CheckEntries(e1, h1));
 
-	BuildTestMtdData(mtd);
-	me[0].starting_offset = me[0].ending_offset + 1;
-	mh->crc32 = MtdHeaderCrc(mh);
-	EXPECT(GPT_ERROR_OUT_OF_REGION == MtdCheckEntries(me, mh));
-
 	/* case: non active entry should be ignored. */
 	BuildTestGptData(gpt);
 	Memset(&e1[1].type, 0, sizeof(e1[1].type));
@@ -857,12 +726,6 @@
 	RefreshCrc32(gpt);
 	EXPECT(0 == CheckEntries(e1, h1));
 
-	BuildTestMtdData(mtd);
-	me[0].flags = 0;
-	me[0].starting_offset = me[0].ending_offset + 1;
-	mh->crc32 = MtdHeaderCrc(mh);
-	EXPECT(GPT_SUCCESS == MtdCheckEntries(me, mh));
-
 	return TEST_OK;
 }
 
@@ -871,9 +734,6 @@
 	GptData *gpt = GetEmptyGptData();
 	GptHeader *h = (GptHeader *)gpt->primary_header;
 	GptEntry *e = (GptEntry *)gpt->primary_entries;
-	MtdData *mtd = GetEmptyMtdData();
-	MtdDiskLayout *mh = &mtd->primary;
-	MtdDiskPartition *me = mh->partitions;
 	int i, j;
 
 	struct {
@@ -926,8 +786,6 @@
 
 	for (i = 0; i < ARRAY_SIZE(cases); ++i) {
 		BuildTestGptData(gpt);
-		BuildTestMtdData(mtd);
-		Memset(mh->partitions, 0, sizeof(mh->partitions));
 		ZeroEntries(gpt);
 		for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) {
 			if (!cases[i].entries[j].starting_lba)
@@ -935,22 +793,14 @@
 
 			if (cases[i].entries[j].active) {
 				Memcpy(&e[j].type, &guid_kernel, sizeof(Guid));
-				me[j].flags =
-					MTD_PARTITION_TYPE_CHROMEOS_KERNEL << MTD_ATTRIBUTE_TYPE_OFFSET;
 			}
 			SetGuid(&e[j].unique, j);
 			e[j].starting_lba = cases[i].entries[j].starting_lba;
 			e[j].ending_lba = cases[i].entries[j].ending_lba;
-			me[j].starting_offset = cases[i].entries[j].starting_lba *
-			    DEFAULT_SECTOR_SIZE;
-			me[j].ending_offset = cases[i].entries[j].ending_lba *
-			    DEFAULT_SECTOR_SIZE;
-
 		}
 		RefreshCrc32(gpt);
 
 		EXPECT(cases[i].overlapped == CheckEntries(e, h));
-		EXPECT(cases[i].overlapped == MtdCheckEntries(me, mh));
 	}
 	return TEST_OK;
 }
@@ -1181,8 +1031,6 @@
 {
 	GptData *gpt = GetEmptyGptData();
 	GptEntry *e = (GptEntry *)(gpt->primary_entries);
-	MtdData *mtd = GetEmptyMtdData();
-	MtdDiskPartition *m = &mtd->primary.partitions[0];
 
 	e->attrs.whole = 0x0000000000000000ULL;
 	SetEntrySuccessful(e, 1);
@@ -1193,15 +1041,6 @@
 	EXPECT(0xFEFFFFFFFFFFFFFFULL == e->attrs.whole);
 	EXPECT(0 == GetEntrySuccessful(e));
 
-	m->flags = 0;
-	MtdSetEntrySuccessful(m, 1);
-	EXPECT(0x00000100 == m->flags);
-	EXPECT(1 == MtdGetEntrySuccessful(m));
-	m->flags = ~0;
-	MtdSetEntrySuccessful(m, 0);
-	EXPECT(0xFFFFFEFF == m->flags);
-	EXPECT(0 == MtdGetEntrySuccessful(m));
-
 	e->attrs.whole = 0x0000000000000000ULL;
 	SetEntryTries(e, 15);
 	EXPECT(15 == GetEntryTries(e));
@@ -1211,15 +1050,6 @@
 	EXPECT(0xFF0FFFFFFFFFFFFFULL == e->attrs.whole);
 	EXPECT(0 == GetEntryTries(e));
 
-	m->flags = 0;
-	MtdSetEntryTries(m, 15);
-	EXPECT(0x000000F0 == m->flags);
-	EXPECT(15 == MtdGetEntryTries(m));
-	m->flags = ~0;
-	MtdSetEntryTries(m, 0);
-	EXPECT(0xFFFFFF0F == m->flags);
-	EXPECT(0 == MtdGetEntryTries(m));
-
 	e->attrs.whole = 0x0000000000000000ULL;
 	SetEntryPriority(e, 15);
 	EXPECT(0x000F000000000000ULL == e->attrs.whole);
@@ -1229,15 +1059,6 @@
 	EXPECT(0xFFF0FFFFFFFFFFFFULL == e->attrs.whole);
 	EXPECT(0 == GetEntryPriority(e));
 
-	m->flags = 0;
-	MtdSetEntryPriority(m, 15);
-	EXPECT(0x0000000F == m->flags);
-	EXPECT(15 == MtdGetEntryPriority(m));
-	m->flags = ~0;
-	MtdSetEntryPriority(m, 0);
-	EXPECT(0xFFFFFFF0 == m->flags);
-	EXPECT(0 == MtdGetEntryPriority(m));
-
 	e->attrs.whole = 0xFFFFFFFFFFFFFFFFULL;
 	EXPECT(1 == GetEntrySuccessful(e));
 	EXPECT(15 == GetEntryPriority(e));
@@ -1277,11 +1098,6 @@
 	Memset(&e->type, 0, sizeof(Guid));
 }
 
-static void MtdFreeEntry(MtdDiskPartition *e)
-{
-	MtdSetEntryType(e, MTD_PARTITION_TYPE_UNUSED);
-}
-
 /* Set up an entry. */
 static void FillEntry(GptEntry *e, int is_kernel,
                       int priority, int successful, int tries)
@@ -1292,16 +1108,6 @@
 	SetEntryTries(e, tries);
 }
 
-static void MtdFillEntry(MtdDiskPartition *e, int is_kernel,
-                      int priority, int successful, int tries)
-{
-	MtdSetEntryType(e, is_kernel ? MTD_PARTITION_TYPE_CHROMEOS_KERNEL :
-									MTD_PARTITION_TYPE_CHROMEOS_FIRMWARE);
-	MtdSetEntryPriority(e, priority);
-	MtdSetEntrySuccessful(e, successful);
-	MtdSetEntryTries(e, tries);
-}
-
 /*
  * Invalidate all kernel entries and expect GptNextKernelEntry() cannot find
  * any usable kernel entry.
@@ -1321,20 +1127,6 @@
 	return TEST_OK;
 }
 
-static int MtdNoValidKernelEntryTest(void)
-{
-	MtdData *mtd = GetEmptyMtdData();
-	MtdDiskPartition *e1 = mtd->primary.partitions;
-
-	BuildTestMtdData(mtd);
-	MtdSetEntryPriority(e1 + KERNEL_A, 0);
-	MtdFreeEntry(e1 + KERNEL_B);
-	EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
-	       MtdNextKernelEntry(mtd, NULL, NULL));
-
-	return TEST_OK;
-}
-
 static int GetNextNormalTest(void)
 {
 	GptData *gpt = GetEmptyGptData();
@@ -1422,169 +1214,6 @@
 	return TEST_OK;
 }
 
-static int MtdGetNextNormalTest(void)
-{
-	MtdData *mtd = GetEmptyMtdData();
-	MtdDiskPartition *e1 = mtd->primary.partitions;
-	uint64_t start, size;
-
-	/* Normal case - both kernels successful */
-	BuildTestMtdData(mtd);
-	MtdFillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
-	MtdFillEntry(e1 + KERNEL_B, 1, 2, 1, 0);
-	mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
-	MtdInit(mtd);
-
-	EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(KERNEL_A == mtd->current_kernel);
-	EXPECT(34 == start);
-	EXPECT(100 == size);
-
-	EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(KERNEL_B == mtd->current_kernel);
-	EXPECT(134 == start);
-	EXPECT(99 == size);
-
-	EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
-	       MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(-1 == mtd->current_kernel);
-
-	/* Call as many times as you want; you won't get another kernel... */
-	EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
-	       MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(-1 == mtd->current_kernel);
-
-	return TEST_OK;
-}
-
-static int MtdGetNextPrioTest(void)
-{
-	MtdData *mtd = GetEmptyMtdData();
-	MtdDiskPartition *e1 = mtd->primary.partitions;
-	uint64_t start, size;
-
-	/* Priority 3, 4, 0, 4 - should boot order B, Y, A */
-	BuildTestMtdData(mtd);
-	MtdFillEntry(e1 + KERNEL_A, 1, 3, 1, 0);
-	MtdFillEntry(e1 + KERNEL_B, 1, 4, 1, 0);
-	MtdFillEntry(e1 + KERNEL_X, 1, 0, 1, 0);
-	MtdFillEntry(e1 + KERNEL_Y, 1, 4, 1, 0);
-	mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
-	MtdInit(mtd);
-
-	EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(KERNEL_B == mtd->current_kernel);
-	EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(KERNEL_Y == mtd->current_kernel);
-	EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(KERNEL_A == mtd->current_kernel);
-	EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
-	       MtdNextKernelEntry(mtd, &start, &size));
-
-	return TEST_OK;
-}
-
-static int MtdGetNextTriesTest(void)
-{
-	MtdData *mtd = GetEmptyMtdData();
-	MtdDiskPartition *e1 = mtd->primary.partitions;
-	uint64_t start, size;
-
-	/* Tries=nonzero is attempted just like success, but tries=0 isn't */
-	BuildTestMtdData(mtd);
-	MtdFillEntry(e1 + KERNEL_A, 1, 2, 1, 0);
-	MtdFillEntry(e1 + KERNEL_B, 1, 3, 0, 0);
-	MtdFillEntry(e1 + KERNEL_X, 1, 4, 0, 1);
-	MtdFillEntry(e1 + KERNEL_Y, 1, 0, 0, 5);
-	mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
-	MtdInit(mtd);
-
-	EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(KERNEL_X == mtd->current_kernel);
-	EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(KERNEL_A == mtd->current_kernel);
-	EXPECT(GPT_ERROR_NO_VALID_KERNEL ==
-	       MtdNextKernelEntry(mtd, &start, &size));
-
-	return TEST_OK;
-}
-
-static int MtdUpdateTest() {
-	MtdData *mtd = GetEmptyMtdData();
-	MtdDiskPartition *e = &mtd->primary.partitions[0];
-	uint64_t start, size;
-
-	BuildTestMtdData(mtd);
-
-	/* Tries=nonzero is attempted just like success, but tries=0 isn't */
-	MtdFillEntry(e + KERNEL_A, 1, 4, 1, 0);
-	MtdFillEntry(e + KERNEL_B, 1, 3, 0, 2);
-	MtdFillEntry(e + KERNEL_X, 1, 2, 0, 2);
-	mtd->primary.crc32 = MtdHeaderCrc(&mtd->primary);
-	mtd->modified = 0;
-	EXPECT(GPT_SUCCESS == MtdInit(mtd));
-
-	/* Successful kernel */
-	EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(KERNEL_A == mtd->current_kernel);
-	EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
-	EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
-	EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
-	/* Trying successful kernel changes nothing */
-	EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
-	EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
-	EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
-	EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
-	EXPECT(0 == mtd->modified);
-	/* Marking it bad also does not update it. */
-	EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
-	EXPECT(1 == MtdGetEntrySuccessful(e + KERNEL_A));
-	EXPECT(4 == MtdGetEntryPriority(e + KERNEL_A));
-	EXPECT(0 == MtdGetEntryTries(e + KERNEL_A));
-	EXPECT(0 == mtd->modified);
-
-	/* Kernel with tries */
-	EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(KERNEL_B == mtd->current_kernel);
-	EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_B));
-	EXPECT(3 == MtdGetEntryPriority(e + KERNEL_B));
-	EXPECT(2 == MtdGetEntryTries(e + KERNEL_B));
-	/* Marking it bad clears it */
-	EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
-	EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_B));
-	EXPECT(0 == MtdGetEntryPriority(e + KERNEL_B));
-	EXPECT(0 == MtdGetEntryTries(e + KERNEL_B));
-	/* And that's caused the mtd to need updating */
-	EXPECT(1 == mtd->modified);
-
-	/* Another kernel with tries */
-	EXPECT(GPT_SUCCESS == MtdNextKernelEntry(mtd, &start, &size));
-	EXPECT(KERNEL_X == mtd->current_kernel);
-	EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
-	EXPECT(2 == MtdGetEntryPriority(e + KERNEL_X));
-	EXPECT(2 == MtdGetEntryTries(e + KERNEL_X));
-	/* Trying it uses up a try */
-	EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
-	EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
-	EXPECT(2 == MtdGetEntryPriority(e + KERNEL_X));
-	EXPECT(1 == MtdGetEntryTries(e + KERNEL_X));
-	/* Trying it again marks it inactive */
-	EXPECT(GPT_SUCCESS == MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_TRY));
-	EXPECT(0 == MtdGetEntrySuccessful(e + KERNEL_X));
-	EXPECT(0 == MtdGetEntryPriority(e + KERNEL_X));
-	EXPECT(0 == MtdGetEntryTries(e + KERNEL_X));
-
-	/* Can't update if entry isn't a kernel, or there isn't an entry */
-	MtdSetEntryType(e + KERNEL_X, MTD_PARTITION_TYPE_UNUSED);
-	EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
-	       MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
-	mtd->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
-	EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
-	       MtdUpdateKernelEntry(mtd, GPT_UPDATE_ENTRY_BAD));
-
-	return TEST_OK;
-}
-
 static int GptUpdateTest(void)
 {
 	GptData *gpt = GetEmptyGptData();
@@ -1691,20 +1320,6 @@
 	return TEST_OK;
 }
 
-static int MtdUpdateInvalidKernelTypeTest(void)
-{
-	MtdData *mtd = GetEmptyMtdData();
-
-	BuildTestMtdData(mtd);
-	/* anything, but not CGPT_KERNEL_ENTRY_NOT_FOUND */
-	mtd->current_kernel = 0;
-	/* any invalid update_type value */
-	EXPECT(GPT_ERROR_INVALID_UPDATE_TYPE ==
-	       MtdUpdateKernelEntry(mtd, 99));
-
-	return TEST_OK;
-}
-
 /* Test duplicate UniqueGuids can be detected. */
 static int DuplicateUniqueGuidTest(void)
 {
@@ -1799,177 +1414,6 @@
 	return TEST_OK;
 }
 
-int nand_read_page(const nand_geom *nand, int page, void *buf, int size) {
-  uint32_t ofs = page * nand->szofpg;
-  uint32_t sz = size;
-  if (ofs + sz > nand_drive_sz) {
-    return -1;
-  }
-  Memcpy(buf, nand_drive + ofs, sz);
-  return 0;
-}
-
-int nand_write_page(const nand_geom *nand, int page,
-                    const void *buf, int size) {
-  uint32_t ofs = page * nand->szofpg;
-  uint32_t sz = size;
-  uint32_t i;
-  if (ofs + sz > nand_drive_sz) {
-    return -1;
-  }
-  for (i = 0; i < sz; i++) {
-    if (nand_drive[ofs + i] != 0xff) {
-      return -1;
-    }
-  }
-  Memcpy(nand_drive + ofs, buf, sz);
-  return 0;
-}
-
-int nand_erase_block(const nand_geom *nand, int block) {
-  uint32_t ofs = block * nand->szofblk;
-  uint32_t sz = nand->szofblk;
-  if (ofs + sz > nand_drive_sz) {
-    return -1;
-  }
-  if (!--nand_bad_block_map[block]) {
-    return -1;
-  }
-  Memset(nand_drive + ofs, 0xFF, sz);
-  return 0;
-}
-
-int nand_is_bad_block(const nand_geom *nand, int block) {
-  return nand_bad_block_map[block] == 0;
-}
-
-
-static void nand_make_ramdisk() {
-  if (nand_drive) {
-    free(nand_drive);
-  }
-  if (nand_bad_block_map) {
-    free(nand_bad_block_map);
-  }
-  nand_drive_sz = 1024 * 1024 * 16;
-  nand_drive = (uint8_t *)malloc(nand_drive_sz);
-  nand_bad_block_map = (uint8_t *)malloc(nand_drive_sz / 512);
-  Memset(nand_drive, 0xff, nand_drive_sz);
-  Memset(nand_bad_block_map, 0xff, nand_drive_sz / 512);
-}
-
-static int MtdFtsTest() {
-  int MtdLoad(struct drive *drive, int sector_bytes);
-  int MtdSave(struct drive *drive);
-  int FlashGet(const char *key, uint8_t *data, uint32_t *bufsz);
-  int FlashSet(const char *key, const uint8_t *data, uint32_t bufsz);
-
-  int i, j, err;
-
-  struct {
-    int result;
-    unsigned int offset, size, block_size_bytes, page_size_bytes;
-  } cases[] = {
-    { 0, 1, 2, 1024 * 1024, 1024 * 4 },
-    { 0, 1, 2, 1024 * 1024, 1024 * 16 },
-
-    /* Failure cases, non-power-of-2 */
-    { -ENODEV, 1, 2, 5000000, 1024 * 16 },
-    { -ENODEV, 1, 2, 1024 * 1024, 65535 },
-
-    /* Page > block */
-    { -ENODEV, 1, 2, 1024 * 16, 1024 * 1024 },
-  };
-
-
-  /* Check if the FTS store works */
-  for (i = 0; i < ARRAY_SIZE(cases); i++) {
-    nand_make_ramdisk();
-    EXPECT(cases[i].result == flash_ts_init(cases[i].offset, cases[i].size,
-                                            cases[i].page_size_bytes,
-                                            cases[i].block_size_bytes, 512, 0));
-
-    if (cases[i].result == 0) {
-      /* We should have a working FTS store now */
-      char buffer[64];
-      uint8_t blob[256], blob_read[256];
-      uint32_t sz = sizeof(blob_read);
-      struct drive drive;
-
-      /* Test the low level API */
-      EXPECT(0 == flash_ts_set("some_key", "some value"));
-      flash_ts_get("some_key", buffer, sizeof(buffer));
-      EXPECT(0 == strcmp(buffer, "some value"));
-
-      /* Check overwrite */
-      EXPECT(0 == flash_ts_set("some_key", "some other value"));
-      flash_ts_get("some_key", buffer, sizeof(buffer));
-      EXPECT(0 == strcmp(buffer, "some other value"));
-
-      /* Check delete */
-      EXPECT(0 == flash_ts_set("some_key", ""));
-
-      /* Verify that re-initialization pulls the right record. */
-      flash_ts_init(cases[i].offset, cases[i].size, cases[i].page_size_bytes,
-                    cases[i].block_size_bytes, 512, 0);
-      flash_ts_get("some_key", buffer, sizeof(buffer));
-      EXPECT(0 == strcmp(buffer, ""));
-
-      /* Fill up the disk, eating all erase cycles */
-      for (j = 0; j < nand_drive_sz / 512; j++) {
-        nand_bad_block_map[j] = 2;
-      }
-      for (j = 0; j < 999999; j++) {
-        char str[32];
-        sprintf(str, "%d", j);
-        err = flash_ts_set("some_new_key", str);
-        if (err) {
-          EXPECT(err == -ENOMEM);
-          break;
-        }
-
-        /* Make sure we can figure out where the latest is. */
-        flash_ts_init(cases[i].offset, cases[i].size, cases[i].page_size_bytes,
-                      cases[i].block_size_bytes, 512, 0);
-        flash_ts_get("some_new_key", buffer, sizeof(buffer));
-        EXPECT(0 == strcmp(buffer, str));
-      }
-      EXPECT(j < 999999);
-
-      /* We need our drive back. */
-      nand_make_ramdisk();
-      flash_ts_init(cases[i].offset, cases[i].size, cases[i].page_size_bytes,
-                    cases[i].block_size_bytes, 512, 0);
-
-
-      for (j = 0; j < 256; j++) {
-        blob[j] = j;
-      }
-
-      /* Hex conversion / blob storage */
-      EXPECT(0 == FlashSet("some_blob", blob, sizeof(blob)));
-      EXPECT(0 == FlashGet("some_blob", blob_read, &sz));
-      EXPECT(sz == sizeof(blob_read));
-      EXPECT(0 == Memcmp(blob, blob_read, sizeof(blob)));
-
-      BuildTestMtdData(&drive.mtd);
-      drive.mtd.flash_block_bytes = cases[i].block_size_bytes;
-      drive.mtd.flash_page_bytes = cases[i].page_size_bytes;
-      drive.mtd.fts_block_offset = cases[i].offset;
-      drive.mtd.fts_block_size = cases[i].size;
-      drive.mtd.sector_bytes = 512;
-      drive.mtd.drive_sectors = nand_drive_sz / 512;
-
-      /* MTD-level API */
-      EXPECT(0 == MtdSave(&drive));
-      Memset(&drive.mtd.primary, 0, sizeof(drive.mtd.primary));
-      EXPECT(0 == MtdLoad(&drive, 512));
-    }
-  }
-
-  return TEST_OK;
-}
-
 static int CheckHeaderOffDevice()
 {
 	GptData* gpt = GetEmptyGptData();
@@ -2039,7 +1483,6 @@
 	} test_cases[] = {
 		{ TEST_CASE(StructSizeTest), },
 		{ TEST_CASE(TestBuildTestGptData), },
-		{ TEST_CASE(TestBuildTestMtdData), },
 		{ TEST_CASE(ParameterTests), },
 		{ TEST_CASE(HeaderCrcTest), },
 		{ TEST_CASE(HeaderSameTest), },
@@ -2057,24 +1500,17 @@
 		{ TEST_CASE(OverlappedPartitionTest), },
 		{ TEST_CASE(SanityCheckTest), },
 		{ TEST_CASE(NoValidKernelEntryTest), },
-		{ TEST_CASE(MtdNoValidKernelEntryTest), },
 		{ TEST_CASE(EntryAttributeGetSetTest), },
 		{ TEST_CASE(EntryTypeTest), },
 		{ TEST_CASE(GetNextNormalTest), },
 		{ TEST_CASE(GetNextPrioTest), },
 		{ TEST_CASE(GetNextTriesTest), },
-		{ TEST_CASE(MtdGetNextNormalTest), },
-		{ TEST_CASE(MtdGetNextPrioTest), },
-		{ TEST_CASE(MtdGetNextTriesTest), },
 		{ TEST_CASE(GptUpdateTest), },
-		{ TEST_CASE(MtdUpdateTest), },
 		{ TEST_CASE(UpdateInvalidKernelTypeTest), },
-		{ TEST_CASE(MtdUpdateInvalidKernelTypeTest), },
 		{ TEST_CASE(DuplicateUniqueGuidTest), },
 		{ TEST_CASE(TestCrc32TestVectors), },
 		{ TEST_CASE(GetKernelGuidTest), },
 		{ TEST_CASE(ErrorTextTest), },
-		{ TEST_CASE(MtdFtsTest), },
 		{ TEST_CASE(CheckHeaderOffDevice), },
 	};