#include #include #include #include #include #include #include #include #include #include /*ICT Test-VPD definition*/ #define ASSEMBLY_NUM_OFFSET 0x07 #define SERIAL_NUM_OFFSET 0x17 #define FRU_MFG_DATE_OFFSET 0x33 #define FRU_NUM_OFFSET 0x3F #define VPD_PROGRAMMED_SIZE 72 #define MAGIC_NO_CTLR 0x1043544C #define MAGIC_NO_HIC 0x10484341 #define FRU_NAME_CTLR "CTLR" #define FRU_NAME_FC_HIC "HOST_8F" #define FRU_NAME_IB_HIC "HOST_IB" #define FRU_NAME_ISCSI_HIC "HOST_IS" #define FRU_NAME_SAS_HIC "HOST_SAS" unsigned char VPD_DEFAULT[ VPD_PROGRAMMED_SIZE ] = { /*00h*/ 0x10,0x43,0x54,0x4C, 0x50,0x4E,0x20,0xFF, 0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20, /*10h*/ 0x20,0x20,0x20,0x00, 0x53,0x4E,0x20,0xFF, 0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20, /*20h*/ 0x20,0x20,0x20,0x00, 0x56,0x4E,0x20,0x4C, 0x53,0x49,0x20,0x20, 0x20,0x20,0x20,0x00, /*30h*/ 0x44,0x54,0x20,0x30, 0x36,0x2F,0x32,0x30, 0x31,0x30,0x20,0x00, 0x46,0x54,0x20,0xFF, /*00h*/ 0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x00, }; unsigned char VPD_DEFAULT_HIC[ VPD_PROGRAMMED_SIZE ] = { /*00h*/ 0x10,0x48,0x43,0x41, 0x50,0x4E,0x20,0xFF, 0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20, /*10h*/ 0x20,0x20,0x20,0x00, 0x53,0x4E,0x20,0xFF, 0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20, /*20h*/ 0x20,0x20,0x20,0x00, 0x56,0x4E,0x20,0x4C, 0x53,0x49,0x20,0x20, 0x20,0x20,0x20,0x00, /*30h*/ 0x44,0x54,0x20,0x30, 0x36,0x2F,0x32,0x30, 0x31,0x30,0x20,0x00, 0x46,0x54,0x20,0xFF, /*00h*/ 0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x00, }; void dump_hex(char *buf, int length) { int i, j; printk("\r\n--------------------------------------------------------------------------------\r\n"); for (i = 0; i < length; i+= 16) { printk("%4x char ", i); for (j = 0; j < 16; j++) { unsigned char x = buf[i+j]; if (x < 32 || x > 126) x = '.'; if ((i+j) >= length) break; printk("%c", x); } printk("%*s hex", 16-j, ""); for (j = 0; j < 16; j++) { if ((i+j) >= length) break; printk(" %02x", (unsigned char)buf[i+j]); } printk("\r\n"); } printk("--------------------------------------------------------------------------------"); } #define EEPROM04_PAGE_SIZE 8 /* XXX: backward compatible to 2K Bit eeprom page size */ static int __i2cEeprom4KBitWrite(struct i2c_adapter *adap, uint16_t i2c_addr, uint8_t offset, uint8_t *buf, int count) { uint8_t __buf[EEPROM04_PAGE_SIZE + 1]; int __count, tx_count = 0; struct i2c_msg msg; int ret; do { if ((count - tx_count) > EEPROM04_PAGE_SIZE) __count = EEPROM04_PAGE_SIZE; else __count = count - tx_count; /* word address */ __buf[0] = (uint8_t) (offset + tx_count); memcpy(&__buf[1], (buf + tx_count), __count); msg.addr = i2c_addr; msg.flags = 0; //write msg.len = __count + 1; msg.buf = __buf; if ((ret = i2c_transfer(adap, &msg, 1)) != 1) { return (ret); } tx_count += __count; /* Max Write Cycle Time */ mdelay(5); } while (tx_count < count); return (0); } int i2cEeprom4KBitWrite(struct i2c_adapter *adap, uint16_t i2c_addr, uint16_t offset, uint8_t *buf, int count) { uint16_t __offset = offset; int tx_count = 0; uint16_t __i2c_addr; int __count; int ret = 0; do { /* Each read/write can not accross 256 byte alignment */ __count = 256 - ((uint8_t) __offset); if ((__count + tx_count) > count) __count = count - tx_count; /* MSB of eeprom address */ __i2c_addr = i2c_addr | (__offset >> 8); ret = __i2cEeprom4KBitWrite(adap, __i2c_addr, (uint8_t) __offset, &buf[tx_count], __count); if (ret) break; __offset += __count; tx_count += __count; } while (tx_count != count); return (ret); } #define EEPROM64_PAGE_SIZE 32 int i2cEeprom64KBitWrite(struct i2c_adapter *adap, uint16_t i2c_addr, uint16_t offset, uint8_t *buf, int count) { uint8_t __buf[EEPROM64_PAGE_SIZE + 2]; int __count, tx_count = 0; struct i2c_msg msg; int ret; do { if ((count - tx_count) > EEPROM64_PAGE_SIZE) __count = EEPROM64_PAGE_SIZE; else __count = count - tx_count; /* word address */ __buf[0] = (uint8_t) ((offset + tx_count) >> 8); //MSB of word address __buf[1] = (uint8_t) ((offset + tx_count) & 0xFF); //LSB of word address memcpy(&__buf[2], (buf + tx_count), __count); msg.addr = i2c_addr; msg.flags = 0; //write msg.len = __count + 2; msg.buf = __buf; if ((ret = i2c_transfer(adap, &msg, 1)) != 1) { return (ret); } tx_count += __count; /* Max Write Cycle Time */ mdelay(20); } while (tx_count != count); return (0); } int i2cRestoreMidPlaneEeprom( int bus ) { struct i2c_client *client; char buf[]={ 0x54, 0x45, 0x53, 0x54, 0x31, 0x32, 0x33, 0x34 }; int ret, err = 0; unsigned char act = 0; // Identify Midplane Type if( identifyMidplaneType() != MIDPLANE_TEST ) { printk( "%s is working only w/ Test Midplane\n", __func__ ); return -ENODEV; } if( bus == 1 ) act |= 0x01; else if( bus == 2 ) act |= 0x02; else if( bus == 3 ) act |= 0x03; else { printk( "Invalid bus no: %d\n", bus ); return -ENODEV; } if( act & 0x01 ) { /* VPD EEPROM */ client = getI2cDevClient( EEPROM_2KB_NAME, VPD_EEPROM_ADDR, FPGA_I2C_BUS_1 ); if( !client ) { printk( "%s: cannot get SBB VPD (FPGA I2C Bus 1) device\n", __func__ ); return -ENODEV; } ret = i2cEeprom4KBitWrite( client->adapter, client->addr, 0, buf, 8 ); if( ret ) { printk( "i2cRestoreMidPlaneEeprom Bus 1: Write eeprom failed(%d)\n", ret ); err++; } else { printk( "i2cRestoreMidPlaneEeprom Bus 1: Write eeprom OK\n" ); } } if( act & 0x02 ) { /* VPD EEPROM */ client = getI2cDevClient( EEPROM_2KB_NAME, VPD_EEPROM_ADDR, FPGA_I2C_BUS_2 ); if( !client ) { printk( "%s: cannot get SBB VPD (FPGA I2C Bus 2) device\n", __func__ ); return -ENODEV; } ret = i2cEeprom4KBitWrite( client->adapter, client->addr, 0, buf, 8 ); if (ret) { printk( "i2cRestoreMidPlaneEeprom Bus 2: Write eeprom failed(%d)\n", ret ); err++; } else { printk( "i2cRestoreMidPlaneEeprom Bus 2: Write eeprom OK\n" ); } } if( err ) { printk( "Error during i2cRestoreMidPlaneEeprom()\n" ); } else { printk( "i2cRestoreMidPlaneEeprom() done\n" ); } return 0; } int i2cWriteMBVPDEeprom( char *AssemNum, char *SerialNum, char *mfg_date ) { struct i2c_client *client; int ret = 0, x = 0, len; char buf[ VPD_PROGRAMMED_SIZE ]; // Sanity check if( !AssemNum || !SerialNum || !mfg_date ) { printk( "%s: Lack of input paramaters\n", __func__ ); return -EINVAL; } /* VPD EEPROM */ client = getI2cDevClient( EEPROM_64KB_NAME, VPD_EEPROM_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get MB VPD (MUX 7) device\n", __func__ ); return -ENODEV; } len = strlen( AssemNum ); if( (AssemNum[ len - 1 ] >= 'A' && AssemNum[ len - 1 ] <= 'Z') || (AssemNum[ len - 1 ] >= 'a' && AssemNum[len-1] <= 'z') ) len--; if( AssemNum[ 0 ] == 'P' ) { x++; len--; } memcpy( buf, VPD_DEFAULT, VPD_PROGRAMMED_SIZE ); strncpy( &buf[ ASSEMBLY_NUM_OFFSET ], &AssemNum[ x ], len ); strncpy( &buf[ SERIAL_NUM_OFFSET ], SerialNum, 10 ); strncpy( &buf[ FRU_NUM_OFFSET ], FRU_NAME_CTLR, 4 ); strncpy( &buf[ FRU_MFG_DATE_OFFSET ], mfg_date, 6 ); dump_hex( buf, VPD_PROGRAMMED_SIZE ); // Update MB VPD ret = i2cEeprom64KBitWrite( client->adapter, client->addr, 0x00, buf, sizeof( buf ) ); if( ret ) { commReportError(MEC_I2C, I2C_DG_ITEM_VPD_EEPROM, I2C_DG_CODE_VPD_EEPROM, I2C_DG_MSG_VPD_EEPROM, 0, 0, 0, DG_FORMAT_NONE); } return ret; } int i2cRestoreHICVPDEeprom( char *AssemNum, char *SerialNum, char *mfg_date ) { struct i2c_client *client; int ret = 0, x = 0, len; char buf[ VPD_PROGRAMMED_SIZE ]; unsigned short hicLoadFlag; unsigned int busno; // Sanity check if( !AssemNum || !SerialNum || !mfg_date ) { printk( "%s: Lack of input paramaters\n", __func__ ); return -EINVAL; } hicLoadFlag = identifyHostInterfaceCardFlag(); switch( hicLoadFlag ) { case HICF_IB_ELK_PARK: busno = MUX_I2C_BUS_6; break; case HICF_SAS_GLACIER: case HICF_FC_MANITOU: case HICF_ISCSI_GLEN_COVE: busno = HIC_MUX_I2C_BUS_4; break; default: printk( "%s: No HIC Installed\n", __func__ ); return -ENODEV; } /* VPD EEPROM */ client = getI2cHicDevClient( EEPROM_64KB_NAME, VPD_EEPROM_ADDR, busno ); if( !client ) { printk( "%s: cannot get HIC VPD device\n", __func__ ); return -ENODEV; } len = strlen( AssemNum ); if( (AssemNum[ len - 1 ] >= 'A' && AssemNum[ len - 1 ] <= 'Z') || (AssemNum[ len - 1 ] >= 'a' && AssemNum[ len - 1 ] <= 'z') ) len--; if( AssemNum[ 0 ] == 'P' ) { x++; len--; } memcpy( buf, VPD_DEFAULT_HIC, VPD_PROGRAMMED_SIZE ); strncpy( &buf[ ASSEMBLY_NUM_OFFSET ], &AssemNum[ x ], len ); strncpy( &buf[ SERIAL_NUM_OFFSET ], SerialNum, 10 ); strncpy( &buf[ FRU_MFG_DATE_OFFSET ], mfg_date, 6 ); switch( hicLoadFlag ) { case HICF_IB_ELK_PARK: strncpy( &buf[ FRU_NUM_OFFSET ], FRU_NAME_IB_HIC, 8 ); printk( "Host Card type: 40Gb IB!!\n" ); break; case HICF_FC_MANITOU: strncpy( &buf[ FRU_NUM_OFFSET ], FRU_NAME_FC_HIC, 8 ); printk( "Host Card type: 8Gb FC!!\n" ); break; case HICF_ISCSI_GLEN_COVE: strncpy( &buf[ FRU_NUM_OFFSET ], FRU_NAME_ISCSI_HIC, 8 ); printk( "Host Card type: iSCSI!!\n" ); break; case HICF_SAS_GLACIER: strncpy( &buf[ FRU_NUM_OFFSET ], FRU_NAME_SAS_HIC, 8 ); printk( "Host Card type: SAS!!\n"); break; default: printk("No Host Card present or Host Card type unvalid!!\n"); return -ENODEV; } dump_hex( buf, VPD_PROGRAMMED_SIZE ); ret = i2cEeprom64KBitWrite( client->adapter, client->addr, 0x00, buf, sizeof( buf ) ); if( ret ) { commReportError(MEC_I2C, I2C_DG_ITEM_VPD_EEPROM, I2C_DG_CODE_VPD_EEPROM, I2C_DG_MSG_VPD_EEPROM, 0, 0, 0, DG_FORMAT_NONE); } return ret; } MODULE_AUTHOR( "merck.hung@netapp.com" ); MODULE_DESCRIPTION( "NetApp Component Restore Code" ); MODULE_LICENSE( "GPL" ); MODULE_VERSION( "0.1" );