C H A P T E R  3

User Flash

This chapter describes the user flash driver for the onboard flash PROM and how to use it. The Netra CP2300 is equipped with user flash memory. This chapter includes the following sections:


User Flash Usage and Implementation

The customer can use the flash memory for various purposes such as storage for RTOS, user data storage, OpenBoot PROM information or to store dropins. Dropins simplify customizing a system for the user.

When OpenBoot PROM in system flash is corrupted, and if a backup copy of OpenBoot PROM is stored in user flash, you can switch the SMC switch to boot the OpenBoot PROM from the user flash and then use flash update to get a good OpenBoot PROM image back into the system flash.

The user flash includes a flash PROM chip that can be programmed. The Netra CP2300 has an 8MB flash that is logically divided into two parts: 1MB for the system/boot flash and 7MB for the user flash. The physical address for the flash is 1ff.f000.0000.


System Compatibility

The following releases support the user flash driver:


User Flash Driver

The uflash is the device driver for the flash PROM device on the Netra CP2300. Access to the driver is carried out through open, read, write, pread, pwrite and ioctl system interfaces.

On the Netra CP2300, one of these devices is supported. There is one logical device file for each physical device that can be accessed from applications. Users can use these devices for storing applications and data.

An instance of the driver is loaded for the device. The driver blocks any reads to the device while a write is in progress. Multiple, concurrent reads can go through to the same device at the same time. Writes to a device occur one at a time. All read and write operations are supported at this time. Access to the device normally happens a byte at a time.

The device also supports erase and lock features. Applications can use them through the IOCTL interface. The device is divided into logical blocks. Applications that issue these operations also supply a block number or a range of blocks that are a target of these operations. Locks are preserved across reboots. Locking a block prevents an erase or write operation on that block.

Switch Settings

The user flash modules on the Netra CP2300 are write enabled by default. The user flash is detected during OpenBoot PROM boot by default.

OpenBoot PROM Device Tree and Properties

This section provides information on the user flash OpenBoot PROM device node and its properties.

User flash OpenBoot PROM device node is:

/pci@1f,0/pci@1,1/isa@7/flashprom@1f,100000

See TABLE 3-1 for the user flash node properties.

TABLE 3-1 User Flash Node Properties

Property

Description/Value

dcode-offset

00000002

blocks-per-bank

00000038

block-size

00020000

model

SUNW,yyy-yyyy

compatible

nct-uflash

reg

0000001f 00100000 00700000


User Flash Device Files

The user flash device files are as follows:

Interface (Header) File

The user flash header file is located in the following path:

/usr/platform/SUNW,Netra-CP2300/include/sys/uflash_if.h


Application Programming Interface

Access to the user flash device from the Solaris operating environment is through an application or user C program. No command-line tool is available. User programs open this device file and then issue read, write, or ioctl commands to use the user flash device.

The system calls are listed below in TABLE 3-2.

TABLE 3-2 System Calls

Call

Description

read(), pread()

reads device

pwrite()

writes device

ioctl()

erases device, queries device parameters


The ioctl supported commands are listed below:

#define UIOCIBLK (uflashIOC|0)     /* identify */
#define UIOCQBLK (uflashIOC|1)     /* query a block */
#define UIOCLBLK (uflashIOC|2)     /* lock a block */
#define UIOCCLCK (uflashIOC|4)     /* clear all locks */
#define UIOCEBLK (uflashIOC|5)     /* erase a block */

Note that these ioctl commands are not supported:

#define UIOCMLCK (uflashIOC|3)     /* master lock */
#define UIOCEALL (uflashIOC|6)     /* erase all unlocked blocks */
#define UIOCEFUL (uflashIOC|7)     /* erase full chip */

Structures to Use in IOCTL Arguments

PROM Information Structure

The PROM information structure holds device information returned by the driver in response to an identify command.

CODE EXAMPLE 3-1 PROM Information Structure
/*
 * PROM info structure.
 */
typedef struct {
        uint16_t        mfr_id;            /* manufacturer id */
        uint16_t        dev_id;            /* device id */
        /* allow future expansion */
        int8_t          blk_status[256];   /* blks status filled by driver */
        int32_t         blk_num;           /* total # of blocks */
        int32_t         blk_size;          /* # of bytes per block */
} uflash_info_t;

