#include #include #include #include #include #include #include #include #include #include #define VPD_PROGRAMMED_SIZE 72 #define PCH0_SMBUS_VENID 0x8086 #define PATSBURG_PCH0_SMBUS_DEVID 0x1D22 #define IBX_PCH0_SMBUS_DEVID 0x3B30 #include #include static struct pci_dev *pdevPCH = NULL; static unsigned long pch_smba = 0; UINT8 gSAS2308EepromPattern[ 8 ] = { 0x00, 0x7F, 0xAA, 0xFF, 0xCC, 0xF0, 0x55, 0x0F }; UINT8 gVPDEepromPattern[ 8 ] = { 0x00, 0x7F, 0xAA, 0xFF, 0xCC, 0xF0, 0x55, 0x0F }; #define SMBHSTSTS (0 + pch_smba) #define SMBHSTCNT (2 + pch_smba) #define SMBHSTCMD (3 + pch_smba) #define SMBHSTADD (4 + pch_smba) #define SMBHSTDAT0 (5 + pch_smba) #define SMBHSTDAT1 (6 + pch_smba) #define SMBBLKDAT (7 + pch_smba) #define SMBPEC (8 + pch_smba) #define SMBAUXSTS (12 + pch_smba) #define SMBAUXCTL (13 + pch_smba) #define SMBBPINCTL (15 + pch_smba) #define SMBBPINCTL_SDA 0x2 #define SMBBPINCTL_SCL 0x1 #define SMBHSTSTS_DEF_VALUE 0x00 #define SMBAUXSTS_DEF_VALUE 0x00 #define SMBBPINCTL_DEF_VALUE 0x07 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("--------------------------------------------------------------------------------"); } VOID fpgaI2cMux9548Reset(BOOLEAN status) { INT32 result; UINT8 temp; temp = fpgaRegisterRead(FPGA_MISCELLANEOUS_CONTROL_2); if(status) { result = fpgaRegisterWrite(FPGA_MISCELLANEOUS_CONTROL_2, temp | I2C_RESET_BIT); } else { result = fpgaRegisterWrite(FPGA_MISCELLANEOUS_CONTROL_2, temp & (~I2C_RESET_BIT)); } } int i2cEeprom64KBitRead(struct i2c_adapter *adap, uint16_t i2c_addr, uint16_t offset, uint8_t *buf, int count) { uint8_t __offset[2]; struct i2c_msg msg[2]; int ret; __offset[0] = (uint8_t) (offset >> 8); //MSB of word address __offset[1] = (uint8_t) (offset & 0xFF); //LSB of word address /* dummy write */ msg[0].addr = i2c_addr; msg[0].flags = 0; msg[0].len = 2; msg[0].buf = __offset; /* read op */ msg[1].addr = i2c_addr; msg[1].flags = I2C_M_RD; msg[1].len = count; msg[1].buf = buf; if ((ret = i2c_transfer(adap, msg, 2)) != 2) return (ret); return (0); } static int __i2cEeprom4KBitRead(struct i2c_adapter *adap, uint16_t i2c_addr, uint8_t offset, uint8_t *buf, int count) { uint8_t __offset = offset; struct i2c_msg msg[2]; int ret; /* dummy write */ msg[0].addr = i2c_addr; msg[0].flags = 0; msg[0].len = 1; msg[0].buf = &__offset; /* read op */ msg[1].addr = i2c_addr; msg[1].flags = I2C_M_RD; msg[1].len = count; msg[1].buf = buf; if ((ret = i2c_transfer(adap, msg, 2)) != 2) return (ret); return (0); } int i2cEeprom4KBitRead(struct i2c_adapter *adap, uint16_t i2c_addr, uint16_t offset, uint8_t *buf, int count) { uint16_t __offset = offset; int rx_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 + rx_count) > count) __count = count - rx_count; /* MSB of eeprom address */ __i2c_addr = i2c_addr | (__offset >> 8); ret = __i2cEeprom4KBitRead(adap, __i2c_addr, (uint8_t) __offset, &buf[rx_count], __count); if (ret) break; __offset += __count; rx_count += __count; } while (rx_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); } static void setupTestBuffer(uint8_t *buf, uint8_t *pattern, int bufSize, int patternSize) { int count; int offset = 0; do { if ((bufSize - offset) >= patternSize) count = patternSize; else count = bufSize - offset; memcpy(&buf[offset], pattern, count); offset += count; } while(offset != bufSize); } static int i2cEeprom64KBitTest(struct i2c_adapter *adap, uint16_t i2cAddr, uint8_t *pattern) { int EEPROM_SIZE = 8 * 1024; int RW_SIZE = 256; uint8_t *orgBuf = NULL; uint8_t *writeBuf = NULL; uint8_t *readBuf = NULL; int ret = 0; int i; orgBuf = kzalloc(EEPROM_SIZE, GFP_KERNEL); if (orgBuf == NULL) return (-ENOMEM); writeBuf = kzalloc(EEPROM_SIZE, GFP_KERNEL); if (writeBuf == NULL) { ret = -ENOMEM; goto free; } readBuf = kzalloc(EEPROM_SIZE, GFP_KERNEL); if (readBuf == NULL) { ret = -ENOMEM; goto free; } for (i = 0; i < EEPROM_SIZE; i+= RW_SIZE) { ret = i2cEeprom64KBitRead(adap, i2cAddr, i, &orgBuf[i], RW_SIZE); if (ret) { printk("[EEPROM TEST] failed to save eeprom contents(%d)\n", i); goto free; } commPostProgress("[EEPROM TEST] save contents", i + RW_SIZE, EEPROM_SIZE); } /* Debug */ printk("[DEBUG] First 160 bytes of eeprom\n"); for (i = 0; i < 160; i++) { if ((i%16) == 0) printk("\n"); printk("%02X ", (uint8_t) orgBuf[i]); } printk("\n\n"); setupTestBuffer(writeBuf, pattern, sizeof(writeBuf), sizeof(pattern)); for (i = 0; i < EEPROM_SIZE; i+= RW_SIZE) { ret = i2cEeprom64KBitWrite(adap, i2cAddr, i, &writeBuf[i], RW_SIZE); if (ret) { printk("[EEPROM TEST] failed to write eeprom(%d)\n", i); goto restore; } commPostProgress("[EEPROM TEST] write patterns", i + RW_SIZE, EEPROM_SIZE); } for (i = 0; i < EEPROM_SIZE; i+= RW_SIZE) { ret = i2cEeprom64KBitRead(adap, i2cAddr, i, &readBuf[i], RW_SIZE); if (ret) { printk("[EEPROM TEST] failed to read eeprom(%d)\n", i); goto restore; } commPostProgress("[EEPROM TEST] read eeprom", i + RW_SIZE, EEPROM_SIZE); } for (i = 0; i < EEPROM_SIZE; i++) { if (writeBuf[i] != readBuf[i]) { printk("[EEPROM TEST] data mis-compare addr(%x) exp:%x obs:%x\n", i, writeBuf[i], readBuf[i]); break; } } restore: for (i = 0; i < EEPROM_SIZE; i+= RW_SIZE) { ret = i2cEeprom64KBitWrite(adap, i2cAddr, i, &orgBuf[i], RW_SIZE); if (ret) { printk("[EEPROM TEST] failed to restore eeprom(%d)" "WARNING: The eeprom contents may be corrupted\n", i); break; } commPostProgress("[EEPROM TEST] restore eeprom", i + RW_SIZE, EEPROM_SIZE); } /* Debug */ memset(orgBuf, 0, EEPROM_SIZE); ret = i2cEeprom64KBitRead(adap, i2cAddr, 0, orgBuf, 160); if (ret) { printk("[DEBUG] failed to read eeprom\n"); goto free; } printk("[DEBUG] After testing, first 160 bytes of eeprom\n"); for (i = 0; i < 160; i++) { if ((i%16) == 0) printk("\n"); printk("%02X ", (uint8_t) orgBuf[i]); } printk("\n\n"); free: if (readBuf) kfree(readBuf); if (writeBuf) kfree(writeBuf); if (orgBuf) kfree(orgBuf); return (ret); } int i2cZebulonBusLineTest( void ) { struct i2c_client *client = NULL; uint8_t data; char *devname = NULL; int ret = 0, err = 0; int (*eepromRead) (struct i2c_adapter *adapter, uint16_t i2c_addr, uint16_t offset, uint8_t *buf, int count) = NULL; // // Basic Read PCA9548 I2C MUX Device // client = getI2cMuxClient( PCA9548_NAME, PCA9548_ADDR, FPGA_I2C_BUS_0 ); if( !client ) { printk( "I2C Zebulon Bus 0: cannot get PCA9548 device\n" ); ret = -ENODEV; err++; goto nextTst1; } ret = i2c_master_recv( client, &data, 1 ); if( ret != 1 ) { printk( "I2C Zebulon Bus 0: read pca9548 failed(%d)\n", ret ); ret = -ENODEV; err++; } nextTst1: // // Identify the midplane we're using // if( identifyMidplaneType() == MIDPLANE_STANDARD ) { eepromRead = i2cEeprom64KBitRead; devname = EEPROM_64KB_NAME; } else { eepromRead = i2cEeprom4KBitRead; devname = EEPROM_2KB_NAME; } // // Read SBB VPD EEPROM on FPGA I2C 1 // client = getI2cDevClient( devname, VPD_EEPROM_ADDR, FPGA_I2C_BUS_1 ); if( !client ) { printk( "I2C Zebulon Bus 1: cannot get VPD EEPROM device\n" ); ret = -ENODEV; err++; goto nextTst2; } ret = eepromRead( client->adapter, client->addr, 0, &data, 1 ); if (ret) { printk( "I2C Zebulon Bus 1: read eeprom failed(%d)\n", ret ); ret = -ENODEV; err++; } nextTst2: // // Read SBB VPD EEPROM on FPGA I2C 2 // client = getI2cDevClient( devname, VPD_EEPROM_ADDR, FPGA_I2C_BUS_2 ); if( !client ) { printk( "I2C Zebulon Bus 1: cannot get VPD EEPROM device\n" ); ret = -ENODEV; err++; goto nextTst3; } ret = eepromRead( client->adapter, client->addr, 0, &data, 1 ); if (ret) { printk("I2C Zebulon Bus 2: read eeprom failed(%d)\n", ret); err++; ret = -ENODEV; } nextTst3: // Error Report if( err ) { commReportError(MEC_I2C, I2C_DG_ITEM_ZEBULON_BUS_LINE, I2C_DG_CODE_ZEBULON_BUS_LINE, I2C_DG_MSG_ZEBULON_BUS_LINE, 0, 0, 0, DG_FORMAT_NONE); } return ret; } EXPORT_SYMBOL(i2cZebulonBusLineTest); #define PCA9548_READ_REG(client, value) \ { \ int ret; \ ret = i2c_master_recv(client, &value, 1); \ if (ret != 1){ \ printk(KERN_ERR "%s(%d): Can not read register\n", __func__, __LINE__); \ commReportError(MEC_I2C, I2C_DG_ITEM_PCA9548, I2C_DG_CODE_PCA9548, \ I2C_DG_MSG_PCA9548_READ, 0, 0, 0, DG_FORMAT_NONE); \ return (ret); \ } \ } #define PCA9548_WRITE_REG(client, value) \ { \ int ret; \ ret = i2c_master_send(client, &value, 1); \ if (ret != 1){ \ printk(KERN_ERR "%s(%d): Can not write register\n", __func__, __LINE__); \ commReportError(MEC_I2C, I2C_DG_ITEM_PCA9548, I2C_DG_CODE_PCA9548, \ I2C_DG_MSG_PCA9548_WRITE, 0, 0, 0, DG_FORMAT_NONE); \ return (ret); \ } \ } #define PCA9548_CHANNEL_TEST(client, chann) \ { \ uint8_t reg = 0; \ PCA9548_WRITE_REG(client, reg); \ mdelay(10); \ reg = 1 << chann; \ PCA9548_WRITE_REG(client, reg); \ mdelay(10); \ PCA9548_READ_REG(client, reg); \ if ( reg != (1 << chann)) { \ printk("%s channel [%d] test failed\n", __func__, chann); \ commReportError(MEC_I2C, I2C_DG_ITEM_PCA9548, I2C_DG_CODE_PCA9548, \ I2C_DG_MSG_PCA9548_REG, 0, 0, 0, DG_FORMAT_NONE); \ return (-1); \ } \ } int i2cSwitchTest( void ) { int i; uint8_t org, def; struct i2c_client *client = NULL; // Get I2C Client Device client = getI2cMuxClient( PCA9548_NAME, PCA9548_ADDR, FPGA_I2C_BUS_0 ); if( !client ) { printk( "I2C Zebulon Bus 0: cannot get PCA9548 device\n" ); return -ENODEV; } // Get I2C virtual adapters of PCA9548 for( i = MUX_I2C_BUS_0 ; i <= MUX_I2C_BUS_7 ; i++ ) { //printk( "Acquiring I2C MUX Ch[%d] virtual adapter\n", i - MUX_I2C_BUS_0 ); if( !i2c_get_adapter( i ) ) { printk( "I2C MUX Ch[%d]: cannot virtual adapter\n", i - MUX_I2C_BUS_0 ); return -ENODEV; } } // Channel Test for( i = MUX_I2C_BUS_0 ; i <= MUX_I2C_BUS_7 ; i++ ) { //printk( "%s: test channel [%d]\n", __func__, i - MUX_I2C_BUS_0 ); PCA9548_CHANNEL_TEST( client, (i - MUX_I2C_BUS_0) ); } /* Test reset line */ PCA9548_READ_REG(client, org); def = 1 << 3; PCA9548_WRITE_REG( client, def ); /* FPGA reset switch */ fpgaI2cMux9548Reset( 1 ); mdelay(10); fpgaI2cMux9548Reset( 0 ); /* Read register after reset */ PCA9548_READ_REG( client, def ); printk("Default register value 0x%02X\n", def); /* Should reset to zero */ if (def != 0x00){ commReportError(MEC_I2C, I2C_DG_ITEM_PCA9548, I2C_DG_CODE_PCA9548, I2C_DG_MSG_PCA9548_RESET, 0, 0, 0, DG_FORMAT_NONE); } /* Restore original value */ PCA9548_WRITE_REG(client, org); return 0; } int i2cDiagReadHICVPDEeprom( void ) { int ret = 0, err = 0; char buf[ VPD_PROGRAMMED_SIZE ]; unsigned short hicLoadFlag; unsigned int busno; struct i2c_client *client; // Get HIC Load Flag 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; case HICF_UNKNOWN: default: return 0; } /* VPD EEPROM */ client = getI2cHicDevClient( EEPROM_64KB_NAME, VPD_EEPROM_ADDR, busno ); if( !client ) { printk( "%s: cannot get HIC VPD device\n", __func__ ); err++; ret = -ENODEV; goto nextTst; } ret = i2cEeprom64KBitRead( client->adapter, client->addr, 0x00, buf, sizeof( buf ) ); if( ret ) { err++; ret = -ENODEV; goto nextTst; } #if 0 dump_hex( buf, VPD_PROGRAMMED_SIZE ); #endif nextTst: if( err ) { 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; } static int i2cTestSwitchChannLine0( void ) { return 0; } static int sasEepromReadTest( unsigned int busno ) { struct i2c_client *client; uint8_t data; // Get VPD driver client = getI2cDevClient( SAS2308_EEPROM_NAME, SAS2308_EEPROM_ADDR, busno ); if( !client ) { printk( "%s: cannot get SAS2308 VPD device\n", __func__ ); return -ENODEV; } // Test EEPROM if( i2cEeprom64KBitRead( client->adapter, client->addr, 0, &data, 1) ) { printk( "I2C MUX [%d]: SAS2308 EEPROM read failed\n", busno - MUX_I2C_BUS_0 ); return -ENODEV; } return 0; } static int i2cTestSwitchChannLine1( void ) { // SAS2308 EEPROM return sasEepromReadTest( MUX_I2C_BUS_1 ); } static int i2cTestSwitchChannLine2( void ) { // SAS2308 EEPROM return sasEepromReadTest( MUX_I2C_BUS_2 ); } static int i2cTestSwitchChannLine3( void ) { // PSOC return 0; } static int i2cTestSwitchChannLine4( void ) { // SAS2308 EEPROM return sasEepromReadTest( MUX_I2C_BUS_4 ); } static int i2cTestSwitchChannLine5( void ) { // BBU return 0; } static int i2cTestSwitchChannLine6( void ) { // HIC VPD Test return i2cDiagReadHICVPDEeprom(); } int max6657MfgId( void ) { struct i2c_client *max6657; /* MAX6657 */ max6657 = getI2cDevClient( MAX6657_NAME, MAX6657_ADDR, MUX_I2C_BUS_7 ); if( !max6657 ) { printk( "%s: cannot get max6657 device\n", __func__ ); return -ENODEV; } // Read manufacturing ID return i2c_smbus_read_byte_data( max6657, 0xFE ); } static int i2cTestSwitchChannLine7( void ) { struct i2c_client *client; uint8_t data; int ret = 0, err = 0; int mfgid; /* VPD EEPROM */ client = getI2cDevClient( EEPROM_64KB_NAME, VPD_EEPROM_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get Board VPD device\n", __func__ ); err++; ret = -ENODEV; goto nextTst; } if( i2cEeprom64KBitRead( client->adapter, client->addr, 0, &data, 1) ) { printk( "Pca9548 Channel 7 VPD EEPROM read failed\n" ); err++; ret = -ENODEV; } nextTst: /* MAX6657 */ mfgid = max6657MfgId(); if( (mfgid != 0x4D) && (mfgid != 0x41) ) { printk( "Pca9548 Channel 7 max6657 Sensor read(%d) failed\n", ret ); err++; ret = -ENODEV; } if( err ) { commReportError(MEC_I2C, I2C_DG_ITEM_PCA9548_CHANN, I2C_DG_CODE_PCA9548_CHANN, I2C_DG_MSG_PCA9548_CHANN, 0, 0, 0, DG_FORMAT_NONE); } return ret; } int i2cSwitchChannLineTest( void ) { int ret; // NO Device ret = i2cTestSwitchChannLine0(); if( ret < 0 ) return ret; // SAS2308 EEPROM #0 ret = i2cTestSwitchChannLine1(); if( ret < 0 ) return ret; // SAS2308 EEPROM #1 ret = i2cTestSwitchChannLine2(); if( ret < 0 ) return ret; // PSOC ret = i2cTestSwitchChannLine3(); if( ret < 0 ) return ret; // SAS2308 EEPROM #2 ret = i2cTestSwitchChannLine4(); if( ret < 0 ) return ret; // BBU ret = i2cTestSwitchChannLine5(); if( ret < 0 ) return ret; // HIC ret = i2cTestSwitchChannLine6(); if( ret < 0 ) return ret; // MAX6657 & VPD ret = i2cTestSwitchChannLine7(); if( ret < 0 ) return ret; return 0; } EXPORT_SYMBOL(i2cSwitchChannLineTest); int i2cDiagVPDEeprom( void ) { struct i2c_client *client; int ret; /* VPD EEPROM */ client = getI2cDevClient( EEPROM_64KB_NAME, VPD_EEPROM_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get Board VPD device\n", __func__ ); return -ENODEV; } ret = i2cEeprom64KBitTest( client->adapter, client->addr, gVPDEepromPattern ); 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; } static int i2cSasEeprom64KBitTest(struct i2c_adapter *adap, uint16_t i2cAddr, uint8_t *pattern) { int EEPROM_SIZE = 1 * 1024; int RW_SIZE = 256; uint8_t *orgBuf = NULL; uint8_t *writeBuf = NULL; uint8_t *readBuf = NULL; int ret = 0; int i; /* The size of 2008 Falcon bin file is 8 * 1024 */ /* In odrder to avoid to damage the content of Falcon bin file stored in eeprom, we skip this region, and just diagnose some blank region.*/ int offset = 9 * 1024; printk("[EEPROM TEST] offset is [%d]\n", offset); orgBuf = kzalloc(EEPROM_SIZE, GFP_KERNEL); if (orgBuf == NULL) return (-ENOMEM); writeBuf = kzalloc(EEPROM_SIZE, GFP_KERNEL); if (writeBuf == NULL) { ret = -ENOMEM; goto free; } readBuf = kzalloc(EEPROM_SIZE, GFP_KERNEL); if (readBuf == NULL) { ret = -ENOMEM; goto free; } for (i = 0; i < EEPROM_SIZE; i+= RW_SIZE) { ret = i2cEeprom64KBitRead(adap, i2cAddr, i+offset, &orgBuf[i], RW_SIZE); if (ret) { printk("[EEPROM TEST] failed to save eeprom contents(%d)\n", i); goto free; } commPostProgress("[EEPROM TEST] save contents", i + RW_SIZE, EEPROM_SIZE); } /* Debug */ printk("[DEBUG] First 160 bytes of eeprom\n"); for (i = 0; i < 160; i++) { if ((i%16) == 0) printk("\n"); printk("%02X ", (uint8_t) orgBuf[i]); } printk("\n\n"); setupTestBuffer(writeBuf, pattern, sizeof(writeBuf), sizeof(pattern)); for (i = 0; i < EEPROM_SIZE; i+= RW_SIZE) { ret = i2cEeprom64KBitWrite(adap, i2cAddr, i+offset, &writeBuf[i], RW_SIZE); if (ret) { printk("[EEPROM TEST] failed to write eeprom(%d)\n", i); goto restore; } commPostProgress("[EEPROM TEST] write patterns", i + RW_SIZE, EEPROM_SIZE); } for (i = 0; i < EEPROM_SIZE; i+= RW_SIZE) { ret = i2cEeprom64KBitRead(adap, i2cAddr, i+offset, &readBuf[i], RW_SIZE); if (ret) { printk("[EEPROM TEST] failed to read eeprom(%d)\n", i); goto restore; } commPostProgress("[EEPROM TEST] read eeprom", i + RW_SIZE, EEPROM_SIZE); } for (i = 0; i < EEPROM_SIZE; i++) { if (writeBuf[i] != readBuf[i]) { printk("[EEPROM TEST] data mis-compare addr(%x) exp:%x obs:%x\n", i, writeBuf[i], readBuf[i]); break; } } restore: for (i = 0; i < EEPROM_SIZE; i+= RW_SIZE) { ret = i2cEeprom64KBitWrite(adap, i2cAddr, i+offset, &orgBuf[i], RW_SIZE); if (ret) { printk("[EEPROM TEST] failed to restore eeprom(%d)" "WARNING: The eeprom contents may be corrupted\n", i); break; } commPostProgress("[EEPROM TEST] restore eeprom", i + RW_SIZE, EEPROM_SIZE); } /* Debug */ memset(orgBuf, 0, EEPROM_SIZE); ret = i2cEeprom64KBitRead(adap, i2cAddr, 0+offset, orgBuf, 160); if (ret) { printk("[DEBUG] failed to read eeprom\n"); goto free; } printk("[DEBUG] After testing, first 160 bytes of eeprom\n"); for (i = 0; i < 160; i++) { if ((i%16) == 0) printk("\n"); printk("%02X ", (uint8_t) orgBuf[i]); } printk("\n\n"); free: if (readBuf) kfree(readBuf); if (writeBuf) kfree(writeBuf); if (orgBuf) kfree(orgBuf); return (ret); } int i2cDiagSAS2308Eeprom( unsigned int no ) { struct i2c_client *client; int ret; unsigned int busno = 0; // Sanity check switch( no ) { case 0: busno = MUX_I2C_BUS_1; break; case 1: busno = MUX_I2C_BUS_2; break; case 2: busno = MUX_I2C_BUS_4; break; case 3: busno = HIC_MUX_I2C_BUS_0; break; case 4: busno = HIC_MUX_I2C_BUS_1; break; default: return -ENODEV; } // Get VPD driver client = getI2cDevClient( SAS2308_EEPROM_NAME, SAS2308_EEPROM_ADDR, busno ); if( !client ) { printk( "%s: cannot get SAS2308 VPD device\n", __func__ ); return -ENODEV; } // Test SAS2308 EEPROM ret = i2cSasEeprom64KBitTest( client->adapter, client->addr, gSAS2308EepromPattern ); if( ret ) { commReportError(MEC_I2C, I2C_DG_ITEM_SAS2008_EEPROM, I2C_DG_CODE_SAS2008_EEPROM, I2C_DG_MSG_SAS2008_EEPROM, 0, 0, 0, DG_FORMAT_NONE); } return 0; } int i2cDiagSAS2008Eeprom(void) { return i2cDiagSAS2308Eeprom(2); } int i2cDiagReadVPDEeprom( void ) { int ret = 0; char buf[ VPD_PROGRAMMED_SIZE ]; struct i2c_client *client; /* VPD EEPROM */ client = getI2cDevClient( EEPROM_64KB_NAME, VPD_EEPROM_ADDR, MUX_I2C_BUS_7 ); if( !client ) { printk( "%s: cannot get Board VPD device\n", __func__ ); return -ENODEV; } ret = i2cEeprom64KBitRead( client->adapter, client->addr, 0x00, buf, sizeof( buf ) ); dump_hex( buf, client->addr ); 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 i2cPCHBusLineTest(void) { int ret, err = 0; struct i2c_client *client; // CK420 client = getI2cDevClient( CK420_NAME, CK420_ADDR, PCH_I2C_BUS_0 ); if( !client ) { printk( "%s: cannot get CK420 device\n", __func__ ); return -ENODEV; } ret = i2c_smbus_read_byte_data( client, 0x07 ); if( ret < 0 ) { printk("Read CK505/CK420 Failed(%d)\n", ret ); err++; } // DB1201 client = getI2cDevClient( DB1201_NAME, DB1201_ADDR, PCH_I2C_BUS_0 ); if( !client ) { printk( "%s: cannot get DB1201 device\n", __func__ ); return -ENODEV; } ret = i2c_smbus_read_byte_data( client, 0x00 ); if( ret < 0 ) { printk("Read DB1201 Failed(%d)\n", ret ); err++; } if (err) { commReportError(MEC_I2C, I2C_DG_ITEM_PCH_BUS_LINE, I2C_DG_CODE_PCH_BUS_LINE, I2C_DG_MSG_PCH_BUS_LINE, 0, 0, 0, DG_FORMAT_NONE); } return (0); } static int i2cPCHInit( void ) { // Get PCH0 PCI device pdevPCH = pci_get_device( PCH0_SMBUS_VENID, PATSBURG_PCH0_SMBUS_DEVID, 0 ); if( !pdevPCH ) { pdevPCH = pci_get_device( PCH0_SMBUS_VENID, IBX_PCH0_SMBUS_DEVID, 0 ); } if( !pdevPCH ) { commReportError(MEC_I2C, I2C_DG_ITEM_INIT, I2C_DG_CODE_INIT, I2C_DG_MSG_PCH_INIT_FAILED, 0, 0, 0, DG_FORMAT_NONE); return -ENODEV; } // resource at BAR4 pch_smba = pci_resource_start( pdevPCH, 4 ); if( !pch_smba ) { commReportError(MEC_I2C, I2C_DG_ITEM_INIT, I2C_DG_CODE_INIT, I2C_DG_MSG_PCH_INIT_FAILED, 0, 0, 0, DG_FORMAT_NONE); return -ENODEV; } pch_smba &= 0xfffc; return 0; } VOID fpgaProcI2cSdaLow( BOOLEAN status ) { INT32 result; UINT8 temp; temp = fpgaRegisterRead(FPGA_I2C_CONTROL_1); if( status ) result = fpgaRegisterWrite(FPGA_I2C_CONTROL_1, temp & (~I2C_DATA_BIT)); else result = fpgaRegisterWrite(FPGA_I2C_CONTROL_1, temp | I2C_DATA_BIT); } VOID fpgaProcI2cSclLow( BOOLEAN status ) { INT32 result; UINT8 temp; temp = fpgaRegisterRead(FPGA_I2C_CONTROL_1); if( status ) result = fpgaRegisterWrite(FPGA_I2C_CONTROL_1, temp & (~I2C_CLK_BIT)); else result = fpgaRegisterWrite(FPGA_I2C_CONTROL_1, temp | I2C_CLK_BIT); } #define I2C_PCH_REGISTER_CHK(reg, def) \ { \ volatile uint8_t value; \ value = inb_p(reg); \ if (value != def) { \ printk("%s: reg(%x) = %x, expect %x\n", __func__, (uint32_t) reg, value, def); \ } \ } static void i2cPCHReset( void ) { uint8_t hostc; /* Host Configuration Register */ int timeout = 1000; pci_read_config_byte( pdevPCH, 0x40, &hostc ); hostc |= 0x8; /* SSRESET */ pci_write_config_byte( pdevPCH, 0x40, hostc ); do { pci_read_config_byte( pdevPCH, 0x40, &hostc ); timeout--; } while( hostc & 0x8 && timeout ); if( timeout == 0 && (hostc & 0x8) ) { printk("[I2C PCH] reset complete timeout\n"); } } static int i2cPCHRegisterTest( void ) { i2cPCHReset(); I2C_PCH_REGISTER_CHK( SMBHSTSTS, SMBHSTSTS_DEF_VALUE ); /*FIXME: skip this register test * since its reserved file has a value */ //I2C_PCH_REGISTER_CHK(SMBAUXSTS, SMBAUXSTS_DEF_VALUE); I2C_PCH_REGISTER_CHK( SMBBPINCTL, SMBBPINCTL_DEF_VALUE ); return 0; } #define I2C_PCH_CHK_SDA(level) \ { \ volatile uint8_t value; \ value = inb_p(SMBBPINCTL); \ if (((value & SMBBPINCTL_SDA) >> 1) != level) { \ printk("%s SMBBPINCTL = %x, expect level %x\n", __func__, value, level); \ } \ } static int i2cPCHSdaLineTest( void ) { i2cPCHReset(); /* fpga pull down sda line */ fpgaProcI2cSdaLow( 1 ); mdelay( 10 ); I2C_PCH_CHK_SDA( 0 ); /* fpga pull up sda line */ fpgaProcI2cSdaLow( 0 ); mdelay( 10 ); I2C_PCH_CHK_SDA( 1 ); return 0; } #define I2C_PCH_CHK_SCL(level) \ { \ volatile uint8_t value; \ value = inb_p(SMBBPINCTL); \ if ((value & SMBBPINCTL_SCL) != level) { \ printk("%s SMBBPINCTL = %x, expect level %x\n", __func__, value, level); \ } \ } static int i2cPCHSclLineTest( void ) { i2cPCHReset(); /* fpga pull down scl line */ fpgaProcI2cSclLow( 1 ); mdelay( 10 ); I2C_PCH_CHK_SCL( 0 ); /* fpga pull up scl line */ fpgaProcI2cSclLow( 0 ); mdelay( 10 ); I2C_PCH_CHK_SCL( 1 ); return 0; } int i2cPCHBusMasterTest( void ) { struct i2c_adapter *adap; int ret = 0, err = 0; // Get PCH0 Adapter adap = i2c_get_adapter( PCH_I2C_BUS_0 ); if( adap == NULL ) { commReportError(MEC_I2C, I2C_DG_ITEM_PCH_MASTER, I2C_DG_CODE_INIT, I2C_DG_MSG_PCH_INIT_FAILED, 0, 0, 0, DG_FORMAT_NONE); return -ENODEV; } // Initialize variables of PCI & SMBUS base ret = i2cPCHInit(); if( ret ) { commReportError(MEC_I2C, I2C_DG_ITEM_PCH_MASTER, I2C_DG_CODE_INIT, I2C_DG_MSG_PCH_INIT_FAILED, 0, 0, 0, DG_FORMAT_NONE); err++; return -ENODEV; } // Lock this adapter rt_mutex_lock( &adap->bus_lock ); // Test registers ret = i2cPCHRegisterTest(); if( ret ) { commReportError(MEC_I2C, I2C_DG_ITEM_PCH_MASTER, I2C_DG_CODE_PCH_REG, I2C_DG_MSG_PCH_REG, 0, 0, 0, DG_FORMAT_NONE); err++; } // Test SDA line ret = i2cPCHSdaLineTest(); if( ret ) { commReportError(MEC_I2C, I2C_DG_ITEM_PCH_MASTER, I2C_DG_CODE_PCH_SDA, I2C_DG_MSG_PCH_SDA, 0, 0, 0, DG_FORMAT_NONE); err++; } // Test SCL Line ret = i2cPCHSclLineTest(); if( ret ) { commReportError(MEC_I2C, I2C_DG_ITEM_PCH_MASTER, I2C_DG_CODE_PCH_SCL, I2C_DG_MSG_PCH_SCL, 0, 0, 0, DG_FORMAT_NONE); err++; } // Unlock this adapter rt_mutex_unlock( &adap->bus_lock ); if( err ) { commReportError(MEC_I2C, I2C_DG_ITEM_PCH_MASTER, I2C_DG_CODE_PCH_BUS_LINE, I2C_DG_MSG_PCH_BUS_LINE, 0, 0, 0, DG_FORMAT_NONE); } return ret; } int i2cReadMidPlaneEeprom( int bus ) { struct i2c_client *client; char buf[ VPD_PROGRAMMED_SIZE ]; int ret, err = 0; char *devname; int (*eepromRead) (struct i2c_adapter *adapter, uint16_t i2c_addr, uint16_t offset, uint8_t *buf, int count) = NULL; // Identify Midplane Type if( identifyMidplaneType() == MIDPLANE_TEST ) { eepromRead = i2cEeprom4KBitRead; devname = EEPROM_2KB_NAME; } else { eepromRead = i2cEeprom64KBitRead; devname = EEPROM_64KB_NAME; } if( bus != 1 && bus != 2 ) { printk( "Invalid bus no: %d\n", bus ); return -ENODEV; } if( bus == 1 ) { /* VPD EEPROM */ client = getI2cDevClient( devname, 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 = eepromRead( client->adapter, client->addr, 0, buf, VPD_PROGRAMMED_SIZE ); if( ret ) { printk( "%s Bus 1: read eeprom failed(%d)\n", __func__, ret ); err++; } } else if( bus == 2 ) { /* VPD EEPROM */ client = getI2cDevClient( devname, 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 = eepromRead( client->adapter, client->addr, 0, buf, VPD_PROGRAMMED_SIZE ); if( ret ) { printk( "%s Bus 2: read eeprom failed(%d)\n", __func__, ret ); err++; } } else return 0; dump_hex( buf, sizeof( buf ) ); if( err ) { commReportError(MEC_I2C, I2C_DG_ITEM_ZEBULON_BUS_LINE, I2C_DG_CODE_ZEBULON_BUS_LINE, I2C_DG_MSG_ZEBULON_BUS_LINE, 0, 0, 0, DG_FORMAT_NONE); } else { printk( "%s done\n", __func__ ); } return 0; } //sysfs interface static ssize_t i2cDiag_entry_show(struct kobject *kobject, struct kobj_attribute *attr, char *buf) { int result; result = i2cPCHBusMasterTest(); if(result) return sprintf(buf, "SUCCESSFULL"); else return sprintf(buf, "FAILED"); } static ssize_t i2cDiag_entry_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { return count; } static struct kobject *p_i2cDiag_kobj = NULL; static struct kobj_attribute i2cDiag_entry_attribute = __ATTR(i2cDiag_entry, 0660, i2cDiag_entry_show, i2cDiag_entry_store); static struct attribute *i2cDiagAttrs[] = { &i2cDiag_entry_attribute.attr, NULL, }; static struct attribute_group i2cDiagAttrGroup = { .attrs = i2cDiagAttrs, }; static int __init i2cDiag_init(void) { p_i2cDiag_kobj = kobject_create_and_add("i2cDiag", firmware_kobj); if(NULL != p_i2cDiag_kobj) { sysfs_create_group(p_i2cDiag_kobj, &i2cDiagAttrGroup); } printk(KERN_INFO "i2c Diagnostic Interface Driver\n"); return 0; } static void __exit i2cDiag_exit(void) { if(p_i2cDiag_kobj) { sysfs_remove_group(p_i2cDiag_kobj, &i2cDiagAttrGroup); kobject_put(p_i2cDiag_kobj); } } module_init(i2cDiag_init); module_exit(i2cDiag_exit); MODULE_AUTHOR( "merck.hung@netapp.com" ); MODULE_DESCRIPTION( "NetApp I2C Diag Code" ); MODULE_LICENSE( "GPL" ); MODULE_VERSION( "0.1" );