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
6 * Copyright (C) 1999-2002 Silicon Graphics, Inc. All rights reserved.
10 * WARNING: There is more than one copy of this file in different isms.
11 * All copies must be kept exactly in sync.
12 * Do not modify this file without also updating the following:
14 * irix/kern/io/eeprom.c
15 * stand/arcs/lib/libsk/ml/eeprom.c
16 * stand/arcs/lib/libkl/io/eeprom.c
18 * (from time to time they might not be in sync but that's due to bringup
19 * activity - this comment is to remind us that they eventually have to
24 * access to board-mounted EEPROMs via the L1 system controllers
28 #include <linux/types.h>
29 #include <linux/config.h>
30 #include <linux/slab.h>
31 #include <asm/sn/sgi.h>
32 #include <asm/sn/io.h>
33 #include <asm/sn/iograph.h>
34 #include <asm/sn/invent.h>
35 #include <asm/sn/hcl.h>
36 #include <asm/sn/hcl_util.h>
37 #include <asm/sn/labelcl.h>
38 #include <asm/sn/eeprom.h>
39 #include <asm/sn/router.h>
40 #include <asm/sn/module.h>
41 #include <asm/sn/ksys/l1.h>
42 #include <asm/sn/nodepda.h>
43 #include <asm/sn/clksupport.h>
44 #include <asm/sn/sn_cpuid.h>
45 #include <asm/sn/simulator.h>
47 #if defined(EEPROM_DEBUG)
48 #define db_printf(x) printk x
50 #define db_printf(x) printk x
53 #define BCOPY(x,y,z) memcpy(y,x,z)
55 #define UNDERSCORE 0 /* don't convert underscores to hyphens */
56 #define HYPHEN 1 /* convert underscores to hyphens */
58 void copy_ascii_field( char *to, char *from, int length,
59 int change_underscore );
60 uint64_t generate_unique_id( char *sn, int sn_len );
61 uchar_t char_to_base36( char c );
62 int nicify( char *dst, eeprom_brd_record_t *src );
63 static void int64_to_hex_string( char *out, uint64_t val );
65 // extern int router_lock( net_vec_t, int, int );
66 // extern int router_unlock( net_vec_t );
67 #define ROUTER_LOCK(p) // router_lock(p, 10000, 3000000)
68 #define ROUTER_UNLOCK(p) // router_unlock(p)
70 #define IP27LOG_OVNIC "OverrideNIC"
73 /* the following function converts an EEPROM record to a close facsimile
74 * of the string returned by reading a Dallas Semiconductor NIC (see
75 * one of the many incarnations of nic.c for details on that driver)
77 int nicify( char *dst, eeprom_brd_record_t *src )
82 eeprom_board_ia_t *board;
84 board = src->board_ia;
85 ASSERT( board ); /* there should always be a board info area */
87 /* copy part number */
88 strcpy( cur_dst, "Part:" );
89 cur_dst += strlen( cur_dst );
90 ASSERT( (board->part_num_tl & FIELD_FORMAT_MASK)
91 == FIELD_FORMAT_ASCII );
92 field_len = board->part_num_tl & FIELD_LENGTH_MASK;
93 copy_ascii_field( cur_dst, board->part_num, field_len, HYPHEN );
96 /* copy product name */
97 strcpy( cur_dst, ";Name:" );
98 cur_dst += strlen( cur_dst );
99 ASSERT( (board->product_tl & FIELD_FORMAT_MASK) == FIELD_FORMAT_ASCII );
100 field_len = board->product_tl & FIELD_LENGTH_MASK;
101 copy_ascii_field( cur_dst, board->product, field_len, UNDERSCORE );
102 cur_dst += field_len;
104 /* copy serial number */
105 strcpy( cur_dst, ";Serial:" );
106 cur_dst += strlen( cur_dst );
107 ASSERT( (board->serial_num_tl & FIELD_FORMAT_MASK)
108 == FIELD_FORMAT_ASCII );
109 field_len = board->serial_num_tl & FIELD_LENGTH_MASK;
110 copy_ascii_field( cur_dst, board->serial_num, field_len,
113 cur_dst += field_len;
116 strcpy( cur_dst, ";Revision:");
117 cur_dst += strlen( cur_dst );
118 ASSERT( (board->board_rev_tl & FIELD_FORMAT_MASK)
119 == FIELD_FORMAT_ASCII );
120 field_len = board->board_rev_tl & FIELD_LENGTH_MASK;
121 copy_ascii_field( cur_dst, board->board_rev, field_len, HYPHEN );
122 cur_dst += field_len;
124 /* EEPROMs don't have equivalents for the Group, Capability and
125 * Variety fields, so we pad these with 0's
127 strcpy( cur_dst, ";Group:ff;Capability:ffffffff;Variety:ff" );
128 cur_dst += strlen( cur_dst );
130 /* use the board serial number to "fake" a laser id */
131 strcpy( cur_dst, ";Laser:" );
132 cur_dst += strlen( cur_dst );
133 unique_id = generate_unique_id( board->serial_num,
134 board->serial_num_tl & FIELD_LENGTH_MASK );
135 int64_to_hex_string( cur_dst, unique_id );
142 /* These functions borrow heavily from chars2* in nic.c
144 void copy_ascii_field( char *to, char *from, int length,
145 int change_underscore )
148 for( i = 0; i < length; i++ ) {
150 /* change underscores to hyphens if requested */
151 if( from[i] == '_' && change_underscore == HYPHEN )
154 /* ; and ; are separators, so mustn't appear within
156 else if( from[i] == ':' || from[i] == ';' )
159 /* I'm not sure why or if ASCII character 0xff would
160 * show up in an EEPROM field, but the NIC parsing
161 * routines wouldn't like it if it did... so we
162 * get rid of it, just in case. */
163 else if( (unsigned char)from[i] == (unsigned char)0xff )
166 /* unprintable characters are replaced with . */
167 else if( from[i] < ' ' || from[i] >= 0x7f )
170 /* otherwise, just copy the character */
176 to[i] = ' '; /* return at least a space... */
179 to[i] = 0; /* terminating null */
182 /* Note that int64_to_hex_string currently only has a big-endian
186 static void int64_to_hex_string( char *out, uint64_t val )
189 uchar_t table[] = "0123456789abcdef";
190 uchar_t *byte_ptr = (uchar_t *)&val;
191 for( i = 0; i < sizeof(uint64_t); i++ ) {
192 out[i*2] = table[ ((*byte_ptr) >> 4) & 0x0f ];
193 out[i*2+1] = table[ (*byte_ptr) & 0x0f ];
199 #else /* little endian */
201 static void int64_to_hex_string( char *out, uint64_t val )
205 printk("int64_to_hex_string needs a little-endian implementation.\n");
209 /* Convert a standard ASCII serial number to a unique integer
210 * id number by treating the serial number string as though
211 * it were a base 36 number
213 uint64_t generate_unique_id( char *sn, int sn_len )
218 #define VALID_BASE36(c) ((c >= '0' && c <='9') \
219 || (c >= 'A' && c <='Z') \
220 || (c >= 'a' && c <='z'))
222 for( i = 0; i < sn_len; i++ ) {
223 if( !VALID_BASE36(sn[i]) )
226 uid += char_to_base36( sn[i] );
235 uchar_t char_to_base36( char c )
239 if( c >= '0' && c <= '9' )
242 else if( c >= 'A' && c <= 'Z' )
243 val = (c - 'A' + 10);
245 else if( c >= 'a' && c <= 'z' )
246 val = (c - 'a' + 10);
254 /* given a pointer to the three-byte little-endian EEPROM representation
255 * of date-of-manufacture, this function translates to a big-endian
258 int eeprom_xlate_board_mfr_date( uchar_t *src )
262 rval += ((int)(*src) << 8); src ++;
263 rval += ((int)(*src) << 16);
268 int eeprom_str( char *nic_str, nasid_t nasid, int component )
270 eeprom_brd_record_t eep;
271 eeprom_board_ia_t board;
272 eeprom_chassis_ia_t chassis;
275 if( (component & C_DIMM) == C_DIMM ) {
276 /* this function isn't applicable to DIMMs */
280 eep.board_ia = &board;
282 if( !(component & SUBORD_MASK) )
283 eep.chassis_ia = &chassis; /* only main boards have a chassis
286 eep.chassis_ia = NULL;
289 switch( component & BRICK_MASK ) {
291 r = cbrick_eeprom_read( &eep, nasid, component );
294 r = iobrick_eeprom_read( &eep, nasid, component );
297 return EEP_PARAM; /* must be an invalid component */
301 if( !nicify( nic_str, &eep ) )
307 int vector_eeprom_str( char *nic_str, nasid_t nasid,
308 int component, net_vec_t path )
310 eeprom_brd_record_t eep;
311 eeprom_board_ia_t board;
312 eeprom_chassis_ia_t chassis;
315 eep.board_ia = &board;
316 if( !(component & SUBORD_MASK) )
317 eep.chassis_ia = &chassis; /* only main boards have a chassis
320 eep.chassis_ia = NULL;
322 if( !(component & VECTOR) )
325 if( (r = vector_eeprom_read( &eep, nasid, path, component )) )
328 if( !nicify( nic_str, &eep ) )
335 int is_iobrick( int nasid, int widget_num )
338 int part_num, mfg_num;
340 /* Read the widget's WIDGET_ID register to get
341 * its part number and mfg number
343 wid_reg = *(volatile int32_t *)
344 (NODE_SWIN_BASE( nasid, widget_num ) + WIDGET_ID);
346 part_num = (wid_reg & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
347 mfg_num = (wid_reg & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT;
349 /* Is this the "xbow part" of an XBridge? If so, this
350 * widget is definitely part of an I/O brick.
352 if( part_num == XXBOW_WIDGET_PART_NUM &&
353 mfg_num == XXBOW_WIDGET_MFGR_NUM )
357 /* Is this a "bridge part" of an XBridge? If so, once
358 * again, we know this widget is part of an I/O brick.
360 if( part_num == XBRIDGE_WIDGET_PART_NUM &&
361 mfg_num == XBRIDGE_WIDGET_MFGR_NUM )
369 int cbrick_uid_get( nasid_t nasid, uint64_t *uid )
371 #if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
375 char msg[BRL1_QSIZE];
379 int local = (nasid == get_nasid());
381 if ( IS_RUNNING_ON_SIMULATOR() )
384 /* If the promlog variable pointed to by IP27LOG_OVNIC is set,
385 * use that value for the cbrick UID rather than the EEPROM
389 if( ip27log_getenv( nasid, IP27LOG_OVNIC, uid_str, NULL, 0 ) >= 0 )
391 /* We successfully read IP27LOG_OVNIC, so return it as the UID. */
392 db_printf(( "cbrick_uid_get:"
393 "Overriding UID with environment variable %s\n",
395 *uid = strtoull( uid_str, NULL, 0 );
400 /* If this brick is retrieving its own uid, use the local l1sc_t to
401 * arbitrate access to the l1; otherwise, set up a new one.
408 sc_init( &sc, nasid, BRL1_LOCALHUB_UART );
411 /* fill in msg with the opcode & params */
412 BZERO( msg, BRL1_QSIZE );
413 if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 )
416 if( (len = sc_construct_msg( scp, subch, msg, BRL1_QSIZE,
417 L1_ADDR_TASK_GENERAL,
418 L1_REQ_SER_NUM, 0 )) < 0 )
420 sc_close( scp, subch );
424 /* send the request to the L1 */
425 if( sc_command( scp, subch, msg, msg, &len ) ) {
426 sc_close( scp, subch );
430 /* free up subchannel */
431 sc_close(scp, subch);
434 if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 )
439 *uid = generate_unique_id( uid_str, strlen( uid_str ) );
442 #endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */
446 int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid )
448 #if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
452 char msg[BRL1_QSIZE];
456 if ( IS_RUNNING_ON_SIMULATOR() )
462 printk( "rbrick_uid_get failed; using current time as uid\n" ); \
467 sc_init( &sc, nasid, path );
469 /* fill in msg with the opcode & params */
470 BZERO( msg, BRL1_QSIZE );
471 if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) {
476 if( (len = sc_construct_msg( &sc, subch, msg, BRL1_QSIZE,
477 L1_ADDR_TASK_GENERAL,
478 L1_REQ_SER_NUM, 0 )) < 0 )
481 sc_close( &sc, subch );
485 /* send the request to the L1 */
486 if( sc_command( &sc, subch, msg, msg, &len ) ) {
488 sc_close( &sc, subch );
492 /* free up subchannel */
494 sc_close(&sc, subch);
497 if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 )
502 *uid = generate_unique_id( uid_str, strlen( uid_str ) );
505 #endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */
508 int iobrick_uid_get( nasid_t nasid, uint64_t *uid )
510 eeprom_brd_record_t eep;
511 eeprom_board_ia_t board;
512 eeprom_chassis_ia_t chassis;
515 eep.board_ia = &board;
516 eep.chassis_ia = &chassis;
519 r = iobrick_eeprom_read( &eep, nasid, IO_BRICK );
525 *uid = generate_unique_id( board.serial_num,
526 board.serial_num_tl & FIELD_LENGTH_MASK );
532 int ibrick_mac_addr_get( nasid_t nasid, char *eaddr )
534 eeprom_brd_record_t eep;
535 eeprom_board_ia_t board;
536 eeprom_chassis_ia_t chassis;
540 eep.board_ia = &board;
541 eep.chassis_ia = &chassis;
544 r = iobrick_eeprom_read( &eep, nasid, IO_BRICK );
545 if( (r != EEP_OK) || (board.mac_addr[0] == '\0') ) {
546 db_printf(( "ibrick_mac_addr_get: "
547 "Couldn't read MAC address from EEPROM\n" ));
551 /* successfully read info area */
553 tmp = board.mac_addr;
554 for( ix = 0; ix < (board.mac_addr_tl & FIELD_LENGTH_MASK); ix++ )
566 * eeprom_vertex_info_set
568 * Given a vertex handle, a component designation, a starting nasid
569 * and (in the case of a router) a vector path to the component, this
570 * function will read the EEPROM and attach the resulting information
571 * to the vertex in the same string format as that provided by the
572 * Dallas Semiconductor NIC drivers. If the vertex already has the
573 * string, this function just returns the string.
576 extern char *nic_vertex_info_get( devfs_handle_t );
577 extern void nic_vmc_check( devfs_handle_t, char * );
578 /* the following were lifted from nic.c - change later? */
579 #define MAX_INFO 2048
580 #define NEWSZ(ptr,sz) ((ptr) = kern_malloc((sz)))
581 #define DEL(ptr) (kern_free((ptr)))
583 char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v,
590 /* see if this vertex is already marked */
591 info_tmp = nic_vertex_info_get(v);
592 if (info_tmp) return info_tmp;
594 /* get a temporary place for the data */
595 NEWSZ(info_tmp, MAX_INFO);
596 if (!info_tmp) return NULL;
598 /* read the EEPROM */
599 if( component & R_BRICK ) {
600 if( RBRICK_EEPROM_STR( info_tmp, nasid, path ) != EEP_OK )
604 if( eeprom_str( info_tmp, nasid, component ) != EEP_OK )
608 /* allocate a smaller final place */
609 info_len = strlen(info_tmp)+1;
610 NEWSZ(info, info_len);
612 strcpy(info, info_tmp);
618 /* add info to the vertex */
619 hwgraph_info_add_LBL(v, INFO_LBL_NIC,
620 (arbitrary_info_t) info);
622 /* see if someone else got there first */
623 info_tmp = nic_vertex_info_get(v);
624 if (info != info_tmp) {
629 /* export the data */
630 hwgraph_info_export_LBL(v, INFO_LBL_NIC, info_len);
632 /* trigger all matching callbacks */
633 nic_vmc_check(v, info);
639 /*********************************************************************
641 * stubs for use until the Bedrock/L1 link is available
645 #include <asm/sn/nic.h>
647 /* #define EEPROM_TEST */
649 /* fake eeprom reading functions (replace when the BR/L1 communication
650 * channel is in working order)
654 /* generate a charater in [0-9A-Z]; if an "extra" character is
655 * specified (such as '_'), include it as one of the possibilities.
657 char random_eeprom_ch( char extra )
664 ch = rtc_time() % modval;
668 else if( ch >= 10 && ch < 36 )
676 /* create a part number of the form xxx-xxxx-xxx.
677 * It may be important later to generate different
678 * part numbers depending on the component we're
679 * supposed to be "reading" from, so the component
680 * paramter is provided.
682 void fake_a_part_number( char *buf, int component )
685 switch( component ) {
687 /* insert component-specific routines here */
690 strcpy( buf, "030-1266-001" );
693 for( i = 0; i < 12; i++ ) {
694 if( i == 3 || i == 8 )
697 buf[i] = random_eeprom_ch(0);
703 /* create a six-character serial number */
704 void fake_a_serial_number( char *buf, uint64_t ser )
707 static const char hexchars[] = "0123456789ABCDEF";
710 for( i = 5; i >=0; i-- ) {
711 buf[i] = hexchars[ser & 0xf];
716 for( i = 0; i < 6; i++ )
717 buf[i] = random_eeprom_ch(0);
722 void fake_a_product_name( uchar_t *format, char* buf, int component )
724 switch( component & BRICK_MASK ) {
727 if( component & SUBORD_MASK ) {
728 strcpy( buf, "C_BRICK_SUB" );
732 strcpy( buf, "IP35" );
738 if( component & SUBORD_MASK ) {
739 strcpy( buf, "R_BRICK_SUB" );
743 strcpy( buf, "R_BRICK" );
749 if( component & SUBORD_MASK ) {
750 strcpy( buf, "IO_BRICK_SUB" );
754 strcpy( buf, "IO_BRICK" );
760 strcpy( buf, "UNK_DEVICE" );
767 int fake_an_eeprom_record( eeprom_brd_record_t *buf, int component,
770 eeprom_board_ia_t *board;
771 eeprom_chassis_ia_t *chassis;
774 board = buf->board_ia;
775 chassis = buf->chassis_ia;
777 if( !(component & SUBORD_MASK) ) {
782 chassis->type = 0x17;
784 chassis->part_num_tl = 0xCC;
785 fake_a_part_number( chassis->part_num, component );
786 chassis->serial_num_tl = 0xC6;
787 fake_a_serial_number( chassis->serial_num, ser );
789 cs = chassis->format + chassis->length + chassis->type
790 + chassis->part_num_tl + chassis->serial_num_tl;
791 for( i = 0; i < (chassis->part_num_tl & FIELD_LENGTH_MASK); i++ )
792 cs += chassis->part_num[i];
793 for( i = 0; i < (chassis->serial_num_tl & FIELD_LENGTH_MASK); i++ )
794 cs += chassis->serial_num[i];
795 chassis->checksum = 256 - (cs % 256);
803 board->mfg_date = 1789200; /* noon, 5/26/99 */
804 board->manuf_tl = 0xC3;
805 strcpy( board->manuf, "SGI" );
807 fake_a_product_name( &(board->product_tl), board->product, component );
809 board->serial_num_tl = 0xC6;
810 fake_a_serial_number( board->serial_num, ser );
812 board->part_num_tl = 0xCC;
813 fake_a_part_number( board->part_num, component );
815 board->board_rev_tl = 0xC2;
816 board->board_rev[0] = '0';
817 board->board_rev[1] = '1';
819 board->eeprom_size_tl = 0x01;
820 board->eeprom_size = 1;
822 board->temp_waiver_tl = 0xC2;
823 board->temp_waiver[0] = '0';
824 board->temp_waiver[1] = '1';
826 cs = board->format + board->length + board->language
827 + (board->mfg_date & 0xFF)
828 + (board->mfg_date & 0xFF00)
829 + (board->mfg_date & 0xFF0000)
830 + board->manuf_tl + board->product_tl + board->serial_num_tl
831 + board->part_num_tl + board->board_rev_tl
832 + board->board_rev[0] + board->board_rev[1]
833 + board->eeprom_size_tl + board->eeprom_size + board->temp_waiver_tl
834 + board->temp_waiver[0] + board->temp_waiver[1];
835 for( i = 0; i < (board->manuf_tl & FIELD_LENGTH_MASK); i++ )
836 cs += board->manuf[i];
837 for( i = 0; i < (board->product_tl & FIELD_LENGTH_MASK); i++ )
838 cs += board->product[i];
839 for( i = 0; i < (board->serial_num_tl & FIELD_LENGTH_MASK); i++ )
840 cs += board->serial_num[i];
841 for( i = 0; i < (board->part_num_tl & FIELD_LENGTH_MASK); i++ )
842 cs += board->part_num[i];
844 board->checksum = 256 - (cs % 256);
849 #define EEPROM_CHUNKSIZE 64
851 #if defined(EEPROM_DEBUG)
852 #define RETURN_ERROR \
854 printk( "read_ia error return, component 0x%x, line %d" \
855 ", address 0x%x, ia code 0x%x\n", \
856 l1_compt, __LINE__, sc->subch[subch].target, ia_code ); \
861 #define RETURN_ERROR return(EEP_L1)
864 int read_ia( l1sc_t *sc, int subch, int l1_compt,
865 int ia_code, char *eep_record )
867 #if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
870 char msg[BRL1_QSIZE]; /* message buffer */
871 int len; /* number of bytes used in message buffer */
872 int ia_len = EEPROM_CHUNKSIZE; /* remaining bytes in info area */
873 int offset = 0; /* current offset into info area */
875 if ( IS_RUNNING_ON_SIMULATOR() )
878 BZERO( msg, BRL1_QSIZE );
880 /* retrieve EEPROM data in 64-byte chunks
885 /* fill in msg with opcode & params */
886 if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
887 L1_ADDR_TASK_GENERAL,
889 L1_ARG_INT, l1_compt,
892 L1_ARG_INT, ia_len )) < 0 )
897 /* send the request to the L1 */
899 if( sc_command( sc, subch, msg, msg, &len ) ) {
904 if( sc_interpret_resp( msg, 5,
906 L1_ARG_UNKNOWN, &len, eep_record ) < 0 )
911 if( ia_len > EEPROM_CHUNKSIZE )
912 ia_len = EEPROM_CHUNKSIZE;
914 eep_record += EEPROM_CHUNKSIZE;
915 offset += EEPROM_CHUNKSIZE;
919 #endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */
923 int read_spd( l1sc_t *sc, int subch, int l1_compt,
926 #if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
929 char msg[BRL1_QSIZE]; /* message buffer */
930 int len; /* number of bytes used in message buffer */
931 int resp; /* l1 response code */
932 int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */
933 int offset = 0; /* current offset into spd record */
934 char *spd_p = spd->bytes; /* "thumb" for writing to spd */
936 if ( IS_RUNNING_ON_SIMULATOR() )
939 BZERO( msg, BRL1_QSIZE );
941 /* retrieve EEPROM data in 64-byte chunks
946 /* fill in msg with opcode & params */
947 if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
948 L1_ADDR_TASK_GENERAL,
950 L1_ARG_INT, l1_compt,
951 L1_ARG_INT, L1_EEP_SPD,
953 L1_ARG_INT, spd_len )) < 0 )
958 /* send the request to the L1 */
959 if( sc_command( sc, subch, msg, msg, &len ) ) {
964 if( (resp = sc_interpret_resp( msg, 5,
965 L1_ARG_INT, &spd_len,
966 L1_ARG_UNKNOWN, &len, spd_p )) < 0 )
969 * translate l1 response code to eeprom.c error codes:
970 * The L1 response will be L1_RESP_NAVAIL if the spd
971 * can't be read (i.e. the spd isn't physically there). It will
972 * return L1_RESP_INVAL if the spd exists, but fails the checksum
973 * test because the eeprom wasn't programmed, programmed incorrectly,
974 * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present,
975 * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is
978 if(resp == L1_RESP_INVAL) {
979 resp = EEP_BAD_CHECKSUM;
986 if( spd_len > EEPROM_CHUNKSIZE )
987 spd_len = EEPROM_CHUNKSIZE;
989 spd_p += EEPROM_CHUNKSIZE;
990 offset += EEPROM_CHUNKSIZE;
993 #endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */
997 int read_chassis_ia( l1sc_t *sc, int subch, int l1_compt,
998 eeprom_chassis_ia_t *ia )
1000 char eep_record[512]; /* scratch area for building up info area */
1001 char *eep_rec_p = eep_record; /* thumb for moving through eep_record */
1002 int checksum = 0; /* use to verify eeprom record checksum */
1005 /* Read in info area record from the L1.
1007 if( read_ia( sc, subch, l1_compt, L1_EEP_CHASSIS, eep_record )
1013 /* Now we've got the whole info area. Transfer it to the data structure.
1016 eep_rec_p = eep_record;
1017 ia->format = *eep_rec_p++;
1018 ia->length = *eep_rec_p++;
1019 if( ia->length == 0 ) {
1020 /* since we're using 8*ia->length-1 as an array index later, make
1023 db_printf(( "read_chassis_ia: eeprom length byte of ZERO\n" ));
1026 ia->type = *eep_rec_p++;
1028 ia->part_num_tl = *eep_rec_p++;
1030 (void)BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) );
1031 eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK);
1033 ia->serial_num_tl = *eep_rec_p++;
1035 BCOPY( eep_rec_p, ia->serial_num,
1036 (ia->serial_num_tl & FIELD_LENGTH_MASK) );
1037 eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK);
1039 ia->checksum = eep_record[(8 * ia->length) - 1];
1041 /* verify checksum */
1042 eep_rec_p = eep_record;
1044 for( i = 0; i < (8 * ia->length); i++ ) {
1045 checksum += *eep_rec_p++;
1048 if( (checksum & 0xff) != 0 )
1050 db_printf(( "read_chassis_ia: bad checksum\n" ));
1051 db_printf(( "read_chassis_ia: target 0x%x uart 0x%lx\n",
1052 sc->subch[subch].target, sc->uart ));
1053 return EEP_BAD_CHECKSUM;
1060 int read_board_ia( l1sc_t *sc, int subch, int l1_compt,
1061 eeprom_board_ia_t *ia )
1063 char eep_record[512]; /* scratch area for building up info area */
1064 char *eep_rec_p = eep_record; /* thumb for moving through eep_record */
1065 int checksum = 0; /* running checksum total */
1068 BZERO( ia, sizeof( eeprom_board_ia_t ) );
1070 /* Read in info area record from the L1.
1072 if( read_ia( sc, subch, l1_compt, L1_EEP_BOARD, eep_record )
1075 db_printf(( "read_board_ia: error reading info area from L1\n" ));
1079 /* Now we've got the whole info area. Transfer it to the data structure.
1082 eep_rec_p = eep_record;
1083 ia->format = *eep_rec_p++;
1084 ia->length = *eep_rec_p++;
1085 if( ia->length == 0 ) {
1086 /* since we're using 8*ia->length-1 as an array index later, make
1089 db_printf(( "read_board_ia: eeprom length byte of ZERO\n" ));
1092 ia->language = *eep_rec_p++;
1094 ia->mfg_date = eeprom_xlate_board_mfr_date( (uchar_t *)eep_rec_p );
1097 ia->manuf_tl = *eep_rec_p++;
1099 BCOPY( eep_rec_p, ia->manuf, (ia->manuf_tl & FIELD_LENGTH_MASK) );
1100 eep_rec_p += (ia->manuf_tl & FIELD_LENGTH_MASK);
1102 ia->product_tl = *eep_rec_p++;
1104 BCOPY( eep_rec_p, ia->product, (ia->product_tl & FIELD_LENGTH_MASK) );
1105 eep_rec_p += (ia->product_tl & FIELD_LENGTH_MASK);
1107 ia->serial_num_tl = *eep_rec_p++;
1109 BCOPY(eep_rec_p, ia->serial_num, (ia->serial_num_tl & FIELD_LENGTH_MASK));
1110 eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK);
1112 ia->part_num_tl = *eep_rec_p++;
1114 BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) );
1115 eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK);
1117 eep_rec_p++; /* we do not use the FRU file id */
1119 ia->board_rev_tl = *eep_rec_p++;
1121 BCOPY( eep_rec_p, ia->board_rev, (ia->board_rev_tl & FIELD_LENGTH_MASK) );
1122 eep_rec_p += (ia->board_rev_tl & FIELD_LENGTH_MASK);
1124 ia->eeprom_size_tl = *eep_rec_p++;
1125 ia->eeprom_size = *eep_rec_p++;
1127 ia->temp_waiver_tl = *eep_rec_p++;
1129 BCOPY( eep_rec_p, ia->temp_waiver,
1130 (ia->temp_waiver_tl & FIELD_LENGTH_MASK) );
1131 eep_rec_p += (ia->temp_waiver_tl & FIELD_LENGTH_MASK);
1133 /* if there's more, we must be reading a main board; get
1136 if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) {
1138 ia->ekey_G_tl = *eep_rec_p++;
1139 BCOPY( eep_rec_p, (char *)&ia->ekey_G,
1140 ia->ekey_G_tl & FIELD_LENGTH_MASK );
1141 eep_rec_p += (ia->ekey_G_tl & FIELD_LENGTH_MASK);
1143 ia->ekey_P_tl = *eep_rec_p++;
1144 BCOPY( eep_rec_p, (char *)&ia->ekey_P,
1145 ia->ekey_P_tl & FIELD_LENGTH_MASK );
1146 eep_rec_p += (ia->ekey_P_tl & FIELD_LENGTH_MASK);
1148 ia->ekey_Y_tl = *eep_rec_p++;
1149 BCOPY( eep_rec_p, (char *)&ia->ekey_Y,
1150 ia->ekey_Y_tl & FIELD_LENGTH_MASK );
1151 eep_rec_p += (ia->ekey_Y_tl & FIELD_LENGTH_MASK);
1154 * need to get a couple more fields if this is an I brick
1156 if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) {
1158 ia->mac_addr_tl = *eep_rec_p++;
1159 BCOPY( eep_rec_p, ia->mac_addr,
1160 ia->mac_addr_tl & FIELD_LENGTH_MASK );
1161 eep_rec_p += (ia->mac_addr_tl & FIELD_LENGTH_MASK);
1163 ia->ieee1394_cfg_tl = *eep_rec_p++;
1164 BCOPY( eep_rec_p, ia->ieee1394_cfg,
1165 ia->ieee1394_cfg_tl & FIELD_LENGTH_MASK );
1170 ia->checksum = eep_record[(ia->length * 8) - 1];
1172 /* verify checksum */
1173 eep_rec_p = eep_record;
1175 for( i = 0; i < (8 * ia->length); i++ ) {
1176 checksum += *eep_rec_p++;
1179 if( (checksum & 0xff) != 0 )
1181 db_printf(( "read_board_ia: bad checksum\n" ));
1182 db_printf(( "read_board_ia: target 0x%x uart 0x%lx\n",
1183 sc->subch[subch].target, sc->uart ));
1184 return EEP_BAD_CHECKSUM;
1191 int _cbrick_eeprom_read( eeprom_brd_record_t *buf, l1sc_t *scp,
1194 #if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
1202 int l1_compt, subch;
1204 if ( IS_RUNNING_ON_SIMULATOR() )
1207 /* make sure we're targeting a cbrick */
1208 if( !(component & C_BRICK) )
1211 /* If the promlog variable pointed to by IP27LOG_OVNIC is set,
1212 * use that value for the cbrick UID rather than the EEPROM
1216 if( ip27log_getenv( scp->nasid, IP27LOG_OVNIC, uid_str, "0", 0 ) >= 0 )
1218 db_printf(( "_cbrick_eeprom_read: "
1219 "Overriding UID with environment variable %s\n",
1221 uid = strtoull( uid_str, NULL, 0 );
1225 if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 )
1228 if((component & C_DIMM) == C_DIMM) {
1229 l1_compt = L1_EEP_DIMM(component & COMPT_MASK);
1230 r = read_spd(scp,subch,l1_compt, buf->spd);
1231 sc_close(scp,subch);
1238 /* c-brick motherboard */
1239 l1_compt = L1_EEP_NODE;
1240 r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia );
1242 sc_close( scp, subch );
1243 db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" ));
1244 return fake_an_eeprom_record( buf, component, uid );
1247 /* If IP27LOG_OVNIC is set, we want to put that value
1249 fake_a_serial_number( buf->chassis_ia->serial_num, uid );
1250 buf->chassis_ia->serial_num_tl = 6;
1255 /* one of the PIMM boards */
1256 l1_compt = L1_EEP_PIMM( component & COMPT_MASK );
1260 /* unsupported board type */
1261 sc_close( scp, subch );
1265 r = read_board_ia( scp, subch, l1_compt, buf->board_ia );
1266 sc_close( scp, subch );
1269 db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" ));
1270 return fake_an_eeprom_record( buf, component, uid );
1273 #endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */
1277 int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
1280 #if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
1284 int local = (nasid == get_nasid());
1286 if ( IS_RUNNING_ON_SIMULATOR() )
1289 /* If this brick is retrieving its own uid, use the local l1sc_t to
1290 * arbitrate access to the l1; otherwise, set up a new one (prom) or
1291 * use an existing remote l1sc_t (kernel)
1297 scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
1300 return _cbrick_eeprom_read( buf, scp, component );
1301 #endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */
1305 int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
1308 #if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
1312 int l1_compt, subch;
1314 int local = (nasid == get_nasid());
1316 if ( IS_RUNNING_ON_SIMULATOR() )
1319 /* make sure we're talking to an applicable brick */
1320 if( !(component & IO_BRICK) ) {
1324 /* If we're talking to this c-brick's attached io brick, use
1325 * the local l1sc_t; otherwise, set up a new one (prom) or
1326 * use an existing remote l1sc_t (kernel)
1332 scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc;
1335 if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 )
1342 /* IO brick motherboard */
1343 l1_compt = L1_EEP_LOGIC;
1344 r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia );
1347 sc_close( scp, subch );
1349 * Whenever we no longer need to test on hardware
1350 * that does not have EEPROMS, then this can be removed.
1352 r = fake_an_eeprom_record( buf, component, rtc_time() );
1358 /* IO brick power board */
1359 l1_compt = L1_EEP_POWER;
1363 /* unsupported board type */
1364 sc_close( scp, subch );
1368 r = read_board_ia( scp, subch, l1_compt, buf->board_ia );
1369 sc_close( scp, subch );
1374 #endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */
1378 int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid,
1379 net_vec_t path, int component )
1381 #if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL)
1386 int l1_compt, subch;
1389 if ( IS_RUNNING_ON_SIMULATOR() )
1392 /* make sure we're targeting an applicable brick */
1393 if( !(component & VECTOR) )
1396 switch( component & BRICK_MASK )
1399 ROUTER_LOCK( path );
1400 sc_init( &sc, nasid, path );
1402 if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 )
1404 db_printf(( "vector_eeprom_read: couldn't open subch\n" ));
1405 ROUTER_UNLOCK(path);
1411 /* r-brick motherboard */
1412 l1_compt = L1_EEP_LOGIC;
1413 r = read_chassis_ia( &sc, subch, l1_compt, buf->chassis_ia );
1415 sc_close( &sc, subch );
1416 ROUTER_UNLOCK( path );
1417 printk( "vector_eeprom_read: couldn't get rbrick eeprom info;"
1418 " using current time as uid\n" );
1420 db_printf(("vector_eeprom_read: using a fake eeprom record\n"));
1421 return fake_an_eeprom_record( buf, component, uid );
1426 /* r-brick power board */
1427 l1_compt = L1_EEP_POWER;
1431 /* unsupported board type */
1432 sc_close( &sc, subch );
1433 ROUTER_UNLOCK( path );
1436 r = read_board_ia( &sc, subch, l1_compt, buf->board_ia );
1437 sc_close( &sc, subch );
1438 ROUTER_UNLOCK( path );
1440 db_printf(( "vector_eeprom_read: using a fake eeprom record\n" ));
1441 return fake_an_eeprom_record( buf, component, uid );
1446 sc_init( &sc, nasid, path );
1447 return _cbrick_eeprom_read( buf, &sc, component );
1450 /* unsupported brick type */
1453 #endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */