eeprom.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:36k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * This file is subject to the terms and conditions of the GNU General Public
  3.  * License.  See the file "COPYING" in the main directory of this archive
  4.  * for more details.
  5.  *
  6.  * Copyright (C) 1999-2002 Silicon Graphics, Inc. All rights reserved.
  7.  */
  8. /*
  9.  * WARNING:     There is more than one copy of this file in different isms.
  10.  *              All copies must be kept exactly in sync.
  11.  *              Do not modify this file without also updating the following:
  12.  *
  13.  *              irix/kern/io/eeprom.c
  14.  *              stand/arcs/lib/libsk/ml/eeprom.c
  15.  * stand/arcs/lib/libkl/io/eeprom.c
  16.  *
  17.  *      (from time to time they might not be in sync but that's due to bringup
  18.  *       activity - this comment is to remind us that they eventually have to
  19.  *       get back together)
  20.  *
  21.  * eeprom.c
  22.  *
  23.  * access to board-mounted EEPROMs via the L1 system controllers
  24.  *
  25.  */
  26. #include <linux/types.h>
  27. #include <linux/config.h>
  28. #include <linux/slab.h>
  29. #include <asm/sn/sgi.h>
  30. #include <asm/sn/io.h>
  31. #include <asm/sn/iograph.h>
  32. #include <asm/sn/invent.h>
  33. #include <asm/sn/hcl.h>
  34. #include <asm/sn/hcl_util.h>
  35. #include <asm/sn/labelcl.h>
  36. #include <asm/sn/eeprom.h>
  37. #include <asm/sn/router.h>
  38. #include <asm/sn/module.h>
  39. #include <asm/sn/ksys/l1.h>
  40. #include <asm/sn/nodepda.h>
  41. #include <asm/sn/clksupport.h>
  42. #include <asm/sn/sn_cpuid.h>
  43. #include <asm/sn/simulator.h>
  44. #if defined(EEPROM_DEBUG)
  45. #define db_printf(x) printk x
  46. #else
  47. #define db_printf(x) printk x
  48. #endif
  49. #define BCOPY(x,y,z) memcpy(y,x,z)
  50. #define UNDERSCORE 0 /* don't convert underscores to hyphens */
  51. #define HYPHEN 1 /* convert underscores to hyphens */
  52. void copy_ascii_field( char *to, char *from, int length,
  53.           int change_underscore );
  54. uint64_t generate_unique_id( char *sn, int sn_len );
  55. uchar_t char_to_base36( char c );
  56. int nicify( char *dst, eeprom_brd_record_t *src );
  57. static void int64_to_hex_string( char *out, uint64_t val );
  58. // extern int router_lock( net_vec_t, int, int );
  59. // extern int router_unlock( net_vec_t );
  60. #define ROUTER_LOCK(p)  // router_lock(p, 10000, 3000000)
  61. #define ROUTER_UNLOCK(p)  // router_unlock(p)
  62. #define IP27LOG_OVNIC           "OverrideNIC"
  63. /* the following function converts an EEPROM record to a close facsimile
  64.  * of the string returned by reading a Dallas Semiconductor NIC (see
  65.  * one of the many incarnations of nic.c for details on that driver)
  66.  */
  67. int nicify( char *dst, eeprom_brd_record_t *src )
  68. {
  69.     int field_len;
  70.     uint64_t unique_id;
  71.     char *cur_dst = dst;
  72.     eeprom_board_ia_t   *board;
  73.     board   = src->board_ia;
  74.     ASSERT( board );  /* there should always be a board info area */
  75.     /* copy part number */
  76.     strcpy( cur_dst, "Part:" );
  77.     cur_dst += strlen( cur_dst );
  78.     ASSERT( (board->part_num_tl & FIELD_FORMAT_MASK)
  79.     == FIELD_FORMAT_ASCII );
  80.     field_len = board->part_num_tl & FIELD_LENGTH_MASK;
  81.     copy_ascii_field( cur_dst, board->part_num, field_len, HYPHEN );
  82.     cur_dst += field_len;
  83.     /* copy product name */
  84.     strcpy( cur_dst, ";Name:" );
  85.     cur_dst += strlen( cur_dst );
  86.     ASSERT( (board->product_tl & FIELD_FORMAT_MASK) == FIELD_FORMAT_ASCII );
  87.     field_len = board->product_tl & FIELD_LENGTH_MASK;
  88.     copy_ascii_field( cur_dst, board->product, field_len, UNDERSCORE );
  89.     cur_dst += field_len;
  90.     /* copy serial number */
  91.     strcpy( cur_dst, ";Serial:" );
  92.     cur_dst += strlen( cur_dst );
  93.     ASSERT( (board->serial_num_tl & FIELD_FORMAT_MASK)
  94.     == FIELD_FORMAT_ASCII );
  95.     field_len = board->serial_num_tl & FIELD_LENGTH_MASK;
  96.     copy_ascii_field( cur_dst, board->serial_num, field_len,
  97.       HYPHEN);
  98.     cur_dst += field_len;
  99.     /* copy revision */
  100.     strcpy( cur_dst, ";Revision:");
  101.     cur_dst += strlen( cur_dst );
  102.     ASSERT( (board->board_rev_tl & FIELD_FORMAT_MASK)
  103.     == FIELD_FORMAT_ASCII );
  104.     field_len = board->board_rev_tl & FIELD_LENGTH_MASK;
  105.     copy_ascii_field( cur_dst, board->board_rev, field_len, HYPHEN );
  106.     cur_dst += field_len;
  107.     /* EEPROMs don't have equivalents for the Group, Capability and
  108.      * Variety fields, so we pad these with 0's
  109.      */
  110.     strcpy( cur_dst, ";Group:ff;Capability:ffffffff;Variety:ff" );
  111.     cur_dst += strlen( cur_dst );
  112.     /* use the board serial number to "fake" a laser id */
  113.     strcpy( cur_dst, ";Laser:" );
  114.     cur_dst += strlen( cur_dst );
  115.     unique_id = generate_unique_id( board->serial_num,
  116.     board->serial_num_tl & FIELD_LENGTH_MASK );
  117.     int64_to_hex_string( cur_dst, unique_id );
  118.     strcat( dst, ";" );
  119.     return 1;
  120. }
  121. /* These functions borrow heavily from chars2* in nic.c
  122.  */
  123. void copy_ascii_field( char *to, char *from, int length,
  124.        int change_underscore )
  125. {
  126.     int i;
  127.     for( i = 0; i < length; i++ ) {
  128. /* change underscores to hyphens if requested */
  129. if( from[i] == '_' && change_underscore == HYPHEN )
  130.     to[i] = '-';
  131. /* ; and ; are separators, so mustn't appear within
  132.  * a field */
  133. else if( from[i] == ':' || from[i] == ';' )
  134.     to[i] = '?';
  135. /* I'm not sure why or if ASCII character 0xff would
  136.  * show up in an EEPROM field, but the NIC parsing
  137.  * routines wouldn't like it if it did... so we
  138.  * get rid of it, just in case. */
  139. else if( (unsigned char)from[i] == (unsigned char)0xff )
  140.     to[i] = ' ';
  141. /* unprintable characters are replaced with . */
  142. else if( from[i] < ' ' || from[i] >= 0x7f )
  143.     to[i] = '.';
  144. /* otherwise, just copy the character */
  145. else
  146.     to[i] = from[i];
  147.     }
  148.     if( i == 0 ) {
  149. to[i] = ' '; /* return at least a space... */
  150. i++;
  151.     }
  152.     to[i] = 0;      /* terminating null */
  153. }
  154. /* Note that int64_to_hex_string currently only has a big-endian
  155.  * implementation.
  156.  */
  157. #ifdef _MIPSEB
  158. static void int64_to_hex_string( char *out, uint64_t val )
  159. {
  160.     int i;
  161.     uchar_t table[] = "0123456789abcdef";
  162.     uchar_t *byte_ptr = (uchar_t *)&val;
  163.     for( i = 0; i < sizeof(uint64_t); i++ ) {
  164. out[i*2] = table[ ((*byte_ptr) >> 4) & 0x0f ];
  165. out[i*2+1] = table[ (*byte_ptr) & 0x0f ];
  166. byte_ptr++;
  167.     }
  168.     out[i*2] = '';
  169. }
  170. #else /* little endian */
  171. static void int64_to_hex_string( char *out, uint64_t val )
  172. {
  173. printk("int64_to_hex_string needs a little-endian implementation.n");
  174. }
  175. #endif /* _MIPSEB */
  176. /* Convert a standard ASCII serial number to a unique integer
  177.  * id number by treating the serial number string as though
  178.  * it were a base 36 number
  179.  */
  180. uint64_t generate_unique_id( char *sn, int sn_len )
  181. {
  182.     int uid = 0;
  183.     int i;
  184.     #define VALID_BASE36(c) ((c >= '0' && c <='9') 
  185.     ||   (c >= 'A' && c <='Z') 
  186.     ||   (c >= 'a' && c <='z'))
  187.     for( i = 0; i < sn_len; i++ ) {
  188. if( !VALID_BASE36(sn[i]) )
  189.     continue;
  190. uid *= 36;
  191. uid += char_to_base36( sn[i] );
  192.     }
  193.     if( uid == 0 )
  194. return rtc_time();
  195.     return uid;
  196. }
  197. uchar_t char_to_base36( char c )
  198. {
  199.     uchar_t val;
  200.     if( c >= '0' && c <= '9' )
  201. val = (c - '0');
  202.     else if( c >= 'A' && c <= 'Z' )
  203. val = (c - 'A' + 10);
  204.     else if( c >= 'a' && c <= 'z' )
  205. val = (c - 'a' + 10);
  206.     else val = 0;
  207.     return val;
  208. }
  209. /* given a pointer to the three-byte little-endian EEPROM representation
  210.  * of date-of-manufacture, this function translates to a big-endian
  211.  * integer format
  212.  */
  213. int eeprom_xlate_board_mfr_date( uchar_t *src )
  214. {
  215.     int rval = 0;
  216.     rval += *src; src++;
  217.     rval += ((int)(*src) << 8); src ++;
  218.     rval += ((int)(*src) << 16);
  219.     return rval;
  220. }
  221. int eeprom_str( char *nic_str, nasid_t nasid, int component )
  222. {
  223.     eeprom_brd_record_t eep;
  224.     eeprom_board_ia_t board;
  225.     eeprom_chassis_ia_t chassis;
  226.     int r;
  227.     if( (component & C_DIMM) == C_DIMM ) {
  228. /* this function isn't applicable to DIMMs */
  229. return EEP_PARAM;
  230.     }
  231.     else {
  232. eep.board_ia = &board;
  233. eep.spd = NULL;
  234. if( !(component & SUBORD_MASK) )
  235.     eep.chassis_ia = &chassis;  /* only main boards have a chassis
  236.  * info area */
  237. else
  238.     eep.chassis_ia = NULL;
  239.     }
  240.     
  241.     switch( component & BRICK_MASK ) {
  242.       case C_BRICK:
  243. r = cbrick_eeprom_read( &eep, nasid, component );
  244. break;
  245.       case IO_BRICK:
  246. r = iobrick_eeprom_read( &eep, nasid, component );
  247. break;
  248.       default:
  249. return EEP_PARAM;  /* must be an invalid component */
  250.     }
  251.     if( r )
  252. return r;
  253.     if( !nicify( nic_str, &eep ) )
  254. return EEP_NICIFY;
  255.     return EEP_OK;
  256. }
  257. int vector_eeprom_str( char *nic_str, nasid_t nasid,
  258.        int component, net_vec_t path )
  259. {
  260.     eeprom_brd_record_t eep;
  261.     eeprom_board_ia_t board;
  262.     eeprom_chassis_ia_t chassis;
  263.     int r;
  264.     eep.board_ia = &board;
  265.     if( !(component & SUBORD_MASK) )
  266.         eep.chassis_ia = &chassis;  /* only main boards have a chassis
  267.                                      * info area */
  268.     else
  269.         eep.chassis_ia = NULL;
  270.     if( !(component & VECTOR) )
  271. return EEP_PARAM;
  272.     if( (r = vector_eeprom_read( &eep, nasid, path, component )) )
  273. return r;
  274.     if( !nicify( nic_str, &eep ) )
  275.         return EEP_NICIFY;
  276.     return EEP_OK;
  277. }
  278. int is_iobrick( int nasid, int widget_num )
  279. {
  280.     uint32_t wid_reg;
  281.     int part_num, mfg_num;
  282.     /* Read the widget's WIDGET_ID register to get
  283.      * its part number and mfg number
  284.      */
  285.     wid_reg = *(volatile int32_t *)
  286.         (NODE_SWIN_BASE( nasid, widget_num ) + WIDGET_ID);
  287.     part_num = (wid_reg & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
  288.     mfg_num = (wid_reg & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT;
  289.     /* Is this the "xbow part" of an XBridge?  If so, this
  290.      * widget is definitely part of an I/O brick.
  291.      */
  292.     if( part_num == XXBOW_WIDGET_PART_NUM &&
  293. mfg_num == XXBOW_WIDGET_MFGR_NUM )
  294. return 1;
  295.     /* Is this a "bridge part" of an XBridge?  If so, once
  296.      * again, we know this widget is part of an I/O brick.
  297.      */
  298.     if( part_num == XBRIDGE_WIDGET_PART_NUM &&
  299. mfg_num == XBRIDGE_WIDGET_MFGR_NUM )
  300. return 1;
  301.     return 0;
  302. }
  303. int cbrick_uid_get( nasid_t nasid, uint64_t *uid )
  304. {
  305.     char uid_str[32];
  306.     char msg[BRL1_QSIZE];
  307.     int subch, len;
  308.     l1sc_t sc;
  309.     l1sc_t *scp;
  310.     int local = (nasid == get_nasid());
  311.     if ( IS_RUNNING_ON_SIMULATOR() )
  312. return EEP_L1;
  313.     /* If the promlog variable pointed to by IP27LOG_OVNIC is set,
  314.      * use that value for the cbrick UID rather than the EEPROM
  315.      * serial number.
  316.      */
  317. #ifdef LOG_GETENV
  318.     if( ip27log_getenv( nasid, IP27LOG_OVNIC, uid_str, NULL, 0 ) >= 0 )
  319.     {
  320. /* We successfully read IP27LOG_OVNIC, so return it as the UID. */
  321. db_printf(( "cbrick_uid_get:"
  322.     "Overriding UID with environment variable %sn", 
  323.     IP27LOG_OVNIC ));
  324. *uid = strtoull( uid_str, NULL, 0 );
  325. return EEP_OK;
  326.     }
  327. #endif
  328.     /* If this brick is retrieving its own uid, use the local l1sc_t to
  329.      * arbitrate access to the l1; otherwise, set up a new one.
  330.      */
  331.     if( local ) {
  332. scp = get_l1sc();
  333.     }
  334.     else {
  335. scp = &sc;
  336. sc_init( &sc, nasid, BRL1_LOCALHUB_UART );
  337.     }
  338.     /* fill in msg with the opcode & params */
  339.     BZERO( msg, BRL1_QSIZE );
  340.     if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 )
  341. return EEP_L1;
  342.     if( (len = sc_construct_msg( scp, subch, msg, BRL1_QSIZE,
  343.  L1_ADDR_TASK_GENERAL,
  344.  L1_REQ_SER_NUM, 0 )) < 0 )
  345.     {
  346. sc_close( scp, subch );
  347. return( EEP_L1 );
  348.     }
  349.     /* send the request to the L1 */
  350.     if( sc_command( scp, subch, msg, msg, &len ) ) {
  351. sc_close( scp, subch );
  352. return( EEP_L1 );
  353.     }
  354.     /* free up subchannel */
  355.     sc_close(scp, subch);
  356.     /* check response */
  357.     if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 )
  358.     {
  359. return( EEP_L1 );
  360.     }
  361.     *uid = generate_unique_id( uid_str, strlen( uid_str ) );
  362.     return EEP_OK;
  363. }
  364. int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid )
  365. {
  366.     char uid_str[32];
  367.     char msg[BRL1_QSIZE];
  368.     int subch, len;
  369.     l1sc_t sc;
  370.     if ( IS_RUNNING_ON_SIMULATOR() )
  371. return EEP_L1;
  372. #define FAIL
  373.     {
  374. *uid = rtc_time();
  375. printk( "rbrick_uid_get failed; using current time as uidn" );
  376. return EEP_OK;
  377.     }
  378.     ROUTER_LOCK(path);
  379.     sc_init( &sc, nasid, path );
  380.     /* fill in msg with the opcode & params */
  381.     BZERO( msg, BRL1_QSIZE );
  382.     if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) {
  383. ROUTER_UNLOCK(path);
  384. FAIL;
  385.     }
  386.     if( (len = sc_construct_msg( &sc, subch, msg, BRL1_QSIZE,
  387.  L1_ADDR_TASK_GENERAL,
  388.  L1_REQ_SER_NUM, 0 )) < 0 )
  389.     {
  390. ROUTER_UNLOCK(path);
  391. sc_close( &sc, subch );
  392. FAIL;
  393.     }
  394.     /* send the request to the L1 */
  395.     if( sc_command( &sc, subch, msg, msg, &len ) ) {
  396. ROUTER_UNLOCK(path);
  397. sc_close( &sc, subch );
  398. FAIL;
  399.     }
  400.     /* free up subchannel */
  401.     ROUTER_UNLOCK(path);
  402.     sc_close(&sc, subch);
  403.     /* check response */
  404.     if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 )
  405.     {
  406. FAIL;
  407.     }
  408.     *uid = generate_unique_id( uid_str, strlen( uid_str ) );
  409.     return EEP_OK;
  410. }
  411. int iobrick_uid_get( nasid_t nasid, uint64_t *uid )
  412. {
  413.     eeprom_brd_record_t eep;
  414.     eeprom_board_ia_t board;
  415.     eeprom_chassis_ia_t chassis;
  416.     int r;
  417.     eep.board_ia = &board;
  418.     eep.chassis_ia = &chassis;
  419.     eep.spd = NULL;
  420.     r = iobrick_eeprom_read( &eep, nasid, IO_BRICK );
  421.     if( r != EEP_OK ) {
  422.         *uid = rtc_time();
  423.         return r;
  424.     }
  425.     *uid = generate_unique_id( board.serial_num,
  426.                                board.serial_num_tl & FIELD_LENGTH_MASK );
  427.     return EEP_OK;
  428. }
  429. int ibrick_mac_addr_get( nasid_t nasid, char *eaddr )
  430. {
  431.     eeprom_brd_record_t eep;
  432.     eeprom_board_ia_t board;
  433.     eeprom_chassis_ia_t chassis;
  434.     int r;
  435.     char *tmp;
  436.     eep.board_ia = &board;
  437.     eep.chassis_ia = &chassis;
  438.     eep.spd = NULL;
  439.     r = iobrick_eeprom_read( &eep, nasid, IO_BRICK );
  440.     if( (r != EEP_OK) || (board.mac_addr[0] == '') ) {
  441. db_printf(( "ibrick_mac_addr_get: "
  442.     "Couldn't read MAC address from EEPROMn" ));
  443. return EEP_L1;
  444.     }
  445.     else {
  446. /* successfully read info area */
  447. int ix;
  448. tmp = board.mac_addr;
  449. for( ix = 0; ix < (board.mac_addr_tl & FIELD_LENGTH_MASK); ix++ )
  450. {
  451.     *eaddr++ = *tmp++;
  452. }
  453. *eaddr = '';
  454.     }
  455.     return EEP_OK;
  456. }
  457. /* 
  458.  * eeprom_vertex_info_set
  459.  *
  460.  * Given a vertex handle, a component designation, a starting nasid
  461.  * and (in the case of a router) a vector path to the component, this
  462.  * function will read the EEPROM and attach the resulting information
  463.  * to the vertex in the same string format as that provided by the
  464.  * Dallas Semiconductor NIC drivers.  If the vertex already has the
  465.  * string, this function just returns the string.
  466.  */
  467. extern char *nic_vertex_info_get( devfs_handle_t );
  468. extern void nic_vmc_check( devfs_handle_t, char * );
  469. /* the following were lifted from nic.c - change later? */
  470. #define MAX_INFO 2048
  471. #define NEWSZ(ptr,sz)   ((ptr) = kern_malloc((sz)))
  472. #define DEL(ptr) (kern_free((ptr)))
  473. char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v,
  474.                               net_vec_t path )
  475. {
  476.         char *info_tmp;
  477.         int info_len;
  478.         char *info;
  479.         /* see if this vertex is already marked */
  480.         info_tmp = nic_vertex_info_get(v);
  481.         if (info_tmp) return info_tmp;
  482.         /* get a temporary place for the data */
  483.         NEWSZ(info_tmp, MAX_INFO);
  484.         if (!info_tmp) return NULL;
  485.         /* read the EEPROM */
  486. if( component & R_BRICK ) {
  487.     if( RBRICK_EEPROM_STR( info_tmp, nasid, path ) != EEP_OK )
  488. return NULL;
  489. }
  490. else {
  491.             if( eeprom_str( info_tmp, nasid, component ) != EEP_OK )
  492.         return NULL;
  493. }
  494.         /* allocate a smaller final place */
  495.         info_len = strlen(info_tmp)+1;
  496.         NEWSZ(info, info_len);
  497.         if (info) {
  498.                 strcpy(info, info_tmp);
  499.                 DEL(info_tmp);
  500.         } else {
  501.                 info = info_tmp;
  502.         }
  503.         /* add info to the vertex */
  504.         hwgraph_info_add_LBL(v, INFO_LBL_NIC,
  505.                              (arbitrary_info_t) info);
  506.         /* see if someone else got there first */
  507.         info_tmp = nic_vertex_info_get(v);
  508.         if (info != info_tmp) {
  509.             DEL(info);
  510.             return info_tmp;
  511.         }
  512.         /* export the data */
  513.         hwgraph_info_export_LBL(v, INFO_LBL_NIC, info_len);
  514.         /* trigger all matching callbacks */
  515.         nic_vmc_check(v, info);
  516.         return info;
  517. }
  518. /*********************************************************************
  519.  *
  520.  * stubs for use until the Bedrock/L1 link is available
  521.  *
  522.  */
  523. #include <asm/sn/nic.h>
  524. /* #define EEPROM_TEST */
  525. /* fake eeprom reading functions (replace when the BR/L1 communication
  526.  * channel is in working order)
  527.  */
  528. /* generate a charater in [0-9A-Z]; if an "extra" character is
  529.  * specified (such as '_'), include it as one of the possibilities.
  530.  */
  531. char random_eeprom_ch( char extra ) 
  532. {
  533.     char ch;
  534.     int modval = 36;
  535.     if( extra )
  536. modval++;
  537.     
  538.     ch = rtc_time() % modval;
  539.     if( ch < 10 )
  540.         ch += '0';
  541.     else if( ch >= 10 && ch < 36 )
  542. ch += ('A' - 10);
  543.     else
  544. ch = extra;
  545.     return ch;
  546. }
  547. /* create a part number of the form xxx-xxxx-xxx.
  548.  * It may be important later to generate different
  549.  * part numbers depending on the component we're
  550.  * supposed to be "reading" from, so the component
  551.  * paramter is provided.
  552.  */
  553. void fake_a_part_number( char *buf, int component )
  554. {
  555.     int i;
  556.     switch( component ) {
  557.     /* insert component-specific routines here */
  558.     case C_BRICK:
  559. strcpy( buf, "030-1266-001" );
  560. break;
  561.     default:
  562.         for( i = 0; i < 12; i++ ) {
  563.     if( i == 3 || i == 8 )
  564.         buf[i] = '-';
  565.     else
  566.         buf[i] = random_eeprom_ch(0);
  567.         }
  568.     }
  569. }
  570. /* create a six-character serial number */
  571. void fake_a_serial_number( char *buf, uint64_t ser )
  572. {
  573.     int i;
  574.     static const char hexchars[] = "0123456789ABCDEF";
  575.     if (ser) {
  576. for( i = 5; i >=0; i-- ) {
  577.     buf[i] = hexchars[ser & 0xf];
  578.     ser >>= 4;
  579. }
  580.     }
  581.     else {
  582. for( i = 0; i < 6; i++ )
  583.     buf[i] = random_eeprom_ch(0);
  584.     }
  585. }
  586. void fake_a_product_name( uchar_t *format, char* buf, int component )
  587. {
  588.     switch( component & BRICK_MASK ) {
  589.     case C_BRICK:
  590. if( component & SUBORD_MASK ) {
  591.     strcpy( buf, "C_BRICK_SUB" );
  592.     *format = 0xCB;
  593. }
  594. else {
  595.     strcpy( buf, "IP35" );
  596.     *format = 0xC4;
  597. }
  598. break;
  599.     case R_BRICK:
  600.         if( component & SUBORD_MASK ) {
  601.             strcpy( buf, "R_BRICK_SUB" );
  602.             *format = 0xCB;
  603.         }
  604.         else {
  605.             strcpy( buf, "R_BRICK" );
  606.             *format = 0xC7;
  607.         }
  608.         break;
  609.     case IO_BRICK:
  610.         if( component & SUBORD_MASK ) {
  611.             strcpy( buf, "IO_BRICK_SUB" );
  612.             *format = 0xCC;
  613.         }
  614.         else {
  615.             strcpy( buf, "IO_BRICK" );
  616.             *format = 0xC8;
  617.         }
  618.         break;
  619.     default:
  620. strcpy( buf, "UNK_DEVICE" );
  621. *format = 0xCA;
  622.     }
  623. }
  624. int fake_an_eeprom_record( eeprom_brd_record_t *buf, int component, 
  625.    uint64_t ser )
  626. {
  627.     eeprom_board_ia_t *board;
  628.     eeprom_chassis_ia_t *chassis;
  629.     int i, cs;
  630.     board = buf->board_ia;
  631.     chassis = buf->chassis_ia;
  632.     if( !(component & SUBORD_MASK) ) {
  633. if( !chassis )
  634.     return EEP_PARAM;
  635. chassis->format = 0;
  636. chassis->length = 5;
  637. chassis->type = 0x17;
  638. chassis->part_num_tl = 0xCC;
  639. fake_a_part_number( chassis->part_num, component );
  640. chassis->serial_num_tl = 0xC6;
  641. fake_a_serial_number( chassis->serial_num, ser );
  642. cs = chassis->format + chassis->length + chassis->type
  643.     + chassis->part_num_tl + chassis->serial_num_tl;
  644. for( i = 0; i < (chassis->part_num_tl & FIELD_LENGTH_MASK); i++ )
  645.     cs += chassis->part_num[i];
  646. for( i = 0; i < (chassis->serial_num_tl & FIELD_LENGTH_MASK); i++ )
  647.     cs += chassis->serial_num[i];
  648. chassis->checksum = 256 - (cs % 256);
  649.     }
  650.     if( !board )
  651. return EEP_PARAM;
  652.     board->format = 0;
  653.     board->length = 10;
  654.     board->language = 0;
  655.     board->mfg_date = 1789200; /* noon, 5/26/99 */
  656.     board->manuf_tl = 0xC3;
  657.     strcpy( board->manuf, "SGI" );
  658.     fake_a_product_name( &(board->product_tl), board->product, component );
  659.     board->serial_num_tl = 0xC6;
  660.     fake_a_serial_number( board->serial_num, ser );
  661.     board->part_num_tl = 0xCC;
  662.     fake_a_part_number( board->part_num, component );
  663.     board->board_rev_tl = 0xC2;
  664.     board->board_rev[0] = '0';
  665.     board->board_rev[1] = '1';
  666.     board->eeprom_size_tl = 0x01;
  667.     board->eeprom_size = 1;
  668.     board->temp_waiver_tl = 0xC2;
  669.     board->temp_waiver[0] = '0';
  670.     board->temp_waiver[1] = '1';
  671.     cs = board->format + board->length + board->language
  672. + (board->mfg_date & 0xFF)
  673. + (board->mfg_date & 0xFF00)
  674. + (board->mfg_date & 0xFF0000)
  675. + board->manuf_tl + board->product_tl + board->serial_num_tl
  676. + board->part_num_tl + board->board_rev_tl
  677. + board->board_rev[0] + board->board_rev[1]
  678. + board->eeprom_size_tl + board->eeprom_size + board->temp_waiver_tl
  679. + board->temp_waiver[0] + board->temp_waiver[1];
  680.     for( i = 0; i < (board->manuf_tl & FIELD_LENGTH_MASK); i++ )
  681. cs += board->manuf[i];
  682.     for( i = 0; i < (board->product_tl & FIELD_LENGTH_MASK); i++ )
  683. cs += board->product[i];
  684.     for( i = 0; i < (board->serial_num_tl & FIELD_LENGTH_MASK); i++ )
  685. cs += board->serial_num[i];
  686.     for( i = 0; i < (board->part_num_tl & FIELD_LENGTH_MASK); i++ )
  687. cs += board->part_num[i];
  688.     
  689.     board->checksum = 256 - (cs % 256);
  690.     return EEP_OK;
  691. }
  692. #define EEPROM_CHUNKSIZE 64
  693. #if defined(EEPROM_DEBUG)
  694. #define RETURN_ERROR
  695. {
  696.     printk( "read_ia error return, component 0x%x, line %d"
  697.     ", address 0x%x, ia code 0x%xn",
  698.     l1_compt, __LINE__, sc->subch[subch].target, ia_code );
  699.     return EEP_L1;
  700. }
  701. #else
  702. #define RETURN_ERROR return(EEP_L1)
  703. #endif
  704. int read_ia( l1sc_t *sc, int subch, int l1_compt, 
  705.      int ia_code, char *eep_record )
  706. {
  707.     char msg[BRL1_QSIZE];     /* message buffer */
  708.     int len;                  /* number of bytes used in message buffer */
  709.     int ia_len = EEPROM_CHUNKSIZE; /* remaining bytes in info area */
  710.     int offset = 0;                /* current offset into info area */
  711.     if ( IS_RUNNING_ON_SIMULATOR() )
  712. return EEP_L1;
  713.     BZERO( msg, BRL1_QSIZE );
  714.     /* retrieve EEPROM data in 64-byte chunks
  715.      */
  716.     while( ia_len )
  717.     {
  718. /* fill in msg with opcode & params */
  719. if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
  720.      L1_ADDR_TASK_GENERAL,
  721.      L1_REQ_EEPROM, 8,
  722.      L1_ARG_INT, l1_compt,
  723.      L1_ARG_INT, ia_code,
  724.      L1_ARG_INT, offset,
  725.      L1_ARG_INT, ia_len )) < 0 )
  726. {
  727.     RETURN_ERROR;
  728. }
  729. /* send the request to the L1 */
  730. if( sc_command( sc, subch, msg, msg, &len ) ) {
  731.     RETURN_ERROR;
  732. }
  733. /* check response */
  734. if( sc_interpret_resp( msg, 5, 
  735.        L1_ARG_INT, &ia_len,
  736.        L1_ARG_UNKNOWN, &len, eep_record ) < 0 )
  737. {
  738.     RETURN_ERROR;
  739. }
  740. if( ia_len > EEPROM_CHUNKSIZE )
  741.     ia_len = EEPROM_CHUNKSIZE;
  742. eep_record += EEPROM_CHUNKSIZE;
  743. offset += EEPROM_CHUNKSIZE;
  744.     }
  745.     return EEP_OK;
  746. }
  747. int read_spd( l1sc_t *sc, int subch, int l1_compt,
  748.       eeprom_spd_u *spd )
  749. {
  750.     char msg[BRL1_QSIZE];      /* message buffer */
  751.     int len;                   /* number of bytes used in message buffer */
  752.     int resp;                       /* l1 response code */
  753.     int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */
  754.     int offset = 0;     /* current offset into spd record */
  755.     char *spd_p = spd->bytes;     /* "thumb" for writing to spd */
  756.     if ( IS_RUNNING_ON_SIMULATOR() )
  757. return EEP_L1;
  758.     BZERO( msg, BRL1_QSIZE );
  759.     /* retrieve EEPROM data in 64-byte chunks
  760.      */
  761.     while( spd_len )
  762.     {
  763. /* fill in msg with opcode & params */
  764. if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
  765.      L1_ADDR_TASK_GENERAL,
  766.      L1_REQ_EEPROM, 8,
  767.      L1_ARG_INT, l1_compt,
  768.      L1_ARG_INT, L1_EEP_SPD,
  769.      L1_ARG_INT, offset,
  770.      L1_ARG_INT, spd_len )) < 0 )
  771. {
  772.     return( EEP_L1 );
  773. }
  774. /* send the request to the L1 */
  775. if( sc_command( sc, subch, msg, msg, &len ) ) {
  776.     return( EEP_L1 );
  777. }
  778. /* check response */
  779. if( (resp = sc_interpret_resp( msg, 5, 
  780.        L1_ARG_INT, &spd_len,
  781.        L1_ARG_UNKNOWN, &len, spd_p )) < 0 )
  782. {
  783.             /*
  784.              * translate l1 response code to eeprom.c error codes:
  785.              * The L1 response will be L1_RESP_NAVAIL if the spd
  786.              * can't be read (i.e. the spd isn't physically there). It will
  787.              * return L1_RESP_INVAL if the spd exists, but fails the checksum
  788.              * test because the eeprom wasn't programmed, programmed incorrectly,
  789.              * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present,
  790.              * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is
  791.              * invalid.
  792.              */
  793.             if(resp == L1_RESP_INVAL) {
  794.                 resp = EEP_BAD_CHECKSUM;
  795.             } else {
  796.                 resp = EEP_L1;
  797.             }
  798.             return( resp );
  799. }
  800. if( spd_len > EEPROM_CHUNKSIZE )
  801.     spd_len = EEPROM_CHUNKSIZE;
  802. spd_p += EEPROM_CHUNKSIZE;
  803. offset += EEPROM_CHUNKSIZE;
  804.     }
  805.     return EEP_OK;
  806. }
  807. int read_chassis_ia( l1sc_t *sc, int subch, int l1_compt,
  808.      eeprom_chassis_ia_t *ia )
  809. {
  810.     char eep_record[512];          /* scratch area for building up info area */
  811.     char *eep_rec_p = eep_record;  /* thumb for moving through eep_record */
  812.     int checksum = 0;              /* use to verify eeprom record checksum */
  813.     int i;
  814.     /* Read in info area record from the L1.
  815.      */
  816.     if( read_ia( sc, subch, l1_compt, L1_EEP_CHASSIS, eep_record )
  817. != EEP_OK )
  818.     {
  819. return EEP_L1;
  820.     }
  821.     /* Now we've got the whole info area.  Transfer it to the data structure.
  822.      */
  823.     eep_rec_p = eep_record;
  824.     ia->format = *eep_rec_p++;
  825.     ia->length = *eep_rec_p++;
  826.     if( ia->length == 0 ) {
  827. /* since we're using 8*ia->length-1 as an array index later, make
  828.  * sure it's sane.
  829.  */
  830. db_printf(( "read_chassis_ia: eeprom length byte of ZEROn" ));
  831. return EEP_L1;
  832.     }
  833.     ia->type = *eep_rec_p++;
  834.    
  835.     ia->part_num_tl = *eep_rec_p++;
  836.     (void)BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) );
  837.     eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK);
  838.     ia->serial_num_tl = *eep_rec_p++;
  839.     BCOPY( eep_rec_p, ia->serial_num, 
  840.    (ia->serial_num_tl & FIELD_LENGTH_MASK) );
  841.     eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK);
  842.     ia->checksum = eep_record[(8 * ia->length) - 1];
  843.     /* verify checksum */
  844.     eep_rec_p = eep_record;
  845.     checksum = 0;
  846.     for( i = 0; i < (8 * ia->length); i++ ) {
  847. checksum += *eep_rec_p++;
  848.     }
  849.     if( (checksum & 0xff) != 0 )
  850.     {
  851. db_printf(( "read_chassis_ia: bad checksumn" ));
  852. db_printf(( "read_chassis_ia: target 0x%x  uart 0x%lxn",
  853.    sc->subch[subch].target, sc->uart ));
  854. return EEP_BAD_CHECKSUM;
  855.     }
  856.     return EEP_OK;
  857. }
  858. int read_board_ia( l1sc_t *sc, int subch, int l1_compt,
  859.    eeprom_board_ia_t *ia )
  860. {
  861.     char eep_record[512];          /* scratch area for building up info area */
  862.     char *eep_rec_p = eep_record;  /* thumb for moving through eep_record */
  863.     int checksum = 0;              /* running checksum total */
  864.     int i;
  865.     BZERO( ia, sizeof( eeprom_board_ia_t ) );
  866.     /* Read in info area record from the L1.
  867.      */
  868.     if( read_ia( sc, subch, l1_compt, L1_EEP_BOARD, eep_record )
  869. != EEP_OK )
  870.     {
  871. db_printf(( "read_board_ia: error reading info area from L1n" ));
  872. return EEP_L1;
  873.     }
  874.      /* Now we've got the whole info area.  Transfer it to the data structure.
  875.       */
  876.     eep_rec_p = eep_record;
  877.     ia->format = *eep_rec_p++;
  878.     ia->length = *eep_rec_p++;
  879.     if( ia->length == 0 ) {
  880. /* since we're using 8*ia->length-1 as an array index later, make
  881.  * sure it's sane.
  882.  */
  883. db_printf(( "read_board_ia: eeprom length byte of ZEROn" ));
  884. return EEP_L1;
  885.     }
  886.     ia->language = *eep_rec_p++;
  887.     
  888.     ia->mfg_date = eeprom_xlate_board_mfr_date( (uchar_t *)eep_rec_p );
  889.     eep_rec_p += 3;
  890.     ia->manuf_tl = *eep_rec_p++;
  891.     
  892.     BCOPY( eep_rec_p, ia->manuf, (ia->manuf_tl & FIELD_LENGTH_MASK) );
  893.     eep_rec_p += (ia->manuf_tl & FIELD_LENGTH_MASK);
  894.     ia->product_tl = *eep_rec_p++;
  895.     
  896.     BCOPY( eep_rec_p, ia->product, (ia->product_tl & FIELD_LENGTH_MASK) );
  897.     eep_rec_p += (ia->product_tl & FIELD_LENGTH_MASK);
  898.     ia->serial_num_tl = *eep_rec_p++;
  899.     
  900.     BCOPY(eep_rec_p, ia->serial_num, (ia->serial_num_tl & FIELD_LENGTH_MASK));
  901.     eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK);
  902.     ia->part_num_tl = *eep_rec_p++;
  903.     BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) );
  904.     eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK);
  905.     eep_rec_p++; /* we do not use the FRU file id */
  906.     
  907.     ia->board_rev_tl = *eep_rec_p++;
  908.     
  909.     BCOPY( eep_rec_p, ia->board_rev, (ia->board_rev_tl & FIELD_LENGTH_MASK) );
  910.     eep_rec_p += (ia->board_rev_tl & FIELD_LENGTH_MASK);
  911.     ia->eeprom_size_tl = *eep_rec_p++;
  912.     ia->eeprom_size = *eep_rec_p++;
  913.     ia->temp_waiver_tl = *eep_rec_p++;
  914.     
  915.     BCOPY( eep_rec_p, ia->temp_waiver, 
  916.    (ia->temp_waiver_tl & FIELD_LENGTH_MASK) );
  917.     eep_rec_p += (ia->temp_waiver_tl & FIELD_LENGTH_MASK);
  918.     /* if there's more, we must be reading a main board; get
  919.      * additional fields
  920.      */
  921.     if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) {
  922. ia->ekey_G_tl = *eep_rec_p++;
  923. BCOPY( eep_rec_p, (char *)&ia->ekey_G, 
  924.        ia->ekey_G_tl & FIELD_LENGTH_MASK );
  925. eep_rec_p += (ia->ekey_G_tl & FIELD_LENGTH_MASK);
  926. ia->ekey_P_tl = *eep_rec_p++;
  927. BCOPY( eep_rec_p, (char *)&ia->ekey_P, 
  928.        ia->ekey_P_tl & FIELD_LENGTH_MASK );
  929. eep_rec_p += (ia->ekey_P_tl & FIELD_LENGTH_MASK);
  930. ia->ekey_Y_tl = *eep_rec_p++;
  931. BCOPY( eep_rec_p, (char *)&ia->ekey_Y, 
  932.        ia->ekey_Y_tl & FIELD_LENGTH_MASK );
  933. eep_rec_p += (ia->ekey_Y_tl & FIELD_LENGTH_MASK);
  934. /* 
  935.  * need to get a couple more fields if this is an I brick 
  936.  */
  937. if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) {
  938.     ia->mac_addr_tl = *eep_rec_p++;
  939.     BCOPY( eep_rec_p, ia->mac_addr, 
  940.    ia->mac_addr_tl & FIELD_LENGTH_MASK );
  941.     eep_rec_p += (ia->mac_addr_tl & FIELD_LENGTH_MASK);
  942.     
  943.     ia->ieee1394_cfg_tl = *eep_rec_p++;
  944.     BCOPY( eep_rec_p, ia->ieee1394_cfg,
  945.    ia->ieee1394_cfg_tl & FIELD_LENGTH_MASK );
  946.     
  947. }
  948.     }
  949.     ia->checksum = eep_record[(ia->length * 8) - 1];
  950.     /* verify checksum */
  951.     eep_rec_p = eep_record;
  952.     checksum = 0;
  953.     for( i = 0; i < (8 * ia->length); i++ ) {
  954. checksum += *eep_rec_p++;
  955.     }
  956.     if( (checksum & 0xff) != 0 )
  957.     {
  958. db_printf(( "read_board_ia: bad checksumn" ));
  959. db_printf(( "read_board_ia: target 0x%x  uart 0x%lxn",
  960.     sc->subch[subch].target, sc->uart ));
  961. return EEP_BAD_CHECKSUM;
  962.     }
  963.     return EEP_OK;
  964. }
  965. int _cbrick_eeprom_read( eeprom_brd_record_t *buf, l1sc_t *scp,
  966.  int component )
  967. {
  968.     int r;
  969.     uint64_t uid = 0;
  970. #ifdef LOG_GETENV
  971.     char uid_str[32];
  972. #endif
  973.     int l1_compt, subch;
  974.     if ( IS_RUNNING_ON_SIMULATOR() )
  975. return EEP_L1;
  976.     /* make sure we're targeting a cbrick */
  977.     if( !(component & C_BRICK) )
  978. return EEP_PARAM;
  979.     /* If the promlog variable pointed to by IP27LOG_OVNIC is set,
  980.      * use that value for the cbrick UID rather than the EEPROM
  981.      * serial number.
  982.      */
  983. #ifdef LOG_GETENV
  984.     if( ip27log_getenv( scp->nasid, IP27LOG_OVNIC, uid_str, "0", 0 ) >= 0 )
  985.     {
  986. db_printf(( "_cbrick_eeprom_read: "
  987.     "Overriding UID with environment variable %sn", 
  988.     IP27LOG_OVNIC ));
  989. uid = strtoull( uid_str, NULL, 0 );
  990.     }
  991. #endif
  992.     if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 )
  993. return EEP_L1;
  994.     if((component & C_DIMM) == C_DIMM) {
  995.         l1_compt = L1_EEP_DIMM(component & COMPT_MASK);
  996.         r = read_spd(scp,subch,l1_compt, buf->spd);
  997.         sc_close(scp,subch);
  998.         return(r);
  999.     }
  1000.     switch( component )
  1001.     {
  1002.       case C_BRICK:
  1003. /* c-brick motherboard */
  1004. l1_compt = L1_EEP_NODE;
  1005. r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia );
  1006. if( r != EEP_OK ) {
  1007.     sc_close( scp, subch );
  1008.     db_printf(( "_cbrick_eeprom_read: using a fake eeprom recordn" ));
  1009.     return fake_an_eeprom_record( buf, component, uid );
  1010. }
  1011. if( uid ) {
  1012.     /* If IP27LOG_OVNIC is set, we want to put that value
  1013.      * in as our UID. */
  1014.     fake_a_serial_number( buf->chassis_ia->serial_num, uid );
  1015.     buf->chassis_ia->serial_num_tl = 6;
  1016. }
  1017. break;
  1018.       case C_PIMM:
  1019. /* one of the PIMM boards */
  1020. l1_compt = L1_EEP_PIMM( component & COMPT_MASK );
  1021. break;
  1022.       default:
  1023. /* unsupported board type */
  1024. sc_close( scp, subch );
  1025. return EEP_PARAM;
  1026.     }
  1027.       
  1028.     r = read_board_ia( scp, subch, l1_compt, buf->board_ia );
  1029.     sc_close( scp, subch );
  1030.     if( r != EEP_OK ) 
  1031.     {
  1032. db_printf(( "_cbrick_eeprom_read: using a fake eeprom recordn" ));
  1033. return fake_an_eeprom_record( buf, component, uid );
  1034.     }
  1035.     return EEP_OK;
  1036. }
  1037. int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
  1038.              int component )
  1039. {
  1040.     l1sc_t *scp;
  1041.     int local = (nasid == get_nasid());
  1042.     if ( IS_RUNNING_ON_SIMULATOR() )
  1043. return EEP_L1;
  1044.     /* If this brick is retrieving its own uid, use the local l1sc_t to
  1045.      * arbitrate access to the l1; otherwise, set up a new one (prom) or
  1046.      * use an existing remote l1sc_t (kernel)
  1047.      */
  1048.     if( local ) {
  1049. scp = get_l1sc();
  1050.     }
  1051.     else {
  1052. scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
  1053.     }
  1054.     return _cbrick_eeprom_read( buf, scp, component );
  1055. }
  1056. int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
  1057.  int component )
  1058. {
  1059.     int r;
  1060.     int l1_compt, subch;
  1061.     l1sc_t *scp;
  1062.     int local = (nasid == get_nasid());
  1063.     if ( IS_RUNNING_ON_SIMULATOR() )
  1064. return EEP_L1;
  1065.     /* make sure we're talking to an applicable brick */
  1066.     if( !(component & IO_BRICK) ) {
  1067. return EEP_PARAM;
  1068.     }
  1069.     /* If we're talking to this c-brick's attached io brick, use
  1070.      * the local l1sc_t; otherwise, set up a new one (prom) or
  1071.      * use an existing remote l1sc_t (kernel)
  1072.      */
  1073.     if( local ) {
  1074. scp = get_l1sc();
  1075.     }
  1076.     else {
  1077. scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
  1078.     }
  1079.     if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 )
  1080. return EEP_L1;
  1081.     switch( component )
  1082.     {
  1083.       case IO_BRICK:
  1084. /* IO brick motherboard */
  1085. l1_compt = L1_EEP_LOGIC;
  1086. r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia );
  1087. if( r != EEP_OK ) {
  1088.     sc_close( scp, subch );
  1089. /*
  1090.  * Whenever we no longer need to test on hardware
  1091.  * that does not have EEPROMS, then this can be removed.
  1092.  */
  1093.     r = fake_an_eeprom_record( buf, component, rtc_time() );
  1094.     return r;
  1095. }
  1096. break;
  1097.       case IO_POWER:
  1098. /* IO brick power board */
  1099. l1_compt = L1_EEP_POWER;
  1100. break;
  1101.       default:
  1102. /* unsupported board type */
  1103. sc_close( scp, subch );
  1104. return EEP_PARAM;
  1105.     }
  1106.     r = read_board_ia( scp, subch, l1_compt, buf->board_ia );
  1107.     sc_close( scp, subch );
  1108.     if( r != EEP_OK ) {
  1109. return r;
  1110.     }
  1111.     return EEP_OK;
  1112. }
  1113. int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
  1114. net_vec_t path, int component )
  1115. {
  1116.     int r;
  1117.     uint64_t uid = 0;
  1118.     int l1_compt, subch;
  1119.     l1sc_t sc;
  1120.     if ( IS_RUNNING_ON_SIMULATOR() )
  1121. return EEP_L1;
  1122.     /* make sure we're targeting an applicable brick */
  1123.     if( !(component & VECTOR) )
  1124. return EEP_PARAM;
  1125.     switch( component & BRICK_MASK )
  1126.     {
  1127.       case R_BRICK:
  1128. ROUTER_LOCK( path );
  1129. sc_init( &sc, nasid, path );
  1130. if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 )
  1131. {
  1132.     db_printf(( "vector_eeprom_read: couldn't open subchn" ));
  1133.     ROUTER_UNLOCK(path);
  1134.     return EEP_L1;
  1135. }
  1136. switch( component )
  1137. {
  1138.   case R_BRICK:
  1139.     /* r-brick motherboard */
  1140.     l1_compt = L1_EEP_LOGIC;
  1141.          r = read_chassis_ia( &sc, subch, l1_compt, buf->chassis_ia );
  1142.     if( r != EEP_OK ) {
  1143. sc_close( &sc, subch );
  1144. ROUTER_UNLOCK( path );
  1145. printk( "vector_eeprom_read: couldn't get rbrick eeprom info;"
  1146. " using current time as uidn" );
  1147. uid = rtc_time();
  1148. db_printf(("vector_eeprom_read: using a fake eeprom recordn"));
  1149. return fake_an_eeprom_record( buf, component, uid );
  1150.     }
  1151.     break;
  1152.   case R_POWER:
  1153.     /* r-brick power board */
  1154.     l1_compt = L1_EEP_POWER;
  1155.     break;
  1156.   default:
  1157.     /* unsupported board type */
  1158.     sc_close( &sc, subch );
  1159.     ROUTER_UNLOCK( path );
  1160.     return EEP_PARAM;
  1161. }
  1162. r = read_board_ia( &sc, subch, l1_compt, buf->board_ia );
  1163. sc_close( &sc, subch );
  1164. ROUTER_UNLOCK( path );
  1165. if( r != EEP_OK ) {
  1166.     db_printf(( "vector_eeprom_read: using a fake eeprom recordn" ));
  1167.     return fake_an_eeprom_record( buf, component, uid );
  1168. }
  1169. return EEP_OK;
  1170.       case C_BRICK:
  1171. sc_init( &sc, nasid, path );
  1172. return _cbrick_eeprom_read( buf, &sc, component );
  1173.       default:
  1174. /* unsupported brick type */
  1175. return EEP_PARAM;
  1176.     }
  1177. }