📄 l1_command.c
字号:
/* $Id$ * * 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) 1992 - 1997, 2000 - 2001 Silicon Graphics, Inc. * All rights reserved. */ #include <linux/types.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>#define ELSC_TIMEOUT 1000000 /* ELSC response timeout (usec) */#define LOCK_TIMEOUT 5000000 /* Hub lock timeout (usec) */#define LD(x) (*(volatile uint64_t *)(x))#define SD(x, v) (LD(x) = (uint64_t) (v))#define hub_cpu_get() 0#define LBYTE(caddr) (*(char *) caddr)extern char *bcopy(const char * src, char * dest, int count);#define LDEBUG 0/* * ELSC data is in NVRAM page 7 at the following offsets. */#define NVRAM_MAGIC_AD 0x700 /* magic number used for init */#define NVRAM_PASS_WD 0x701 /* password (4 bytes in length) */#define NVRAM_DBG1 0x705 /* virtual XOR debug switches */#define NVRAM_DBG2 0x706 /* physical XOR debug switches */#define NVRAM_CFG 0x707 /* ELSC Configuration info */#define NVRAM_MODULE 0x708 /* system module number */#define NVRAM_BIST_FLG 0x709 /* BIST flags (2 bits per nodeboard) */#define NVRAM_PARTITION 0x70a /* module's partition id */#define NVRAM_DOMAIN 0x70b /* module's domain id */#define NVRAM_CLUSTER 0x70c /* module's cluster id */#define NVRAM_CELL 0x70d /* module's cellid */#define NVRAM_MAGIC_NO 0x37 /* value of magic number */#define NVRAM_SIZE 16 /* 16 bytes in nvram *//* * Declare a static ELSC NVRAM buffer to hold all data read from * and written to NVRAM. This nvram "cache" will be used only during the * IP27prom execution. */static char elsc_nvram_buffer[NVRAM_SIZE];#define SC_COMMAND sc_command/* * elsc_init * * Initialize ELSC structure */void elsc_init(elsc_t *e, nasid_t nasid){ sc_init((l1sc_t *)e, nasid, BRL1_LOCALHUB_UART);}/* * elsc_errmsg * * Given a negative error code, * returns a corresponding static error string. */char *elsc_errmsg(int code){ switch (code) { case ELSC_ERROR_CMD_SEND: return "Command send error"; case ELSC_ERROR_CMD_CHECKSUM: return "Command packet checksum error"; case ELSC_ERROR_CMD_UNKNOWN: return "Unknown command"; case ELSC_ERROR_CMD_ARGS: return "Invalid command argument(s)"; case ELSC_ERROR_CMD_PERM: return "Permission denied"; case ELSC_ERROR_RESP_TIMEOUT: return "System controller response timeout"; case ELSC_ERROR_RESP_CHECKSUM: return "Response packet checksum error"; case ELSC_ERROR_RESP_FORMAT: return "Response format error"; case ELSC_ERROR_RESP_DIR: return "Response direction error"; case ELSC_ERROR_MSG_LOST: return "Message lost because queue is full"; case ELSC_ERROR_LOCK_TIMEOUT: return "Timed out getting ELSC lock"; case ELSC_ERROR_DATA_SEND: return "Error sending data"; case ELSC_ERROR_NIC: return "NIC protocol error"; case ELSC_ERROR_NVMAGIC: return "Bad magic number in NVRAM"; case ELSC_ERROR_MODULE: return "Module location protocol error"; default: return "Unknown error"; }}/* * elsc_nvram_init * * Initializes reads and writes to NVRAM. This will perform a single * read to NVRAM, getting all data at once. When the PROM tries to * read NVRAM, it returns the data from the buffer being read. If the * PROM tries to write out to NVRAM, the write is done, and the internal * buffer is updated. */void elsc_nvram_init(nasid_t nasid, uchar_t *elsc_nvram_data){ /* This might require implementation of multiple-packet request/responses * if it's to provide the same behavior that was available in SN0. */ nasid = nasid; elsc_nvram_data = elsc_nvram_data;}/* * elsc_nvram_copy * * Copies the content of a buffer into the static buffer in this library. */void elsc_nvram_copy(uchar_t *elsc_nvram_data){ memcpy(elsc_nvram_buffer, elsc_nvram_data, NVRAM_SIZE);}/* * elsc_nvram_write * * Copies bytes from 'buf' into NVRAM, starting at NVRAM address * 'addr' which must be between 0 and 2047. * * If 'len' is non-negative, the routine copies 'len' bytes. * * If 'len' is negative, the routine treats the data as a string and * copies bytes up to and including a NUL-terminating zero, but not * to exceed '-len' bytes. */int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len){ /* Here again, we might need to work out the details of a * multiple-packet protocol. */ /* For now, pretend it worked. */ e = e; addr = addr; buf = buf; return (len < 0 ? -len : len);}/* * elsc_nvram_read * * Copies bytes from NVRAM into 'buf', starting at NVRAM address * 'addr' which must be between 0 and 2047. * * If 'len' is non-negative, the routine copies 'len' bytes. * * If 'len' is negative, the routine treats the data as a string and * copies bytes up to and including a NUL-terminating zero, but not * to exceed '-len' bytes. NOTE: This method is no longer supported. * It was never used in the first place. */int elsc_nvram_read(elsc_t *e, int addr, char *buf, int len){ /* multiple packets? */ e = e; addr = addr; buf = buf; len = len; return -1;}/* * Command Set */int elsc_version(elsc_t *e, char *result){ char msg[BRL1_QSIZE]; int len; /* length of message being sent */ int subch; /* system controller subchannel used */ int major, /* major rev number */ minor, /* minor rev number */ bugfix; /* bugfix rev number */ /* fill in msg with the opcode & params */ bzero( msg, BRL1_QSIZE ); subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL ); if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, L1_ADDR_TASK_GENERAL, L1_REQ_FW_REV, 0 )) < 0 ) { sc_close( e, subch ); return( ELSC_ERROR_CMD_ARGS ); } /* send the request to the L1 */ if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) { sc_close( e, subch ); return( ELSC_ERROR_CMD_SEND ); } /* free up subchannel */ sc_close( (l1sc_t *)e, subch ); /* check response */ if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major, L1_ARG_INT, &minor, L1_ARG_INT, &bugfix ) < 0 ) { return( ELSC_ERROR_RESP_FORMAT ); } sprintf( result, "%d.%d.%d", major, minor, bugfix ); return 0;}int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2){ /* shush compiler */ e = e; byte1 = byte1; byte2 = byte2; /* fill in a buffer with the opcode & params; call sc_command */ return 0;}int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2){ char msg[BRL1_QSIZE]; int subch; /* system controller subchannel used */ int dbg_sw; /* holds debug switch settings */ int len; /* number of msg buffer bytes used */ /* fill in msg with the opcode & params */ bzero( msg, BRL1_QSIZE ); if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) { return( ELSC_ERROR_CMD_SEND ); } if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, L1_ADDR_TASK_GENERAL, L1_REQ_RDBG, 0 ) ) < 0 ) { sc_close( e, subch ); return( ELSC_ERROR_CMD_ARGS ); } /* send the request to the L1 */ if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) < 0 ) { sc_close( e, subch ); return( ELSC_ERROR_CMD_SEND ); } /* free up subchannel */ sc_close( (l1sc_t *)e, subch ); /* check response */ if( sc_interpret_resp( msg, 2, L1_ARG_INT, &dbg_sw ) < 0 ) { return( ELSC_ERROR_RESP_FORMAT ); } /* copy out debug switch settings (last two bytes of the * integer response) */ *byte1 = ((dbg_sw >> 8) & 0xFF); *byte2 = (dbg_sw & 0xFF); return 0;}/* * elsc_rack_bay_get fills in the two int * arguments with the * rack number and bay number of the L1 being addressed */int elsc_rack_bay_get(elsc_t *e, uint *rack, uint *bay){ char msg[BRL1_QSIZE]; /* L1 request/response info */ int subch; /* system controller subchannel used */ int len; /* length of message */ uint32_t buf32; /* used to copy 32-bit rack/bay out of msg */ /* fill in msg with the opcode & params */ bzero( msg, BRL1_QSIZE ); if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) { return( ELSC_ERROR_CMD_SEND ); } if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE, L1_ADDR_TASK_GENERAL, L1_REQ_RRACK, 0 )) < 0 ) { sc_close( e, subch ); return( ELSC_ERROR_CMD_ARGS ); } /* send the request to the L1 */ if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) ) { sc_close( e, subch ); return( ELSC_ERROR_CMD_SEND ); } /* free up subchannel */ sc_close(e, subch); /* check response */ if( sc_interpret_resp( msg, 2, L1_ARG_INT, &buf32 ) < 0 ) { return( ELSC_ERROR_RESP_FORMAT ); } /* extract rack/bay info * * note that the 32-bit value returned by the L1 actually * only uses the low-order sixteen bits for rack and bay * information. A "normal" L1 address puts rack and bay * information in bit positions 12 through 28. So if * we initially shift the value returned 12 bits to the left, * we can use the L1 addressing #define's to extract the * values we need (see ksys/l1.h for a complete list of the * various fields of an L1 address). */ buf32 <<= L1_ADDR_BAY_SHFT; *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; return 0;}/* elsc_rack_bay_type_get fills in the three int * arguments with the * rack number, bay number and brick type of the L1 being addressed. Note * that if the L1 operation fails and this function returns an error value, * garbage may be written to brick_type. */int elsc_rack_bay_type_get( l1sc_t *sc, uint *rack, uint *bay, uint *brick_type ){ char msg[BRL1_QSIZE]; /* L1 request/response info */ int subch; /* system controller subchannel used */ int len; /* length of message */ uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */ /* fill in msg with the opcode & params */ bzero( msg, BRL1_QSIZE ); if( (subch = sc_open( sc, L1_ADDR_LOCAL )) < 0 ) { return ELSC_ERROR_CMD_SEND; } if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE, L1_ADDR_TASK_GENERAL, L1_REQ_RRBT, 0 )) < 0 ) { sc_close( sc, subch ); return( ELSC_ERROR_CMD_ARGS ); } /* send the request to the L1 */ if( SC_COMMAND( sc, subch, msg, msg, &len ) ) { sc_close( sc, subch ); return( ELSC_ERROR_CMD_SEND ); } /* free up subchannel */ sc_close( sc, subch ); /* check response */ if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32, L1_ARG_INT, brick_type ) < 0 ) { return( ELSC_ERROR_RESP_FORMAT ); } /* extract rack/bay info * * note that the 32-bit value returned by the L1 actually * only uses the low-order sixteen bits for rack and bay * information. A "normal" L1 address puts rack and bay * information in bit positions 12 through 28. So if * we initially shift the value returned 12 bits to the left, * we can use the L1 addressing #define's to extract the * values we need (see ksys/l1.h for a complete list of the * various fields of an L1 address). */ buf32 <<= L1_ADDR_BAY_SHFT; *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT; *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT; /* convert brick_type to lower case */ *brick_type = *brick_type - 'A' + 'a'; return 0;}int elsc_module_get(elsc_t *e){ extern char brick_types[]; uint rnum, rack, bay, bricktype, t; int ret; /* construct module ID from rack and slot info */ if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) { return ret; } /* report unset location info. with a special, otherwise invalid modid */ if (rnum == 0 && bay == 0) return MODULE_NOT_SET; if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT) return ELSC_ERROR_MODULE; /* Build a moduleid_t-compatible rack number */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -