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 CP2500 is equipped with user flash memory. This chapter includes the following sections:


User Flash Usage and Implementation

You can use the flash memory for various purposes, such as storage for RTOS, user data storage, and OpenBoot PROM information. The Netra CP2500 has a 16Mbyte flash that is logically divided into two parts: 2Mbytes for the system/boot flash and 14Mbytes for the user flash.

The main OpenBoot PROM image and a backup copy of the image are stored in the system flash. If the OpenBoot PROM is corrupted, you can boot the OpenBoot PROM from the backup copy to get a good OpenBoot PROM image back into the system flash. On a Netra CP2500, the SW3301 dip switch on the board itself can be changed to allow you to boot from the backup copy. Refer to the Netra CP2500 Installation and Technical Reference Manual for information on this dip switch.


User Flash Driver

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

On the Netra CP2500, one device is supported. There is one logical device file for the physical device that can be accessed from applications. Users can use this device 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.

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.

OpenBoot PROM Device Tree and Properties

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

The user flash OpenBoot PROM device node is /pci@1e,600000/isa@7/flashprom@2,0.

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


TABLE 3-1 User Flash Node Properties

Property

Description/Value

sunw,location

U38

system-banks

00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 03

flash-banks

00 00 00 00 00 00 00 1f

write-window

00 08 00 00 00 08 00 00

boot-banks

00 00 00 00 00 00 00 02 00 00 00 04 00 00 00 06

boot-window

00 00 00 00 00 08 00 00

bank-size

00080000

model

SUNW,370-xxxx

version

version number

name

flashprom

compatible

isa-flashprom

reg

00000002 00000000 00100000


User Flash Device Files

The user flash device file is /dev/uflash0.

Interface (Header) File

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

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


Application Programming Interface

Access to the user flash device from the Solaris OS 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 might 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.

EBUSY

A write operation is already in progress when more than one write requests are made.



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();
} 

Block Erase Example Program

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


CODE EXAMPLE 3-5 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-6 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,
 *         -) erase block
 *        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 -- clear    all locks",
       "6 -- erase    blocks",
       "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 '6':       /* erase flash PROM block */
              fprintf(stderr,
                                "Enter PROM block number[0, 56]> ");
                        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 '5':       /* clear all locks */
              if (ioctl(fd, UIOCCLCK, &uflash_if) == -1)
                                goto getout;
              break;
 
           case '4':       /* lock flash PROM block */
              /* on certain PROMs */
              fprintf(stderr,
                                "Enter PROM block number[0, 56]> ");
                        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, 56]> ");
                        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] & 0x1);
              }
              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() */