User Flash User Interface Structure

The user flash user interface structure holds user parameters to commands such as erase.

CODE EXAMPLE 3-2 User Flash Interface Structure
/*
 * uflash user interface structure.
 */
typedef struct {
        int             blk_num;
        int             num_of_blks;
        uflash_info_t   info;              /* to be filled by the driver */
} uflash_if_t;

Errors

EINVAL

Application passed one or more incorrect arguments to the system call.

EACCESS

Write or Erase operation was attempted on a locked block.

ECANCELLED

A hardware malfunction has been detected. Normally, retrying the command should fix this problem. If the problem persists, power cycling the system may be necessary.

ENXIO

This error indicates problems with the driver state. Power cycle of the system or reinstallation of driver may be necessary.

EFAULT

An error was encountered when copying arguments between the application and driver (kernel) space.

ENOMEM

System was low on memory when the driver attempted to acquire it.



Example Programs

Example programs are provided in this section for the following actions on user flash device:

Read Example Program

CODE EXAMPLE 3-3 contains the Read Action on the user flash device.

CODE EXAMPLE 3-3 Read Action on User Flash Device
/*
* uflash_read.c
 * An example that shows how to read user flash
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <uflash_if.h>
char *uflash0 = "/dev/uflash0";
int ufd0;
uflash_if_t ufif0;
char *buf0;
char *module;
static int
uflash_init() {
  char *buf0 = malloc(ufif0.info.blk_size);
if (!buf0) {
    printf("%s: cannot allocate memory\n", module);
    return(-1);
  }
/* open device */
  if ((ufd0 = open(uflash0, O_RDWR)) == -1 ) {
    perror("uflash0: ");
    exit(1);
  }
/* get uflash sizes */
  if (ioctl(ufd0, UIOCIBLK, &ufif0) == -1 ) {
    perror("ioctl(ufd0, UIOCIBLK): ");
    exit(1);
  }
if (ufd0) {
    printf("%s: \n", uflash0);
    printf("manfacturer id = 0x%p\n", ufif0.info.mfr_id);
    printf("device id = 0x%p\n", ufif0.info.dev_id);
    printf("number of blocks = 0x%p", ufif0.info.blk_num); 
    printf("block size = 0x%p"  ufif0.info.blk_size);
  }
static int
uflash_uninit() {
  if (ufd0)
    close(ufd0);
cleanup:
  if (buf0)
    free(buf0);
}
static int
uflash_read() {
  /* read block 0 of user flash */
  if (pread(ufd0, buf0, ufif0.info.blk_size, 0) != ufif0.info.blk_size)
        perror("uflash0:read");
return(0);
}
main() {
  int ret;
module = argv[0];
ret = uflash_init();
if (!ret)
    uflash_read();
uflash_uninit();
} 

Write Example Program

CODE EXAMPLE 3-4 contains the Write Action on the user flash device.

CODE EXAMPLE 3-4 Write Action on User Flash Device
/*
 * uflash_write.c
 * An example that shows how to write user flash
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <uflash_if.h>
char *uflash0 = "/dev/uflash0";
int ufd0;
uflash_if_t ufif0;
char *buf0;
char *module;
static int
uflash_init() {
  char *buf0 = malloc(ufif0.info.blk_size);
if (!buf0) {
    printf("%s: cannot allocate memory\n", module);
    return(-1);
  }
/* open device */
  if ((ufd0 = open(uflash0, O_RDWR)) == -1 ) {
    perror("uflash0: ");
    exit(1);
  }
/* get uflash sizes */
  if (ioctl(ufd0, UIOCIBLK, &ufif0) == -1 ) {
    perror("ioctl(ufd0, UIOCIBLK): ");
    exit(1);
  }
