coinstaller \\r
fwupdate \\r
wsdinstall \\r
- vstat\r
+ vstat \\r
+ mtcr \\r
+ flint \\r
+ mread \\r
+ mwrite \\r
+ mst \\r
+ spark \\r
--- /dev/null
+DIRS=\
+ user
--- /dev/null
+TARGETNAME=flint\r
+TARGETTYPE=PROGRAM\r
+UMTYPE=console\r
+USE_CRTDLL=1\r
+USE_NTDLL=1\r
+\r
+\r
+!if !defined(WINIBHOME)\r
+WINIBHOME=..\..\..\r
+!endif\r
+\r
+TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR)\r
+\r
+\r
+\r
+ZLIB=$(WINIBHOME)\tools\ext_libs\user\zlib-1.1.4\r
+\r
+\r
+SOURCES=flint.rc \\r
+ flint.cpp\r
+\r
+\r
+INCLUDES= $(WINIBHOME)\inc; \\r
+ $(WINIBHOME)\inc\user; \\r
+ $(WINIBHOME)\inc\iba; \\r
+ $(WINIBHOME)\tools\mtcr\user; \\r
+ $(ZLIB)\include;\r
+\r
+TARGETLIBS= \\r
+!if $(FREEBUILD)\r
+ $(CRT_LIB_PATH)\msvcrt.lib \\r
+ $(SDK_LIB_PATH)\Ws2_32.lib\\r
+ $(TARGETPATH)\*\mtcr.lib\r
+!else\r
+ $(CRT_LIB_PATH)\msvcrtd.lib\\r
+ $(SDK_LIB_PATH)\Ws2_32.lib\\r
+ $(TARGETPATH)\*\mtcr.lib\r
+!endif\r
+\r
+USER_C_FLAGS=$(USER_C_FLAGS) /Ze /EHsc\r
+\r
+# TODO:Should I define the __WIN__ manually\r
+C_DEFINES=$(C_DEFINES) -D__WIN__ -DZEXPORT=__cdecl\r
+\r
+C_DEFINES=$(C_DEFINES) -DNO_ZLIB\r
+\r
+\r
+!if $(FREEBUILD)\r
+\r
+!else\r
+C_DEFINES=$(C_DEFINES) -DDEBUG\r
+!endif\r
+\r
+# Version:\r
+!if !defined(MFT_BLD_VER)\r
+MFT_BLD_VER=Devel\r
+!endif\r
+C_DEFINES=$(C_DEFINES) "-DVERSION_ID=$(MFT_BLD_VER)"\r
+\r
+386_STDCALL=0\r
+\r
+MSC_WARNING_LEVEL= /W3\r
+\r
--- /dev/null
+/*
+ *
+ * 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 <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#ifndef NO_ZLIB
+#include <zlib.h>
+#endif
+
+#include <signal.h>
+
+#ifndef __WIN__
+
+//
+// Linux
+//
+
+#include <byteswap.h>
+#include <endian.h>
+#include <alloca.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#else // __WIN__
+
+//
+// Windows (Under DDK)
+//
+
+#include <io.h>
+#include <Winsock2.h>
+
+// 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 <memory>
+#include <vector>
+
+#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<sizeof(s)/sizeof(u_int32_t); ii++,p++) \
+ *p = __be32_to_cpu(*p); \
+ } while(0)
+#define TOCPUn(s, n) do { \
+ u_int32_t *p = (u_int32_t *)(s); \
+ for (u_int32_t ii=0; ii<(n); ii++,p++) \
+ *p = __be32_to_cpu(*p); \
+ } while(0)
+#define TOCPUBY(s) do { \
+ u_int32_t *p = (u_int32_t *)(&s); \
+ for (u_int32_t ii=0; ii<sizeof(s)/sizeof(u_int32_t); ii++,p++) \
+ *p = __be32_to_cpu(*p); \
+ } while(0)
+#define TOCPUBY64(s) do { \
+ guid_t *p = s; \
+ for (unsigned ii=0; ii<sizeof(s)/sizeof(guid_t); ii++,p++) \
+ be_guid_to_cpu(p,p); \
+ } while(0)
+#define CRC(c, s) do { \
+ u_int32_t *p = (u_int32_t *)(s); \
+ for (u_int32_t ii=0; ii<sizeof(s)/sizeof(u_int32_t); ii++) \
+ c << *p++; \
+ } while(0)
+#define CRCn(c, s, n) do { \
+ u_int32_t *p = (u_int32_t *)(s); \
+ for (u_int32_t ii=0; ii<(n); ii++) \
+ c << *p++; \
+ } while(0)
+#define CRCBY(c, s) do { \
+ u_int32_t *p = (u_int32_t *)(&s); \
+ for (u_int32_t ii=0; ii<sizeof(s)/sizeof(u_int32_t); ii++) \
+ c << *p++; \
+ } while(0)
+#define CRC1(c, s) do { \
+ u_int32_t *p = (u_int32_t *)(s); \
+ for (u_int32_t ii=0; ii<sizeof(s)/sizeof(u_int32_t) - 1; ii++) \
+ c << *p++; \
+ } while(0)
+#define CRC1n(c, s, n) do { \
+ u_int32_t *p = (u_int32_t *)(s); \
+ for (u_int32_t ii=0; ii<(n) - 1; ii++) \
+ c << *p++; \
+ } while(0)
+#define CRC1BY(c, s) do { \
+ u_int32_t *p = (u_int32_t *)(&s); \
+ for (u_int32_t ii=0; ii<sizeof(s)/sizeof(u_int32_t) - 1; ii++) \
+ c << *p++; \
+ } while(0)
+#define CHECKB2(f,b,o,n,p) do { if (!checkBoot2(f,b,o,n,p)) return false; } while (0)
+#define CHECKGN(f,b,o,n,p) do { if (!checkGen(f,b,o,n,p)) return false; } while (0)
+#define CHECKLS(f,o,p) do { if (!checkList(f,o,p)) return false; } while(0)
+#define READ4(f,o,d,p) do { if (!f.read(o,d)) { \
+ return errmsg("%s - read error (%s)\n", p, f.err()); }} while (0)
+#define READBUF(f,o,d,l,p) do { if (!f.read(o,d,l)) { \
+ return errmsg("%s - read error (%s)\n", p, f.err()); }} while (0)
+
+#if 1
+
+ #define MWRITE4(offs,val) do { \
+ if (mwrite4(_mf, offs, val) != 4) return false; } while (0)
+ #define MREAD4(offs,val) do { \
+ if (mread4(_mf, offs, val) != 4) return false; } while (0)
+
+#else
+
+ #define MWRITE4(offs,val) do { \
+ printf("%08x <- %08x\n", (u_int32_t)offs, (u_int32_t)val); \
+ if (mwrite4(_mf, offs, val) != 4) return false; } while (0)
+ #define MREAD4(offs,val) do { \
+ if (mread4(_mf, offs, val) != 4) return false; \
+ printf("%08x -> %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; i<len/4; i++) {
+ p[i] = _buf[addr/4];
+ addr += 4;
+ }
+ return true;
+} // FImage::read
+
+////////////////////////////////////////////////////////////////////////
+u_int32_t FImage::get_sector_size()
+{
+ u_int32_t log2_sector_sz_ptr;
+ u_int32_t log2_sector_sz;
+ u_int32_t signature;
+
+ read(0x24, &signature);
+ TOCPU1(signature);
+ if (signature == SIGNATURE) {
+ // full image:
+ read(0x14, &log2_sector_sz_ptr);
+ TOCPU1(log2_sector_sz_ptr);
+ log2_sector_sz_ptr &= 0xffff;
+
+ read(0x30 + log2_sector_sz_ptr, &log2_sector_sz);
+ TOCPU1(log2_sector_sz);
+ log2_sector_sz &= 0xffff;
+
+ return(1 << log2_sector_sz);
+
+ } else {
+ return 0;
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Flash Class Implementation
+//
+////////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////////
+bool Flash::open(const char *device, bool force_lock, bool read_only)
+{
+
+ // Open device
+ _mf = mopen(device);
+ if (!_mf) {
+ return errmsg("Can't open device %s: %s", device, strerror(errno));
+ }
+
+ _locked = lock();
+
+ if (!_locked) {
+ if (force_lock) {
+ report("Warning: Taking flash lock even though semaphore is set.\n");
+ _locked = true;
+ } else {
+ return false;
+ }
+ }
+
+ if (!init_gpios())
+ return false;
+
+ if (!read_only) {
+ if (!get_cmd_set())
+ return false;
+
+ // Reset flash
+ return _cmd_set->reset();
+ }
+
+ 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 <device>\" 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<len/4; i++) {
+ if (!read(addr, p++))
+ return false;
+ addr += 4;
+
+ // Report
+ if (verbose) {
+ u_int32_t new_perc = (i * 100) / len;
+ if (new_perc != perc) {
+ printf("\b\b\b\b%03d%%", new_perc);
+ fflush(stdout);
+ perc = new_perc;
+ }
+ }
+ }
+
+ // Report
+ if (verbose) {
+ printf("\b\b\b\b100%%");
+ fflush(stdout);
+ }
+
+ return true;
+} // Flash::read
+
+
+////////////////////////////////////////////////////////////////////////
+bool Flash::write (u_int32_t addr,
+ void* data,
+ int cnt,
+ bool noerase,
+ bool noverify)
+{
+ if (addr + cnt > 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<u_int32_t> 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; i<q->num_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<cnt; i++,addr++) {
+ u_int32_t word;
+ u_int8_t act, exp;
+ int cnt1 = 0;
+
+ 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 we're in unlock mode, we must re-lock before erase sector
+ if (_unlock_bypass) {
+ if (!unlock_bypass(false)) {
+ return _f.errmsg("Failed re-lock bypass");
+ }
+ }
+
+
+ if (!erase_sector(_curr_sector))
+ return false;
+
+
+ if (_unlock_bypass) {
+ if (!unlock_bypass(true)) {
+ return _f.errmsg("Failed unlock bypass");
+ }
+ }
+ }
+ }
+
+ if (_no_burn)
+ continue;
+
+ if (_f._use_scr) {
+
+ //
+ // Special burning interface via Scratchpad
+ // ----------------------------------------
+ //
+ u_int32_t cmd;
+ u_int32_t data = (*p++ & 0xff) << 24;
+ data |= (*p++ & 0xff) << 16;
+ data |= (*p++ & 0xff) << 8;
+ data |= (*p++ & 0xff);
+ if (mwrite4(_f._mf, _f.USE_SCR+4 , data) != 4) return false;
+ if (mwrite4(_f._mf, _f.USE_SCR , WRITE1 | (3 << LEN_SHIFT) | (addr & ADDR_MSK)) != 4) return false;
+ do {
+ int loop_cnt = 0;
+ // Timeout checks
+ if (++loop_cnt > 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<cnt; i++,addr++) {
+ u_int32_t status;
+ u_int8_t act, exp;
+ int cnt1 = 0;
+
+ 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;
+
+ if ((u_int8_t)(*p) != 0xff) {
+ // Write byte
+ if (!_f.write_internal(addr, FC_Write))
+ 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 - 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<u_int8_t> _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<u_int32_t> 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<u_int8_t>::iterator((u_int8_t*)buff),
+ vector<u_int8_t>::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<u_int8_t> 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; i<ind/4; i++) {
+ word = __be32_to_cpu(buf[i]);
+ crc << word;
+ }
+ for (i=0; i<(u_int32_t)nguids*2; i++)
+ crc << new_buf[i];
+
+ // Patch GUIDs
+ for (i=0; i<sizeof(new_buf)/sizeof(u_int32_t); ++i) {
+ new_buf[i] = __cpu_to_be32(new_buf[i]);
+ }
+ memcpy(&buf[ind/4], &new_buf[0], nguids * 2 * sizeof(u_int32_t));
+
+ // Insert new CRC
+ crc.finish();
+ word = crc.get();
+ buf[ind/4 + nguids*2] = __cpu_to_be32(word);
+} // patchGUIDsSection
+
+
+////////////////////////////////////////////////////////////////////////
+void Operations::_patchVSD(FImage& f, int ind, char *vsd)
+{
+ u_int32_t *buf = f.getBuf();
+ Crc16 crc;
+ PS *ps = (PS*)&buf[ind/4];
+
+ memcpy(&ps->vsd[0], vsd, VSD_LEN + PSID_LEN);
+
+ u_int32_t *qp = (u_int32_t *)ps;
+ for (unsigned int i=0; i<sizeof(PS)/sizeof(u_int32_t) - 1; i++) {
+ u_int32_t qq = *qp++;
+ TOCPU1(qq);
+ crc << qq;
+ }
+ crc.finish();
+ u_int32_t crc016 = crc.get();
+ ps->crc016 = __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; i<fix_end/4; i++) {
+ *qp = bswap_32(*qp);
+ qp++;
+ }
+
+ if (imageAddr) {
+ ps->fi_addr = __cpu_to_be32(imageAddr);
+ }
+
+ qp = (u_int32_t *)ps;
+ for (unsigned int i=0; i<sizeof(PS)/sizeof(u_int32_t) - 1; i++) {
+ u_int32_t qq = *qp++;
+ TOCPU1(qq);
+ crc << qq;
+ }
+ crc.finish();
+ u_int32_t crc016 = crc.get();
+ ps->crc016 = __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<GUIDS; i++) {
+ u_int32_t h = buf[ind1/4 + i*2];
+ TOCPU1(h);
+ u_int32_t l = buf[ind1/4 + i*2 + 1];
+ TOCPU1(l);
+ image_file_guids[i].h = h;
+ image_file_guids[i].l = l;
+ }
+ if (image_file_old_guids_fmt)
+ printf(" Old image!!!! Only %d GUIDs may be set.\n", nguid1);
+ if (old_guids) {
+ printf(" Current GUIDs are:\n");
+ printf(" Node: " GUID_FORMAT "\n", old_guids[0].h,old_guids[0].l);
+ printf(" Port1: " GUID_FORMAT "\n", old_guids[1].h,old_guids[1].l);
+ if (_num_ports > 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...] <command> [parameters...]\n"
+ "\n"
+ "\n"
+ "Switches summary:\n"
+ "-----------------\n"
+ " -bsn <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> - Device flash is connected to.\n"
+ " Commands affected: all\n"
+ "\n"
+ " -guid <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 <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] <image> - 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 <string> - Write this string, of up to 208 characters, to VSD when burn.\n"
+ "\n"
+ " -psid <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<Flash> 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<Operations::GUIDS; i++) {
+ u_int64_t g=user_guids[0].h;
+ g=(g<<32) | user_guids[0].l;
+ g += i;
+ user_guids[i].h = (u_int32_t)(g>>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<Operations::GUIDS; i++) {
+ u_int64_t g=user_guids[0].h;
+ g=(g<<32) | user_guids[0].l;
+ g += i;
+ user_guids[i].h = (u_int32_t)(g>>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<Operations::GUIDS; j++) {
+ GETGUID(av[i], &user_guids[j]);
+ if (++i >= 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<Flash> 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 <ADDR>
+ // Parameters: <ADDR>
+ //
+ u_int32_t addr;
+ char *endp;
+
+ // Address of sector to erase
+ NEXTC("<ADDR>", "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: <ADDR> <LENGTH> [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("<ADDR>", "rb");
+ addr = strtoul(av[i], &endp, 0);
+ if (*endp) {
+ printf("Invalid address \"%s\"\n", av[i]);
+ rc = 1; goto done;
+ }
+ NEXTC("<LENGTH>", "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("<OUT_FILENAME>", "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 <ADDR>
+ // Parameters: <ADDR>
+ u_int32_t data, addr;
+ char *endp;
+
+ // Address
+ NEXTC("<ADDR>", "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("<OUT_FILENAME>", "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("<OUT_FILENAME>", "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: <IN_FILENAME> <ADDR>
+ 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("<IN_FILENAME>", "wb");
+
+ fname = av[i];
+
+ // Address
+ NEXTC("<ADDR>", "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: <ADDR> <DATA>
+ u_int32_t data, addr;
+ char *endp;
+
+ // Address and data
+ NEXTC("<ADDR>", "ww");
+ addr = strtoul(av[i], &endp, 0);
+ if (*endp) {
+ printf("Invalid address \"%s\"\n", av[i]);
+ rc = 1; goto done;
+ }
+ NEXTC("<DATA>", "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: <ADDR> <SIZE> <DATA>
+ u_int32_t size, addr;
+ char *endp;
+
+ // Address and data
+ NEXTC("<ADDR>", "wbne");
+ addr = strtoul(av[i], &endp, 0);
+ if (*endp) {
+ printf("Invalid address \"%s\"\n", av[i]);
+ rc = 1; goto done;
+ }
+ NEXTC("<SIZE>", "wbne");
+ size = strtoul(av[i], &endp, 0);
+ if (*endp || size % 4) {
+ printf("Invalid size \"%s\"\n", av[i]);
+ rc = 1; goto done;
+ }
+ vector<u_int32_t> data_vec(size/4);
+ for (u_int32_t w = 0; w < size/4 ; w++) {
+ NEXTC("<DATA>", "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: <ADDR> <DATA>
+ u_int32_t data, addr;
+ char *endp;
+
+ // Address and data
+ NEXTC("<ADDR>", "wwne");
+ addr = strtoul(av[i], &endp, 0);
+ if (*endp) {
+ printf("Invalid address \"%s\"\n", av[i]);
+ rc = 1; goto done;
+ }
+ NEXTC("<DATA>", "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;
+}
+
--- /dev/null
+/*\r
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id: mst.rc 219 2005-07-27 10:15:27Z sleybo $\r
+ */\r
+\r
+\r
+#include <oib_ver.h>\r
+\r
+#define VER_FILETYPE VFT_APP\r
+#define VER_FILESUBTYPE VFT2_UNKNOWN\r
+\r
+#if DBG\r
+#define VER_FILEDESCRIPTION_STR "Mellanox HCAs FW burning tool. (Debug)"\r
+#else\r
+#define VER_FILEDESCRIPTION_STR "Mellanox HCAs FW burning tool."\r
+#endif\r
+\r
+#define VER_INTERNALNAME_STR "flint.exe"\r
+#define VER_ORIGINALFILENAME_STR "flint.exe"\r
+\r
+#include <common.ver>\r
--- /dev/null
+#\r
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source\r
+# file to this component. This file merely indirects to the real make file\r
+# that is shared by all the driver components of the Windows NT DDK\r
+#\r
+\r
+!INCLUDE ..\..\..\inc\openib.def\r
--- /dev/null
+TARGETNAME=mread\r
+TARGETTYPE=PROGRAM\r
+UMTYPE=console\r
+USE_CRTDLL=1\r
+\r
+\r
+!if !defined(WINIBHOME)\r
+WINIBHOME=..\..\..\r
+!endif\r
+\r
+TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR)\r
+\r
+\r
+\r
+SOURCES=mread.c \\r
+ mread.rc\r
+\r
+INCLUDES= $(WINIBHOME)\inc; \\r
+ $(WINIBHOME)\inc\user; \\r
+ $(WINIBHOME)\inc\iba; \\r
+ $(WINIBHOME)\tools\mtcr\user;\r
+\r
+TARGETLIBS= \\r
+!if $(FREEBUILD)\r
+ $(TARGETPATH)\*\mtcr.lib\r
+!else\r
+ $(TARGETPATH)\*\mtcr.lib\r
+!endif\r
+\r
+!if $(FREEBUILD)\r
+\r
+!else\r
+C_DEFINES=$(C_DEFINES) -DDEBUG\r
+!endif\r
+\r
+C_DEFINES=$(C_DEFINES) -D__WIN__\r
+\r
+386_STDCALL=0\r
+\r
+\r
--- /dev/null
+#\r
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source\r
+# file to this component. This file merely indirects to the real make file\r
+# that is shared by all the driver components of the Windows NT DDK\r
+#\r
+\r
+!INCLUDE ..\..\..\inc\openib.def\r
+\r
--- /dev/null
+/*
+ *
+ * mread.c - CR Space read access
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mtcr.h"
+
+void usage(const char *n)
+{
+ printf("%s <device> <addr> [<i2c_slave>]\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<rc1; i++)
+ {
+ printf("Found: \"%s\"\n", p);
+ p += strlen(p)+1;
+ }
+ exit(0);
+#endif
+
+ if (ac < 3)
+ usage(av[0]);
+ addr = strtoul(av[2], &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 >= 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;
+}
--- /dev/null
+DIRS=\
+ user
--- /dev/null
+TARGETNAME=mst\r
+TARGETTYPE=PROGRAM\r
+UMTYPE=console\r
+USE_CRTDLL=1\r
+\r
+\r
+!if !defined(WINIBHOME)\r
+WINIBHOME=..\..\..\r
+!endif\r
+\r
+TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR)\r
+\r
+\r
+\r
+SOURCES=mst.c \\r
+ mst.rc\r
+\r
+\r
+INCLUDES= $(WINIBHOME)\inc; \\r
+ $(WINIBHOME)\inc\user; \\r
+ $(WINIBHOME)\inc\iba; \\r
+ $(WINIBHOME)\tools\mtcr\user;\r
+\r
+TARGETLIBS= \\r
+!if $(FREEBUILD)\r
+ $(TARGETPATH)\*\mtcr.lib\r
+!else\r
+ $(TARGETPATH)\*\mtcr.lib\r
+!endif\r
+\r
+!if $(FREEBUILD)\r
+\r
+!else\r
+C_DEFINES=$(C_DEFINES) -DDEBUG\r
+!endif\r
+\r
+C_DEFINES=$(C_DEFINES) -D__WIN__\r
+\r
+386_STDCALL=0\r
+\r
+\r
--- /dev/null
+#\r
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source\r
+# file to this component. This file merely indirects to the real make file\r
+# that is shared by all the driver components of the Windows NT DDK\r
+#\r
+\r
+!INCLUDE ..\..\..\inc\openib.def\r
+\r
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}
+
--- /dev/null
+/*\r
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id: mst.rc 219 2005-07-27 10:15:27Z sleybo $\r
+ */\r
+\r
+\r
+#include <oib_ver.h>\r
+\r
+#define VER_FILETYPE VFT_APP\r
+#define VER_FILESUBTYPE VFT2_UNKNOWN\r
+\r
+#if DBG\r
+#define VER_FILEDESCRIPTION_STR "Mellanox HW access device listing. (Debug)"\r
+#else\r
+#define VER_FILEDESCRIPTION_STR "Mellanox HW access device listing."\r
+#endif\r
+\r
+#define VER_INTERNALNAME_STR "mst.exe"\r
+#define VER_ORIGINALFILENAME_STR "mst.exe"\r
+\r
+#include <common.ver>\r
--- /dev/null
+DIRS=\
+ user
--- /dev/null
+#\r
+# Name: sources\r
+#\r
+# Purpose:\r
+# Building MTCR for this platform (user space)\r
+#\r
+\r
+TARGETTYPE=DYNLINK\r
+TARGETNAME=mtcr\r
+DLLENTRY=_DllMainCRTStartup\r
+DLLDEF=mtcr.def\r
+USE_CRTDLL=1\r
+\r
+!if !defined(WINIBHOME)\r
+WINIBHOME=..\..\..\r
+!endif\r
+\r
+LIBPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR)\r
+\r
+TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR)\r
+\r
+\r
+INCLUDES= $(WINIBHOME)\inc; \\r
+ $(WINIBHOME)\inc\user; \\r
+ $(WINIBHOME)\inc\iba; \\r
+ .\usb;\r
+ \r
+\r
+SOURCES= \\r
+ mtcr.rc \\r
+ mtcr_i2c.c \\r
+ mtcr.c \\r
+ usb.cpp\r
+ \r
+\r
+TARGETLIBS= \\r
+!if $(FREEBUILD)\r
+ $(TARGETPATH)\*\complib.lib \\r
+ $(CRT_LIB_PATH)\msvcrt.lib \\r
+ $(TARGETPATH)\*\ibal.lib\\r
+ $(SDK_LIB_PATH)\Kernel32.lib\\r
+!else\r
+ $(TARGETPATH)\*\complibd.lib\\r
+ $(CRT_LIB_PATH)\msvcrt.lib\\r
+ $(TARGETPATH)\*\ibald.lib\\r
+ $(SDK_LIB_PATH)\Ws2_32.lib\\r
+ $(SDK_LIB_PATH)\Kernel32.lib\\r
+\r
+!endif\r
+\r
+\r
+# dimax driver not provided for 64 bits arch.\r
+MTCR_NO_USB=1\r
+\r
+\r
+!if !defined(MTCR_NO_USB)\r
+TARGETLIBS=$(TARGETLIBS)\\r
+ .\usb\usbi2cio.lib \\r
+ .\usb\I2cBrdg.lib\r
+ \r
+C_DEFINES=$(C_DEFINES) -DMTCR_USB_SUPPORT\r
+!endif\r
+\r
+\r
+\r
+\r
+# TODO:Should I define the __WIN__ manually\r
+C_DEFINES=$(C_DEFINES) /DMTCR_EXPORTS /DMTL_MODULE=MTCR -D__WIN__ \r
+\r
+\r
+!if $(FREEBUILD)\r
+\r
+!else\r
+C_DEFINES=$(C_DEFINES) -DDEBUG -DDBG\r
+!endif\r
+\r
+\r
+# This is for the perl and zlib lib funcs, which requires __cdecl.\r
+# TODO: define for all arch. check if MSC_STDCALL works.\r
+386_STDCALL=0\r
+amd64_STDCALL=0\r
+\r
+MSC_WARNING_LEVEL= /W3\r
+\r
+#BUILD_CONSUMES=mlxsys\r
+BUILD_PRODUCES=mtcr\r
+\r
--- /dev/null
+/* - 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 <io.h>
+#include <windows.h>
+
+
+#include <windows.h>
+
+// TODO: reference additional headers your program requires here
+#include <stdio.h>
+#include <stdlib.h>
+
+
+//-----------------------------------------------------
+// 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 <stdio.h>
+ #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 <errno.h>
+
+ /****************** 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
--- /dev/null
+#\r
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source\r
+# file to this component. This file merely indirects to the real make file\r
+# that is shared by all the driver components of the Windows NT DDK\r
+#\r
+\r
+!INCLUDE ..\..\..\inc\openib.def\r
+\r
--- /dev/null
+// mtcr.c : Defines the entry point for the DLL application.\r
+//\r
+#include <stdlib.h>\r
+#include <errno.h>\r
+#include <ib_types.h>\r
+#include <ib_al.h>\r
+\r
+\r
+#include "com_def.h"\r
+#include "usb.h"\r
+#include "mtcr.h"\r
+#include "mtcr_i2c.h"\r
+\r
+//-----------------------------------------------------\r
+// NEW FEATURES\r
+//-----------------------------------------------------\r
+#define FIX_NAME 1\r
+#define SUPPORT_I2CM 1\r
+\r
+#define USB_DEV_NAME "mtusb-1"\r
+#define CLEAR(st) memset(&(st), 0, sizeof(st))\r
+\r
+\r
+\r
+#define MTCR_DEBUG_ENV "MTCR_DEBUG_LEVEL"\r
+#ifdef DBG\r
+ULONG g_DebugLevel = DEBUG_LEVEL_MID;\r
+#else\r
+ULONG g_DebugLevel = DEBUG_LEVEL_LOW;\r
+#endif\r
+\r
+//-----------------------------------------------------\r
+\r
+\r
+\r
+\r
+// Copied from : #include <ib_al.h>\r
+/* Definitions intended to become shared with UM. Later... */\r
+\r
+typedef\r
+struct _map_crspace {\r
+ PVOID va; /* address of CRSPACE, mapped to user space */\r
+ PVOID ctx; /* opaque operation context; to be used in FW_UNMAP_CRSPACE */\r
+ ULONG size; /* size of CRSPACE, mapped to user space */\r
+} map_crspace;\r
+\r
+typedef\r
+struct _unmap_crspace {\r
+ PVOID va; /* address of CRSPACE, mapped to user space */\r
+ PVOID ctx; /* operation context, received in FW_MAP_CRSPACE */\r
+} unmap_crspace;\r
+\r
+\r
+/* Definitions for hca_driver commands*/\r
+#define FW_READ 0x00\r
+#define FW_WRITE 0x01\r
+#define FW_READ_CMD 0x08\r
+#define FW_WRITE_CMD 0x09\r
+#define FW_MAP_CRSPACE 0x0A\r
+#define FW_UNMAP_CRSPACE 0x0B\r
+#define FW_OPEN_IF 0xe7\r
+#define FW_CLOSE_IF 0x7e\r
+\r
+\r
+#define MAX_HCA_NUM 16\r
+\r
+\r
+typedef struct mfile_ibal_t {\r
+ mfile s;\r
+ ib_al_handle_t h_al; \r
+ ib_ca_handle_t h_ca;\r
+ map_crspace cr_map;\r
+} mfile_ibal;\r
+\r
+\r
+BOOL APIENTRY DllMain( HANDLE hModule,\r
+ DWORD ul_reason_for_call,\r
+ LPVOID lpReserved\r
+ )\r
+{\r
+ char* pszDbgLevel;\r
+ switch (ul_reason_for_call)\r
+ {\r
+ case DLL_PROCESS_ATTACH:\r
+ // s_hCtl = (HANDLE)-1;\r
+ // ConnectToDriver();\r
+ g_DebugLevel = 0;\r
+ pszDbgLevel = getenv(MTCR_DEBUG_ENV);\r
+ if (pszDbgLevel) {\r
+ g_DebugLevel = atol(pszDbgLevel);\r
+ }\r
+\r
+ break;\r
+ \r
+ case DLL_PROCESS_DETACH:\r
+ // DisconnectFromDriver();\r
+ break;\r
+ \r
+ case DLL_THREAD_ATTACH:\r
+ case DLL_THREAD_DETACH:\r
+ break;\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+// device ids\r
+#define DEVASYS_DEV_ID 12345 /* dummy */\r
+#define TAVOR_DEV_ID 23108\r
+#define TAVOR_CONF_DEV_ID 23109\r
+#define ARBEL_TM_DEV_ID 25208\r
+#define ARBEL_TM_CONF_DEV_ID 25209\r
+#define ARBEL_DEV_ID 25218\r
+#define ARBEL_CONF_DEV_ID 25219\r
+#define SINAI_4X_DEV_ID 24204\r
+#define SINAI_4X_CONF_DEV_ID 24205\r
+#define SINAI_8X_DEV_ID 25204\r
+#define SINAI_8X_CONF_DEV_ID 25205\r
+\r
+#define IS_CONF_DEV(dev_id) \\r
+ ((dev_id == TAVOR_CONF_DEV_ID) || \\r
+ (dev_id == ARBEL_TM_CONF_DEV_ID) || \\r
+ (dev_id == ARBEL_CONF_DEV_ID) || \\r
+ (dev_id == SINAI_4X_CONF_DEV_ID) || \\r
+ (dev_id == SINAI_8X_CONF_DEV_ID))\r
+ \r
+#define MAX_DEV_NAME 32\r
+typedef struct {\r
+ USHORT DevId; // Device Id, e.g. 23108 \r
+ UCHAR DevName[MAX_DEV_NAME]; // exported name, e.g. "InfiniHost"\r
+ Mdevs mask;\r
+} DEVICE_DB_T, *PDEVICE_DB_T;\r
+\r
+\r
+#define TAVOR_TYPE_DEVICE_NAME_FMT "mt%hu_pci%s%hu"\r
+#define MDT_DEVICE_NAME_FMT "%s%hu"\r
+\r
+static DEVICE_DB_T db[] = {\r
+ { DEVASYS_DEV_ID, "devasys_usb", MDEVS_TAVOR },\r
+ { TAVOR_DEV_ID, "InfiniHost", MDEVS_TAVOR },\r
+ { TAVOR_CONF_DEV_ID, "InfiniHostBd", MDEVS_TAVOR_CR },\r
+ { ARBEL_TM_DEV_ID, "InfiniHost", MDEVS_TAVOR },\r
+ { ARBEL_TM_CONF_DEV_ID, "InfiniHostBd", MDEVS_TAVOR_CR },\r
+ { ARBEL_DEV_ID, "InfiniHost_III_Ex", MDEVS_TAVOR },\r
+ { ARBEL_CONF_DEV_ID, "InfiniHostBd", MDEVS_TAVOR_CR },\r
+ { SINAI_4X_DEV_ID, "InfiniHost_III_Lx", MDEVS_TAVOR },\r
+ { SINAI_4X_CONF_DEV_ID, "InfiniHostBd", MDEVS_TAVOR_CR },\r
+ { SINAI_8X_DEV_ID, "InfiniHost_III_Lx", MDEVS_TAVOR },\r
+ { SINAI_8X_CONF_DEV_ID, "InfiniHostBd", MDEVS_TAVOR_CR },\r
+};\r
+#define DEVICE_DB_SIZE (sizeof(db) / sizeof(DEVICE_DB_T))\r
+\r
+Mdevs dmasks[] = { MDEVS_TAVOR_CR, MDEVS_TAVOR_CR, MDEVS_TAVOR_UAR, MDEVS_TAVOR_DDR };\r
+char *dsuffix[] = { "conf", "_cr", "_uar", "_ddr"};\r
+#define MASKS_SIZE (sizeof(dmasks) / sizeof(Mdevs))\r
+\r
+\r
+// Return: < 0 - Error. > 0 - Numbern of characters written (including last '\0')\r
+int create_mst_names_by_dev_id(USHORT dev_id, int dev_ix, int mask, char *name, int name_len, int *cnt)\r
+{\r
+ int i,j; char *suffix; BOOL found = FALSE; char *nm_ptr = name;\r
+ int tot_len = 0;\r
+\r
+ DPRINT3(( "create_mst_names_by_dev_id: dev_id %d, dev_ix %d, mask %#x, name_len %d\n", \r
+ dev_id, dev_ix, mask, name_len ));\r
+ \r
+ // specific stuff: for CONF devices create only "_cr" device\r
+ *name = 0;\r
+ *cnt = 0;\r
+ if (IS_CONF_DEV(dev_id)) {\r
+ int len;\r
+ tot_len += _snprintf(name, name_len, TAVOR_TYPE_DEVICE_NAME_FMT, dev_id, "conf", dev_ix );\r
+ tot_len++; // trailing null\r
+ *cnt = 1;\r
+ return tot_len;\r
+ }\r
+ DPRINT3(( "create_mst_names_by_dev_id: not conf device %hu, is_conf_dev %d \n", \r
+ dev_id, IS_CONF_DEV(dev_id) ));\r
+ \r
+ // find device\r
+ for (i=0; i<DEVICE_DB_SIZE; i++) {\r
+ if ((db[i].DevId == dev_id) && (db[i].mask & mask)) {\r
+ found = TRUE;\r
+ break;\r
+ }\r
+ }\r
+ if (!found) {\r
+ DPRINT1(( "create_mst_names_by_dev_id: device %hu, mask %#x not found \n", \r
+ dev_id, mask ));\r
+ return -1;\r
+ }\r
+ \r
+ // names generation\r
+ for (j=0; j<MASKS_SIZE; j++) {\r\r
+ if ((db[i].mask & mask) & dmasks[j]) {\r
+ char l_name[MAX_DEV_NAME]; int len; \r
+ // create one name\r
+ len = _snprintf(l_name, sizeof(l_name), TAVOR_TYPE_DEVICE_NAME_FMT, dev_id, dsuffix[j], dev_ix );\r
+ len++;\r
+ // check whether we have enough place\r
+ if (len > name_len) {\r
+ DPRINT1(( "create_mst_names_by_dev_id: not enough length (%d > %d)\n", \r
+ len, name_len ));\r
+ return -1; \r
+ }\r
+ // copy the results\r
+ DPRINT5(( "create_mst_names_by_dev_id: name %s\n", \r
+ l_name ));\r
+ memcpy( nm_ptr, l_name, len );\r
+ nm_ptr += len;\r
+ tot_len += len;\r
+ name_len -= len;\r
+ (*cnt)++;\r
+ }\r
+ }\r
+ \r
+ return tot_len;\r
+}\r
+\r
+\r
+// Return: 0 - error, 1 - OK\r
+int parse_mst_name(const char *mst_name, \r
+ PUSHORT dev_id,\r
+ PUSHORT dev_ix,\r
+ MType* mst_dev_type,\r
+ Mdevs* access_type)\r
+{\r
+ char *ptr;\r
+ char suffix[MAX_DEV_NAME];\r
+ const char* fname;\r
+\r
+ // Unix device name compatibility: Remove path (if exists) from device name:\r
+\r
+ if ((fname = strrchr(mst_name, '/')) || (fname = strrchr(mst_name, '\\'))) {\r
+ DPRINT3(("Removing path from file: %s --> %s\n", mst_name, fname + 1));\r
+ mst_name = fname + 1;\r
+ }\r
+\r
+ suffix[0] = '\0';\r
+\r
+ if (strstr(mst_name, USB_DEV_NAME)) {\r
+ *dev_id = DEVASYS_DEV_ID;\r
+ *dev_ix =0;\r
+ *mst_dev_type = MST_USB;\r
+\r
+ } else {\r
+ // get dev_id and suffix. dev_ix gets a dummy value.\r
+ sscanf( mst_name, TAVOR_TYPE_DEVICE_NAME_FMT, dev_id, suffix, dev_ix );\r
+ // step over the suffix. ptr will be at the card's number\r
+ if ((ptr=strstr( suffix, "conf"))) { /* CONF device */\r
+ ptr += 7;\r
+ *mst_dev_type = MST_PCICONF;\r
+ } else if ((ptr=strstr( suffix, "_cr"))) {\r
+ ptr += 3;\r
+ *mst_dev_type = MST_PCI;\r
+ *access_type = MDEVS_TAVOR_CR;\r
+ } else if ((ptr=strstr( suffix, "_uar"))) {\r
+ ptr += 4;\r
+ *mst_dev_type = MST_PCI;\r
+ *access_type = MDEVS_TAVOR_UAR;\r
+ } else if ((ptr=strstr( suffix, "_ddr"))) {\r
+ ptr += 4;\r
+ *mst_dev_type = MST_PCI;\r
+ *access_type = MDEVS_TAVOR_DDR;\r
+ } else {\r
+ DPRINT1(( "parse_mst_name: incorrect device name '%s' \n", mst_name ));\r
+ return 0;\r
+ }\r
+ \r
+ // get dev_ix\r
+ sscanf( ptr, "%hu", dev_ix );\r
+ }\r
+ \r
+ DPRINT3( ("parse_mst_name: name %s, dev_id %d, dev_ix %d\n", \r
+ mst_name, *dev_id, *dev_ix));\r
+ return 1;\r
+}\r
+\r
+\r
+// Return: 0 - error, 1 - OK\r
+int create_mdt_name_by_dev_id(USHORT dev_id, USHORT dev_ix, char *name, int name_len)\r
+{\r
+ int i; \r
+ \r
+ DPRINT3(( "create_mdt_name_by_dev_id: dev_id %d, dev_ix %d\n", \r
+ dev_id, dev_ix ));\r
+ \r
+ // name generation\r
+ *name = 0;\r
+ for (i=0; i<DEVICE_DB_SIZE; i++) {\r
+ DPRINT5(( "create_mdt_name_by_dev_id: dev_id %d, i %d\n", \r
+ db[i].DevId, i ));\r
+ if (db[i].DevId == dev_id) {\r
+ _snprintf(name, name_len, MDT_DEVICE_NAME_FMT, db[i].DevName, dev_ix );\r
+ return 1; // OK\r
+ }\r
+ }\r
+ DPRINT1(( "create_mdt_name_by_dev_id: not found device with dev_id %hu\n", dev_id));\r
+ return 0;\r
+} \r
+\r
+\r
+//\r
+// IBAL Access function\r
+//\r
+\r
+\r
+\r
+static\r
+ib_api_status_t ibal_access(ib_ca_handle_t h_ca, u_int32_t offset, void *p_data, uint32_t length, uint32_t operation )\r
+{\r
+ \r
+ ib_ci_op_t ci_op;\r
+ ib_api_status_t ib_status;\r
+\r
+ BOOL dev_status;\r
+ DWORD bytes_ret;\r
+\r
+ ci_op.buf_size = length;\r
+ ci_op.p_buf = p_data;\r
+ ci_op.buf_info = offset;\r
+ ci_op.num_bytes_ret = sizeof (ib_ci_op_t);\r
+ ci_op.command = operation;\r
+\r
+ ib_status = ib_ci_call (h_ca, NULL, 0, &ci_op);\r
+\r
+ if ( ib_status != IB_SUCCESS )\r
+ {\r
+ DPRINTS1(("Failed ib_ci_call , cmd %x.\n", operation), ib_status );\r
+ return ib_status;\r
+ }\r
+ return IB_SUCCESS;\r
+}\r
+\r
+\r
+//\r
+// Return an array of dev IDs of the HCAs on local machine.\r
+// IDs are returned in the dev_ids array (allocated by caller)\r
+//\r
+// Returns number of HCAs found or -1 for error\r
+//\r
+int get_dev_ids(ib_al_handle_t h_al, USHORT* dev_ids, u_int32_t size) {\r
+ int cnt = 0;\r
+\r
+ u_int32_t stub;\r
+ \r
+ u_int32_t i;\r
+ ib_net64_t guids[MAX_HCA_NUM];\r
+ ib_api_status_t ib_status;\r
+ size_t ca_guids_count = MAX_HCA_NUM;\r
+ \r
+ ib_status = ib_get_ca_guids ( h_al, guids, &ca_guids_count );\r
+ if (ib_status != IB_SUCCESS) {\r
+ DPRINTS1(("Failed to get CA GUIDs\n"), ib_status);\r
+ goto ErrExit;\r
+ }\r
+ \r
+ if (ca_guids_count == 0) {\r
+ DPRINT3(("FOUND NO GUIDS\n"));\r
+ goto OkExit;\r
+ }\r
+ \r
+ if (ca_guids_count > size) {\r
+ DPRINT1(("get_dev_ids(): Got buffer for %d HCAs, but %d HCAs found on machine.\n", size, ca_guids_count));\r
+ goto ErrExit;\r
+ }\r
+\r
+ for (i = 0; i < ca_guids_count ; i++) {\r
+ ib_ca_attr_t* ca_data;\r
+ u_int32_t bsize;\r
+\r
+ cnt++;\r
+\r
+ // Query the CA\r
+ ib_status = ib_query_ca_by_guid(h_al, guids[i], NULL, &bsize);\r
+ if(ib_status != IB_INSUFFICIENT_MEMORY)\r
+ {\r
+ DPRINTS1(("Failed to get size of query ca %d by guid.\n", i), ib_status);\r
+ dev_ids[i] = 0;\r
+ continue; \r
+ }\r
+\r
+ ca_data = (ib_ca_attr_t*)malloc(bsize);\r
+ if (ca_data == NULL) {\r
+ DPRINT1(("get_dev_ids: malloc failed.\n"));\r
+ continue;\r
+ }\r
+\r
+ ca_data->dev_id = 0;\r
+\r
+ ib_status = ib_query_ca_by_guid(h_al, guids[i], ca_data, &bsize);\r
+ if(ib_status != IB_SUCCESS)\r
+ {\r
+ DPRINTS1(("Failed to query ca %d by guid.\n", i), ib_status);\r
+ }\r
+\r
+ // Get the device id:\r
+ dev_ids[i] = ca_data->dev_id;\r
+\r
+ free(ca_data);\r
+\r
+ }\r
+\r
+ goto OkExit;\r
+\r
+ErrExit:\r
+ cnt = -1;\r
+\r
+OkExit:\r
+\r
+ return cnt;\r
+}\r
+\r
+\r
+int get_hca_idx(ib_al_handle_t h_al, USHORT dev_id, USHORT dev_ix) {\r
+ USHORT dev_ids[MAX_HCA_NUM];\r
+ int cnt;\r
+ int i;\r
+ int matching_devs_found = 0;\r
+\r
+ cnt = get_dev_ids(h_al, dev_ids, MAX_HCA_NUM);\r
+\r
+ if (cnt < 0) {\r
+ return cnt;\r
+ }\r
+\r
+ for (i = 0 ; i < cnt ; i++) {\r
+ if (dev_ids[i] == dev_id) {\r
+ if (matching_devs_found == dev_ix) {\r
+ DPRINT3(("get_hca_idx, type=%d, idx=%d. HCA index = %d\n", dev_id, dev_ix, i));\r
+ return i;\r
+ }\r
+ matching_devs_found++;\r
+ }\r
+ }\r
+\r
+ DPRINT3(("get_hca_idx, type=%d, idx=%d. No matching device found in %d HCAs\n", dev_id, dev_ix, i));\r
+\r
+ return -1;\r
+}\r
+\r
+\r
+\r
+//\r
+// dev_idx_by_type - stores current hca type idx for each type. Assumed to\r
+// be in the same size of DEVICE_DB_SIZE\r
+//\r
+int get_and_inc_dev_idx(u_int32_t* dev_idx_by_type, USHORT dev_id) {\r
+ u_int32_t i;\r
+ int ret = -1;\r
+\r
+ for (i = 0; i < DEVICE_DB_SIZE; i++) {\r
+ if (dev_id == db[i].DevId) {\r
+ ret = dev_idx_by_type[i];\r
+ dev_idx_by_type[i]++;\r
+ break;\r
+ }\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+\r
+//\r
+//\r
+// List devices in their MST compatible names.\r
+// Each device type is indexed sepetrately.\r
+//\r
+//\r
+\r
+MTCR_API int mdevices(char *buf, int len, int mask)\r
+{\r
+ u_int32_t tot_len = 0;\r
+ char* p = buf;\r
+ int devs = 0;\r
+ int i;\r
+\r
+ u_int32_t dev_idx_by_type[DEVICE_DB_SIZE];\r
+ USHORT dev_ids[MAX_HCA_NUM];\r
+ int cnt = 0;\r
+\r
+ ib_api_status_t ib_status;\r
+ ib_al_handle_t h_al = 0;\r
+\r
+\r
+\r
+ memset( (char*)dev_idx_by_type, 0, sizeof(dev_idx_by_type));\r
+ \r
+ ib_status = ib_open_al( &h_al );\r
+ if ( ib_status != IB_SUCCESS ) {\r
+ DPRINTS1(("Failed to open AL\n"), ib_status );\r
+ // return -1;\r
+ } else {\r
+ cnt = get_dev_ids(h_al, dev_ids, MAX_HCA_NUM);\r
+\r
+ if (cnt < 0) {\r
+ cnt = 0;\r
+ }\r
+\r
+ ib_close_al(h_al);\r
+\r
+ }\r
+\r
+ for(i = 0; i < cnt; i++) {\r
+ int idx;\r
+ int curr_cnt = 0;\r
+ int curr_len;\r
+\r
+ if (dev_ids[i] == 0) {\r
+ continue;\r
+ }\r
+\r
+ idx = get_and_inc_dev_idx(dev_idx_by_type, dev_ids[i]);\r
+\r
+ if (idx < 0) {\r
+ DPRINT1(("mdevices: Unknown dev id detected: %d. skipped.\n", dev_ids[i]));\r
+ continue;\r
+ }\r
+\r
+ // For now - get only TAVOR_CR (cr, conf ) devices.\r
+ curr_len = create_mst_names_by_dev_id(dev_ids[i], idx, MDEVS_TAVOR_CR , p , len - tot_len , &curr_cnt);\r
+ if (curr_cnt < 0) {\r
+ return -1;\r
+ }\r
+\r
+ tot_len += curr_len;\r
+ p += curr_len; \r
+ devs += curr_cnt;\r
+ }\r
+\r
+\r
+ if (usb_is_connected() ) {\r
+ sprintf(p, USB_DEV_NAME );\r
+ devs++;\r
+ }\r
+\r
+ return devs;\r
+\r
+}\r
+\r
+\r
+MTCR_API mfile *mopen(const char *name)\r
+{\r
+ return mopend(name, MST_TAVOR);\r
+}\r
+\r
+MTCR_API mfile *mopend(const char *name, DType dtype)\r
+{\r
+ USHORT dev_id=0, dev_ix=0;\r
+ HANDLE h;\r
+ MType mst_dev_type;\r
+ Mdevs access_type;\r
+ int target_hca;\r
+ \r
+ /* allocate mfile struct */\r
+ mfile_ibal *mf = (mfile_ibal *)malloc(sizeof(mfile_ibal));\r
+ if (!mf) {\r
+ errno = ENOMEM;\r
+ return 0;\r
+ }\r
+\r
+ memset( (char*)mf, 0, sizeof(mfile_ibal));\r
+\r
+ mf->s.sock = -1;\r
+\r
+ /* parse name */\r
+\r
+ if (!parse_mst_name(name, &dev_id, &dev_ix, &mst_dev_type, &access_type )) {\r
+ goto ErrExit;\r
+ }\r
+\r
+ DPRINT3(( "mopend: %s, dtype %d, devid %d\n", name, dtype, dev_id));\r
+\r
+ \r
+ switch(dev_id) {\r
+ case TAVOR_DEV_ID: case ARBEL_TM_DEV_ID:\r
+ case ARBEL_DEV_ID: case SINAI_4X_DEV_ID:\r
+ case SINAI_8X_DEV_ID:\r
+ mf->s.itype = MST_TAVOR;\r
+ break;\r
+ default: \r
+ mf->s.itype = MST_GAMLA;\r
+ }\r
+\r
+\r
+ /* Type of device */\r
+ mf->s.dtype = dtype;\r
+ if (dtype == MST_TAVOR)\r
+ mf->s.i2c_slave = 0x48;\r
+ else\r
+ mf->s.i2c_slave = 0x5a;\r
+\r
+#ifdef SUPPORT_I2CM\r
+ /* Use the device as I2C master? */\r
+ mf->s.is_i2cm = strstr(name, "i2cm") ? 1 : 0;\r
+\r
+ /* Type of interface (relevant when is_i2cm==1, unused otherwise */\r
+ if (mf->s.is_i2cm)\r
+ {\r
+ switch(dev_id) {\r
+ case TAVOR_DEV_ID: case ARBEL_TM_DEV_ID:\r
+ case ARBEL_DEV_ID: case SINAI_4X_DEV_ID:\r
+ case SINAI_8X_DEV_ID:\r
+ mf->s.itype = MST_TAVOR;\r
+ break;\r
+ default: \r
+ goto ErrExit;\r
+ }\r
+ }\r
+#endif\r
+\r
+ if (dev_id != DEVASYS_DEV_ID ) {\r
+ /* Open ibal HCA handle */\r
+ u_int32_t stub;\r
+ \r
+ ib_net64_t guids[MAX_HCA_NUM];\r
+\r
+ ib_api_status_t ib_status;\r
+ size_t ca_guids_count = MAX_HCA_NUM;\r
+\r
+ ib_status = ib_open_al( &mf->h_al );\r
+\r
+ if ( ib_status != IB_SUCCESS ) {\r
+ M_DEBUGS(("Failed to open AL\n"), ib_status );\r
+ goto ErrExit;\r
+ }\r
+\r
+\r
+ ib_status = ib_get_ca_guids ( mf->h_al, guids, &ca_guids_count );\r
+ if (ib_status != IB_SUCCESS) {\r
+ M_DEBUGS(("Failed to get CA GUIDs\n"), ib_status);\r
+ goto ErrExit;\r
+ }\r
+ \r
+ if (ca_guids_count == 0) {\r
+ DPRINT1(("FOUND NO GUIDS\n"));\r
+ goto ErrExit;\r
+ }\r
+\r
+ target_hca = get_hca_idx(mf->h_al, dev_id , dev_ix );\r
+ if (target_hca < 0) {\r
+ goto ErrExit;\r
+ }\r
+\r
+ ib_status = ib_open_ca( mf->h_al, guids[target_hca], NULL, mf, &mf->h_ca );\r
+ if (ib_status != IB_SUCCESS)\r
+ {\r
+ DPRINTS1(("Failed to open CA\n"), ib_status);\r
+ goto ErrExit;\r
+ }\r
+\r
+ if(mst_dev_type == MST_PCICONF) {\r
+ // Type of file \r
+ mf->s.tp = MST_PCICONF;\r
+\r
+ DPRINT5(("Calling: ibal_access(mf->h_ca, 0x0, &stub, 4, FW_OPEN_IF )\n"));\r
+ if (ibal_access(mf->h_ca, 0x0, &stub, 4, FW_OPEN_IF ) != IB_SUCCESS) {\r
+ goto ErrExit;\r
+ }\r
+ } else {\r
+ \r
+ int bar_num;\r
+\r
+ // Type of file \r
+ mf->s.tp = MST_PCI;\r
+ \r
+ // calculate bar number\r
+ if (access_type == MDEVS_TAVOR_CR) { \r
+ // TODO: See what about UAR and DDR bars - not supported for now.\r
+\r
+ } else {\r
+ DPRINT1(("Only _cr access is supported"));\r
+ goto ErrName;\r
+ }\r
+ \r
+ // check FW_MAP_CRSPACE\r
+ if (ibal_access(mf->h_ca, 0x0, &mf->cr_map, sizeof(mf->cr_map), FW_MAP_CRSPACE ) != IB_SUCCESS) {\r
+ goto ErrExit;\r
+ }\r
+\r
+ mf->s.ptr = mf->cr_map.va;\r
+ }\r
+ \r
+ } else if (dev_id == DEVASYS_DEV_ID) {\r
+ // Type of file \r
+ h = usb_open();\r
+ if ( h == INVALID_HANDLE_VALUE ) \r
+ goto ErrExit;\r
+ mf->s.fd = FromHandle(h);\r
+ // mf->s.tp = (usb_is_dimax()) ? MST_USB_DIMAX : MST_USB;\r
+ mf->s.tp = MST_USB;\r
+ } else {\r
+ goto ErrExit;\r
+ }\r
+ \r
+ /* OK */\r
+ return (mfile*)mf;\r
+ErrName: \r
+// CloseHandle(h);\r
+ErrExit: \r
+ mclose((mfile*)mf);\r
+ errno = ENODEV;\r
+ return 0;\r
+}\r
+\r
+MTCR_API void maccelerate(mfile *mf)\r
+{\r
+#ifdef SUPPORT_I2CM\r
+ if (mf->is_i2cm)\r
+ i2c_master_set((mfile*)mf);\r
+#endif\r
+}\r
+\r
+MTCR_API void mrestore(mfile *mf)\r
+{\r
+#ifdef SUPPORT_I2CM\r
+ if (mf->is_i2cm)\r
+ i2c_master_restore(mf);\r
+#endif\r
+}\r
+\r
+MTCR_API int mclose(mfile *mf)\r
+{\r
+ int rc=0;\r
+ \r
+ if (mf->tp == MST_USB) {\r
+ rc = usb_close( (HANDLE)mf->fd);\r
+ } else {\r
+ mfile_ibal* mfi = (mfile_ibal*)mf;\r
+ u_int32_t stub;\r
+\r
+ if (mf->tp == MST_PCICONF) {\r
+ ibal_access(mfi->h_ca, 0x0, &stub, 4, FW_CLOSE_IF );\r
+ } else if (mf->tp = MST_PCI) {\r
+ if (mfi->cr_map.size) {\r
+ unmap_crspace unmap;\r
+ \r
+ unmap.va = mfi->cr_map.va;\r
+ unmap.ctx = mfi->cr_map.ctx;\r
+ if (ibal_access(mfi->h_ca, 0x0, &unmap, sizeof(unmap), FW_UNMAP_CRSPACE ) != IB_SUCCESS) {\r
+ DPRINT1(("Unmap crspace failed"));\r
+ } \r
+ }\r
+ }\r
+ \r
+ if (mfi->h_ca)\r
+ ib_close_ca( mfi->h_ca, NULL );\r
+ if (mfi->h_al)\r
+ ib_close_al( mfi->h_al);\r
+ }\r
+ \r
+ free(mf);\r
+ return rc;\r
+}\r
+\r
+MTCR_API int mread4(mfile *mf, unsigned int offset, u_int32_t *value)\r
+{\r
+ int rc = 4;\r
+ u_int32_t lvalue;\r
+ mfile_ibal* mfi = (mfile_ibal*)mf;\r
+ switch (mf->tp) {\r
+ \r
+ case MST_PCI:\r
+\r
+ if (!mf->ptr)\r
+ return -1;\r
+\r
+ if (offset >= mfi->cr_map.size) {\r
+ DPRINT1(("MTCR:mread4: Tried to access value at offset %x, which is out of pci bar (size %x)\n",\r
+ offset,\r
+ mfi->cr_map.size));\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+\r
+\r
+#ifdef SUPPORT_I2CM\r
+ if (mf->is_i2cm)\r
+ return i2c_master_read_cr(mf, value, offset, 4);\r
+#endif\r
+\r
+ if (mf->dtype == MST_TAVOR)\r
+ *value = __be32_to_cpu(*((volatile unsigned int *)((char *)mf->ptr + offset)));\r
+ else\r
+ *value = *((volatile unsigned int *)((char *)mf->ptr + offset));\r
+ break;\r
+\r
+ case MST_PCICONF:\r
+ {\r
+\r
+#ifdef SUPPORT_I2CM\r
+ if (mf->is_i2cm)\r
+ return i2c_master_read_cr(mf, value, offset, 4);\r
+#endif\r
+\r
+ if (ibal_access(((mfile_ibal*)mf)->h_ca, offset, value, 4, FW_READ_CMD) == IB_SUCCESS) {\r
+ rc = 4;\r
+ } else {\r
+ rc = -1;\r
+ }\r
+\r
+ break;\r
+ }\r
+\r
+ case MST_USB:\r
+ {\r
+ switch(mf->dtype)\r
+ {\r
+ case MST_GAMLA:\r
+ {\r
+ unsigned int offs = (usb_is_dimax()) ? offset : __cpu_to_be32(offset);\r
+ unsigned int addr_len = 2;\r
+ rc = usb_read( (HANDLE)mf->fd, I2C_TRANS_32ADR, mf->i2c_slave, offs, addr_len, \r
+ (u_int8_t*)&lvalue, 4 );\r
+ break;\r
+ }\r
+ case MST_TAVOR:\r
+ default:\r
+ {\r
+ unsigned int offs = (usb_is_dimax()) ? offset : __cpu_to_be32(offset);\r
+ unsigned int addr_len = 4;\r
+ rc = usb_read( (HANDLE)mf->fd, I2C_TRANS_32ADR, mf->i2c_slave, offs, addr_len, \r
+ (u_int8_t*)&lvalue, 4 );\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if (rc == MT_OK) {\r
+ *value = __be32_to_cpu(lvalue);\r
+ rc = 4;\r
+ }\r
+ break;\r
+\r
+ }\r
+\r
+ default:\r
+ return -1;\r
+ }\r
+\r
+ DPRINT5(( "MTCR:mread4: off 0x%x, val 0x%x\n", offset, *value));\r
+ return rc;\r
+}\r
+\r
+MTCR_API int mwrite4(mfile *mf, unsigned int offset, u_int32_t value)\r
+{\r
+ int rc = 4;\r
+ unsigned int lvalue;\r
+ mfile_ibal* mfi = (mfile_ibal*)mf;\r
+\r
+ switch(mf->tp)\r
+ {\r
+ case MST_PCI:\r
+ if (!mf->ptr)\r
+ return -1;\r
+\r
+ if (offset >= mfi->cr_map.size) {\r
+ DPRINT1(("MTCR:mwrite4: Tried to access value at offset %x, which is out of pci bar (size %x)\n",\r
+ offset,\r
+ mfi->cr_map.size));\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+\r
+#ifdef SUPPORT_I2CM\r
+ if (mf->is_i2cm)\r
+ return i2c_master_write_cr(mf, value, offset, 4);\r
+#endif\r
+ \r
+ if (mf->dtype == MST_TAVOR)\r
+ *((volatile unsigned int *)((char *)mf->ptr + offset)) = __cpu_to_be32(value);\r
+ else\r
+ *((volatile unsigned int *)((char *)mf->ptr + offset)) = value;\r
+ break;\r
+ \r
+ case MST_PCICONF:\r
+ {\r
+\r
+#ifdef SUPPORT_I2CM\r
+ if (mf->is_i2cm)\r
+ return i2c_master_write_cr(mf, value, offset, 4);\r
+#endif\r
+\r
+ if (ibal_access(((mfile_ibal*)mf)->h_ca, offset, &value, 4, FW_WRITE_CMD) == IB_SUCCESS) {\r
+ rc = 4;\r
+ } else {\r
+ rc = -1;\r
+ }\r
+\r
+ break;\r
+ }\r
+ \r
+ case MST_USB:\r
+ {\r
+\r
+ switch(mf->dtype)\r
+ {\r
+ case MST_GAMLA:\r
+ {\r
+ unsigned int offs = (usb_is_dimax()) ? offset : __cpu_to_be32(offset);\r
+ unsigned int addr_len = 2;\r
+ lvalue = __cpu_to_be32(value);\r
+ rc = usb_write( (HANDLE)mf->fd, I2C_TRANS_32ADR, mf->i2c_slave, offs, addr_len, \r
+ (u_int8_t*)&lvalue, 4 );\r
+ break;\r
+ }\r
+ case MST_TAVOR:\r
+ default:\r
+ {\r
+ unsigned int offs = (usb_is_dimax()) ? offset : __cpu_to_be32(offset);\r
+ unsigned int addr_len = 4;\r
+ lvalue = __cpu_to_be32(value);\r
+ rc = usb_write( (HANDLE)mf->fd, I2C_TRANS_32ADR, mf->i2c_slave, offs, addr_len, \r
+ (u_int8_t*)&lvalue, 4 );\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (rc == MT_OK) {\r
+ rc = 4;\r
+ }\r
+ break;\r
+ }\r
+ default:\r
+ return -1;\r
+ }\r
+ \r
+ DPRINT5(("MTCR:mwrite4: off 0x%x, val 0x%x\n", offset, value));\r
+ return rc;\r
+}\r
+\r
+MTCR_API int mread64(mfile *mf, unsigned int offset, void *data, int length)\r
+{\r
+ int rc;\r
+\r
+ if (length > MAX_TRANS_SIZE)\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+\r
+ switch(mf->tp)\r
+ {\r
+ case MST_PCI:\r
+ case MST_PCICONF:\r
+ {\r
+ int i;\r
+ unsigned char *cdata = (unsigned char *)data;\r
+\r
+ for (i=0; i<length; i++)\r
+ {\r
+ rc = i2c_master_read_cr(mf, cdata++, offset++, 1);\r
+ if (rc < 0)\r
+ return rc;\r
+ else if (rc < 1)\r
+ return i;\r
+ }\r
+ return length;\r
+ }\r
+ break;\r
+\r
+#ifdef MTCR_USB_SUPPORT\r
+ case MST_USB:\r
+ {\r
+ call_result_t ret;\r
+ int aw = 0;\r
+ int trans_type = I2C_TRANS_NOADR;\r
+ switch (mf->dtype)\r
+ {\r
+ case MST_NOADDR: trans_type = I2C_TRANS_NOADR; aw = 0; break;\r
+ case MST_DIMM: trans_type = I2C_TRANS_8ADR; aw = 1; break;\r
+ case MST_GAMLA: trans_type = I2C_TRANS_16ADR; aw = 2; break;\r
+ case MST_TAVOR: trans_type = I2C_TRANS_32ADR; aw = 4; break;\r
+ }\r
+\r
+ ret = usb_read((HANDLE)mf->fd, trans_type, mf->i2c_slave, offset, aw, data, length);\r
+ if (ret == MT_OK) {\r
+ return length;\r
+ } else {\r
+ errno = ret;\r
+ return -1;\r
+ }\r
+ }\r
+#endif\r
+\r
+\r
+ }\r
+\r
+ errno = EPERM;\r
+ return -1;\r
+}\r
+\r
+\r
+MTCR_API int mwrite64(mfile *mf, unsigned int offset, void *data, int length)\r
+{\r
+\r
+ int rc;\r
+\r
+ if (length > MAX_TRANS_SIZE)\r
+ {\r
+ errno = EINVAL;\r
+ return -1;\r
+ }\r
+\r
+ switch(mf->tp)\r
+ {\r
+ case MST_PCI:\r
+ case MST_PCICONF:\r
+ {\r
+ int i;\r
+ unsigned char *cdata = (unsigned char *)data;\r
+\r
+ for (i=0; i<length; i++)\r
+ {\r
+ rc = i2c_master_write_cr(mf, *cdata++, offset++, 1);\r
+ if (rc < 0)\r
+ return rc;\r
+ else if (rc < 1)\r
+ return i;\r
+ }\r
+ return length;\r
+ }\r
+\r
+#ifdef MTCR_USB_SUPPORT\r
+ case MST_USB:\r
+ {\r
+ call_result_t ret;\r
+ int aw = 0;\r
+ int trans_type = I2C_TRANS_NOADR;\r
+ switch (mf->dtype)\r
+ {\r
+ case MST_NOADDR: trans_type = I2C_TRANS_NOADR; aw = 0; break;\r
+ case MST_DIMM: trans_type = I2C_TRANS_8ADR; aw = 1; break;\r
+ case MST_GAMLA: trans_type = I2C_TRANS_16ADR; aw = 2; break;\r
+ case MST_TAVOR: trans_type = I2C_TRANS_32ADR; aw = 4; break;\r
+ }\r
+\r
+ ret = usb_write((HANDLE)mf->fd, trans_type, mf->i2c_slave, offset, aw, data, length);\r
+ if (ret == MT_OK) {\r
+ return length;\r
+ } else {\r
+ errno = ret;\r
+ return -1;\r
+ }\r
+ }\r
+#endif\r
+\r
+ }\r
+\r
+ errno = EPERM;\r
+ return -1;\r
+}\r
+\r
+unsigned char mset_i2c_slave(mfile *mf, unsigned char new_i2c_slave)\r
+{\r
+ unsigned char ret;\r
+ if (mf)\r
+ {\r
+ ret = mf->i2c_slave;\r
+ mf->i2c_slave = new_i2c_slave;\r
+ }\r
+ else\r
+ ret = 0xff;\r
+ return ret;\r
+}\r
+\r
--- /dev/null
+EXPORTS
\ No newline at end of file
--- /dev/null
+/*
+ *
+ * mtcr.h - Mellanox Software tools (mst) driver definitions
+ *
+ */
+
+#ifndef _MST_H
+#define _MST_H
+
+
+#ifdef __WIN__
+
+#include <windows.h>
+
+#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 <sys/types.h>
+#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
--- /dev/null
+/*
+ * 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 <oib_ver.h>
+
+#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 <common.ver>
--- /dev/null
+/* - 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 <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __WIN__
+#include "com_def.h"
+#else
+#include <asm/byteorder.h>
+
+#include <unistd.h>
+
+
+#include <sys/ioctl.h>
+#include <endian.h>
+#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);
+}
--- /dev/null
+/* - 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
--- /dev/null
+/* - 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<DIMAX_READ_RETRIES; i++ ) {
+ u2c_rc = U2C_Read( h, &t );
+ if (u2c_rc == U2C_SUCCESS)
+ break;
+ }
+ if (u2c_rc != U2C_SUCCESS) {
+ DPRINT1(("usb_read: U2C_Read failed (%d) after %d retries: slv_addr %#x, addr_len %d, mem_base %#x, data_sz %d\n",
+ u2c_rc, DIMAX_READ_RETRIES, (ULONG)t.nSlaveDeviceAddress,
+ t.nMemoryAddressLength, t.nMemoryAddress, t.nBufferLength ));
+ return MT_ERROR;
+ } else {
+ DPRINT5(("usb_read: U2C_Read succeeded after %d retries: value %#x\n",
+ i+1, *(ULONG*)t.Buffer ));
+ }
+
+ // copy the results
+ memcpy( data_arr_r, t.Buffer, data_size );
+ return MT_OK;
+ }
+
+ // validate parameters
+ if (data_size > 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
--- /dev/null
+/* - 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 <usbi2cio.h>
+
+/******************************************************************************
+ * 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
+
--- /dev/null
+TARGETNAME=mwrite\r
+TARGETTYPE=PROGRAM\r
+UMTYPE=console\r
+USE_CRTDLL=1\r
+\r
+\r
+!if !defined(WINIBHOME)\r
+WINIBHOME=..\..\..\r
+!endif\r
+\r
+TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR)\r
+\r
+\r
+\r
+SOURCES=mwrite.c \\r
+ mwrite.rc\r
+\r
+INCLUDES= $(WINIBHOME)\inc; \\r
+ $(WINIBHOME)\inc\user; \\r
+ $(WINIBHOME)\inc\iba; \\r
+ $(WINIBHOME)\tools\mtcr\user;\r
+\r
+TARGETLIBS= \\r
+!if $(FREEBUILD)\r
+ $(TARGETPATH)\*\mtcr.lib\r
+!else\r
+ $(TARGETPATH)\*\mtcr.lib\r
+!endif\r
+\r
+!if $(FREEBUILD)\r
+\r
+!else\r
+C_DEFINES=$(C_DEFINES) -DDEBUG\r
+!endif\r
+\r
+C_DEFINES=$(C_DEFINES) -D__WIN__\r
+\r
+386_STDCALL=0\r
+\r
+\r
--- /dev/null
+#\r
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source\r
+# file to this component. This file merely indirects to the real make file\r
+# that is shared by all the driver components of the Windows NT DDK\r
+#\r
+\r
+!INCLUDE ..\..\..\inc\openib.def\r
+\r
--- /dev/null
+/*\r
+ *\r
+ * mwrite.c - CR Space write access\r
+ *\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "mtcr.h"\r
+\r
+void usage(const char *n)\r
+{\r
+ printf("%s <device> <addr> <value> [<i2c_slave>]\n", n);\r
+ exit(1);\r
+}\r
+\r
+int main(int ac, char *av[])\r
+{\r
+ char *endp;\r
+ int rc=0;\r
+ unsigned int addr, val;\r
+ mfile *mf;\r
+ DType dtype = MST_TAVOR;\r
+\r
+ if (ac < 4)\r
+ usage(av[0]);\r
+ addr = strtoul(av[2], &endp, 0);\r
+ if (*endp)\r
+ usage(av[0]);\r
+ val = strtoul(av[3], &endp, 0);\r
+ if (*endp)\r
+ usage(av[0]);\r
+\r
+ if (strstr(av[1], "mt21108_pci") && !strstr(av[1], "i2cm"))\r
+ dtype = MST_GAMLA;\r
+ mf = mopend(av[1], dtype);\r
+ if ( !mf )\r
+ {\r
+ perror("mopen");\r
+ return 1;\r
+ }\r
+\r
+ if (ac >= 5)\r
+ mset_i2c_slave(mf, (unsigned char)strtoul(av[4],0,0));\r
+\r
+ if ((rc = mwrite4(mf, addr, val)) < 0)\r
+ {\r
+ mclose(mf);\r
+ perror("mwrite");\r
+ return 1;\r
+ }\r
+ if (rc < 4)\r
+ {\r
+ mclose(mf);\r
+ printf("Write only %d bytes\n", rc);\r
+ return 1;\r
+ }\r
+ mclose(mf);\r
+ return 0;\r
+}\r
--- /dev/null
+DIRS=\
+ user
--- /dev/null
+TARGETNAME=spark\r
+TARGETTYPE=PROGRAM\r
+UMTYPE=console\r
+USE_CRTDLL=1\r
+USE_NTDLL=1\r
+\r
+\r
+!if !defined(WINIBHOME)\r
+WINIBHOME=..\..\..\r
+!endif\r
+\r
+TARGETPATH=$(WINIBHOME)\bin\user\obj$(BUILD_ALT_DIR)\r
+\r
+\r
+SOURCES=spark.rc \\r
+ spark.cpp\r
+\r
+\r
+INCLUDES= $(WINIBHOME)\inc; \\r
+ $(WINIBHOME)\inc\user; \\r
+ $(WINIBHOME)\inc\iba; \\r
+ $(WINIBHOME)\tools\mtcr\user; \\r
+ $(ZLIB)\include;\r
+\r
+TARGETLIBS= \\r
+!if $(FREEBUILD)\r
+ $(CRT_LIB_PATH)\msvcprt.lib \\r
+ $(SDK_LIB_PATH)\Ws2_32.lib\\r
+ $(TARGETPATH)\*\mtcr.lib\r
+!else\r
+ $(CRT_LIB_PATH)\msvcprt.lib\\r
+ $(SDK_LIB_PATH)\Ws2_32.lib\\r
+ $(TARGETPATH)\*\mtcr.lib\r
+!endif\r
+\r
+USER_C_FLAGS=$(USER_C_FLAGS) /Ze /EHsc\r
+\r
+# TODO:Should I define the __WIN__ manually\r
+C_DEFINES=$(C_DEFINES) -D__WIN__\r
+\r
+\r
+!if $(FREEBUILD)\r
+\r
+!else\r
+C_DEFINES=$(C_DEFINES) -DDEBUG\r
+!endif\r
+\r
+# Version:\r
+!if !defined(MFT_BLD_VER)\r
+MFT_BLD_VER=Devel\r
+!endif\r
+C_DEFINES=$(C_DEFINES) "-DVERSION_ID=$(MFT_BLD_VER)"\r
+\r
+386_STDCALL=0\r
+\r
+MSC_WARNING_LEVEL= /W3\r
+\r
--- /dev/null
+#\r
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source\r
+# file to this component. This file merely indirects to the real make file\r
+# that is shared by all the driver components of the Windows NT DDK\r
+#\r
+\r
+!INCLUDE ..\..\..\inc\openib.def\r
--- /dev/null
+/* - 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+
+
+
+
+#ifndef __WIN__
+
+//
+// Linux
+//
+
+#include <endian.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <byteswap.h>
+
+#else // __WIN__
+
+//
+// Windows (Under DDK)
+//
+
+#include <io.h>
+#include <Winsock2.h>
+
+// 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 <iostream>
+#include <sstream>
+#include <map>
+#include <vector>
+#include <list>
+#include <string>
+
+
+#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<u_int8_t> 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<EeLoc, u_int32_t> 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<EeRange>
+ 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<EeLoc> _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<Section*> 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<u_int8_t, DataVec> 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<EeRange> eer = _conv->ConvertRange(addr, data.size());
+
+ if (eer.size() > 1) {
+ u_int32_t totWritten = 0;
+ for (vector<EeRange>::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<FieldId, ReplaceFieldData> 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<SectionType, const char*> _sectionTypeNames;
+ std::map<FieldId, const char*> _fieldIdNames;
+ std::map<FieldId, u_int32_t> _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<EeLoc>::const_iterator it = _devmap.begin(); it != _devmap.end() ; ++it) {
+ res += it->offset;
+ }
+
+ return res;
+}
+
+
+EeLoc EeAddressConvertor::Convert (u_int32_t addr) const {
+ vector<EeRange> 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<EeRange> EeAddressConvertor::ConvertRange (u_int32_t addr, u_int32_t len) const {
+ vector<EeRange> 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<EeRange>::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<Section*>::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<Section*>::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<EeRange> eer = _conv->ConvertRange(addr, len);
+
+ for (vector<EeRange>::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<EeRange> 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<SectionType, const char*>::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<FieldId,u_int32_t>::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...] <command> [parameters...]\n"
+ "\n"
+ "\n"
+ "Switches summary:\n"
+ "-----------------\n"
+ "\n"
+// " -crc - Print CRC after each section when verify.\n"
+// "\n"
+ " -d[evice] <device> - The device the eeprom is connected to.\n"
+ " Commands affected: all\n"
+ "\n"
+ " -i[mage] <image> - Image file in \".img\" format.\n"
+ " Commands affected: burn, verify\n"
+ "\n"
+ " -guid <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 <GUID> - 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 <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 <Descr> - 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 <i2c_addr> - 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 <i2c_addr> - 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 <i2c_addr> - 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 <dev> <offs> <size> <out-file>
+ 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;
+}
+
--- /dev/null
+/*\r
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id: mst.rc 219 2005-07-27 10:15:27Z sleybo $\r
+ */\r
+\r
+\r
+#include <oib_ver.h>\r
+\r
+#define VER_FILETYPE VFT_APP\r
+#define VER_FILESUBTYPE VFT2_UNKNOWN\r
+\r
+#if DBG\r
+#define VER_FILEDESCRIPTION_STR "Mellanox Switches FW burning tool. (Debug)"\r
+#else\r
+#define VER_FILEDESCRIPTION_STR "Mellanox Switches FW burning tool."\r
+#endif\r
+\r
+#define VER_INTERNALNAME_STR "spark.exe"\r
+#define VER_ORIGINALFILENAME_STR "spark.exe"\r
+\r
+#include <common.ver>\r