Beispiel #1
0
static ssize_t ftl_reload(FAR void *priv, FAR uint8_t *buffer,
                          off_t startblock, size_t nblocks)
{
  struct ftl_struct_s *dev = (struct ftl_struct_s *)priv;
  ssize_t nread;

  /* Read the full erase block into the buffer */

  nread   = MTD_BREAD(dev->mtd, startblock, nblocks, buffer);
  if (nread != nblocks)
    {
      fdbg("Read %d blocks starting at block %d failed: %d\n",
            nblocks, startblock, nread);
    }
  return nread;
}
Beispiel #2
0
int nxffs_rdcache(FAR struct nxffs_volume_s *volume, off_t block)
{
    size_t nxfrd;

    /* Check if the requested data is already in the cache */

    if (block != volume->cblock)
    {
        /* Read the specified blocks into cache */

        nxfrd = MTD_BREAD(volume->mtd, block, 1, volume->cache);
        if (nxfrd != 1)
        {
            fdbg("ERROR: Read block %d failed: %d\n", block, nxfrd);
            return -EIO;
        }

        /* Remember what is in the cache */

        volume->cblock  = block;
    }

    return OK;
}
Beispiel #3
0
int nxffs_dump(FAR struct mtd_dev_s *mtd, bool verbose)
{
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_FS)
  struct nxffs_blkinfo_s blkinfo;
  int ret;

  /* Get the volume geometry. (casting to uintptr_t first eliminates
   * complaints on some architectures where the sizeof long is different
   * from the size of a pointer).
   */

  memset(&blkinfo, 0, sizeof(struct nxffs_blkinfo_s));
  ret = MTD_IOCTL(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&blkinfo.geo));
  if (ret < 0)
    {
      fdbg("ERROR: MTD ioctl(MTDIOC_GEOMETRY) failed: %d\n", -ret);
      goto errout;
    }

  /* Save the verbose output indication */

  blkinfo.verbose = verbose;

  /* Allocate a buffer to hold one block */

  blkinfo.buffer = (FAR uint8_t *)kmalloc(blkinfo.geo.blocksize);
  if (!blkinfo.buffer)
    {
      fdbg("ERROR: Failed to allocate block cache\n");
      ret = -ENOMEM;
      goto errout;
    }

  /* Now read every block on the device */

  fdbg("NXFFS Dump:\n");
  fdbg(g_hdrformat);

  blkinfo.nblocks = blkinfo.geo.erasesize * blkinfo.geo.neraseblocks / blkinfo.geo.blocksize;
  for (blkinfo.block = 0, blkinfo.offset = 0;
       blkinfo.block < blkinfo.nblocks;
       blkinfo.block++, blkinfo.offset += blkinfo.geo.blocksize)
    {
      /* Read the next block */

      ret = MTD_BREAD(mtd, blkinfo.block, 1, blkinfo.buffer);
      if (ret < 0)
        {
          fdbg("ERROR: Failed to read block %d\n", blkinfo.block);
          goto errout_with_block;
        }

      /* Analyze the block */

      nxffs_analyze(&blkinfo);
    }
  fdbg("%d blocks analyzed\n", blkinfo.nblocks);

errout_with_block:
  kfree(blkinfo.buffer);
errout:
  return ret;

#else
  return -ENOSYS;