if (ufd0) {
    printf("%s: \n", uflash0);
    printf("manfacturer id = 0x%p\n", ufif0.info.mfr_id);
    printf("device id = 0x%p\n", ufif0.info.dev_id);
    printf("number of blocks = 0x%p", ufif0.info.blk_num); 
    printf("block size = 0x%p"  ufif0.info.blk_size);
  }
}
static int
uflash_uninit() {
  if (ufd0)
    close(ufd0);
cleanup:
  if (buf0)
    free(buf0);
}
static int
uflash_write() {
  int i;
/* write some pattern to the buffers */
  for (i = 0; i < ufif0.info.blk_size; i += sizeof(int))
        *((int *) (buf0 + i)) = 0xDEADBEEF;
/* write block 0 of user flash */
  if (pwrite(ufd0, buf0, ufif0.info.blk_size, 0) != ufif0.info.blk_size)
        perror("uflash0:write");
return(0);
}
main() {
  int ret;
module = argv[0];
ret = uflash_init();
if (!ret)
    uflash_write();
uflash_uninit();
} 

Erase Example Program

CODE EXAMPLE 3-5 contains the Erase Action on the user flash device.

CODE EXAMPLE 3-5 Erase Action on User Flash Device
/*
 * uflash_erase.c
 * An example that shows how to erase user flash
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <uflash_if.h>
char *uflash0 = "/dev/uflash0";
int ufd0;
uflash_if_t ufif0;
char *module;
static int
uflash_init() {
 /* open device */
  if ((ufd0 = open(uflash0, O_RDWR)) == -1 ) {
    perror("uflash0: ");
    exit(1);
  }
/* get uflash sizes */
  if (ufd0 && ioctl(ufd0, UIOCIBLK, &ufif0) == -1 ) {
    perror("ioctl(ufd0, UIOCIBLK): ");
    exit(1);
  }
if (ufd0) {
    printf("%s: \n", uflash0);
    printf("manfacturer id = 0x%p\n", ufif0.info.mfr_id);
    printf("device id = 0x%p\n", ufif0.info.dev_id);
    printf("number of blocks = 0x%p", ufif0.info.blk_num); 
    printf("block size = 0x%p"  ufif0.info.blk_size);
  }
}
static int
uflash_uninit() {
  if (ufd0)
    close(ufd0);
}
static int
uflash_erase() {   
  if (ufd0 && ioctl(ufd0, UIOCEFUL, &ufif0) == -1 ) {
    perror("ioctl(ufd0, UIOCEFUL): ");
    return(-1);
  }
  printf("\nerase successful on %s\n", uflash0);
return(0);
}
main() {
  int ret;
module = argv[0];
ret = uflash_init();
if (!ret)
    uflash_erase();
uflash_uninit();
} 

Block Erase Example Program

CODE EXAMPLE 3-6 contains the Block Erase Action on the user flash device.

CODE EXAMPLE 3-6 Block Erase Action on User Flash Device
/*
 * uflash_blockerase.c
 * An example that shows how to erase block(s) of user flash
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <uflash_if.h>
char *uflash0 = "/dev/uflash0";
int ufd0;
uflash_if_t ufif0;
char *module;
static int
uflash_init() {
 /* open device */
  if ((ufd0 = open(uflash0, O_RDWR)) == -1 ) {
    perror("uflash0: ");
    exit(1);
  }
/* get uflash sizes */
  if (ioctl(ufd0, UIOCIBLK, &ufif0) == -1 ) {
    perror("ioctl(ufd0, UIOCIBLK): ");
    exit(1);
  }
if (ufd0) {
    printf("%s: \n", uflash0);
    printf("manfacturer id = 0x%p\n", ufif0.info.mfr_id);
    printf("device id = 0x%p\n", ufif0.info.dev_id);
    printf("number of blocks = 0x%p", ufif0.info.blk_num); 
    printf("block size = 0x%p"  ufif0.info.blk_size);
  }
}
static int
uflash_uninit() {
  if (ufd0)
    close(ufd0);
}
static int
uflash_blockerase() {
  /* erase 2 blocks starting from block 1 of user flash */
  uf0.blk_num = 1;
  uf0.num_of_blks = 2;
  if (ufd0 && ioctl(ufd0, UIOCEBLK, &ufif0) == -1 ) {
    perror("ioctl(ufd0, UIOCEBLK): ");
    return(-1);
  }
  printf("\nblockerase successful on %s\n", uflash0);
return(0);
}
main() {
  int ret;
module = argv[0];
ret = uflash_init();
if (!ret)
    uflash_blockerase();
uflash_uninit();
} 

