diff options
Diffstat (limited to 'arch/ia64/sn/io/eeprom.c')
-rw-r--r-- | arch/ia64/sn/io/eeprom.c | 1454 |
1 files changed, 0 insertions, 1454 deletions
diff --git a/arch/ia64/sn/io/eeprom.c b/arch/ia64/sn/io/eeprom.c deleted file mode 100644 index 5b190517de6f9f..00000000000000 --- a/arch/ia64/sn/io/eeprom.c +++ /dev/null @@ -1,1454 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1999-2002 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * WARNING: There is more than one copy of this file in different isms. - * All copies must be kept exactly in sync. - * Do not modify this file without also updating the following: - * - * irix/kern/io/eeprom.c - * stand/arcs/lib/libsk/ml/eeprom.c - * stand/arcs/lib/libkl/io/eeprom.c - * - * (from time to time they might not be in sync but that's due to bringup - * activity - this comment is to remind us that they eventually have to - * get back together) - * - * eeprom.c - * - * access to board-mounted EEPROMs via the L1 system controllers - * - */ - -#include <linux/types.h> -#include <linux/config.h> -#include <linux/slab.h> -#include <asm/sn/sgi.h> -#include <asm/sn/io.h> -#include <asm/sn/iograph.h> -#include <asm/sn/invent.h> -#include <asm/sn/hcl.h> -#include <asm/sn/hcl_util.h> -#include <asm/sn/labelcl.h> -#include <asm/sn/eeprom.h> -#include <asm/sn/router.h> -#include <asm/sn/module.h> -#include <asm/sn/ksys/l1.h> -#include <asm/sn/nodepda.h> -#include <asm/sn/clksupport.h> -#include <asm/sn/sn_cpuid.h> -#include <asm/sn/simulator.h> - -#if defined(EEPROM_DEBUG) -#define db_printf(x) printk x -#else -#define db_printf(x) printk x -#endif - -#define BCOPY(x,y,z) memcpy(y,x,z) - -#define UNDERSCORE 0 /* don't convert underscores to hyphens */ -#define HYPHEN 1 /* convert underscores to hyphens */ - -void copy_ascii_field( char *to, char *from, int length, - int change_underscore ); -uint64_t generate_unique_id( char *sn, int sn_len ); -uchar_t char_to_base36( char c ); -int nicify( char *dst, eeprom_brd_record_t *src ); -static void int64_to_hex_string( char *out, uint64_t val ); - -// extern int router_lock( net_vec_t, int, int ); -// extern int router_unlock( net_vec_t ); -#define ROUTER_LOCK(p) // router_lock(p, 10000, 3000000) -#define ROUTER_UNLOCK(p) // router_unlock(p) - -#define IP27LOG_OVNIC "OverrideNIC" - - -/* the following function converts an EEPROM record to a close facsimile - * of the string returned by reading a Dallas Semiconductor NIC (see - * one of the many incarnations of nic.c for details on that driver) - */ -int nicify( char *dst, eeprom_brd_record_t *src ) -{ - int field_len; - uint64_t unique_id; - char *cur_dst = dst; - eeprom_board_ia_t *board; - - board = src->board_ia; - ASSERT( board ); /* there should always be a board info area */ - - /* copy part number */ - strcpy( cur_dst, "Part:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->part_num_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->part_num_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->part_num, field_len, HYPHEN ); - cur_dst += field_len; - - /* copy product name */ - strcpy( cur_dst, ";Name:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->product_tl & FIELD_FORMAT_MASK) == FIELD_FORMAT_ASCII ); - field_len = board->product_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->product, field_len, UNDERSCORE ); - cur_dst += field_len; - - /* copy serial number */ - strcpy( cur_dst, ";Serial:" ); - cur_dst += strlen( cur_dst ); - ASSERT( (board->serial_num_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->serial_num_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->serial_num, field_len, - HYPHEN); - - cur_dst += field_len; - - /* copy revision */ - strcpy( cur_dst, ";Revision:"); - cur_dst += strlen( cur_dst ); - ASSERT( (board->board_rev_tl & FIELD_FORMAT_MASK) - == FIELD_FORMAT_ASCII ); - field_len = board->board_rev_tl & FIELD_LENGTH_MASK; - copy_ascii_field( cur_dst, board->board_rev, field_len, HYPHEN ); - cur_dst += field_len; - - /* EEPROMs don't have equivalents for the Group, Capability and - * Variety fields, so we pad these with 0's - */ - strcpy( cur_dst, ";Group:ff;Capability:ffffffff;Variety:ff" ); - cur_dst += strlen( cur_dst ); - - /* use the board serial number to "fake" a laser id */ - strcpy( cur_dst, ";Laser:" ); - cur_dst += strlen( cur_dst ); - unique_id = generate_unique_id( board->serial_num, - board->serial_num_tl & FIELD_LENGTH_MASK ); - int64_to_hex_string( cur_dst, unique_id ); - strcat( dst, ";" ); - - return 1; -} - - -/* These functions borrow heavily from chars2* in nic.c - */ -void copy_ascii_field( char *to, char *from, int length, - int change_underscore ) -{ - int i; - for( i = 0; i < length; i++ ) { - - /* change underscores to hyphens if requested */ - if( from[i] == '_' && change_underscore == HYPHEN ) - to[i] = '-'; - - /* ; and ; are separators, so mustn't appear within - * a field */ - else if( from[i] == ':' || from[i] == ';' ) - to[i] = '?'; - - /* I'm not sure why or if ASCII character 0xff would - * show up in an EEPROM field, but the NIC parsing - * routines wouldn't like it if it did... so we - * get rid of it, just in case. */ - else if( (unsigned char)from[i] == (unsigned char)0xff ) - to[i] = ' '; - - /* unprintable characters are replaced with . */ - else if( from[i] < ' ' || from[i] >= 0x7f ) - to[i] = '.'; - - /* otherwise, just copy the character */ - else - to[i] = from[i]; - } - - if( i == 0 ) { - to[i] = ' '; /* return at least a space... */ - i++; - } - to[i] = 0; /* terminating null */ -} - -/* Note that int64_to_hex_string currently only has a big-endian - * implementation. - */ -#ifdef _MIPSEB -static void int64_to_hex_string( char *out, uint64_t val ) -{ - int i; - uchar_t table[] = "0123456789abcdef"; - uchar_t *byte_ptr = (uchar_t *)&val; - for( i = 0; i < sizeof(uint64_t); i++ ) { - out[i*2] = table[ ((*byte_ptr) >> 4) & 0x0f ]; - out[i*2+1] = table[ (*byte_ptr) & 0x0f ]; - byte_ptr++; - } - out[i*2] = '\0'; -} - -#else /* little endian */ - -static void int64_to_hex_string( char *out, uint64_t val ) -{ - - - printk("int64_to_hex_string needs a little-endian implementation.\n"); -} -#endif /* _MIPSEB */ - -/* Convert a standard ASCII serial number to a unique integer - * id number by treating the serial number string as though - * it were a base 36 number - */ -uint64_t generate_unique_id( char *sn, int sn_len ) -{ - int uid = 0; - int i; - - #define VALID_BASE36(c) ((c >= '0' && c <='9') \ - || (c >= 'A' && c <='Z') \ - || (c >= 'a' && c <='z')) - - for( i = 0; i < sn_len; i++ ) { - if( !VALID_BASE36(sn[i]) ) - continue; - uid *= 36; - uid += char_to_base36( sn[i] ); - } - - if( uid == 0 ) - return rtc_time(); - - return uid; -} - -uchar_t char_to_base36( char c ) -{ - uchar_t val; - - if( c >= '0' && c <= '9' ) - val = (c - '0'); - - else if( c >= 'A' && c <= 'Z' ) - val = (c - 'A' + 10); - - else if( c >= 'a' && c <= 'z' ) - val = (c - 'a' + 10); - - else val = 0; - - return val; -} - - -/* given a pointer to the three-byte little-endian EEPROM representation - * of date-of-manufacture, this function translates to a big-endian - * integer format - */ -int eeprom_xlate_board_mfr_date( uchar_t *src ) -{ - int rval = 0; - rval += *src; src++; - rval += ((int)(*src) << 8); src ++; - rval += ((int)(*src) << 16); - return rval; -} - - -int eeprom_str( char *nic_str, nasid_t nasid, int component ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - if( (component & C_DIMM) == C_DIMM ) { - /* this function isn't applicable to DIMMs */ - return EEP_PARAM; - } - else { - eep.board_ia = &board; - eep.spd = NULL; - if( !(component & SUBORD_MASK) ) - eep.chassis_ia = &chassis; /* only main boards have a chassis - * info area */ - else - eep.chassis_ia = NULL; - } - - switch( component & BRICK_MASK ) { - case C_BRICK: - r = cbrick_eeprom_read( &eep, nasid, component ); - break; - case IO_BRICK: - r = iobrick_eeprom_read( &eep, nasid, component ); - break; - default: - return EEP_PARAM; /* must be an invalid component */ - } - if( r ) - return r; - if( !nicify( nic_str, &eep ) ) - return EEP_NICIFY; - - return EEP_OK; -} - -int vector_eeprom_str( char *nic_str, nasid_t nasid, - int component, net_vec_t path ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - eep.board_ia = &board; - if( !(component & SUBORD_MASK) ) - eep.chassis_ia = &chassis; /* only main boards have a chassis - * info area */ - else - eep.chassis_ia = NULL; - - if( !(component & VECTOR) ) - return EEP_PARAM; - - if( (r = vector_eeprom_read( &eep, nasid, path, component )) ) - return r; - - if( !nicify( nic_str, &eep ) ) - return EEP_NICIFY; - - return EEP_OK; -} - - -int is_iobrick( int nasid, int widget_num ) -{ - uint32_t wid_reg; - int part_num, mfg_num; - - /* Read the widget's WIDGET_ID register to get - * its part number and mfg number - */ - wid_reg = *(volatile int32_t *) - (NODE_SWIN_BASE( nasid, widget_num ) + WIDGET_ID); - - part_num = (wid_reg & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; - mfg_num = (wid_reg & WIDGET_MFG_NUM) >> WIDGET_MFG_NUM_SHFT; - - /* Is this the "xbow part" of an XBridge? If so, this - * widget is definitely part of an I/O brick. - */ - if( part_num == XXBOW_WIDGET_PART_NUM && - mfg_num == XXBOW_WIDGET_MFGR_NUM ) - - return 1; - - /* Is this a "bridge part" of an XBridge? If so, once - * again, we know this widget is part of an I/O brick. - */ - if( part_num == XBRIDGE_WIDGET_PART_NUM && - mfg_num == XBRIDGE_WIDGET_MFGR_NUM ) - - return 1; - - return 0; -} - - -int cbrick_uid_get( nasid_t nasid, uint64_t *uid ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char uid_str[32]; - char msg[BRL1_QSIZE]; - int subch, len; - l1sc_t sc; - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* If the promlog variable pointed to by IP27LOG_OVNIC is set, - * use that value for the cbrick UID rather than the EEPROM - * serial number. - */ -#ifdef LOG_GETENV - if( ip27log_getenv( nasid, IP27LOG_OVNIC, uid_str, NULL, 0 ) >= 0 ) - { - /* We successfully read IP27LOG_OVNIC, so return it as the UID. */ - db_printf(( "cbrick_uid_get:" - "Overriding UID with environment variable %s\n", - IP27LOG_OVNIC )); - *uid = strtoull( uid_str, NULL, 0 ); - return EEP_OK; - } -#endif - - /* If this brick is retrieving its own uid, use the local l1sc_t to - * arbitrate access to the l1; otherwise, set up a new one. - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = ≻ - sc_init( &sc, nasid, BRL1_LOCALHUB_UART ); - } - - /* fill in msg with the opcode & params */ - BZERO( msg, BRL1_QSIZE ); - if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) - return EEP_L1; - - if( (len = sc_construct_msg( scp, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SER_NUM, 0 )) < 0 ) - { - sc_close( scp, subch ); - return( EEP_L1 ); - } - - /* send the request to the L1 */ - if( sc_command( scp, subch, msg, msg, &len ) ) { - sc_close( scp, subch ); - return( EEP_L1 ); - } - - /* free up subchannel */ - sc_close(scp, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 ) - { - return( EEP_L1 ); - } - - *uid = generate_unique_id( uid_str, strlen( uid_str ) ); - - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int rbrick_uid_get( nasid_t nasid, net_vec_t path, uint64_t *uid ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char uid_str[32]; - char msg[BRL1_QSIZE]; - int subch, len; - l1sc_t sc; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - -#define FAIL \ - { \ - *uid = rtc_time(); \ - printk( "rbrick_uid_get failed; using current time as uid\n" ); \ - return EEP_OK; \ - } - - ROUTER_LOCK(path); - sc_init( &sc, nasid, path ); - - /* fill in msg with the opcode & params */ - BZERO( msg, BRL1_QSIZE ); - if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) { - ROUTER_UNLOCK(path); - FAIL; - } - - if( (len = sc_construct_msg( &sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_SER_NUM, 0 )) < 0 ) - { - ROUTER_UNLOCK(path); - sc_close( &sc, subch ); - FAIL; - } - - /* send the request to the L1 */ - if( sc_command( &sc, subch, msg, msg, &len ) ) { - ROUTER_UNLOCK(path); - sc_close( &sc, subch ); - FAIL; - } - - /* free up subchannel */ - ROUTER_UNLOCK(path); - sc_close(&sc, subch); - - /* check response */ - if( sc_interpret_resp( msg, 2, L1_ARG_ASCII, uid_str ) < 0 ) - { - FAIL; - } - - *uid = generate_unique_id( uid_str, strlen( uid_str ) ); - - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - -int iobrick_uid_get( nasid_t nasid, uint64_t *uid ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - - eep.board_ia = &board; - eep.chassis_ia = &chassis; - eep.spd = NULL; - - r = iobrick_eeprom_read( &eep, nasid, IO_BRICK ); - if( r != EEP_OK ) { - *uid = rtc_time(); - return r; - } - - *uid = generate_unique_id( board.serial_num, - board.serial_num_tl & FIELD_LENGTH_MASK ); - - return EEP_OK; -} - - -int ibrick_mac_addr_get( nasid_t nasid, char *eaddr ) -{ - eeprom_brd_record_t eep; - eeprom_board_ia_t board; - eeprom_chassis_ia_t chassis; - int r; - char *tmp; - - eep.board_ia = &board; - eep.chassis_ia = &chassis; - eep.spd = NULL; - - r = iobrick_eeprom_read( &eep, nasid, IO_BRICK ); - if( (r != EEP_OK) || (board.mac_addr[0] == '\0') ) { - db_printf(( "ibrick_mac_addr_get: " - "Couldn't read MAC address from EEPROM\n" )); - return EEP_L1; - } - else { - /* successfully read info area */ - int ix; - tmp = board.mac_addr; - for( ix = 0; ix < (board.mac_addr_tl & FIELD_LENGTH_MASK); ix++ ) - { - *eaddr++ = *tmp++; - } - *eaddr = '\0'; - } - - return EEP_OK; -} - - -/* - * eeprom_vertex_info_set - * - * Given a vertex handle, a component designation, a starting nasid - * and (in the case of a router) a vector path to the component, this - * function will read the EEPROM and attach the resulting information - * to the vertex in the same string format as that provided by the - * Dallas Semiconductor NIC drivers. If the vertex already has the - * string, this function just returns the string. - */ - -extern char *nic_vertex_info_get( devfs_handle_t ); -extern void nic_vmc_check( devfs_handle_t, char * ); -/* the following were lifted from nic.c - change later? */ -#define MAX_INFO 2048 -#define NEWSZ(ptr,sz) ((ptr) = kern_malloc((sz))) -#define DEL(ptr) (kern_free((ptr))) - -char *eeprom_vertex_info_set( int component, int nasid, devfs_handle_t v, - net_vec_t path ) -{ - char *info_tmp; - int info_len; - char *info; - - /* see if this vertex is already marked */ - info_tmp = nic_vertex_info_get(v); - if (info_tmp) return info_tmp; - - /* get a temporary place for the data */ - NEWSZ(info_tmp, MAX_INFO); - if (!info_tmp) return NULL; - - /* read the EEPROM */ - if( component & R_BRICK ) { - if( RBRICK_EEPROM_STR( info_tmp, nasid, path ) != EEP_OK ) - return NULL; - } - else { - if( eeprom_str( info_tmp, nasid, component ) != EEP_OK ) - return NULL; - } - - /* allocate a smaller final place */ - info_len = strlen(info_tmp)+1; - NEWSZ(info, info_len); - if (info) { - strcpy(info, info_tmp); - DEL(info_tmp); - } else { - info = info_tmp; - } - - /* add info to the vertex */ - hwgraph_info_add_LBL(v, INFO_LBL_NIC, - (arbitrary_info_t) info); - - /* see if someone else got there first */ - info_tmp = nic_vertex_info_get(v); - if (info != info_tmp) { - DEL(info); - return info_tmp; - } - - /* export the data */ - hwgraph_info_export_LBL(v, INFO_LBL_NIC, info_len); - - /* trigger all matching callbacks */ - nic_vmc_check(v, info); - - return info; -} - - -/********************************************************************* - * - * stubs for use until the Bedrock/L1 link is available - * - */ - -#include <asm/sn/nic.h> - -/* #define EEPROM_TEST */ - -/* fake eeprom reading functions (replace when the BR/L1 communication - * channel is in working order) - */ - - -/* generate a charater in [0-9A-Z]; if an "extra" character is - * specified (such as '_'), include it as one of the possibilities. - */ -char random_eeprom_ch( char extra ) -{ - char ch; - int modval = 36; - if( extra ) - modval++; - - ch = rtc_time() % modval; - - if( ch < 10 ) - ch += '0'; - else if( ch >= 10 && ch < 36 ) - ch += ('A' - 10); - else - ch = extra; - - return ch; -} - -/* create a part number of the form xxx-xxxx-xxx. - * It may be important later to generate different - * part numbers depending on the component we're - * supposed to be "reading" from, so the component - * paramter is provided. - */ -void fake_a_part_number( char *buf, int component ) -{ - int i; - switch( component ) { - - /* insert component-specific routines here */ - - case C_BRICK: - strcpy( buf, "030-1266-001" ); - break; - default: - for( i = 0; i < 12; i++ ) { - if( i == 3 || i == 8 ) - buf[i] = '-'; - else - buf[i] = random_eeprom_ch(0); - } - } -} - - -/* create a six-character serial number */ -void fake_a_serial_number( char *buf, uint64_t ser ) -{ - int i; - static const char hexchars[] = "0123456789ABCDEF"; - - if (ser) { - for( i = 5; i >=0; i-- ) { - buf[i] = hexchars[ser & 0xf]; - ser >>= 4; - } - } - else { - for( i = 0; i < 6; i++ ) - buf[i] = random_eeprom_ch(0); - } -} - - -void fake_a_product_name( uchar_t *format, char* buf, int component ) -{ - switch( component & BRICK_MASK ) { - - case C_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "C_BRICK_SUB" ); - *format = 0xCB; - } - else { - strcpy( buf, "IP35" ); - *format = 0xC4; - } - break; - - case R_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "R_BRICK_SUB" ); - *format = 0xCB; - } - else { - strcpy( buf, "R_BRICK" ); - *format = 0xC7; - } - break; - - case IO_BRICK: - if( component & SUBORD_MASK ) { - strcpy( buf, "IO_BRICK_SUB" ); - *format = 0xCC; - } - else { - strcpy( buf, "IO_BRICK" ); - *format = 0xC8; - } - break; - - default: - strcpy( buf, "UNK_DEVICE" ); - *format = 0xCA; - } -} - - - -int fake_an_eeprom_record( eeprom_brd_record_t *buf, int component, - uint64_t ser ) -{ - eeprom_board_ia_t *board; - eeprom_chassis_ia_t *chassis; - int i, cs; - - board = buf->board_ia; - chassis = buf->chassis_ia; - - if( !(component & SUBORD_MASK) ) { - if( !chassis ) - return EEP_PARAM; - chassis->format = 0; - chassis->length = 5; - chassis->type = 0x17; - - chassis->part_num_tl = 0xCC; - fake_a_part_number( chassis->part_num, component ); - chassis->serial_num_tl = 0xC6; - fake_a_serial_number( chassis->serial_num, ser ); - - cs = chassis->format + chassis->length + chassis->type - + chassis->part_num_tl + chassis->serial_num_tl; - for( i = 0; i < (chassis->part_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += chassis->part_num[i]; - for( i = 0; i < (chassis->serial_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += chassis->serial_num[i]; - chassis->checksum = 256 - (cs % 256); - } - - if( !board ) - return EEP_PARAM; - board->format = 0; - board->length = 10; - board->language = 0; - board->mfg_date = 1789200; /* noon, 5/26/99 */ - board->manuf_tl = 0xC3; - strcpy( board->manuf, "SGI" ); - - fake_a_product_name( &(board->product_tl), board->product, component ); - - board->serial_num_tl = 0xC6; - fake_a_serial_number( board->serial_num, ser ); - - board->part_num_tl = 0xCC; - fake_a_part_number( board->part_num, component ); - - board->board_rev_tl = 0xC2; - board->board_rev[0] = '0'; - board->board_rev[1] = '1'; - - board->eeprom_size_tl = 0x01; - board->eeprom_size = 1; - - board->temp_waiver_tl = 0xC2; - board->temp_waiver[0] = '0'; - board->temp_waiver[1] = '1'; - - cs = board->format + board->length + board->language - + (board->mfg_date & 0xFF) - + (board->mfg_date & 0xFF00) - + (board->mfg_date & 0xFF0000) - + board->manuf_tl + board->product_tl + board->serial_num_tl - + board->part_num_tl + board->board_rev_tl - + board->board_rev[0] + board->board_rev[1] - + board->eeprom_size_tl + board->eeprom_size + board->temp_waiver_tl - + board->temp_waiver[0] + board->temp_waiver[1]; - for( i = 0; i < (board->manuf_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->manuf[i]; - for( i = 0; i < (board->product_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->product[i]; - for( i = 0; i < (board->serial_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->serial_num[i]; - for( i = 0; i < (board->part_num_tl & FIELD_LENGTH_MASK); i++ ) - cs += board->part_num[i]; - - board->checksum = 256 - (cs % 256); - - return EEP_OK; -} - -#define EEPROM_CHUNKSIZE 64 - -#if defined(EEPROM_DEBUG) -#define RETURN_ERROR \ -{ \ - printk( "read_ia error return, component 0x%x, line %d" \ - ", address 0x%x, ia code 0x%x\n", \ - l1_compt, __LINE__, sc->subch[subch].target, ia_code ); \ - return EEP_L1; \ -} - -#else -#define RETURN_ERROR return(EEP_L1) -#endif - -int read_ia( l1sc_t *sc, int subch, int l1_compt, - int ia_code, char *eep_record ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char msg[BRL1_QSIZE]; /* message buffer */ - int len; /* number of bytes used in message buffer */ - int ia_len = EEPROM_CHUNKSIZE; /* remaining bytes in info area */ - int offset = 0; /* current offset into info area */ - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - BZERO( msg, BRL1_QSIZE ); - - /* retrieve EEPROM data in 64-byte chunks - */ - - while( ia_len ) - { - /* fill in msg with opcode & params */ - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EEPROM, 8, - L1_ARG_INT, l1_compt, - L1_ARG_INT, ia_code, - L1_ARG_INT, offset, - L1_ARG_INT, ia_len )) < 0 ) - { - RETURN_ERROR; - } - - /* send the request to the L1 */ - - if( sc_command( sc, subch, msg, msg, &len ) ) { - RETURN_ERROR; - } - - /* check response */ - if( sc_interpret_resp( msg, 5, - L1_ARG_INT, &ia_len, - L1_ARG_UNKNOWN, &len, eep_record ) < 0 ) - { - RETURN_ERROR; - } - - if( ia_len > EEPROM_CHUNKSIZE ) - ia_len = EEPROM_CHUNKSIZE; - - eep_record += EEPROM_CHUNKSIZE; - offset += EEPROM_CHUNKSIZE; - } - - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int read_spd( l1sc_t *sc, int subch, int l1_compt, - eeprom_spd_u *spd ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - char msg[BRL1_QSIZE]; /* message buffer */ - int len; /* number of bytes used in message buffer */ - int resp; /* l1 response code */ - int spd_len = EEPROM_CHUNKSIZE; /* remaining bytes in spd record */ - int offset = 0; /* current offset into spd record */ - char *spd_p = spd->bytes; /* "thumb" for writing to spd */ - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - BZERO( msg, BRL1_QSIZE ); - - /* retrieve EEPROM data in 64-byte chunks - */ - - while( spd_len ) - { - /* fill in msg with opcode & params */ - if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, - L1_ADDR_TASK_GENERAL, - L1_REQ_EEPROM, 8, - L1_ARG_INT, l1_compt, - L1_ARG_INT, L1_EEP_SPD, - L1_ARG_INT, offset, - L1_ARG_INT, spd_len )) < 0 ) - { - return( EEP_L1 ); - } - - /* send the request to the L1 */ - if( sc_command( sc, subch, msg, msg, &len ) ) { - return( EEP_L1 ); - } - - /* check response */ - if( (resp = sc_interpret_resp( msg, 5, - L1_ARG_INT, &spd_len, - L1_ARG_UNKNOWN, &len, spd_p )) < 0 ) - { - /* - * translate l1 response code to eeprom.c error codes: - * The L1 response will be L1_RESP_NAVAIL if the spd - * can't be read (i.e. the spd isn't physically there). It will - * return L1_RESP_INVAL if the spd exists, but fails the checksum - * test because the eeprom wasn't programmed, programmed incorrectly, - * or corrupted. L1_RESP_NAVAIL indicates the eeprom is likely not present, - * whereas L1_RESP_INVAL indicates the eeprom is present, but the data is - * invalid. - */ - if(resp == L1_RESP_INVAL) { - resp = EEP_BAD_CHECKSUM; - } else { - resp = EEP_L1; - } - return( resp ); - } - - if( spd_len > EEPROM_CHUNKSIZE ) - spd_len = EEPROM_CHUNKSIZE; - - spd_p += EEPROM_CHUNKSIZE; - offset += EEPROM_CHUNKSIZE; - } - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int read_chassis_ia( l1sc_t *sc, int subch, int l1_compt, - eeprom_chassis_ia_t *ia ) -{ - char eep_record[512]; /* scratch area for building up info area */ - char *eep_rec_p = eep_record; /* thumb for moving through eep_record */ - int checksum = 0; /* use to verify eeprom record checksum */ - int i; - - /* Read in info area record from the L1. - */ - if( read_ia( sc, subch, l1_compt, L1_EEP_CHASSIS, eep_record ) - != EEP_OK ) - { - return EEP_L1; - } - - /* Now we've got the whole info area. Transfer it to the data structure. - */ - - eep_rec_p = eep_record; - ia->format = *eep_rec_p++; - ia->length = *eep_rec_p++; - if( ia->length == 0 ) { - /* since we're using 8*ia->length-1 as an array index later, make - * sure it's sane. - */ - db_printf(( "read_chassis_ia: eeprom length byte of ZERO\n" )); - return EEP_L1; - } - ia->type = *eep_rec_p++; - - ia->part_num_tl = *eep_rec_p++; - - (void)BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK); - - ia->serial_num_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->serial_num, - (ia->serial_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK); - - ia->checksum = eep_record[(8 * ia->length) - 1]; - - /* verify checksum */ - eep_rec_p = eep_record; - checksum = 0; - for( i = 0; i < (8 * ia->length); i++ ) { - checksum += *eep_rec_p++; - } - - if( (checksum & 0xff) != 0 ) - { - db_printf(( "read_chassis_ia: bad checksum\n" )); - db_printf(( "read_chassis_ia: target 0x%x uart 0x%lx\n", - sc->subch[subch].target, sc->uart )); - return EEP_BAD_CHECKSUM; - } - - return EEP_OK; -} - - -int read_board_ia( l1sc_t *sc, int subch, int l1_compt, - eeprom_board_ia_t *ia ) -{ - char eep_record[512]; /* scratch area for building up info area */ - char *eep_rec_p = eep_record; /* thumb for moving through eep_record */ - int checksum = 0; /* running checksum total */ - int i; - - BZERO( ia, sizeof( eeprom_board_ia_t ) ); - - /* Read in info area record from the L1. - */ - if( read_ia( sc, subch, l1_compt, L1_EEP_BOARD, eep_record ) - != EEP_OK ) - { - db_printf(( "read_board_ia: error reading info area from L1\n" )); - return EEP_L1; - } - - /* Now we've got the whole info area. Transfer it to the data structure. - */ - - eep_rec_p = eep_record; - ia->format = *eep_rec_p++; - ia->length = *eep_rec_p++; - if( ia->length == 0 ) { - /* since we're using 8*ia->length-1 as an array index later, make - * sure it's sane. - */ - db_printf(( "read_board_ia: eeprom length byte of ZERO\n" )); - return EEP_L1; - } - ia->language = *eep_rec_p++; - - ia->mfg_date = eeprom_xlate_board_mfr_date( (uchar_t *)eep_rec_p ); - eep_rec_p += 3; - - ia->manuf_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->manuf, (ia->manuf_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->manuf_tl & FIELD_LENGTH_MASK); - - ia->product_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->product, (ia->product_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->product_tl & FIELD_LENGTH_MASK); - - ia->serial_num_tl = *eep_rec_p++; - - BCOPY(eep_rec_p, ia->serial_num, (ia->serial_num_tl & FIELD_LENGTH_MASK)); - eep_rec_p += (ia->serial_num_tl & FIELD_LENGTH_MASK); - - ia->part_num_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->part_num, (ia->part_num_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->part_num_tl & FIELD_LENGTH_MASK); - - eep_rec_p++; /* we do not use the FRU file id */ - - ia->board_rev_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->board_rev, (ia->board_rev_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->board_rev_tl & FIELD_LENGTH_MASK); - - ia->eeprom_size_tl = *eep_rec_p++; - ia->eeprom_size = *eep_rec_p++; - - ia->temp_waiver_tl = *eep_rec_p++; - - BCOPY( eep_rec_p, ia->temp_waiver, - (ia->temp_waiver_tl & FIELD_LENGTH_MASK) ); - eep_rec_p += (ia->temp_waiver_tl & FIELD_LENGTH_MASK); - - /* if there's more, we must be reading a main board; get - * additional fields - */ - if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) { - - ia->ekey_G_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_G, - ia->ekey_G_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_G_tl & FIELD_LENGTH_MASK); - - ia->ekey_P_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_P, - ia->ekey_P_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_P_tl & FIELD_LENGTH_MASK); - - ia->ekey_Y_tl = *eep_rec_p++; - BCOPY( eep_rec_p, (char *)&ia->ekey_Y, - ia->ekey_Y_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->ekey_Y_tl & FIELD_LENGTH_MASK); - - /* - * need to get a couple more fields if this is an I brick - */ - if( ((unsigned char)*eep_rec_p != (unsigned char)EEPROM_EOF) ) { - - ia->mac_addr_tl = *eep_rec_p++; - BCOPY( eep_rec_p, ia->mac_addr, - ia->mac_addr_tl & FIELD_LENGTH_MASK ); - eep_rec_p += (ia->mac_addr_tl & FIELD_LENGTH_MASK); - - ia->ieee1394_cfg_tl = *eep_rec_p++; - BCOPY( eep_rec_p, ia->ieee1394_cfg, - ia->ieee1394_cfg_tl & FIELD_LENGTH_MASK ); - - } - } - - ia->checksum = eep_record[(ia->length * 8) - 1]; - - /* verify checksum */ - eep_rec_p = eep_record; - checksum = 0; - for( i = 0; i < (8 * ia->length); i++ ) { - checksum += *eep_rec_p++; - } - - if( (checksum & 0xff) != 0 ) - { - db_printf(( "read_board_ia: bad checksum\n" )); - db_printf(( "read_board_ia: target 0x%x uart 0x%lx\n", - sc->subch[subch].target, sc->uart )); - return EEP_BAD_CHECKSUM; - } - - return EEP_OK; -} - - -int _cbrick_eeprom_read( eeprom_brd_record_t *buf, l1sc_t *scp, - int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - int r; - uint64_t uid = 0; -#ifdef LOG_GETENV - char uid_str[32]; -#endif - int l1_compt, subch; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're targeting a cbrick */ - if( !(component & C_BRICK) ) - return EEP_PARAM; - - /* If the promlog variable pointed to by IP27LOG_OVNIC is set, - * use that value for the cbrick UID rather than the EEPROM - * serial number. - */ -#ifdef LOG_GETENV - if( ip27log_getenv( scp->nasid, IP27LOG_OVNIC, uid_str, "0", 0 ) >= 0 ) - { - db_printf(( "_cbrick_eeprom_read: " - "Overriding UID with environment variable %s\n", - IP27LOG_OVNIC )); - uid = strtoull( uid_str, NULL, 0 ); - } -#endif - - if( (subch = sc_open( scp, L1_ADDR_LOCAL )) < 0 ) - return EEP_L1; - - if((component & C_DIMM) == C_DIMM) { - l1_compt = L1_EEP_DIMM(component & COMPT_MASK); - r = read_spd(scp,subch,l1_compt, buf->spd); - sc_close(scp,subch); - return(r); - } - - switch( component ) - { - case C_BRICK: - /* c-brick motherboard */ - l1_compt = L1_EEP_NODE; - r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia ); - if( r != EEP_OK ) { - sc_close( scp, subch ); - db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - if( uid ) { - /* If IP27LOG_OVNIC is set, we want to put that value - * in as our UID. */ - fake_a_serial_number( buf->chassis_ia->serial_num, uid ); - buf->chassis_ia->serial_num_tl = 6; - } - break; - - case C_PIMM: - /* one of the PIMM boards */ - l1_compt = L1_EEP_PIMM( component & COMPT_MASK ); - break; - - default: - /* unsupported board type */ - sc_close( scp, subch ); - return EEP_PARAM; - } - - r = read_board_ia( scp, subch, l1_compt, buf->board_ia ); - sc_close( scp, subch ); - if( r != EEP_OK ) - { - db_printf(( "_cbrick_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int cbrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* If this brick is retrieving its own uid, use the local l1sc_t to - * arbitrate access to the l1; otherwise, set up a new one (prom) or - * use an existing remote l1sc_t (kernel) - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - } - - return _cbrick_eeprom_read( buf, scp, component ); -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int iobrick_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - int r; - int l1_compt, subch; - l1sc_t *scp; - int local = (nasid == get_nasid()); - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're talking to an applicable brick */ - if( !(component & IO_BRICK) ) { - return EEP_PARAM; - } - - /* If we're talking to this c-brick's attached io brick, use - * the local l1sc_t; otherwise, set up a new one (prom) or - * use an existing remote l1sc_t (kernel) - */ - if( local ) { - scp = get_l1sc(); - } - else { - scp = &NODEPDA( NASID_TO_COMPACT_NODEID(nasid) )->module->elsc; - } - - if( (subch = sc_open( scp, L1_ADDR_LOCALIO )) < 0 ) - return EEP_L1; - - - switch( component ) - { - case IO_BRICK: - /* IO brick motherboard */ - l1_compt = L1_EEP_LOGIC; - r = read_chassis_ia( scp, subch, l1_compt, buf->chassis_ia ); - - if( r != EEP_OK ) { - sc_close( scp, subch ); - /* - * Whenever we no longer need to test on hardware - * that does not have EEPROMS, then this can be removed. - */ - r = fake_an_eeprom_record( buf, component, rtc_time() ); - return r; - } - break; - - case IO_POWER: - /* IO brick power board */ - l1_compt = L1_EEP_POWER; - break; - - default: - /* unsupported board type */ - sc_close( scp, subch ); - return EEP_PARAM; - } - - r = read_board_ia( scp, subch, l1_compt, buf->board_ia ); - sc_close( scp, subch ); - if( r != EEP_OK ) { - return r; - } - return EEP_OK; -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} - - -int vector_eeprom_read( eeprom_brd_record_t *buf, nasid_t nasid, - net_vec_t path, int component ) -{ -#if !defined(CONFIG_SERIAL_SGI_L1_PROTOCOL) - return EEP_L1; -#else - int r; - uint64_t uid = 0; - int l1_compt, subch; - l1sc_t sc; - - if ( IS_RUNNING_ON_SIMULATOR() ) - return EEP_L1; - - /* make sure we're targeting an applicable brick */ - if( !(component & VECTOR) ) - return EEP_PARAM; - - switch( component & BRICK_MASK ) - { - case R_BRICK: - ROUTER_LOCK( path ); - sc_init( &sc, nasid, path ); - - if( (subch = sc_open( &sc, L1_ADDR_LOCAL )) < 0 ) - { - db_printf(( "vector_eeprom_read: couldn't open subch\n" )); - ROUTER_UNLOCK(path); - return EEP_L1; - } - switch( component ) - { - case R_BRICK: - /* r-brick motherboard */ - l1_compt = L1_EEP_LOGIC; - r = read_chassis_ia( &sc, subch, l1_compt, buf->chassis_ia ); - if( r != EEP_OK ) { - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - printk( "vector_eeprom_read: couldn't get rbrick eeprom info;" - " using current time as uid\n" ); - uid = rtc_time(); - db_printf(("vector_eeprom_read: using a fake eeprom record\n")); - return fake_an_eeprom_record( buf, component, uid ); - } - break; - - case R_POWER: - /* r-brick power board */ - l1_compt = L1_EEP_POWER; - break; - - default: - /* unsupported board type */ - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - return EEP_PARAM; - } - r = read_board_ia( &sc, subch, l1_compt, buf->board_ia ); - sc_close( &sc, subch ); - ROUTER_UNLOCK( path ); - if( r != EEP_OK ) { - db_printf(( "vector_eeprom_read: using a fake eeprom record\n" )); - return fake_an_eeprom_record( buf, component, uid ); - } - return EEP_OK; - - case C_BRICK: - sc_init( &sc, nasid, path ); - return _cbrick_eeprom_read( buf, &sc, component ); - - default: - /* unsupported brick type */ - return EEP_PARAM; - } -#endif /* CONFIG_SERIAL_SGI_L1_PROTOCOL */ -} |