From: tzachid Date: Tue, 21 Mar 2006 17:13:31 +0000 (+0000) Subject: [tools] Added flint + mst + mread + mwrite + mtcr + spark X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=823e2e108fc8b87cf7253ec9a0751b06f7dd3e61;p=~shefty%2Frdma-win.git [tools] Added flint + mst + mread + mwrite + mtcr + spark git-svn-id: svn://openib.tc.cornell.edu/gen1@247 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- diff --git a/trunk/tools/dirs b/trunk/tools/dirs index 58b35e99..1acc72b3 100644 --- a/trunk/tools/dirs +++ b/trunk/tools/dirs @@ -2,4 +2,10 @@ DIRS=\ coinstaller \ fwupdate \ wsdinstall \ - vstat + vstat \ + mtcr \ + flint \ + mread \ + mwrite \ + mst \ + spark \ diff --git a/trunk/tools/flint/dirs b/trunk/tools/flint/dirs new file mode 100644 index 00000000..5a7e8b31 --- /dev/null +++ b/trunk/tools/flint/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/trunk/tools/flint/user/SOURCES b/trunk/tools/flint/user/SOURCES new file mode 100644 index 00000000..0696bfd8 --- /dev/null +++ b/trunk/tools/flint/user/SOURCES @@ -0,0 +1,63 @@ +TARGETNAME=flint +TARGETTYPE=PROGRAM +UMTYPE=console +USE_CRTDLL=1 +USE_NTDLL=1 + + +!if !defined(WINIBHOME) +WINIBHOME=..\..\.. +!endif + +TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + + + +ZLIB=$(WINIBHOME)\tools\ext_libs\user\zlib-1.1.4 + + +SOURCES=flint.rc \ + flint.cpp + + +INCLUDES= $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; \ + $(WINIBHOME)\inc\iba; \ + $(WINIBHOME)\tools\mtcr\user; \ + $(ZLIB)\include; + +TARGETLIBS= \ +!if $(FREEBUILD) + $(CRT_LIB_PATH)\msvcrt.lib \ + $(SDK_LIB_PATH)\Ws2_32.lib\ + $(TARGETPATH)\*\mtcr.lib +!else + $(CRT_LIB_PATH)\msvcrtd.lib\ + $(SDK_LIB_PATH)\Ws2_32.lib\ + $(TARGETPATH)\*\mtcr.lib +!endif + +USER_C_FLAGS=$(USER_C_FLAGS) /Ze /EHsc + +# TODO:Should I define the __WIN__ manually +C_DEFINES=$(C_DEFINES) -D__WIN__ -DZEXPORT=__cdecl + +C_DEFINES=$(C_DEFINES) -DNO_ZLIB + + +!if $(FREEBUILD) + +!else +C_DEFINES=$(C_DEFINES) -DDEBUG +!endif + +# Version: +!if !defined(MFT_BLD_VER) +MFT_BLD_VER=Devel +!endif +C_DEFINES=$(C_DEFINES) "-DVERSION_ID=$(MFT_BLD_VER)" + +386_STDCALL=0 + +MSC_WARNING_LEVEL= /W3 + diff --git a/trunk/tools/flint/user/flint.cpp b/trunk/tools/flint/user/flint.cpp new file mode 100644 index 00000000..17e56765 --- /dev/null +++ b/trunk/tools/flint/user/flint.cpp @@ -0,0 +1,6451 @@ +/* + * + * flint.cpp - FLash INTerface + * + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Version: $Id: flint.cpp 912 2006-02-07 13:48:50Z orenk $ + * + */ + +//MTCR needs to be first since it needs to define all kind of +//macros which affect standard headers. + +#include "mtcr.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_ZLIB +#include +#endif + +#include + +#ifndef __WIN__ + +// +// Linux +// + +#include +#include +#include +#include +#include + +#else // __WIN__ + +// +// Windows (Under DDK) +// + +#include +#include + +// Sleep adaptor +#define usleep(x) Sleep((x)/1000) +#define sleep(x) Sleep((x)*1000) + +#define vsnprintf _vsnprintf +#define strtoull _strtoui64 +#define isatty _isatty + +#define COMP_CDECL __cdecl + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __BYTE_ORDER __LITTLE_ENDIAN + + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define bswap_32(x) ntohl(x) +#else +#error windows is assumed to run a on little endian architecture +#endif + +#endif // __WIN__ + +#include +#include + +#ifndef DEV_MST_EXAMPLE1 + #define DEV_MST_EXAMPLE1 "/dev/mst/mt23108_pci_cr0" +#endif + +#ifndef DEV_MST_EXAMPLE2 + #define DEV_MST_EXAMPLE2 "/dev/mst/mt23108_pciconf0" +#endif + +#ifndef FLINT_NAME + #ifdef __GNUC__ + #define FLINT_NAME "%1$s" + #else + #define FLINT_NAME "./flint" + #endif +#endif + +namespace std {}; using namespace std; + +#ifdef VERSION_ID +//char* _versionID = VERSION_ID ; +#define __VFSTR(x) #x +#define _VFSTR(x) __VFSTR(x) +char* _versionID = _VFSTR( VERSION_ID ) ; +#else +char* _versionID = "VERSION_ID_HERE"; +#endif + +char* _svnID = "$Revision$"; + +#ifndef __be32_to_cpu + #define __be32_to_cpu(x) ntohl(x) + #ifndef bswap_32 + #define bswap_32(x) (htonl(x)) + #endif +#endif +#ifndef __cpu_to_be32 + #define __cpu_to_be32(x) htonl(x) +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN + #ifndef __cpu_to_le32 + #define __cpu_to_le32(x) (x) + #endif + #ifndef __le32_to_cpu + #define __le32_to_cpu(x) (x) + #endif +#elif __BYTE_ORDER == __BIG_ENDIAN + #ifndef __cpu_to_le32 + #define __cpu_to_le32(x) bswap_32(x) + #endif + #ifndef __le32_to_cpu + #define __le32_to_cpu(x) bswap_32(x) + #endif +#else + #ifndef __cpu_to_le32 + #define __cpu_to_le32(x) bswap_32(__cpu_to_be32(x)) + #endif + #ifndef __le32_to_cpu + #define __le32_to_cpu(x) __be32_to_cpu(bswap_32(x)) + #endif +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN + #ifndef __cpu_to_le16 + #define __cpu_to_le16(x) (x) + #endif + #ifndef __le16_to_cpu + #define __le16_to_cpu(x) (x) + #endif +#elif __BYTE_ORDER == __BIG_ENDIAN + #ifndef __cpu_to_le16 + #define __cpu_to_le16(x) bswap_16(x) + #endif + #ifndef __le16_to_cpu + #define __le16_to_cpu(x) bswap_16(x) + #endif +#else + #ifndef __cpu_to_le16 + #define __cpu_to_le16(x) bswap_16(__cpu_to_be16(x)) + #endif + #ifndef __le16_to_cpu + #define __le16_to_cpu(x) __be16_to_cpu(bswap_16(x)) + #endif +#endif + + +//////////////////////////////////////////////////////////////////////// +// // +// ****************************************************************** // +// Miscellaneous global stuff // +// ****************************************************************** // +// // +//////////////////////////////////////////////////////////////////////// +typedef struct guid { + u_int32_t h; + u_int32_t l; +} guid_t; + +static inline void be_guid_to_cpu(guid_t* to, guid_t* from) { + to->h=__be32_to_cpu(from->h); + to->l=__be32_to_cpu(from->l); +} + +static inline void cpu_to_be_guid(guid_t* to, guid_t* from) { + to->h=__cpu_to_be32(from->h); + to->l=__cpu_to_be32(from->l); +} + +#define GUID_FORMAT "%8.8x%8.8x" +#define TOCPU1(s) s = __be32_to_cpu(s) +#define TOCPU(s) do { \ + u_int32_t *p = (u_int32_t *)(s); \ + for (u_int32_t ii=0; ii %08x\n", (u_int32_t)offs, (u_int32_t)(*(val))); \ + } while (0) + +#endif + +class ErrMsg +{ +public: + ErrMsg() : _err(0) { } + ~ErrMsg() { err_clear(); } + const char *err() const { return _err; } + void err_clear() { delete [] _err; _err = 0; } + +protected: + + char *vprint(const char *format, va_list args) + { + const int INIT_VAL = 1024; + int max_str, max_buf = INIT_VAL; + char *out_buf; + + while (1) + { + out_buf = new char[max_buf]; + max_str = max_buf - 1; + + if (vsnprintf(out_buf, max_str, format, args) < max_str) + return out_buf; + delete [] out_buf; + max_buf *= 2; + } + } + + + bool errmsg(const char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format (printf, 2, 3))) +#endif + ; + +private: + + char *_err; +}; + + +bool ErrMsg::errmsg(const char *format, ...) { + va_list args; + + char* prev_err = _err; + + va_start(args, format); + _err = vprint(format, args); + va_end(args); + + delete[] prev_err; + + return false; +} + + +enum { + SIGNATURE=0x5a445a44 +}; +struct PS { + u_int32_t fi_addr; + u_int32_t fi_size; + u_int32_t signature; + u_int32_t fw_reserved[5]; + u_int32_t vsd[52]; + u_int32_t psid[4]; + u_int32_t branch_to; + u_int32_t crc016; +}; +enum { + H_FIRST = 1, + H_DDR = 1, + H_CNF = 2, + H_JMP = 3, + H_EMT = 4, + H_ROM = 5, + H_GUID = 6, + H_BOARD_ID = 7, + H_USER_DATA = 8, + H_FW_CONF = 9, + H_IMG_INFO = 10, + H_LAST = 10 +}; + +struct GPH { + u_int32_t type; + u_int32_t size; + u_int32_t param; + u_int32_t next; +}; + +const u_int32_t BOARD_ID_BSN_LEN=64; +const u_int32_t BOARD_ID_BID_LEN=32; +const u_int32_t BOARD_ID_PID=7; + +struct BOARD_ID { + char bsn[BOARD_ID_BSN_LEN]; + char bid[BOARD_ID_BID_LEN]; +}; + +int const VSD_LEN = 208; +int const PSID_LEN = 16; + +// +// TODO: Remove the below globals to class members. +// +bool _print_crc = false; +bool _silent = false; +bool _assume_yes = false; +bool _image_is_full; +bool _no_erase = false; +bool _no_burn = false; + +bool _unlock_bypass = false; + +bool _byte_write = false; + + +void report(const char *format, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 1, 2))) +#endif +; +void report(const char *format, ...) +{ + va_list args; + + if (!_silent) { + va_start(args, format); + vprintf(format, args); + va_end(args); + } +} // report + +void report_erase(const char *format, ...) +{ + va_list args; + char buf[256]; + int i; + int len; + + if (_silent) + return; + + va_start(args, format); + vsnprintf(buf, sizeof buf, format, args); + va_end(args); + + len = strlen(buf); + for(i=0; i < len; ++i) + printf("\b"); +} // report_erase + +static u_int32_t log2up (u_int32_t in) { + u_int32_t i; + for (i = 0; i < 32; i++) { + if (in <= (u_int32_t)(1 << i)) + break; + } + + return i; +} + + +//////////////////////////////////////////////////////////////////////// +// // +// ****************************************************************** // +// CRC16 CALCULATION // +// ****************************************************************** // +// // +//////////////////////////////////////////////////////////////////////// +class Crc16 { +public: + Crc16(bool d = false) : _debug(d) { clear();} + u_int16_t get() { return _crc;} + void clear() { _crc = 0xffff;} + void operator<<(u_int32_t val) { add(val);} + void add(u_int32_t val); + void finish(); +private: + u_int16_t _crc; + bool _debug; +}; + +//////////////////////////////////////////////////////////////////////// +void Crc16::add(u_int32_t o) +{ + if (_debug) + printf("Crc16::add(%08x)\n", o); + for (int i=0; i<32; i++) { + if (_crc & 0x8000) + _crc = (u_int16_t) ((((_crc<<1) | (o>>31)) ^ 0x100b) & 0xffff); + else + _crc= (u_int16_t) (((_crc<<1) | (o>>31)) & 0xffff); + o = (o<<1) & 0xffffffff; + } +} // Crc16::add + + +//////////////////////////////////////////////////////////////////////// +void Crc16::finish() +{ + for (int i=0; i<16; i++) { + if (_crc & 0x8000) + _crc=((_crc<<1) ^ 0x100b) & 0xffff; + else + _crc=(_crc<<1) & 0xffff; + } + + // Revert 16 low bits + _crc = _crc ^ 0xffff; + +} // Crc16::finish + + +////////////////////////////////////////////////////////////////////// +// +// class u_int32_ba (bit access): +// A uint wrapper which allows easy access to bit/range of bits. +// +// Usage example: +// u_int32_ba a; +// Read_Word( Table.reg ,&a); +// int upper_byte = a.range(31,24); +// if (a[15]) +// cout << " Bit 15 is 1 \n"; +// else +// cout << " Bit 15 is 0 \n"; +// +// u_int32_ba b; +// b.range(15,12) = 0xa; +// b[31] = 1; // b == 0x8000a000 +// Write_Word( Table.reg ,b); +// +////////////////////////////////////////////////////////////////////// + + +class u_int32_ba { +public: + u_int32_ba(u_int32_t i = 0) : + _bits(i), + _rbits(_bits), + _sptr(0), + _eptr(31) {} + + u_int32_ba operator[](u_int32_t idx) {return range((u_int8_t)idx,(u_int8_t)idx);} + u_int32_ba& operator= (u_int32_t i) {_rbits = ((i << _sptr) & mask()) | (_rbits & ~mask()); return *this;} + u_int32_t* operator& () {return &_bits;} + operator u_int32_t () {return((mask() & _rbits) >> _sptr);} + + u_int32_ba range (u_int8_t eptr, + u_int8_t sptr) {return u_int32_ba(*this,eptr,sptr);} + +private: + u_int32_ba(u_int32_ba& other, u_int8_t eptr, u_int8_t sptr) : + _bits(other._bits), + _rbits(other._bits), + _sptr(sptr), + _eptr(eptr) {} + + u_int32_t mask () { + u_int32_t s_msk = (u_int32_t)-1; // start mask + u_int32_t e_msk = (u_int32_t)-1; // end mask + + s_msk = (s_msk << _sptr); + e_msk = (_eptr >= (sizeof(_bits)*8-1)) ? e_msk : ~(e_msk << (_eptr+1)); + + return(s_msk & e_msk); + }; + + u_int32_t _bits; + u_int32_t& _rbits; + + u_int8_t _sptr; + u_int8_t _eptr; +}; + + +//////////////////////////////////////////////////////////////////////// +// // +// ****************************************************************** // +// FLASH ACCESS // +// ****************************************************************** // +// // +//////////////////////////////////////////////////////////////////////// + +// Common base class for Flash and for FImage +class FBase : public ErrMsg{ +public: + FBase() {} + virtual ~FBase() {} + + virtual bool open(const char *, bool) {return false;} + virtual void close() = 0; + virtual bool read(u_int32_t addr, u_int32_t *data) = 0; + virtual bool read(u_int32_t addr, void *data, int len, + bool verbose=false) = 0; + + virtual u_int32_t get_sector_size() = 0; + virtual u_int32_t get_size() = 0; + + enum { + MAX_FLASH = 4*1048576 + }; +}; + +// Flash image (RO) +class FImage : public FBase { +public: + FImage() : _buf(0) {} + virtual ~FImage() { close();} + + u_int32_t *getBuf() { return _buf;} + u_int32_t getBufLength() { return _len;} + virtual bool open(const char *fname, bool read_only = false); + virtual void close(); + virtual bool read(u_int32_t addr, u_int32_t *data); + virtual bool read(u_int32_t addr, void *data, int len, bool verbose=false); + + virtual u_int32_t get_sector_size(); + virtual u_int32_t get_size() { return getBufLength();} + +private: + u_int32_t *_buf; + u_int32_t _len; +}; + +// Flash access (R/W) + +// +// Flash classes heirarchy: +// +// +// Flash { CmdSet (abstract) } +// | +// | +// +----> ParallelFlash { CmdSetAmd, CmdSetIntel } +// | +// | +// |----> SerialFlash +// | +// +--------> SpiFlash { CmdSetStSpi } +// | +// +- - - - > LpcFlash (currently not uset - not implemented) +// +// +// Flash Interface: +// - open +// - close +// - read +// - detect type (and allocate CmdSet accordingly) +// +// +// Flash Class HAS A command set. +// +// CmdSet Interface: +// - write +// - erase_sector +// +// Q: Why is diferentiation needed for both flash type and CmdSet ? +// A: Read operation is done in the same way for all flash devices of +// the same type (serial or parallel). This is a basic requirement +// from the flash, since the HCA HW reads from flash at boot, and +// the way it reads can not be changed. +// However, Write and Erase operations protocol varies between flash +// vendors. +// The term 'command set' is taken from the Common Flash Interface (CFI) +// specification. +// +// +// Flash Allocation flow: +// +// 1. Main checks device type, and allocates Flash sub class accordingly. +// 2. In Flash.open() , get_cmd_set() is called. this function checks flash +// type, gets flash attributes (size, sector size) and allocates CmdSet. +// +// + + + +// +// +// +class Flash : public FBase { +public: + Flash(u_int32_t log2_bank_size) : + _mf(0), + _cmd_set(NULL), + _curr_bank(0xffffffff), + _log2_bank_size(log2_bank_size) + {} + + virtual ~Flash() { close();}; + + // FBase Interface + + virtual bool open (const char *device, + bool force_lock = false, + bool read_only = false); + + virtual void close (); + + virtual bool read (u_int32_t addr, + u_int32_t *data) = 0; + + virtual bool read (u_int32_t addr, + void* data, + int len, + bool verbose = false); + // + // Flash Interface + // + + virtual u_int32_t + get_sector_size () { return _get_sector_size(); } + + virtual u_int32_t + get_size () {return _cfi_data.device_size ? _cfi_data.device_size : (u_int32_t)MAX_FLASH;} + + + virtual bool wait_ready (const char* msg = NULL) = 0; + + + // Write and Erase functions are performed by the Command Set + + virtual bool erase_sector (u_int32_t addr) {if (!set_bank(addr)) return false;return _cmd_set->erase_sector(addr);} + + virtual bool write (u_int32_t addr, + void* data, + int cnt, + bool noerase = false, + bool noverify = false); + + virtual bool write (u_int32_t addr, + u_int32_t data); + + bool print_cfi_info(); + + + enum { + TRANS = 4096 + }; + +#ifndef _MSC_VER +protected: +#endif + + // FLASH constants + enum FlashConstant { + FLASH_CMD_CNT = 5000, // Number of reads till flash cmd is zeroed + ERASE_DELAY = 200000, // Delay between reads when wating for sector erase + ERASE_CNT = 80, // Maximal number of reads when wating for sector erase + READ_CNT_FAST = 5000, // Number of fast reads after write byte + READ_CNT_SLOW = 50, // Number of slow reads after write byte + READ_DELAY = 100000, // Delay between slow reads after write byte + WR_REPORT_FAST = 256, // Report frequency when write (fast interfaces) + WR_REPORT_SLOW = 4, // Report frequency when write (slow interfaces) + RD_REPORT_FAST = 4096, // Report frequency when read (fast interfaces) + RD_REPORT_SLOW = 64, // Report frequency when read (slow interfaces) + GPIO_SEM_TRIES = 10240, // Number of tries to obtain a GPIO sem. + MAX_WRITE_BUFFER_SIZE = 32// Max buffer size for buffer write devices + }; + + + enum CrAddres { + GPIO_DIR_L = 0xf008c, + GPIO_POL_L = 0xf0094, + GPIO_MOD_L = 0xf009c, + GPIO_DAT_L = 0xf0084, + GPIO_DATACLEAR_L = 0xf00d4, + GPIO_DATASET_L = 0xf00dc, + + SEMAP63 = 0xf03fc + }; + + virtual bool lock (bool retry=true); + virtual bool unlock (); + + virtual bool init_gpios () = 0; + + virtual bool get_cmd_set () = 0; + + bool set_bank (u_int32_t addr); + + virtual bool write_internal(u_int32_t addr, + u_int8_t data) = 0; + + bool write_internal(u_int32_t addr, + u_int8_t* data, + u_int32_t cnt); + + class CmdSet { + public: + CmdSet () : _curr_sector(0xffffffff) {} + virtual ~CmdSet () {} + + virtual bool write (u_int32_t addr, + void* data, + int cnt, + bool noerase = false, + bool noverify = false) = 0; + + virtual bool erase_sector (u_int32_t addr) = 0; + + virtual bool reset () = 0; + + protected: + + u_int32_t _curr_sector; + }; + + + // + // This structure holds all CFI query information as defined + // in the JEDEC standard. All information up to + // primary_extended_query is standard among all amnufactures + // with CFI enabled devices. + // + + struct cfi_query { + cfi_query() { + memset(this, 0, sizeof(*this)); + } + u_int8_t manuf_id; + u_int8_t device_id; + + char query_string[4]; // Should be 'QRY' + u_int16_t oem_command_set; // Command set + u_int16_t primary_table_address; // Addy of entended table + u_int16_t alt_command_set; // Alt table + u_int16_t alt_table_address; // Alt table addy + float vcc_min; // Vcc minimum + float vcc_max; // Vcc maximum + float vpp_min; // Vpp minimum, if supported + float vpp_max; // Vpp maximum, if supported + int timeout_single_write; // Time of single write + int timeout_buffer_write; // Time of buffer write + int timeout_block_erase; // Time of sector erase + int timeout_chip_erase; // Time of chip erase + int max_timeout_single_write; // Max time of single write + int max_timeout_buffer_write; // Max time of buffer write + int max_timeout_block_erase; // Max time of sector erase + int max_timeout_chip_erase; // Max time of chip erase + long device_size; // Device size in bytes + u_int16_t interface_description; // Interface description + int max_multi_byte_write; // Time of multi-byte write + int num_erase_blocks; // Number of sector defs. + struct { + unsigned long sector_size; // Byte size of sector + int num_sectors; // Num sectors of this size + u_int32_t sector_mask; // Sector mask + } erase_block[8]; // Max of 256, but 8 is good + + // AMD SPECIFIC + char primary_extended_query[4]; // Vendor specific info here + u_int16_t major_version; // Major code version + u_int16_t minor_version; // Minor code version + u_int8_t sensitive_unlock; // Is byte sensitive unlock? + u_int8_t erase_suspend; // Capable of erase suspend? + u_int8_t sector_protect; // Can Sector protect? + u_int8_t sector_temp_unprotect; // Can we temporarily unprotect? + u_int8_t protect_scheme; // Scheme of unprotection + u_int8_t is_simultaneous; // Is a smulataneous part? + u_int8_t is_burst; // Is a burst mode part? + u_int8_t is_page; // Is a page mode part? + }; + + bool print_cfi_info ( const cfi_query *q ); + + + virtual bool set_bank_int (u_int32_t bank) = 0; + u_int32_t bank_mask () {return((1 << _log2_bank_size) -1 );} + + mfile *_mf; + + cfi_query _cfi_data; + CmdSet* _cmd_set; + + u_int32_t _curr_bank; + u_int32_t _log2_bank_size; + + bool _locked; + + + /* Work around for MX flashes reporting weird erase sector size. */ + /* It reports two sector sizes, actually works as 1. */ + bool _mx_flash_workaround() { + return (_cfi_data.num_erase_blocks == 2 && + //_cfi_data.manuf_id == 0xff && _cfi_data.device_id == 0xff && + _cfi_data.erase_block[0].sector_size == 0x2000 && + _cfi_data.erase_block[0].sector_mask == 0xffffe000 && + _cfi_data.erase_block[0].num_sectors == 8 && + _cfi_data.erase_block[1].sector_size == 0x10000 && + _cfi_data.erase_block[1].sector_mask == 0xffff0000 && + _cfi_data.erase_block[1].num_sectors == 63); + } + u_int32_t + _get_sector_mask () + { + return _mx_flash_workaround()? + _cfi_data.erase_block[1].sector_mask : + _cfi_data.erase_block[0].sector_mask; + } + u_int32_t + _get_sector_size () + { + return _mx_flash_workaround()? + _cfi_data.erase_block[1].sector_size : + _cfi_data.erase_block[0].sector_size; + } +}; + + +class ParallelFlash : public Flash { +public: + ParallelFlash(); + ~ParallelFlash() {close();} + + enum { + CS_INTEL = 0x01, + CS_AMD = 0x02, + }; + + // FBase Interface + +// virtual bool open (const char *device, +// bool read_only = false); + + virtual void close (); + + + virtual bool read (u_int32_t addr, + u_int32_t *data); + + virtual bool read (u_int32_t addr, + void* data, + int len, + bool verbose=false) {return Flash::read(addr, data, len, verbose);} + + virtual bool wait_ready (const char* msg = NULL); + + static void set_byte_mode (bool mode) {CmdSetAmd::set_byte_mode(mode);} + + +#ifndef _MSC_VER +protected: +#endif + + virtual bool init_gpios (); + + virtual bool get_cmd_set (); + + virtual bool set_bank_int (u_int32_t bank); + + virtual bool write_internal(u_int32_t addr, + u_int8_t data); + + enum FlashCmds { + IDLE = 0, + READ4 = (1<<29), + WRITE1 = (2<<29) + }; + + enum { + BANK_SHIFT = 19, + BANK_MASK = 0xfff80000 + }; + + enum { + FLASH = 0xf01a4, + ADDR_MSK = 0x7ffffUL, + CMD_MASK = 0xe0000000UL + }; + + enum { + LEN_MSK = 0x3ff, + LEN_SHIFT = 19 + }; + + enum { + CPUMODE_MSK = 0xc0000000UL, + CPUMODE_SHIFT = 30 + }; + + enum CrAddres { + CPUMODE = 0xf0150 + }; + + + // + // AMD's Am29LV033C command set + // + class CmdSetAmd : public Flash::CmdSet { + public: + CmdSetAmd (ParallelFlash& f ) : _f(f) {} + + virtual bool write (u_int32_t addr, + void* data, + int cnt, + bool noerase = false, + bool noverify = false); + + virtual bool erase_sector (u_int32_t addr); + virtual bool reset (); + + static void set_byte_mode (bool mode) {_byte_mode = mode;} + + protected: + ParallelFlash& _f; + + static bool _byte_mode; + + bool unlock_bypass (bool unlock); + }; + + + // + // Intel's 28F320J3 x8 command set, using buffer writes + // + class CmdSetIntel : public Flash::CmdSet { + public: + enum FlashCommand { + FC_ReadID = 0x90, + FC_Read = 0xFF, + FC_Erase = 0x20, + FC_Confirm = 0xD0, + FC_Clear = 0x50, + FC_Write = 0x40, + FC_LoadPB = 0xE0, + FC_PBWrite = 0x0C, + FC_Status = 0x70, + FC_Suspend = 0xB0, + FC_Resume = 0xD0, + FC_ReadESR = 0x71, + FC_QueryCFI = 0x98, + FC_SCSErase = 0x28, + FC_SCSWrite = 0xE8 + }; + + enum FlashStatus { + FS_Ready = 0x80, + FS_Suspended = 0x40, + FS_Error = 0x3E, + FS_BlockError = 0x3F + }; + + CmdSetIntel (ParallelFlash& f ) : _f(f) {} + + virtual bool write (u_int32_t addr, + void* data, + int cnt, + bool noerase = false, + bool noverify = false); + + virtual bool erase_sector (u_int32_t addr); + virtual bool reset (); + + protected: + ParallelFlash& _f; + }; + + // + // Intel's 28F320J3 x8 command set, using byte write (For debug only). + // + class CmdSetIntelWriteByte : public CmdSetIntel { + public: + CmdSetIntelWriteByte (ParallelFlash& f) : CmdSetIntel(f) {} + + virtual bool write (u_int32_t addr, + void* data, + int cnt, + bool noerase = false, + bool noverify = false); + + }; + + bool get_cfi (cfi_query *query); + + u_int16_t extract_word ( const u_int8_t* pb, int data_width) { + assert (data_width == 1 || data_width == 2); + u_int16_t ret = *pb | ((*(pb + data_width)) << 8); + return ret; + } + + u_int32_t USE_SCR; + bool _use_scr; + + // Place holders to keep GPIO data for restoring after closing flash. + u_int32_t _dir; + u_int32_t _pol; + u_int32_t _mod; + u_int32_t _data; + +}; + + +class SerialFlash : public Flash { +public: + SerialFlash() : Flash(20) {} + + enum CrAddres { + FLASH_GW = 0xf0400, + FLASH_ADDR = 0xf0404, + FLASH_DATA = 0xf0408, + FLASH_CS = 0xf0418, + + GPIO_LOCK = 0xf00ec + }; + + enum BitOffset { + READ_OP = 0, + ADDR_INCR = 1, + + LPC_STOP = 3, + SPI_NO_DATA = 4, + SPI_NO_ADDR = 5, + SPI_SPECIAL = 6, + + MSIZE_S = 8, + MSIZE_E = 10, + + STATUS_S = 26, + STATUS_E = 29, + + BUSY = 30, + + SPI_ADDR_S = 0, + SPI_ADDR_E = 23, + + SPI_CMD_S = 24, + SPI_CMD_E = 31, + + SPI_GPIO_S = 5, + SPI_GPIO_E = 7 + }; + + +protected: + + virtual bool write_internal(u_int32_t addr, + u_int8_t data); + +}; + +bool SerialFlash::write_internal (u_int32_t addr, + u_int8_t data) {addr = 0; data = 0; return true;} + + +class SpiFlash : public SerialFlash { +public: + SpiFlash() {} + ~SpiFlash() {close();} + + + // FBase Interface + + virtual void close (); + + virtual bool read (u_int32_t addr, + u_int32_t *data); + + virtual bool read (u_int32_t addr, + void* data, + int len, + bool verbose=false) {return Flash::read(addr, data, len, verbose);} + + virtual bool wait_ready (const char* msg); + +protected: + + virtual bool init_gpios (); + + virtual bool get_cmd_set (); + + virtual bool set_bank_int (u_int32_t bank); + + + virtual bool read_id (u_int8_t *data, u_int8_t cmd); + + + // + // ST's M25P80 command set + // + class CmdSetStSpi : public Flash::CmdSet { + public: + CmdSetStSpi (SpiFlash& f ) : _f(f) , _mf(f._mf){} + + virtual bool write (u_int32_t addr, + void* data, + int cnt, + bool noerase = false, + bool noverify = false); + + virtual bool erase_sector (u_int32_t addr); + + virtual bool reset () {return true;} + + enum FlashCommand { + FC_SE = 0xD8, + FC_PP = 0x02, + FC_RDSR = 0x05, + FC_WREN = 0x06, + FC_READ = 0x03, + FC_RDID = 0xF9, + FC_RES = 0xAB + }; + + + protected: + bool write_block (u_int32_t block_addr, + void* block_data, + u_int32_t block_size); + + bool wait_wip (u_int32_t delay, + u_int32_t retrys, + u_int32_t fast_retry = 0); + + bool write_enable (); + + + SpiFlash& _f; + mfile* _mf; + + }; + + bool fill_cfi (cfi_query *query); + +}; + + +//////////////////////////////////////////////////////////////////////// +// +// FImage Class Implementation +// +//////////////////////////////////////////////////////////////////////// + +bool FImage::open(const char *fname, bool read_only) +{ + int fsize; + int r_cnt; + FILE *fh; + + read_only = true; // FImage can be opened only for read + + fh = fopen(fname, "rb"); + + if (!fh) { + return errmsg("Can't open file \"%s\" - %s\n", fname, strerror(errno)); + } + + // Get the file size: + if (fseek(fh, 0, SEEK_END) < 0) { + return errmsg("Can't get file size for \"%s\" - %s\n", fname, strerror(errno)); + } + + fsize = ftell(fh); + if (fsize < 0) { + return errmsg("Can't get file size for \"%s\" - %s\n", fname, strerror(errno)); + } + rewind(fh); + + //printf("-D- %s size is %d\n", fname, fsize); + if (fsize & 0x3) { + return errmsg("Image size should be 4-bytes aligned. Make sure file %s is in the right format (binary image)", + fname); + } + + _buf = new u_int32_t[fsize/4]; + if ((r_cnt = fread(_buf, 1, fsize, fh)) != fsize) { + if (r_cnt < 0) + return errmsg("Read error on file \"%s\" - %s\n",fname, strerror(errno)); + else + return errmsg("Read error on file \"%s\" - read only %d bytes (from %ld)\n", + fname, r_cnt, (unsigned long)fsize); + } + + _len = fsize; + fclose(fh); + + return true; +} // FImage::open + +//////////////////////////////////////////////////////////////////////// +void FImage::close() +{ + delete [] _buf; + _buf = 0; +} // FImage::close + +//////////////////////////////////////////////////////////////////////// +bool FImage::read(u_int32_t addr, u_int32_t *data) +{ + return read(addr, data, 4); +} // FImage::read + +//////////////////////////////////////////////////////////////////////// +bool FImage::read(u_int32_t addr, void *data, int len, bool) +{ + if (addr & 0x3) { + return errmsg("Address should be 4-bytes aligned."); + } + if (len & 0x3) { + return errmsg("Length should be 4-bytes aligned."); + } + if (!_buf) { + return errmsg("read() when not opened"); + } + + if (addr + len > _len) { + return errmsg("Reading 0x%x bytes from address 0x%x is out of image limits (0x%x bytes)", + len, addr, _len); + } + + u_int32_t *p = (u_int32_t *)data; + for (int i=0; ireset(); + } + + return true; +} // Flash::open + +//////////////////////////////////////////////////////////////////////// +void Flash::close() +{ + if (!_mf) + return; + + delete _cmd_set; + + // ??? Check if unlock should be before delete _cmd_set + if (_locked) { + unlock(); + } + + mclose(_mf); + _mf = 0; + +} // Flash::close + + +bool Flash::lock(bool retry) { + + retry = false; // compiler - REMOVE ??? + + // Obtain GPIO Semaphore + u_int32_t cnt=0; + u_int32_t word; + do { + if (++cnt > GPIO_SEM_TRIES) { + return errmsg("Can not obtain Flash semaphore (63). You can run \"flint -clear_semaphore -d \" to force semaphore unlock. See help for details."); + } + MREAD4(SEMAP63, &word); + } // while (word); + // HACK! : On win 64, the semaphore reg, when read through pci (mmap), does not appear + // as 0x00000000 when cleared, but as 0xffffff00 , or 0xffff00ff . Could not find the + // reason for that. + // The hack is to treat anything which is NOT 0xffffffff or 0x1 as a free semaphore. + // Though ugly, this is safe. + while (word == 0xffffffff || word == 0x00000001); + + return true; +} + + +bool Flash::unlock() { + + // Free GPIO Semaphore + mwrite4(_mf, SEMAP63, 0); + return true; +} + + +//////////////////////////////////////////////////////////////////////// +bool Flash::read(u_int32_t addr, void *data, int len, bool verbose) +{ + u_int32_t perc = 0xffffffff; + + if (addr & 0x3) { + return errmsg("Address should be 4-bytes aligned."); + } + if (len & 0x3) { + return errmsg("Length should be 4-bytes aligned."); + } + + // Report + if (verbose) { + printf("000%%"); + fflush(stdout); + } + + u_int32_t *p = (u_int32_t *)data; + for (int i=0; i get_size()) { + return errmsg( + "Trying to write %d bytes to address 0x%x, which exceeds flash size (0x%x).", + cnt, + addr, + get_size()); + } + + return _cmd_set->write(addr, data, cnt, noerase, noverify); +} + + +//////////////////////////////////////////////////////////////////////// +bool Flash::write(u_int32_t addr, u_int32_t data) +{ + if (!_mf) { + return errmsg("Not opened"); + } + if (addr & 0x3) { + return errmsg("Address should be 4-bytes aligned."); + } + + // Here, we use non-virtual variants for efficiency + // TODO: Rewrite using get_sector_size() only + u_int32_t word; + u_int32_t sector_mask = _get_sector_mask(); + u_int32_t sector_size = _get_sector_size(); + + u_int32_t sector = addr & sector_mask; + u_int32_t word_in_sector = (addr & ~sector_mask)/sizeof(u_int32_t); + + if (!read(addr, &word)) + return false; + if (word == data) + return true; // already there + + vector buff(sector_size/sizeof(u_int32_t)); + if (!read(sector, &buff[0] , sector_size)) + return false; + buff[word_in_sector] = data; + return write(sector, &buff[0], sector_size); +} // Flash::write + +//////////////////////////////////////////////////////////////////////// + +inline +bool Flash::set_bank (u_int32_t addr) { + u_int32_t bank = (addr >> _log2_bank_size); + + if (bank != _curr_bank ) { + if (!set_bank_int(bank)) + return false; + + _curr_bank = bank; + } + + return true; +} + + +// A smaple function which loops through and prints out the data +// contained in the CFI query structure. Should ONLY be called +// after init_flash + +bool Flash::print_cfi_info() +{ + + const cfi_query *q = &_cfi_data; + + int i=0; + printf("\n"); + + char* head_fmt = "%-50s "; + + printf(head_fmt, "CFI Query String Read:"); + printf("[%s]\n", (char *) q->query_string); + + printf(head_fmt, "Primary table address at offset:"); + printf("[0x%2x] hex.\n", q->primary_table_address); + + printf(head_fmt, "Manufacturer ID, Device ID:"); + printf("[0x%02x,0x%02x] hex.\n", q->manuf_id, q->device_id ); + + printf(head_fmt, "Command set:"); + printf("[0x%04x] hex.\n", q->oem_command_set); + + printf(head_fmt, "Write buffer:"); + printf("[%d] bytes\n", q->max_multi_byte_write ); + + printf("\n----Voltage and Signal Timing Parameters-------------------\n"); + printf(head_fmt, "Vcc operating voltage:"); + printf("[%2.3f] to [%2.3f] Volts\n", q->vcc_min, q->vcc_max); + + + printf(head_fmt, "Vpp operating voltage:"); + if (q->vpp_min == 0.0) + printf("Device does not support Vpp voltage.\n"); + else { + printf("[%2.3f] to [%2.3f] Volts\n", q->vpp_min, q->vpp_max); + } + + printf(head_fmt, "Typical timeout for single write (micro-sec):"); + printf("[%8i]us\n", q->timeout_single_write); + + + + printf(head_fmt,"Typical timeout for single write (micro-sec):"); + if (q->timeout_buffer_write == 0x00) + printf("Buffer writes not supported in this device.\n"); + else { + printf("[%8i]us\n" ,q->timeout_buffer_write); + } + + printf(head_fmt, "Typical timeout for block erase (milli-sec):", q->timeout_block_erase); + printf("[%8i]ms\n", q->timeout_block_erase); + + printf(head_fmt, "Typical timeout for chip erase (milli-sec):"); + if (q->timeout_chip_erase == 0x00) + printf("Not supported in this device.\n"); + else { + printf("[%8i]ms\n", q->timeout_single_write); + } + + printf(head_fmt, "Maximum timeout for single write (micro-sec) :"); + printf("[%8i]us\n", q->max_timeout_single_write); + + printf(head_fmt, "Maximum timeout for buffer write (micro-sec) :"); + if (q->max_timeout_buffer_write == 0x00) + printf("Not supported in this device.\n"); + else { + printf("[%8i]us\n", q->max_timeout_buffer_write); + } + + printf(head_fmt, "Maximum timeout for block erase (milli-sec) :"); + printf("[%8i]ms\n", q->max_timeout_block_erase); + + printf(head_fmt, "Maximum timeout for chip erase (milli-sec) :"); + if (q->max_timeout_chip_erase == 0x00) + printf("Not supported in this device.\n"); + else { + printf("[%8i]ms\n", q->max_timeout_chip_erase); + } + + + + + printf("\n----Sector Organization Parameters-------------------\n\n"); + + printf(head_fmt, "Device size:"); + printf("[%8li] bytes, or [%2i] Mbit\n", + q->device_size, + (int) (q->device_size/((long)0x20000))); + + printf(head_fmt, "Number of erase block regions:"); + printf("%d\n",q->num_erase_blocks); + + for (i=0; inum_erase_blocks; i++) { + printf(" Size:[%8lx] bytes, Mask [%08x], [Number:[%4i]\n", + q->erase_block[i].sector_size, + q->erase_block[i].sector_mask, + q->erase_block[i].num_sectors); + } + + printf("\n----Primary Vendor-Specific Extended Parameters----\n\n"); + + printf(head_fmt, "CFI Extended String Read:"); + printf("[%s]\n", (char *) q->primary_extended_query); + + printf(head_fmt, "Major version:", q->major_version); + printf("[%3x]\n", q->major_version); + + printf(head_fmt, "Minor version:", q->minor_version); + printf("[%3x]\n", q->minor_version); + + printf(head_fmt, "Sensitive Unlock:", q->sensitive_unlock); + printf("[%3x]\n", q->sensitive_unlock); + + printf(head_fmt, "Erase Suspend:", q->erase_suspend); + printf("[%3x]\n", q->erase_suspend); + + printf(head_fmt, "Sector Protect:", q->sector_protect); + printf("[%3x]\n", q->sector_protect); + + printf(head_fmt, "Temporary Sector Unprotect:", q->sector_temp_unprotect); + printf("[%3x]\n", q->sector_temp_unprotect); + + printf(head_fmt, "Protection Scheme:", q->protect_scheme); + printf("[%3x]\n", q->protect_scheme); + + printf(head_fmt, "Is simultaneous? :", q->is_simultaneous); + printf("[%3x]\n", q->is_simultaneous); + + printf(head_fmt, "Is Burst capable? :", q->is_burst); + printf("[%3x]\n", q->is_burst); + + printf(head_fmt, "Is Page capable? :", q->is_page); + printf("[%3x]\n", q->is_page); + + printf("Done.\n\n"); + + return true; +} // Flash::print_cfi_info() + + + +//////////////////////////////////////////////////////////////////////// +// +// ParallelFlash Class Implementation +// +//////////////////////////////////////////////////////////////////////// + +ParallelFlash::ParallelFlash() : Flash(19) +{ + char *use_scr_p = getenv("FLINT_USE_SCRATCHPAD"); + + if (use_scr_p) { + char *endp; + + USE_SCR = strtoul(use_scr_p, &endp, 0); + if (*endp) { + printf("Invalid FLINT_USE_SCRATCHPAD syntax (%s). Must be integer.", + use_scr_p); + _use_scr = false; + } else { + printf("Burning via SCRATCHPAD interface by addr 0x%x\n", USE_SCR); + _use_scr = true; + } + } else + _use_scr = false; +} // Flash::Flash + + + +//////////////////////////////////////////////////////////////////////// +bool ParallelFlash::init_gpios() { + + // Save old values + MREAD4(GPIO_DIR_L, &_dir); + MREAD4(GPIO_POL_L, &_pol); + MREAD4(GPIO_MOD_L, &_mod); + MREAD4(GPIO_DAT_L, &_data); + + // Set Direction=1, Polarity=0, Mode=0 for 3 GPIO lower bits + u_int32_t dir = _dir | 0x70; + u_int32_t pol = _pol & ~0x70; + u_int32_t mod = _mod & ~0x70; + MWRITE4(GPIO_DIR_L, dir); + MWRITE4(GPIO_POL_L, pol); + MWRITE4(GPIO_MOD_L, mod); + + // Set CPUMODE + u_int32_t word; + MREAD4(CPUMODE, &word); + word &= ~CPUMODE_MSK; + word |= 1 << CPUMODE_SHIFT; + MWRITE4(CPUMODE, word); + + return true; +} + +void ParallelFlash::close() { + + // Restore origin values + mwrite4(_mf, GPIO_DIR_L, _dir); + mwrite4(_mf, GPIO_POL_L, _pol); + mwrite4(_mf, GPIO_MOD_L, _mod); + mwrite4(_mf, GPIO_DAT_L, _data); + + _curr_bank = 0xffffffff; + + Flash::close(); +} + + +bool ParallelFlash::get_cmd_set() { + + // + // CFI Query + // + if (!get_cfi(&_cfi_data)) + return false; + + // + // Some sanity checks: + // + + if (_cfi_data.max_multi_byte_write > MAX_WRITE_BUFFER_SIZE) { + return errmsg("Device write buffer(%d) is larger than the supported size(%d).", + _cfi_data.max_multi_byte_write, MAX_WRITE_BUFFER_SIZE); + } + + if (!_mx_flash_workaround() && _cfi_data.num_erase_blocks > 1) { + return errmsg("Device has more than one sector size - not supported by this tool"); + } + + // + // Sellect CmdSet + // + + switch (_cfi_data.oem_command_set) { + case CS_INTEL: + if (_byte_write || _cfi_data.max_multi_byte_write == 0) + _cmd_set = new CmdSetIntelWriteByte(*this); + else + _cmd_set = new CmdSetIntel(*this); + break; + case CS_AMD: + _cmd_set = new CmdSetAmd(*this); + break; + + default: + return errmsg("Unknown CFI command set (%d)",_cfi_data.oem_command_set) ; + } + + return true; +} + + + +//////////////////////////////////////////////////////////////////////// +bool ParallelFlash::set_bank_int(u_int32_t bank) +{ + if (!_mf) { + return errmsg("Not opened"); + } + + //printf("\n*** Flash::set_bank(0x%lx) : 0x%lx\n", bank, (bank >> 19) & 0x07); + MWRITE4(GPIO_DATACLEAR_L, 0x70); + MWRITE4(GPIO_DATASET_L, (bank << 4) & 0x70); + + return true; +} // Flash::ParallelFlashGw::set_bank_int + + +//////////////////////////////////////////////////////////////////////// +bool ParallelFlash::wait_ready(const char* msg) { + u_int32_t cnt = 0; + u_int32_t cmd; + do { + // Timeout checks + if (++cnt > FLASH_CMD_CNT) { + return errmsg("Flash gateway timeout: %s", msg); + } + + MREAD4(FLASH, &cmd); + + } while (cmd & CMD_MASK); + + return true; +} + +//////////////////////////////////////////////////////////////////////// +bool ParallelFlash::read(u_int32_t addr, u_int32_t *data) +{ + if (!_mf) { + return errmsg("Not opened"); + } + + u_int32_t cmd; + if (addr & 0x3) { + return errmsg("Address should be 4-bytes aligned."); + } + + if (!set_bank(addr)) + return false; + + + MWRITE4(FLASH, READ4 | (addr & ADDR_MSK)); + + if (!wait_ready("Read")) + return false; + + MREAD4(FLASH+4, &cmd); + cmd = __cpu_to_be32(cmd); + memcpy(data, &cmd, sizeof(u_int32_t)); + + return true; +} // Flash::read + +//////////////////////////////////////////////////////////////////////// +bool ParallelFlash::write_internal(u_int32_t addr, u_int8_t data) +{ + MWRITE4(FLASH+4, data << 24); + MWRITE4(FLASH, WRITE1 | (addr & ADDR_MSK)); + + if (!wait_ready("Write")) + return false; + + return true; +} // Flash::write_internal + + +//////////////////////////////////////////////////////////////////////// +bool ParallelFlash::CmdSetAmd::unlock_bypass(bool unlock) { + + if (unlock) { + // unlock bypass + + if (!_f.write_internal(0x555, 0xaa)) + return false; + if (!_f.write_internal(0x2aa, 0x55)) + return false; + if (!_f.write_internal(0x555, 0x20)) + return false; + } else { + // unlock reset + if (!_f.write_internal(0x555, 0x90)) + return false; + if (!_f.write_internal(0x2aa, 0x00)) + return false; + } + return true; +} + + +//////////////////////////////////////////////////////////////////////// + +bool ParallelFlash::CmdSetAmd::_byte_mode = false; + +bool ParallelFlash::CmdSetAmd::write(u_int32_t addr, void *data, int cnt, + bool noerase, bool noverify) +{ + if (!_f._mf) { + return _f.errmsg("Not opened"); + } + if (addr & 0x3) { + return _f.errmsg("Address should be 4-bytes aligned."); + } + + char *p = (char *)data; + + if (_unlock_bypass) { + if (!unlock_bypass(true)) { + return _f.errmsg("Failed unlock bypass"); + } + } + + for (int i=0; i FLASH_CMD_CNT) { + return _f.errmsg("Use scratchpad: CMD doesn't become zero"); + } + if (mread4(_f._mf, _f.USE_SCR , &cmd) != 4) return false; + + } while (cmd & CMD_MASK); + i += 3; + addr += 3; + } else if ((u_int8_t)(*p) != 0xff) { + + if (_byte_mode) { + + if (!_f.write_internal(0xaaa, 0xaa)) + return false; + if (!_f.write_internal(0x555, 0x55)) + return false; + if (!_f.write_internal(0xaaa, 0xa0)) + return false; + } else { + if (!_unlock_bypass) { + if (!_f.write_internal(0x555, 0xaa)) + return false; + if (!_f.write_internal(0x2aa, 0x55)) + return false; + } + + if (!_f.write_internal(0x555, 0xa0)) + return false; + } + + if (!_f.write_internal(addr, *p++)) + return false; + + do { + // Timeout checks + if (++cnt1 > READ_CNT_FAST) + usleep(READ_DELAY); + if (cnt1 > READ_CNT_FAST + READ_CNT_SLOW) { + return _f.errmsg("Flash write error - read value didn't stabilize."); + return false; + } + + if (!_f.read(addr & ~3, &word)) + return false; + + word = __be32_to_cpu(word); + act = (u_int8_t) ((word >> ((3 - (addr & 3)) * 8)) & 0xff); + exp = *(p-1) & 0xff; + //if (act != exp) + // printf("write: %08x - exp:%02x act:%02x /%08x/\n", + // addr, exp & 0xff, act & 0xff, word); + } while (!noverify && act != exp); + + } else { + p++; + } + } + + if (_unlock_bypass) { + if (!unlock_bypass(false)) { + return _f.errmsg("Failed re-lock bypass"); + } + } + + return true; +} // flash_write + + + +bool ParallelFlash::CmdSetIntelWriteByte::write(u_int32_t addr, void *data, int cnt, + bool noerase, bool noverify) +{ + if (!_f._mf) { + return _f.errmsg("Not opened"); + } + if (addr & 0x3) { + return _f.errmsg("Address should be 4-bytes aligned."); + } + + char *p = (char *)data; + + for (int i=0; i READ_CNT_FAST) + usleep(READ_DELAY); + if (cnt1 > READ_CNT_FAST + READ_CNT_SLOW) { + return _f.errmsg("Flash write error - timeout waiting for ready after write."); + } + + // TODO - Move to read single for Arbel + if (!_f.read(addr & ~3, &status)) + return false; + + //if (act != exp) + // printf("write: %08x - exp:%02x act:%02x /%08x/\n", + // addr, exp & 0xff, act & 0xff, word); + } while ((status & FS_Ready) == 0); + + if (status & FS_Error) { + return _f.errmsg("Flash write error - error staus detected."); + } + + if (!noverify) { + u_int32_t word; + if (!reset()) + return false; + // TODO - Move to read single for Arbel + if (!_f.read(addr & ~3, &word)) + return false; + + word = __be32_to_cpu(word); + act = (u_int8_t) ((word >> ((3 - (addr & 3)) * 8)) & 0xff); + exp = *(p-1) & 0xff; + + if (act != exp) { + printf("write: %08x - exp:%02x act:%02x /%08x/\n", + addr, exp & 0xff, act & 0xff, word); + + return _f.errmsg("Write verification failed"); + } + } + + } else { + p++; + } + } + + if (!reset()) + return false; + + return true; +} // flash_write + +/////////////////////////////////////////////////////////////////////////// + +// +// Use the buffer write capability. +// +bool ParallelFlash::CmdSetIntel::write(u_int32_t addr, void *data, int cnt, + bool noerase, bool noverify) +{ + if (!_f._mf) { + return _f.errmsg("Not opened"); + } + if (addr & 0x3) { + return _f.errmsg("Address should be 4-bytes aligned."); + } + + u_int8_t *p = (u_int8_t *)data; + + u_int32_t block_size = _f._cfi_data.max_multi_byte_write; + u_int32_t block_mask = ~(block_size - 1 ); + + // TODO - Check MAX_WRITE_BUFFER_SIZE against block_size in open (or here) + u_int8_t tmp_buff[MAX_WRITE_BUFFER_SIZE]; + + while (cnt) { + + u_int32_t prefix_pad_size = 0; + u_int32_t suffix_pad_size = 0; + + u_int32_t block_addr = addr & block_mask; + u_int32_t data_size = block_size; + + u_int8_t* write_data = p; + + + // + // First and last cycles (can be the same one) may not be block aligned. + // Check the status, and copy data to a padded temp bufer if not alligned. + // (there's an option to write partial buffer, but Intel reference code always + // writes full buffer, with pads if needed. I do the dame ...) + // + + prefix_pad_size = addr - block_addr; + + if ((addr & block_mask) == ((addr + cnt) & block_mask)) { + suffix_pad_size = block_size - ((addr + cnt) % block_size); + } + + if (suffix_pad_size || prefix_pad_size) { + memset(tmp_buff, 0xff, block_size); + + data_size -= prefix_pad_size; + data_size -= suffix_pad_size; + + memcpy(tmp_buff + prefix_pad_size, p , data_size); + + write_data = tmp_buff; + } + + int cnt1 = 0; + + // + // Bank setup. + // + if (!_f.set_bank(addr)) + return false; + + if (!noerase) { + u_int32_t sector = (addr / _f.get_sector_size()) * _f.get_sector_size(); + if (sector != _curr_sector) { + _curr_sector = sector; + if (!erase_sector(_curr_sector)) + return false; + } + } + + if (_no_burn) + continue; + + // + // Check to see if there's something to do + // + bool all_ffs = true; + for (u_int32_t i = 0; i < block_size ; i++) { + if (write_data[i] != 0xff) { + all_ffs = false; + break; + } + } + + if (!all_ffs) { + + u_int32_t status; + cnt1 = 0; + do { + // Get Write buffer + if (!_f.write_internal(block_addr, FC_SCSWrite)) + return false; + + if (cnt1 > ((READ_CNT_FAST + READ_CNT_SLOW) * 4)) { + //printf("-D- status = %08x\n", status); + reset(); + return _f.errmsg("Flash write error - Write buffer not ready."); + } + + cnt1++; + + if (!_f.read(block_addr, &status)) + return false; + + } while (!(status & FS_Ready)); + + if (status & FS_Error) { + return _f.errmsg("Flash write error - Error getting write buffer"); + } + + // word count (allways full buffer, coded as cull buffer size -1) + if (!_f.write_internal(block_addr, block_size - 1)) + return false; + + // Write data to buffer + for (u_int32_t i = 0; i < block_size ; i++ ) { + if (!_f.write_internal(block_addr + i, write_data[i])) + return false; + } + + // write confirm + if (!_f.write_internal(block_addr, FC_Confirm)) + return false; + + cnt1 = 0; + do { + // Timeout checks + if (++cnt1 > READ_CNT_FAST) + usleep(READ_DELAY); + if (cnt1 > READ_CNT_FAST + READ_CNT_SLOW) { + reset(); + return _f.errmsg("Flash write error - Write buffer status timeout"); + } + + // TODO - Move to read single for Arbel + if (!_f.read(block_addr, &status)) + return false; + + //if (act != exp) + // printf("write: %08x - exp:%02x act:%02x /%08x/\n", + // addr, exp & 0xff, act & 0xff, word); + } while ((status & 0x80) == 0); + + // + // TODO: Status checks. + // + + if (!noverify) { + u_int8_t verify_buffer[MAX_WRITE_BUFFER_SIZE]; + if (!reset()) + return false; + + if (!_f.read(addr, verify_buffer, data_size)) + return false; + + for (u_int32_t i = 0 ; i < data_size ; i++) { + if (verify_buffer[i] != write_data[i + prefix_pad_size]) { + return _f.errmsg( + "Write verification failed. Addr: %08x - exp:%02x act:%02x", + addr + i, + write_data[i + prefix_pad_size] , + verify_buffer[i]); + } + } + } + } + + + // + // loop advance + // + + addr += data_size; + p += data_size; + cnt -= data_size; + } + + if (!reset()) + return false; + + return true; +} // flash_write + +//////////////////////////////////////////////////////////////////////// +bool ParallelFlash::CmdSetAmd::reset() { + if (!_f.write_internal(0x555, 0xf0)) { + return _f.errmsg("Device reset failed: %s", _f.err()); + } + return true; +} + +//////////////////////////////////////////////////////////////////////// +bool ParallelFlash::CmdSetAmd::erase_sector(u_int32_t addr) +{ + u_int32_t word = 0; + int cnt = 0; + + if (_no_erase) + return true; + + // Just to insure zeroes because erase completion waits for ones + if (!write(addr, &word, sizeof(word), true)) + return false; + + // erase sector sequence + if (_byte_mode ) { + + if (!_f.write_internal(0xaaa, 0xaa)) + return false; + if (!_f.write_internal(0x555, 0x55)) + return false; + if (!_f.write_internal(0xaaa, 0x80)) + return false; + if (!_f.write_internal(0xaaa, 0xaa)) + return false; + if (!_f.write_internal(0x555, 0x55)) + return false; + if (!_f.write_internal(addr, 0x30)) + return false; + } else { + + if (!_f.write_internal(0x555, 0xaa)) + return false; + if (!_f.write_internal(0x2aa, 0x55)) + return false; + if (!_f.write_internal(0x555, 0x80)) + return false; + if (!_f.write_internal(0x555, 0xaa)) + return false; + if (!_f.write_internal(0x2aa, 0x55)) + return false; + if (!_f.write_internal(addr, 0x30)) + return false; + + } + + // Wait while erase completes + do { + // Timeout checks + if (++cnt > ERASE_CNT) { + return _f.errmsg("Flash erase sector timeout"); + } + if (!_f.read(addr, &word)) + return false; + + //printf("erase_sector: addr:%08lx, %08x\n", addr, word); + usleep(ERASE_DELAY); + } while (word != 0xffffffff); + + + return true; +} // Flash::erase_sector + +//////////////////////////////////////////////////////////////////////// + +bool ParallelFlash::CmdSetIntel::reset() { + if (!_f.write_internal(0x555, FC_Read)) { + return _f.errmsg("Device reset failed"); + } + return true; +} + +//////////////////////////////////////////////////////////////////////// +bool ParallelFlash::CmdSetIntel::erase_sector(u_int32_t addr) +{ + u_int32_t status = 0; + int cnt = 0; + + if (_no_erase) + return true; + + // Just to insure zeroes because erase completion waits for ones + //if (!write(addr, &word, sizeof(word), true)) + // return false; + + // Erase command + if (!_f.write_internal(addr, FC_Erase)) + return false; + + // Erase confirm + if (!_f.write_internal(addr, FC_Confirm)) + return false; + + usleep(ERASE_DELAY); + + // Wait while erase completes + do { + // Timeout checks + if (++cnt > ERASE_CNT) { + return _f.errmsg("Flash erase sector timeout"); + } + if (!_f.read(addr, &status)) + return false; + + //printf("CmdSetIntel::erase_sector: addr:%08lx, %08x\n", addr, word); + usleep(ERASE_DELAY); + } while ((status & FS_Ready) == 0); + + if (status & FS_Error) { + return _f.errmsg("Status register detected erase error (0x%x)", status & FS_Error); + } + + // Reset + if (!reset()) + return false; + + return true; +} // ParallelFlash::CmdSetIntel::erase_sector + +//******************************************************************* +// flash_get_cfi() is the main CFI workhorse function. Due to it's +// complexity and size it need only be called once upon +// initializing the flash system. Once it is called, all operations +// are performed by looking at the cfi_query structure. +// All possible care was made to make this algorithm as efficient as +// possible. 90% of all operations are memory reads, and all +// calculations are done using bit-shifts when possible +//******************************************************************* + +bool ParallelFlash::get_cfi(struct cfi_query *query) +{ + + enum { + TOTAL_QUERY_SIZE = 1024, + EXTENDED_QUERY_SIZE = 12 + }; + + u_int8_t fwp[TOTAL_QUERY_SIZE]; // flash window + + int volts=0, milli=0, temp=0, i=0; + int offset=0; + + u_int32_t query_base = 0x10; + + // Initial house-cleaning + memset(fwp, 0xff, TOTAL_QUERY_SIZE); + + for (i=0; i < 8; i++) { + query->erase_block[i].sector_size = 0; + query->erase_block[i].num_sectors = 0; + } query->erase_block[i].sector_mask = 0; + + // reset + if (!write_internal(0x55, 0xff)) + return false; + + // CFI QUERY + if (!write_internal(0x55, 0x98)) + return false; + + char query_str_x8[4]; + char query_str_x16asx8[8]; + + if (!read(0x10, query_str_x8, 0x4)) + return false; + + if (!read(0x20, query_str_x16asx8, 0x8)) + return false; + + query_str_x8[3] = '\0'; + query_str_x16asx8[7] = '\0'; + + if ( strncmp( query_str_x8 , "QRY" ,3 ) == 0) { + // x8 CFI flash (AMD) + query_base = 1; + } else if ( query_str_x16asx8[0] == 'Q' && + query_str_x16asx8[2] == 'R' && + query_str_x16asx8[4] == 'Y') { + // x16 CFI flash worqing in x8 mode + query_base = 2; + } else { + + printf(" Received CFI query from addr 0x10: [%s]\n", query_str_x8 ); + printf(" Received CFI query from addr 0x20: [%s]\n", query_str_x16asx8); + + return errmsg("Failed CFI query"); + } + + if (!read(0x0, fwp, 0x4)) // Dev ID + return false; + + if (!read(query_base * 0x10, fwp + query_base * 0x10, query_base * 0x20)) + return false; + + query->manuf_id = fwp[query_base * 0]; + query->device_id = fwp[query_base * 1]; + + query->query_string[0] = fwp[query_base * 0x10]; + query->query_string[1] = fwp[query_base * 0x11]; + query->query_string[2] = fwp[query_base * 0x12]; + query->query_string[3] = '\0'; + + query->oem_command_set = extract_word(fwp + query_base * 0x13, query_base); + query->primary_table_address = extract_word(fwp + query_base * 0x15, query_base); // Important one! + query->alt_command_set = extract_word(fwp + query_base * 0x17, query_base); + query->alt_table_address = extract_word(fwp + query_base * 0x19, query_base); + + // We will do some bit translation to give the following values + // numerical meaning in terms of C 'float' numbers + + volts = ((fwp[query_base * 0x1B] & 0xF0) >> 4); + milli = ( fwp[query_base * 0x1B] & 0x0F); + query->vcc_min = (float) (volts + ((float)milli/10)); + + volts = ((fwp[query_base * 0x1C] & 0xF0) >> 4); + milli = ( fwp[query_base * 0x1C] & 0x0F); + query->vcc_max = (float) (volts + ((float)milli/10)); + + volts = ((fwp[query_base * 0x1D] & 0xF0) >> 4); + milli = ( fwp[query_base * 0x1D] & 0x0F); + query->vpp_min = (float) (volts + ((float)milli/10)); + + volts = ((fwp[query_base * 0x1E] & 0xF0) >> 4); + milli = ( fwp[query_base * 0x1E] & 0x0F); + query->vpp_max = (float) (volts + ((float)milli/10)); + + // Let's not drag in the libm library to calculate powers + // for something as simple as 2^(power) + // Use a bit shift instead - it's faster + + temp = fwp[query_base * 0x1F]; + query->timeout_single_write = (1 << temp); + + temp = fwp[query_base * 0x20]; + if (temp != 0x00) + query->timeout_buffer_write = (1 << temp); + else + query->timeout_buffer_write = 0x00; + + temp = 0; + temp = fwp[query_base * 0x21]; + query->timeout_block_erase = (1 << temp); + + temp = fwp[query_base * 0x22]; + if (temp != 0x00) + query->timeout_chip_erase = (1 << temp); + else + query->timeout_chip_erase = 0x00; + + temp = fwp[query_base * 0x23]; + query->max_timeout_single_write = (1 << temp) * + query->timeout_single_write; + + temp = fwp[query_base * 0x24]; + if (temp != 0x00) + query->max_timeout_buffer_write = (1 << temp) * + query->timeout_buffer_write; + else + query->max_timeout_buffer_write = 0x00; + + temp = fwp[query_base * 0x25]; + query->max_timeout_block_erase = (1 << temp) * + query->timeout_block_erase; + + temp = fwp[query_base * 0x26]; + if (temp != 0x00) + query->max_timeout_chip_erase = (1 << temp) * + query->timeout_chip_erase; + else + query->max_timeout_chip_erase = 0x00; + + temp = fwp[query_base * 0x27]; + query->device_size = (long) (((long)1) << temp); + + query->interface_description = extract_word(fwp + query_base * 0x28, query_base); + + temp = fwp[query_base * 0x2A]; + if (temp != 0x00) + query->max_multi_byte_write = (1 << temp); + else + query->max_multi_byte_write = 0; + + query->num_erase_blocks = fwp[query_base * 0x2C]; + + if (!read(query_base * 0x2C, fwp + query_base * 0x2C ,query_base * 4 * (query->num_erase_blocks + 1))) + return false; + + for (i=0; i < query->num_erase_blocks; i++) { + query->erase_block[i].num_sectors = extract_word(fwp + query_base * (0x2D+(4*i)), query_base); + query->erase_block[i].num_sectors++; + + query->erase_block[i].sector_size = (long) 256 * + ( (long)256 * fwp[(query_base * (0x30+(4*i)))] + + fwp[(query_base * (0x2F+(4*i)))] ); + + query->erase_block[i].sector_mask = ~(query->erase_block[i].sector_size - 1); + } + + // Store primary table offset in variable for clarity + offset = query->primary_table_address; + + if ((offset + EXTENDED_QUERY_SIZE) * query_base > TOTAL_QUERY_SIZE) { + return errmsg("Primary extended query larger than TOTAL_QUERY_SIZE (%d)",TOTAL_QUERY_SIZE) ; + } + + + // DEBUG: + //printf("Raw Cfi query:\n"); + //printf(" 0123456789abcdef_123456789abcdef_123456789abcdef\n "); + //for (u_int32_t i = 0x10 * query_base ; i <= (0x30 * query_base); i+= query_base) { + // printf("%02x", fwp[i]); + //} + //printf("\n"); + + u_int32_t dw_aligned_offs = (((offset * query_base) >> 2 ) << 2); + + if (!read(dw_aligned_offs , fwp + dw_aligned_offs , EXTENDED_QUERY_SIZE * query_base)) + return false; + + query->primary_extended_query[0] = fwp[query_base * (offset)]; + query->primary_extended_query[1] = fwp[query_base * (offset + 1)]; + query->primary_extended_query[2] = fwp[query_base * (offset + 2)]; + query->primary_extended_query[3] = '\0'; + + if ( query->primary_extended_query[0] != 'P' && + query->primary_extended_query[1] != 'R' && + query->primary_extended_query[2] != 'I') { + return errmsg("Bad primary table address in CFI query"); + } + + query->major_version = fwp[query_base * (offset + 3)]; + query->minor_version = fwp[query_base * (offset + 4)]; + + query->sensitive_unlock = (u_int8_t) (fwp[query_base * (offset+5)] & 0x0F); + query->erase_suspend = (u_int8_t) (fwp[query_base * (offset+6)] & 0x0F); + query->sector_protect = (u_int8_t) (fwp[query_base * (offset+7)] & 0x0F); + query->sector_temp_unprotect = (u_int8_t) (fwp[query_base * (offset+8)] & 0x0F); + query->protect_scheme = (u_int8_t) (fwp[query_base * (offset+9)] & 0x0F); + query->is_simultaneous = (u_int8_t) (fwp[query_base * (offset+10)] & 0x0F); + query->is_burst = (u_int8_t) (fwp[query_base * (offset+11)] & 0x0F); + query->is_page = (u_int8_t) (fwp[query_base * (offset+12)] & 0x0F); + + return true; +} + + + +//////////////////////////////////////////////////////////////////////// +// +// SpiFlash Class Implementation +// +//////////////////////////////////////////////////////////////////////// + +bool SpiFlash::init_gpios() { + + // + // Set Multi SPI CS to output and 0. + // Assuming 4 flashes. If there are less than 4 flashes and there's + // a write attempt, it will fail. + // + + u_int32_t num_of_spis = 4; + u_int32_t spi_en = (1 << (num_of_spis - 1 ) ) -1; + + u_int32_ba dir; + u_int32_ba mod; + u_int32_ba pol; + + // No need to set the data - SPI GW CS does that in HW + //MREAD4(GPIO_DAT_L, &data); + + MREAD4(GPIO_DIR_L, &dir); + MREAD4(GPIO_POL_L, &pol); + MREAD4(GPIO_MOD_L, &mod); + + dir.range (SPI_GPIO_E, SPI_GPIO_S) = spi_en; + pol.range (SPI_GPIO_E, SPI_GPIO_S) = ~spi_en; + mod.range(SPI_GPIO_E, SPI_GPIO_S) = ~spi_en; + + // unlock gpio + MWRITE4(GPIO_LOCK , 0xaaaa); + + MWRITE4(GPIO_DIR_L, dir); + MWRITE4(GPIO_POL_L, pol); + MWRITE4(GPIO_MOD_L, mod); + + return true; +} + +void SpiFlash::close() { + // Chip reset does not reset the chip sellect - Make sure after reset + // boot loads FW from SPI 0. + set_bank(0); + + // unlock gpio + mwrite4(_mf, GPIO_LOCK , 0xaaaa); +} + +bool SpiFlash::get_cmd_set () { + + // + // Read device ID and allocate command set accordingly. + // + + // + // Initiate some CFI fields to mimic cfi query procedure of parallel flash: + // + + _cfi_data.max_multi_byte_write = 16; // In SPI context, this is the transaction size. Max is 16. + _cfi_data.num_erase_blocks = 1; + _cfi_data.erase_block[0].sector_size = 64 * 1024; + _cfi_data.erase_block[0].sector_mask = ~(_cfi_data.erase_block[0].sector_size - 1); + + u_int32_t spi_size = 0; + u_int32_t num_spis = 0; + + for (u_int32_t spi_sel = 0 ; spi_sel < 4 ; spi_sel++) { + if (!set_bank_int(spi_sel)) return false; + + unsigned char es; // electronic signature + u_int32_t cur_spi_size = 0; + + if (!read_id(&es, CmdSetStSpi::FC_RES)) return false; + + if (es >= 0x10 && es < 0x16) { + // Range OK: + + // NOTE: This mapping between electronic signature and device size is device specific! + // This mapping works for ST M25Pxx and Saifun SA25Fxxx families. + cur_spi_size = 1 << (es + 1); + + num_spis++; + + if (spi_sel == 0) { + spi_size = cur_spi_size; + } else if (cur_spi_size != spi_size){ + return errmsg("SPI flash #%d of size 0x%x bytes differs in size from SPI flash #%d of size 0x%x bytes. " + "All flash devices must be of the same size.", + spi_sel, + cur_spi_size, + spi_sel - 1, + spi_size); + } + + + } else if (es == 0xff) { + // No spi device on this chip_select + break; + } else { + return errmsg("Unexpected SPI electronic signature value (0x%2x) when detecting flash size. " + "Flash #%d my be defected.", + es, + spi_sel); + } + + // printf("-D- %3d %08x\n", spi_sel, cur_spi_size); + } + + _cfi_data.device_size = spi_size * num_spis; + _log2_bank_size = log2up(spi_size); + + + _cmd_set = new CmdSetStSpi(*this); + + return true; +} + + +bool SpiFlash::set_bank_int(u_int32_t bank) +{ + if (!_mf) { + return errmsg("Not opened"); + } + + // TODO: Check number of banks in open! + if (bank > 3) { + return errmsg("Tried to set bank to %d but %d is the is the largest bank number", bank, 3); + } + + //printf("\n*** Flash::set_bank(0x%lx) : 0x%lx\n", bank, (bank >> 19) & 0x07); + u_int32_ba flash_cs; + flash_cs.range(31,30) = bank; + MWRITE4(FLASH_CS, flash_cs); + + return true; +} // Flash::SpiFlash::set_bank + + +//////////////////////////////////////////////////////////////////////// +bool SpiFlash::wait_ready(const char* msg) +{ + u_int32_ba gw_cmd = 0; + u_int32_t cnt = 0; + do { + // Timeout checks + if (++cnt > FLASH_CMD_CNT) { + return errmsg("Flash gateway timeout: %s.", msg); + } + + MREAD4(FLASH_GW, &gw_cmd); + + } while (gw_cmd[BUSY]); + + return true; +} + + +//////////////////////////////////////////////////////////////////////// +bool SpiFlash::read(u_int32_t addr, u_int32_t *data) +{ + if (!_mf) { + return errmsg("Not opened"); + } + + if (addr & 0x3) { + return errmsg("Address should be 4-bytes aligned."); + } + + if (!set_bank(addr)) + return false; + + + // + // Prepare command word + // + + u_int32_ba gw_cmd; + u_int32_ba gw_addr; + + gw_cmd[BUSY] = 1; + gw_cmd[READ_OP] = 1; + //gw_cmd[ADDR_INCR] = 0; + + gw_cmd.range(MSIZE_E, MSIZE_S) = 2; + + gw_addr.range(SPI_ADDR_E, SPI_ADDR_S) = addr & bank_mask(); + + MWRITE4(FLASH_ADDR, gw_addr); + MWRITE4(FLASH_GW, gw_cmd); + + if (!wait_ready("Read")) + return false; + + MREAD4(FLASH_DATA, data); + + *data = __cpu_to_be32(*data); + + return true; +} // SpiFlash::read + + +//////////////////////////////////////////////////////////////////////// +bool SpiFlash::read_id(u_int8_t *data, u_int8_t cmd) +{ + + // + // Prepare command word + // + + u_int32_ba gw_cmd; + u_int32_ba gw_addr; + u_int32_t flash_data; + + gw_cmd[BUSY] = 1; + gw_cmd[READ_OP] = 1; + gw_cmd[SPI_SPECIAL] = 1; + gw_cmd[SPI_NO_ADDR] = 1; + + gw_cmd.range(MSIZE_E, MSIZE_S) = 2; + + gw_addr.range(SPI_CMD_E, SPI_CMD_S) = cmd; + + MWRITE4(FLASH_ADDR, gw_addr); + MWRITE4(FLASH_GW, gw_cmd); + + if (!wait_ready("Read id")) + return false; + + MREAD4(FLASH_DATA, &flash_data); + + /* ID is at offset 3 in word */ + *data = (u_int8_t)(flash_data & 0xff); + + //printf("-D- ES is %02x\n", *data); + + return true; +} // SpiFlash::read + +// +// TODO: Unify all the block handling code with the CmdSet001 write. +// + +bool SpiFlash::CmdSetStSpi::write (u_int32_t addr, + void* data, + int cnt, + bool noerase, + bool noverify) { + + if (!_f._mf) { + return _f.errmsg("Not opened"); + } + if (addr & 0x3) { + return _f.errmsg("Address should be 4-bytes aligned."); + } + + u_int8_t *p = (u_int8_t *)data; + + u_int32_t block_size = _f._cfi_data.max_multi_byte_write; + u_int32_t block_mask = ~(block_size - 1 ); + + // TODO - Check MAX_WRITE_BUFFER_SIZE against block_size in open (or here) + u_int8_t tmp_buff[MAX_WRITE_BUFFER_SIZE]; + + while (cnt) { + + u_int32_t prefix_pad_size = 0; + u_int32_t suffix_pad_size = 0; + + u_int32_t block_addr = addr & block_mask; + u_int32_t data_size = block_size; + + u_int8_t* block_data = p; + + + // + // First and last cycles (can be the same one) may not be block aligned. + // Check the status, and copy data to a padded temp bufer if not alligned. + // (there's an option to write partial buffer, but Intel reference code always + // writes full buffer, with pads if needed. I do the dame ...) + // + + prefix_pad_size = addr - block_addr; + + if ((addr & block_mask) == ((addr + cnt) & block_mask)) { + suffix_pad_size = block_size - ((addr + cnt) % block_size); + } + + if (suffix_pad_size || prefix_pad_size) { + memset(tmp_buff, 0xff, block_size); + + data_size -= prefix_pad_size; + data_size -= suffix_pad_size; + + memcpy(tmp_buff + prefix_pad_size, p , data_size); + + block_data = tmp_buff; + } + + // + // Bank setup. + // + if (!_f.set_bank(addr)) + return false; + + if (!noerase) { + u_int32_t sector = (addr / _f.get_sector_size()) * _f.get_sector_size(); + if (sector != _curr_sector) { + _curr_sector = sector; + if (!erase_sector(_curr_sector)) + return false; + } + } + + if (_no_burn) + continue; + + // + // Check to see if there's something to do + // + bool all_ffs = true; + for (u_int32_t i = 0; i < block_size ; i++) { + if (block_data[i] != 0xff) { + all_ffs = false; + break; + } + } + + if (!all_ffs) { + + write_block(block_addr, block_data, block_size); + + if (!noverify) { + u_int8_t verify_buffer[MAX_WRITE_BUFFER_SIZE]; + if (!reset()) + return false; + + if (!_f.read(addr, verify_buffer, data_size)) + return false; + + for (u_int32_t i = 0 ; i < data_size ; i++) { + if (verify_buffer[i] != block_data[i + prefix_pad_size]) { + return _f.errmsg("Write verification failed. Addr %08x - exp:%02x act:%02x\n", + addr + i, + block_data[i + prefix_pad_size] , + verify_buffer[i]); + } + } + } + } + + + // + // loop advance + // + + addr += data_size; + p += data_size; + cnt -= data_size; + } + + if (!reset()) + return false; + + return true; +} + +bool SpiFlash::CmdSetStSpi::erase_sector(u_int32_t addr) +{ + + if (_no_erase) + return true; + + u_int32_ba gw_cmd; + u_int32_ba gw_addr; + + + if (!write_enable()) + return false; + + // + // Erase sector command: + // + + gw_cmd[BUSY] = 1; + gw_cmd[SPI_SPECIAL] = 1; + gw_cmd[SPI_NO_DATA] = 1; + + gw_addr.range(SPI_CMD_E, SPI_CMD_S) = FC_SE; + gw_addr.range(SPI_ADDR_E, SPI_ADDR_S) = addr & _f.bank_mask(); + + MWRITE4(FLASH_ADDR, gw_addr); + MWRITE4(FLASH_GW, gw_cmd); + + if (!_f.wait_ready("ES")) + return false; + + // + // Wait for erase completion + // + + if (!wait_wip(ERASE_DELAY, ERASE_CNT)) + return false; + + return true; +} // Flash::erase_sector + + + +bool SpiFlash::CmdSetStSpi::write_block(u_int32_t block_addr, + void* block_data, + u_int32_t block_size) { + + u_int32_ba gw_cmd; + u_int32_ba gw_addr; + + // sanity check ??? remove ??? + if (block_size != (u_int32_t)_f._cfi_data.max_multi_byte_write) { + return _f.errmsg("Block write of wrong block size. %d instead of %d", + block_size, (u_int32_t)_f._cfi_data.max_multi_byte_write); + } + + if (!write_enable()) + return false; + + // + // Write the data block + // + + + gw_cmd[BUSY] = 1; + gw_cmd[SPI_SPECIAL] = 1; + + gw_cmd.range(MSIZE_E, MSIZE_S) = log2up(block_size); + + gw_addr.range(SPI_CMD_E, SPI_CMD_S) = FC_PP; + gw_addr.range(SPI_ADDR_E, SPI_ADDR_S) = block_addr & _f.bank_mask(); + + MWRITE4(FLASH_ADDR, gw_addr); + + // Data: + for (u_int32_t offs = 0 ; offs < block_size ; offs += 4) { + // NOTE: !!! To much swapping around the data. !!! + // Flash GW in sinai eats full DWords with byte0 as high data. + // TODO: Swap on writes in Parallel flash. Save double swapping for serial flash. + u_int32_t word = *((u_int32_t*)((u_int8_t*)block_data + offs)); + word = __be32_to_cpu(word); + MWRITE4(FLASH_DATA + offs, word ); + } + + MWRITE4(FLASH_GW, gw_cmd); + + if (!_f.wait_ready("PP command")) + return false; + + // + // Wait for end of write in flash (WriteInProgress = 0): + // + + if (!wait_wip(READ_DELAY, READ_CNT_SLOW + READ_CNT_FAST, READ_CNT_FAST)) + return false; + + return true; +} + + +bool SpiFlash::CmdSetStSpi::write_enable() { + + u_int32_ba gw_cmd; + u_int32_ba gw_addr; + + // + // Write enable: + // + + gw_cmd[BUSY] = 1; + gw_cmd[SPI_NO_ADDR] = 1; + gw_cmd[SPI_NO_DATA] = 1; + gw_cmd[SPI_SPECIAL] = 1; + + gw_addr.range(SPI_CMD_E, SPI_CMD_S) = FC_WREN; + + MWRITE4(FLASH_ADDR, gw_addr); + MWRITE4(FLASH_GW, gw_cmd); + + if (!_f.wait_ready("WREN command")) + return false; + + return true; +} + +bool SpiFlash::CmdSetStSpi::wait_wip(u_int32_t delay, u_int32_t retrys, u_int32_t fast_retrys ) { + + + u_int32_ba gw_cmd; + u_int32_ba gw_data; + u_int32_ba gw_addr; + + u_int32_t cnt = 0; + + // + // Read SR: + // + + gw_cmd[BUSY] = 1; + gw_cmd[READ_OP] = 1; + gw_cmd[SPI_NO_ADDR] = 1; + gw_cmd[SPI_SPECIAL] = 1; + + gw_addr.range(SPI_CMD_E, SPI_CMD_S) = FC_RDSR; + + do { + + if (++cnt > fast_retrys) + usleep(delay); + if (cnt > retrys) { + reset(); + return _f.errmsg("Flash write error - Write In Progress bit didn't clear."); + } + + MWRITE4(FLASH_ADDR, gw_addr); + MWRITE4(FLASH_GW, gw_cmd); + + if (!_f.wait_ready("RDSR")) + return false; + + MREAD4(FLASH_DATA, &gw_data); + + } while (gw_data[24]); // WIP bit in status reg - Note byte 0 is in bits 31-24 of data word. + + return true; +} + + +//////////////////////////////////////////////////////////////////////// +// +// Burn Operations functions +// +//////////////////////////////////////////////////////////////////////// + +class Operations : public ErrMsg { +public: + + Operations() : _last_image_addr(0), _num_ports(2), _allow_skip_is(false) {} + + enum { + GUIDS = 4 + }; + + enum ImageInfoTags { + II_IiFormatRevision = 0, + II_FwVersion = 1, + II_FwBuildTime = 2, + II_DeviceType = 3, + II_PSID = 4, + II_VSD = 5, + II_SuppurtedPsids = 6, + II_Last = 7, // Mark the end of used tag ids + II_End = 0xff + }; + + struct ImageInfo; + + bool write_image (Flash& f, u_int32_t addr, void *data, int cnt, bool need_report); + bool WriteSignature (Flash& f, u_int32_t image_idx, u_int32_t sig); + bool repair (Flash& f, const int from, const int to, bool need_report); + bool FailSafe_burn (Flash& f, void *data, int size, bool single_image_burn, bool need_report); + + bool Verify (FBase& f); + bool DumpConf (const char* conf_file = NULL); + + + bool DisplayImageInfo(ImageInfo* info); + + bool QueryAll (FBase& f, ImageInfo* info) {return QueryIs(f, info) && + (!info->isFailsafe || QueryPs(f, info)) && + QueryImage(f, info);} + + bool getBSN (char *s, guid_t *guid); + bool getGUID (const char *s, guid_t *guid); + + bool patchVSD (FImage& f, + const char *user_vsd, + const char *user_psid, + const char *curr_vsd, + const char *curr_psid, + const char *image_psid); + + bool patchGUIDs (FImage& f, guid_t guids[GUIDS], guid_t old_guids[GUIDS], bool interactive); + + void SetNumPorts (u_int32_t num_ports) {_num_ports = num_ports;} + void SetAllowSkipIs (bool asis) {_allow_skip_is = asis;} + + bool ask_user (const char* msg); + + u_int32_t _last_image_addr; + + + // + // ImageInfo struct: Everything you wanted to know about the FW image (and was afraid to ask). + // This struct includes both user's info (psid, dev rev , fwver ...) and tools internal + // info (images locations, guid ptr ...). + // + struct ImageInfo { + ImageInfo() : + invSectOk(false), + psOk(false), + imageOk(false) + { + psid[0] = '\0'; + vsd[0] = '\0'; + for (int i=0; i < II_Last; i++ ) + infoFound[i] = false; + } + + // *Ok : The exit status ofthe specific query. + // Note - invSectOk = true doesnt mean that invariant sector exists, it + // only means that the query was OK (and isFailsafe may be false). + + bool invSectOk; + bool psOk; + bool imageOk; + + bool isFailsafe; + + + bool validImage[2]; + u_int32_t psStart; + u_int32_t imgStart; + + guid_t guids[4]; + char vsd[209]; + char psid[17]; + + u_int8_t isVer; + u_int16_t fwVer[3]; // = {major_ver, minor_ver , sum_minor_ver} + u_int16_t fwTime[6]; // = {year, month, day, hour, minute, second} + + u_int16_t devType; + u_int8_t devRev; + + bool infoFound[II_Last]; + + }; + + + +private: + + bool FailSafe_burn_image (Flash& f, + void *data, + int ps_addr, + const char* image_name, + int image_addr, + int image_size, + bool need_report); + + bool CheckInvariantSector (Flash& f, u_int32_t *data32, int sect_size); + + bool FailSafe_burn_internal (Flash& f, void *data, int cnt, bool need_report); + + bool checkBoot2 (FBase& f, u_int32_t beg, u_int32_t offs, + u_int32_t& next, const char *pref); + + bool checkGen (FBase& f, u_int32_t beg, + u_int32_t offs, u_int32_t& next, const char *pref); + + bool checkPS (FBase& f, u_int32_t offs, u_int32_t& next, const char *pref); + + bool checkList (FBase& f, u_int32_t offs, const char *pref); + + bool extractGUIDptr (u_int32_t sign, u_int32_t *buf, int buf_len, + char *pref, u_int32_t *ind, int *nguids); + + void patchGUIDsSection (u_int32_t *buf, u_int32_t ind, + guid_t guids[GUIDS], int nguids); + + u_int32_t BSN_subfield (const char *s, int beg, int len); + + void _patchVSD (FImage& f, int ind, char *vsd); + + void PatchPs (u_int8_t* rawPs, + const char vsd[VSD_LEN], + const char psid[PSID_LEN] = NULL, + u_int32_t imageAddr = 0); + + + bool QueryIs (FBase& f, ImageInfo* info); + bool QueryPs (FBase& f, ImageInfo* info); + bool QueryImage (FBase& f, ImageInfo* info); + + + bool ParseInfoSect (u_int8_t* buff, u_int32_t byteSize, ImageInfo *info); + + u_int32_t _num_ports; + bool _allow_skip_is; + + std::vector _fw_conf_sect; +}; + + +// +// Asks user a yes/no question. +// Returns true if user chose Y, false if user chose N. +// + +bool Operations::ask_user(const char* msg) { + printf(msg); + if (_assume_yes) + printf("y\n"); + else { + char ansbuff[32]; + ansbuff[0] = '\0'; + + if (!isatty(0)) { + return errmsg("Not on tty - Can't interact. assuming \"no\" for question \"%s\"", msg); + } + fflush(stdout); + fgets(ansbuff, 30, stdin); + + if ( strcmp(ansbuff, "y\n") && + strcmp(ansbuff, "Y\n") && + strcmp(ansbuff, "yes\n") && + strcmp(ansbuff, "Yes\n") && + strcmp(ansbuff, "YES\n")) + return errmsg("Aborted by user"); + } + return true; +} + +bool Operations::write_image(Flash& f, u_int32_t addr, void *data, int cnt, bool need_report) +{ + u_int8_t *p = (u_int8_t *)data; + u_int32_t curr_addr = addr; + u_int32_t towrite = cnt; + u_int32_t perc = 0xffffffff; + + //f.curr_sector = 0xffffffff; // Erase sector first time + if (need_report) { + printf("000%%"); + fflush(stdout); + } + + while (towrite) { + // Write + int trans = (towrite > (int)Flash::TRANS) ? (int)Flash::TRANS : towrite; + if (!f.write(curr_addr, p, trans)) + return errmsg("Flash write failed: %s", f.err()); + p += trans; + curr_addr += trans; + towrite -= trans; + + // Report + if (need_report) { + u_int32_t new_perc = ((cnt - towrite) * 100) / cnt; + if (new_perc != perc) { + printf("\b\b\b\b%03d%%", new_perc); + fflush(stdout); + perc = new_perc; + } + } + } + + if (need_report) { + printf("\b\b\b\b100%%"); + fflush(stdout); + } + + return true; +} // Flash::write_image + + +//////////////////////////////////////////////////////////////////////// +bool Operations::WriteSignature(Flash& f, u_int32_t image_idx, u_int32_t sig) { + u_int32_t sect_size = f.get_sector_size(); + + if (!f.write( sect_size * (image_idx + 1) + 8, &sig, 4, true, false)) + return false; + + return true; +} + + +//////////////////////////////////////////////////////////////////////// +bool Operations::repair(Flash& f, const int from, const int to, bool need_report) +{ + + u_int32_t sect_size = f.get_sector_size(); + + report("Repairing: Copy %s image to %s -", from ? "secondary" : "primary" , + to ? "secondary" : "primary"); + + + // Read valid pointer sector + u_int32_t sect[sizeof(PS)/4]; + report("\b READ %s ", from ? "SPS" : "PPS"); + if (!f.read(from ? sect_size*2 : sect_size, sect, sizeof(sect) , need_report)) { + report("FAILED\n\n"); + return false; + } + report_erase(" READ %s 100%", from ? "SPS" : "PPS"); + + + + u_int32_t im_ptr = sect[0]; + u_int32_t sig = sect[2]; + + TOCPU1(im_ptr); + TOCPU1(sig); + + // Make sure ps ik ok: + if (sig != SIGNATURE) { + return errmsg("Can't copy image. Pointer sector %d signature is bad (%08x).", from, sig); + } + + // Valid image size in bytes + u_int32_t im_size_b; + if (!f.read(sect_size * (from+1) + 4, &im_size_b)) { + report("FAILED\n\n"); + return false; + } + TOCPU1(im_size_b); + + // Valid image size in sectors + u_int32_t im_size_s = (im_size_b + sect_size - 1) / sect_size; + + // Address to copy valid image + u_int32_t write_to = (!to) ? sect_size * 3 : sect_size * (3 + im_size_s); + + // f.read valid image + report(" READ FW "); + fflush(stdout); + char *buf = new char[im_size_b]; + if (!f.read(im_ptr, buf, im_size_b, need_report)) { + report("FAILED\n\n"); + delete [] buf; + return false; + } + report_erase(" READ FW 100%"); + + // Copy it to right place + report("\b WRITE FW "); + fflush(stdout); + if (!write_image(f, write_to, buf, im_size_b, need_report)) { + report("FAILED\n\n"); + delete [] buf; + return false; + } + delete [] buf; + report_erase(" WRITE FW 100%"); + + // Set new image address + // ++++++ + sect[0] = __be32_to_cpu(write_to); + + // Calculate new CRC + // ++++++ + Crc16 crc; + + for (u_int32_t i = 0; i < (sizeof(sect)/4 - 1) ; i++) { + crc << __be32_to_cpu(sect[i]); + } + crc.finish(); + + sect[sizeof(sect)/4 - 1] = __be32_to_cpu(crc.get()); + + // Corrupt signature + u_int32_t valid_signature = sect[2]; + sect[2] = 0xffffffff; + + // Write it to invalid sector + report("\b WRITE %s ", to ? "SPS" : "PPS"); + if (!write_image(f, to ? sect_size*2 : sect_size, sect, sizeof(sect), need_report)) { + report("FAILED\n\n"); + return false; + } + report_erase(" WRITE %s 100%", to ? "SPS" : "PPS"); + + // Validate signature + report("\b SIGNATURE "); + if (!WriteSignature(f, to, valid_signature)) { + report("FAILED\n\n"); + return false; + } + + report_erase(" SIGNATURE "); + report(" OK \n"); + return true; +} // Flash::repair + + + + + +//////////////////////////////////////////////////////////////////////// +bool Operations::FailSafe_burn_image(Flash& f, + void *data, + int ps_addr, + const char* image_name, + int image_addr, + int image_size, + bool need_report) { + + u_int8_t* data8 = (u_int8_t*) data; + u_int32_t sect_size = f.get_sector_size(); + + report("Burning %-9s FW image without signatures - ", image_name); + fflush(stdout); + + // Invalidate signature + u_int32_t zeros = 0; + if (!f.write(ps_addr + 8, &zeros, 4, true, false)) { + report("FAILED (Invalidating signature)\n\n"); + return false; + } + + // Burn image (from new offset) + + // Both burnt images are taken from the first image in the file - both images in file are identical. + // (future binary releases may contain a single image). + if (!write_image(f, image_addr, data8 + sect_size * 3, image_size, need_report)) { + report("FAILED\n\n"); + return false; + } + report("\b\b\b\bOK \n"); + report("Restoring %-9s signature - ", image_name); + fflush(stdout); + + // Burn PS + if (!write_image(f, ps_addr, data8 + ps_addr, sect_size, false)) { + report("FAILED\n\n"); + return false; + } + + // Validate signature + u_int32_t sig = SIGNATURE; + TOCPU1(sig); + if (!f.write(ps_addr + 8, &sig, 4, true, false)) { + report("FAILED\n\n"); + return false; + } + + report("OK \n"); + + return true; +} + + +//////////////////////////////////////////////////////////////////////// +bool Operations::FailSafe_burn_internal(Flash& f, void *data, int cnt, bool need_report) +{ + u_int32_t *data32 = (u_int32_t *)data; + + u_int32_t sect_size = f.get_sector_size(); + + // Extract Primary/Secondary image pointers and lengths + u_int32_t prim_ptr = data32[sect_size / 4]; + u_int32_t prim_len = data32[sect_size / 4 + 1]; + u_int32_t scnd_ptr = data32[(sect_size * 2) / 4]; + u_int32_t scnd_len = data32[(sect_size * 2) / 4 + 1]; + TOCPU1(prim_ptr); + TOCPU1(prim_len); + TOCPU1(scnd_ptr); + TOCPU1(scnd_len); + if ((cnt < (int)(prim_ptr + prim_len)) || (cnt < (int)(scnd_ptr + scnd_len))) { + return errmsg("Invalid image: too small."); + } + if (prim_len != scnd_len) { + return errmsg("Invalid image: two FW images should be in a same size."); + } + + // Image size from flash + u_int32_t old_im_size; + if (!f.read(sect_size + 4, &old_im_size)) { + report("FAILED\n\n"); + return false; + } + TOCPU1(old_im_size); + + u_int32_t prim_order; + u_int32_t scnd_order; + + u_int32_t ps_addr[2]; + u_int32_t image_addr[2]; + char* image_name[2]; + + + if (prim_len > old_im_size) { + scnd_order = 0; + prim_order = 1; + } else { + prim_order = 0; + scnd_order = 1; + } + + image_name[scnd_order] = "Secondary"; + image_addr[scnd_order] = scnd_ptr; + ps_addr [scnd_order] = sect_size * 2; + + image_name[prim_order] = "Primary"; + image_addr[prim_order] = prim_ptr; + ps_addr [prim_order] = sect_size; + + + for (int i = 0 ; i < 2 ; i++) { + if (!FailSafe_burn_image(f, data, ps_addr[i], image_name[i], image_addr[i], prim_len, need_report)) { + return false; + } + } + + return true; +} + +bool Operations::CheckInvariantSector(Flash& f, u_int32_t *data32, int sect_size) { + int i; + + report("\nRead and verify Invariant Sector - "); + fflush(stdout); + + // Once more check signature - the Inv.Sector signature should be OK + u_int32_t signature; + if (!f.read(0x24, &signature)) { + report("FAILED\n\n"); + return false; + } + TOCPU1(signature); + if (signature != SIGNATURE) { + report("FAILED\n\n"); + return errmsg("Flash has wrong signature in Invariant Sector (Expected %08x, got %08x).", SIGNATURE, signature); + } + + // Now check Invariant sector contents + vector buf1(sect_size/4); + + if (!f.read(0, &buf1[0] , sect_size)) { + report("FAILED\n\n"); + return false; + } + + int first_diff = -1; + + for (i=0; i < sect_size/4; i++) { + if (buf1[i] != data32[i] && (data32[i] != 0 || buf1[i] != 0xffffffff)) { + if (first_diff == -1) + first_diff = i; + } + } + + // Check if a diff was found: + if (first_diff != -1) { + report("DIFF DETECTED\n\n"); + printf(" Invariant sector mismatch. Address 0x%x " + " in image: 0x%08x, while in flash: 0x%08x\n\n", + first_diff*4 , data32[first_diff], buf1[first_diff]); + + printf(" The invariant sector can not be burnt in a failsafe manner.\n" + " To force burn of the invariant sector, rerun with -nofs flag.\n"); + + if (_allow_skip_is) { + printf(" You can also continue to update the FW without updating the invariant sector.\n" + " See the firmware release notes for more details.\n\n"); + + return ask_user(" Do you want to continue ? "); + + } else { + // Continue with burn + printf(" You can also update the FW without updating the invariant sector by\n" + " specifying the -skip_is flag.\n" + " See the firmware release notes for more details.\n\n"); + + return errmsg("Invariant sector mismatch"); + } + } + + report("OK\n"); + return true; + +} + +//////////////////////////////////////////////////////////////////////// +bool Operations::FailSafe_burn(Flash& f, void *data, int size, bool single_image_burn, bool need_report) +{ + u_int32_t *data32 = (u_int32_t *)data; + u_int8_t *data8 = (u_int8_t *)data; + + u_int32_t i; + + u_int32_t sect_size = f.get_sector_size(); + + if (size < (int)sect_size * 3) { + report("FAILED\n\n"); + return errmsg("Image is too small."); + } + + if (!CheckInvariantSector(f, data32, sect_size)) { + return false; + } + + // Check signatures in image + u_int32_t actual_signature = data32[sect_size/4 + 2]; + + u_int32_t signature_for_compare = actual_signature; + + TOCPU1(signature_for_compare); + if (signature_for_compare != SIGNATURE) { + return errmsg("Bad image file given: signature in PPS is 0x%08x (should be 0x%08x)", + signature_for_compare, SIGNATURE); + } + signature_for_compare = data32[(sect_size * 2)/4 + 2]; + TOCPU1(signature_for_compare); + if (signature_for_compare != SIGNATURE) { + return errmsg("Bad image file given: signature in SPS is 0x%08x (should be 0x%08x)", + signature_for_compare, SIGNATURE); + } + + // Corrupt signatures in image + data32[sect_size/4 + 2] = 0xffffffff; + data32[(sect_size * 2)/4 + 2] = 0xffffffff; + + bool cur_image_ok[2] = {false, false}; + u_int32_t cur_image_addr[2]; + u_int32_t cur_image_size[2]; + + // Check signatures on flash + report("Read and verify PPS/SPS in flash - "); + for (i = 0 ; i < 2 ; i++) { + if (!f.read(sect_size * (i+1) + 8, &signature_for_compare)) { + + } + TOCPU1(signature_for_compare); + if (signature_for_compare == SIGNATURE) { + cur_image_ok[i] = true; + + if (!f.read(sect_size * (i+1) , &cur_image_addr[i]) || + !f.read(sect_size * (i+1) + 4, &cur_image_size[i])) { + report("FAILED\n\n"); + return false; + } + + TOCPU1(cur_image_addr[i]); + TOCPU1(cur_image_size[i]); + } + } + + if (!cur_image_ok[0] && !cur_image_ok[1]) { + // + // Both images are invalid in flash + // -------------------------------- + // + printf("\nBoth images (primary and secondary) are invalid in flash.\n"); + printf("The burning can't be failsafe, but it is harmless for host.\n"); + if(!ask_user("\n Do you want to continue ? (y/n) [n] : ")) { + return false; + } + + // Burn all image + report("Burn FW image without signatures - "); + fflush(stdout); + if (!write_image(f, sect_size, data8 + sect_size, size - sect_size, need_report)) { + report("FAILED\n\n"); + return false; + } + report("\b\b\b\bOK \n"); + + // Restore signatures + report("Restore right signatures - "); + fflush(stdout); + if (!WriteSignature(f, 0, actual_signature)) { + report("FAILED (PPS Signature)\n\n"); + return false; + } + if (!WriteSignature(f, 1, actual_signature)) { + report("FAILED (SPS Signature)\n\n"); + return false; + } + report("OK\n"); + return true; + } else { + report("OK\n"); + } + + if (single_image_burn == false) { + + if (cur_image_ok[0] == false || cur_image_ok[1] == false) { + int image_from; + int image_to; + + assert (cur_image_ok[1] || cur_image_ok[0]); + + if (cur_image_ok[1]) { + image_from = 1; + image_to = 0; + } else { + image_from = 0; + image_to = 1; + } + + report("Reparable Error Detected.\n"); + if (!repair(f, image_from, image_to, need_report)) + return false; + } + + // + // Both images are valid in flash + // + return FailSafe_burn_internal(f, data, size, need_report); + + } else { + + // + // Single image burn: + // + + // Extract Primary/Secondary image pointers and lengths + u_int32_t frst_new_image_addr = data32[sect_size / 4]; + u_int32_t frst_new_image_size = data32[sect_size / 4 + 1]; + TOCPU1(frst_new_image_addr); + TOCPU1(frst_new_image_size); + + if (!cur_image_ok[0] && cur_image_ok[1]) { + // Second image is valid on flash. + // If the new image can fit in the first image gap, it would be + // burnt as first image. + // Otherwise (new image too big), image on flash is copied from second to + // first image, and new image would be written as second. + + if (frst_new_image_addr + frst_new_image_size > cur_image_addr[1]) { + // New image is too large - can't get in between first image start + // and current (second) image - move current image to be first. + if (!repair(f, 1, 0, need_report)) + return false; + + // Now 2 images are valid + cur_image_ok[0] = true; + } else { + if (!FailSafe_burn_image(f, data, sect_size, "first", sect_size * 3, frst_new_image_size, need_report)) + return false; + + if (!WriteSignature(f, 1, 0)) + return false; + + return true; + } + } + + if (cur_image_ok[0] && cur_image_ok[1]) { + + // Invalidate second image + if (!WriteSignature(f, 1, 0)) { + report("FAILED\n"); + return false; + } + + cur_image_ok[1] = false; + } + + if (cur_image_ok[0] && !cur_image_ok[1]) { + u_int32_t new_image_size_sect = ((frst_new_image_size - 1) / sect_size) + 1 ; + + // First image is valid on flash. + // If the new image is smaller than current image, it would + // overwrite the end of current image. In this case, move the current image + // to the second position and burn in first. + // + // TODO: STOP THIS MOVEMENT BULLSHI%@#&! !!! : Reproduce PS in flint with the correct addr. Locate second image in middle of flash. + + if ( (3 + new_image_size_sect) * sect_size < cur_image_addr[0] + cur_image_size[0]) { + // New image overwrites end of cur image + // move current image to be second. + if (!repair(f, 0, 1, need_report)) + return false; + + // Now 2 images are valid + cur_image_ok[1] = true; + + // Burn new image as firse + if (!FailSafe_burn_image(f, data, sect_size, "first", + sect_size * 3, frst_new_image_size, need_report)) + return false; + + if (!WriteSignature(f, 1, 0)) + return false; + + return true; + + + } else { + if (!FailSafe_burn_image(f, data, sect_size * 2, "second", + sect_size * (3 + new_image_size_sect) , frst_new_image_size, need_report)) + return false; + + // Invalidate first image + if (!WriteSignature(f, 0, 0)) + return false; + + return true; + + } + + + } else { + report("Bad flash state: Valid images = (%d,%d).\n", cur_image_ok[0], cur_image_ok[1] ); + return false; + } + + } + + return true; +} + + +//////////////////////////////////////////////////////////////////////// +// // +// ****************************************************************** // +// VERIFY FLASH // +// ****************************************************************** // +// // +//////////////////////////////////////////////////////////////////////// +bool Operations::checkBoot2(FBase& f, u_int32_t beg, u_int32_t offs, + u_int32_t& next, const char *pref) +{ + u_int32_t size; + + char *pr = (char *)alloca(strlen(pref) + 512); + + sprintf(pr, "%s /0x%08x/ (BOOT2)", pref, offs+beg); + + // Size + READ4(f, offs+beg+4, &size, pr); + TOCPU1(size); + if (size > 1048576 || size < 4) { + report("%s /0x%08x/ - unexpected size (0x%x)\n", pr, offs+beg+4, size); + return false; + } + + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (BOOT2)", pref, offs+beg, + offs+beg+(size+4)*4-1, (size+4)*4); + + Crc16 crc; + u_int32_t *buff = (u_int32_t*)alloca((size + 4)*sizeof(u_int32_t)); + + READBUF(f, offs+beg, buff, size*4 + 16, pr); + TOCPUn(buff, size+4); + CRC1n(crc, buff, size+4); + crc.finish(); + u_int32_t crc_act = buff[size+3]; + if (crc.get() != crc_act) { + report("%s /0x%08x/ - wrong CRC (exp:0x%x, act:0x%x)\n", + pr, offs+beg, crc.get(), crc_act); + return false; + } + + if (_print_crc) + report("%s - OK (CRC:0x%04x)\n", pr, crc_act&0xffff); + else + report("%s - OK\n", pr); + next = offs + size*4 + 16; + return true; +} // checkBoot2 + +static int part_cnt; + +//////////////////////////////////////////////////////////////////////// +bool Operations::checkGen(FBase& f, u_int32_t beg, + u_int32_t offs, u_int32_t& next, const char *pref) +{ + char *pr = (char *)alloca(strlen(pref) + 100); + + u_int32_t size=0; + GPH gph; + + // GPH + sprintf(pr, "%s /0x%08x/ (GeneralHeader)", pref, offs+beg); + READBUF(f, offs+beg, &gph, sizeof(GPH), pr); + TOCPUBY(gph); + + // Body + + part_cnt++; + + // May be BOOT3? + if (gph.type < H_FIRST || gph.type > H_LAST) { + if (part_cnt > 2) { + //report("%s /0x%x/ - Invalid partition type (%d)\n", + // pref, offs+beg, gph.type); + //return false; + } else + return checkBoot2(f, beg, offs, next, pref); + } + + // All partitions here + offs += beg; + switch (gph.type) { + case H_DDR: + size = gph.size * sizeof(u_int32_t); + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (DDR)", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4); + break; + case H_CNF: + size = gph.size * sizeof(u_int32_t); + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (Configuration)", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4); + break; + case H_JMP: + size = gph.size * sizeof(u_int32_t); + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (Jump addresses)", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4); + break; + case H_EMT: + size = gph.size; + size = (size + 3) / 4 * 4; + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (EMT Service)", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4); + break; + case H_FW_CONF: + size = gph.size * sizeof(u_int32_t); + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (FW Configuration)", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4); + break; + case H_ROM: + size = gph.size * sizeof(u_int32_t); + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (ROM)", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4); + break; + case H_USER_DATA: + size = gph.size * sizeof(u_int32_t); + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (User Data)", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4); + break; + case H_IMG_INFO: + size = gph.size * sizeof(u_int32_t); + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (Image Info)", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4); + break; + case H_BOARD_ID: + size = gph.size * sizeof(u_int32_t); + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (Board ID)", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4); + break; + case H_GUID: + size = gph.size * sizeof(u_int32_t); + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (GUID)", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4); + break; + default: + // For forward compatibility, try analyzing even if section type is uncknown + // Assuming the size is in DW, like all other sections (except emt service). + // If this assumption is wrong, CRC calc would fail - no harm done. + size = gph.size * sizeof(u_int32_t); + sprintf(pr, "%s /0x%08x-0x%08x (0x%06x)/ (UNKNOWN SECTION TYPE (%d))", + pref, offs, offs+size+(u_int32_t)sizeof(gph)+3, + size+(u_int32_t)sizeof(gph)+4, gph.type); + + } + + // CRC + Crc16 crc; + + // Fix for win32: alloca fails on large allocations. + // TODO: Mem leak possible - fix. + //u_int32_t *buff = (u_int32_t*)alloca(size); + u_int32_t *buff = new u_int32_t[size/4]; + + READBUF(f, offs+sizeof(gph), buff, size, pr); + TOCPUn(buff,size/4); + CRCBY(crc, gph); + CRCn(crc, buff, size/4); + crc.finish(); + u_int32_t crc_act; + READ4(f, offs+sizeof(gph)+size, &crc_act, pr); + TOCPU1(crc_act); + if (crc.get() != crc_act) { + report("%s /0x%08x/ - wrong CRC (exp:0x%x, act:0x%x)\n", + pr, offs, crc.get(), crc_act); + return false; + } + + if (_print_crc) + report("%s - OK (CRC:0x%04x)\n", pr, crc_act&0xffff); + else + report("%s - OK\n", pr); + next = gph.next; + + if (gph.type == H_FW_CONF) { + _fw_conf_sect.clear(); + _fw_conf_sect.insert(_fw_conf_sect.end(), + vector::iterator((u_int8_t*)buff), + vector::iterator((u_int8_t*)buff + size)); + + } + + // mark last read addr + _last_image_addr = offs + size +sizeof(gph) + 4; // the 4 is for the trailing crc + + delete buff; + + return true; +} // checkGen + +//////////////////////////////////////////////////////////////////////// +bool Operations::checkPS(FBase& f, u_int32_t offs, u_int32_t& next, const char *pref) +{ + Crc16 crc; + PS ps; + f.read(offs, &ps, sizeof(ps)); + TOCPUBY(ps); + + // Signature + if (ps.signature != SIGNATURE) { + report("%s Pointer Sector /0x%08x/ - invalid signature (%08x)\n", + pref, offs, ps.signature); + return false; + } + + // CRC + CRC1BY(crc, ps); + crc.finish(); + if (crc.get() != ps.crc016) { + report("%s Pointer Sector /0x%08x/ - wrong CRC (exp:0x%x, act:0x%x)\n", + pref, offs, ps.crc016, crc.get()); + return false; + } + + next = ps.fi_addr; + if (_print_crc) + report("%s Image /0x%08x-0x%08x (0x%06x)/ (Pointer Sector)- OK (CRC:0x%04x)\n", pref, offs, + offs+(u_int32_t)sizeof(ps)-1, (u_int32_t)sizeof(ps), ps.crc016&0xffff); + else + report("%s Image /0x%08x-0x%08x (0x%06x)/ (Pointer Sector)- OK\n", pref, offs, + offs+(u_int32_t)sizeof(ps)-1, (u_int32_t)sizeof(ps)); + return true; +} // checkPS + +//////////////////////////////////////////////////////////////////////// +bool Operations::checkList(FBase& f, u_int32_t offs, const char *pref) +{ + u_int32_t next_ptr; + + CHECKB2(f, offs, 0x28, next_ptr, pref); + part_cnt = 1; + while (next_ptr && next_ptr != 0xff000000) + CHECKGN(f, offs, next_ptr, next_ptr, pref); + + return true; +} // checkList + +//////////////////////////////////////////////////////////////////////// +bool Operations::Verify(FBase& f) +{ + u_int32_t prim_ptr, scnd_ptr; + u_int32_t signature; + + bool ret = true; + + READ4(f, 0x24, &signature, "Signature"); + TOCPU1(signature); + if (signature == SIGNATURE) { + // Full image + _image_is_full = true; + report("\nFailsafe image:\n\n"); + CHECKB2(f, 0, 0x28, prim_ptr, "Invariant "); + report("\n"); + if (checkPS(f, f.get_sector_size(), prim_ptr, "Primary ")) + ret &= checkList(f, prim_ptr, " "); + report("\n"); + if (checkPS(f, f.get_sector_size() * 2, scnd_ptr, "Secondary")) + CHECKLS(f, scnd_ptr, " "); + } else { + // Short image + _image_is_full = false; + report("\nShort image:\n"); + CHECKLS(f, 0, " "); + } + + return ret; +} // Verify + + +bool Operations::DumpConf (const char* conf_file) { +#ifndef NO_ZLIB + + FILE* out; + if (conf_file == NULL) { + out = stdout; + } else { + out = fopen(conf_file, "w"); + + if (out == NULL) { + return errmsg("Can't open file %s for write: %s.", conf_file, strerror(errno)); + } + } + + if (_fw_conf_sect.empty()) { + return errmsg("Fw configuration section not found in the given image."); + } + + // restore endianess. + TOCPUn(&(_fw_conf_sect[0]), _fw_conf_sect.size()/4); + + // uncompress: + uLongf destLen = _fw_conf_sect.size(); + destLen *= 10; + vector dest(destLen); + + int rc = uncompress((Bytef *)&(dest[0]), &destLen, + (const Bytef *)&(_fw_conf_sect[0]), _fw_conf_sect.size()); + + if (rc != Z_OK) + { + return errmsg("Failed uncompressing FW Info section. uncompress returnes %d", rc); + } + + dest.resize(destLen); + dest[destLen] = 0; // Terminating NULL + fprintf(out, "%s", (char*)&(dest[0])); + + if (conf_file != NULL) { + fclose(out); + } + + return true; +#else + return errmsg("Executable was compiled with \"dump configuration\" option disabled."); +#endif + +} // DumpConf + + + +//////////////////////////////////////////////////////////////////////// +// // +// ****************************************************************** // +// GUIDs TREATMENT // +// ****************************************************************** // +// // +//////////////////////////////////////////////////////////////////////// +#define GETGUID(s, g) do { if (!ops.getGUID(s,g)) return 1; } while (0) +#define GETBSN(s, g) do { if (!ops.getBSN(s,g)) return 1; } while (0) + +#define BSN_RET do { \ + printf("Invalid BSN. Should be MTxxxxx[-]R[xx]ddmmyy-nnn[-cc]\n"); \ + return false; \ +} while(0) +#define BSN_RET1(s) do { \ + printf("Valid BSN format is: MTxxxxx[-]R[xx]ddmmyy-nnn[-cc]\n%s.\n",s); \ + return false; \ +} while(0) +u_int32_t Operations::BSN_subfield(const char *s, int beg, int len) +{ + char buf[64]; + strncpy(buf, &s[beg], len); + buf[len] = '\0'; + return strtoul(&buf[0], 0, 10); +} +bool Operations::getBSN(char *s, guid_t *guid) +{ + const u_int64_t COMPANY_ID = 0x0002c9; + const u_int64_t TYPE = 1; + bool cc_present = false; + char *p; + int date_offs = 0; + int i; + + // Convert to lowercase + for (p = s; *p; p++) + *p = (char)tolower(*p); + + // Check validity + p = s; + if (strncmp(p, "mt", 2)) // MT + BSN_RET; + p += 2; + for (i=0; i<5; i++) + if (!isdigit(*p++)) // xxxxx + BSN_RET; + if (*p == '-') { // - /optional/ + p++; + date_offs++; + } + if (*p < 'a' || *p > 'z') // R + BSN_RET; + p++; + + // Count how many digits after R + char *q = p; + int ndigits=0; + while (isdigit(*q++)) + ndigits++; + + switch (ndigits) { + case 6: + p += 6; // skip ddmmyy + break; + case 8: + p += 8; // skip xxddmmyy + date_offs += 2; + break; + default: + BSN_RET; + } + + if (*p++ != '-') // - + BSN_RET; + for (i=0; i<3; i++) // nnn + if (!isdigit(*p++)) + BSN_RET; + if (*p) { + cc_present = true; + if (*p++ != '-') // - + BSN_RET; + for (i=0; i<2; i++) // cc + if (!isdigit(*p++)) + BSN_RET; + } + + u_int32_t dd = BSN_subfield(s, 8+date_offs, 2); + if (dd > 31) + BSN_RET1("Day (dd) should not exceed 31"); + if (!dd) + BSN_RET1("Day (dd) can't be zero"); + u_int32_t mm = BSN_subfield(s, 10+date_offs, 2); + if (mm > 12) + BSN_RET1("Months (mm) should not exceed 12"); + if (!mm) + BSN_RET1("Months (mm) can't be zero"); + u_int32_t yy = BSN_subfield(s, 12+date_offs, 2); + if (yy > 99) + BSN_RET1("Year (yy) should not exceed 99"); + if (!yy) + BSN_RET1("Year (yy) can't be zero"); + u_int32_t num = BSN_subfield(s, 15+date_offs, 3); + if (num > 999) + BSN_RET1("Number (num) should not exceed 999"); + if (!num) + BSN_RET1("Number (num) can't be zero"); + int cc = 1; + if (cc_present) { + cc = BSN_subfield(s, 19+date_offs, 2); + if (cc > 14) + BSN_RET1("Chip number (cc) should not exceed 14"); + if (!cc) + BSN_RET1("Chip number (cc) can't be zero"); + } + u_int64_t id = ((((yy*12+mm-1)*31+ dd-1) * 1000) + num-1) * 112; + id += (cc-1)*8; + + u_int64_t g = (COMPANY_ID << 40) | (TYPE << 32) | id; + guid->h = (u_int32_t)(g>>32); + guid->l = (u_int32_t)g; + return true; +} + +bool Operations::getGUID(const char *s, guid_t *guid) +{ + char* endp; + u_int64_t g; + + g = strtoull(s, &endp, 16); + if (*endp || (g == 0xffffffffffffffffULL && errno == ERANGE)) { + printf("Invalid GUID syntax (%s) %s \n", + s, + errno ? strerror(errno) : "" ); + return false; + } + guid->h = (u_int32_t)(g >> 32); + guid->l = (u_int32_t)(g & 0xffffffff); + return true; +} // getGUID + +//////////////////////////////////////////////////////////////////////// +bool Operations::extractGUIDptr(u_int32_t sign, u_int32_t *buf, int buf_len, + char *pref, u_int32_t *ind, int *nguids) +{ + u_int32_t offs = 0; + + // Check signature + if (sign) { + u_int32_t signature = buf[(sign + 8)/4]; + TOCPU1(signature); + if (signature != SIGNATURE) { + printf("%s pointer section not valid\n", pref); + return false; + } + offs = buf[sign/4]; + TOCPU1(offs); + } + + // Get GUID ptr + *ind = buf[(offs+0x24)/4]; + TOCPU1(*ind); + *ind += offs; + if (*ind >= (u_int32_t)buf_len) { + printf("%s image - insane GUID pointer (%08x)\n", pref, *ind); + return false; + } + *nguids = buf[*ind/4 - 3]; + TOCPU1(*nguids); + *nguids /= 2; + + // More sanity check + if (*nguids > GUIDS) { + printf("%s image - insane number of GUIDs (%d)\n", pref, *nguids); + return false; + } + + return true; +} // extractGUIDptr + +//////////////////////////////////////////////////////////////////////// +void Operations::patchGUIDsSection(u_int32_t *buf, u_int32_t ind, + guid_t guids[GUIDS], int nguids) +{ + u_int32_t i, word; + u_int32_t new_buf[GUIDS*2]; + Crc16 crc; + + // Form new GUID section + for (i=0; i<(u_int32_t)nguids; i++) { + new_buf[i*2] = guids[i].h; + new_buf[i*2+1] = guids[i].l; + } + + // Calculate new CRC16 + for (i=ind/4 - 4; ivsd[0], vsd, VSD_LEN + PSID_LEN); + + u_int32_t *qp = (u_int32_t *)ps; + for (unsigned int i=0; icrc016 = __cpu_to_be32(crc016); +} // _patchVSD + + +// +// PatchPs() : +// This func assumes it gets a pointer (rawPs) to a valid PS. +// It patches the PS with the given data, recalculated CRC , +// and copies it back to the rawPs. +// + +void Operations::PatchPs(u_int8_t* rawPs, + const char* vsd, + const char* psid, + u_int32_t imageAddr) { + + Crc16 crc; + PS *ps = (PS*)rawPs; + + u_int32_t fix_start = 0; + u_int32_t fix_end = 0; + + if (vsd) { + u_int32_t len = strlen(vsd); + + memset(&ps->vsd[0], 0, VSD_LEN ); + memcpy(&ps->vsd[0], vsd, len); + + fix_end += VSD_LEN; + } else { + fix_start +=VSD_LEN; + } + if (psid) { + u_int32_t len = strlen(psid); + + memset(&ps->psid[0], 0, PSID_LEN ); + memcpy(&ps->psid[0], psid, len ); + fix_end += PSID_LEN; + } + + //vsd is kept in flash byte-swapped. + //recode it back before patching + u_int32_t *qp; + + qp = (u_int32_t *)&ps->vsd[0]; + for (u_int32_t i=fix_start; ifi_addr = __cpu_to_be32(imageAddr); + } + + qp = (u_int32_t *)ps; + for (unsigned int i=0; icrc016 = __cpu_to_be32(crc016); + +} + + +//////////////////////////////////////////////////////////////////////// +//Note that vsd1 is a string of bytes. +bool Operations::patchVSD(FImage& f, + const char *user_vsd, + const char *user_psid, + const char *curr_vsd, + const char *curr_psid, + const char *image_psid) +{ + const char* vsd_to_use = curr_vsd ? curr_vsd : ""; + const char* psid_to_use = image_psid; + + // Form new VSD + + if (user_psid) { + // New psid is explicitly given - take it from user + printf("\n You are about to replace current PSID in the image file - \"%s\" with a different PSID - \"%s\".\n" + " Note: It is highly recommended NOT to change the image PSID.\n", user_psid, image_psid); + + if (! ask_user("\n Is it OK ? (y/n) [n] : ")) + return false; + + psid_to_use = user_psid; + } + + if (user_vsd) { + vsd_to_use = user_vsd; + } + + + if (curr_psid && strncmp( psid_to_use, (char*) curr_psid, PSID_LEN)) { + printf("\n You are about to replace current PSID in flash - \"%s\" with a different PSID - \"%s\".\n", curr_psid, psid_to_use); + + if (! ask_user("\n Is it OK ? (y/n) [n] : ")) + return false; + } + + PatchPs((u_int8_t*)f.getBuf() + f.get_sector_size(), vsd_to_use, psid_to_use); + PatchPs((u_int8_t*)f.getBuf() + f.get_sector_size() * 2, vsd_to_use, psid_to_use); + + return true; +} // pathVSD + + +//////////////////////////////////////////////////////////////////////// +bool Operations::patchGUIDs(FImage& f, guid_t new_guids[GUIDS], guid_t old_guids[GUIDS], bool interactive) +{ + guid_t image_file_guids[GUIDS]; + guid_t* used_guids = old_guids ? old_guids : new_guids; + u_int32_t *buf = f.getBuf(); + int buf_len = f.getBufLength(); + u_int32_t signature = buf[0x24/4]; + u_int32_t ind1=0,ind2=0; + int nguid1, nguid2; + + TOCPU1(signature); + if (signature == SIGNATURE) { + // Full image + if (interactive) + printf("\nFull image:\n\n"); + if (!extractGUIDptr(f.get_sector_size() , buf, buf_len, "Primary" , &ind1, &nguid1) && + !extractGUIDptr(f.get_sector_size() *2, buf, buf_len, "Secondary", &ind2, &nguid2)) + return false; + + } else { + // Short image + if (interactive) + printf("\nShort image:\n\n"); + if (!extractGUIDptr(0, buf, buf_len, "Primary", &ind1, &nguid1)) + return false; + } + + // Print old GUIDs and get confirmation + if (interactive && new_guids) { + bool image_file_old_guids_fmt = nguid1 < GUIDS; + for (int i=0; i 1) + printf(" Port2: " GUID_FORMAT "\n", old_guids[2].h,old_guids[2].l); + if (!image_file_old_guids_fmt) + printf(" Sys.Image: " GUID_FORMAT "\n", old_guids[3].h,old_guids[3].l); + } + + printf("\n You are about to burn the image with the following GUIDs:\n"); + printf(" Node: " GUID_FORMAT "\n", new_guids[0].h,new_guids[0].l); + printf(" Port1: " GUID_FORMAT "\n", new_guids[1].h,new_guids[1].l); + if (_num_ports > 1) + printf(" Port2: " GUID_FORMAT "\n", new_guids[2].h,new_guids[2].l); + if (!image_file_old_guids_fmt) + printf(" Sys.Image: " GUID_FORMAT "\n", new_guids[3].h,new_guids[3].l); + + if (!ask_user("\n Is it OK ? (y/n) [n] : ")) + return false; + + used_guids = new_guids; + } + + // Path GUIDs section + if (ind1) + patchGUIDsSection(buf, ind1, used_guids, nguid1); + if (ind2) + patchGUIDsSection(buf, ind2, used_guids, nguid2); + + if (!interactive) { + bool old_guids_fmt = nguid1 < GUIDS; + printf("\n Burn image with the following GUIDs:\n"); + printf(" Node: " GUID_FORMAT "\n", used_guids[0].h,used_guids[0].l); + printf(" Port1: " GUID_FORMAT "\n", used_guids[1].h,used_guids[1].l); + if (_num_ports > 1) + printf(" Port2: " GUID_FORMAT "\n", used_guids[2].h,used_guids[2].l); + if (!old_guids_fmt) + printf(" Sys.Image: " GUID_FORMAT "\n", used_guids[3].h,used_guids[3].l); + } + return true; +} // patchGUIDs + + +//////////////////////////////////////////////////////////////////////// +// // +// ****************************************************************** // +// Revision info and board ID // +// ****************************************************************** // +// // +//////////////////////////////////////////////////////////////////////// + +bool Operations::QueryIs (FBase& f, + Operations::ImageInfo* info) { + u_int32_t signature; + + READ4(f, 0x24, &signature, "Signature"); + TOCPU1(signature); + if (signature == SIGNATURE) { + // Full image + info->isFailsafe = true; + + // FW ID + u_int32_t fw_id; + + READ4(f, 0x10, &fw_id, "FW ID"); + TOCPU1(fw_id); + + info->isVer = ( fw_id >> 8) && 0xff; + info->devRev = fw_id >> 24; + + } else { + info->isFailsafe = false; + info->imgStart = 0; + } + + info->invSectOk = true; + return true; +} + +bool Operations::QueryPs (FBase& f, + Operations::ImageInfo* info) { + + if (!info->isFailsafe) { + return errmsg("Internal Error: Tried to query PS when image is not failsafe"); + } + + u_int32_t prim_ptr, scnd_ptr; + u_int32_t sectSize = f.get_sector_size(); + + bool currSielent = _silent; + _silent = true; + + if (checkPS(f, sectSize, prim_ptr, "Primary ")) { + info->imgStart = prim_ptr; + info->psStart = sectSize; + } else if (checkPS(f, sectSize * 2, scnd_ptr, "Secondary")) { + info->imgStart = scnd_ptr; + info->psStart = sectSize * 2; + } else { + return errmsg("No valid image found."); + } + + char vsd[VSD_LEN+PSID_LEN+1]; // +1 => Leave a space for \0 when psid size == 16 . + + memset(vsd, 0, sizeof(vsd)); + READBUF(f, info->psStart + 0x20, vsd, VSD_LEN+PSID_LEN , "Vendor Specific Data (Board ID)"); + TOCPUBY(vsd); + + memcpy(info->vsd, vsd, VSD_LEN); + memcpy(info->psid, vsd + VSD_LEN, PSID_LEN); + + info->vsd [sizeof(info->vsd) - 1] = '\0'; + info->psid[sizeof(info->psid) - 1] = '\0'; + + _silent = currSielent; + + info->psOk = true; + + return true; +} + + +bool Operations::QueryImage (FBase& f, + Operations::ImageInfo* info) { + + u_int32_t guid_ptr, nguids; + guid_t guids[GUIDS]; + + // FW ID + u_int32_t fw_id; + u_int32_t im_start = info->imgStart; + + + READ4(f, im_start + 0x10, &fw_id, "FW ID"); + TOCPU1(fw_id); + + info->devRev = fw_id >> 24; + // Read GUIDs + READ4(f, im_start + 0x24, &guid_ptr, "GUID PTR"); + TOCPU1(guid_ptr); + guid_ptr += im_start; + if (guid_ptr >= f.get_size()) { + return errmsg("Failed to read GUIDs - Insane GUID pointer (%08x). Probably image is corrupted", guid_ptr); + } + READ4(f, guid_ptr - 3*sizeof(u_int32_t), &nguids, "Number of GUIDs"); + TOCPU1(nguids); + if (nguids > GUIDS*2) { + report("Failed to read GUIDs - Insane Number of GUIDs (%d)\n", nguids); + return false; + } + READBUF(f, guid_ptr, guids, nguids / 2 * sizeof(u_int64_t), "GUIDS"); + TOCPUBY64(guids); + for (u_int32_t i = 0 ; i < nguids/2 ; i++) { + info->guids[i] = guids[i]; + } + + // Read Info: + u_int32_ba info_ptr_ba; + u_int32_t info_ptr; + u_int32_t info_size; + u_int8_t info_ptr_cs = 0; + READ4(f, im_start + 0x1C, &info_ptr, "INFO PTR"); + TOCPU1(info_ptr); + + // Verify info_ptr checksum (should be 0) + info_ptr_ba = info_ptr; + for (u_int32_t i = 0; i < 4 ; i++) { + info_ptr_cs += (u_int8_t)info_ptr_ba.range(i*8+7, i*8); + } + + if (info_ptr_cs) { + return errmsg("Failed to read Info Section - Bad checksum for Info section pointer (%08x). Probably image is corrupted", info_ptr); + } + + info_ptr = info_ptr_ba.range(23,0); + if (info_ptr_cs == 0 && info_ptr != 0) { + + info_ptr += im_start; + if (info_ptr >= f.get_size()) { + return errmsg("Failed to read Info Section - Info section pointer (%08x) too large. Probably image is corrupted", info_ptr); + } + READ4(f, info_ptr - 3*sizeof(u_int32_t), &info_size, "Info section size"); + TOCPU1(info_size); + + // byte size; + info_size *= 4; + + u_int8_t* info_buff = (u_int8_t*)alloca(info_size); + READBUF(f, info_ptr, info_buff, info_size, "Info Section"); + + if (ParseInfoSect(info_buff, info_size, info)) { + return false; + } + } + + info->imageOk = true; + return true; +} + + +bool Operations::ParseInfoSect(u_int8_t* buff, u_int32_t byteSize, Operations::ImageInfo *info) { + + u_int32_t *p = (u_int32_t*)buff; + u_int32_t offs = 0; + + bool endFound = false; + + while ((__be32_to_cpu(*p) >> 24) != II_End && offs < byteSize) { + u_int32_t tagSize = __be32_to_cpu(*p) & 0xffffff; + u_int32_t tagId = __be32_to_cpu(*p) >> 24; + + u_int32_t tmp; + + switch (tagId) { + case II_FwVersion: + info->fwVer[0] = __be32_to_cpu(*(p+1)) >> 16; + tmp = __be32_to_cpu(*(p+2)); + info->fwVer[1] = tmp >> 16; + info->fwVer[2] = tmp & 0xffff; + + info->infoFound[tagId] = true; + break; + + case II_DeviceType: + tmp = __be32_to_cpu(*(p+1)); + info->devType = tmp & 0xffff; + //info->devRev = (tmp >> 16) & 0xff; + info->infoFound[tagId] = true; + + case II_PSID: + // set psid only if not previosly found in PS + if (!info->psOk) { + const char* str = (const char*)p; + str += 4; + + for (int i = 0 ; i < PSID_LEN ; i++) { + info->psid[i] = str[i]; + } + info->psid[PSID_LEN] = '\0'; + + info->infoFound[tagId] = true; + + } + break; + + case II_End: + endFound = true; + break; + + //default: + //printf("-D- Found tag ID %d of size %d - ignoring.\n", tagId, tagSize); + } + + p += tagSize/4 + 1; + offs += tagSize; + } + + offs += 4; + + if (offs != byteSize) { + if (endFound) { + return errmsg("Info section corrupted: Section data size is %x bytes, " + "but end tag found after %x bytes.", byteSize, offs); + } else { + return errmsg("Info section corrupted: Section data size is %x bytes, " + "but end tag not found before section end.", byteSize); + } + } + + return true; +} + +bool Operations::DisplayImageInfo(Operations::ImageInfo* info) { + + report("Image type: %s\n", info->isFailsafe ? "Failsafe" : "Short"); + + if (info->infoFound[II_FwVersion]) { + report("FW Version: %d.%d.%d\n", info->fwVer[0], info->fwVer[1], info->fwVer[2]); + } + + if (info->isFailsafe) { + report("I.S. Version: %d\n", info->isVer ); + } + + if (info->infoFound[II_DeviceType]) { + report("Device ID: %d\n", info->devType); + } + + report("Chip Revision: %X\n", info->devRev); + + // GUIDS: + report("GUID Des: Node Port1 "); + + if (_num_ports > 1) + report("Port2 "); + report( "Sys image\n"); + + report("GUIDs: "); + for (u_int32_t i=0; i < GUIDS; i++) { + if (i != 2 || _num_ports > 1 ) + report(GUID_FORMAT " ", info->guids[i].h, info->guids[i].l); + } + + + // VSD, PSID + + report("\nBoard ID: %s", info->vsd); + if (info->psid[0]) + report(" (%s)\n", info->psid); + else + report("\n"); + + report("VSD: %s\n", info->vsd); + report("PSID: %s\n", info->psid); + + return true; +} + +//////////////////////////////////////////////////////////////////////// +// // +// ****************************************************************** // +// Detect Device type and return matching Flash interface // +// ****************************************************************** // +// // +//////////////////////////////////////////////////////////////////////// + +Flash* get_serial_flash(mfile* mf) { + + enum { + CR_FLASH_TYPE = 0xf0810, + BO_FLASH_TYPE_S = 10, + BO_FLASH_TYPE_E = 11, + }; + + enum FlashType { + FT_LPC = 0, + FT_SPI = 1, + FT_XBUS = 2, + FT_EEPROM = 3 + }; + + char* flash_type_str[] = {"LPC", "SPI", "XBUS", "EEPROM"}; + + u_int32_ba strap_option; + u_int32_t flash_type; + + if (mread4(mf, CR_FLASH_TYPE, &strap_option) != 4) return false; + + flash_type = strap_option.range(BO_FLASH_TYPE_E, BO_FLASH_TYPE_S); + + + switch (flash_type) { + case FT_SPI: + return new SpiFlash; + case FT_LPC: + case FT_XBUS: + case FT_EEPROM: + printf("*** ERROR *** flash of type %s not supported.\n", + flash_type_str[flash_type]); + } + + return NULL; + +} + + +Flash* get_flash(const char* device, u_int32_t& num_ports) { + Flash* f = NULL; + + // + // Check device ID. Allocate flash accordingly + // + + u_int32_t dev_id; + + mfile* mf = mopen(device); + if (!mf) { + printf("*** ERROR *** Can't open %s: %s\n", device, strerror(errno)); + return NULL; + } + + if (mread4(mf, 0xf0014, &dev_id) != 4) return false; + + dev_id &= 0xffff; + + //printf("-D- read dev id: %d\n", dev_id); + + switch (dev_id) { + case 23108: + case 25208: + num_ports = 2; + f = new ParallelFlash; + break; + + case 24204: + case 25204: + num_ports = 1; + f = get_serial_flash(mf); + break; + + case 0xffff: + printf("*** ERROR *** Read a corrupted device id (0x%x). Probably HW/PCI access problem\n", dev_id); + default: + printf("*** ERROR *** Device type %d not supported.\n", dev_id); + } + + mclose(mf); + + return f; +} + + +//////////////////////////////////////////////////////////////////////// +// // +// ****************************************************************** // +// MAIN // +// ****************************************************************** // +// // +//////////////////////////////////////////////////////////////////////// +// sed -e 's/"/\\"/g' < flint.txt | perl -pe 's/^(.*)$/"$1\\n"/' +void usage(const char *sname, bool full = false) +{ + const char *descr = + "\n" + " FLINT - FLash INTerface\n" + "\n" + "InfiniHost flash memory operations.\n" + "\n" + "Usage:\n" + "------\n" + "\n" + " " FLINT_NAME " [switches...] [parameters...]\n" + "\n" + "\n" + "Switches summary:\n" + "-----------------\n" + " -bsn - Mellanox Board Serial Number (BSN).\n" + " Valid BSN format is:\n" + " MTxxxxx[-]R[xx]ddmmyy-nnn[-cc]\n" + " Commands affected: burn\n" + "\n" + " -crc - Print CRC after each section when verify.\n" + "\n" + " -d[evice] - Device flash is connected to.\n" + " Commands affected: all\n" + "\n" + " -guid - Base value for up to 4 GUIDs, which\n" + " are automatically assigned the\n" + " following values:\n" + "\n" + " guid -> node GUID\n" + " guid+1 -> port1\n" + " guid+2 -> port2\n" + " guid+3 -> system image GUID.\n" + "\n" + " Note: For a single port HCA, port2 guid is assigned\n" + " with the 'guid + 2' value, although it is ignored.\n" + "\n" + " Commands affected: burn\n" + "\n" + " -guids - 4 GUIDs must be specified here.\n" + " The specified GUIDs are assigned\n" + " the following values, repectively:\n" + " node, port1, port2 and system image GUID.\n" + "\n" + " Note: For a single port HCA, port2 guid must be\n" + " specified (can be set to 0x0), although it is ignored.\n" + "\n" + " Commands affected: burn\n" + "\n" + " -clear_semaphore - Force clear of the flash semaphore on the device.\n" + " This flag should come BEFORE the -d[evice] flag in the command line.\n" + " No command is allowed when this flag is used.\n" + " NOTE: Using this flag may result in an unstable behavior and flash image\n" + " corruption if the device or another flash application is currently\n" + " using the flash. Handle with care.\n" + "\n" + " -h[elp] - Prints this message and exits\n" + " -hh - Prints extended command help\n" + "\n" + " -i[mage] - Binary image file.\n" + " Commands affected: burn, verify\n" + "\n" + " -nofs - Burn image not in failsafe manner.\n" + "\n" + " -skip_is - Allow burning the FW image without updating the invariant sector,\n" + " to insures failsafe burning even when invariant sector difference is detected.\n" + " See the specific FW release notes for more details.\n" + "\n" + " -byte_mode - Shift address when accessing flash internal registers. May\n" + " be required for burn/write commands when accessing certain\n" + " flash types.\n" + "\n" +#if 0 + " -unlock - Use unlock bypass feature of the flash for quicker burn.\n" + " Commands affected: burn\n" + "\n" +#endif + " -s[ilent] - Do not print burn progress flyer.\n" + " Commands affected: burn\n" + "\n" + " -y[es] - Non interactive mode - assume answer\n" + " \"yes\" to all questions.\n" + " Commands affected: all\n" + "\n" + " -vsd - Write this string, of up to 208 characters, to VSD when burn.\n" + "\n" + " -psid - Write the Parameter Set ID (PSID) string to PS-ID field (last 16 bytes of VSD) when burn.\n" + "\n" + " -use_image_ps - Burn vsd as appears in the given image - don't keep existing vsd on flash.\n" + " Commands affected: burn\n" + "\n" + " -dual_image - Make the burn process burn two images on flash (previously default algorithm). Current\n" + " default failsafe burn process burns a single image (in alternating locations).\n" + " Commands affected: burn\n" + "\n" + " -v - Version info.\n" + "\n" + "Commands summary (use -hh flag for full commands description):\n" + "-----------------\n" + " b[urn] - Burn flash\n" + " e[rase] - Erase sector\n" + " q[uery] - Query misc. flash/FW characteristics\n" + " rw - Read one dword from flash\n" + " v[erify] - Verify entire flash\n" + " ww - Write one dword to flash\n" + " bb - Burn Block - Burns the given image as is. No checks are done.\n" + " wwne - Write one dword to flash without sector erase\n" + " wbne - Write a data block to flash without sector erase\n" + " rb - Read a data block from flash\n" + " ri - Read the fw image on the flash.\n" + " dc - Dump Configuration: print fw configuration file for the given image.\n" + "\n"; + + const char* full_descr = + "\n" + "Command descriptions:\n" + "----------------------------\n" + "\n" + "* Burn flash\n" + " Burns entire flash from raw binary image.\n" + "\n" + " Command:\n" + " b[urn]\n" + " Parameters:\n" + " None\n" + " Examples:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " -i image1.bin burn\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE2 " -guid 0x2c9000100d050 -i image1.bin b\n" + "\n" + "\n" + "* Burn Block\n" + " Burns entire flash from raw binary image as is. No checks are done on the flash or\n" + " on the given image file. No fields (such as VSD or Guids) are read from flash. \n" + "\n" + " Command:\n" + " bb\n" + " Parameters:\n" + " None\n" + " Examples:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " -i image1.bin bb\n" + "\n" + "\n" + "* Erase sector.\n" + " Erases a sector that contains specified address.\n" + "\n" + " Command:\n" + " e[rase]\n" + " Parameters:\n" + " addr - address of word in sector that you want\n" + " to erase.\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " erase 0x10000\n" + "\n" + "\n" + "* Query miscellaneous FW and flash parameters\n" + "\n" + " Command:\n" + " q[uery]\n" + " Parameters:\n" + " None\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " query\n" + "\n" + "\n" + "* Query flash device parameters (Common Flash Interface)\n" + "\n" + " Command:\n" + " cfi\n" + " Parameters:\n" + " None\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " cfi\n" + "\n" + "\n" + "* Read one dword from flash.\n" + "\n" + " Command:\n" + " rw\n" + " Parameters:\n" + " addr - address of word to read\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " rw 0x20\n" + "\n" + "\n" + "* Verify entire flash.\n" + "\n" + " Command:\n" + " v[erify]\n" + " Parameters:\n" + " None\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " v\n" + "\n" + "\n" + "* Write one dword to flash.\n" + " Note that the utility will read an entire flash sector,\n" + " modify one word and write the sector back. This may take\n" + " a few seconds.\n" + "\n" + " Command:\n" + " ww\n" + " Parameters:\n" + " addr - address of word\n" + " data - value of word\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " ww 0x10008 0x5a445a44\n" + "\n" + "\n" + "* Write one dword to flash without sector erase.\n" + " Note that the result of operation is undefined and depends\n" + " on flash type. Usually \"bitwise AND\" (&) between specified\n" + " word and previous flash contents will be written to\n" + " specified address.\n" + "\n" + " Command:\n" + " wwne\n" + " Parameters:\n" + " addr - address of word\n" + " data - value of word\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " wwne 0x10008 0x5a445a44\n" + "\n" + "* Read a data block from the flash and write it to a file or to screen.\n" + "\n" + " Command:\n" + " rb\n" + " Parameters:\n" + " addr - address of block\n" + " size - size of data to read in bytes\n" + " file - filename to write the block (raw binary). If not given, the data\n" + " is printed to screen\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " rb 0x10000 100 file.bin\n" + "\n" + "* Read the FW image from flash and write it to a file.\n" + "\n" + " Command:\n" + " ri\n" + " Parameters:\n" + " file - filename to write the image to (raw binary).\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " ri file.bin\n" + "\n" + "* Write a block of data to the flash without erasing.\n" + "\n" + " Command:\n" + " wbne\n" + " Parameters:\n" + " addr - address of block\n" + " size - size of data to write in bytes\n" + " data - data to write - space seperated dwords\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " wbne 0x10000 12 0x30000 0x76800 0x5a445a44\n" + "\n" + "* Print (to screen or to a file) the firmware configuration text file used by the image generation process.\n" + " This command would fail if the image does not contain a FW configuration section. Existence of this\n" + " section depends on the version of the image generation tool.\n" + "\n" + " Command:\n" + " dc\n" + " Parameters:\n" + " file - (optional) filename to write the dumped configuration to. If not given, the data\n" + " is printed to screen\n" + " Example:\n" + " " FLINT_NAME " -d " DEV_MST_EXAMPLE1 " dc\n" + "\n"; + + printf(descr, sname); + + if (full) { + printf(full_descr, sname); + } +} + + +// +// Signal handlers +// + +Flash* g_flash = NULL; + +#ifdef _WIN32 +HANDLE g_hMainTread = GetCurrentThread(); +#endif + + + +int g_signals_for_termination[] = { + SIGINT, +#ifndef _WIN32 + SIGHUP, +#endif + SIGTERM +}; + + + +void TerminationHandler (int signum) +{ + static volatile sig_atomic_t fatal_error_in_progress = 0; + +#ifdef _WIN32 + if (signum == 0) { + + report ("\nWarning: Got SIGINT. Raising SIGTERM\n"); + raise(SIGTERM); + return; + } + + report ("\nWarning: This program can not be interrupted.Please wait for its termination.\n"); + signal(signum, TerminationHandler); + return; +#endif + + + if (fatal_error_in_progress) + raise (signum); + fatal_error_in_progress = 1; + + signal (signum, SIG_DFL); + + if (g_flash != NULL) { + report("\n Received signal %d. Cleaning up ...", signum); + fflush(stdout); + sleep(1); // let erase sector end + g_flash->wait_ready("Process termination"); + + g_flash->close(); + report(" Done.\n"); + } + raise(signum); +} + +// +// Commands database and parsing methods +// +enum CommandInput { + CI_NONE = 0x01, + CI_IMG_ONLY = 0x02, + CI_DEV_ONLY = 0x04, + CI_IMG_OR_DEV = 0x06, + CI_IMG_AND_DEV = 0x08 +}; + +enum CommandType { + CMD_UNKNOWN, + CMD_BURN, + CMD_BURN_BLOCK, + CMD_QUERY, + CMD_VERIFY, + CMD_READ_WORD, + CMD_READ_BLOCK, + CMD_WRITE_WORD, + CMD_WRITE_WORD_NE, + CMD_WRITE_BLOCK, + CMD_WRITE_BLOCK_NE, + CMD_ERASE_SECT, + CMD_DUMP_CONF, + CMD_READ_IMAGE, + CMD_CFI, + CMD_CLEAR_SEM +}; + +struct CommandInfo { + CommandType cmd; + const char* cmdName; + bool requireExactMatch; + int maxArgs; + CommandInput requiredInput; + const char* cmdDescription; + +}; + +CommandInfo const g_commands[] = { + { CMD_BURN , "burn" ,false , 0 , CI_IMG_AND_DEV , ""}, + { CMD_BURN_BLOCK , "bb" ,true , 0 , CI_IMG_AND_DEV , ""}, + { CMD_QUERY , "query" ,false , 0 , CI_IMG_OR_DEV , ""}, + { CMD_VERIFY , "verify",false , 0 , CI_IMG_OR_DEV , ""}, + { CMD_READ_WORD , "rw" ,true , 1 , CI_DEV_ONLY , ""}, + { CMD_READ_BLOCK , "rb" ,true , 3 , CI_IMG_OR_DEV , ""}, + { CMD_WRITE_WORD , "ww" ,true , 2 , CI_DEV_ONLY , ""}, + { CMD_WRITE_WORD_NE , "wwne" ,true , 2 , CI_DEV_ONLY , ""}, + { CMD_WRITE_BLOCK , "wb" ,true , 2 , CI_DEV_ONLY , ""}, + { CMD_WRITE_BLOCK_NE , "wbne" ,true ,-1 , CI_DEV_ONLY , ""}, + { CMD_ERASE_SECT , "erase" ,false , 1 , CI_DEV_ONLY , ""}, + { CMD_DUMP_CONF , "dc" ,true , 1 , CI_IMG_OR_DEV , ""}, + { CMD_READ_IMAGE , "ri" ,true , 1 , CI_DEV_ONLY , ""}, + { CMD_CLEAR_SEM , "clear_semaphore" ,true , 0 , CI_DEV_ONLY , ""}, + { CMD_CFI , "cfi" ,true , 0 , CI_DEV_ONLY , ""} +}; + +#define numbel(x) (sizeof(x)/sizeof((x)[0])) + + +const CommandInfo* GetCommandInfo(CommandType cmd) { + for (u_int32_t i = 0 ; i < numbel(g_commands); i++ ) { + if (cmd == g_commands[i].cmd) { + return &g_commands[i]; + } + } + + return NULL; +} + +CommandType ParseCommand(const char* cmd) { + u_int32_t cmdLenGiven = strlen(cmd); + + for (u_int32_t i = 0 ; i < numbel(g_commands); i++ ) { + if (g_commands[i].requireExactMatch ) { + if (!strcmp(cmd, g_commands[i].cmdName)) { + return g_commands[i].cmd; + } + } else { + // Match if given cmd maches the beginning of the checked cmd + if (!strncmp(cmd, g_commands[i].cmdName, cmdLenGiven )) { + return g_commands[i].cmd; + } + } + } + return CMD_UNKNOWN; +} + + +bool CheckCommandInputs(const char* dev, + const char* img, + CommandType cmd) { + + const CommandInfo* cmdInfo = GetCommandInfo(cmd); + + if (!cmdInfo) { + printf("*** INTERNAL ERROR *** Unknown command given to CheckCommandInputs() (%d)\n", cmd); + return false; + } + + char* inputDesStr [] = { + NULL, + "neither a device nor an image file", // CI_NONE + "an image file", // CI_IMG_ONLY, + NULL, + "a device", // CI_DEV_ONLY, + NULL, + "either an image file or a device", // CI_IMG_OR_DEV, + NULL, + "both an image file and a device" // CI_IMG_AND_DEV + }; + + CommandInput given; + + if ( dev && img) { + given = CI_IMG_AND_DEV; + } else if (!dev && img) { + given = CI_IMG_ONLY; + } else if (dev && !img) { + given = CI_DEV_ONLY; + } else { + given = CI_NONE; + } + + if ((given & cmdInfo->requiredInput) == 0) { + printf("*** ERROR *** Command \"%s\" requires %s to be specified", + cmdInfo->cmdName, + inputDesStr[cmdInfo->requiredInput]); + + if (given != CI_NONE) { + printf(", but %s %s given.\n", + inputDesStr[given], + given == CI_IMG_AND_DEV ? "are" : "is"); + } else { + printf(".\n"); + } + + return false; + } + + return true; +} + +bool CheckMaxCmdArguments(CommandType cmd, int numArgs) { + const CommandInfo* cmdInfo = GetCommandInfo(cmd); + if (!cmdInfo) { + printf("*** INTERNAL ERROR *** Unknown command given to CheckMaxCmdArguments (%d)\n", cmd); + return false; + } + + if (cmdInfo->maxArgs >= 0 && numArgs > cmdInfo->maxArgs) { + printf("*** ERROR *** Command \"%s\" requires %d arguments, but %d arguments were given\n", + cmdInfo->cmdName, + cmdInfo->maxArgs, + numArgs); + return false; + } + return true; +} + +//////////////////////////////////////////////////////////////////////// +#define NEXTS(s) do { \ + if (++i >= ac) \ + { \ + printf("Missed parameter after \"%s\" switch\n", s); \ + return 1; \ + }} while(0) +#define NEXTC(p, s) do { \ + if (++i >= ac) \ + { \ + printf("Missed %s parameter after \"%s\" command\n", p,s); \ + return 1; \ + }} while(0) + +#define SETERR(args) do { printf("*** ERROR *** "); printf args; printf("\n"); return 1; } while(0) + + +int main(int ac, char *av[]) +{ + + char *image_fname=0, *device=0; + bool clear_semaphore = false; + bool silent = false; + bool guids_specified = false; + bool burn_failsafe = true; + bool use_image_ps = false; + bool single_image_burn = true; + + char* cmdStr = NULL; + + char *user_vsd=0; + char *user_psid=0; + guid_t user_guids[Operations::GUIDS]; + int rc = 0; + + CommandType cmd = CMD_UNKNOWN; + + auto_ptr f; + FImage fim; + + Operations ops; + + // + // Map termination signal handlers + // + int i; + for (i = 0 ; i < (int)(sizeof(g_signals_for_termination)/sizeof(g_signals_for_termination[0])) ; i++ ) { + signal (g_signals_for_termination[i], TerminationHandler); + } + + if (ac < 2) { + usage(av[0]); + rc = 1; goto done; + } + + // Go thru command line options + for (i=1; i < ac; i++) { + // + // Switches + // -------- + // + if (*av[i] == '-') { + int switchLen = strlen(av[i]); + + if (!strcmp(av[i], "-dual_image")) + single_image_burn = false; + + else if (!strcmp(av[i], "-clear_semaphore")) { + clear_semaphore = true; + } + + else if (!strncmp(av[i], "-device", switchLen)) { + NEXTS("-device"); + device = av[i]; + + //f.reset( get_flash(device) ); + + } else if (!strcmp(av[i], "-v") || !strcmp(av[i], "-vv")) { + printf("%s: %s .", + av[0], + _versionID); + + if (!strcmp(av[i], "-vv")) { + printf(" SVN %s", _svnID + 1); + } + + printf("\n"); + rc = 0; goto done; + + } else if (!strcmp(av[i], "-unlock")) { + _unlock_bypass = true; + } else if (!strcmp(av[i], "-noerase")) + _no_erase = true; + else if (!strcmp(av[i], "-noburn")) + _no_burn = true; + else if (!strcmp(av[i], "-crc")) + _print_crc = true; + else if (!strcmp(av[i], "-bytewrite")) { + if (device) { + printf("\"-bytewrite\" should be specifies before \"-device\" switch in the command line.\n"); + rc = 1; goto done; + } + _byte_write = true; + } else if (!strcmp(av[i], "-vsd")) { + NEXTS("-vsd"); + user_vsd = av[i]; + } + // -vsd1 is an alias to -vsd, for backward compatibility. Can be removed in the future. + else if (!strcmp(av[i], "-vsd1")) { + NEXTS("-vsd1"); + user_vsd = av[i]; + } else if (!strcmp(av[i], "-psid")) { + NEXTS("-psid"); + user_psid = av[i]; + } + // -vsd2 is an alias to psid, for backward compatibility. Can be removed in the future. + else if (!strcmp(av[i], "-vsd2")) { + NEXTS("-vsd2"); + user_psid = av[i]; + } else if (!strcmp(av[i], "-bsn")) { + NEXTS("-bsn"); + GETBSN(av[i], &user_guids[0]); + for (int i=1; i>32); + user_guids[i].l = (u_int32_t)g; + } + guids_specified = true; + } else if (!strncmp(av[i], "-image", switchLen)) { + NEXTS("-image"); + image_fname = av[i]; + } else if (!strcmp(av[i], "-guid")) { + NEXTS("-guid"); + GETGUID(av[i], &user_guids[0]); + for (int i=1; i>32); + user_guids[i].l = (u_int32_t)g; + } + guids_specified = true; + } else if (!strcmp(av[i], "-guids")) { + NEXTS("-guids"); + for (int j=0; j= ac) { + printf("Exactly four GUIDs must be specified.\n"); + rc = 1; goto done; + } + } + i--; + guids_specified = true; + } else if (!strncmp(av[i], "-silent", switchLen)) + silent = true; + else if (!strncmp(av[i], "-use_image_ps", 2)) + use_image_ps = true; + else if (!strncmp(av[i], "-nofs", 5)) + burn_failsafe = false; + else if (!strcmp(av[i], "-skip_is")) + ops.SetAllowSkipIs(true); + else if (!strncmp(av[i], "-yes", switchLen)) + _assume_yes = true; + else if (!strcmp(av[i], "-byte_mode")) + ParallelFlash::set_byte_mode(true); + + else if (!strncmp(av[i], "-hh", 3) || !strncmp(av[i], "--hh", 4)) { + usage(av[0], true); + rc = 1; goto done; + } else if (!strncmp(av[i], "-help", switchLen) || !strncmp(av[i], "--h", 3)) { + usage(av[0]); + rc = 1; goto done; + } else { + printf("*** ERROR *** Invalid switch \"%s\" is specified.\n", av[i]); + rc = 1; goto done; + } + } else { + // command + cmdStr = av[i]; + break; + } + } + + + // + // Commands + // -------- + // + + if (clear_semaphore) { + if (cmdStr) { + printf("*** ERROR *** No command is allowed when -clear_semaphore flag is given.\n"); + rc = 1; goto done; + } else { + cmdStr = "clear_semaphore"; + } + } + + if (!cmdStr) { + printf("*** ERROR *** No command given. See help for details.\n"); + rc = 1; goto done; + } + + // + // Check and parse command + // + cmd = ParseCommand(cmdStr); + + if (cmd == CMD_UNKNOWN) { + printf("*** ERROR *** Invalid command \"%s\".\n", av[i]); + rc = 1; goto done; + } + + if (cmd == CMD_CLEAR_SEM) { + clear_semaphore = true; + } + + if (!CheckCommandInputs(device, image_fname, cmd)) { + rc = 1; goto done; + } + + if (!CheckMaxCmdArguments(cmd, ac - i - 1 )) { + rc = 1; goto done; + } + + + FBase* fbase; + char* cmdTarget; + char* cmdAccess; + + if (device) { + // Open the device + + u_int32_t num_ports; + auto_ptr tmp( get_flash(device, num_ports)); + f = tmp; + + if (f.get() == NULL) { + printf("*** ERROR *** Can't get flash type using device %s\n", device); + rc = 1; goto done; + } + + ops.SetNumPorts(num_ports); + + g_flash = f.get(); + if (!f->open(device, clear_semaphore)) { + printf("*** ERROR *** Can't open %s: %s\n", device, f->err()); + rc = 1; goto done; + } + + cmdTarget = "Flash"; + cmdAccess = device; + fbase = f.get(); + } + + if (image_fname) { + if (!fim.open(image_fname)) { + printf("*** ERROR *** Image file open failed: %s\n", fim.err()); + rc = 1; goto done; + } + + cmdTarget = "Image file"; + cmdAccess = image_fname; + fbase = &fim; + } + + + + + + switch (cmd) { + case CMD_BURN: + case CMD_BURN_BLOCK: + { + + // + // BURN + // + + bool burn_block = (cmd == CMD_BURN_BLOCK); + + if (!burn_block) { + // Make checks and replace vsd/guids. + + Operations::ImageInfo fileInfo; + Operations::ImageInfo flashInfo; + + bool old_silent = _silent; + _silent = true; + if (!ops.Verify(fim) || !ops.QueryAll(fim, &fileInfo)) { + printf("*** ERROR *** %s: Not a valid image file (%s)\n", image_fname, ops.err()); + rc = 1; goto done; + } + + // Check that the flash sector size is well defined in the image + if (fim.get_sector_size() && (fim.get_sector_size() != f->get_sector_size())) { + printf("*** ERROR *** Flash sector size(0x%x) differs from sector size defined in the image (0x%x).\n" + " This means that the given FW file is not configured to work with the burnt HCA board type.\n", + f->get_sector_size(), + fim.get_sector_size()); + rc = 1; goto done; + } + + // Get GUID and VSD info from flash + + bool read_guids = true; + bool read_ps = true; + + // Flash query (unlike image file query) does not have to + // pass. E.G. blank flash and the user supplies the needed data (guids, vsd). + + bool flash_query_res = ops.QueryAll(*f, &flashInfo); + + if (guids_specified) + read_guids = false; + + if ((user_vsd && user_psid) || use_image_ps) + read_ps = false; + + if (read_guids && !flash_query_res) { + + if (read_guids && !flashInfo.imageOk) { + + printf("\n"); + printf("*** ERROR *** Can't extract GUIDS info from flash. " + "Please specify GUIDs (using command line flags -guid(s) ). \n"); + } + + if (burn_failsafe) { + printf(" Can't burn in a failsafe mode. Please use \"-nofs\" flag to burn in a none failsafe mode.\n"); + } + rc = 1; goto done; + } + + if (read_ps && !flashInfo.psOk) { + printf("\n"); + if (burn_failsafe) { + + printf("*** ERROR *** Can't extract VSD/PSID info from flash.\n" + " Can't burn in a failsafe mode. Please use \"-nofs\" flag to burn in a none failsafe mode.\n"); + rc = 1; goto done; + } else { + printf("*** WARNING *** Can't extract VSD/PSID info from flash.\n\n" + " To use a specific VSD, abort and re-burn specifying the\n" + " needed info (using command line flags -vsd / -use_image_ps).\n" + " You can also continue burn using blank VSD.\n"); + + if (!ops.ask_user("\n Continue burn using a blank VSD ? (y/n) ")) { + rc = 1; goto done; + } + } + } + + // Print FW versions: + printf(" Current FW version on flash: "); + if (flashInfo.infoFound[Operations::II_FwVersion]) { + printf("%d.%d.%d\n", flashInfo.fwVer[0], flashInfo.fwVer[1], flashInfo.fwVer[2]); + } else { + printf("N/A\n"); + } + + printf(" New FW version: "); + if (fileInfo.infoFound[Operations::II_FwVersion]) { + printf("%d.%d.%d\n", fileInfo.fwVer[0], fileInfo.fwVer[1], fileInfo.fwVer[2]); + } else { + printf("N/A\n"); + } + + + // Patch GUIDS + if (guids_specified) { + if (!ops.patchGUIDs(fim, + user_guids, + flashInfo.imageOk ? flashInfo.guids : NULL, + isatty(0) != 0)) { + rc = 1; goto done; + } + } else { + if (!ops.patchGUIDs(fim, NULL, flashInfo.guids, false)) { + rc = 1; goto done; + } + } + + if (_image_is_full && !use_image_ps) + if (!ops.patchVSD(fim, + user_vsd, + user_psid, + flashInfo.psOk ? flashInfo.vsd : NULL, + flashInfo.psOk ? flashInfo.psid : NULL, + fileInfo.psid )) { + rc = 1; goto done; + } + + _silent = old_silent; + } else { + // BURN BLOCK: + burn_failsafe = false; + } + + // Burn it + if (burn_failsafe) { + // Failsafe burn + if (!_image_is_full) { + printf("*** ERROR *** Failsafe burn failed: FW Image on flash is short.\n"); + printf("It is impossible to burn a short image in a failsafe mode.\n"); + printf("If you want to burn in non failsafe mode, use the \"-nofs\" switch.\n"); + rc = 1; goto done; + } + + // FS burn + if (!ops.FailSafe_burn(*f, + fim.getBuf(), + fim.getBufLength(), + single_image_burn, + !silent)) { + if (f->err()) { + // The error is in flash access: + printf("*** ERROR *** Flash access failed during burn: %s\n", f->err()); + } else { + // operation/ algorithm error: + printf("*** ERROR *** Failsafe burn failed: %s\n", ops.err()); + printf("If you want to burn in non failsafe mode, use the \"-nofs\" switch.\n"); + } + rc = 1; goto done; + } + } else { + // + // Not failsafe (sequential) burn + // + + // Ask is it OK + printf("\n"); + if (burn_block) { + printf("Block burn: The given image will be burnt as is. No fields (such\n"); + printf("as GUIDS,VSD) are taken from current image on flash.\n"); + } + printf("Burn process will not be failsafe. No checks are performed.\n"); + printf("ALL flash, including Invariant Sector will be overwritten.\n"); + printf("If this process fails computer may remain in unoperatable state.\n"); + + if (!ops.ask_user("\nAre you sure ? (y/n) [n] : ")) { + rc = 1; goto done; + } + + // Non FS burn + if (!ops.write_image(*f, 0, fim.getBuf(), fim.getBufLength(), + !silent)) { + report("\n"); + printf("*** ERROR *** Non failsafe burn failed: %s\n", ops.err()); + rc = 1; goto done; + } + report("\n"); + } + } + break; + + case CMD_ERASE_SECT: + { + // + // ERASE SECTOR + // Parameters: + // + u_int32_t addr; + char *endp; + + // Address of sector to erase + NEXTC("", "erase"); + addr = strtoul(av[i], &endp, 0); + if (*endp) { + printf("Invalid address \"%s\"\n", av[i]); + rc = 1; goto done; + } + + // Erase + if (!f->erase_sector(addr)) { + printf("*** ERROR *** Erase sector failed: %s\n", f->err()); + rc = 1; goto done; + } + } + break; + + case CMD_QUERY: + { + // QUERY + Operations::ImageInfo info; + + if (!ops.QueryAll(*fbase, &info)) { + printf("*** ERROR *** %s query (%s) failed: %s\n", cmdTarget , cmdAccess, ops.err()); + rc = 1; goto done; + } + + ops.DisplayImageInfo(&info); + } + break; + + case CMD_READ_BLOCK: + { + // READ BLOCK + // Parameters: [OUT_FILENAME] + // if OUT_FILENAME is given, binari read block is stored + // in the given file. Otherwise, data is printed to screen. + u_int32_t addr, length; + u_int8_t *data; + char *endp; + + bool to_file = false; + + // Address and length + NEXTC("", "rb"); + addr = strtoul(av[i], &endp, 0); + if (*endp) { + printf("Invalid address \"%s\"\n", av[i]); + rc = 1; goto done; + } + NEXTC("", "rb"); + length = strtoul(av[i], &endp, 0); + if (*endp) { + printf("Invalid length \"%s\"\n", av[i]); + rc = 1; goto done; + } + data = new u_int8_t[length]; + + // Output file + FILE* fh; + + if (i + 2 == ac) + to_file = true; + + if (to_file) { + NEXTC("", "rb"); + if ((fh = fopen(av[i], "wb")) == NULL) { + fprintf(stderr, "Can't open "); + perror(av[i]); + rc = 1; goto done; + } + } + + // Read flash + if (!fbase->read(addr, data, length)) { + printf("*** ERROR *** Flash read failed: %s\n", fbase->err()); + rc = 1; goto done; + } + + if (to_file) { + // Write output + if (fwrite(data, 1, length, fh) != length) { + perror("Write error"); + rc = 1; goto done; + } + fclose(fh); + } else { + for (u_int32_t i = 0; i < length ; i+=4) { + u_int32_t word = *((u_int32_t*)(data + i)); + + word = __be32_to_cpu(word); + printf("0x%08x ", word); + } + printf("\n"); + } + delete [] data; + } + break; + + case CMD_READ_WORD: + { + // READ DWORD + // Parameters: + u_int32_t data, addr; + char *endp; + + // Address + NEXTC("", "rw"); + addr = strtoul(av[i], &endp, 0); + if (*endp) { + printf("Invalid address \"%s\"\n", av[i]); + rc = 1; goto done; + } + + // Read + if (!f->read(addr, &data)) { + printf("*** ERROR *** Flash read failed: %s\n", f->err()); + rc = 1; goto done; + } + printf("0x%08x\n", (unsigned int)__cpu_to_be32(data)); + + } + break; + + case CMD_VERIFY: + { + // VERIFY + if (!ops.Verify(*fbase)) { + printf("\n*** ERROR *** FW Image verification failed. AN HCA DEVICE CAN NOT BOOT FROM THIS IMAGE.\n"); + rc = 1; goto done; + } else { + printf("\nFW Image verification succeeded. Image is OK.\n\n"); + } + } + break; + + case CMD_DUMP_CONF: + { + // Dump conf + _silent = true; + + char* conf_file = NULL; + if (i + 2 <= ac) { + NEXTC("", "dc"); + conf_file = av[i]; + } + + ops.Verify(*fbase); + + if(!ops.DumpConf(conf_file)) { + printf("*** ERROR *** Failed dumping FW configuration: %s\n", ops.err()); + rc = 1; goto done; + } + } + break; + + case CMD_READ_IMAGE: + { + // Dump conf + _silent = true; + + char* img_file = NULL; + NEXTC("", "ri"); + img_file = av[i]; + + ops.Verify(*f); + + //printf("Last addr: 0x%08x\n", ops._last_image_addr); + + u_int32_t length = ops._last_image_addr; + u_int8_t* data = new u_int8_t[length]; + + FILE* fh; + + if ((fh = fopen(av[i], "wb")) == NULL) { + fprintf(stderr, "Can't open "); + perror(av[i]); + rc = 1; goto done; + } + + // Read flash + if (!f->read(0, data, length)) { + printf("*** ERROR *** Flash read failed: %s\n", f->err()); + rc = 1; goto done; + } + + // Write output + if (fwrite(data, 1, length, fh) != length) { + perror("Write error"); + rc = 1; goto done; + } + fclose(fh); + + delete [] data; + } + break; + + case CMD_WRITE_BLOCK: + { + // WRITE BLOCK + // Parameters: + u_int32_t addr; + char *endp; + + char* fname; + + // Device + if (!device) { + printf("For wb command \"-device\" switch must be specified.\n"); + rc = 1; goto done; + } + + // Input file + FImage fim; + + NEXTC("", "wb"); + + fname = av[i]; + + // Address + NEXTC("", "wb"); + addr = strtoul(av[i], &endp, 0); + if (*endp) { + printf("Invalid address \"%s\"\n", av[i]); + rc = 1; goto done; + } + + if (!fim.open(image_fname)) { + printf("*** ERROR *** Image file open failed: %s\n", fim.err()); + rc = 1; goto done; + } + + // Write flash + if (!ops.write_image(*f, addr, fim.getBuf(), fim.getBufLength(), !silent)) { + printf("*** ERROR *** Flash write failed: %s\n", ops.err()); + rc = 1; goto done; + } + } + break; + + case CMD_WRITE_WORD: + { + // WRITE DWORD + // Parameters: + u_int32_t data, addr; + char *endp; + + // Address and data + NEXTC("", "ww"); + addr = strtoul(av[i], &endp, 0); + if (*endp) { + printf("Invalid address \"%s\"\n", av[i]); + rc = 1; goto done; + } + NEXTC("", "ww"); + data = __cpu_to_be32(strtoul(av[i], &endp, 0)); + if (*endp) { + printf("Invalid data \"%s\"\n", av[i]); + rc = 1; goto done; + } + + //f->curr_sector = 0xffffffff; // First time erase sector + if (!f->write(addr, data)) { + printf("*** ERROR *** Flash write failed: %s\n", f->err()); + rc = 1; goto done; + } + } + break; + + case CMD_WRITE_BLOCK_NE: + { + // WRITE DWORD WITHOUT ERASE + // Parameters: + u_int32_t size, addr; + char *endp; + + // Address and data + NEXTC("", "wbne"); + addr = strtoul(av[i], &endp, 0); + if (*endp) { + printf("Invalid address \"%s\"\n", av[i]); + rc = 1; goto done; + } + NEXTC("", "wbne"); + size = strtoul(av[i], &endp, 0); + if (*endp || size % 4) { + printf("Invalid size \"%s\"\n", av[i]); + rc = 1; goto done; + } + vector data_vec(size/4); + for (u_int32_t w = 0; w < size/4 ; w++) { + NEXTC("", "wbne"); + data_vec[w] = __cpu_to_be32(strtoul(av[i], &endp, 0)); + if (*endp) { + printf("Invalid data \"%s\"\n", av[i]); + rc = 1; goto done; + } + + //printf("-D- writing: %08x : %08x\n", addr + w*4 , data_vec[w]); + } + + if (!f->write(addr, &data_vec[0], size, true, false)) { + printf("*** ERROR *** Flash write failed: %s\n", f->err()); + rc = 1; goto done; + } + } + break; + + case CMD_WRITE_WORD_NE: + { + // WRITE DWORD WITHOUT ERASE + // Parameters: + u_int32_t data, addr; + char *endp; + + // Address and data + NEXTC("", "wwne"); + addr = strtoul(av[i], &endp, 0); + if (*endp) { + printf("Invalid address \"%s\"\n", av[i]); + rc = 1; goto done; + } + NEXTC("", "wwne"); + data = __cpu_to_be32(strtoul(av[i], &endp, 0)); + if (*endp) { + printf("Invalid data \"%s\"\n", av[i]); + rc = 1; goto done; + } + + if (!f->write(addr, &data, 4, true, false)) { + printf("*** ERROR *** Flash write failed: %s\n", f->err()); + rc = 1; goto done; + } + } + break; + + case CMD_CFI: + { + if (!f->print_cfi_info()) { + printf("*** ERROR *** Cfi query failed: %s\n", f->err()); + rc = 1; goto done; + } + } + break; + + case CMD_CLEAR_SEM: + // Do nothing - opening the device already cleared the semaphore. + break; + + default: + printf("*** INTERNAL ERROR *** Invalid command %d.\n", cmd); + rc = 1; goto done; + } + +done: + + //mask signals + for (i = 0 ; i < (int)(sizeof(g_signals_for_termination)/sizeof(g_signals_for_termination[0])) ; i++ ) { + signal (g_signals_for_termination[i], SIG_IGN); + } + + return rc; +} + diff --git a/trunk/tools/flint/user/flint.rc b/trunk/tools/flint/user/flint.rc new file mode 100644 index 00000000..2c7f074e --- /dev/null +++ b/trunk/tools/flint/user/flint.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mst.rc 219 2005-07-27 10:15:27Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Mellanox HCAs FW burning tool. (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Mellanox HCAs FW burning tool." +#endif + +#define VER_INTERNALNAME_STR "flint.exe" +#define VER_ORIGINALFILENAME_STR "flint.exe" + +#include diff --git a/trunk/tools/flint/user/makefile b/trunk/tools/flint/user/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/trunk/tools/flint/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/trunk/tools/mread/user/SOURCES b/trunk/tools/mread/user/SOURCES new file mode 100644 index 00000000..359ceff6 --- /dev/null +++ b/trunk/tools/mread/user/SOURCES @@ -0,0 +1,40 @@ +TARGETNAME=mread +TARGETTYPE=PROGRAM +UMTYPE=console +USE_CRTDLL=1 + + +!if !defined(WINIBHOME) +WINIBHOME=..\..\.. +!endif + +TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + + + +SOURCES=mread.c \ + mread.rc + +INCLUDES= $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; \ + $(WINIBHOME)\inc\iba; \ + $(WINIBHOME)\tools\mtcr\user; + +TARGETLIBS= \ +!if $(FREEBUILD) + $(TARGETPATH)\*\mtcr.lib +!else + $(TARGETPATH)\*\mtcr.lib +!endif + +!if $(FREEBUILD) + +!else +C_DEFINES=$(C_DEFINES) -DDEBUG +!endif + +C_DEFINES=$(C_DEFINES) -D__WIN__ + +386_STDCALL=0 + + diff --git a/trunk/tools/mread/user/makefile b/trunk/tools/mread/user/makefile new file mode 100644 index 00000000..80d407b3 --- /dev/null +++ b/trunk/tools/mread/user/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def + diff --git a/trunk/tools/mread/user/mread.c b/trunk/tools/mread/user/mread.c new file mode 100644 index 00000000..dd3db44c --- /dev/null +++ b/trunk/tools/mread/user/mread.c @@ -0,0 +1,73 @@ +/* + * + * mread.c - CR Space read access + * + */ + +#include +#include +#include + +#include "mtcr.h" + +void usage(const char *n) +{ + printf("%s []\n", n); + exit(1); +} + +int main(int ac, char *av[]) +{ + char *endp; + int rc=0; + unsigned int addr, val; + mfile *mf; + DType dtype = MST_TAVOR; + +#if 0 + int i, rc1; + char buf[1024], *p=buf; + rc1 = mdevices(buf, 1024); + for (i=0; i= 4) + mset_i2c_slave(mf, (unsigned char)strtoul(av[3],0,0)); + + if ((rc = mread4(mf, addr, &val)) < 0) + { + mclose(mf); + perror("mread"); + return 1; + } + if (rc < 4) + { + mclose(mf); + printf("Read only %d bytes\n", rc); + return 1; + } + + mclose(mf); + printf("Read 0x%08x:0x%08x\n", addr, val); + return rc; +} diff --git a/trunk/tools/mst/dirs b/trunk/tools/mst/dirs new file mode 100644 index 00000000..5a7e8b31 --- /dev/null +++ b/trunk/tools/mst/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/trunk/tools/mst/user/SOURCES b/trunk/tools/mst/user/SOURCES new file mode 100644 index 00000000..c6662baa --- /dev/null +++ b/trunk/tools/mst/user/SOURCES @@ -0,0 +1,41 @@ +TARGETNAME=mst +TARGETTYPE=PROGRAM +UMTYPE=console +USE_CRTDLL=1 + + +!if !defined(WINIBHOME) +WINIBHOME=..\..\.. +!endif + +TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + + + +SOURCES=mst.c \ + mst.rc + + +INCLUDES= $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; \ + $(WINIBHOME)\inc\iba; \ + $(WINIBHOME)\tools\mtcr\user; + +TARGETLIBS= \ +!if $(FREEBUILD) + $(TARGETPATH)\*\mtcr.lib +!else + $(TARGETPATH)\*\mtcr.lib +!endif + +!if $(FREEBUILD) + +!else +C_DEFINES=$(C_DEFINES) -DDEBUG +!endif + +C_DEFINES=$(C_DEFINES) -D__WIN__ + +386_STDCALL=0 + + diff --git a/trunk/tools/mst/user/makefile b/trunk/tools/mst/user/makefile new file mode 100644 index 00000000..80d407b3 --- /dev/null +++ b/trunk/tools/mst/user/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def + diff --git a/trunk/tools/mst/user/mst.c b/trunk/tools/mst/user/mst.c new file mode 100644 index 00000000..41a42601 --- /dev/null +++ b/trunk/tools/mst/user/mst.c @@ -0,0 +1,46 @@ +#include +#include +#include + +#include "mtcr.h" + +void usage(const char *n) +{ + printf("%s: List available mst devices.\nUsage: %s status\n", n, n); + exit(1); +} + +int list_devices() { + char buff[1024]; + int devs; + int i; + char* p = buff; + devs = mdevices(buff, sizeof(buff), 0xffffffff); + + if (devs < 0) { + printf("-E- Error getting devices\n"); + return 0; + } + + printf("Found %d devices:\n", devs); + + for (i = 0; i < devs ; i++) { + printf(" %s\n", p); + p += strlen(p) + 1; + } + return 1; +} + +int __cdecl main(int ac, char *av[]) +{ + + if (ac != 2 || strcmp(av[1],"status")) { + usage(av[0]); + } + + if (!list_devices()) + return 1; + + return 0; +} + diff --git a/trunk/tools/mst/user/mst.rc b/trunk/tools/mst/user/mst.rc new file mode 100644 index 00000000..75a4d4b7 --- /dev/null +++ b/trunk/tools/mst/user/mst.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mst.rc 219 2005-07-27 10:15:27Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Mellanox HW access device listing. (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Mellanox HW access device listing." +#endif + +#define VER_INTERNALNAME_STR "mst.exe" +#define VER_ORIGINALFILENAME_STR "mst.exe" + +#include diff --git a/trunk/tools/mtcr/dirs b/trunk/tools/mtcr/dirs new file mode 100644 index 00000000..5a7e8b31 --- /dev/null +++ b/trunk/tools/mtcr/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/trunk/tools/mtcr/user/SOURCES b/trunk/tools/mtcr/user/SOURCES new file mode 100644 index 00000000..d0111cfa --- /dev/null +++ b/trunk/tools/mtcr/user/SOURCES @@ -0,0 +1,87 @@ +# +# Name: sources +# +# Purpose: +# Building MTCR for this platform (user space) +# + +TARGETTYPE=DYNLINK +TARGETNAME=mtcr +DLLENTRY=_DllMainCRTStartup +DLLDEF=mtcr.def +USE_CRTDLL=1 + +!if !defined(WINIBHOME) +WINIBHOME=..\..\.. +!endif + +LIBPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + +TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + + +INCLUDES= $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; \ + $(WINIBHOME)\inc\iba; \ + .\usb; + + +SOURCES= \ + mtcr.rc \ + mtcr_i2c.c \ + mtcr.c \ + usb.cpp + + +TARGETLIBS= \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(CRT_LIB_PATH)\msvcrt.lib \ + $(TARGETPATH)\*\ibal.lib\ + $(SDK_LIB_PATH)\Kernel32.lib\ +!else + $(TARGETPATH)\*\complibd.lib\ + $(CRT_LIB_PATH)\msvcrt.lib\ + $(TARGETPATH)\*\ibald.lib\ + $(SDK_LIB_PATH)\Ws2_32.lib\ + $(SDK_LIB_PATH)\Kernel32.lib\ + +!endif + + +# dimax driver not provided for 64 bits arch. +MTCR_NO_USB=1 + + +!if !defined(MTCR_NO_USB) +TARGETLIBS=$(TARGETLIBS)\ + .\usb\usbi2cio.lib \ + .\usb\I2cBrdg.lib + +C_DEFINES=$(C_DEFINES) -DMTCR_USB_SUPPORT +!endif + + + + +# TODO:Should I define the __WIN__ manually +C_DEFINES=$(C_DEFINES) /DMTCR_EXPORTS /DMTL_MODULE=MTCR -D__WIN__ + + +!if $(FREEBUILD) + +!else +C_DEFINES=$(C_DEFINES) -DDEBUG -DDBG +!endif + + +# This is for the perl and zlib lib funcs, which requires __cdecl. +# TODO: define for all arch. check if MSC_STDCALL works. +386_STDCALL=0 +amd64_STDCALL=0 + +MSC_WARNING_LEVEL= /W3 + +#BUILD_CONSUMES=mlxsys +BUILD_PRODUCES=mtcr + diff --git a/trunk/tools/mtcr/user/com_def.h b/trunk/tools/mtcr/user/com_def.h new file mode 100644 index 00000000..52a1fe42 --- /dev/null +++ b/trunk/tools/mtcr/user/com_def.h @@ -0,0 +1,194 @@ +/* - Mellanox Confidential and Proprietary - + * + * Copyright (C) May 2002, Mellanox Technologies Ltd. ALL RIGHTS RESERVED. + * + * Except as specifically permitted herein, no portion of the information, + * including but not limited to object code and source code, may be reproduced, + * modified, distributed, republished or otherwise exploited in any form or by + * any means for any purpose without the prior written permission of Mellanox + * Technologies Ltd. Use of software subject to the terms and conditions + * detailed in the file "LICENSE.txt". + * + * End of legal section ...................................................... + * + * wincomat.h - Windows compatibility + * + * Version: $Id$ + * + * Author: Alex Rezinsky (alexr@mellanox.co.il) + */ + +#ifndef COM_DEF_H +#define COM_DEF_H + +#include +#include + + +#include + +// TODO: reference additional headers your program requires here +#include +#include + + +//----------------------------------------------------- +// DEBUG PRINTS +//----------------------------------------------------- + +#define DEBUG_LEVEL_HIGH 5 +#define DEBUG_LEVEL_MID 3 +#define DEBUG_LEVEL_LOW 1 +#define DEBUG_LEVEL_ALWAYS 0 + + +#ifdef __cplusplus +#define EXTERN_VAR extern "C" +#else +#define EXTERN_VAR extern +#endif + +EXTERN_VAR ULONG g_DebugLevel; + +// +// HACK: For this revision, allow debug prng (up to level 3) also for non debug build +// + +//#ifdef DBG +#define DEBUG_PRINT_ON 1 +//#else +// to see the prints - uncomment the next line and set level to DEBUG_LEVEL_MID +//#define DEBUG_PRINT_ON 1 +//#endif + +#ifdef DEBUG_PRINT_ON + + #include + #define M_DEBUG(args) do { printf("-D- "); printf args ;} while(0) + #define M_DEBUGS(args, stat) do { printf("-D- "); printf ("stat:%#x:%s: ", stat, ib_get_err_str(stat)); printf args ;} while(0) + + #define DBG_PRINT(lvl, params ) \ + if (g_DebugLevel >= lvl) { M_DEBUG (params); } + + #define DBG_PRINTS(lvl, params, stat ) \ + if (g_DebugLevel >= lvl) { M_DEBUGS (params, stat); } + +#else + #define DBG_PRINT(lvl, params ) + #define M_DEBUG(args) + #define M_DEBUGS(args, stat) + #define DBG_PRINTS(lvl, params, stat ) +#endif + + +#define DPRINT0(params) DBG_PRINT(DEBUG_LEVEL_ALWAYS, params) +#define DPRINT1(params) DBG_PRINT(DEBUG_LEVEL_LOW, params) +#define DPRINT3(params) DBG_PRINT(DEBUG_LEVEL_MID, params) + +#ifdef DBG +#define DPRINT5(params) DBG_PRINT(DEBUG_LEVEL_HIGH, params) +#else +#define DPRINT5(params) +#endif + +#define DPRINTS1(params, stat) DBG_PRINTS(DEBUG_LEVEL_LOW, params, stat) + + +/* + * Errors + */ +#include + + /****************** General Purpose Error Codes (0 to -999) *****************/ + +#define ERROR_LIST_GENERAL \ + INFO( MT_OK, 0, "success" ) \ + INFO( MT_ERROR, -1, "generic error" ) \ + INFO( MT_ENOINIT, -2, "module not initialized" ) \ + INFO( MT_EINVAL, -3, "invalid argument" ) \ + INFO( MT_ENORSC, -4, "No such resource (probably out of range)" ) \ + INFO( MT_EPERM, -5, "Not enough permissions to perform operation" ) \ + INFO( MT_ENOSYS, -6, "The system doesn't support requested operation" ) \ + INFO( MT_EAGAIN, -7, "Resource temporarily unavailable" ) \ + INFO( MT_EALIGN, -8, "Alignment error (offset/size not aligned)" ) \ + INFO( MT_EDEADLK, -9, "Resource deadlock avoided" ) \ + INFO( MT_ENOENT, -10, "No such file or directory" ) \ + INFO( MT_EACCES, -11, "Permission denied" ) \ + INFO( MT_EINTR, -12, "process received interrupt") \ + INFO( MT_ESTATE, -13, "Invalid state") \ + INFO( MT_ENOMOD, -ENOSYS, "module not loaded") /* When module not loaded, syscall return ENOSYS */ + + /**************** Memory Handling Error Codes (-1000 to -1199) **************/ + + +#define ERROR_LIST_MEMORY \ + INFO( MT_EKMALLOC, -1000, "Can't allocate kernel memory" ) \ + INFO( MT_ENOMEM, -1001, "Given address doesn't match process address space" ) \ + INFO( MT_EMALLOC, -1002, "malloc fail") \ + INFO( MT_EFAULT, -1003, "Bad address" ) + + /****************** General Device Error Codes (-1200 to -1399) *************/ + +#define ERROR_LIST_DEVICE \ + INFO( MT_ENODEV, -1200, "No such device" ) \ + INFO( MT_EBUSY, -1201, "Device or resource busy (or used by another)" ) \ + INFO( MT_EBUSBUSY, -1202, "Bus busy" ) + + /*********************** I2C Error Codes (-1400 to -1499) *******************/ + +#define ERROR_LIST_I2C \ + INFO( MT_EI2CNACK, -1400, "I2C: received NACK from slave" ) \ + INFO( MT_EI2PINHI, -1401, "I2C: Pending Interrupt Not does no become low" ) \ + INFO( MT_EI2TOUT, -1402, "I2C: Operation has been timed out" ) + +#define ERROR_LIST ERROR_LIST_GENERAL ERROR_LIST_MEMORY ERROR_LIST_DEVICE ERROR_LIST_I2C + + /** + ** See at end of file the full list of POSIX errors + **/ + + +typedef enum { +#define INFO(A,B,C) A = B, + ERROR_LIST +#undef INFO + MT_DUMMY_ERROR /* this one is needed to quite warning by -pedantic */ +} call_result_t; +/* + * Different names + */ +#define sys_errlist _sys_errlist + +/* + * Types + */ + +/* + * Endianess + */ +#define __be32_to_cpu __cpu_to_be32 + +#ifdef _WIN64 +#define __cpu_to_be32(x) ((((x) >> 24)&0x000000ff) | (((x) >> 8)&0x0000ff00) | (((x) << 8)&0x00ff0000) | (((x) << 24)&0xff000000)) +#elif defined(_WIN32) +__inline __int32 __cpu_to_be32( __int32 dwX ) +{ + _asm mov eax, dwX + _asm bswap eax + _asm mov dwX, eax + + return dwX; +} +#else +#error unsupported platform +#endif + +#define __be16_to_cpu __cpu_to_be16 +#define __cpu_to_be16(x) ((((x) >> 8)&0xff) | (((x) << 8)&0xff00)) + +/* + * usleep + */ +_inline void usleep( unsigned long x) { Sleep((x + 999) / 1000); } + +#endif diff --git a/trunk/tools/mtcr/user/makefile b/trunk/tools/mtcr/user/makefile new file mode 100644 index 00000000..80d407b3 --- /dev/null +++ b/trunk/tools/mtcr/user/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def + diff --git a/trunk/tools/mtcr/user/mtcr.c b/trunk/tools/mtcr/user/mtcr.c new file mode 100644 index 00000000..1105e0c9 --- /dev/null +++ b/trunk/tools/mtcr/user/mtcr.c @@ -0,0 +1,1064 @@ +// mtcr.c : Defines the entry point for the DLL application. +// +#include +#include +#include +#include + + +#include "com_def.h" +#include "usb.h" +#include "mtcr.h" +#include "mtcr_i2c.h" + +//----------------------------------------------------- +// NEW FEATURES +//----------------------------------------------------- +#define FIX_NAME 1 +#define SUPPORT_I2CM 1 + +#define USB_DEV_NAME "mtusb-1" +#define CLEAR(st) memset(&(st), 0, sizeof(st)) + + + +#define MTCR_DEBUG_ENV "MTCR_DEBUG_LEVEL" +#ifdef DBG +ULONG g_DebugLevel = DEBUG_LEVEL_MID; +#else +ULONG g_DebugLevel = DEBUG_LEVEL_LOW; +#endif + +//----------------------------------------------------- + + + + +// Copied from : #include +/* Definitions intended to become shared with UM. Later... */ + +typedef +struct _map_crspace { + PVOID va; /* address of CRSPACE, mapped to user space */ + PVOID ctx; /* opaque operation context; to be used in FW_UNMAP_CRSPACE */ + ULONG size; /* size of CRSPACE, mapped to user space */ +} map_crspace; + +typedef +struct _unmap_crspace { + PVOID va; /* address of CRSPACE, mapped to user space */ + PVOID ctx; /* operation context, received in FW_MAP_CRSPACE */ +} unmap_crspace; + + +/* Definitions for hca_driver commands*/ +#define FW_READ 0x00 +#define FW_WRITE 0x01 +#define FW_READ_CMD 0x08 +#define FW_WRITE_CMD 0x09 +#define FW_MAP_CRSPACE 0x0A +#define FW_UNMAP_CRSPACE 0x0B +#define FW_OPEN_IF 0xe7 +#define FW_CLOSE_IF 0x7e + + +#define MAX_HCA_NUM 16 + + +typedef struct mfile_ibal_t { + mfile s; + ib_al_handle_t h_al; + ib_ca_handle_t h_ca; + map_crspace cr_map; +} mfile_ibal; + + +BOOL APIENTRY DllMain( HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + char* pszDbgLevel; + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + // s_hCtl = (HANDLE)-1; + // ConnectToDriver(); + g_DebugLevel = 0; + pszDbgLevel = getenv(MTCR_DEBUG_ENV); + if (pszDbgLevel) { + g_DebugLevel = atol(pszDbgLevel); + } + + break; + + case DLL_PROCESS_DETACH: + // DisconnectFromDriver(); + break; + + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return TRUE; +} + +// device ids +#define DEVASYS_DEV_ID 12345 /* dummy */ +#define TAVOR_DEV_ID 23108 +#define TAVOR_CONF_DEV_ID 23109 +#define ARBEL_TM_DEV_ID 25208 +#define ARBEL_TM_CONF_DEV_ID 25209 +#define ARBEL_DEV_ID 25218 +#define ARBEL_CONF_DEV_ID 25219 +#define SINAI_4X_DEV_ID 24204 +#define SINAI_4X_CONF_DEV_ID 24205 +#define SINAI_8X_DEV_ID 25204 +#define SINAI_8X_CONF_DEV_ID 25205 + +#define IS_CONF_DEV(dev_id) \ + ((dev_id == TAVOR_CONF_DEV_ID) || \ + (dev_id == ARBEL_TM_CONF_DEV_ID) || \ + (dev_id == ARBEL_CONF_DEV_ID) || \ + (dev_id == SINAI_4X_CONF_DEV_ID) || \ + (dev_id == SINAI_8X_CONF_DEV_ID)) + +#define MAX_DEV_NAME 32 +typedef struct { + USHORT DevId; // Device Id, e.g. 23108 + UCHAR DevName[MAX_DEV_NAME]; // exported name, e.g. "InfiniHost" + Mdevs mask; +} DEVICE_DB_T, *PDEVICE_DB_T; + + +#define TAVOR_TYPE_DEVICE_NAME_FMT "mt%hu_pci%s%hu" +#define MDT_DEVICE_NAME_FMT "%s%hu" + +static DEVICE_DB_T db[] = { + { DEVASYS_DEV_ID, "devasys_usb", MDEVS_TAVOR }, + { TAVOR_DEV_ID, "InfiniHost", MDEVS_TAVOR }, + { TAVOR_CONF_DEV_ID, "InfiniHostBd", MDEVS_TAVOR_CR }, + { ARBEL_TM_DEV_ID, "InfiniHost", MDEVS_TAVOR }, + { ARBEL_TM_CONF_DEV_ID, "InfiniHostBd", MDEVS_TAVOR_CR }, + { ARBEL_DEV_ID, "InfiniHost_III_Ex", MDEVS_TAVOR }, + { ARBEL_CONF_DEV_ID, "InfiniHostBd", MDEVS_TAVOR_CR }, + { SINAI_4X_DEV_ID, "InfiniHost_III_Lx", MDEVS_TAVOR }, + { SINAI_4X_CONF_DEV_ID, "InfiniHostBd", MDEVS_TAVOR_CR }, + { SINAI_8X_DEV_ID, "InfiniHost_III_Lx", MDEVS_TAVOR }, + { SINAI_8X_CONF_DEV_ID, "InfiniHostBd", MDEVS_TAVOR_CR }, +}; +#define DEVICE_DB_SIZE (sizeof(db) / sizeof(DEVICE_DB_T)) + +Mdevs dmasks[] = { MDEVS_TAVOR_CR, MDEVS_TAVOR_CR, MDEVS_TAVOR_UAR, MDEVS_TAVOR_DDR }; +char *dsuffix[] = { "conf", "_cr", "_uar", "_ddr"}; +#define MASKS_SIZE (sizeof(dmasks) / sizeof(Mdevs)) + + +// Return: < 0 - Error. > 0 - Numbern of characters written (including last '\0') +int create_mst_names_by_dev_id(USHORT dev_id, int dev_ix, int mask, char *name, int name_len, int *cnt) +{ + int i,j; char *suffix; BOOL found = FALSE; char *nm_ptr = name; + int tot_len = 0; + + DPRINT3(( "create_mst_names_by_dev_id: dev_id %d, dev_ix %d, mask %#x, name_len %d\n", + dev_id, dev_ix, mask, name_len )); + + // specific stuff: for CONF devices create only "_cr" device + *name = 0; + *cnt = 0; + if (IS_CONF_DEV(dev_id)) { + int len; + tot_len += _snprintf(name, name_len, TAVOR_TYPE_DEVICE_NAME_FMT, dev_id, "conf", dev_ix ); + tot_len++; // trailing null + *cnt = 1; + return tot_len; + } + DPRINT3(( "create_mst_names_by_dev_id: not conf device %hu, is_conf_dev %d \n", + dev_id, IS_CONF_DEV(dev_id) )); + + // find device + for (i=0; i name_len) { + DPRINT1(( "create_mst_names_by_dev_id: not enough length (%d > %d)\n", + len, name_len )); + return -1; + } + // copy the results + DPRINT5(( "create_mst_names_by_dev_id: name %s\n", + l_name )); + memcpy( nm_ptr, l_name, len ); + nm_ptr += len; + tot_len += len; + name_len -= len; + (*cnt)++; + } + } + + return tot_len; +} + + +// Return: 0 - error, 1 - OK +int parse_mst_name(const char *mst_name, + PUSHORT dev_id, + PUSHORT dev_ix, + MType* mst_dev_type, + Mdevs* access_type) +{ + char *ptr; + char suffix[MAX_DEV_NAME]; + const char* fname; + + // Unix device name compatibility: Remove path (if exists) from device name: + + if ((fname = strrchr(mst_name, '/')) || (fname = strrchr(mst_name, '\\'))) { + DPRINT3(("Removing path from file: %s --> %s\n", mst_name, fname + 1)); + mst_name = fname + 1; + } + + suffix[0] = '\0'; + + if (strstr(mst_name, USB_DEV_NAME)) { + *dev_id = DEVASYS_DEV_ID; + *dev_ix =0; + *mst_dev_type = MST_USB; + + } else { + // get dev_id and suffix. dev_ix gets a dummy value. + sscanf( mst_name, TAVOR_TYPE_DEVICE_NAME_FMT, dev_id, suffix, dev_ix ); + // step over the suffix. ptr will be at the card's number + if ((ptr=strstr( suffix, "conf"))) { /* CONF device */ + ptr += 7; + *mst_dev_type = MST_PCICONF; + } else if ((ptr=strstr( suffix, "_cr"))) { + ptr += 3; + *mst_dev_type = MST_PCI; + *access_type = MDEVS_TAVOR_CR; + } else if ((ptr=strstr( suffix, "_uar"))) { + ptr += 4; + *mst_dev_type = MST_PCI; + *access_type = MDEVS_TAVOR_UAR; + } else if ((ptr=strstr( suffix, "_ddr"))) { + ptr += 4; + *mst_dev_type = MST_PCI; + *access_type = MDEVS_TAVOR_DDR; + } else { + DPRINT1(( "parse_mst_name: incorrect device name '%s' \n", mst_name )); + return 0; + } + + // get dev_ix + sscanf( ptr, "%hu", dev_ix ); + } + + DPRINT3( ("parse_mst_name: name %s, dev_id %d, dev_ix %d\n", + mst_name, *dev_id, *dev_ix)); + return 1; +} + + +// Return: 0 - error, 1 - OK +int create_mdt_name_by_dev_id(USHORT dev_id, USHORT dev_ix, char *name, int name_len) +{ + int i; + + DPRINT3(( "create_mdt_name_by_dev_id: dev_id %d, dev_ix %d\n", + dev_id, dev_ix )); + + // name generation + *name = 0; + for (i=0; i size) { + DPRINT1(("get_dev_ids(): Got buffer for %d HCAs, but %d HCAs found on machine.\n", size, ca_guids_count)); + goto ErrExit; + } + + for (i = 0; i < ca_guids_count ; i++) { + ib_ca_attr_t* ca_data; + u_int32_t bsize; + + cnt++; + + // Query the CA + ib_status = ib_query_ca_by_guid(h_al, guids[i], NULL, &bsize); + if(ib_status != IB_INSUFFICIENT_MEMORY) + { + DPRINTS1(("Failed to get size of query ca %d by guid.\n", i), ib_status); + dev_ids[i] = 0; + continue; + } + + ca_data = (ib_ca_attr_t*)malloc(bsize); + if (ca_data == NULL) { + DPRINT1(("get_dev_ids: malloc failed.\n")); + continue; + } + + ca_data->dev_id = 0; + + ib_status = ib_query_ca_by_guid(h_al, guids[i], ca_data, &bsize); + if(ib_status != IB_SUCCESS) + { + DPRINTS1(("Failed to query ca %d by guid.\n", i), ib_status); + } + + // Get the device id: + dev_ids[i] = ca_data->dev_id; + + free(ca_data); + + } + + goto OkExit; + +ErrExit: + cnt = -1; + +OkExit: + + return cnt; +} + + +int get_hca_idx(ib_al_handle_t h_al, USHORT dev_id, USHORT dev_ix) { + USHORT dev_ids[MAX_HCA_NUM]; + int cnt; + int i; + int matching_devs_found = 0; + + cnt = get_dev_ids(h_al, dev_ids, MAX_HCA_NUM); + + if (cnt < 0) { + return cnt; + } + + for (i = 0 ; i < cnt ; i++) { + if (dev_ids[i] == dev_id) { + if (matching_devs_found == dev_ix) { + DPRINT3(("get_hca_idx, type=%d, idx=%d. HCA index = %d\n", dev_id, dev_ix, i)); + return i; + } + matching_devs_found++; + } + } + + DPRINT3(("get_hca_idx, type=%d, idx=%d. No matching device found in %d HCAs\n", dev_id, dev_ix, i)); + + return -1; +} + + + +// +// dev_idx_by_type - stores current hca type idx for each type. Assumed to +// be in the same size of DEVICE_DB_SIZE +// +int get_and_inc_dev_idx(u_int32_t* dev_idx_by_type, USHORT dev_id) { + u_int32_t i; + int ret = -1; + + for (i = 0; i < DEVICE_DB_SIZE; i++) { + if (dev_id == db[i].DevId) { + ret = dev_idx_by_type[i]; + dev_idx_by_type[i]++; + break; + } + } + + return ret; +} + + +// +// +// List devices in their MST compatible names. +// Each device type is indexed sepetrately. +// +// + +MTCR_API int mdevices(char *buf, int len, int mask) +{ + u_int32_t tot_len = 0; + char* p = buf; + int devs = 0; + int i; + + u_int32_t dev_idx_by_type[DEVICE_DB_SIZE]; + USHORT dev_ids[MAX_HCA_NUM]; + int cnt = 0; + + ib_api_status_t ib_status; + ib_al_handle_t h_al = 0; + + + + memset( (char*)dev_idx_by_type, 0, sizeof(dev_idx_by_type)); + + ib_status = ib_open_al( &h_al ); + if ( ib_status != IB_SUCCESS ) { + DPRINTS1(("Failed to open AL\n"), ib_status ); + // return -1; + } else { + cnt = get_dev_ids(h_al, dev_ids, MAX_HCA_NUM); + + if (cnt < 0) { + cnt = 0; + } + + ib_close_al(h_al); + + } + + for(i = 0; i < cnt; i++) { + int idx; + int curr_cnt = 0; + int curr_len; + + if (dev_ids[i] == 0) { + continue; + } + + idx = get_and_inc_dev_idx(dev_idx_by_type, dev_ids[i]); + + if (idx < 0) { + DPRINT1(("mdevices: Unknown dev id detected: %d. skipped.\n", dev_ids[i])); + continue; + } + + // For now - get only TAVOR_CR (cr, conf ) devices. + curr_len = create_mst_names_by_dev_id(dev_ids[i], idx, MDEVS_TAVOR_CR , p , len - tot_len , &curr_cnt); + if (curr_cnt < 0) { + return -1; + } + + tot_len += curr_len; + p += curr_len; + devs += curr_cnt; + } + + + if (usb_is_connected() ) { + sprintf(p, USB_DEV_NAME ); + devs++; + } + + return devs; + +} + + +MTCR_API mfile *mopen(const char *name) +{ + return mopend(name, MST_TAVOR); +} + +MTCR_API mfile *mopend(const char *name, DType dtype) +{ + USHORT dev_id=0, dev_ix=0; + HANDLE h; + MType mst_dev_type; + Mdevs access_type; + int target_hca; + + /* allocate mfile struct */ + mfile_ibal *mf = (mfile_ibal *)malloc(sizeof(mfile_ibal)); + if (!mf) { + errno = ENOMEM; + return 0; + } + + memset( (char*)mf, 0, sizeof(mfile_ibal)); + + mf->s.sock = -1; + + /* parse name */ + + if (!parse_mst_name(name, &dev_id, &dev_ix, &mst_dev_type, &access_type )) { + goto ErrExit; + } + + DPRINT3(( "mopend: %s, dtype %d, devid %d\n", name, dtype, dev_id)); + + + switch(dev_id) { + case TAVOR_DEV_ID: case ARBEL_TM_DEV_ID: + case ARBEL_DEV_ID: case SINAI_4X_DEV_ID: + case SINAI_8X_DEV_ID: + mf->s.itype = MST_TAVOR; + break; + default: + mf->s.itype = MST_GAMLA; + } + + + /* Type of device */ + mf->s.dtype = dtype; + if (dtype == MST_TAVOR) + mf->s.i2c_slave = 0x48; + else + mf->s.i2c_slave = 0x5a; + +#ifdef SUPPORT_I2CM + /* Use the device as I2C master? */ + mf->s.is_i2cm = strstr(name, "i2cm") ? 1 : 0; + + /* Type of interface (relevant when is_i2cm==1, unused otherwise */ + if (mf->s.is_i2cm) + { + switch(dev_id) { + case TAVOR_DEV_ID: case ARBEL_TM_DEV_ID: + case ARBEL_DEV_ID: case SINAI_4X_DEV_ID: + case SINAI_8X_DEV_ID: + mf->s.itype = MST_TAVOR; + break; + default: + goto ErrExit; + } + } +#endif + + if (dev_id != DEVASYS_DEV_ID ) { + /* Open ibal HCA handle */ + u_int32_t stub; + + ib_net64_t guids[MAX_HCA_NUM]; + + ib_api_status_t ib_status; + size_t ca_guids_count = MAX_HCA_NUM; + + ib_status = ib_open_al( &mf->h_al ); + + if ( ib_status != IB_SUCCESS ) { + M_DEBUGS(("Failed to open AL\n"), ib_status ); + goto ErrExit; + } + + + ib_status = ib_get_ca_guids ( mf->h_al, guids, &ca_guids_count ); + if (ib_status != IB_SUCCESS) { + M_DEBUGS(("Failed to get CA GUIDs\n"), ib_status); + goto ErrExit; + } + + if (ca_guids_count == 0) { + DPRINT1(("FOUND NO GUIDS\n")); + goto ErrExit; + } + + target_hca = get_hca_idx(mf->h_al, dev_id , dev_ix ); + if (target_hca < 0) { + goto ErrExit; + } + + ib_status = ib_open_ca( mf->h_al, guids[target_hca], NULL, mf, &mf->h_ca ); + if (ib_status != IB_SUCCESS) + { + DPRINTS1(("Failed to open CA\n"), ib_status); + goto ErrExit; + } + + if(mst_dev_type == MST_PCICONF) { + // Type of file + mf->s.tp = MST_PCICONF; + + DPRINT5(("Calling: ibal_access(mf->h_ca, 0x0, &stub, 4, FW_OPEN_IF )\n")); + if (ibal_access(mf->h_ca, 0x0, &stub, 4, FW_OPEN_IF ) != IB_SUCCESS) { + goto ErrExit; + } + } else { + + int bar_num; + + // Type of file + mf->s.tp = MST_PCI; + + // calculate bar number + if (access_type == MDEVS_TAVOR_CR) { + // TODO: See what about UAR and DDR bars - not supported for now. + + } else { + DPRINT1(("Only _cr access is supported")); + goto ErrName; + } + + // check FW_MAP_CRSPACE + if (ibal_access(mf->h_ca, 0x0, &mf->cr_map, sizeof(mf->cr_map), FW_MAP_CRSPACE ) != IB_SUCCESS) { + goto ErrExit; + } + + mf->s.ptr = mf->cr_map.va; + } + + } else if (dev_id == DEVASYS_DEV_ID) { + // Type of file + h = usb_open(); + if ( h == INVALID_HANDLE_VALUE ) + goto ErrExit; + mf->s.fd = FromHandle(h); + // mf->s.tp = (usb_is_dimax()) ? MST_USB_DIMAX : MST_USB; + mf->s.tp = MST_USB; + } else { + goto ErrExit; + } + + /* OK */ + return (mfile*)mf; +ErrName: +// CloseHandle(h); +ErrExit: + mclose((mfile*)mf); + errno = ENODEV; + return 0; +} + +MTCR_API void maccelerate(mfile *mf) +{ +#ifdef SUPPORT_I2CM + if (mf->is_i2cm) + i2c_master_set((mfile*)mf); +#endif +} + +MTCR_API void mrestore(mfile *mf) +{ +#ifdef SUPPORT_I2CM + if (mf->is_i2cm) + i2c_master_restore(mf); +#endif +} + +MTCR_API int mclose(mfile *mf) +{ + int rc=0; + + if (mf->tp == MST_USB) { + rc = usb_close( (HANDLE)mf->fd); + } else { + mfile_ibal* mfi = (mfile_ibal*)mf; + u_int32_t stub; + + if (mf->tp == MST_PCICONF) { + ibal_access(mfi->h_ca, 0x0, &stub, 4, FW_CLOSE_IF ); + } else if (mf->tp = MST_PCI) { + if (mfi->cr_map.size) { + unmap_crspace unmap; + + unmap.va = mfi->cr_map.va; + unmap.ctx = mfi->cr_map.ctx; + if (ibal_access(mfi->h_ca, 0x0, &unmap, sizeof(unmap), FW_UNMAP_CRSPACE ) != IB_SUCCESS) { + DPRINT1(("Unmap crspace failed")); + } + } + } + + if (mfi->h_ca) + ib_close_ca( mfi->h_ca, NULL ); + if (mfi->h_al) + ib_close_al( mfi->h_al); + } + + free(mf); + return rc; +} + +MTCR_API int mread4(mfile *mf, unsigned int offset, u_int32_t *value) +{ + int rc = 4; + u_int32_t lvalue; + mfile_ibal* mfi = (mfile_ibal*)mf; + switch (mf->tp) { + + case MST_PCI: + + if (!mf->ptr) + return -1; + + if (offset >= mfi->cr_map.size) { + DPRINT1(("MTCR:mread4: Tried to access value at offset %x, which is out of pci bar (size %x)\n", + offset, + mfi->cr_map.size)); + errno = EINVAL; + return -1; + } + + +#ifdef SUPPORT_I2CM + if (mf->is_i2cm) + return i2c_master_read_cr(mf, value, offset, 4); +#endif + + if (mf->dtype == MST_TAVOR) + *value = __be32_to_cpu(*((volatile unsigned int *)((char *)mf->ptr + offset))); + else + *value = *((volatile unsigned int *)((char *)mf->ptr + offset)); + break; + + case MST_PCICONF: + { + +#ifdef SUPPORT_I2CM + if (mf->is_i2cm) + return i2c_master_read_cr(mf, value, offset, 4); +#endif + + if (ibal_access(((mfile_ibal*)mf)->h_ca, offset, value, 4, FW_READ_CMD) == IB_SUCCESS) { + rc = 4; + } else { + rc = -1; + } + + break; + } + + case MST_USB: + { + switch(mf->dtype) + { + case MST_GAMLA: + { + unsigned int offs = (usb_is_dimax()) ? offset : __cpu_to_be32(offset); + unsigned int addr_len = 2; + rc = usb_read( (HANDLE)mf->fd, I2C_TRANS_32ADR, mf->i2c_slave, offs, addr_len, + (u_int8_t*)&lvalue, 4 ); + break; + } + case MST_TAVOR: + default: + { + unsigned int offs = (usb_is_dimax()) ? offset : __cpu_to_be32(offset); + unsigned int addr_len = 4; + rc = usb_read( (HANDLE)mf->fd, I2C_TRANS_32ADR, mf->i2c_slave, offs, addr_len, + (u_int8_t*)&lvalue, 4 ); + break; + } + } + + if (rc == MT_OK) { + *value = __be32_to_cpu(lvalue); + rc = 4; + } + break; + + } + + default: + return -1; + } + + DPRINT5(( "MTCR:mread4: off 0x%x, val 0x%x\n", offset, *value)); + return rc; +} + +MTCR_API int mwrite4(mfile *mf, unsigned int offset, u_int32_t value) +{ + int rc = 4; + unsigned int lvalue; + mfile_ibal* mfi = (mfile_ibal*)mf; + + switch(mf->tp) + { + case MST_PCI: + if (!mf->ptr) + return -1; + + if (offset >= mfi->cr_map.size) { + DPRINT1(("MTCR:mwrite4: Tried to access value at offset %x, which is out of pci bar (size %x)\n", + offset, + mfi->cr_map.size)); + errno = EINVAL; + return -1; + } + +#ifdef SUPPORT_I2CM + if (mf->is_i2cm) + return i2c_master_write_cr(mf, value, offset, 4); +#endif + + if (mf->dtype == MST_TAVOR) + *((volatile unsigned int *)((char *)mf->ptr + offset)) = __cpu_to_be32(value); + else + *((volatile unsigned int *)((char *)mf->ptr + offset)) = value; + break; + + case MST_PCICONF: + { + +#ifdef SUPPORT_I2CM + if (mf->is_i2cm) + return i2c_master_write_cr(mf, value, offset, 4); +#endif + + if (ibal_access(((mfile_ibal*)mf)->h_ca, offset, &value, 4, FW_WRITE_CMD) == IB_SUCCESS) { + rc = 4; + } else { + rc = -1; + } + + break; + } + + case MST_USB: + { + + switch(mf->dtype) + { + case MST_GAMLA: + { + unsigned int offs = (usb_is_dimax()) ? offset : __cpu_to_be32(offset); + unsigned int addr_len = 2; + lvalue = __cpu_to_be32(value); + rc = usb_write( (HANDLE)mf->fd, I2C_TRANS_32ADR, mf->i2c_slave, offs, addr_len, + (u_int8_t*)&lvalue, 4 ); + break; + } + case MST_TAVOR: + default: + { + unsigned int offs = (usb_is_dimax()) ? offset : __cpu_to_be32(offset); + unsigned int addr_len = 4; + lvalue = __cpu_to_be32(value); + rc = usb_write( (HANDLE)mf->fd, I2C_TRANS_32ADR, mf->i2c_slave, offs, addr_len, + (u_int8_t*)&lvalue, 4 ); + break; + } + } + + if (rc == MT_OK) { + rc = 4; + } + break; + } + default: + return -1; + } + + DPRINT5(("MTCR:mwrite4: off 0x%x, val 0x%x\n", offset, value)); + return rc; +} + +MTCR_API int mread64(mfile *mf, unsigned int offset, void *data, int length) +{ + int rc; + + if (length > MAX_TRANS_SIZE) + { + errno = EINVAL; + return -1; + } + + switch(mf->tp) + { + case MST_PCI: + case MST_PCICONF: + { + int i; + unsigned char *cdata = (unsigned char *)data; + + for (i=0; idtype) + { + case MST_NOADDR: trans_type = I2C_TRANS_NOADR; aw = 0; break; + case MST_DIMM: trans_type = I2C_TRANS_8ADR; aw = 1; break; + case MST_GAMLA: trans_type = I2C_TRANS_16ADR; aw = 2; break; + case MST_TAVOR: trans_type = I2C_TRANS_32ADR; aw = 4; break; + } + + ret = usb_read((HANDLE)mf->fd, trans_type, mf->i2c_slave, offset, aw, data, length); + if (ret == MT_OK) { + return length; + } else { + errno = ret; + return -1; + } + } +#endif + + + } + + errno = EPERM; + return -1; +} + + +MTCR_API int mwrite64(mfile *mf, unsigned int offset, void *data, int length) +{ + + int rc; + + if (length > MAX_TRANS_SIZE) + { + errno = EINVAL; + return -1; + } + + switch(mf->tp) + { + case MST_PCI: + case MST_PCICONF: + { + int i; + unsigned char *cdata = (unsigned char *)data; + + for (i=0; idtype) + { + case MST_NOADDR: trans_type = I2C_TRANS_NOADR; aw = 0; break; + case MST_DIMM: trans_type = I2C_TRANS_8ADR; aw = 1; break; + case MST_GAMLA: trans_type = I2C_TRANS_16ADR; aw = 2; break; + case MST_TAVOR: trans_type = I2C_TRANS_32ADR; aw = 4; break; + } + + ret = usb_write((HANDLE)mf->fd, trans_type, mf->i2c_slave, offset, aw, data, length); + if (ret == MT_OK) { + return length; + } else { + errno = ret; + return -1; + } + } +#endif + + } + + errno = EPERM; + return -1; +} + +unsigned char mset_i2c_slave(mfile *mf, unsigned char new_i2c_slave) +{ + unsigned char ret; + if (mf) + { + ret = mf->i2c_slave; + mf->i2c_slave = new_i2c_slave; + } + else + ret = 0xff; + return ret; +} + diff --git a/trunk/tools/mtcr/user/mtcr.def b/trunk/tools/mtcr/user/mtcr.def new file mode 100644 index 00000000..dead913e --- /dev/null +++ b/trunk/tools/mtcr/user/mtcr.def @@ -0,0 +1 @@ +EXPORTS \ No newline at end of file diff --git a/trunk/tools/mtcr/user/mtcr.h b/trunk/tools/mtcr/user/mtcr.h new file mode 100644 index 00000000..b799fd3d --- /dev/null +++ b/trunk/tools/mtcr/user/mtcr.h @@ -0,0 +1,216 @@ +/* + * + * mtcr.h - Mellanox Software tools (mst) driver definitions + * + */ + +#ifndef _MST_H +#define _MST_H + + +#ifdef __WIN__ + +#include + +#ifdef MTCR_EXPORTS +#define MTCR_API __declspec(dllexport) +#else +#define MTCR_API __declspec(dllimport) +#endif + +typedef unsigned __int8 u_int8_t; +typedef __int8 int8_t; +typedef unsigned __int16 u_int16_t; +typedef __int16 int16_t; +typedef unsigned __int32 u_int32_t; +typedef __int32 int32_t; +typedef unsigned __int64 u_int64_t; +typedef __int64 int64_t; + +#if defined(_WIN64) + typedef __int64 MT_long_ptr_t; + typedef unsigned __int64 MT_ulong_ptr_t; +#else + typedef _W64 long MT_long_ptr_t; + typedef _W64 unsigned long MT_ulong_ptr_t; +#endif + +#else /* UNIX */ + +#include +#define MTCR_API + +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef USE_IB_MGT +typedef struct mib_private_t { + int dummy; +} MIB_Private; +#else +#include "mtcr_ib_private.h" +#endif + +typedef enum MType_t {MST_PCI, MST_PCICONF, MST_CALBR, MST_USB, + MST_IB, MST_IF, MST_PPC, MST_USB_DIMAX +#ifdef ENABLE_MST_DEV_I2C + ,MST_DEV_I2C +#endif +} MType; +typedef enum DType_t {MST_GAMLA, MST_TAVOR, MST_DIMM, MST_NOADDR} DType; +#define MST_ANAFA2 MST_TAVOR +#define MST_EEPROM MST_GAMLA +typedef enum Mdevs_t { + MDEVS_GAMLA = 0x01, /* Each device that actually is a Gamla */ + MDEVS_I2CM = 0x02, /* Each device that can work as I2C master */ + MDEVS_MEM = 0x04, /* Each device that is a memory driver (vtop) */ + MDEVS_TAVOR_DDR = 0x08, /* Each device that maps to Tavor DDR */ + MDEVS_TAVOR_UAR = 0x10, /* Each device that maps to Tavor UAR */ + MDEVS_TAVOR_CR = 0x20, /* Each device that maps to Tavor CR */ + MDEVS_IF = 0x40, /* Standard device interface */ + MDEVS_REM = 0x80, /* Remote devices */ + MDEVS_PPC = 0x100, /* PPC devices */ + MDEVS_DEV_I2C = 0x200, /* Generic linux kernel i2c device */ + MDEVS_TAVOR = (MDEVS_TAVOR_DDR|MDEVS_TAVOR_UAR|MDEVS_TAVOR_CR), + MDEVS_ALL = 0xffffffff +} Mdevs; + +/* All fields in follow structure are not supposed to be used */ +/* or modified by user programs. Except i2c_slave that may be */ +/* modified before each access to target I2C slave address */ +typedef struct mfile_t { + MType tp; /* type of driver */ + DType dtype; /* target device to access to */ + DType itype; /* interface device to access via */ + int is_i2cm; /* use device as I2C master */ + unsigned char i2c_slave; +#ifdef __WIN__ + MT_ulong_ptr_t fd; +#else + int fd; +#endif + int sock; /* in not -1 - remote interface */ + void *ptr; + MIB_Private mib; /* Data for IB interface (if relevant) */ + unsigned int i2c_RESERVED; /* Reserved for internal usage (i2c internal) */ + enum Mdevs_t flags; +} mfile; + +#ifdef __WIN__ +#define FromHandle(h) ((MT_ulong_ptr_t)(h)) +#define ToHandle(h) ((HANDLE)(h)) +#else +#define FromHandle(h) ((int)(h)) +#define ToHandle(h) ((HANDLE)(h)) +#endif + +/* + * Get list of MST (Mellanox Software Tools) devices. + * Put all device names as null-terminated strings to buf. + * + * Return number of devices found or -1 if buf overflow + */ +MTCR_API int mdevices(char *buf, int len, int mask); + +/* + * Open Mellanox Software tools (mst) driver. + * Return valid mfile ptr or 0 on failure + */ +MTCR_API mfile *mopend(const char *name, DType dtype); + +/* + * Open Mellanox Software tools (mst) driver. Device type==TAVOR + * Return valid mfile ptr or 0 on failure + */ +MTCR_API mfile *mopen(const char *name); + +/* + * Close Mellanox driver + * req. descriptor + */ +MTCR_API int mclose(mfile *mf); + +/* + * Accelerate device if possible. + * When device is I2C master - overclock it + */ +MTCR_API void maccelerate(mfile *mf); + +/* + * Restore normal settings, if device was accelerated. + */ +MTCR_API void mrestore(mfile *mf); + +/* + * Read 4 bytes, return number of succ. read bytes or -1 on failure + */ +MTCR_API int mread4(mfile *mf, unsigned int offset, u_int32_t *value); + +/* + * Write 4 bytes, return number of succ. written bytes or -1 on failure + */ +MTCR_API int mwrite4(mfile *mf, unsigned int offset, u_int32_t value); + +/* + * Read lots of bytes, return number of succ. read bytes or -1 on failure + * + * Works for any interface, but important for long bursts. + */ +MTCR_API int mread_by_chunks(mfile *mf, unsigned int offset, void *data, int length); + +/* + * Read up to 64 bytes, return number of succ. read bytes or -1 on failure + * + * This makes sense only w/ CALIBRE/DevaSys interfaces *to EEPROM reading only* + */ +MTCR_API int mread64(mfile *mf, unsigned int offset, void *data, int length); + +/* + * Write up to 64 bytes, return number of succ. written bytes or -1 on failure + * + * This makes sense only w/ CALIBRE/DevaSys interfaces *to EEPROM burning only* + */ +MTCR_API int mwrite64(mfile *mf, unsigned int offset, void *data, int length); + +/* + * Set a new value for i2c_slave + * Return previous value + */ +MTCR_API unsigned char mset_i2c_slave(mfile *mf, unsigned char new_i2c_slave); + +/* + * get free phys. contigous pages + * order should be in range [0..9] + * the size of allocated memory will be (2^order * 4096) + * return pointer to virtual address mapped to the allocated area + * on failure returns 0 and errno is set + */ +MTCR_API void *mget_free_pages (mfile *mf, unsigned int order); + +/* + * free phys. contigous pages + * order should be in range [0..9] + * vma is freed + * on success returns 0 + * on failure returns -1 and errno is set + */ +MTCR_API int mfree_pages (mfile *mf, void *addr, unsigned int order); + + + +/* + * translate virtual address to physical address + * return physical address on success, or 0 on error + */ +MTCR_API unsigned long mvtop (mfile *mf, void *va); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/trunk/tools/mtcr/user/mtcr.rc b/trunk/tools/mtcr/user/mtcr.rc new file mode 100644 index 00000000..f2a383a4 --- /dev/null +++ b/trunk/tools/mtcr/user/mtcr.rc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: vstat.rc 219 2005-07-27 10:15:27Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#ifdef _DEBUG_ +#ifdef MTCR_USB_SUPPORT +#define VER_FILEDESCRIPTION_STR "Mellanox HW Access library (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Mellanox HW Access library. No USB support. (Debug)" +#endif + +#else + +#ifdef MTCR_USB_SUPPORT +#define VER_FILEDESCRIPTION_STR "Mellanox HW Access library" +#else +#define VER_FILEDESCRIPTION_STR "Mellanox HW Access library. No USB support." +#endif + +#endif + +#define VER_INTERNALNAME_STR "mtcr.dll" +#define VER_ORIGINALFILENAME_STR "mtcr.dll" + +#include diff --git a/trunk/tools/mtcr/user/mtcr_i2c.c b/trunk/tools/mtcr/user/mtcr_i2c.c new file mode 100644 index 00000000..fb03a942 --- /dev/null +++ b/trunk/tools/mtcr/user/mtcr_i2c.c @@ -0,0 +1,612 @@ +/* - Mellanox Confidential and Proprietary - + * + * Copyright (C) March 2002, Mellanox Technologies Ltd. ALL RIGHTS RESERVED. + * + * Except as specifically permitted herein, no portion of the information, + * including but not limited to object code and source code, may be reproduced, + * modified, distributed, republished or otherwise exploited in any form or by + * any means for any purpose without the prior written permission of Mellanox + * Technologies Ltd. Use of software subject to the terms and conditions + * detailed in the file "LICENSE.txt". + * + * End of legal section ...................................................... + * + */ + +/* + * + * mtcr_i2c.c - Mellanox Software tools (mst) driver: I2C master routines + * + */ + + +#include +#include +#include +#include + +#ifdef __WIN__ +#include "com_def.h" +#else +#include + +#include + + +#include +#include +#include "mst_pci.h" +#include "mst_pciconf.h" +#endif + +#include "mtcr.h" +#include "mtcr_i2c.h" + + +#define REPEAT_WRITE_IF_NACK +/* #define LOWR_LEVEL_DEBUG */ +/* #define LOWW_LEVEL_DEBUG */ +/* #define MID_LEVEL_DEBUG */ +/* #define HIGH_LEVEL_DEBUG */ + +enum CONSTANTS { + EPROM_PRIMARY_COUNT = 5000, /* Amount of "fast" check */ + EPROM_SECONDARY_COUNT = 10, /* Amount of "slow" check */ + EPROM_REQUEST_PAUSE = 100, /* Microseconds for pause */ + MAX_REPETITION = 100, /* Maximal number of transaction repet. */ + ST_IN_TRANSACTION = 7, /* Status: cycle in transaction completed OK */ + ST_TIMEOUT = 6, /* Status: transaction timeout */ + ST_IDLE = 0 /* Status: IDLE */ +}; + +/* SPM registers offset */ +#define SPM_OFFS ((mf->itype == MST_TAVOR) ? 0xf0180 : 0x3180) + +#define CLEAR(st) memset(&(st), 0, sizeof(st)) + +/* Like mread4, but only for PCI/PCICONF interfaces and doesn't check is_i2cm */ +static int mread4_(mfile *mf, unsigned int offset, unsigned int *value) +{ + int rc = 4; + + +#ifdef SUPPORT_PCICONF + struct mst_read4_st r4; +#endif + + +#ifdef LOWR_LEVEL_DEBUG + printf("mread4_: tp=%d,itype=%d - try read offs=0x%x\n", + mf->tp, mf->itype, offset); +#endif + + switch(mf->tp) + { + case MST_PCI: + if (!mf->ptr) + { + errno = EFAULT; + return -1; + } + + if (mf->itype == MST_TAVOR) + *value = __be32_to_cpu(*((unsigned int *)((char *)mf->ptr + offset))); + else + *value = *((unsigned int *)((char *)mf->ptr + offset)); + break; +#ifdef SUPPORT_PCICONF + case MST_PCICONF: + CLEAR(r4); + r4.offset = offset; + if ((rc = ioctl(mf->fd, PCICONF_READ4, &r4)) < 0) + return rc; + *value = r4.data; + rc = 4; + break; +#endif + default: + errno = EINVAL; + rc = -1; + } + +#ifdef LOWR_LEVEL_DEBUG + printf(" mread4_: rc=%d,offs=0x%x val=0x%08x\n", rc, offset, *value); +#endif + + return rc; +} + +/* Like mwrite4, but only for PCI/PCICONF interfaces and doesn't check is_i2cm */ +static int mwrite4_(mfile *mf, unsigned int offset, unsigned int value) +{ + int rc = 4; + + +#ifdef SUPPORT_PCICONF + struct mst_write4_st r4; +#endif + +#ifdef LOWW_LEVEL_DEBUG + printf("mwrite4_: tp=%d,itype=%d - try write offs=0x%x val=0x%08x\n", + mf->tp, mf->itype, offset, value); +#endif + + switch(mf->tp) + { + case MST_PCI: + if (!mf->ptr) + { + errno = EFAULT; + return -1; + } + + if (mf->itype == MST_TAVOR) + *((unsigned int *)((char *)mf->ptr + offset)) = __cpu_to_be32(value); + else + *((unsigned int *)((char *)mf->ptr + offset)) = value; + break; +#ifdef SUPPORT_PCICONF + case MST_PCICONF: + CLEAR(r4); + r4.offset = offset; + r4.data = value; + if ((rc = ioctl(mf->fd, PCICONF_WRITE4, &r4)) < 0) + return rc; + rc = 4; + break; +#endif + default: + errno = EINVAL; + rc = -1; + } + +#ifdef LOWW_LEVEL_DEBUG + printf(" mwrite4_: rc=%d\n", rc); +#endif + + return rc; +} + + +/* Return -1 when I/O error or cmd doesn't become zero */ +/* Return status field otherwise */ +static int wait_trans(mfile *mf) +{ + u_int32_t val; + u_int32_t cnt = 0; + + while(1) + { + if (mread4_(mf, SPM_OFFS, &val) != 4) + return -1; + if (!(val >> 29)) + break; + if (cnt > EPROM_PRIMARY_COUNT) + usleep(EPROM_REQUEST_PAUSE); + if (cnt > EPROM_PRIMARY_COUNT+EPROM_SECONDARY_COUNT) + { + errno = EBUSY; + return -1; + } + cnt++; + } + return (val>>16) & 0x07; +} + +/* Return status field or -1 on fatal failure */ +static int w_trans(mfile *mf, void *data_, int len) +{ + char *data = (char *)data_; + int vbt = -1; + u_int32_t val = 0; + +#ifdef MID_LEVEL_DEBUG + printf("w_trans: data=0x%08x, len:%d\n", *(unsigned int *)data, len); +#endif + + switch (len) + { + case 1: + vbt = 0; + val = (*data << 24) & 0xff000000; + break; + case 2: + vbt = 1; + val = ((*data << 24) & 0xff000000) | ((data[1] << 16) & 0xff0000); + break; + case 3: + vbt = 2; + val = ((*data << 24) & 0xff000000) | ((data[1] << 16) & 0xff0000) | + ((data[2] << 8) & 0xff00); + break; + case 4: + vbt = 3; + val = ((*data << 24) & 0xff000000) | ((data[1] << 16) & 0xff0000) | + ((data[2] << 8) & 0xff00) | (data[3] & 0xff); + break; + default: + return -1; + } + if (mwrite4_(mf, SPM_OFFS + 4, val) != 4) + return -1; + if (mwrite4_(mf, SPM_OFFS, (2<<29) | (vbt << 22) | (mf->i2c_slave & 0x7f)) != 4) + return -1; + + return wait_trans(mf); +} + + +/* Return status field or -1 on fatal failure */ +static int r_trans(mfile *mf, void *data_, int len) +{ + char *data = (char *)data_; + int vbt = -1, rc; + u_int32_t val = 0; + +#ifdef MID_LEVEL_DEBUG + printf("r_trans: len:%d\n", len); +#endif + + switch (len) + { + case 1: + vbt = 0; + break; + case 2: + vbt = 1; + break; + case 3: + vbt = 2; + break; + case 4: + vbt = 3; + break; + default: + return -1; + } + + if (mwrite4_(mf, SPM_OFFS, (1<<29) | (vbt << 22) | (mf->i2c_slave & 0x7f)) != 4) + return -1; + rc = wait_trans(mf); + if (rc != 7) + return rc; + + if (mread4_(mf, SPM_OFFS + 4, &val) != 4) + return -1; + + switch (len) + { + case 1: + *data = (val >> 24) & 0xff; + break; + case 2: + *data++ = (val >> 24) & 0xff; + *data = (val >> 16) & 0xff; + break; + case 3: + *data++ = (val >> 24) & 0xff; + *data++ = (val >> 16) & 0xff; + *data = (val >> 8) & 0xff; + break; + case 4: + *data++ = (val >> 24) & 0xff; + *data++ = (val >> 16) & 0xff; + *data++ = (val >> 8) & 0xff; + *data = val & 0xff; + break; + default: + return -1; + } + return 7; +} + +/* Return status field or -1 on fatal failure */ +static int end_trans(mfile *mf) +{ + if (mwrite4_(mf, SPM_OFFS, (3<<29) | (mf->i2c_slave & 0x7f)) != 4) + return -1; + return wait_trans(mf); +} + +int i2c_master_write_cr(mfile *mf, unsigned int value, unsigned int offset, + int len) +{ + unsigned int ivalue = __cpu_to_be32(value); + unsigned short svalue = __cpu_to_be16((unsigned short)(value & 0xffff)); + unsigned char cvalue = value & 0xff; + int rc=0, repeat=1; + unsigned short offs = __cpu_to_be16(offset & 0xffff); + unsigned char off1 = offset & 0xff; + +#ifdef HIGH_LEVEL_DEBUG + printf("i2c_master_write_cr i2c:0x%x, offs:0x%x, val:0x%x, len:%d\n", + mf->i2c_slave, offset, value, len); +#endif + + offset = __cpu_to_be32(offset); + + while (repeat) + { + /* Write address (1byte for DIMM, 2bytes for Gamla and 4bytes for Tavor) */ + switch(mf->dtype) + { + case MST_TAVOR: + rc = w_trans(mf, &offset, sizeof(offset)); + break; + case MST_GAMLA: + rc = w_trans(mf, &offs, sizeof(offs)); + break; + case MST_DIMM: + rc = w_trans(mf, &off1, sizeof(off1)); + break; + case MST_NOADDR: + rc = ST_IN_TRANSACTION; /* FAKE! No address transaction */ + break; + } + + /* Write data */ + if (rc == ST_IN_TRANSACTION) + switch(len) + { + case 1: + rc = w_trans(mf, &cvalue, sizeof(cvalue)); + break; + case 2: + rc = w_trans(mf, &svalue, sizeof(svalue)); + break; + case 4: + rc = w_trans(mf, &ivalue, sizeof(ivalue)); + break; + default: + errno = EINVAL; + return -1; + } + + /* End transaction (anyway, even it was an error)s */ + if (end_trans(mf) < 0) + return -1; + + /* Now check Gw status and repeat transaction if timeout */ + switch (rc) + { + case ST_IN_TRANSACTION: + repeat = 0; + break; +#ifdef REPEAT_WRITE_IF_NACK + default: + if (++repeat > MAX_REPETITION) + { + errno = EIO; + return -1; + } +#else + case ST_TIMEOUT: + if (++repeat > MAX_REPETITION) + return -1; + /* printf("i2c_master_write_cr: repeat:%d\n", repeat); */ + break; + default: + errno = EIO; + return -1; +#endif + } + } + +#ifdef HIGH_LEVEL_DEBUG + printf(" i2c_master_write_cr: rc=%d\n", len); +#endif + + return len; +} + +int i2c_master_read_cr(mfile *mf, void *value, unsigned int offset, int len) +{ + unsigned int *ivalue = (unsigned int *)value; + unsigned short *svalue = (unsigned short *)value; + unsigned char *cvalue = (unsigned char *)value; + int rc=0, repeat=1; + unsigned short offs = __cpu_to_be16(offset & 0xffff); + unsigned char off1 = offset & 0xff; + +#ifdef HIGH_LEVEL_DEBUG + printf("i2c_master_read_cr i2c:0x%x, offs:0x%x, len:%d\n", + mf->i2c_slave, offset, len); +#endif + + offset = __cpu_to_be32(offset); + + while (repeat) + { + /* Write address (1byte for DIMM, 2bytes for Gamla and 4bytes for Tavor) */ + switch(mf->dtype) + { + case MST_TAVOR: + rc = w_trans(mf, &offset, sizeof(offset)); + break; + case MST_GAMLA: + rc = w_trans(mf, &offs, sizeof(offs)); + break; + case MST_DIMM: + rc = w_trans(mf, &off1, sizeof(off1)); + break; + case MST_NOADDR: + rc = ST_IN_TRANSACTION; /* FAKE! No address transaction */ + break; + } + + /* Read data */ + if (rc == ST_IN_TRANSACTION) + switch(len) + { + case 1: + rc = r_trans(mf, cvalue, 1); + break; + case 2: + rc = r_trans(mf, svalue, 2); + break; + case 4: + rc = r_trans(mf, ivalue, 4); + break; + default: + errno = EINVAL; + return -1; + } + + /* End transaction (anyway, even it was an error)s */ + if (end_trans(mf) < 0) + return -1; + + /* Now check Gw status and repeat transaction if timeout */ + switch (rc) + { + case ST_IN_TRANSACTION: + repeat = 0; + break; + case ST_TIMEOUT: + if (++repeat > MAX_REPETITION) + return -1; + /* printf("i2c_master_read_cr: repeat:%d\n", repeat); */ + break; + default: + errno = EIO; + return -1; + } + } + + /* Convert output value */ + switch(len) + { + case 2: + *svalue = __be16_to_cpu(*svalue); + break; + case 4: + *ivalue = __be32_to_cpu(*ivalue); + break; + } + +#ifdef HIGH_LEVEL_DEBUG + printf(" i2c_master_read_cr: val:0x%x rc=%d\n", *ivalue, len); +#endif + + return len; +} +int i2c_master_read(mfile *mf, void *value, unsigned int offset, int len) +{ + unsigned int *ivalue = (unsigned int *)value; + unsigned short *svalue = (unsigned short *)value; + unsigned char *cvalue = (unsigned char *)value; + int rc=0, repeat=1; + unsigned short offs = __cpu_to_be16(offset & 0xffff); + unsigned char off1 = offset & 0xff; + +#ifdef HIGH_LEVEL_DEBUG + printf("i2c_master_read_cr i2c:0x%x, offs:0x%x, len:%d\n", + mf->i2c_slave, offset, len); +#endif + + offset = __cpu_to_be32(offset); + + while (repeat) + { + /* Write address (1byte for DIMM, 2bytes for Gamla and 4bytes for Tavor) */ + switch(mf->dtype) + { + case MST_TAVOR: + rc = w_trans(mf, &offset, sizeof(offset)); + break; + case MST_GAMLA: + rc = w_trans(mf, &offs, sizeof(offs)); + break; + case MST_DIMM: + rc = w_trans(mf, &off1, sizeof(off1)); + break; + case MST_NOADDR: + rc = ST_IN_TRANSACTION; /* FAKE! No address transaction */ + break; + } + + /* Read data */ + if (rc == ST_IN_TRANSACTION) + switch(len) + { + case 1: + rc = r_trans(mf, cvalue, 1); + break; + case 2: + rc = r_trans(mf, svalue, 2); + break; + case 3: + rc = r_trans(mf, svalue, 3); + break; + case 4: + rc = r_trans(mf, ivalue, 4); + break; + default: + errno = EINVAL; + return -1; + } + + /* End transaction (anyway, even it was an error)s */ + if (end_trans(mf) < 0) + return -1; + + /* Now check Gw status and repeat transaction if timeout */ + switch (rc) + { + case ST_IN_TRANSACTION: + repeat = 0; + break; + case ST_TIMEOUT: + if (++repeat > MAX_REPETITION) + return -1; + /* printf("i2c_master_read_cr: repeat:%d\n", repeat); */ + break; + default: + errno = EIO; + return -1; + } + } + +#ifdef HIGH_LEVEL_DEBUG + printf(" i2c_master_read_cr: val:0x%x rc=%d\n", *ivalue, len); +#endif + + return len; +} + +void i2c_master_set(mfile *mf) +{ + unsigned int val; + int i; + + if (mf->itype == MST_GAMLA) + { + /* Screw up SPM clock. Works w/ Gamla only */ + mread4_(mf, SPM_OFFS + 12, &val); + mf->i2c_RESERVED = val; + val &= 0xffff0000; + val |= 0x100; + mwrite4_(mf, SPM_OFFS + 12, val); + } + + /* Tavor I2C bug workaround */ + if (mf->dtype == MST_TAVOR) + { + for (i=0; i<9; i++) + end_trans(mf); + + i2c_master_read_cr(mf, &val, 0xf0014, 4); + + for (i=0; i<9; i++) + end_trans(mf); + } + else + i2c_master_read_cr(mf, &val, 0x2800, 4); +} + +void i2c_master_restore(mfile *mf) +{ + if (mf->itype == MST_GAMLA) + /* Restore SPM clock. */ + mwrite4_(mf, SPM_OFFS + 12, mf->i2c_RESERVED); +} diff --git a/trunk/tools/mtcr/user/mtcr_i2c.h b/trunk/tools/mtcr/user/mtcr_i2c.h new file mode 100644 index 00000000..8142b54a --- /dev/null +++ b/trunk/tools/mtcr/user/mtcr_i2c.h @@ -0,0 +1,38 @@ +/* - Mellanox Confidential and Proprietary - + * + * Copyright (C) March 2002, Mellanox Technologies Ltd. ALL RIGHTS RESERVED. + * + * Except as specifically permitted herein, no portion of the information, + * including but not limited to object code and source code, may be reproduced, + * modified, distributed, republished or otherwise exploited in any form or by + * any means for any purpose without the prior written permission of Mellanox + * Technologies Ltd. Use of software subject to the terms and conditions + * detailed in the file "LICENSE.txt". + * + * End of legal section ...................................................... + * + * mtcr_i2c.h - Mellanox Software tools (mst) driver: I2C master routines + * + * Version: $Id$ + * + */ + +#ifndef _MTCR_I2C_H +#define _MTCR_I2C_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_TRANS_SIZE 64 + +int i2c_master_write_cr(mfile *mf, unsigned int value, unsigned int offset, int len); +int i2c_master_read_cr(mfile *mf, void *value, unsigned int offset, int len); +void i2c_master_restore(mfile *mf); +void i2c_master_set(mfile *mf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/trunk/tools/mtcr/user/usb.cpp b/trunk/tools/mtcr/user/usb.cpp new file mode 100644 index 00000000..9186dfc5 --- /dev/null +++ b/trunk/tools/mtcr/user/usb.cpp @@ -0,0 +1,510 @@ +/* - Mellanox Confidential and Proprietary - + * + * Copyright (C) December 2001, Mellanox Technologies Ltd. ALL RIGHTS RESERVED. + * + * Except as specifically permitted herein, no portion of the information, + * including but not limited to object code and source code, may be reproduced, + * modified, distributed, republished or otherwise exploited in any form or by + * any means for any purpose without the prior written permission of Mellanox + * Technologies Ltd. Use of software subject to the terms and conditions + * detailed in the file "LICENSE.txt". + * + * End of legal section ...................................................... + * + * eeprom_usb.h - EEPROM access via usb implementation + * + * Version: $Id$ + * + * Author: Alex Rezinsky (alexr@mellanox.co.il) + */ + +#include "com_def.h" +#include "usb.h" + +#ifdef MTCR_USB_SUPPORT +// ------------------------------------------------------------------------------------- +// PREPROCESSOR FLAGS +// ------------------------------------------------------------------------------------- + +// print debug information +//#define DEBUG_PRINT + +// verify read operations +//#define VERIFY_EACH_READ + +// delay between I2C operation */ +//#define SLEEP_AFTER_EACH_USB_IO + +// verify write operations +//#define COMPARE_AFTER_EACH_WRITE + +// ------------------------------------------------------------------------------------- +// LITERALS +// ------------------------------------------------------------------------------------- + #define USB_DEVICE_NAME "UsbI2cIo" + #define USB_WRITE_DELAY_MSEC 16 + #define USB_READ_DELAY_MSEC 16 + +// ------------------------------------------------------------------------------------- +// GLOBALS +// ------------------------------------------------------------------------------------- +I2C_TRANS TransI2C; // parameter structure + + +// ------------------------------------------------------------------------------------- +// DIMAX +// ------------------------------------------------------------------------------------- +static BOOL is_dimax = FALSE; +BOOL usb_is_dimax() { return is_dimax;} + #include "i2cbridge.h" + +// ------------------------------------------------------------------------------------- +// DEBUG PRINT FACILITY +// ------------------------------------------------------------------------------------- + + #ifdef DEBUG_PRINT + +char g_DebugInfo[2048]; +char *g_DebugInfo_p = g_DebugInfo; +int g_DebugInfoCnt = 0; +FILE *fd; +char g_buf[300]; + +void OpenDebugInfo(char * str) +{ + fd = fopen( str, "a" ); +} + +void CloseDebugInfo() +{ + fclose(fd); +} + +void WriteDebugInfo(char * str) +{ + int cnt = strlen(str); + g_DebugInfoCnt++; + if (g_DebugInfo_p + cnt > g_DebugInfo + sizeof(g_DebugInfo) ) + g_DebugInfo_p = g_DebugInfo; + memcpy( g_DebugInfo_p, str, cnt ); + g_DebugInfo_p += cnt; + fputs( str, fd ); +} + +void StoreDebugInfo(HANDLE h) +{ + int cnt; + char lpsDebugInfo[300]; + + cnt = DAPI_ReadDebugBuffer( lpsDebugInfo, h, sizeof(lpsDebugInfo)); + lpsDebugInfo[cnt] = 0; + WriteDebugInfo( lpsDebugInfo ); + cnt = DAPI_ReadDebugBuffer( lpsDebugInfo, h, sizeof(lpsDebugInfo)); + lpsDebugInfo[cnt] = 0; + WriteDebugInfo( lpsDebugInfo ); +} + #endif + + +// ------------------------------------------------------------------------------------- +// USB: LOW-LEVEL ROUTINES +// ------------------------------------------------------------------------------------- + +static call_result_t usb_read_trans( + HANDLE h, + const u_int32_t trans_type, + const u_int8_t slv_addr, + const u_int32_t mem_base, + u_int8_t *data_arr_r, + const u_int32_t data_size) +{ + call_result_t rc; + LONG lReadCnt; + + // debug print +#ifdef DEBUG_PRINT + WriteDebugInfo("\n------ usb_read_trans ------\n"); +#endif + + if (trans_type == I2C_TRANS_NOADR || trans_type == I2C_TRANS_32ADR) { /* work in I2C_TRANS_NOADR mode */ + + // + // write offset + // + + // calculate address size + static int sizes[] = {4,1,2,4,4}; + int mem_base_sz = sizes[trans_type]; + + // prepare parameters + TransI2C.byTransType = I2C_TRANS_NOADR; + TransI2C.wMemoryAddr = 0; + TransI2C.bySlvDevAddr = slv_addr<<1; + TransI2C.wCount = (WORD)mem_base_sz; + memcpy(TransI2C.Data, (char*)&mem_base, mem_base_sz); + + // write the offset + LONG lWriteCnt = DAPI_WriteI2c( h, &TransI2C); + rc = (lWriteCnt == TransI2C.wCount) ? MT_OK : MT_ERROR; + + // debug print +#ifdef DEBUG_PRINT + sprintf( g_buf, "write: type %d, addr 0x%02x, offset 0x%02x, req'd: %d, got: %d)\n", + TransI2C.byTransType, TransI2C.bySlvDevAddr, mem_base, TransI2C.wCount, lWriteCnt); + WriteDebugInfo(g_buf); + StoreDebugInfo( h ); +#endif + + // check the results + if (rc != MT_OK) + return rc; + + // + // read data + // + + // prepare parameters + TransI2C.byTransType = I2C_TRANS_NOADR; + TransI2C.wMemoryAddr = 0; + TransI2C.bySlvDevAddr = slv_addr<<1; + TransI2C.wCount = (WORD)data_size; + + } /* work in I2C_TRANS_NOADR mode */ + else { /* work in I2C_TRANS_xxxADR mode */ + + // prepare parameters + TransI2C.byTransType = (BYTE)trans_type; + TransI2C.wMemoryAddr = (WORD)mem_base; + TransI2C.bySlvDevAddr = slv_addr<<1; + TransI2C.wCount = (WORD)data_size; + + } /* work in I2C_TRANS_xxxADR mode */ + + // read the data + lReadCnt = DAPI_ReadI2c( h, &TransI2C); + rc = (lReadCnt == TransI2C.wCount) ? MT_OK : MT_ERROR; + + // debug print +#ifdef DEBUG_PRINT + sprintf( g_buf, "read: type %d, addr 0x%02x, offset 0x%02x, req'd: %d, got: %d)\n", + TransI2C.byTransType, TransI2C.bySlvDevAddr, TransI2C.wMemoryAddr, TransI2C.wCount, lReadCnt); + WriteDebugInfo(g_buf); + StoreDebugInfo( h ); +#endif + + // check the results + if (rc == MT_OK) + memcpy(data_arr_r, TransI2C.Data, lReadCnt); + + return rc; +} + +// ------------------------------------------------------------------------------------- +// USB: EXPORTED ROUTINES +// ------------------------------------------------------------------------------------- + + +BOOL usb_is_connected() { + // DIMAX + BYTE dev_num; + + dev_num = U2C_GetDeviceCount(); + DPRINT3(("Found %d DIMAX usb devices\n", dev_num)); + if (dev_num) { + return TRUE; + } + + // DEVASYS + dev_num = DAPI_GetDeviceCount(USB_DEVICE_NAME); + DPRINT3(("Found %d DEVASYS (%s) usb devices\n", dev_num, USB_DEVICE_NAME)); + if (dev_num) { + return TRUE; + } + + return FALSE; +} + + +//=============== +//* usb_open +//=============== +HANDLE usb_open() +{ + HANDLE usb; + + // DIMAX + BYTE dev_num = U2C_GetDeviceCount(); + if (!dev_num) { + DPRINT5(("usb_open: no DiMax devices\n" )); + } else { + DPRINT5(("usb_open: found %d DiMax devices\n", dev_num )); + usb = U2C_OpenDevice( 0 ); + if (usb == INVALID_HANDLE_VALUE) { + DPRINT1(("usb_open: U2C_OpenDevice failed\n" )); + } else { + U2C_VERSION_INFO Fw = {0,0}, Dll = {0,0}, Drv = {0,0}; + U2C_GetFirmwareVersion( usb, &Fw ); + Dll = U2C_GetDllVersion(); + U2C_GetDriverVersion( usb, &Drv ); + DPRINT3(("usb_open: DiMax: Dll %d.%d, Drv %d.%d, Fw %d.%d, \n", + Dll.MajorVersion, Dll.MinorVersion, + Drv.MajorVersion, Drv.MinorVersion, + Fw.MajorVersion, Fw.MinorVersion )); + is_dimax = TRUE; + return usb; + } + } + + // debug print +#ifdef DEBUG_PRINT + OpenDebugInfo( "UsbI2cIo.log" ); + WriteDebugInfo("\n------ usb_open ------\n"); +#endif + + // open device + usb = DAPI_OpenDeviceInstance(USB_DEVICE_NAME, 0); + + // debug print +#ifdef DEBUG_PRINT + StoreDebugInfo( usb ); +#endif + + return usb; +} + + +//=============== +//* usb_close +//=============== +call_result_t usb_close(HANDLE h) +{ + call_result_t rc; + + // DIMAX + if (is_dimax) { + rc = ( U2C_CloseDevice(h) == U2C_SUCCESS) ? MT_OK : MT_ERROR; + return rc; + } + + rc = ( DAPI_CloseDeviceInstance(h) ) ? MT_OK : MT_ERROR; + +#ifdef DEBUG_PRINT + WriteDebugInfo("\n------ usb_close ------\n"); + CloseDebugInfo(); +#endif + + return rc; +} + + +//=============== +//* usb_read +//=============== +call_result_t usb_read( + HANDLE h, + const u_int32_t trans_type, + const u_int8_t slv_addr, + const u_int32_t mem_base, + const u_int32_t mem_size, + u_int8_t *data_arr_r, + const u_int32_t data_size) +{ + + // DIMAX + if (is_dimax) { + U2C_TRANSACTION t; + U2C_RESULT u2c_rc; + int i; +#define DIMAX_READ_RETRIES 3 + + // validate parameters + if (data_size > sizeof(t.Buffer)) + return MT_ENORSC; + + // prepare the transaction + t.nSlaveDeviceAddress = (BYTE)slv_addr; + t.nMemoryAddressLength = (BYTE)mem_size; + t.nMemoryAddress = (DWORD)mem_base; + t.nBufferLength = (USHORT)data_size; + DPRINT5(("usb_read: going to read: slv_addr %#x, addr_len %d, mem_base %#x, data_sz %d\n", + (ULONG)t.nSlaveDeviceAddress, + t.nMemoryAddressLength, t.nMemoryAddress, t.nBufferLength )); + + // read + for (i=0; i MAX_I2C_TRANSACTION) + return MT_ENORSC; + +#ifdef VERIFY_EACH_READ + + call_result_t rc; + u_int8_t data1[MAX_I2C_TRANSACTION], data2[MAX_I2C_TRANSACTION]; + if ((rc = usb_read_trans(h, trans_type, slv_addr, mem_base, data1, data_size)) != MT_OK) + return rc; + if ((rc = usb_read_trans(h, trans_type, slv_addr, mem_base, data2, data_size)) != MT_OK) + return rc; + if (memcmp(data1, data2, data_size)) + return MT_ERROR; + memcpy(data_arr_r, data1, data_size); + return MT_OK; + +#else /* VERIFY_EACH_READ */ + + return usb_read_trans(h, trans_type, slv_addr, mem_base, data_arr_r, data_size); + +#endif /* VERIFY_EACH_READ */ + +} + + +//=============== +//* usb_write +//=============== +call_result_t usb_write( + HANDLE h, + const u_int32_t trans_type, + const u_int8_t slv_addr, + const u_int32_t mem_base, + const u_int32_t mem_size, + u_int8_t *data_arr_w, + const u_int32_t data_size) +{ + u_int8_t * data_p = (u_int8_t *)&TransI2C.Data[0]; + + // DIMAX + if (is_dimax) { + U2C_TRANSACTION t; + U2C_RESULT u2c_rc; + + // validate parameters + if (data_size > sizeof(t.Buffer)) + return MT_ENORSC; + + // prepare the transaction + t.nSlaveDeviceAddress = (BYTE)slv_addr; + t.nMemoryAddressLength = (BYTE)mem_size; + t.nMemoryAddress = (DWORD)mem_base; + t.nBufferLength = (USHORT)data_size; + memcpy(t.Buffer, data_arr_w, data_size); + + // read + u2c_rc = U2C_Write( h, &t ); + if (u2c_rc != U2C_SUCCESS) { + DPRINT1(("usb_write: U2C_Write failed (%d), slv_addr %#x, mem_base %#x, data_sz %d\n", + u2c_rc, (ULONG)slv_addr, mem_base, data_size )); + return MT_ERROR; + } + + return MT_OK; + } + + + // validate parameters + if (data_size > MAX_I2C_TRANSACTION) + return MT_ENORSC; + + // debug print +#ifdef DEBUG_PRINT + WriteDebugInfo("\n------ usb_write ------\n"); +#endif + + if (trans_type == I2C_TRANS_NOADR || trans_type == I2C_TRANS_32ADR) { /* work in I2C_TRANS_NOADR mode */ + + // calculate address size + static int sizes[] = {4,1,2,4,4}; + int mem_base_sz = sizes[trans_type]; + + // validate parameters + if (mem_base_sz + data_size > MAX_I2C_TRANSACTION) + return MT_ENORSC; + + // prepare parameters + TransI2C.byTransType = I2C_TRANS_NOADR; + TransI2C.wMemoryAddr = 0; + TransI2C.bySlvDevAddr = slv_addr<<1; + TransI2C.wCount = mem_base_sz + data_size; + memcpy(TransI2C.Data, (char*)&mem_base, mem_base_sz); + data_p += mem_base_sz; + + } /* work in I2C_TRANS_NOADR mode */ + else { /* work in I2C_TRANS_xxxADR mode */ + + // prepare parameters + TransI2C.byTransType = (BYTE)trans_type; + TransI2C.wMemoryAddr = (WORD)mem_base; + TransI2C.bySlvDevAddr = slv_addr<<1; + TransI2C.wCount = (WORD)data_size; + + } /* work in I2C_TRANS_xxxADR mode */ + + // fill data + memcpy(data_p, data_arr_w, data_size); + + // write data + LONG lWriteCnt = DAPI_WriteI2c(h, &TransI2C); + + // debug print +#ifdef DEBUG_PRINT + sprintf( g_buf, "write: type %d, addr 0x%02x, offset 0x%02x, req'd: %d, got: %d)\n", + TransI2C.byTransType, TransI2C.bySlvDevAddr, TransI2C.wMemoryAddr, TransI2C.wCount, lWriteCnt); + WriteDebugInfo(g_buf); + StoreDebugInfo( h ); +#endif + + // check the results + if (lWriteCnt != TransI2C.wCount) + return MT_ERROR; + + // delay on need +#ifdef SLEEP_AFTER_EACH_USB_IO + Sleep(USB_WRITE_DELAY_MSEC); +#endif + + // verify on need +#ifdef COMPARE_AFTER_EACH_WRITE + + u_int8_t data[MAX_I2C_TRANSACTION]; + call_result_t rc; + + // read the written data + if ((rc = usb_read_trans(h, trans_type, slv_addr, mem_base, data, lWriteCnt)) != MT_OK) + return rc; + + // delay on need +#ifdef SLEEP_AFTER_EACH_USB_IO + Sleep(USB_READ_DELAY_MSEC); +#endif + + // compare the read with the written data + if (memcmp(data, data_arr_w, lWriteCnt)) + return MT_ERROR; + return MT_OK; + +#else /* COMPARE_AFTER_EACH_WRITE */ + + return MT_OK; + +#endif /* COMPARE_AFTER_EACH_WRITE */ + +} +#endif diff --git a/trunk/tools/mtcr/user/usb.h b/trunk/tools/mtcr/user/usb.h new file mode 100644 index 00000000..347fa9c5 --- /dev/null +++ b/trunk/tools/mtcr/user/usb.h @@ -0,0 +1,172 @@ +/* - Mellanox Confidential and Proprietary - + * + * Copyright (C) December 2001, Mellanox Technologies Ltd. ALL RIGHTS RESERVED. + * + * Except as specifically permitted herein, no portion of the information, + * including but not limited to object code and source code, may be reproduced, + * modified, distributed, republished or otherwise exploited in any form or by + * any means for any purpose without the prior written permission of Mellanox + * Technologies Ltd. Use of software subject to the terms and conditions + * detailed in the file "LICENSE.txt". + * + * End of legal section ...................................................... + * + * eeprom_usb.h - EEPROM access via usb definitions + * + * Version: $Id$ + * + * Author: Alex Rezinsky (alexr@mellanox.co.il) + */ + +#ifndef __USB_H +#define __USB_H + +#include "com_def.h" +#include "mtcr.h" + +// I2C transaction type +#define I2C_TRANS_32ADR 4 + +// limitation constant +#define MAX_I2C_TRANSACTION 64 + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef MTCR_USB_SUPPORT + +#define USB2I2C + +#include + +/****************************************************************************** + * Function: usb_open + * + * Description: + * Open usb device + * + * Parameters: + * + * Returns: HANDLE - USB device handler or + * INVALID_HANDLE_VALUE - Fail to open + * + *******************************************************************************/ +HANDLE usb_open(); + +/******************************************************************************* + * Function: usb_close + * + * Description: + * Close usb device + * + * Parameters: + * h(IN): HANDLE + * Device handler to close + * + * Returns: MT_OK success + * MT_ERROR + * + ******************************************************************************/ +call_result_t usb_close(HANDLE h); + + +/****************************************************************************** + * Function: usb_read + * + * Description: + * reads the data from the given device on I2C bus + * starting from the given address in the device. + * + * Parameters: + * trans_type(IN): I2C transaction type + * data_arr_r(OUT): array of data + * data_size(IN): the size of the array. + * slv_addr(IN): I2C address of target device. + * mem_base(IN): the address in the memory space of the device + * from which we should start reading the data. + * Returns: MT_OK success + * MT_ERROR + * + * Notes: + * + ******************************************************************************/ +call_result_t usb_read( + HANDLE h, + const u_int32_t trans_type, + const u_int8_t slv_addr, + const u_int32_t mem_base, + const u_int32_t mem_size, + u_int8_t *data_arr_r, + const u_int32_t data_size); + + +/****************************************************************************** + * Function: usb_write + * + * Description: + * writes the data to the given device on I2C bus + * starting from the given address in the device. + * + * Parameters: + * trans_type(IN): I2C transaction type + * data_arr_w(IN ): array of data + * data_size(IN): the size of the array. + * slv_addr(IN): I2C address of target device. + * mem_base(IN): the address in the memory space of the device + * from which we should start writing the data. + * Returns: MT_OK success + * MT_ERROR + * + * Notes: + * + ******************************************************************************/ +call_result_t usb_write( + HANDLE h, + const u_int32_t trans_type, + const u_int8_t slv_addr, + const u_int32_t mem_base, + const u_int32_t mem_size, + u_int8_t *data_arr_r, + const u_int32_t data_size); + +BOOL usb_is_dimax(); + +BOOL usb_is_connected(); + +#else + +static inline BOOL usb_is_dimax() { return FALSE; } +static inline BOOL usb_is_connected() { return FALSE; } +static inline HANDLE usb_open() { return INVALID_HANDLE_VALUE; } +static inline call_result_t usb_close(HANDLE h) { return MT_ERROR; } + +static inline call_result_t usb_read( + HANDLE h, + const u_int32_t trans_type, + const u_int8_t slv_addr, + const u_int32_t mem_base, + const u_int32_t mem_size, + u_int8_t *data_arr_r, + const u_int32_t data_size) { return MT_ERROR; } + +static inline call_result_t usb_write( + HANDLE h, + const u_int32_t trans_type, + const u_int8_t slv_addr, + const u_int32_t mem_base, + const u_int32_t mem_size, + u_int8_t *data_arr_r, + const u_int32_t data_size) { return MT_ERROR; } + +#define I2C_TRANS_16ADR 0 /*dummy */ + +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/trunk/tools/mwrite/user/SOURCES b/trunk/tools/mwrite/user/SOURCES new file mode 100644 index 00000000..d39cbc74 --- /dev/null +++ b/trunk/tools/mwrite/user/SOURCES @@ -0,0 +1,40 @@ +TARGETNAME=mwrite +TARGETTYPE=PROGRAM +UMTYPE=console +USE_CRTDLL=1 + + +!if !defined(WINIBHOME) +WINIBHOME=..\..\.. +!endif + +TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + + + +SOURCES=mwrite.c \ + mwrite.rc + +INCLUDES= $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; \ + $(WINIBHOME)\inc\iba; \ + $(WINIBHOME)\tools\mtcr\user; + +TARGETLIBS= \ +!if $(FREEBUILD) + $(TARGETPATH)\*\mtcr.lib +!else + $(TARGETPATH)\*\mtcr.lib +!endif + +!if $(FREEBUILD) + +!else +C_DEFINES=$(C_DEFINES) -DDEBUG +!endif + +C_DEFINES=$(C_DEFINES) -D__WIN__ + +386_STDCALL=0 + + diff --git a/trunk/tools/mwrite/user/makefile b/trunk/tools/mwrite/user/makefile new file mode 100644 index 00000000..80d407b3 --- /dev/null +++ b/trunk/tools/mwrite/user/makefile @@ -0,0 +1,8 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def + diff --git a/trunk/tools/mwrite/user/mwrite.c b/trunk/tools/mwrite/user/mwrite.c new file mode 100644 index 00000000..4d982f6c --- /dev/null +++ b/trunk/tools/mwrite/user/mwrite.c @@ -0,0 +1,62 @@ +/* + * + * mwrite.c - CR Space write access + * + */ + +#include +#include +#include + +#include "mtcr.h" + +void usage(const char *n) +{ + printf("%s []\n", n); + exit(1); +} + +int main(int ac, char *av[]) +{ + char *endp; + int rc=0; + unsigned int addr, val; + mfile *mf; + DType dtype = MST_TAVOR; + + if (ac < 4) + usage(av[0]); + addr = strtoul(av[2], &endp, 0); + if (*endp) + usage(av[0]); + val = strtoul(av[3], &endp, 0); + if (*endp) + usage(av[0]); + + if (strstr(av[1], "mt21108_pci") && !strstr(av[1], "i2cm")) + dtype = MST_GAMLA; + mf = mopend(av[1], dtype); + if ( !mf ) + { + perror("mopen"); + return 1; + } + + if (ac >= 5) + mset_i2c_slave(mf, (unsigned char)strtoul(av[4],0,0)); + + if ((rc = mwrite4(mf, addr, val)) < 0) + { + mclose(mf); + perror("mwrite"); + return 1; + } + if (rc < 4) + { + mclose(mf); + printf("Write only %d bytes\n", rc); + return 1; + } + mclose(mf); + return 0; +} diff --git a/trunk/tools/spark/dirs b/trunk/tools/spark/dirs new file mode 100644 index 00000000..5a7e8b31 --- /dev/null +++ b/trunk/tools/spark/dirs @@ -0,0 +1,2 @@ +DIRS=\ + user diff --git a/trunk/tools/spark/user/SOURCES b/trunk/tools/spark/user/SOURCES new file mode 100644 index 00000000..06c29496 --- /dev/null +++ b/trunk/tools/spark/user/SOURCES @@ -0,0 +1,57 @@ +TARGETNAME=spark +TARGETTYPE=PROGRAM +UMTYPE=console +USE_CRTDLL=1 +USE_NTDLL=1 + + +!if !defined(WINIBHOME) +WINIBHOME=..\..\.. +!endif + +TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR) + + +SOURCES=spark.rc \ + spark.cpp + + +INCLUDES= $(WINIBHOME)\inc; \ + $(WINIBHOME)\inc\user; \ + $(WINIBHOME)\inc\iba; \ + $(WINIBHOME)\tools\mtcr\user; \ + $(ZLIB)\include; + +TARGETLIBS= \ +!if $(FREEBUILD) + $(CRT_LIB_PATH)\msvcprt.lib \ + $(SDK_LIB_PATH)\Ws2_32.lib\ + $(TARGETPATH)\*\mtcr.lib +!else + $(CRT_LIB_PATH)\msvcprt.lib\ + $(SDK_LIB_PATH)\Ws2_32.lib\ + $(TARGETPATH)\*\mtcr.lib +!endif + +USER_C_FLAGS=$(USER_C_FLAGS) /Ze /EHsc + +# TODO:Should I define the __WIN__ manually +C_DEFINES=$(C_DEFINES) -D__WIN__ + + +!if $(FREEBUILD) + +!else +C_DEFINES=$(C_DEFINES) -DDEBUG +!endif + +# Version: +!if !defined(MFT_BLD_VER) +MFT_BLD_VER=Devel +!endif +C_DEFINES=$(C_DEFINES) "-DVERSION_ID=$(MFT_BLD_VER)" + +386_STDCALL=0 + +MSC_WARNING_LEVEL= /W3 + diff --git a/trunk/tools/spark/user/makefile b/trunk/tools/spark/user/makefile new file mode 100644 index 00000000..128ed372 --- /dev/null +++ b/trunk/tools/spark/user/makefile @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE ..\..\..\inc\openib.def diff --git a/trunk/tools/spark/user/spark.cpp b/trunk/tools/spark/user/spark.cpp new file mode 100644 index 00000000..78c69a1d --- /dev/null +++ b/trunk/tools/spark/user/spark.cpp @@ -0,0 +1,3498 @@ +/* - Mellanox Confidential and Proprietary - + * + * Copyright (C) May 2003, Mellanox Technologies Ltd. ALL RIGHTS RESERVED. + * + * Except as specifically permitted herein, no portion of the information, + * including but not limited to object code and source code, may be reproduced, + * modified, distributed, republished or otherwise exploited in any form or by + * any means for any purpose without the prior written permission of Mellanox + * Technologies Ltd. Use of software subject to the terms and conditions + * detailed in the file "LICENSE.txt". + * + * End of legal section ...................................................... + * + * eburn.cpp - Command line EEPROM burning tool (Gamla/Anafa) + * + * Version: $Id: spark.cpp 2733 2006-01-15 16:12:53Z orenk $ + * + * Standalone compiling: + * g++ -g -Wall -I/usr/mst/include -L/usr/mst/lib -o spark spark.cpp -lmtcr + * + * Author: Oren Kladnitsky orenk@mellanox.co.il + */ + + +#include +#include +#include +#include +#include +#include +#include + + + + +#ifndef __WIN__ + +// +// Linux +// + +#include +#include +#include +#include + +#else // __WIN__ + +// +// Windows (Under DDK) +// + +#include +#include + +// Sleep adaptor +#define usleep(x) Sleep((x)/1000) +#define sleep(x) Sleep((x)*1000) + +#define vsnprintf _vsnprintf +#define strtoull _strtoui64 +#define isatty _isatty + +#define COMP_CDECL __cdecl + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __BYTE_ORDER __LITTLE_ENDIAN + + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define bswap_32(x) ntohl(x) +#define bswap_16(x) ntohs(x) +#else +#error windows is assumed to run a on little endian architecture +#endif + + +// DEBUG : Internal imp of strtoull for win2k msvcrt does not have _strtoui64 + + +#endif // __WIN__ + + + + +#include +#include +#include +#include +#include +#include + + +#include "mtcr.h" + +// +// endianess issues: +// + +#ifndef __be32_to_cpu + #define __be32_to_cpu(x) ntohl(x) +#endif +#ifndef __cpu_to_be32 + #define __cpu_to_be32(x) htonl(x) +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN + #ifndef __cpu_to_le32 + #define __cpu_to_le32(x) (x) + #endif + #ifndef __le32_to_cpu + #define __le32_to_cpu(x) (x) + #endif +#elif __BYTE_ORDER == __BIG_ENDIAN + #ifndef __cpu_to_le32 + #define __cpu_to_le32(x) bswap_32(x) + #endif + #ifndef __le32_to_cpu + #define __le32_to_cpu(x) bswap_32(x) + #endif +#else + #ifndef __cpu_to_le32 + #define __cpu_to_le32(x) bswap_32(__cpu_to_be32(x)) + #endif + #ifndef __le32_to_cpu + #define __le32_to_cpu(x) __be32_to_cpu(bswap_32(x)) + #endif +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN + #ifndef __cpu_to_le16 + #define __cpu_to_le16(x) (x) + #endif + #ifndef __le16_to_cpu + #define __le16_to_cpu(x) (x) + #endif + #ifndef __cpu_to_be16 + #define __cpu_to_be16(x) bswap_16(x) + #endif + #ifndef __be16_to_cpu + #define __be16_to_cpu(x) bswap_16(x) + #endif +#elif __BYTE_ORDER == __BIG_ENDIAN + #ifndef __cpu_to_le16 + #define __cpu_to_le16(x) bswap_16(x) + #endif + #ifndef __le16_to_cpu + #define __le16_to_cpu(x) bswap_16(x) + #endif + #ifndef __cpu_to_be16 + #define __cpu_to_be16(x) (x) + #endif + #ifndef __be16_to_cpu + #define __be16_to_cpu(x) (x) + #endif +#else + #ifndef __cpu_to_le16 + #define __cpu_to_le16(x) bswap_16(__cpu_to_be16(x)) + #endif + #ifndef __le16_to_cpu + #define __le16_to_cpu(x) __be16_to_cpu(bswap_16(x)) + #endif + #ifndef __cpu_to_be16 + #define __cpu_to_be16(x) (x) + #endif + #ifndef __be16_to_cpu + #define __be16_to_cpu(x) (x) + #endif +#endif + +// Version globals +#ifdef VERSION_ID +#define __VFSTR(x) #x +#define _VFSTR(x) __VFSTR(x) +char* _versionID = _VFSTR( VERSION_ID ) ; +#else +char* _versionID = "VERSION_ID_HERE"; +#endif + +char* _cvsID = "$Revision: 2676 $"; + +using namespace std; + +typedef std::vector DataVec; + +struct EeLoc { + EeLoc(u_int32_t o = 0, u_int8_t d = 0) : offset(o) , dev(d) {} + u_int32_t offset; + u_int8_t dev; +}; + + +class ErrMsg +{ +public: + ErrMsg() : _err(0) { } + ~ErrMsg() { err_clear(); } + const char *err() const { return _err; } + void err_clear() { delete [] _err; _err = 0; } + +protected: + + char *vprint(const char *format, va_list args) + { + const int INIT_VAL = 1024; + int max_str, max_buf = INIT_VAL; + char *out_buf; + + while (1) + { + out_buf = new char[max_buf]; + max_str = max_buf - 1; + + if (vsnprintf(out_buf, max_str, format, args) < max_str) + return out_buf; + delete [] out_buf; + max_buf *= 2; + } + } + + + bool errmsg(const char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format (printf, 2, 3))) +#endif + ; + +private: + + char *_err; +}; + + +bool ErrMsg::errmsg(const char *format, ...) { + va_list args; + + char* prev_err = _err; + + va_start(args, format); + _err = vprint(format, args); + va_end(args); + + delete[] prev_err; + + return false; +} + +typedef pair EeRange; + +// +// Endianness handler: +// +inline +u_int32_t ImgBytes2Dw(const u_int8_t* p) { + return __be32_to_cpu(*(u_int32_t*)p); +} + +inline +void PatchImgBytes(u_int8_t* p, u_int32_t val) { + u_int32_t correct_endianess_val = __cpu_to_be32(val); + memcpy(p , &correct_endianess_val, 4); +} + + + +//////////////////////////////////////////////////////////////////////// +// // +// ****************************************************************** // +// CRC16 CALCULATION // +// ****************************************************************** // +// // +//////////////////////////////////////////////////////////////////////// +class Crc16 { +public: + Crc16(bool d = false) : _debug(d) { clear();} + u_int16_t get() { return _crc;} + void clear() { _crc = 0xffff;} + void operator<<(u_int32_t val) { add(val);} + void add(u_int32_t val); + void finish(); +private: + u_int16_t _crc; + bool _debug; +}; + +//////////////////////////////////////////////////////////////////////// +void Crc16::add(u_int32_t o) +{ + if (_debug) + printf("Crc16::add(%08x)\n", o); + for (int i=0; i<32; i++) { + if (_crc & 0x8000) + _crc = (u_int16_t) ((((_crc<<1) | (o>>31)) ^ 0x100b) & 0xffff); + else + _crc= (u_int16_t) (((_crc<<1) | (o>>31)) & 0xffff); + o = (o<<1) & 0xffffffff; + } +} // Crc16::add + + +//////////////////////////////////////////////////////////////////////// +void Crc16::finish() +{ + for (int i=0; i<16; i++) { + if (_crc & 0x8000) + _crc=((_crc<<1) ^ 0x100b) & 0xffff; + else + _crc=(_crc<<1) & 0xffff; + } + + // Revert 16 low bits + _crc = _crc ^ 0xffff; + +} // Crc16::finish + + +// +// Interface class for translations between addr/dev and contiguous address space. +// +class EeAddressConvertor { +public: + enum { + EEPROMS = 8 + }; + + virtual bool Init (const u_int32_t eepromData[EEPROMS]); + virtual bool Init (const u_int8_t* eepromDataBytes); + + virtual u_int32_t Convert (const EeLoc& ee_loc) const; + virtual EeLoc Convert (u_int32_t addr ) const; + + virtual std::vector + ConvertRange (u_int32_t addr, + u_int32_t len) const; + + virtual u_int32_t GetTotalSize () const; + + virtual void Clear() {_devmap.clear();} + + virtual ~EeAddressConvertor () {} + +protected: + + // In this vector the offset of the EeLoc represents size of Eeprom + std::vector _devmap; + +}; + +// +// FW Data Section +// +struct Section { + Section(u_int8_t s, u_int32_t o) : + location(o, s) , + addr(0) {} + + Section(const char *n, u_int8_t s, u_int32_t o) : + name(n), + location(o, s), + addr(0) {} + + std::string name; + EeLoc location; + u_int32_t addr; + u_int8_t type; + + DataVec data; +}; + +typedef std::vector SectionVec; + + +// IoBase +class IoBase : public ErrMsg { +public: + IoBase() : + _conv(NULL), + _primaryEeprom(0), + _secondaryEeprom(0) {} + + virtual ~IoBase() {} + + virtual bool open (const char *) {return false;} + + virtual bool close () = 0; + + virtual bool read (u_int32_t addr, + u_int32_t len, + DataVec& data); + + virtual bool read (u_int8_t i2c_slave, + u_int32_t offset, + u_int32_t len, + DataVec& data) = 0; + + virtual bool SetAddressConvertor(EeAddressConvertor* conv) {_conv = conv; return true;} + + virtual const EeAddressConvertor* + GetAddressConvertor() {return _conv;} + + virtual u_int8_t GetPrimaryEeprom() {return _primaryEeprom;} + virtual u_int8_t GetSecondaryEeprom() {return _secondaryEeprom;} + + virtual void SetPrimaryEeprom(u_int8_t eeprom) {_primaryEeprom = eeprom;} + virtual void SetSecondaryEeprom(u_int8_t eeprom) {_secondaryEeprom = eeprom;} + +protected: + EeAddressConvertor* _conv; + + u_int8_t _primaryEeprom; + u_int8_t _secondaryEeprom; +}; + +class ImageFile : public IoBase { +public: + + virtual bool open (const char* imageFile); + virtual bool close () {return true;} + + virtual bool read (u_int8_t i2c_slave, + u_int32_t offset, + u_int32_t len, + DataVec& data); + + + virtual const SectionVec& + GetSections() {return _sections;} + + + virtual const string& + FileName() {return _fileName;} + + +private: + + typedef std::map DeviceDataMap; + + bool LoadBin (const char* imageFile) {imageFile = NULL; return false;} + bool LoadImg (const char* imageFile); + + DeviceDataMap _deviceData; + std::string _fileName; + + SectionVec _sections; + +}; + + + +// ProgressMeter (Base). + +class ProgressMeter { +public: + virtual bool Add (u_int32_t amount) = 0; + virtual bool Reset (u_int32_t max = 0) = 0; + virtual ~ProgressMeter () {} +}; + +class PercentProgressMeter : public ProgressMeter { +public: + PercentProgressMeter (const std::string& msg = "" , u_int32_t max = 0) : + _add_count(0), + _current_progress(0), + _progress_max (max), + _done (false), + _status("OK"), + _msg (msg) {} + + virtual bool Add (u_int32_t amount); + virtual bool Reset (u_int32_t max) {_add_count = 0; + _current_progress = 0; + _done = false; + if (max) _progress_max = max ; + return Add(0);} + + void SetMsg(const std::string& msg) {_msg = msg;} + void Done(const char* status = NULL) {if (status) _status = status; _current_progress = _progress_max; Add(0);} + +private: + u_int32_t _add_count; + u_int32_t _current_progress; + u_int32_t _progress_max; + bool _done; + const char* _status; + + std::string _msg; + + static const char _spinner[8]; +}; + + +class Eeprom : public IoBase { +public: + Eeprom() : + _prog (NULL) {} + + virtual bool open (const char* dev); + virtual bool close (); + + virtual bool write (u_int32_t addr, + DataVec& data); + + virtual bool write (u_int8_t i2c_slave, + u_int32_t offset, + DataVec& data); + + + virtual bool read (u_int8_t i2c_slave, + u_int32_t offset, + u_int32_t len, + DataVec& data); + + virtual void SetProgressMeter(ProgressMeter* prog) {_prog = prog;} + + + bool InitImageAddressesFromUser (u_int8_t primarySlaveAddr, + u_int8_t secondarySlaveAddr); + + bool InitImageAddressesFromIs3 (u_int8_t is3SlaveAddr); + + +private: + + ProgressMeter* _prog; + + enum EPROM_CMD { + EPROM_WRITE, EPROM_READ, EPROM_END // EEPROM commands + }; + enum CONSTANTS { + MAX_ERROR_LEN = 512, // Maximal length of error string + EPROM_UNIT = 4, // EEPROM unit length + EPROM_PRIMARY_COUNT = 5000, // Amount of "fast" check + EPROM_SECONDARY_COUNT = 100, // Amount of "slow" check + EPROM_REQUEST_PAUSE = 100, // Microseconds for pause + EPROM_ALIGN_W = 32, // Write accesses can't cross this boundary + EPROM_BURST_W = 32, // Maximal data burst on I2C bus on write + EPROM_BURST_R = 64, // Maximal data burst on I2C bus on read + MAX_REPETITION = 100, // Maximal number of transaction repet. + MAX_I2C_WR_RETRY = 256, // Maximal number of writing attempts + MAX_I2C_RD_RETRY = 16 // Maximal number of reading attempts + }; + + bool read_field (u_int32_t addr, u_int8_t offs, u_int8_t len, u_int32_t* v); + bool write_field(u_int32_t addr, u_int8_t offs, u_int8_t len, u_int32_t v); + bool eprom_wait(u_int32_t exp); + bool eprom_cmd(EPROM_CMD cmd); + bool eprom_check(); + + void micro_sleep(const int n); + + // + // PCI access functions (MT43132 only) + // + bool eprom_w_trans(int len, u_int8_t *data); + bool eprom_r_trans(int len, u_int8_t *data); + bool pci_read(u_int32_t addr, u_int8_t *data, u_int32_t length); + bool pci_write(u_int32_t addr, u_int8_t *data, u_int32_t length); + + void eprom_wdelay(int data_size) { micro_sleep((4700 + data_size*10250 + 4700) / 1000 + 1); }; + + mfile *_mf; + bool _was_tmo; + bool _verbose; + + const char* _dev; + + bool _dbg_high; + bool _dbg_low; + bool _internal_read; + +public: + void wdelay() { eprom_wdelay(EPROM_BURST_W); } + +}; + + + +#define MISCC_SPM_ADR7 0x3180, 0, 7 +#define MISCC_SPM_STS 0x3180, 16, 3 +#define MISCC_SPM_VBT 0x3180, 22, 2 +#define MISCC_SPM_CMD 0x3180, 29, 3 +#define MISCC_SPM_DAT_3 0x3184, 0, 32 + +#define MASK32(S) ( ((u_int32_t) ~0L) >> (32-(S)) ) +#define BITS32(O,S) ( MASK32(S) << (O) ) +#define EXTRACT32(W,O,S) ( ((W)>>(O)) & MASK32(S) ) +#define INSERT32(W,F,O,S) ((W)= ( ( (W) & (~BITS32(O,S)) ) | (((F) & MASK32(S))<<(O)) )) + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +bool Eeprom::InitImageAddressesFromIs3(u_int8_t is3SlaveAddr) { + + // The Primary and Secondary I2c slave addresses of the eeproms are taken from + // strapping options and accessible from cr-space. + // Primary eeprom - Cr Address 0x60010 bits 14:8 + // Seconary eeprom - Hard wires 4'b1010 concatenated to Cr Address 0x60010 bits {17,16,26} + + // Need to open another interface because address width for is3 access is 32 bits, + // and for eeproms it's 16 bits. + mfile* mf; + u_int32_t initData; + int ret; + + if (!_mf) + return errmsg("Internal error: InitImageAddressesFromIs3 before open()"); + + if (!(mf = mopend(_dev , MST_TAVOR))) + return errmsg("Failed to open device %s for IS3 access", _dev); + + mset_i2c_slave(mf, is3SlaveAddr); + ret = mread4(mf, 0x60010, &initData); + mclose(mf); + + if (ret != 4) { + return errmsg("IS3 device access failed" ); + } + + _primaryEeprom = EXTRACT32(initData, 8, 7); + _secondaryEeprom = 0x50 | (EXTRACT32(initData, 16, 2) << 1) | EXTRACT32(initData, 26, 1); + + //printf("-D- InitData:%08x Eeprom addresses: P: %02x S: %02x\n", initData, _primaryEeprom, _secondaryEeprom); + return true; +} + +bool Eeprom::InitImageAddressesFromUser(u_int8_t primarySlaveAddr, u_int8_t secondarySlaveAddr) { + _primaryEeprom = primarySlaveAddr; + _secondaryEeprom = secondarySlaveAddr; + return true; +} + +bool Eeprom::open (const char* dev) { + // Open MTCR device + if ( !(_mf = mopend(dev, MST_GAMLA)) ) + { + return errmsg(strerror(errno)); + } + if (_mf->sock != -1) + { + return errmsg("Remote operation not supporeted."); + } + + _dev = dev; + return true; +} + +bool Eeprom::close () { + mclose (_mf); + _mf = NULL; + + return true; +} + + +bool Eeprom::read_field(u_int32_t addr, u_int8_t offs, u_int8_t len, u_int32_t* v) +{ + + if (mread4(_mf, addr, v) != 4) + return errmsg("CR read failed: %s", strerror(errno)); + *v = __le32_to_cpu(*v); + *v = EXTRACT32(*v, offs, len); + + if (_dbg_low) + printf("%sEeprom::read_field(0x%x, %d, %d) -> 0x%x\n", + _internal_read ? " " : "", addr, offs, len, *v); + return true; +} // Eeprom::read_field + +//////////////////////////////////////////////////////////////////////// +bool Eeprom::write_field(u_int32_t addr, u_int8_t offs, u_int8_t len, u_int32_t val) +{ + _internal_read = true; + u_int32_t v; + if (!read_field(addr, 0, 32, &v)) return false; + _internal_read = false; + + INSERT32(v, val, offs, len); + v = __cpu_to_le32(v); + if (_dbg_low) + printf("Eeprom::write_field(0x%x, %d, %d, 0x%x) /0x%x/\n", + addr, offs, len, val, v); + + if (mwrite4(_mf, (unsigned int)addr, (unsigned int)v) != 4) + return errmsg("Eeprom write field failed: %s", strerror(errno)); + + return true; +} // Eeprom::write_field + +//////////////////////////////////////////////////////////////////////// +bool Eeprom::eprom_wait(u_int32_t exp) +{ + u_int32_t f; + u_int32_t cnt = 0; + + while(1) { + if (!read_field(MISCC_SPM_CMD, &f )) return false; + if (f == 0) + break; + if (cnt > EPROM_PRIMARY_COUNT) + micro_sleep(EPROM_REQUEST_PAUSE); + if (cnt > EPROM_PRIMARY_COUNT+EPROM_SECONDARY_COUNT) + { + _was_tmo = true; + return errmsg("EPROM command timeout (command is 0x%x instead of 0)", f); + } + cnt++; + } + + if (!read_field(MISCC_SPM_STS, &f )) return false; + if (f != exp) + { + return errmsg("EPROM invalid status (status is 0x%x instead of 0x%x)", f , exp); + } + + return true; +} // Eeprom::eprom_wait + +//////////////////////////////////////////////////////////////////////// +bool Eeprom::eprom_cmd(EPROM_CMD cmd) +{ + int exp=0; + + switch (cmd) + { + case EPROM_READ: + if (!write_field(MISCC_SPM_CMD, 1)) return false; + exp = 7; + break; + case EPROM_WRITE: + if (!write_field(MISCC_SPM_CMD, 2)) return false; + exp = 7; + break; + case EPROM_END: + if (!write_field(MISCC_SPM_CMD, 3)) return false; + exp = 0; + break; + } + if (!eprom_wait(exp)) return false; + + return true; +} // Eeprom::eprom_cmd + +//////////////////////////////////////////////////////////////////////// +bool Eeprom::eprom_check(void) +{ + u_int32_t f; + + if (!read_field(MISCC_SPM_STS, &f)) return false; + if (f != 0) { + if (!eprom_cmd(EPROM_END)) return false; + } + + return true; +} // Eeprom::eprom_check + +//////////////////////////////////////////////////////////////////////// +bool Eeprom::eprom_w_trans(int len, u_int8_t *data) +{ + int vbt=-1; // Initialized w/ invalid value + u_int32_t val = 0; + + switch (len) + { + case 1: + vbt = 0; + val = (*data << 24) & 0xff000000; + break; + case 2: + vbt = 1; + val = ((*data << 24) & 0xff000000) | ((data[1] << 16) & 0xff0000); + break; + case 3: + vbt = 2; + val = ((*data << 24) & 0xff000000) | ((data[1] << 16) & 0xff0000) | + ((data[2] << 8) & 0xff00); + break; + case 4: + vbt = 3; + val = ((*data << 24) & 0xff000000) | ((data[1] << 16) & 0xff0000) | + ((data[2] << 8) & 0xff00) | (data[3] & 0xff); + break; + default: + return errmsg("Invalid EEPROM unit length: %d", len); + } + if (_dbg_high) + printf("eprom_w_trans; len:%d val:%08x\n", len, val); + + if (!write_field(MISCC_SPM_VBT, vbt)) return false; + if (!write_field(MISCC_SPM_DAT_3, val)) return false; + if (!eprom_cmd(EPROM_WRITE)) return false; + + return true; +} // Eeprom::eprom_w_trans + +//////////////////////////////////////////////////////////////////////// +bool Eeprom::eprom_r_trans(int len, u_int8_t *data) +{ + int vbt=-1; // Initialized w/ invalid value + u_int32_t val = 0; + + switch (len) + { + case 1: + vbt = 0; + break; + case 2: + vbt = 1; + break; + case 3: + vbt = 2; + break; + case 4: + vbt = 3; + break; + default: + return errmsg("Invalid EEPROM unit length: %d", len); + } + + if (!write_field(MISCC_SPM_VBT, vbt)) return false; + if (!eprom_cmd(EPROM_READ)) return false; + if (!read_field(MISCC_SPM_DAT_3, &val)) return false; + + switch (len) + { + case 1: + *data = (val >> 24) & 0xff; + break; + case 2: + *data++ = (val >> 24) & 0xff; + *data = (val >> 16) & 0xff; + break; + case 3: + *data++ = (val >> 24) & 0xff; + *data++ = (val >> 16) & 0xff; + *data = (val >> 8) & 0xff; + break; + case 4: + *data++ = (val >> 24) & 0xff; + *data++ = (val >> 16) & 0xff; + *data++ = (val >> 8) & 0xff; + *data = val & 0xff; + break; + default: + return errmsg("Invalid EEPROM unit length: %d", len); + } + if (_dbg_high) + printf("eprom_r_trans; len:%d %08x\n", len, val); + + return true; +} + +//////////////////////////////////////////////////////////////////////// +bool Eeprom::pci_read(u_int32_t addr, u_int8_t *data, u_int32_t length) +{ + u_int16_t addr16 = (u_int16_t) (addr & 0xffff); + int orig_len = length, repeat=1; + u_int8_t *orig_data = data; + + _was_tmo = false; + while (repeat) + { + + addr16 = __cpu_to_be16(addr16); + if (!eprom_check() || // Check precondition + !eprom_w_trans(2, (u_int8_t *)&addr16)) { // Write address + goto PCI_READ_ERROR; + } + + // Read reply + while (length) + { + int unit_len = length > EPROM_UNIT ? (int)EPROM_UNIT : length; + if (!eprom_r_trans(unit_len, data)) { + goto PCI_READ_ERROR; + } + data += unit_len; + length -= unit_len; + } + + eprom_cmd(EPROM_END); // End transaction + repeat = 0; // If error wasn't set everything is OK + + continue; + + // Error handling: + PCI_READ_ERROR: + if (_was_tmo) + { + if (_dbg_high) + printf("pci_read - transaction repeated\n"); + _was_tmo = false; + eprom_cmd(EPROM_END); + addr16 = __cpu_to_be16(addr16); + length = orig_len; + data = orig_data; + if (++repeat > MAX_REPETITION) + return errmsg("Pci read failed %d times: %s", MAX_REPETITION, err()); + } + else + return false; + } + + return true; +} // Eeprom::pci_read + +//////////////////////////////////////////////////////////////////////// +bool Eeprom::pci_write(u_int32_t addr, u_int8_t *data, u_int32_t length) +{ + u_int16_t addr16 = (u_int16_t) (addr & 0xffff); + int orig_len = length, repeat=1; + u_int8_t *orig_data = data; + + _was_tmo = false; + while (repeat) + { + + addr16 = __cpu_to_be16(addr16); + if (!eprom_check() || // Check precondition + !eprom_w_trans(2, (u_int8_t *)&addr16)) { // Write address + goto PCI_WRITE_ERROR; + } + + // Write data + while (length) + { + int unit_len = length > EPROM_UNIT ? (int)EPROM_UNIT : length; + eprom_w_trans(unit_len, data); + data += unit_len; + length -= unit_len; + } + + eprom_cmd(EPROM_END); // End transaction + eprom_wdelay(orig_len); + repeat = 0; // If error wasn't set everything is OK + + continue; + + PCI_WRITE_ERROR: + + if (_was_tmo) + { + if (_dbg_high) + printf("pci_write - transaction repeated, cnt=%d\n", repeat); + _was_tmo = false; + eprom_cmd(EPROM_END); + eprom_wdelay(orig_len); + addr16 = __cpu_to_be16(addr16); + length = orig_len; + data = orig_data; + if (++repeat > MAX_REPETITION) + return errmsg("Pci readwrite failed %d times: %s", MAX_REPETITION, err()); + } + else + return false; + + } + + return true; +} + + +//////////////////////////////////////////////////////////////////////// +void Eeprom::micro_sleep(const int n) +{ + usleep(n); +} // Eeprom::micro_sleep + + +//////////////////////////////////////////////////////////////////////// + + +bool Eeprom::write (u_int32_t addr, + DataVec& data) { + + if (!_conv) { + return errmsg("Internal error: read() when _conv not initialized"); + } + + vector eer = _conv->ConvertRange(addr, data.size()); + + if (eer.size() > 1) { + u_int32_t totWritten = 0; + for (vector::iterator it = eer.begin() ; it != eer.end(); ++it ) { + DataVec curData; + + u_int32_t chunkSize = it->second; + curData.insert(curData.begin(), + data.begin() + totWritten, + data.begin() + totWritten + chunkSize); + + if (!write(it->first.dev, it->first.offset, curData)) + return false; + + totWritten += chunkSize; + } + } else if (eer.size() == 1) { + if (!write(eer[0].first.dev, eer[0].first.offset, data)) + return false; + } else { + // eer.size() == 0 => no conversion: + return errmsg("No address/range conversion to eeprom address/size = %x/%x . Total eproms size: %x", + addr, + (u_int32_t)data.size(), + _conv->GetTotalSize()); + + } + + return true; +} + +bool Eeprom::write (u_int8_t i2c_slave, + u_int32_t offset, + DataVec& data) { + + u_int32_t len = data.size(); + u_int8_t* pdata = &(data[0]); + u_int32_t addr = offset; + + + while (len) + { + int i2c_wr_retry=0; + int burst_len = len > EPROM_BURST_W ? (int)EPROM_BURST_W : len; + int till_next_boundary = EPROM_ALIGN_W - (addr % EPROM_ALIGN_W); + if (burst_len > till_next_boundary) + burst_len = till_next_boundary; + + if (_mf) + { + _mf->i2c_slave = i2c_slave; + switch(_mf->tp) + { + case MST_CALBR: + if (mwrite64(_mf, addr, pdata, burst_len) != burst_len) + { + return errmsg("Write error: I2C slave:0x%02x, ADDR:0x%x - %s\n", + i2c_slave, addr, strerror(errno)); + + } + break; + case MST_USB: + case MST_USB_DIMAX: + case MST_IB: + case MST_IF: + while (mwrite64(_mf, addr, pdata, burst_len) != burst_len) + { + if (++i2c_wr_retry > MAX_I2C_WR_RETRY) + { + return errmsg("Write error: I2C slave:0x%02x, ADDR:0x%x - %s\n", + i2c_slave, addr, strerror(errno)); + } + } + break; + case MST_PPC: + case MST_PCI: + case MST_PCICONF: + if (!write_field(MISCC_SPM_ADR7, _mf->i2c_slave & 0x7f)) return false; + if (!pci_write(addr, pdata, burst_len)) return false; + break; + } + } + else + eprom_wdelay(burst_len); + + if (_prog) { + _prog->Add(burst_len); + } + + pdata += burst_len; + len -= burst_len; + addr += burst_len; + } + + return true; + +} // burn + + +//////////////////////////////////////////////////////////////////////// +bool Eeprom::read (u_int8_t i2c_slave, + u_int32_t offset, + u_int32_t len, + DataVec& data) { + + u_int32_t currSize = data.size(); + data.resize(currSize + len ); + + u_int8_t* pdata = &(data[currSize]); + u_int32_t addr = offset; + + u_int8_t vdata[EPROM_BURST_R]; + + while (len) + { + int i2c_rd_retry=0; + int burst_len = len > EPROM_BURST_R ? (int)EPROM_BURST_R : len; + + if (_mf) + { + _mf->i2c_slave = i2c_slave; + switch(_mf->tp) + { + case MST_CALBR: + if (mread64(_mf, addr, vdata, burst_len) != burst_len) + { + return errmsg("Read error: I2C slave:0x%02x, ADDR:0x%x - %s\n", + i2c_slave, addr, strerror(errno)); + } + break; + case MST_USB: + case MST_USB_DIMAX: + case MST_IB: + case MST_IF: + while (mread64(_mf, addr, vdata, burst_len) != burst_len) + { + if (++i2c_rd_retry > MAX_I2C_RD_RETRY) + { + return errmsg("Read error: I2C slave:0x%02x, ADDR:0x%x - %s\n", + i2c_slave, addr, strerror(errno)); + } + } + break; + case MST_PPC: + case MST_PCI: + case MST_PCICONF: + if (!write_field(MISCC_SPM_ADR7, _mf->i2c_slave & 0x7f)) return false; + if (!pci_read(addr, vdata, burst_len)) return false; + break; + } + + memcpy(pdata, vdata, burst_len); + + } + else + eprom_wdelay(burst_len); + + if (_prog) { + _prog->Add(burst_len); + } + + pdata += burst_len; + len -= burst_len; + addr += burst_len; + } + + return true; +} + + + +// +// ProgressBar: +// + +const char PercentProgressMeter::_spinner[8] = {'-','\\','|','/','-','\\','|','/'}; + +bool PercentProgressMeter::Add (u_int32_t amount) { + _current_progress += amount; + _add_count++; + u_int32_t progress_percent = (_current_progress * 100) / _progress_max; + u_int32_t spin_pos = _add_count % sizeof(_spinner); + + if (_current_progress >= _progress_max) { + if (_done) { + return true; + } + + _done = true; + spin_pos = 0; + } + + printf("\r"); + printf("%c %s - ", _spinner[spin_pos], _msg.c_str()); + if (_done) { + printf(" %s \n", _status); + } else { + printf("%%%02d", progress_percent); + fflush(stdout); + } + + return true; +} + + + +// Algorithm + + +//////////////////////////////////////////////////////////////////////// +// +// Burn Operations functions +// +//////////////////////////////////////////////////////////////////////// + +class Operations : public ErrMsg { +public: + + Operations() : + _useDefaultAnswer(false) + { + InitNames(); + } + + // + // IS3 FW IMAGE DATA + // + + enum { + MAX_IMAGE_SIZE = (128 * 1024), + PSID_CR_ADDR = 0x3ff0c + }; + + + // Data initialization types + enum SectionType { + TYPE_IWI = 1, // Individual words initialization + TYPE_NBI = 2, // Non-homogeneous block initialization + TYPE_HBI = 3, // Homogeneous block initialization + TYPE_RMW = 4, // Read-modify-write block initialization + TYPE_JMP = 5, // Jump address initialization + TYPE_COD = 97, // Code. Same as TYPE_NBI + TYPE_SPC = 98, // Special structire + TYPE_LST = 99, // Last data record + + // Following typed are not "real" type field values (meaning + // that they are not recognized by FW as a valid "type" fiels in + // a section). + TYPE_PLL = 200, + TYPE_BOOT= 201, // Boot section - different structure + TYPE_UNKNOWN= 0, + }; + + // Special STRUCT ID + enum FieldId { + FIELD_UNKNOWN= 0, + SYS_GUID_ID = 1, + NODE_DESC_ID = 2, + NODE_GUID_ID = 5, + BRD_ID = 3, + VS_CLS_EN_ID = 4, + BSN_ID = 6, + + // Not in Special Section: + PSID = 20, + CRC = 21 + }; + + // Simly burn the ImageFile content to rom. No checks or replaces. + bool RawBurn (Eeprom& eeprom, ImageFile& imageFile); + + bool CompareContent (Eeprom& eeprom, ImageFile& imageFile); + + // Failsafe burn flow: + // 1. Read and check imagefile (Primary Image). Exit if bad. + // 2. Read and verify full image on eeproms. + // Remember image state (which is valid). Exit if both are bad. + // 3. ? Compare AddressConvertors and Make sure they're the same. + // 4. Read PSID and Special section data from eeprom. + // 5. Get PSID and Special section data + adresses from image. Duplicate them for both images). + // 6. Patch the image with the data from eeprom (or from user). + // 7. Failsafe burn patched image according to the eeprom image state. + + struct ReplaceFieldData { + ReplaceFieldData() : + type(FIELD_UNKNOWN), + addr(0), + size(0) {} + FieldId type; + u_int32_t addr; + u_int32_t size; + DataVec data; + }; + + typedef std::map SpecialFieldsMap; + + struct FwImageData { + SectionVec _sections; + EeAddressConvertor _conv; + SpecialFieldsMap _specialFields; + + void Clear() { + for (SectionVec::iterator it = _sections.begin(); it != _sections.end(); ++it) { + delete *it; + } + + _conv.Clear(); + _specialFields.clear(); + } + + ~FwImageData() { + Clear(); + } + }; + + bool IS3FwBurn (Eeprom& eeprom, ImageFile& imageFile, const SpecialFieldsMap& userFields, bool fsBurn); + + bool CheckFullImage (IoBase& img, u_int8_t primaryI2cDev, u_int8_t secondaryI2cDev = 0, bool report = true); + bool CheckImage (IoBase& img, u_int8_t i2cDev, FwImageData& fwData, bool report, bool onlyDataSections = false); + + bool QueryImage (IoBase& img, u_int8_t primaryI2cDev, u_int8_t secondaryI2cDev); + bool DumpImage (Eeprom& eeprom, u_int8_t primaryI2cDev, u_int8_t secondaryI2cDev, const char* filename); + + bool ReadBlock (IoBase& img, u_int8_t i2cDev, u_int32_t offset, u_int32_t size, const char* filename); + + bool GetFieldFromString(SpecialFieldsMap& fields, FieldId fid, const char* str); + + void UseDefaultAnswers() {_useDefaultAnswer = true;} + +private: + + bool AskUser (const char* msg, bool def = true); + + bool GetSpecialData (const SectionVec& sectVec, SpecialFieldsMap& specialData); + bool ExtractSpecial (Section* s, SpecialFieldsMap& specialData); + + + bool DumpSections (FILE* f, Operations::FwImageData& imgData, bool convertRange = true); + bool DumpSpecial (FILE* f, Operations::FwImageData& imgData); + + bool GetFieldStringRepresentation(const DataVec& data, FieldId t, string& str); + + + bool FsBurnImage (Eeprom& eeprom, Operations::FwImageData& image, u_int32_t imgOffset); + + bool PatchNewImage (FwImageData& newImageData, + const SpecialFieldsMap& curFields, + const SpecialFieldsMap& userFields, + bool ignoreCurrent = false); + + bool BurnSections (Eeprom& eeprom, + const SectionVec& sectVec, + bool useAddress, + u_int32_t imgOffset, + const char* msg); + + bool CompareSections (Eeprom& eeprom, + const SectionVec& sectVec, + bool useAddress, + u_int32_t imgOffset, + const char* msg); + + bool ReplaceField (FwImageData& image, FieldId fid, const DataVec& fieldData); + bool FixSpecialCrc (FwImageData& image); + + // Verify CRC of the section. CRC is assumed to be found in the lase + // DW (BE) in the vector, and calculated over all the vector except + // last DW. + // Returns true ic CRC is ok, false otherwise. + bool CheckCrc (const DataVec& section); + + u_int32_t CalcCrc (const DataVec& data, u_int32_t size = 0); + + bool RecalcCrc (Section* s); + + + // Section check methods. The section is read from the given eeprom/addr. + // Read data is stores in the given sect struct, allocated by the caller. + bool CheckPlls (IoBase& img, u_int8_t eeprom, Section* sect); + bool CheckBoot (IoBase& img, u_int8_t eeprom, Section* sect); + bool CheckSection (IoBase& img, u_int32_t addr, Section* sect); + + + // Printing methods for verified image + bool ReportSection (Section* sect, const char* status = NULL); + bool ReportSectionHeader(); + + + bool PrintSpecialData (Operations::SpecialFieldsMap& fields, const char* src); + bool PrettyPrintSpecialData (Operations::SpecialFieldsMap& fields); + + std::map _sectionTypeNames; + std::map _fieldIdNames; + std::map _fieldIdSizes; + + bool _useDefaultAnswer; + + void InitNames() { + // Initialize the (static) names map. + if (_sectionTypeNames.empty()) { + _sectionTypeNames[TYPE_PLL] = "PLL"; + _sectionTypeNames[TYPE_BOOT] = "BOOT"; + _sectionTypeNames[TYPE_IWI] = "IWI"; + _sectionTypeNames[TYPE_NBI] = "NBI"; + _sectionTypeNames[TYPE_HBI] = "HBI"; + _sectionTypeNames[TYPE_RMW] = "RMW"; + _sectionTypeNames[TYPE_JMP] = "JUMP"; + _sectionTypeNames[TYPE_COD] = "CODE"; + _sectionTypeNames[TYPE_SPC] = "SPECIAL"; + _sectionTypeNames[TYPE_LST] = "LAST"; + _sectionTypeNames[TYPE_UNKNOWN] = "UNKNOWN"; + + _fieldIdNames[SYS_GUID_ID] = "System Image GUID" ; + _fieldIdNames[NODE_GUID_ID] = "Node GUID" ; + _fieldIdNames[NODE_DESC_ID] = "Node Description"; + _fieldIdNames[BSN_ID] = "Board Serial Number"; + _fieldIdNames[PSID] = "PSID"; + + + _fieldIdSizes[SYS_GUID_ID] = 8; + _fieldIdSizes[NODE_GUID_ID] = 8; + _fieldIdSizes[NODE_DESC_ID] = 64; + _fieldIdSizes[BSN_ID] = 64; + _fieldIdSizes[BRD_ID] = 4; + _fieldIdSizes[VS_CLS_EN_ID] = 4; + _fieldIdSizes[PSID] = 16; + } + } + + +}; + + +bool EeAddressConvertor::Init (const u_int8_t* eepromDataBytes) { + u_int32_t eepromData[EEPROMS]; + for (u_int32_t i = 0 ; i < EEPROMS ; i++ ) { + eepromData[i] = ImgBytes2Dw(eepromDataBytes + i * 4); + } + + return Init(eepromData); +} + +bool EeAddressConvertor::Init (const u_int32_t eepromData[EEPROMS]) { + _devmap.clear(); + for (u_int32_t i = 0 ; i < EEPROMS ; i++ ) { + u_int8_t d = eepromData[i] >> 24; + u_int32_t o = eepromData[i] & 0xffffff; + + _devmap.push_back(EeLoc(o,d)); + } + + return true; +} + + +u_int32_t EeAddressConvertor::GetTotalSize () const { + u_int32_t res = 0; + for (vector::const_iterator it = _devmap.begin(); it != _devmap.end() ; ++it) { + res += it->offset; + } + + return res; +} + + +EeLoc EeAddressConvertor::Convert (u_int32_t addr) const { + vector eer = ConvertRange(addr,1); + + if (eer.empty()) { + // TODO: Check return value for all calls of this function. + return EeLoc(0xffffffff, 0xff); + } else { + return eer[0].first; + } +} + + +vector EeAddressConvertor::ConvertRange (u_int32_t addr, u_int32_t len) const { + vector res; + //printf("-D- Converted (addr,size) => (dev,offset,size) : (%06x, %06x) = > ",addr, len); // NOTE - remove below printf too!!! + for (u_int32_t i = 0; len && i < _devmap.size() ; i++) { + u_int32_t devSize = _devmap[i].offset; + + if (addr < devSize) { + if (addr + len <= devSize) { + res.push_back(EeRange(EeLoc(addr, _devmap[i].dev), len)); + + //for (vector::iterator it = res.begin(); it != res.end(); ++it) + // printf("(%02x,%06x,%06x) ", it->first.dev, it->first.offset, it->second); + // printf("\n"); + + return res; + } + + u_int32_t curr_len = devSize - addr; + res.push_back(EeRange(EeLoc(addr, _devmap[i].dev), curr_len)); + len -= curr_len; + addr = 0; + + } else { + addr -= _devmap[i].offset; + } + } + + // If we're here - no mapping found. + // IBADM_THROW("Addr2OffsetDev: No mapping for the given addr (" << hex << addr << ")."); + res.clear(); + return res; + +} + + +u_int32_t EeAddressConvertor::Convert(const EeLoc& ee_loc) const { + if (_devmap.empty() && ee_loc.dev == 0) { + return ee_loc.offset; + } + + u_int32_t addr = 0; + + for (u_int32_t i = 0; i < _devmap.size() ; i++) { + if (_devmap[i].dev && (_devmap[i].dev == ee_loc.dev)) { + return addr + ee_loc.offset; + } else { + addr += _devmap[i].offset; + } + } + + // If we're here - no mapping found. + return (u_int32_t)(-1); +} + + + +bool ImageFile::open (const char* imageFile) { + + string tmp = imageFile; + string::size_type dotPos = tmp.rfind("."); + string ext; + + + if (dotPos == string::npos) { + ext = ""; + } else { + ext = tmp.substr(dotPos, tmp.size() - dotPos); + } + + if (ext == ".img" || ext == ".eeprom") { + return LoadImg(imageFile); +// } else if (ext == ".bin") { +// return LoadBin(imageFile); + } else { + return errmsg("Unsupported file format (%s). Supported formats: .img ", + ext.c_str()); + } +} + + +bool ImageFile::LoadImg(const char* imageFile) { + // Read and parse image file + + // 1. Load and Store IMG sections in _sections vector + // 2. Move data to the _devceData map. + // 3. Mark _primaryEeprom (the first section). + + + FILE *fp; + if ((fp = fopen(imageFile, "r")) == NULL) + { + return errmsg(strerror(errno)); + } + + u_int32_t lineNum = 0; + + Section *curr_sect = 0; + while(1) + { + const int MAX_STR = 1024; + u_int32_t curr_addr, curr_eepr, curr_value; + static char name[MAX_STR], str[MAX_STR], st[MAX_STR]; + char *endp; + + lineNum++; + + if (!curr_sect) + { + /* + * Outside section + */ + if (!fgets(str, MAX_STR, fp)) + break; + + // Skip comments and empty lines + if (str[strspn(str, " \t")] == '#') + continue; + if (str[strspn(str, " \t")] == '\n') + continue; + + sscanf(str, "%s %s %x %x", st, name, &curr_addr, &curr_eepr); + if (strcmp(st, "START")) + continue; + curr_sect = new Section(name, (u_int8_t)curr_eepr, curr_addr); + } + else + { + /* + * Inside section + */ + if (fscanf(fp, "%s", str) != 1) + { + return errmsg("%s:%d: Wrong EEPROM image format - unexpected EOF", + _fileName.c_str(), + lineNum); + } + if (!strcmp(str, "END")) + { + if (fscanf(fp, "%s", name) != 1) + { + return errmsg( + "Wrong EEPROM image format - after END name of " + "the input section is expected."); + } + if (strcmp(curr_sect->name.c_str(), name)) + { + return errmsg( + "Wrong EEPROM image format - end of section \"%s\" is" + " expected,\nwhile end of section \"%s\" is detected.", + curr_sect->name.c_str(), name); + } + _sections.push_back(curr_sect); + curr_sect = 0; + } + else + { + curr_value = strtoul(str, &endp, 16); + if (*endp != '\0') + return errmsg("Wrong EEPROM image - hexa constant %s" + "has invalid characters.", str); + + curr_sect->data.push_back((u_int8_t)curr_value); + } + } + } + fclose(fp); + + + //for (vector::iterator it = _sections.begin(); it != _sections.end(); ++it) { + // Section* s = *it; + // printf("-D- %-30s %02x %08x\n",s->name.c_str(), s->location.dev, s->location.offset); + //} + + + if (_sections.empty()) { + return errmsg("No image sections found."); + } + + // The first section in the given file is written to the primary eeprom. + _primaryEeprom = (*_sections.begin())->location.dev; + + // Put the data in the deviceData map + for (vector::iterator it = _sections.begin(); it != _sections.end(); ++it) { + + Section* s = *it; + DeviceDataMap::iterator dit = _deviceData.find(s->location.dev); + + if (dit == _deviceData.end()) { + // Add this device + _deviceData[s->location.dev]; + + dit = _deviceData.find(s->location.dev); + } + + DataVec& devData = dit->second; + + if (devData.size() < s->location.offset) { + // new section starts beyond the place where prev section ended - resize to start: + devData.resize(s->location.offset, 0); + } + + if (devData.size() == s->location.offset) { + // The section continues previous section - add to end. + devData.insert(devData.end(), s->data.begin(), s->data.end()); + } else if (devData.size() > s->location.offset + s->data.size() ) { + for (u_int32_t i = 0; i < s->data.size() ; i++) { + devData[s->location.offset + i] = s->data[i]; + } + } else { + return errmsg("Failed to process sections: Found section %s (%02x,$08x) of size %x bytes, but device current size is %x bytes.", + s->name.c_str(), + s->location.dev, + s->location.offset, + (u_int32_t)devData.size()); + } + } + + //for (DeviceDataMap::iterator it = _deviceData.begin(); it != _deviceData.end(); ++it) { + // printf("-D- Dev %02x Size %08x\n", it->first, it->second.size()); + //} + + return true; +} + + +bool IoBase::read (u_int32_t addr, + u_int32_t len, + DataVec& data) { + + if (!_conv) { + return errmsg("Internal error: read() when _conv not initialized"); + } + + vector eer = _conv->ConvertRange(addr, len); + + for (vector::iterator it = eer.begin() ; it != eer.end(); ++it ) { + if (!read(it->first.dev, it->first.offset, it->second, data)) + return false; + } + + return true; +} + + +// read() : Insert the extraced data to the given data vector. +// Note that if data is not empty, new the new data is appended to it. +bool ImageFile::read (u_int8_t i2c_slave, + u_int32_t offset, + u_int32_t len, + DataVec& data) { + + + DeviceDataMap::iterator dit = _deviceData.find(i2c_slave); + + if (dit == _deviceData.end()) { + return errmsg("Tried to read %x bytes from offset %x from a non existing device: %02x.", + len, + offset, + i2c_slave); + } + + DataVec& devData = dit->second; + + if (offset + len > devData.size()) { + return errmsg("Tried to read %x bytes from offset %x - Beyond device %02x size - %x.", + len, + offset, + i2c_slave, + (u_int32_t)devData.size()); + } + + + data.insert(data.end(), devData.begin() + offset, devData.begin() + offset + len); + + return true; +} + + + + +// +// Operations class implementation +// + +bool Operations::CheckPlls(IoBase& img, u_int8_t eeprom, Section* sect) { + sect->type = TYPE_PLL; + img.read(eeprom, 0x0, 0x28 , sect->data ); + + // Verify Checksum + const u_int8_t expectedCheckSum = 0xAB; + u_int8_t actualCheckSum = 0; + for (u_int32_t i = 0; i < 16 ; i++) { + actualCheckSum += sect->data[i]; + } + + if (actualCheckSum != expectedCheckSum) { + return errmsg("Bad PLL checksum: Expected: %02x, Actual: %02x", expectedCheckSum, actualCheckSum); + } + + return true; +} + + +bool Operations::CheckBoot(IoBase& img, u_int8_t eeprom, Section* sect) { + + DataVec data; + sect->type = TYPE_BOOT; + + // Read boot2 section size + img.read(eeprom, 0x2c, 4, data); + + u_int32_t bootSectSize = ImgBytes2Dw(&data[0]); + + // check reasonable size to make sure we're not working on a + // corrupted data (e.g. 0xffffffff of blank eeprom). The boot + // section size (and its crc + PLL boot record) can not cross 32KB. + + if (bootSectSize * 4 >= 32*1024 - 0x38) { + return errmsg("Boot section check failed. Read boot size from eeprom %02x, " + "offset %x is %x bytes, which is larger than 32KB.", + eeprom, + 0x2c, + bootSectSize * 4); + } + + u_int32_t bootSize = bootSectSize * 4 + 0x10; + + img.read(eeprom, 0x28, bootSize, sect->data); + + if (!CheckCrc(sect->data)) { + return false; + } + + return true; +} + +bool Operations::CheckCrc(const DataVec& data) { + + u_int32_t calc_crc = CalcCrc(data, data.size() - 4); + u_int32_t sect_crc = ImgBytes2Dw(&data[data.size() - 4]); + + if (sect_crc != calc_crc) { + return errmsg("Bad CRC: Aclual: %04x, Expected: %04x", + sect_crc, + calc_crc); + } + + return true; +} + + +u_int32_t Operations::CalcCrc(const DataVec& data, u_int32_t size) { + if (size == 0) { + size = data.size(); + } + + assert((size % 4) == 0); + + Crc16 crc; + for (u_int32_t i = 0; i < size ; i += 4) { + u_int32_t w = ImgBytes2Dw(&data[i]); + crc.add(w); + } + crc.finish(); + + return crc.get(); +} + +bool Operations::CheckSection(IoBase& img, u_int32_t addr, Section* sect) { + DataVec data; + + img.read(addr + 4, 4, data); + u_int32_t type_size = ImgBytes2Dw (&data[0]); + + sect->type = type_size >> 24; + u_int32_t sectSize = (type_size & 0xffff) * 4 + 8; + + img.read(addr, sectSize, sect->data); + + if (!CheckCrc(sect->data)) { + return false; + } + + return true; +} + +bool Operations::ReadBlock (IoBase& img, u_int8_t i2cDev, u_int32_t offset, u_int32_t size, const char* filename) { + FwImageData readData; + + Section* sect = new Section("ReadBlock" , i2cDev, offset); + readData._sections.push_back(sect); + + //printf("-D- bool Operations::ReadBlock ( , %x, %x, %x, %s)\n", i2cDev, offset, size,filename); + + if (!img.read(i2cDev, offset, size, sect->data)) + return errmsg("Read failed: %s", img.err()); + + FILE* of = fopen(filename, "w"); + if (of == NULL) { + return errmsg("Failed to open file %s for writing: %s", + filename, + strerror(errno)); + } + + if (!DumpSections(of, readData, false)) { + return false; + } + + fclose(of); + + return true; +} + + + +bool Operations::DumpImage (Eeprom& eeprom, u_int8_t primaryI2cDev, u_int8_t secondaryI2cDev, const char* filename) { + + bool primaryOk = false; + bool secondaryOk = false; + + primaryI2cDev = 0; //COMPILER WARNING; + secondaryI2cDev = 0; //COMPILER WARNING; + + FwImageData primaryImageData; + FwImageData secondaryImageData; + + PercentProgressMeter prog("Reading primary image " , MAX_IMAGE_SIZE); + eeprom.SetProgressMeter(&prog); + + primaryOk = CheckImage(eeprom, eeprom.GetPrimaryEeprom(), primaryImageData, false); + + if (primaryOk) { + prog.Done(); + } else { + prog.Done(err()); + } + + + PercentProgressMeter progSec("Reading secondary image " , MAX_IMAGE_SIZE); + eeprom.SetProgressMeter(&progSec); + secondaryOk = CheckImage(eeprom, eeprom.GetSecondaryEeprom(), secondaryImageData, false); + if (secondaryOk) { + progSec.Done(); + } else { + progSec.Done(err()); + } + + // Get special fields on eeprom and image file : + GetSpecialData(primaryImageData._sections, primaryImageData._specialFields); + GetSpecialData(secondaryImageData._sections, secondaryImageData._specialFields); + + FILE* of = fopen(filename, "w"); + + if (of == NULL) { + return errmsg("Failed to open file %s for writing: %s", + filename, + strerror(errno)); + } + + printf("- Writing image file ...\n"); + + + DumpSpecial(of, primaryImageData); + DumpSpecial(of, secondaryImageData); + + DumpSections(of, primaryImageData); + DumpSections(of, secondaryImageData); + + + fclose(of); + + if (!(primaryOk && secondaryOk)) { + // TODO: Should this be only a warning ? + return errmsg("Errors detected in the eeprom image - Image file may not be full"); + } + + + return true; +} + + +bool Operations::DumpSpecial(FILE* f, Operations::FwImageData& imgData) { + //fprintf(f, "# Operations::DumpSpecial - NOT YET IMPLEMENTED\n\n"); + f=NULL; + imgData._sections.size(); + return true; +} + +bool Operations::DumpSections(FILE* f, Operations::FwImageData& imgData, bool convertRange) { + for (SectionVec::const_iterator it = imgData._sections.begin() ; it != imgData._sections.end() ; ++it) { + Section* s = *it; + + // Sections are dumped in physical device boundaries: + vector eer; + + if (convertRange) + eer = imgData._conv.ConvertRange(s->addr, s->data.size()); + else { + eer.push_back(EeRange(s->location, s->data.size())); + } + + u_int32_t currOffset = 0; + + for (u_int32_t i = 0 ; i < eer.size() ; ++i) { + const char* sectName; + char sectNameBuff[64]; + SectionType t = (SectionType)s->type; + + if (eer.size() > 1) { + sprintf(sectNameBuff, "%s-%d", _sectionTypeNames[t], i); + sectName = sectNameBuff; + } else { + sectName = _sectionTypeNames[t]; + } + + fprintf(f , + "START %s %08x %02x\n", + sectName, + eer[i].first.offset, + eer[i].first.dev); + + const int bytesInLine = 4; + u_int32_t j; + for (j = 0 ; j < eer[i].second ; ++j) { + fprintf(f , " %02x", s->data[currOffset + j]); + if (((j+1) % bytesInLine) == 0) fprintf(f , "\n"); + } + + if (j % bytesInLine) fprintf(f , "\n"); + + fprintf(f , + "END %s\n\n", + sectName); + + currOffset += eer[i].second; + } + } + return true; +} + +bool Operations::CheckFullImage(IoBase& img, u_int8_t primaryI2cDev, u_int8_t secondaryI2cDev, bool report) { + bool ret; + FwImageData primaryImage; + FwImageData secondaryImage; + + if (report) printf("Primary Image:\n"); + ret = CheckImage(img, primaryI2cDev, primaryImage, report); + + if (ret == false && img.GetAddressConvertor() == NULL && secondaryI2cDev == 0) { + // Bad primary image - Address convertor not initialized, and secondary + // eeprom is not given - Can't check secondary image. + // TODO: See if to return errmsg here; + return false; + } + + // CheckImage Initiates address convertor: + if (secondaryI2cDev == 0) { + // Auto detect secondary I2c slave address - It is located in the middle + // of the eeproms size: + u_int32_t secondaryImageAddr = primaryImage._conv.GetTotalSize() / 2 ; + secondaryI2cDev = primaryImage._conv.Convert(secondaryImageAddr).dev; + } + + if (report) printf("\nSecondary Image:\n"); + if (!CheckImage(img, secondaryI2cDev, secondaryImage, report)) { + return false; + } + + return true; +} + +bool Operations::QueryImage(IoBase& img, u_int8_t primaryI2cDev, u_int8_t secondaryI2cDev) { + + bool ret; + FwImageData primaryImage; + FwImageData secondaryImage; + + FwImageData* validImage = NULL; + + ret = CheckImage(img, primaryI2cDev, primaryImage, false, false); + if (ret) + validImage = &primaryImage; + + if (ret == false && img.GetAddressConvertor() == NULL && secondaryI2cDev == 0) { + // Bad primary image - Address convertor not initialized, and secondary + // eeprom is not given - Can't check secondary image. + // TODO: See if to return errmsg here; + return false; + } + + if (validImage == NULL) { + // Check secondary image + if (secondaryI2cDev == 0) { + // Auto detect secondary I2c slave address - It is located in the middle + // of the eeproms size: + u_int32_t secondaryImageAddr = primaryImage._conv.GetTotalSize() / 2 ; + secondaryI2cDev = primaryImage._conv.Convert(secondaryImageAddr).dev; + } + + ret = CheckImage(img, secondaryI2cDev, secondaryImage, false , true); + if (ret) + validImage = &secondaryImage; + } + + if (validImage == NULL) { + return errmsg("No valid image."); + } + + // Print the selected fields: + printf("\nQuery:\n"); + if (!GetSpecialData(validImage->_sections, validImage->_specialFields)) { + return false; + } + + PrettyPrintSpecialData(validImage->_specialFields); + + return true; +} + + +bool Operations::PrettyPrintSpecialData(Operations::SpecialFieldsMap& fields) { + + FieldId queriedFields[] = {NODE_GUID_ID, SYS_GUID_ID, NODE_DESC_ID, BSN_ID, PSID}; + + for (u_int32_t i = 0 ; i < sizeof(queriedFields)/sizeof(queriedFields[0]) ; i++) { + FieldId fid = queriedFields[i]; + + ReplaceFieldData& rep = fields[fid]; + string val; + + if (!GetFieldStringRepresentation (rep.data, rep.type, val)) { + return false; + } + + if (_fieldIdNames[fid]) { + printf(" %-20s %s\n", _fieldIdNames[fid], val.c_str()); + } + } + + return true; +} + + +bool Operations::PrintSpecialData(Operations::SpecialFieldsMap& fields, const char* src) { + printf(" Special data fields of %s:\n", src); + printf("%-20s %-8s %-s4 %s\n", "FIELD", "ADDR", "SIZE", "VALUE"); + for (SpecialFieldsMap::iterator it = fields.begin(); + it != fields.end(); + ++it) { + + ReplaceFieldData& rep = it->second; + + string val; + + if (!GetFieldStringRepresentation (rep.data, rep.type, val)) { + return false; + } + + printf("%-20s %8x %4d %s\n", + _fieldIdNames[it->first], + rep.addr, + (u_int32_t)rep.data.size(), + val.c_str()); + + } + + return true; +} + + +bool Operations::CheckImage(IoBase& img, + u_int8_t i2cDev, + Operations::FwImageData& imageData, + bool report, + bool onlyDataSections) { + + Section* sect; + + if (report) ReportSectionHeader(); + + // PLL Section + sect = new Section(i2cDev, 0); + sect->addr = 0; + + if (!CheckPlls(img, i2cDev, sect)) { + if (report) ReportSection(sect, err()); + return false; + } + imageData._sections.push_back(sect); + if (report) ReportSection(sect); + + sect = new Section(i2cDev, 0x28); + sect->addr = 0x28; + + if (!CheckBoot(img, i2cDev, sect)) { + if (report) ReportSection(sect, err()); + return false; + } + imageData._sections.push_back(sect); + if (report) ReportSection(sect); + + if (!imageData._conv.Init(§->data[8])) { + return errmsg("Address convertor initiation failed"); + } + img.SetAddressConvertor(&imageData._conv); + + // boot start boot size (in bytes) + u_int32_t currAddress = 0x28 + sect->data.size(); + u_int32_t imageOffset = imageData._conv.Convert(EeLoc(0, i2cDev)); + + // Add the imageOffset to the sections already checked: + for (SectionVec::iterator it = imageData._sections.begin(); it != imageData._sections.end(); ++it) { + Section* s = *it; + s->addr += imageOffset; + } + + u_int8_t stopAtType = onlyDataSections ? TYPE_JMP : TYPE_LST; + + while(sect->type != stopAtType && currAddress < MAX_IMAGE_SIZE) { + u_int32_t absAddress = imageOffset + currAddress; + EeLoc loc = imageData._conv.Convert(absAddress); + + sect = new Section(loc.dev , loc.offset); + sect->addr = absAddress; + + if (!CheckSection(img, absAddress, sect)) { + if (report) ReportSection(sect, err()); + + return false; + } + + if (report) ReportSection(sect); + + currAddress += sect->data.size(); + imageData._sections.push_back(sect); + } + + return true; +} + + +bool Operations::ReportSectionHeader() { + printf(" %-3s %-6s %-6s %-10s %s\n", + "DEV", + "OFFSET", + "SIZE", + "TYPE", + "STATUS"); + + return true; +} + +bool Operations::ReportSection(Section* sect, const char* status) { + char unknownNameBuff[64]; + const char* sectName; + + if (status == NULL) { + status = "OK"; + } + + map::iterator it = _sectionTypeNames.find((SectionType)sect->type); + + if (it != _sectionTypeNames.end()) { + sectName = it->second; + } else { + sprintf(unknownNameBuff, "UNKNOWN(%d)" , sect->type); + sectName = unknownNameBuff; + } + + printf(" %02x %06x %06x %-10s %s\n", + sect->location.dev, + sect->location.offset, + (u_int32_t)sect->data.size(), + sectName, + status); + + return true; + +} + + + +bool Operations::GetSpecialData (const SectionVec& sectVec, SpecialFieldsMap& specialData) { + Section* psidSect = NULL; + Section* specialSect = NULL; + + // Find special section and PSID section. + for (SectionVec::const_iterator it = sectVec.begin(); + it != sectVec.end() && (psidSect == NULL || specialSect == NULL) ; ++it) { + Section* s = *it; + + if (s->type == TYPE_SPC) { + specialSect = s; + } else if (s->type == TYPE_NBI && s->data.size() == 32) { + // Check if this section initiates the PSID according to its CR address. + u_int32_t initAddr = ImgBytes2Dw(&s->data[8]); + if (initAddr == PSID_CR_ADDR) { + psidSect = s; + } + } + } + + // Parse the sections + if (!psidSect) { + return errmsg("Failed to find PSID section in the given image"); + } else { + specialData[PSID]; // Add the entry to the map. + ReplaceFieldData& psidField = specialData[PSID]; + + psidField.type = PSID; + psidField.addr = psidSect->addr + 12; + psidField.size = 16; + psidField.data.insert(psidField.data.begin(), + psidSect->data.begin() + 12, + psidSect->data.begin() + 12 + 16); + + + } + + if (!specialSect) { + return errmsg("Failed to find Special section in the given image"); + } + + return ExtractSpecial(specialSect, specialData); + +} + + +bool Operations::ExtractSpecial(Section* s, SpecialFieldsMap& specialData) { + + // Extract the data out of the dpecial section: + + u_int32_t fieldOffset = 8; // + + + while (fieldOffset < s->data.size() - 4) { + u_int16_t type = (u_int16_t)ImgBytes2Dw(&s->data[fieldOffset]); + u_int32_t fieldSize; + + std::map::iterator it = _fieldIdSizes.find((FieldId)type); + + if (it == _fieldIdSizes.end()) { + return errmsg("Failed to parse Special section: Unknown special field id: %x", type); + } else { + fieldSize = it->second; + } + + if (fieldOffset + fieldSize + 8 > s->data.size()) { + return errmsg("Failed to parse Special section: Field \"%s\" of size %d bytes from offset 0x%x " + "exceeds section size 0x%x", + _fieldIdNames[(FieldId)type], + fieldSize, + fieldOffset, + (u_int32_t)s->data.size()); + } + + + specialData[(FieldId)type]; // Add the entry to the map. + ReplaceFieldData& f = specialData[(FieldId)type]; + f.data.clear(); + + f.type = (FieldId)type; + f.addr = s->addr + fieldOffset + 4; + f.size = fieldSize; + f.data.insert(f.data.begin(), + s->data.begin() + fieldOffset + 4, + s->data.begin() + fieldOffset + 4 + fieldSize); + + // printf("-D- Extracted special %d %-20s %06x %d\n", type, _fieldIdNames[f.type], f.addr, f.size); + + fieldOffset = fieldOffset + fieldSize + 4; + + } + + return true; +} + +bool Operations::AskUser (const char* msg, bool def) { + printf(msg); + if (_useDefaultAnswer) { + printf("%s\n", def ? "y" : "n"); + return def; + } else { + char ansbuff[32]; + ansbuff[0] = '\0'; + + if (!isatty(0)) { + return errmsg("Not on tty - Can't interact. assuming \"no\" for question \"%s\"", msg); + } + fflush(stdout); + fgets(ansbuff, 30, stdin); + + if ( strcmp(ansbuff, "y\n") && + strcmp(ansbuff, "Y\n") && + strcmp(ansbuff, "yes\n") && + strcmp(ansbuff, "Yes\n") && + strcmp(ansbuff, "YES\n")) + return errmsg("Aborted by user"); + } + return true; +} + +bool Operations::GetFieldFromString(Operations::SpecialFieldsMap& fields, Operations::FieldId fid, const char* str) { + + u_int64_t guid; + char* eptr; + + u_int32_t len = strlen(str); + + switch (fid) { + case SYS_GUID_ID: + case NODE_GUID_ID: + guid = strtoull(str, &eptr, 16); + if (*eptr != '\0' || (guid == 0xffffffffffffffffULL && errno == ERANGE)) { + return errmsg("Failed to convert string \"%s\" to %s: %s", + str, + _fieldIdNames[fid], + errno ? strerror(errno) : "Bad format" ); + } else { + ReplaceFieldData& f = fields[fid]; // Creates the field in the fields map. + f.type = fid; + f.data.clear(); + f.data.resize(8,0); + + ::PatchImgBytes(&f.data[0], guid >> 32); + ::PatchImgBytes(&f.data[4], guid & 0xffffffff); + } + break; + + case BSN_ID: + case NODE_DESC_ID: + + if (len > 64) { + return errmsg("Field %s size must be less than 64 characters. Given string is %d characters long.", + _fieldIdNames[fid], + len); + } else { + ReplaceFieldData& f = fields[fid]; // Creates the field in the fields map. + f.type = fid; + f.data.clear(); + f.data.resize(64,0); + + for (u_int32_t i = 0; i < len; i++) { + f.data[i] = str[i]; + } + } + + break; + + default: + return errmsg("Failed to convert the given string \"%s\" to field id %d", str, fid); + } + + return true; +} + + +bool Operations::GetFieldStringRepresentation(const DataVec& data, FieldId t, string& str) { + + char buff[65]; + u_int32_t guid_high; + u_int32_t guid_low; + u_int32_t tmp; + u_int32_t i; + + //printf("-D- To string: type:%d, size:%d\n", t, data.size()); + + switch (t) { + case SYS_GUID_ID: + case NODE_GUID_ID: + guid_high = ImgBytes2Dw(&data[0]); + guid_low = ImgBytes2Dw(&data[4]); + + sprintf(buff, "0x%08x%08x", guid_high, guid_low); + break; + + case BSN_ID: + case NODE_DESC_ID: + case PSID: + + for (i = 0; i < data.size(); i++) { + buff[i] = data[i]; + } + + buff[i] = '\0'; + + break; + + case BRD_ID: + case VS_CLS_EN_ID: + tmp = ImgBytes2Dw(&data[0]); + sprintf(buff, "0x%08x", tmp); + break; + + + default: + return errmsg("No string representation fot the given type ID (%d)", t); + } + + str = buff; + return true; +} + + +bool Operations::PatchNewImage (Operations::FwImageData& newImageData, + const Operations::SpecialFieldsMap& curFields, + const Operations::SpecialFieldsMap& userFields, + bool ignoreCurrent) { + + // Patch fields from eeproms to image. + FieldId keepFields[] = {SYS_GUID_ID, NODE_DESC_ID, NODE_GUID_ID, BSN_ID }; + + for (u_int32_t i = 0 ; i < sizeof(keepFields)/sizeof(keepFields[0]); i++) { + // Check if the field is forced by user + FieldId fid = keepFields[i]; + + const DataVec* fieldData; + + SpecialFieldsMap::const_iterator userFieldIt = userFields.find(fid); + SpecialFieldsMap::const_iterator curFieldIt = curFields.find(fid); + + if (ignoreCurrent) { + // Take what ever field we can from current image + // If not in image (when burning a blank eeprom, take from user defined values. + // If not in user defined values, leave as is in new image. + + if (userFieldIt != userFields.end()) { + fieldData = &userFieldIt->second.data; + } else if (curFieldIt != curFields.end()){ + fieldData = &curFieldIt->second.data; + } else { + // Keep the current value of the field in the image: + continue; + } + } else { + + // + // Consider current fields - If a field is not found in the current image, error. + // Prompt user for user defined values. + // + + if (curFieldIt == curFields.end()) { + return errmsg("Can not read field \"%s\" from the eeprom", _fieldIdNames[fid]); + } + + const ReplaceFieldData& curField = curFieldIt->second; + + if (userFieldIt != userFields.end()) { + string curVal; + string userVal; + + const ReplaceFieldData& userField = userFieldIt->second; + + GetFieldStringRepresentation(curField.data, fid, curVal); + GetFieldStringRepresentation(userField.data, fid, userVal); + + + printf("\n You are about to replace %s in eeprom:\n" + " Current value: %s\n" + " New value: %s\n", + _fieldIdNames[fid], + curVal.c_str(), + userVal.c_str() + ); + + if (!AskUser("\n Is it OK ? (y/n) [n] : ")) + return errmsg("Aborted by user"); + + fieldData = &userField.data; + + } else { + fieldData = &curField.data; + } + } + + // Apply the field to the new image: + if (!ReplaceField(newImageData, fid, *fieldData)) { + return false; + } + } + + // Fix CRC after applying current/user supplied fields. + if (!FixSpecialCrc(newImageData)) { + return false; + } + + return true; +} + +bool Operations::ReplaceField(Operations::FwImageData& image, Operations::FieldId fid, const DataVec& fieldData) { + + ReplaceFieldData& f = image._specialFields[fid]; + + Section* targetSection = NULL; + + // Looking for the section to patch with new data. + // Assuming that the new data occupies a single section, + // and that sections are ordered in aecending addr + for (SectionVec::iterator it = image._sections.begin(); it != image._sections.end(); ++it) { + Section* s = *it; + + if (s->addr <= f.addr && (s->addr + s->data.size()) > f.addr ) { + targetSection = s; + break; + } + + } + + u_int32_t fieldSectOffset = f.addr - targetSection->addr; + if (targetSection->data.size() < fieldSectOffset + fieldData.size()) { + return errmsg("Bad image structure: Replaced field %s at address %x of size %d " + "does not fit in the section starting at address %x , size %x", + _fieldIdNames[fid], + f.addr, + (u_int32_t)fieldData.size(), + targetSection->addr, + (u_int32_t)targetSection->data.size()); + } + + // Patch the section data: + for (u_int32_t i = 0; i < fieldData.size() ; i++) { + targetSection->data[fieldSectOffset + i] = fieldData[i]; + } + + return true; +} + +bool Operations::FixSpecialCrc(Operations::FwImageData& image) { + Section* specialSect = NULL; + + // Find special section and PSID section. + for (SectionVec::const_iterator it = image._sections.begin(); + it != image._sections.end() ; ++it) { + Section* s = *it; + + if (s->type == TYPE_SPC) { + specialSect = s; + break; + } + } + + if (specialSect == NULL) { + return errmsg("Special section not found"); + } + + return RecalcCrc(specialSect); +} + + +bool Operations::RecalcCrc(Section* s) { + u_int32_t crc = CalcCrc(s->data, s->data.size() - 4); + + ::PatchImgBytes(&s->data[s->data.size()-4], crc); + return true; +} + +bool Operations::IS3FwBurn (Eeprom& eeprom, + ImageFile& imageFile, + const SpecialFieldsMap& userFields, + bool fsBurn) { + // Failsafe burn flow: + // 1. Read and check imagefile (Primary Image). Exit if bad. + // 2. Read and verify full image on eeproms. + // Remember image state (which is valid). Exit if both are bad. + // 3. ? Compare AddressConvertors and Make sure they're the same. + // 4. Read PSID and Special section data from eeprom. + // 5. Get PSID and Special section data + adresses from image file. Duplicate them for both images). + // 6. Patch the image with the data from eeprom (or from user). + // 7. Failsafe burn patched image according to the eeprom image state + + u_int8_t primaryI2cDev = imageFile.GetPrimaryEeprom(); + + FwImageData newImageData; + if (!CheckImage(imageFile, primaryI2cDev, newImageData, false)) { + return errmsg("Bad image in file %s: %s", imageFile.FileName().c_str(), err()); + } + + + bool primaryOk = false; + bool secondaryOk = false; + + FwImageData curImageData; + + PercentProgressMeter prog("Checking primary image " , MAX_IMAGE_SIZE); + eeprom.SetProgressMeter(&prog); + + primaryOk = CheckImage(eeprom, eeprom.GetPrimaryEeprom(), curImageData, false, !fsBurn); + + if (primaryOk) { + prog.Done(); + } else { + prog.Done(err()); + } + + if (!primaryOk) { + curImageData.Clear(); + PercentProgressMeter progSec("Checking secondary image " , MAX_IMAGE_SIZE); + eeprom.SetProgressMeter(&progSec); + secondaryOk = CheckImage(eeprom, eeprom.GetSecondaryEeprom(), curImageData, false, !fsBurn); + if (secondaryOk) { + progSec.Done(); + } else { + progSec.Done(err()); + } + } + + if (!primaryOk && !secondaryOk) { + if (fsBurn) { + return errmsg("Both images on eeproms %02x and %02x are not valid. Can not perform failsafe burn.", + eeprom.GetPrimaryEeprom(), + eeprom.GetSecondaryEeprom()); + } else { + eeprom.SetAddressConvertor(&newImageData._conv); + } + } + + // Get special fields on eeprom and image file : + if (!GetSpecialData(newImageData._sections, newImageData._specialFields)) { + return errmsg("Failed get special fields from the given image file: %s", err()); + } + + if (!GetSpecialData(curImageData._sections, curImageData._specialFields) && fsBurn) { + return errmsg("Failed get special fields from the eeprom image: %s", err()); + } + + //PrintSpecialData(newImageData._specialFields, "Image file"); + //PrintSpecialData(curImageData._specialFields, "Eeprom"); + + // Check PSIDs + string curPsid; + string newPsid; + if (!GetFieldStringRepresentation(curImageData._specialFields[PSID].data, PSID, curPsid) ) { + return errmsg("Failed getting PSID of the image on eeprom."); + } + + if (!GetFieldStringRepresentation(newImageData._specialFields[PSID].data, PSID, newPsid) ) { + return errmsg("Failed getting PSID of the given image file."); + } + + if (curPsid != newPsid) { + printf("\n You are about to replace current PSID in eeprom - \"%s\" with a different PSID - \"%s\".\n", + curPsid.c_str(), + newPsid.c_str()); + + if (!AskUser("\n Is it OK ? (y/n) [n] : ")) + return errmsg("Aborted by user"); + } + + if (!PatchNewImage(newImageData, curImageData._specialFields , userFields, !fsBurn)) { + return false; + } + + // + // Burn: + // + + u_int32_t primaryOffset = 0; + u_int32_t secondaryOffset = newImageData._conv.Convert(EeLoc(0, eeprom.GetSecondaryEeprom())); + + if (secondaryOffset == 0xffffffff) { + return errmsg("Can't map secondary eeprom i2c address (%02x).", eeprom.GetSecondaryEeprom()); + } + + //printf("\n-I- Burning image with the following values:\n"); + //PrettyPrintSpecialData(newImageData._specialFields); + //printf("\n\n"); + + if (fsBurn) { + if (secondaryOk) { + // Burn primary image first + if (!FsBurnImage(eeprom, newImageData, primaryOffset )) return false; + if (!FsBurnImage(eeprom, newImageData, secondaryOffset)) return false; + } else { + // burn primary image first. + if (!FsBurnImage(eeprom, newImageData, secondaryOffset)) return false; + if (!FsBurnImage(eeprom, newImageData, primaryOffset )) return false; + } + } else { + if (!FsBurnImage(eeprom, newImageData, primaryOffset )) return false; + } + return true; +} + + + + +bool Operations::FsBurnImage(Eeprom& eeprom, Operations::FwImageData& image, u_int32_t imgOffset) { + + // Invalidate the PLL boot record checksum. + + SectionVec& sectVec = image._sections; + + DataVec origData(4); + DataVec& pllSectData = sectVec[0]->data; + for (u_int32_t i = 0 ; i < 4 ;i++) { + origData[i] = pllSectData[i]; + } + + pllSectData[3] = pllSectData[3] + 0xA; + + const char *burnMsg; + const char *verifyMsg; + if (imgOffset == 0) { + burnMsg = "Burning primary image "; + verifyMsg = "Verifying primary image "; + } else { + burnMsg = "Burning secondary image "; + verifyMsg = "Verifying secondary image "; + } + + if (!BurnSections (eeprom, sectVec, true, imgOffset, burnMsg)) { + return false; + } + + if (!CompareSections(eeprom, sectVec, true, imgOffset, verifyMsg)) { + return false; + } + + // Restore PLL boot record section with correct Checksum. + // TODO: Verify: + if (!eeprom.write(imgOffset , origData)) { + return errmsg("EEprom write failed: %s", eeprom.err()); + } + + // Restore the image in memory for future use + for (u_int32_t i = 0 ; i < 4 ;i++) { + pllSectData[i] = origData[i]; + } + + return true; +} + + +bool Operations::BurnSections(Eeprom& eeprom, const SectionVec& sectVec, bool useAddress, u_int32_t imgOffset, const char* msg ) { + + u_int32_t totSize = 0; + SectionVec::const_iterator it; + + for (it = sectVec.begin() ; it != sectVec.end() ; ++it) { + Section* s = *it; + totSize += s->data.size(); + } + + PercentProgressMeter prog(msg, totSize); + eeprom.SetProgressMeter(&prog); + + for (it = sectVec.begin() ; it != sectVec.end(); ++it) { + Section* s = *it; + if (useAddress) { + eeprom.write(s->addr + imgOffset, s->data); + } else { + eeprom.write(s->location.dev, s->location.offset, s->data); + } + } + + eeprom.SetProgressMeter(NULL); + return true; +} + +bool Operations::CompareSections(Eeprom& eeprom, const SectionVec& sectVec, bool useAddress, u_int32_t imgOffset, const char* msg ) { + + u_int32_t totSize = 0; + SectionVec::const_iterator it; + + for (it = sectVec.begin() ; it != sectVec.end() ; ++it) { + Section* s = *it; + totSize += s->data.size(); + } + + PercentProgressMeter prog(msg, totSize); + eeprom.SetProgressMeter(&prog); + + for (SectionVec::const_iterator it = sectVec.begin() ; + it != sectVec.end(); + ++it) { + + Section* s = *it; + DataVec readData; + + if (useAddress) { + ((IoBase*)(&eeprom))->read(s->addr + imgOffset, s->data.size(), readData); + } else { + eeprom.read(s->location.dev, s->location.offset, s->data.size(), readData); + } + + // Compare: + for (u_int32_t i = 0; i < readData.size(); i++) { + if (readData[i] != s->data[i]) { + if (useAddress) { + //for (u_int32_t j = 0; j < 100 ; j++ ) { + // printf("%06x %02x %02x\n", + // } + return errmsg("Address %06x: Expected %02x, got %02x", + s->addr + imgOffset + i, + s->data[i], + readData[i]); + } else { + return errmsg("Eeprom %02x, Offset %x: Expected %02x, got %02x", + s->location.dev, + s->location.offset + i, + s->data[i], + readData[i]); + } + } + } + } + + eeprom.SetProgressMeter(NULL); + return true; +} + + + +bool Operations::RawBurn(Eeprom& eeprom, ImageFile& imageFile) { + const SectionVec& sectVec = imageFile.GetSections(); + + return BurnSections(eeprom, sectVec, false, 0, "Burning Image"); +} + +bool Operations::CompareContent(Eeprom& eeprom, ImageFile& imageFile) { + const SectionVec& sectVec = imageFile.GetSections(); + + return CompareSections(eeprom, sectVec, false, 0, "Verifying "); +} + + + + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +#ifndef SPARK_NAME +#define SPARK_NAME "spark" +#define DEV_MST_EXAMPLE1 "/dev/mst/mtusb-1" +#define DEV_MST_EXAMPLE2 "/dev/mst/mtusb-1" +#endif + +void usage(const char *sname, bool full = false) +{ + const char *descr = + "\n" + " SPARK - Eeprom FW burning tool for Mellanox IS/IS3 switches.\n" + "\n" + "\n" + "Usage:\n" + "------\n" + "\n" + " " SPARK_NAME " [switches...] [parameters...]\n" + "\n" + "\n" + "Switches summary:\n" + "-----------------\n" + "\n" +// " -crc - Print CRC after each section when verify.\n" +// "\n" + " -d[evice] - The device the eeprom is connected to.\n" + " Commands affected: all\n" + "\n" + " -i[mage] - Image file in \".img\" format.\n" + " Commands affected: burn, verify\n" + "\n" + " -guid - Use the given guid as the node guid of the burnt image.\n" + " By default, the guid is taken from the image on the eeprom\n" + "\n" + " Commands affected: burn\n" + "\n" + " -sysguid - Use the given guid as the system image guid of the burnt image.\n" + " By default, this value is taken from the current image on the eeprom\n" + "\n" + " Commands affected: burn\n" + "\n" + " -bsn - Mellanox Board Serial Number (BSN).\n" + " Valid BSN format is:\n" + " MTxxxxx[-]R[xx]ddmmyy-nnn[-cc]\n" + " By default, this value is taken from the current image on the eeprom\n" + "\n" + " Commands affected: burn\n" + "\n" + " -ndesc - Use the given string (max 64 characters) as the node description.\n" + " By default, this value is taken from the current image on the eeprom\n" + "\n" + " Commands affected: burn\n" + "\n" + " -is3_i2c - Provides the I2C address of the switch device. If this flag is not specified,\n" + " then the the default address for Mellanox switch devices is: 0x6c.\n" + "\n" + " -pe_i2c - Provides the I2C address of the primary EEPROM. By default, this address is read\n" + " from the Mellanox switch device. Use this flag only if the switch device is not\n" + " accessible.\n" + "\n" + " -se_i2c - Provides the I2C address of the secondary EEPROM. By default, this address is read \n" + " from the Mellanox switch device. Use this flag only if the switch device is not\n" + " accessible.\n" + "\n" + + " -h[elp] - Prints this message and exits\n" + " -hh - Prints extended command help\n" + "\n" + " -nofs - Burn image not in a failsafe manner.\n" + "\n" +// " -s[ilent] - Do not print burn progress flyer.\n" +// " Commands affected: burn\n" +// "\n" + " -y[es] - Non interactive mode - assume answer\n" + " \"yes\" to all questions.\n" + " Commands affected: all\n" + "\n" + " -v - Version info.\n" + "\n" + "Commands summary (use -hh flag for full commands description):\n" + "-----------------\n" + " b[urn] - Burn flash\n" + " q[uery] - Query misc. eeprom/FW characteristics\n" + " v[erify] - Verify entire eeprom\n" + " bb - Burn Block - Burns the given image as is. No checks are done.\n" + " ri - Read the fw image on the flash.\n" +// " dc - Dump Configuration: print fw configuration file for the given image.\n" + "\n"; + + + + const char* full_descr = + "\n" + "Command descriptions:\n" + "----------------------------\n" + "\n" + "* Burn eeprom\n" + " Burns entire flash from raw binary image.\n" + "\n" + " Command:\n" + " b[urn]\n" + " Parameters:\n" + " None\n" + " Examples:\n" + " " SPARK_NAME " -d " DEV_MST_EXAMPLE1 " -i image1.img burn\n" + " " SPARK_NAME " -d " DEV_MST_EXAMPLE2 " -guid 0x2c9000100d050 -i image1.img b\n" + "\n" + "\n" + "* Burn Block\n" + " Burns the entire eeprom from raw image as is. No checks are done on the eeprom or\n" + " on the given image file. No fields (such as BSN or Guids) are read from eeprom. \n" + " This command can bu used to burn Infiniscale devices.\n" + "\n" + " Command:\n" + " bb\n" + " Parameters:\n" + " None\n" + " Examples:\n" + " " SPARK_NAME " -d " DEV_MST_EXAMPLE1 " -i image1.img bb\n" + "\n" + "\n" + "* Query miscellaneous FW and eeprom parameters\n" + "\n" + " Command:\n" + " q[uery]\n" + " Parameters:\n" + " None\n" + " Example:\n" + " " SPARK_NAME " -d " DEV_MST_EXAMPLE1 " query\n" + "\n" + "* Verify entire flash.\n" + "\n" + " Command:\n" + " v[erify]\n" + " Parameters:\n" + " None\n" + " Example:\n" + " " SPARK_NAME " -d " DEV_MST_EXAMPLE1 " v\n" + "\n" + "* Read the FW image from eeprom and write it to a file.\n" + "\n" + " Command:\n" + " ri\n" + " Parameters:\n" + " file - filename to write the image to (in .img format).\n" + " Example:\n" + " " SPARK_NAME " -d " DEV_MST_EXAMPLE1 " ri file.img\n" + "\n" + "\n"; + + printf(descr, sname); + + if (full) { + printf(full_descr, sname); + } +} + + +// +// Commands database and parsing methods +// +enum CommandInput { + CI_NONE = 0x01, + CI_IMG_ONLY = 0x02, + CI_DEV_ONLY = 0x04, + CI_IMG_OR_DEV = 0x06, + CI_IMG_AND_DEV = 0x08 +}; + +enum CommandType { + CMD_UNKNOWN, + CMD_BURN, + CMD_BURN_BLOCK, + CMD_QUERY, + CMD_VERIFY, + CMD_READ_BLOCK, + CMD_READ_IMAGE, +}; + +struct CommandInfo { + CommandType cmd; + const char* cmdName; + bool requireExactMatch; + int maxArgs; + CommandInput requiredInput; + const char* cmdDescription; + +}; + +CommandInfo const g_commands[] = { + { CMD_BURN , "burn" ,false , 0 , CI_IMG_AND_DEV , ""}, + { CMD_BURN_BLOCK , "bb" ,true , 0 , CI_IMG_AND_DEV , ""}, + { CMD_QUERY , "query" ,false , 0 , CI_IMG_OR_DEV , ""}, + { CMD_VERIFY , "verify",false , 0 , CI_IMG_OR_DEV , ""}, + { CMD_READ_BLOCK , "rb" ,true , 4 , CI_DEV_ONLY , ""}, + { CMD_READ_IMAGE , "ri" ,true , 1 , CI_DEV_ONLY , ""}, +}; + +#define numbel(x) (sizeof(x)/sizeof((x)[0])) + + +const CommandInfo* GetCommandInfo(CommandType cmd) { + for (u_int32_t i = 0 ; i < numbel(g_commands); i++ ) { + if (cmd == g_commands[i].cmd) { + return &g_commands[i]; + } + } + + return NULL; +} + +CommandType ParseCommand(const char* cmd) { + u_int32_t cmdLenGiven = strlen(cmd); + + for (u_int32_t i = 0 ; i < numbel(g_commands); i++ ) { + if (g_commands[i].requireExactMatch ) { + if (!strcmp(cmd, g_commands[i].cmdName)) { + return g_commands[i].cmd; + } + } else { + // Match if given cmd maches the beginning of the checked cmd + if (!strncmp(cmd, g_commands[i].cmdName, cmdLenGiven )) { + return g_commands[i].cmd; + } + } + } + return CMD_UNKNOWN; +} + + +bool CheckCommandInputs(const char* dev, + const char* img, + CommandType cmd) { + + const CommandInfo* cmdInfo = GetCommandInfo(cmd); + + if (!cmdInfo) { + printf("*** INTERNAL ERROR *** Unknown command given to CheckCommandInputs() (%d)\n", cmd); + return false; + } + + char* inputDesStr [] = { + NULL, + "nither device nor an image file", // CI_NONE + "only an image file", // CI_IMG_ONLY, + NULL, + "only a device", // CI_DEV_ONLY, + NULL, + "either an image file or a device", // CI_IMG_OR_DEV, + NULL, + "both an image file and a device" // CI_IMG_AND_DEV + }; + + CommandInput given; + + if ( dev && img) { + given = CI_IMG_AND_DEV; + } else if (!dev && img) { + given = CI_IMG_ONLY; + } else if (dev && !img) { + given = CI_DEV_ONLY; + } else { + given = CI_NONE; + } + + if ((given & cmdInfo->requiredInput) == 0) { + printf("-E- Command \"%s\" requires %s, but %s %s given.\n", + cmdInfo->cmdName, + inputDesStr[cmdInfo->requiredInput], + inputDesStr[given], + given == CI_IMG_AND_DEV ? "are" : "is"); + return false; + } + + return true; +} + +bool CheckMaxCmdArguments(CommandType cmd, int numArgs) { + const CommandInfo* cmdInfo = GetCommandInfo(cmd); + if (!cmdInfo) { + printf("*** INTERNAL ERROR *** Unknown command given to CheckMaxCmdArguments (%d)\n", cmd); + return false; + } + + if (cmdInfo->maxArgs >= 0 && numArgs > cmdInfo->maxArgs) { + printf("-E- Command \"%s\" requires %d arguments, but %d arguments were given\n", + cmdInfo->cmdName, + cmdInfo->maxArgs, + numArgs); + return false; + } + return true; +} + + + + +#define SETERR(args) do { printf("-E- "); printf args ; printf("\n"); return 1; } while(0) + +//////////////////////////////////////////////////////////////////////// +#define NEXT(s) do { \ + if (i+1 >= ac) \ + { \ + SETERR(("Missing parameter after \"%s\" switch", s)); \ + exit(1); \ + } else i++;} while(0) + +#define NEXTC(c,param) do { \ + if (++i >= ac) \ + { \ + SETERR(("Command \"%s\": Missing parameter <%s> ", c , param)); \ + exit(1); \ + }} while(0) + +int main(int ac, char *av[]) +{ + bool verbose = true; + + bool fsBurn = true; + bool useDefaultAnswers = false; + + + char *image_fname=0, *dev=0; + + const char* userNodeGuid = NULL; + const char* userSysGuid = NULL; + const char* userBsn = NULL; + const char* userNodeDesc = NULL; + + const char* cmdStr = NULL; + + u_int8_t is3I2cSlave = 0x6C; // Default IS3 I2C address in Mellanox switch systems. + u_int8_t userPrimaryI2cAddr = 0; + u_int8_t userSecondaryI2cAddr = 0; + + int i; + + // Command line parameters + if (ac < 2) + usage(av[0]); + for (i = 1; i < ac; i++) + { + if (*av[i] == '-') + { + int switchLen = strlen(av[i]); + + if (!strncmp(av[i], "-device", switchLen)) { + NEXT("-device"); + dev = av[i]; + } + else if (!strncmp(av[i], "-image", switchLen)) { + NEXT("-i"); + image_fname = av[i]; + } + else if (!strcmp(av[i], "-v") || !strcmp(av[i], "-vv")) { + printf("%s: %s .", + av[0], + _versionID); + + if (!strcmp(av[i], "-vv")) { + printf(" SVN %s", _cvsID + 1); + } + + printf("\n"); + return 0; + } + else if (!strcmp(av[i], "-s")) + verbose = false; + else if (!strncmp(av[i], "-yes", switchLen)) + useDefaultAnswers = true; + else if (!strcmp(av[i], "-nofs")) + fsBurn = false; + else if (!strcmp(av[i], "-guid")) { + NEXT("-guid"); + userNodeGuid = av[i]; + } + else if (!strcmp(av[i], "-sysguid")) { + NEXT("-sysguid"); + userSysGuid = av[i]; + } + else if (!strcmp(av[i], "-bsn")) { + NEXT("-bsn"); + userBsn = av[i]; + } + else if (!strcmp(av[i], "-ndesc")) { + NEXT("-ndesc"); + userNodeDesc = av[i]; + } + else if (!strcmp(av[i], "-is3_i2c")) { + NEXT("-is3_i2c"); + char* ep; + is3I2cSlave = strtoul(av[i], &ep, 16); + if (*ep) { + SETERR(("Bad argument for %s flag (%s). Expecting a hexadecimal integer.", av[i-1], av[i])); + } + } + else if (!strcmp(av[i], "-pe_i2c") || !strcmp(av[i], "-pe")) { + NEXT("-pe_i2c"); + char* ep; + userPrimaryI2cAddr = strtoul(av[i], &ep, 16); + if (*ep) { + SETERR(("Bad argument for %s flag (%s). Expecting a hexadecimal integer.", av[i-1], av[i])); + } + } + else if (!strcmp(av[i], "-se_i2c") || !strcmp(av[i], "-se") ) { + NEXT(av[i]); + char* ep; + userSecondaryI2cAddr = strtoul(av[i], &ep, 16); + if (*ep) { + SETERR(("Bad argument for %s flag (%s). Expecting a hexadecimal integer.", av[i-1], av[i])); + } + } + else if (!strncmp(av[i], "-hh", 3)) { + usage(av[0], true); + return 1; + } + else if (!strncmp(av[i], "-help", switchLen) || !strncmp(av[i], "--h", 3)) { + usage(av[0]); + return 1; + + } + else { + SETERR(("Invalid switch \"%s\" is specified.\n", av[i])); + } + } else { + cmdStr = av[i]; + break; + } + } + + if (cmdStr == NULL) { + SETERR(("No command given. See help for details.")); + } + + IoBase* img; + + Eeprom* eeprom = NULL; + ImageFile* imageFile = NULL; + + Operations::SpecialFieldsMap userFields; + + Operations op; + + if (useDefaultAnswers) { + op.UseDefaultAnswers(); + } + + // + // Check command + // + CommandType cmd = CMD_UNKNOWN; + cmd = ParseCommand(av[i]); + if (cmd == CMD_UNKNOWN) { + SETERR(("Invalid command \"%s\".\n", av[i])); + } + + if (!CheckCommandInputs(dev, image_fname, cmd)) { + return 1; + } + + if (!CheckMaxCmdArguments(cmd, ac - i - 1 )) { + return 1; + } + + + // + // Open device and image file + // + if (dev) { + eeprom = new Eeprom; + img = eeprom; + if (!img->open(dev)) { + SETERR(("Failed to open device %s: %s", dev, img->err())); + } + + if (cmd != CMD_BURN_BLOCK && cmd != CMD_READ_BLOCK) { + if (userPrimaryI2cAddr) { + eeprom->InitImageAddressesFromUser(userPrimaryI2cAddr, userSecondaryI2cAddr); + } else { + if (!eeprom->InitImageAddressesFromIs3(is3I2cSlave)) { + SETERR(("Failed getting eeproms I2C addresses from IS3 device on I2C address %02x : %s", + is3I2cSlave, + eeprom->err())); + } + } + } + } + + if (image_fname) { + imageFile = new ImageFile; + img = imageFile; + if (!img->open(image_fname)) { + SETERR(("Failed to open image file %s: %s", image_fname, img->err())); + } + } + + // + // Parse and perform commands + // + switch (cmd) { + case CMD_VERIFY: + if (!op.CheckFullImage(*img, img->GetPrimaryEeprom(), img->GetSecondaryEeprom())) { + SETERR(("Image check failed: %s", op.err())); + } + break; + + case CMD_QUERY: + if (!op.QueryImage(*img, img->GetPrimaryEeprom() , img->GetSecondaryEeprom() )) { + SETERR(("Image query failed: %s", op.err())); + } + break; + + case CMD_BURN_BLOCK: + + if (!op.RawBurn(*eeprom, *imageFile)) { + SETERR(("Image check failed: %s", op.err())); + } + + if (!op.CompareContent(*eeprom, *imageFile)) { + SETERR(("Image check failed: %s", op.err())); + } + + break; + + case CMD_READ_IMAGE: + { + + NEXTC("ri" , "output image file"); + const char* outFile = av[i]; + + if (!eeprom) { + SETERR(("A device should be given for ri command\n")); + } + + if (!op.DumpImage(*eeprom, eeprom->GetPrimaryEeprom(), eeprom->GetSecondaryEeprom(), outFile)) { + SETERR((op.err())); + } + } + break; + + case CMD_READ_BLOCK: + { + // rb + u_int32_t args[3]; + char* argNames[3] = {"i2c slave", "offset", "size"}; + + for (int argIdx = 0; argIdx < 3 ; argIdx++ ) { + char* ep; + NEXTC("rb" , argNames[argIdx]); + args[argIdx] = strtoul(av[i], &ep, 16); + if (*ep) { + SETERR(("Bad argument #%d (%s) for rb command (%s). Expecting a hexadecimal integer.", + argIdx, + argNames[argIdx], + av[i])); + } + } + + NEXTC("rb" , "output image file"); + const char* outFile = av[i]; + + if (!op.ReadBlock (*eeprom, (u_int8_t) args[0], args[1], args[2], outFile)) { + SETERR((op.err())); + } + } + break; + + case CMD_BURN: + + // Get user 'setable' fields + if (userNodeGuid) { + if (!op.GetFieldFromString(userFields, Operations::NODE_GUID_ID, userNodeGuid)) { + SETERR((op.err())); + } + } + + if (userSysGuid) { + if (!op.GetFieldFromString(userFields, Operations::SYS_GUID_ID, userSysGuid)) { + SETERR((op.err())); + } + } + + if (userBsn) { + if (!op.GetFieldFromString(userFields, Operations::BSN_ID, userBsn)) { + SETERR((op.err())); + } + } + + if (userNodeDesc) { + if (!op.GetFieldFromString(userFields, Operations::NODE_DESC_ID , userNodeDesc)) { + SETERR((op.err())); + } + } + + + if (!op.IS3FwBurn(*eeprom, *imageFile, userFields, fsBurn)) { + SETERR(("%sBurn failed: %s\n", + fsBurn ? "Failsafe " : "" , + op.err())); + } + break; + + default: + SETERR(("Internal error: Unknown command %d given. See help for details.\n", cmd)); + } + + return 0; +} + diff --git a/trunk/tools/spark/user/spark.rc b/trunk/tools/spark/user/spark.rc new file mode 100644 index 00000000..57b6fbb0 --- /dev/null +++ b/trunk/tools/spark/user/spark.rc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under the OpenIB.org BSD license + * below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: mst.rc 219 2005-07-27 10:15:27Z sleybo $ + */ + + +#include + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN + +#if DBG +#define VER_FILEDESCRIPTION_STR "Mellanox Switches FW burning tool. (Debug)" +#else +#define VER_FILEDESCRIPTION_STR "Mellanox Switches FW burning tool." +#endif + +#define VER_INTERNALNAME_STR "spark.exe" +#define VER_ORIGINALFILENAME_STR "spark.exe" + +#include