Sample User Flash Application Program

You can use the following program to test the user flash device and driver. This program also demonstrates how this device can be used.

CODE EXAMPLE 3-7 Sample User Flash Application Program
/*
 *
 *        This application program demonstrates the user program
 *        interface to the User Flash PROM driver.
 *
 *        One can read or write a number of bytes up to the size of
 *        the user PROM by means of pread() and pwrite() calls.
 *        All other functions of the PROM can be accessed by 
 *        means of ioctl() calls such as:
 *         -) identify the chip,
 *         -) query block,
 *         -) lock block/unlock block,
 *         -) master lock,
 *         -) erase block, erase all unlocked blocks, and 
 *            erase whole PROM
 *        Please note that not all of the above ioctl calls are 
 *        available for all flash PROMs. It is the user's 
 *        responsibility to find out the features of a given PROM. 
 *        The type, block size, and number of blocks of the PROM 
 *        are returned by "identify" ioctl().
 *
 *         The pwrite() erases the block[s] and then does the 
 *         writing.
 *
 *        Use the following line to compile your custom application
 *        programs:
 *          make uflash_test
 */
 
#pragma ident   "@(#)uflash_test.c 1.0     03/04/30 SMI"
 
#include <stdio.h>
#include <sys/signal.h>
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/stream.h>
#include "uflash_if.h"
/*
      */
     #if 1
     #define PROM_SIZE 0x700000 /* 7 MBytes */
     #endif
static char *help[14] = {
       "0 -- read     user flash PROM",
       "1 -- write    user flash PROM",
       "2 -- identify user flash PROM",
       "3 -- query    blocks",
       "4 -- lock     blocks",
       "5 -- master   lock",
       "6 -- clear    all locks",
       "7 -- erase    blocks",
       "8 -- erase    all unlocked blocks",
       "9 -- erase    whole PROM",
       "a -- switch   PROMs",
       "q -- quit",
       "?/h -- display this menu",
       ""
};
 
/*char            get_cmd(); */
 
static char
get_cmd()
{
           char    buf[10];
           gets(buf);
           return (buf[0]);
}
 
/*
 * Main 
 */
