write_page()

PROTOTYPE

#include <bfs.h>

int write_page(ui32 page, const ui8 *src, int mdata, void *dev);

DESCRIPTION

write_page() writes data and ECC check bytes to the NAND page specified by page. src points to where data is copied from and is aligned according to the CACHE_LINE_SIZE definition in “bsp.h”. TargetBFS provides software ECC routines for 1 and 4-bit correction per 512 bytes, but for performance hardware ECC should be used for 4-bit correction and above.

mdata is 1 if the page contains TargetBFS metadata, 0 if it does not. This flag is stored on the flash page. Usually, the metadata flag and the ECC check bytes are stored in the page’s spare area. During initialization, bfsAddNandVol() searches for volume metadata by calling the driver function is_metadata(), which reads the metadata flag.

For fast initialization, the metadata flag should be stored such that its value is recoverable without ECC decoding. For instance, writing a byte with either 0x00 or 0xFF if mdata is either 1 or 0 allows fast recovery of the original value without bit error correction (by counting ‘1’s). The value stored when mdata is 1 must not match the value present when the page is erased.

dev is a driver-supplied data pointer. The value passed to TargetBFS by the bfsAddNandVol() call is passed back as the last parameter of each driver callback function. It can be used in any way that is convenient for the driver implementation.

write_page() should not return until the write is finished. It can poll a flash device’s “ready” bit or, if the system supports this, block until an interrupt from the flash device signals that the operation is finished.

write_page() returns 0 for success, -1 if a chip error occurs, or -2 for a fatal error. If -1 is returned, TargetBFS performs bad block recovery and records the block as “bad”. Once a block becomes bad, it is no longer erased or written to. A fatal error causes all subsequent accesses to fail with errno set to EIO.

EXAMPLE

static int write_page(ui32 page, const ui8 *data, int mdata, void *dev)
{
  uint i, status;

  /*-------------------------------------------------------------------*/
  /* Store metadata flag in spare area, after "initially bad" flag.    */
  /*-------------------------------------------------------------------*/
  Spare[1] = mdata ? 0x00 : 0xFF;

  /*-------------------------------------------------------------------*/
  /* Encode each ECC page and store checkbytes (3 per) in spare buffer.*/
  /*-------------------------------------------------------------------*/
  for (i = 0; i < BFS_PAGE_SIZE / ECC_PAGE_SIZE; ++i)
    eccEnc512B1E(data + i * ECC_PAGE_SIZE, &Spare[2 + i * CB_PER_PAGE]);

  /*-------------------------------------------------------------------*/
  /* Select the device by lowering CE.                                 */
  /*-------------------------------------------------------------------*/
  nandLowerCE(0);

  /*-------------------------------------------------------------------*/
  /* Send the Page Program Setup command.                              */
  /*-------------------------------------------------------------------*/
  nandCmd(0x80);    /* page program setup command */

  /*-------------------------------------------------------------------*/
  /* Send address as five separate bytes.                              */
  /*-------------------------------------------------------------------*/
  nandAddr5B(0, 0, page, page >> 8, page >> 16);

  /*-------------------------------------------------------------------*/
  /* Send main page data in one large write.                           */
  /*-------------------------------------------------------------------*/
  nandWrData8(data, BFS_PAGE_SIZE);

  /*-------------------------------------------------------------------*/
  /* Write the spare bytes.                                            */
  /*-------------------------------------------------------------------*/
  nandWrData8(Spare, MAIN_ECC_BEG + MAIN_CB_CNT);

  /*-------------------------------------------------------------------*/
  /* Send the Page Program Confirm command.                            */
  /*-------------------------------------------------------------------*/
  nandCmd(0x10);    /* page program confirm command */

  /*-------------------------------------------------------------------*/
  /* Wait until device is ready.                                       */
  /*-------------------------------------------------------------------*/
  nandBusyWait(0);

  /*-------------------------------------------------------------------*/
  /* Send Status Read command and read device status.                  */
  /*-------------------------------------------------------------------*/
  nandCmd(0x70);    /* status read command */
  status = REG_8(NAND_PORT);

  /*-------------------------------------------------------------------*/
  /* End device access and return status.                              */
  /*-------------------------------------------------------------------*/
  nandRaiseCE(0);
  assert(status & BIT7);  /* WP must be off */
  assert(status & BIT6);  /* program must have finished */
  return status & BIT0 ? -1 : 0;
} /*lint !e818*/