#endif
}
Beispiel #4
0
static int nxffs_badblocks(FAR struct nxffs_volume_s *volume)
{
  FAR uint8_t *blkptr;   /* Pointer to next block data */
  off_t eblock;          /* Erase block number */
  off_t lblock;          /* Logical block number */
  ssize_t nxfrd;         /* Number of blocks transferred */
  bool good;             /* TRUE: block is good */
  bool modified;         /* TRUE: The erase block has been modified */
  int i;

  /* Read and verify each erase block */

  for (eblock = 0; eblock < volume->geo.neraseblocks; eblock++)
    {
      /* Read the entire erase block */

      lblock = eblock * volume->blkper;
      nxfrd  = MTD_BREAD(volume->mtd, lblock, volume->blkper, volume->pack);
      if (nxfrd != volume->blkper)
        {
          fdbg("Read erase block %d failed: %d\n", lblock, nxfrd);
          return -EIO;
        }

      /* Process each logical block */

      modified = false;
      for (blkptr = volume->pack, i = 0;
           i < volume->blkper;
           blkptr += volume->geo.blocksize, i++)
        {
          FAR struct nxffs_block_s *blkhdr = (FAR struct nxffs_block_s*)blkptr;

          /* Check block header */

          good = true;
          if (memcmp(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE) != 0 ||
              blkhdr->state != BLOCK_STATE_GOOD)
            {
              good = false;
            }

          /* Check that block data is erased */

          else
            {
              size_t blocksize = volume->geo.blocksize - SIZEOF_NXFFS_BLOCK_HDR;
              size_t erasesize = nxffs_erased(&blkptr[SIZEOF_NXFFS_BLOCK_HDR], blocksize);
              good = (blocksize == erasesize);
            }

          /* If the block is bad, attempt to re-write the block header indicating
           * a bad block (of course, if the block has failed, this may not be
           * possible, depending upon failure modes.
           */

          if (!good)
            {
              memcpy(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE);
              blkhdr->state = BLOCK_STATE_BAD;
              modified = true;
            }
        }

      /* If the erase block was modified, then re-write it */

      if (modified)
        {
          nxfrd = MTD_BWRITE(volume->mtd, lblock, volume->blkper, volume->pack);
          if (nxfrd != volume->blkper)
            {
              fdbg("Write erase block %d failed: %d\n", lblock, nxfrd);
              return -EIO;
            }
        }
    }

  return OK;
}
Beispiel #5
0
static off_t  mtdconfig_consolidate(FAR struct mtdconfig_struct_s *dev)
{
  off_t       src_block, dst_block;
  off_t       src_offset, dst_offset;
  uint16_t    blkper, x, bytes, bytes_left_in_block;
  struct mtdconfig_header_s hdr;
  int         ret;
  uint8_t     sig[CONFIGDATA_BLOCK_HDR_SIZE];
  uint8_t     *pBuf;

  /* Prepare to copy block 0 to the last block (erase blocks) */

  src_block = 0;
  dst_block = dev->neraseblocks - 1;

  /* Ensure the last block is erased */

  MTD_ERASE(dev->mtd, dst_block, 1);
  blkper = dev->erasesize / dev->blocksize;
  dst_block *= blkper;            /* Convert to read/write blocks */

  /* Allocate a small buffer for moving data */

  pBuf = (uint8_t *)kmm_malloc(dev->blocksize);
  if (pBuf == NULL)
    {
      return 0;
    }

  /* Now copy block zero to last block */

  for (x = 0; x < blkper; x++)
    {
      ret = MTD_BREAD(dev->mtd, src_block++, 1, dev->buffer);
      if (ret < 0)
        {
          /* I/O Error! */

          goto errout;
        }

      ret = MTD_BWRITE(dev->mtd, dst_block++, 1, dev->buffer);
      if (ret < 0)
        {
          /* I/O Error! */

          goto errout;
        }
    }

  /* Erase block zero and write a format signature. */

  MTD_ERASE(dev->mtd, 0, 1);
  sig[0] = 'C';
  sig[1] = 'D';
  sig[2] = CONFIGDATA_FORMAT_VERSION;
  mtdconfig_writebytes(dev, 0, sig, sizeof(sig));

  /* Now consolidate entries */

  src_block = 1;
  dst_block = 0;
  src_offset = src_block * dev->erasesize + CONFIGDATA_BLOCK_HDR_SIZE;
  dst_offset = CONFIGDATA_BLOCK_HDR_SIZE;

  while (src_block < dev->neraseblocks)
    {
      /* Scan all headers and move them to the src_offset */

retry_relocate:
      MTD_READ(dev->mtd, src_offset, sizeof(hdr), (uint8_t *) &hdr);
      if (hdr.flags == MTD_ERASED_FLAGS)
        {
          /* Test if the source entry is active or if we are at the end
           * of data for this erase block.
           */

          if (hdr.id == MTD_ERASED_ID)
            {
              /* No more data in this erase block.  Advance to the
               * next one.
               */

              src_offset = (src_block + 1) * dev->erasesize + CONFIGDATA_BLOCK_HDR_SIZE;
            }
          else
            {
              /* Test if this entry will fit in the current destination block */

              bytes_left_in_block = (dst_block + 1) * dev->erasesize - dst_offset;
              if (hdr.len + sizeof(hdr) > bytes_left_in_block)
                {
                  /* Item doesn't fit in the block.  Advance to the next one */

                  /* Update control variables */

                  dst_block++;
                  dst_offset = dst_block * dev->erasesize + CONFIGDATA_BLOCK_HDR_SIZE;

                  DEBUGASSERT(dst_block != src_block);

                  /* Retry the relocate */

                  goto retry_relocate;
                }

              /* Copy this entry to the destination */

              //printf("REL HDR: ID=%04X,%02X  Len=%4d  Off=%5d  Src off=%4d\n",
              //  hdr.id, hdr.instance, hdr.len, dst_offset, src_offset);
              mtdconfig_writebytes(dev, dst_offset, (uint8_t *) &hdr, sizeof(hdr));
              src_offset += sizeof(hdr);
              dst_offset += sizeof(hdr);

              /* Now copy the data */

              while (hdr.len)
                {
                  bytes = hdr.len;
                  if (bytes > dev->blocksize)
                    {
                      bytes = dev->blocksize;
                    }

                  /* Move the data. */

                  mtdconfig_readbytes(dev, src_offset, pBuf, bytes);
                  mtdconfig_writebytes(dev, dst_offset, pBuf, bytes);

                  /* Update control variables */

                  hdr.len -= bytes;
                  src_offset += bytes;
                  dst_offset += bytes;
                }
            }
        }
      else
        {
          /* This item has been released.  Skip it! */

          src_offset += sizeof(hdr) + hdr.len;
          if (src_offset + sizeof(hdr) >= (src_block + 1) * dev->erasesize ||
              src_offset == (src_block +1 ) * dev->erasesize)
            {
              /* No room left at end of source block */

              src_offset = (src_block + 1) * dev->erasesize + CONFIGDATA_BLOCK_HDR_SIZE;
            }
        }

      /* Test if we are out of space in the src block */

      if (src_offset + sizeof(hdr) >= (src_block + 1) * dev->erasesize)
        {
          /* No room at end of src block for another header.  Go to next
           * source block.
           */

          src_offset = (src_block + 1) * dev->erasesize + CONFIGDATA_BLOCK_HDR_SIZE;
        }

      /* Test if we advanced to the next block.  If we did, then erase the
       * old block.
       */

      if (src_block != src_offset / dev->erasesize)
        {
          /* Erase the block ... we have emptied it */

          MTD_ERASE(dev->mtd, src_block, 1);
          src_block++;
        }

      /* Test if we are out of space in the dst block */

      if (dst_offset + sizeof(hdr) >= (dst_block + 1) * dev->erasesize)
        {
          /* No room at end of dst block for another header.  Go to next block.  */

          dst_block++;
          dst_offset = dst_block * dev->erasesize + CONFIGDATA_BLOCK_HDR_SIZE;
          DEBUGASSERT(dst_block != src_block);
        }
    }

errout:
  kmm_free(pBuf);
  return 0;
}
Beispiel #6
0
static off_t  mtdconfig_ramconsolidate(FAR struct mtdconfig_struct_s *dev)
{
  FAR uint8_t *pBuf;
  FAR struct  mtdconfig_header_s *phdr;
  struct      mtdconfig_header_s  hdr;
  uint16_t    src_block = 0, dst_block = 0, blkper;
  off_t       dst_offset = CONFIGDATA_BLOCK_HDR_SIZE;
  off_t       src_offset = CONFIGDATA_BLOCK_HDR_SIZE;
  off_t       bytes_left_in_block;
  uint8_t     sig[CONFIGDATA_BLOCK_HDR_SIZE];
  int         ret;

  /* Allocate a consolidation buffer */

  pBuf = (uint8_t *)kmm_malloc(dev->erasesize);
  if (pBuf == NULL)
    {
      /* Unable to allocate buffer, can't consolidate! */

      return 0;
    }

  /* Loop for all blocks and consolidate them */

  blkper = dev->erasesize / dev->blocksize;
  while (src_block < dev->neraseblocks)
    {
      /* Point to beginning of pBuf and read the next erase block */

      ret = MTD_BREAD(dev->mtd, src_block * blkper, blkper, pBuf);
      if (ret < 0)
        {
          /* Error doing block read */

          dst_offset = 0;
          goto errout;
        }

      /* Now erase the block */

      ret = MTD_ERASE(dev->mtd, src_block, 1);
      if (ret < 0)
        {
          /* Error erasing the block */

          dst_offset = 0;
          goto errout;
        }

      /* If this is block zero, then write a format signature */

      if (src_block == 0)
        {
          sig[0] = 'C';
          sig[1] = 'D';
          sig[2] = CONFIGDATA_FORMAT_VERSION;
          mtdconfig_writebytes(dev, 0, sig, sizeof(sig));
        }

      /* Copy active items back to the MTD device */

      while (src_offset < dev->erasesize)
        {
          phdr = (FAR struct mtdconfig_header_s *) &pBuf[src_offset];
          if (phdr->id == MTD_ERASED_ID)
            {
              /* No more data in this erase block */

              src_offset = dev->erasesize;
              continue;
            }

          if (phdr->flags == MTD_ERASED_FLAGS)
            {
              /* This is an active entry.  Copy it.  Check if it
               * fits in the current destination block.
               */

              bytes_left_in_block = (dst_block + 1) * dev->erasesize -
                dst_offset;
              if (bytes_left_in_block < sizeof(*phdr) + phdr->len)
                {
                  /* Item won't fit in the destination block.  Move to
                   * the next block
                   */

                  dst_block++;
                  dst_offset = dst_block * dev->erasesize + CONFIGDATA_BLOCK_HDR_SIZE;

                  /* Test for program bug.  We shouldn't ever overflow
                   * even if no entries were inactive.
                   */

                  DEBUGASSERT(dst_block != dev->neraseblocks);
                }

              /* Now Write the item to the current dst_offset location */

              //printf("REL HDR: ID=%04X,%02X  Len=%4d  Off=%5d  Src off=%4d\n",
              //  phdr->id, phdr->instance, phdr->len, dst_offset, src_offset);
              ret = mtdconfig_writebytes(dev, dst_offset, (uint8_t *) phdr,
                                         sizeof(hdr));
              if (ret < 0)
                {
                  dst_offset = 0;
                  goto errout;
                }

              dst_offset += sizeof(hdr);
              ret = mtdconfig_writebytes(dev, dst_offset, &pBuf[src_offset
                  + sizeof(hdr)], phdr->len);
              dst_offset += phdr->len;

              /* Test if enough space in dst block for another header */

              if (dst_offset + sizeof(hdr) >= (dst_block + 1) * dev->erasesize ||
                  dst_offset == (dst_block + 1) * dev->erasesize)
                {
                  dst_block++;
                  dst_offset = dst_block * dev->erasesize + CONFIGDATA_BLOCK_HDR_SIZE;
                }
            }

          /* Increment past the current source item */

          src_offset += sizeof(hdr) + phdr->len;
          if (src_offset + sizeof(hdr) > dev->erasesize)
            {
              src_offset = dev->erasesize;
            }

          DEBUGASSERT(src_offset <= dev->erasesize);
        }

      /* Increment to next source block */

      src_block++;
      src_offset = CONFIGDATA_BLOCK_HDR_SIZE;
    }

errout:
  kmm_free(pBuf);
  return dst_offset;
}
Beispiel #7
0
static int  mtdconfig_writebytes(FAR struct mtdconfig_struct_s *dev, int offset,
                                 FAR const uint8_t *pdata, int writelen)
{
  int ret = OK;

#ifdef CONFIG_MTD_BYTE_WRITE

  /* Test if this MTD device supports byte write */

  if (dev->mtd->write != NULL)
    {
      ret = MTD_WRITE(dev->mtd, offset, writelen, pdata);
    }
  else
#endif

    /* Perform the write using the block write method of the MTD */

    {
      uint16_t  block;
      uint16_t  index;
      off_t     bytes_this_block;
      off_t     bytes_written = 0;

      while (writelen)
        {
          /* Read existing data from the the block into the buffer */

          block = offset / dev->blocksize;
          ret = MTD_BREAD(dev->mtd, block, 1, dev->buffer);
          if (ret != 1)
            {
              ret = -EIO;
              goto errout;
            }

          index = offset - block * dev->blocksize;
          bytes_this_block = dev->blocksize - index;
          if (bytes_this_block > writelen)
            {
              bytes_this_block = writelen;
            }

          /* Now write data to the block */

          memcpy(&dev->buffer[index], pdata, bytes_this_block);
          ret = MTD_BWRITE(dev->mtd, block, 1, dev->buffer);
          if (ret != 1)
            {
              ret = -EIO;
              goto errout;
            }

          /* Update writelen, etc. */

          writelen -= bytes_this_block;
          pdata += bytes_this_block;
          offset += bytes_this_block;
          bytes_written += bytes_this_block;
        }

      /* Return the number of bytes written */

      ret = bytes_written;
    }

errout:
  return ret;
}
Beispiel #8
0
static int  mtdconfig_readbytes(FAR struct mtdconfig_struct_s *dev, int offset,
                                FAR uint8_t *pdata, int readlen)
{
  off_t  bytestoread = readlen;
  off_t  bytesthisblock, firstbyte;
  off_t  block, index;
  int    ret = OK;
  size_t bytes;

  /* Test if read interface supported.  If it is, use it directly */

  if ((dev->mtd->read == NULL) && (readlen < dev->blocksize))
    {
      /* Read interface available.  Read directly to buffer */

      bytes = MTD_READ(dev->mtd, offset, readlen, pdata);
      if (bytes != readlen)
        {
          /* Error reading data! */

          ret = -EIO;
        }
    }
  else
    {
      /* Read interface not available, do a block read into our buffer */

      block = offset / dev->blocksize;
      firstbyte = offset - (block * dev->blocksize);
      bytesthisblock = dev->blocksize - firstbyte;
      if (bytesthisblock > readlen)
        {
          bytesthisblock = readlen;
        }

      index = 0;

      while (bytestoread > 0)
        {
          if (bytesthisblock < dev->blocksize || bytestoread < dev->blocksize)
            {
              /* Copy to temp buffer first...don't need the whole block */

              bytes = MTD_BREAD(dev->mtd, block, 1, dev->buffer);
              if (bytes != 1)
                {
                  /* Error reading data!  */

                  ret = -EIO;
                  goto errout;
                }

              /* Copy data to the output buffer */

              memcpy(&pdata[index], &dev->buffer[firstbyte], bytesthisblock);
            }
          else
            {
              /* We are reading a whole block.  Read directly to buffer */

              bytes = MTD_BREAD(dev->mtd, block, 1, &pdata[index]);
              if (bytes != 1)
                {
                  /* Error reading data!  */

                  ret = -EIO;
                  goto errout;
                }
            }

          /* Update values for next block read */

          bytestoread -= bytesthisblock;
          index += bytesthisblock;
          bytesthisblock = dev->blocksize;
          if (bytesthisblock > bytestoread)
            {
              bytesthisblock = bytestoread;
            }

          firstbyte = 0;
          block++;
        }
    }

errout:
  return ret;
}
Beispiel #9
0
Datei: ftl.c Projekt: a1ien/nuttx
static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer,
                         off_t startblock, size_t nblocks)
{
  struct ftl_struct_s *dev = (struct ftl_struct_s *)priv;
  off_t  alignedblock;
  off_t  mask;
  off_t  rwblock;
  off_t  eraseblock;
  off_t  offset;
  size_t remaining;
  size_t nxfrd;
  int    nbytes;
  int    ret;

  /* Get the aligned block.  Here is is assumed: (1) The number of R/W blocks
   * per erase block is a power of 2, and (2) the erase begins with that same
   * alignment.
   */

  mask         = dev->blkper - 1;
  alignedblock = (startblock + mask) & ~mask;

  /* Handle partial erase blocks before the first unaligned block */

  remaining = nblocks;
  if (alignedblock > startblock)
    {
      /* Check if the write is shorter than to the end of the erase block */

      bool short_write = (remaining < (alignedblock - startblock));

      /* Read the full erase block into the buffer */

      rwblock = startblock & ~mask;
      nxfrd   = MTD_BREAD(dev->mtd, rwblock, dev->blkper, dev->eblock);
      if (nxfrd != dev->blkper)
        {
          ferr("ERROR: Read erase block %d failed: %d\n", rwblock, nxfrd);
          return -EIO;
        }

      /* Then erase the erase block */

      eraseblock = rwblock / dev->blkper;
      ret        = MTD_ERASE(dev->mtd, eraseblock, 1);
      if (ret < 0)
        {
          ferr("ERROR: Erase block=%d failed: %d\n", eraseblock, ret);
          return ret;
        }

      /* Copy the user data at the end of the buffered erase block */

      offset = (startblock & mask) * dev->geo.blocksize;

      if (short_write)
        {
          nbytes = remaining * dev->geo.blocksize;
        }
      else
        {
          nbytes = dev->geo.erasesize - offset;
        }

      finfo("Copy %d bytes into erase block=%d at offset=%d\n",
             nbytes, eraseblock, offset);

      memcpy(dev->eblock + offset, buffer, nbytes);

      /* And write the erase block back to flash */

      nxfrd = MTD_BWRITE(dev->mtd, rwblock, dev->blkper, dev->eblock);
      if (nxfrd != dev->blkper)
        {
          ferr("ERROR: Write erase block %d failed: %d\n", rwblock, nxfrd);
          return -EIO;
        }

      /* Then update for amount written */

      if (short_write)
        {
          remaining = 0;
        }
      else
        {
          remaining -= dev->blkper - (startblock & mask);
        }

      buffer += nbytes;
    }

  /* How handle full erase pages in the middle */

  while (remaining >= dev->blkper)
    {
      /* Erase the erase block */

      eraseblock = alignedblock / dev->blkper;
      ret        = MTD_ERASE(dev->mtd, eraseblock, 1);
      if (ret < 0)
        {
          ferr("ERROR: Erase block=%d failed: %d\n", eraseblock, ret);
          return ret;
        }

      /* Write a full erase back to flash */

      finfo("Write %d bytes into erase block=%d at offset=0\n",
             dev->geo.erasesize, alignedblock);

      nxfrd = MTD_BWRITE(dev->mtd, alignedblock, dev->blkper, buffer);
      if (nxfrd != dev->blkper)
        {
          ferr("ERROR: Write erase block %d failed: %d\n", alignedblock, nxfrd);
          return -EIO;
        }

      /* Then update for amount written */

      alignedblock += dev->blkper;
      remaining    -= dev->blkper;
      buffer       += dev->geo.erasesize;
    }

  /* Finally, handle any partial blocks after the last full erase block */

  if (remaining > 0)
    {
      /* Read the full erase block into the buffer */

     nxfrd = MTD_BREAD(dev->mtd, alignedblock, dev->blkper, dev->eblock);
      if (nxfrd != dev->blkper)
        {
          ferr("ERROR: Read erase block %d failed: %d\n", alignedblock, nxfrd);
          return -EIO;
        }

      /* Then erase the erase block */

      eraseblock = alignedblock / dev->blkper;
      ret        = MTD_ERASE(dev->mtd, eraseblock, 1);
      if (ret < 0)
        {
          ferr("ERROR: Erase block=%d failed: %d\n", eraseblock, ret);
          return ret;
        }

      /* Copy the user data at the beginning the buffered erase block */

      nbytes = remaining * dev->geo.blocksize;
      finfo("Copy %d bytes into erase block=%d at offset=0\n",
             nbytes, alignedblock);
      memcpy(dev->eblock, buffer, nbytes);

      /* And write the erase back to flash */

      nxfrd = MTD_BWRITE(dev->mtd, alignedblock, dev->blkper, dev->eblock);
      if (nxfrd != dev->blkper)
        {
          ferr("ERROR: Write erase block %d failed: %d\n", alignedblock, nxfrd);
          return -EIO;
        }
    }

  return nblocks;
}
Beispiel #10
0
int nxffs_blockstats(FAR struct nxffs_volume_s *volume,
                     FAR struct nxffs_blkstats_s *stats)
{
#ifndef CONFIG_NXFFS_NAND
  FAR uint8_t *bptr;     /* Pointer to next block data */
  int lblock;            /* Logical block index */
#endif
  off_t ioblock;         /* I/O block number */
  int ret;

  /* Process each erase block */

  memset(stats, 0, sizeof(struct nxffs_blkstats_s));

#ifndef CONFIG_NXFFS_NAND
  for (ioblock = 0; ioblock < volume->nblocks; ioblock += volume->blkper)
    {
      /* Read the full erase block */

      ret = MTD_BREAD(volume->mtd, ioblock, volume->blkper, volume->pack);
      if (ret < volume->blkper)
        {
          ferr("ERROR: Failed to read erase block %d: %d\n",
               ioblock / volume->blkper, ret);
          return ret;
        }

      /* Then examine each logical block in the erase block */

      for (bptr = volume->pack, lblock = 0;
           lblock < volume->blkper;
           bptr += volume->geo.blocksize, lblock++)
        {
          /* We read the block successfully, now check for errors tagged
           * in the NXFFS data.
           */

          FAR struct nxffs_block_s *blkhdr = (FAR struct nxffs_block_s *)bptr;

          /* Increment the total count of blocks examined */

          stats->nblocks++;

          /* Collect statistics */
          /* Check if this is a block that should be recognized by NXFFS */

          if (memcmp(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE) != 0)
            {
              /* Nope.. block must not be formatted */

              stats->nunformat++;
            }
          else if (blkhdr->state == BLOCK_STATE_BAD)
            {
              /* The block is marked as bad */

               stats->nbad++;
            }
          else if (blkhdr->state == BLOCK_STATE_GOOD)
            {
              /* The block is marked as good */

              stats-> ngood++;
            }
          else
            {
              /* The good/bad mark is not recognized.  Let's call this
               * corrupt (vs. unformatted).
               */

              stats->ncorrupt++;
            }
        }
    }

  finfo("Number blocks:        %d\n", stats->nblocks);
  finfo("  Good blocks:        %d\n", stats->ngood);
  finfo("  Bad blocks:         %d\n", stats->nbad);
  finfo("  Unformatted blocks: %d\n", stats->nunformat);
  finfo("  Corrupt blocks:     %d\n", stats->ncorrupt);

#else
  for (ioblock = 0; ioblock < volume->nblocks; ioblock++)
    {
      /* Increment the total count of blocks examined */

      stats->nblocks++;

      /* Read each logical block, one at a time.  We could read all of the
       * blocks in the erase block into volume->pack at once.  But this would
       * be a problem for NAND which may generate read errors due to bad ECC
       * on individual blocks.
       */

      ret = MTD_BREAD(volume->mtd, ioblock, 1, volume->pack);
      if (ret < 1)
        {
          /* This should not happen at all on most kinds of FLASH.  But a
           * bad read will happen normally with a NAND device that has
           * uncorrectable blocks.  So, just for NAND, we keep the count
           * of unreadable blocks.
           */

          ferr("ERROR: Failed to read block %d: %d\n", ioblock, ret);

          /* Increment the count of un-readable blocks */

          stats->nbadread++;
        }
      else
        {
          /* We read the block successfully, now check for errors tagged
           * in the NXFFS data.
           */

          FAR struct nxffs_block_s *blkhdr = (FAR struct nxffs_block_s *)volume->pack;

          /* Collect statistics */
          /* Check if this is a block that should be recognized by NXFFS */

          if (memcmp(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE) != 0)
            {
              /* Nope.. block must not be formatted */

              stats->nunformat++;
            }
          else if (blkhdr->state == BLOCK_STATE_BAD)
            {
              /* The block is marked as bad */

              stats->nbad++;
            }
          else if (blkhdr->state == BLOCK_STATE_GOOD)
            {
              /* The block is marked as good */

              stats-> ngood++;
            }
          else
            {
              /* The good/bad mark is not recognized.  Let's call this
               * corrupt (vs. unformatted).
               */

              stats->ncorrupt++;
            }
        }
    }

  finfo("Number blocks:        %d\n", stats->nblocks);
  finfo("  Good blocks:        %d\n", stats->ngood);
  finfo("  Bad blocks:         %d\n", stats->nbad);
  finfo("  Unformatted blocks: %d\n", stats->nunformat);
  finfo("  Corrupt blocks:     %d\n", stats->ncorrupt);
  finfo("  Unreadable blocks:  %d\n", stats->nbadread);

#endif
  return OK;
}
Beispiel #11
0
int nxffs_dump(FAR struct mtd_dev_s *mtd, bool verbose)
{
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_DEBUG_FS)
  struct nxffs_blkinfo_s blkinfo;
  int ret;

  /* Get the volume geometry. (casting to uintptr_t first eliminates
   * complaints on some architectures where the sizeof long is different
   * from the size of a pointer).
   */

  memset(&blkinfo, 0, sizeof(struct nxffs_blkinfo_s));
  ret = MTD_IOCTL(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&blkinfo.geo));
  if (ret < 0)
    {
      ferr("ERROR: MTD ioctl(MTDIOC_GEOMETRY) failed: %d\n", -ret);
      return ret;
    }

  /* Save the verbose output indication */

  blkinfo.verbose = verbose;

  /* Allocate a buffer to hold one block */

  blkinfo.buffer = (FAR uint8_t *)kmm_malloc(blkinfo.geo.blocksize);
  if (!blkinfo.buffer)
    {
      ferr("ERROR: Failed to allocate block cache\n");
      return -ENOMEM;
    }

  /* Now read every block on the device */

  syslog(LOG_NOTICE, "NXFFS Dump:\n");
  syslog(LOG_NOTICE, g_hdrformat);

  blkinfo.nblocks = blkinfo.geo.erasesize * blkinfo.geo.neraseblocks / blkinfo.geo.blocksize;
  for (blkinfo.block = 0, blkinfo.offset = 0;
       blkinfo.block < blkinfo.nblocks;
       blkinfo.block++, blkinfo.offset += blkinfo.geo.blocksize)
    {
      /* Read the next block */

      ret = MTD_BREAD(mtd, blkinfo.block, 1, blkinfo.buffer);
      if (ret < 0)
        {
#ifndef CONFIG_NXFFS_NAND
          /* Read errors are fatal */

          ferr("ERROR: Failed to read block %d\n", blkinfo.block);
          kmm_free(blkinfo.buffer);
          return ret;
#else
          /* A read error is probably fatal on all media but NAND.
           * On NAND, the read error probably just signifies a block
           * with an uncorrectable ECC failure.  So, to handle NAND,
           * just report the read error and continue.
           */

          syslog(LOG_NOTICE, g_format, blkinfo.block, 0, "BLOCK", "RD FAIL",
               blkinfo.geo.blocksize);
#endif
        }
      else
        {
          /* Analyze the block that we just read */

          nxffs_analyze(&blkinfo);
        }
    }

  syslog(LOG_NOTICE, "%d blocks analyzed\n", blkinfo.nblocks);

  kmm_free(blkinfo.buffer);
  return OK;

#else
  return -ENOSYS;
#endif
}