main(int argc, char *argv[]) 
{
       int          n_byte;             /* returned from pread/pwrite */
       int          size, offset, pat;
       int          fd0, h, i;
       int          fd, prom_id; 
       uflash_if_t  uflash_if;
       caddr_t      r_buf, w_buf;
       char         *devname0 = "/dev/uflash0";
       char         c;
 
       r_buf = (caddr_t)malloc(PROM_SIZE);
       w_buf = (caddr_t)malloc(PROM_SIZE);
 
       /*
        * Open the user flash PROM.
       */
       if ((fd0 = open(devname0, O_RDWR)) < 0) {
           fprintf(stderr, "couldn't open device: %s\n", devname0);
           exit(1);
       }
 
       /* set the default PROM */
       prom_id = 0;
       fd = fd0;
 
       /* let them know about the help menu */
        fprintf(stderr, "Enter <h> or <?> for help on commands\n");
 
       while (1) {
           fprintf(stderr, "[%d]command> ", prom_id);
 
           switch(get_cmd()) {
           case 'q':
              goto getout;
 
           case 'h':
           case '?':
              h = 0;
              while (*help[h]){
                  fprintf(stderr, "   %s\n", help[h]);
                  h++;
              }
              break;
 
           case '9':       /* erase the whole flash PROM */
              fprintf(stderr,
                            "Are you sure?[y/n]");
                             scanf ("%c", &c);
 
              if (c != 'y')
                  continue;
              if (ioctl(fd, UIOCEFUL, &uflash_if) == -1)
                                 goto getout;
              break;
 
          case '8':       /* erase all unlocked flash PROM blocks */
              /*
               * This ioctl is valid only for those
               * chips that have query command.
               */
               if (ioctl(fd, UIOCEALL, &uflash_if) == -1)
                            goto getout;
              break;
 
           case '7':       /* erase flash PROM block */
              fprintf(stderr,
                                "Enter PROM block number[0, 31]> ");
                        scanf ("%d", &uflash_if.blk_num);
 
              fprintf(stderr, 
                  "Enter number of block> ");
              scanf ("%d", &uflash_if.num_of_blks);
 
              if (ioctl(fd, UIOCEBLK, &uflash_if) == -1)
                                goto getout;
              break;
 
           case '6':       /* clear all locks */
              /* on certain PROMs */
              if (ioctl(fd, UIOCCLCK, &uflash_if) == -1)
                                goto getout;
              break;
 
           case '5':       /* master lock */
              /* on certain PROMs */
              if (ioctl(fd, UIOCMLCK, &uflash_if) == -1)
                                goto getout;
              break;
 
           case '4':       /* lock flash PROM block */
              /* on certain PROMs */
              fprintf(stderr,
                                "Enter PROM block number[0, 31]> ");
                        scanf ("%d", &uflash_if.blk_num);
 
              fprintf(stderr, 
                  "Enter number of block> ");
              scanf ("%d", &uflash_if.num_of_blks);
 
              if (ioctl(fd, UIOCLBLK, &uflash_if) == -1)
                                goto getout;
              break;
 
           case '3':       /* query flash PROM */
              /* on certain PROMs */
              fprintf(stderr,
                                "Enter PROM block number[0, 31]> ");
                        scanf ("%d", &uflash_if.blk_num);
 
              fprintf(stderr, 
                  "Enter number of block> ");
              scanf ("%d", &uflash_if.num_of_blks);
 
              if (ioctl(fd, UIOCQBLK, &uflash_if) == -1)
                                goto getout;
              for (i = uflash_if.blk_num; 
                  i < (uflash_if.blk_num+uflash_if.num_of_blks); 
                  i++) 
              {
                  fprintf(stderr, "block[%d] status = %x\n", 
                     i, uflash_if.info.blk_status[i] & 0xF);
              }
              break;
 
           case '2':       /* identify flash PROM */
              if (ioctl(fd, UIOCIBLK, &uflash_if) == -1)
                                goto getout;
              fprintf(stderr, "manufacturer id = 0x%x, device id =\
                         0x%x\n# of blks = %d, blk size = 0x%x\n",
                      uflash_if.info.mfr_id & 0xFF,
                      uflash_if.info.dev_id & 0xFF,
                      uflash_if.info.blk_num,
                      uflash_if.info.blk_size);
              break;
 
           case '1':       /* write to user flash PROM */
              fprintf(stderr,
                                "Enter PROM offset[0, 0xXX,XXXX]> ");
                        scanf ("%x", &offset);
 
              fprintf(stderr, 
                  "Enter number of bytes[hex]> ");
              scanf ("%x", &size);
 
              fprintf(stderr,
                                "Enter data pattern[0, 0xFF]> ");
 
                        scanf ("%x", &pat);
 
              /*
               * init write buffer.
               */
              for (i = 0; i < size; i++) {
                  w_buf[i] = pat;
              }
 
              n_byte = pwrite (fd, w_buf, size, offset);
              if (n_byte != size) {
                  /* the write failed */
                  printf ("Write process was failed at byte 0x%x \n",
                      n_byte);
              }
              break;
 
           case '0':   /* read from user flash PROM */
              fprintf(stderr,
                                "Enter PROM offset[0, 0xXX,XXXX]> ");
                        scanf ("%x", &offset);
 
              fprintf(stderr, 
                  "Enter number of bytes[hex]> ");
              scanf ("%x", &size);
 
              getchar();   /* clean up the char buf */
 
              n_byte = pread (fd, r_buf, size, offset);
              if (n_byte != size) {
                                /* the read failed */
                                printf ("Read process was failed at \
                             byte 0x%x \n",
                                        n_byte);
                  continue;
                        }
 
              printf ("\nuser data buffer:\n");
              for (i = 0; i < size; i++) {
                  printf("%2x ", r_buf[i] & 0xff);
              }
           printf("\n");
 
           default:
              continue;
           }
       }
 
       /* exit */
getout:
       close(fd0);
       return;
 
} /* end of main() */