[openfabrics-ewg] 1.0 branch update owners

Johannes Erdfelt johannes at erdfelt.com
Mon May 1 17:15:07 PDT 2006


On Thu, Apr 27, 2006, Tziporet Koren <tziporet at mellanox.co.il> wrote:
> Please do it on Monday so it can be in RC4

Here's the patch for tvflash. It's a somewhat large patch because of all
of the changes that have happened since the original version was dropped
into subversion.

Changelog:
- Add two new operations, modify Topspin/Cisco boot options, print GUIDs
- Add support for Tiger, Cheetah, Lion Mini and Lion Cub Rev C
- Rewrite support for adding new boards
- Add support for SPI flash chips
- Add support to program through PCI config space

I don't have an account in the OF Subversion. Can I work with someone to
get this checked in?

JE

Index: src/firmware.h
===================================================================
--- src/firmware.h	(revision 6845)
+++ src/firmware.h	(working copy)
@@ -28,8 +28,10 @@
 enum operation {
 	OP_NONE,
 	OP_IDENTIFY,
+	OP_PRINT_GUIDS,
 	OP_DOWNLOAD,
-	OP_UPLOAD,
+	OP_UPLOAD, 
+	OP_MODIFY_OPTIONS,
 };
 
 enum identify_mode {
@@ -38,33 +40,8 @@
 	IDENTIFY_HARDWARE_LABEL,
 };
 
-enum board_type {
-	BOARD_JAGUAR,
-	BOARD_COUGAR,
-	BOARD_COUGARCUB,
-	BOARD_LIONCUB,
-};
+#define TV_FLASH_DEFAULT_SECTOR_SIZE	0x010000	/* 64K */
 
-#define BOARD_JAGUAR_A0_STR	"HCA.Jaguar.A0"
-#define BOARD_JAGUAR_A1_STR	"HCA.Jaguar.A1"
-#define BOARD_COUGAR_A1_STR	"HCA.Cougar.A1"
-#define BOARD_COUGARCUB_A1_STR	"HCA.CougarCub.A1"
-#define BOARD_LIONCUB_A0_STR	"HCA.LionCub.A0"
-
-#define COUGARCUB_VPD_STR	"Cougar cub"
-
-struct tvdevice {
-	struct tvdevice *next;
-
-	struct pci_dev *pdev;
-
-	int num;
-
-	int can_map;
-	int vpd;
-	unsigned char vpd_data[256];
-};
-
 struct topspin_vsd {
 	uint32_t flags;
 /*
@@ -82,11 +59,13 @@
 #define VSD_FLAG_BOOT_ENABLE_PORT_1	0x00010000
 #define VSD_FLAG_BOOT_ENABLE_PORT_2	0x00020000
 #define VSD_FLAG_BOOT_ENABLE_SCAN	0x00040000
+#define VSD_FLAG_BOOT_WAIT_ON_ERROR	0x00080000
+#define VSD_FLAG_BOOT_TRY_FOREVER	0x00100000
 
 #define VSD_FLAG_BOOT_TYPE		0x00C00000
 #define VSD_FLAG_BOOT_TYPE_WELL_KNOWN	0x00000000
 #define VSD_FLAG_BOOT_TYPE_SAVED	0x00400000
-	/* 0x00800000 */
+#define VSD_FLAG_BOOT_TYPE_PXE		0x00800000
 #define VSD_FLAG_BOOT_TYPE_DISABLE	0x00C00000
 
 	uint64_t createtime;
@@ -97,22 +76,25 @@
 	uint16_t micro_ver;	/* 0 */
 	int8_t   revision_ver;	/* 7 (highbit set for rc) */
 	uint8_t  old_build_num;	/* Old build number */
+	/* FIXME: This is in little endian when it should be big endian */
 	uint16_t build_num;	/* For Topspin use (eg 345) */
 
-	uint8_t  hw_label[64];	/* Text label unique to this hardware */
+	char     hw_label[64];	/* Text label unique to this hardware */
 
-	uint8_t  build_rev[16];	/* For Topspin use (eg 2.0.0) */
+	char     build_rev[16];	/* For Topspin use (eg 2.0.0) */
 
-	uint8_t  unused[0xc3 - 0x70]; /* Program as 0 */
+	uint8_t  unused[0xc2 - 0x70];	/* Program as 0 */
 
-	uint8_t  boot_ioc_num;	/* Saved IOC num */
-	uint32_t boot_service_name[2];/* Saved service name */
-	uint8_t  boot_dgid[16];	/* Saved destination GID */
-	uint8_t  boot_port;	/* Port number to use (0 == any) */
-#define BOOT_VERSION	1
-	uint8_t  boot_version;	/* Version of boot firmware options */
+#define BOOT_PXE_SECS_DEFAULT	20
+	uint8_t  boot_pxe_secs;		/* Number of secs to wait for DHCP (0 = inf) */
+	uint8_t  boot_ioc_num;		/* Saved IOC num */
+	uint8_t  boot_service_name[8];	/* Saved service name */
+	uint8_t  boot_dgid[16];		/* Saved destination GID */
+	uint8_t  boot_port;		/* Port number to use (0 == any) */
+#define BOOT_VERSION	2
+	uint8_t  boot_version;		/* Version of boot firmware options */
 
-	uint16_t signature2;	/* 0x05ad */
+	uint16_t signature2;
 } __attribute__((packed));
 
 union vsd {
@@ -128,29 +110,198 @@
 	} data;
 };
 
-struct image {
+struct failsafe {
 	unsigned char valid;
 
-	uint32_t addr;
-	uint32_t size;
+	struct image {
+		unsigned char valid;
 
-	union vsd vsd;
+		uint32_t addr;
+		uint32_t size;
+
+		union vsd vsd;
+	} images[2];
 };
 
-struct failsafe {
-	unsigned char valid;
-	unsigned int sector_sz;
+enum method {
+	METHOD_MMAP,
+	METHOD_PCI_CFG,
+};
 
-	struct image images[2];
+struct pciid;
+
+enum flash_command_set {
+	CS_UNKNOWN = 0,
+	CS_INTEL = 1,
+	CS_AMD = 2,
+	CS_SPI = 3,
 };
 
-#define GUID_LEN	8
+#define GPIO_DAT	0xF0080
+#define GPIO_DIR	0xF0088
+#define GPIO_POL	0xF0090
+#define GPIO_MOD	0xF0098
+#define GPIO_LOCK	0xF00EC
 
-#define TV_FLASH_SIZE			0x400000	/* 4M */
-#define TV_FLASH_BANK_SIZE		0x080000	/* 512K */
-#define TV_FLASH_BANK_MASK		(TV_FLASH_BANK_SIZE - 1)
-#define TV_FLASH_DEFAULT_SECTOR_SIZE	0x010000	/* 64K */
+#define GPIO_DATACLEAR	0xF00F4
+#define GPIO_DATASET	0xF00DC
 
+struct tvdevice {
+	struct tvdevice *next;
+
+	struct pci_dev *pdev;
+	struct pciid *pciid;
+	struct board *board;
+	unsigned char revision;
+
+	unsigned char num;
+	unsigned char flags;
+
+	enum method method;
+	uint8_t *bar0;
+
+	unsigned char flash_bank;
+	struct failsafe failsafe;
+
+	unsigned flash_size;
+
+	enum flash_command_set flash_command_set;
+	unsigned char flash_bank_shift;
+	unsigned int flash_bank_mask;
+	unsigned int flash_sector_sz;
+
+	unsigned int gpio_data[2], gpio_direction[2];
+	unsigned int gpio_polarity[2], gpio_output_mode[2];
+
+	unsigned char vpd_present;
+
+	/* This is just so we can force alignment for this data */
+	union {
+		unsigned char vpd_char[256];
+		unsigned int vpd_int[256/4];
+	} vpd;
+};
+
+enum hca_chip {
+	CHIP_TAVOR,
+	CHIP_ARBEL,
+	CHIP_SINAI,
+};
+
+/* Board identification */
+struct board {
+	char *name;
+	enum hca_chip chip;
+	char *fwlabel;
+	int num_ports;
+};
+
+/* Tavor */
+struct board jaguar = { "Jaguar", CHIP_TAVOR, "HCA.Jaguar", 2 };
+struct board cougar = { "Cougar", CHIP_TAVOR, "HCA.Cougar", 2 };
+struct board cougarcub = { "Cougar Cub", CHIP_TAVOR, "HCA.CougarCub", 2 };
+/* Arbel */
+struct board lioncub = { "Lion Cub", CHIP_ARBEL, "HCA.LionCub", 2 };
+struct board lioncub_revc = { "Lion Cub", CHIP_ARBEL, "HCA.LionCub.RevC", 2 };
+struct board glacier = { "DLGL", CHIP_ARBEL, "HCA.DLGL", 2 };
+struct board bc2 = { "BC2 HSDC", CHIP_ARBEL, "HCA.HSDC", 2 };
+struct board lionmini = { "Lion Mini", CHIP_ARBEL, "HCA.LionMini", 2 };
+struct board genarbel = { "Generic Arbel", CHIP_ARBEL, NULL, 2 };
+/* Sinai */
+struct board tiger = { "Tiger", CHIP_SINAI, "HCA.Tiger", 1 };
+struct board cheetah = { "Cheetah", CHIP_SINAI, "HCA.Cheetah", 1 };
+struct board gensinai = { "Generic Sinai", CHIP_SINAI, NULL, 1 };
+
+/* Map VPD string to board */
+struct board_vpd {
+	char *str;
+
+	struct board *board;
+};
+
+struct board_vpd board_vpds[] = {
+	{ "Cougar cub", &cougarcub },
+	{ "Lion cub", &lioncub },
+	{ "Lion mini", &lionmini },
+	{ "DLGL", &glacier },
+	{ "Tiger", &tiger },
+	{ "Cheetah", &cheetah },
+	{ "BC2 HSDC", &bc2 },
+};
+
+/* Map PCI id to chip and function to identify board */
+#define PCI_VENDOR_MELLANOX			0x15b3
+#define PCI_VENDOR_TOPSPIN			0x1867
+
+#define PCI_DEVICE_MELLANOX_MT23108		0x5a44
+#define PCI_DEVICE_MELLANOX_MT23108_PCICONF	0x5a45
+#define PCI_DEVICE_MELLANOX_MT23108_PCIBRIDGE	0x5a46
+#define PCI_DEVICE_MELLANOX_MT25208		0x6282
+#define PCI_DEVICE_MELLANOX_MT25208_COMPAT	0x6278
+#define PCI_DEVICE_MELLANOX_MT25208_PCICONF	0x6279
+#define PCI_DEVICE_MELLANOX_MT25204		0x6274
+#define PCI_DEVICE_MELLANOX_MT25204_PCICONF	0x6275
+
+struct pciid {
+	uint16_t vendor;
+	uint16_t device;
+	unsigned int flags;
+
+	struct board *(*identify)(struct tvdevice *);
+};
+
+static struct board *tavor_identify(struct tvdevice *);
+static struct board *arbel_identify(struct tvdevice *);
+static struct board *sinai_identify(struct tvdevice *);
+
+#define FLAG_RECOVERY		1
+#define FLAG_TAVOR_COMPAT	2
+
+struct pciid pciids[] = {
+	/* Tavor, only one has VPD */
+	{ PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT23108,
+		0, tavor_identify },
+	{ PCI_VENDOR_TOPSPIN,	PCI_DEVICE_MELLANOX_MT23108,
+		0, tavor_identify },
+	{ PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT23108_PCICONF,
+		FLAG_RECOVERY, tavor_identify },
+	{ PCI_VENDOR_TOPSPIN,	PCI_DEVICE_MELLANOX_MT23108_PCICONF,
+		FLAG_RECOVERY, tavor_identify },
+
+	/* Arbel, all have VPDs */
+	{ PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208,
+		0, arbel_identify },
+	{ PCI_VENDOR_TOPSPIN,	PCI_DEVICE_MELLANOX_MT25208,
+		0, arbel_identify },
+	{ PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208_COMPAT,
+		FLAG_TAVOR_COMPAT, arbel_identify },
+	{ PCI_VENDOR_TOPSPIN,	PCI_DEVICE_MELLANOX_MT25208_COMPAT,
+		FLAG_TAVOR_COMPAT, arbel_identify },
+	{ PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208_PCICONF,
+		FLAG_RECOVERY, arbel_identify },
+	{ PCI_VENDOR_TOPSPIN,	PCI_DEVICE_MELLANOX_MT25208_PCICONF,
+		FLAG_RECOVERY, arbel_identify },
+
+	/* Sinai, all have VPDs */
+	{ PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25204,
+		0, sinai_identify },
+	{ PCI_VENDOR_TOPSPIN,	PCI_DEVICE_MELLANOX_MT25204,
+		0, sinai_identify },
+	{ PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25204_PCICONF,
+		FLAG_RECOVERY, sinai_identify },
+	{ PCI_VENDOR_TOPSPIN,	PCI_DEVICE_MELLANOX_MT25204_PCICONF,
+		FLAG_RECOVERY, sinai_identify },
+	/* Some old Tiger and Cheetah boards use PCI device id 0x538x (24204) */
+	{ PCI_VENDOR_MELLANOX, 0x5e8c,
+		0, sinai_identify },
+	{ PCI_VENDOR_MELLANOX, 0x5e8d,
+		FLAG_RECOVERY, sinai_identify },
+};
+
+#define GUID_LEN		8
+
 #define TV_FLASH_GUID_OFF	0x24
 
+#define MAX_STR			0xB0
+
 #endif
Index: src/tvflash.c
===================================================================
--- src/tvflash.c	(revision 6845)
+++ src/tvflash.c	(working copy)
@@ -24,16 +24,17 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/time.h>
-#include <sys/mman.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
 #include <termios.h>
 #include <fcntl.h>
 #include <pci/pci.h>
+#include <sys/utsname.h>
 #include <limits.h>
 #include <ctype.h>
 #include <time.h>
@@ -41,35 +42,18 @@
 
 #include "firmware.h"
 
-struct tvdevice *tvdevices = NULL;
-
+/* Global variables */
+struct tvdevice *tvdevices = NULL, *tvdevices_tail = NULL;
+unsigned char force = 0, verbose = 1, use_config_space = 0;
 char *argv0;
+unsigned short cols;
 
-unsigned char force = 0, verbose = 1, config = 0;
+/* Local prototypes */
+static void usage(void);
 
 /* Topspin OID */
 static const uint8_t default_oid[] = { 0x00, 0x05, 0xad, 0x00 };
 
-#define PCI_VENDOR_MELLANOX			0x15b3
-#define PCI_VENDOR_TOPSPIN			0x1867
-#define PCI_DEVICE_MELLANOX_MT23108		0x5a44
-#define PCI_DEVICE_MELLANOX_MT23108_PCICONF	0x5a45
-#define PCI_DEVICE_MELLANOX_MT23108_PCIBRIDGE	0x5a46
-#define PCI_DEVICE_MELLANOX_MT25208_COMPAT	0x6278
-#define PCI_DEVICE_MELLANOX_MT25208		0x6282
-#define PCI_DEVICE_MELLANOX_MT25208_PCICONF	0x6279
-
-#define MAX_STR 0xB0
-
-unsigned short cols;
-
-unsigned char flash_bank;
-struct failsafe failsafe;
-unsigned int gpio_data[2], gpio_direction[2], gpio_polarity[2],
-	gpio_output_mode[2];
-struct pci_dev *cur_hca;
-uint8_t *bar0;
-
 /*
  * Simple utility functions
  */
@@ -85,21 +69,19 @@
 		word = (image[4 * j] << 24) | (image[4 * j + 1] << 16) |
 			(image[4 * j + 2] << 8) | image[4 * j + 3];
 		for (i = 0; i < 32; i++) {
-			if (crc & 0x8000) {
+			if (crc & 0x8000)
 				crc = (((crc << 1) | (word >> 31)) ^ 0x100b) & 0xffff;
-			} else {
+			else
 				crc = ((crc << 1) | (word >> 31)) & 0xffff;
-			}
 			word = word << 1;
 		}
 	}
 
 	for (i = 0; i < 16; i++) {
-		if (crc & 0x8000) {
+		if (crc & 0x8000)
 			crc = ((crc << 1) ^ 0x100b) & 0xffff;
-		} else {
+		else
 			crc = (crc << 1) & 0xffff;
-		}
 	}
 
 	crc = crc ^ 0xffff;
@@ -107,11 +89,43 @@
 	return (crc & 0xffff);
 }
 
-static int parse_guid(unsigned char *arg, unsigned char *new_guid)
+/*
+ * We need some LE to host macros and those vary depending on the architecture
+ * and there are no standardized ones. So we mix the ntoh* and hton* functions
+ * with an unconditional swab* to get the desired behavior. Not the most
+ * efficient, but it works and is portable.
+ */
+static uint16_t le16_to_cpu(uint16_t x)
 {
+	uint16_t i = htons(x);
+
+	return ((i >> 8) & 0xff) | ((i & 0xff) << 8);
+}
+
+#if 0
+static uint16_t cpu_to_le16(uint16_t x)
+{
+	uint16_t i = ntohs(x);
+
+	return ((i >> 8) & 0xff) | ((i & 0xff) << 8);
+}
+#endif
+
+static uint32_t swab32(uint32_t x)
+{
+	return ((x >> 24) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8) | (x << 24));
+}
+
+#define be16_to_cpu ntohs
+#define cpu_to_be16 htons
+#define be32_to_cpu ntohl
+#define cpu_to_be32 htonl
+
+static int parse_hex_str(char *arg, unsigned char *hexstr, int octets)
+{
 	if (strchr(arg, ':') != NULL) {
-		unsigned char *p;
-		int octet = 7, octetspercolon;
+		char *p;
+		int octetspercolon;
 
 		/* Determine the format of the GUID. Is it single or double octet? */
 		p = strrchr(arg, ':');
@@ -120,14 +134,14 @@
 		else if (*(p + 1) && *(p + 2) && !*(p + 3))
 			octetspercolon = 1;
 		else {
-			fprintf(stderr, "Unknown GUID format\n");
-			return 1;
+			fprintf(stderr, "Unknown hex string format\n");
+			return -1;
 		}
 
 		/*
-		 * We don't require a full GUID here. If the user doesn't specify
-		 * a full GUID, we'll put in the default OID and 0 pad the rest
-		 * and use as much of a GUID the user gives.
+		 * We don't require a full GUID here. If the user doesn't
+		 * specify a full GUID, we'll put the Topspin OID and 0 pad
+		 * the rest and use as much of a GUID the user gives
 		 */
 		do {
 			unsigned char value, hex;
@@ -141,7 +155,7 @@
 			if (octetspercolon == 2) {
 				/* There should be no more characters after this */
 				if (*(p + 4) != 0)
-					return 1;
+					return -1;
 
 				hex = toupper(*(p + 2));
 				if (hex >= '0' && hex <= '9')
@@ -149,7 +163,7 @@
 				else if (hex >= 'A' && hex <= 'F')
 					value = (hex - 'A' + 10) << 4;
 				else
-					return 1;
+					return -1;
 
 				hex = toupper(*(p + 3));
 				if (hex >= '0' && hex <= '9')
@@ -157,13 +171,13 @@
 				else if (hex >= 'A' && hex <= 'F')
 					value |= hex - 'A' + 10;
 				else
-					return 1;
+					return -1;
 
-				new_guid[octet--] = value;
+				hexstr[--octets] = value;
 			} else {
 				/* There should be no more characters after this */
 				if (*(p + 2) != 0)
-					return 1;
+					return -1;
 			}
 
 			hex = toupper(*p);
@@ -172,7 +186,7 @@
 			else if (hex >= 'A' && hex <= 'F')
 				value = (hex - 'A' + 10) << 4;
 			else
-				return 1;
+				return -1;
 
 			hex = toupper(*(p + 1));
 			if (hex >= '0' && hex <= '9')
@@ -180,37 +194,215 @@
 			else if (hex >= 'A' && hex <= 'F')
 				value |= hex - 'A' + 10;
 			else
-				return 1;
+				return -1;
 
-			new_guid[octet--] = value;
-		} while (p > arg && octet >= 0);
+			hexstr[--octets] = value;
+		} while (p > arg && octets > 0);
 
-		if (octet < 0 && p > arg)
-			/* Still data left */
+		/* Data left over */
+		if (p > arg)
 			return 1;
+	} else {
+		unsigned long low_guid = strtol(arg, NULL, 16);
 
-		if (octet > 0 && octet < 3) {
-			fprintf(stderr, "GUID is not 8 octets, but longer than 4 maximum to automatically generate\n");
+		/* FIXME: Check the result of strtol, or do something more intelligent */
+
+		hexstr[octets - 4] = (low_guid >> 24) & 0xff;
+		hexstr[octets - 3] = (low_guid >> 16) & 0xff;
+		hexstr[octets - 2] = (low_guid >> 8) & 0xff;
+		hexstr[octets - 1] = low_guid & 0xff;
+
+		octets -= 4;
+	}
+
+	return octets;
+}
+
+static int parse_guid(char *arg, unsigned char *new_guid)
+{
+	int octets;
+
+	octets = parse_hex_str(arg, new_guid, GUID_LEN);
+
+	if (octets < 0)
+		return 1;
+
+	if (octets > 0 && octets < 3) {
+		fprintf(stderr, "GUID is not 8 octets, but longer than 4 maximum to automatically generate\n");
+		return 1;
+	}
+
+	if (octets >= 3) {
+		memcpy(new_guid, default_oid, 4);
+
+		if (octets > 3)
+			/* Zero out the non specified portions */
+			memset(new_guid + 3, 0, octets - 3);
+	}
+
+	return 0;
+}
+
+static int parse_change_options(struct topspin_vsd *vsd, char *cmd)
+{
+	char *p = cmd, *end = strchr(cmd, 0);
+
+	while (p && p < end) {
+		char *pc, *pe;
+
+		pc = strchr(p, ',');
+		if (pc) {
+			*pc = 0;
+			pc++;
+		}
+
+		pe = strchr(p, '=');
+		if (!pe) {
+			fprintf(stderr, "Missing = in token '%s'\n", p);
 			return 1;
 		}
 
-		if (octet >= 3) {
-			memcpy(new_guid, default_oid, 4);
+		*pe = 0;
+		pe++;
 
-			if (octet > 3)
-				/* Zero out the non specified portions */
-				memset(new_guid + 3, 0, octet - 3);
+		if (strcasecmp(p, "auto_upgrade") == 0) {
+			if (strcasecmp(pe, "yes") == 0 ||
+			    strcasecmp(pe, "on") == 0 ||
+			    strcasecmp(pe, "1") == 0)
+				vsd->flags |= cpu_to_be32(VSD_FLAG_AUTOUPGRADE);
+			else if (strcasecmp(pe, "no") == 0 ||
+				 strcasecmp(pe, "off") == 0 ||
+				 strcasecmp(pe, "0") == 0)
+				vsd->flags &= ~cpu_to_be32(VSD_FLAG_AUTOUPGRADE);
+			else {
+				fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+				return 1;
+			}
+		} else if (strcasecmp(p, "boot_enable_port_1") == 0) {
+			if (strcasecmp(pe, "yes") == 0 ||
+			    strcasecmp(pe, "on") == 0 ||
+			    strcasecmp(pe, "1") == 0)
+				vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_1);
+			else if (strcasecmp(pe, "no") == 0 ||
+				 strcasecmp(pe, "off") == 0 ||
+				 strcasecmp(pe, "0") == 0)
+				vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_1);
+			else {
+				fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+				return 1;
+			}
+		} else if (strcasecmp(p, "boot_enable_port_2") == 0) {
+			if (strcasecmp(pe, "yes") == 0 ||
+			    strcasecmp(pe, "on") == 0 ||
+			    strcasecmp(pe, "1") == 0)
+				vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_2);
+			else if (strcasecmp(pe, "no") == 0 ||
+				 strcasecmp(pe, "off") == 0 ||
+				 strcasecmp(pe, "0") == 0)
+				vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_2);
+			else {
+				fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+				return 1;
+			}
+		} else if (strcasecmp(p, "boot_service_scan") == 0) {
+			if (strcasecmp(pe, "yes") == 0 ||
+			    strcasecmp(pe, "on") == 0 ||
+			    strcasecmp(pe, "1") == 0)
+				vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_ENABLE_SCAN);
+			else if (strcasecmp(pe, "no") == 0 ||
+				 strcasecmp(pe, "off") == 0 ||
+				 strcasecmp(pe, "0") == 0)
+				vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_ENABLE_SCAN);
+			else {
+				fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+				return 1;
+			}
+		} else if (strcasecmp(p, "boot_wait_on_error") == 0) {
+			if (strcasecmp(pe, "yes") == 0 ||
+			    strcasecmp(pe, "on") == 0 ||
+			    strcasecmp(pe, "1") == 0)
+				vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_WAIT_ON_ERROR);
+			else if (strcasecmp(pe, "no") == 0 ||
+				 strcasecmp(pe, "off") == 0 ||
+				 strcasecmp(pe, "0") == 0)
+				vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_WAIT_ON_ERROR);
+			else {
+				fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+				return 1;
+			}
+		} else if (strcasecmp(p, "boot_try_forever") == 0) {
+			if (strcasecmp(pe, "yes") == 0 ||
+			    strcasecmp(pe, "on") == 0 ||
+			    strcasecmp(pe, "1") == 0)
+				vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_TRY_FOREVER);
+			else if (strcasecmp(pe, "no") == 0 ||
+				 strcasecmp(pe, "off") == 0 ||
+				 strcasecmp(pe, "0") == 0)
+				vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_TRY_FOREVER);
+			else {
+				fprintf(stderr, "Unknown boolean value '%s'\n", pe);
+				return 1;
+			}
+		} else if (strcasecmp(p, "boot_type") == 0) {
+			vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_TYPE);
+			if (strcasecmp(pe, "well_known") == 0)
+				vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_TYPE_WELL_KNOWN);
+			else if (strcasecmp(pe, "saved") == 0)
+				vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_TYPE_SAVED);
+			else if (strcasecmp(pe, "pxe") == 0)
+				vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_TYPE_PXE);
+			else if (strcasecmp(pe, "disable") == 0)
+				vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_TYPE_DISABLE);
+			else {
+				fprintf(stderr, "Unknown boot type '%s'\n", pe);
+				return 1;
+			}
+		} else if (strcasecmp(p, "boot_saved_port") == 0) {
+			unsigned long port;
+
+			port = strtoul(pe, NULL, 10);
+			if (port > 2) {
+				fprintf(stderr, "Invalid port number '%s'\n", pe);
+				return 1;
+			}
+
+			vsd->boot_port = port;
+		} else if (strcasecmp(p, "boot_saved_ioc_num") == 0) {
+			unsigned long ioc;
+
+			ioc = strtoul(pe, NULL, 10);
+			if (ioc == ULONG_MAX) {
+				fprintf(stderr, "Invalid ioc number '%s'\n", pe);
+				return 1;
+			}
+
+			vsd->boot_ioc_num = ioc;
+		} else if (strcasecmp(p, "boot_saved_dgid") == 0) {
+			if (parse_hex_str(pe, vsd->boot_dgid, 16) < 0) {
+				fprintf(stderr, "Couldn't parse dgid\n");
+				return 1;
+			}
+		} else if (strcasecmp(p, "boot_saved_service_name") == 0) {
+			if (parse_hex_str(pe, vsd->boot_service_name, 8) < 0) {
+				fprintf(stderr, "Couldn't parse service name\n");
+				return 1;
+			}
+		} else if (strcasecmp(p, "boot_pxe_secs") == 0) {
+			unsigned long secs;
+
+			secs = strtoul(pe, NULL, 10);
+			if (secs > 250) {
+				fprintf(stderr, "Invalid number of seconds '%s'\n", pe);
+				return 1;
+			}
+
+			vsd->boot_pxe_secs = secs;
+		} else {
+			fprintf(stderr, "Unknown option '%s'\n", p);
+			return 1;
 		}
-	} else {
-		unsigned long low_guid = strtol(arg, NULL, 16);
 
-		/* FIXME: Check the result of strtol, or do something more intelligent */
-
-		memcpy(new_guid, default_oid, 4);
-		new_guid[4] = (low_guid >> 24) & 0xff;
-		new_guid[5] = (low_guid >> 16) & 0xff;
-		new_guid[6] = (low_guid >> 8) & 0xff;
-		new_guid[7] = low_guid & 0xff;
+		p = pc;
 	}
 
 	return 0;
@@ -220,6 +412,7 @@
 {
 	int i, carry = 1;
 
+	/* FIXME: Do we really want to try to increment the vendor oid too? */
 	for (i = 7; i >= 0; i--) {
 		if (carry && guid[i] == 0xFF) {
 			new_guid[i] = 0;
@@ -231,66 +424,89 @@
 	}
 }
 
-static int update_status(char *string, int pos, int max, int curbar)
+unsigned int status_curpos, status_relpos, status_maxpos;
+unsigned int status_curbar;
+unsigned char status_prev;
+
+static void status_start(unsigned int max)
 {
+	status_curpos = 0;
+	status_relpos = 0;
+	status_maxpos = max;
+
+	status_curbar = 0;
+	status_prev = 0;
+
+	if (verbose)
+		printf("Flashing - ");
+}
+
+static void status_update(unsigned char status, unsigned int curpos)
+{
 	unsigned int bar;
 
-	if (cols) {
-		bar = (pos * (cols - 14)) / max;
-		if (bar != curbar) {
-			int i;
+	if (!verbose)
+		return;
 
-			printf("%-10s [", string);
-			for (i = 0; i < bar; i++)
-				printf("=");
+	curpos += status_relpos;
 
-			printf("%*s]\r", (cols - 14) - bar, "");
-			fflush(stdout);
-			curbar = bar;
-		}
-	} else {
-		/* Fall back to something simpler */
-		bar = (pos * 100) / max;
-		if (bar != curbar) {
-			printf("%-10s %3d%%\r", string, bar);
-			fflush(stdout);
-			curbar = bar;
-		}
+	bar = (curpos * (cols - 12)) / status_maxpos;
+	status_curpos = curpos;
+
+	/* Force a character to be printed during a status change */
+	if (status != status_prev && status_curbar >= bar)
+		bar = status_curbar + 1;
+
+	if (status_curbar < bar) {
+		for (; status_curbar < bar; status_curbar++)
+			printf("%c", status);
+
+		fflush(stdout);
 	}
 
-	return curbar;
+	status_prev = status;
 }
 
+static void status_mark(void)
+{
+	status_relpos = status_curpos;
+}
+
+static void status_stop(void)
+{
+	if (verbose)
+		printf("\n");
+}
+
 /*
  * HCA card management
  */
 
+static int vpd_read(struct tvdevice *tvdev);
+
 static int scan_devices(struct pci_access *pacc)
 {
 	struct pci_dev *pdev;
 	struct tvdevice *tvdev;
-	int count = 0, pci_count = 0, pciconf_count = 0;
-	int i;
+	int pci_count = 0, pciconf_count = 0;
+	unsigned short kernel;
+	struct utsname utsname;
 
-#define HCA_PCI_DEV(v, d, c) .vendor = v, .device = d, .can_map = c
+	/*
+	 * libpci, depending on the kernel it's running under, will create the
+	 * PCI device list in the correct order, or backwards. As a result, we
+	 * need to create our list appropriately too so the order of the HCAs
+	 * matches what the kernel sees the HCA list (ie ib0 is HCA #0, etc)
+	 */
+	if (uname(&utsname) < 0) {
+		fprintf(stderr, "couldn't get uname information, assuming 2.4 kernel\n");
+		kernel = 0x0204;
+	} else {
+		unsigned int major, minor;
 
-	static const struct {
-		uint16_t vendor;
-		uint16_t device;
-		int      can_map;
-	} hca_dev_table[] = {
-		{ HCA_PCI_DEV(PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT23108, 1) },
-		{ HCA_PCI_DEV(PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208_COMPAT, 1) },
-		{ HCA_PCI_DEV(PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208, 1) },
-		{ HCA_PCI_DEV(PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT23108_PCICONF, 0) },
-		{ HCA_PCI_DEV(PCI_VENDOR_MELLANOX, PCI_DEVICE_MELLANOX_MT25208_PCICONF, 0) },
-		{ HCA_PCI_DEV(PCI_VENDOR_TOPSPIN,  PCI_DEVICE_MELLANOX_MT23108, 1) },
-		{ HCA_PCI_DEV(PCI_VENDOR_TOPSPIN,  PCI_DEVICE_MELLANOX_MT25208_COMPAT, 1) },
-		{ HCA_PCI_DEV(PCI_VENDOR_TOPSPIN,  PCI_DEVICE_MELLANOX_MT25208, 1) },
-		{ HCA_PCI_DEV(PCI_VENDOR_TOPSPIN,  PCI_DEVICE_MELLANOX_MT23108_PCICONF, 0) },
-		{ HCA_PCI_DEV(PCI_VENDOR_TOPSPIN,  PCI_DEVICE_MELLANOX_MT25208_PCICONF, 0) },
-		{ 0 }
-	};
+		sscanf(utsname.release, "%d.%d", &major, &minor);
+		kernel = ((major & 0xff) << 8) | (minor & 0xff);
+	}
 
 	/*
 	 * Example of how various configurations appear on the PCI bus.
@@ -316,48 +532,58 @@
 	 * 03:01:0 5a45 00a1 (PCI conf)
 	 */
 	for (pdev = pacc->devices; pdev; pdev = pdev->next) {
+		int i;
+
 		pci_fill_info(pdev, PCI_FILL_IDENT);
 
-		for (i = 0; hca_dev_table[i].vendor; ++i) {
-			if (hca_dev_table[i].vendor == pdev->vendor_id &&
-			    hca_dev_table[i].device == pdev->device_id)
-				break;
-		}
+		for (i = 0; i < sizeof(pciids) / sizeof(pciids[0]); i++) {
+			if (pciids[i].vendor != pdev->vendor_id ||
+					pciids[i].device != pdev->device_id)
+				continue;
 
-		if (!hca_dev_table[i].vendor)
-			continue;
+			tvdev = malloc(sizeof(*tvdev));
+			if (!tvdev) {
+				fprintf(stderr, "couldn't allocate %d bytes for device struct\n", (int) sizeof *tvdev);
+				return -1;
+			}
+			memset(tvdev, 0, sizeof(*tvdev));
+			tvdev->pdev = pdev;
+			tvdev->pciid = &pciids[i];
+			tvdev->flags = pciids[i].flags;
 
-		/*
-		 * MT23108 based boards can appear in one of two ways:
-		 * - Normal mode (flash jumper removed) will result in the PCI bridge
-		 *   and MT23108 PCI devices appearing.
-		 * - Recovery mode (flash jumper shorted) will result in only the PCI
-		 *   conf device appearing.
-		 *
-		 * We can use any of these devices, so we store a pointer if we find
-		 * the bridge of conf device. If we hit another one or we find a
-		 * MT23108 device, we load the appropriate modules and start the
-		 * device (if on the switch).
-		 */
+			vpd_read(tvdev);
 
-		tvdev = calloc(sizeof *tvdev, 1);
-		if (!tvdev) {
-			fprintf(stderr, "couldn't allocate %d bytes for device struct\n",
-				(int) sizeof *tvdev);
-			return -1;
+			tvdev->revision = pci_read_word(pdev, PCI_CLASS_REVISION) & 0xff;
+
+			/* According to the documentation, a revision of 0x00 is an A0 */
+			if (tvdev->revision == 0x00)
+				tvdev->revision = 0xA0;
+			else if (tvdev->revision == 0x01)
+				tvdev->revision = 0xA1;
+
+			if (kernel <= 0x0204) {
+				tvdev->next = tvdevices;
+				if (!tvdevices_tail)
+					tvdevices_tail = tvdev;
+				tvdevices = tvdev;
+			} else {
+				if (tvdevices_tail)
+					tvdevices_tail->next = tvdev;
+				else /* first device we found */
+					tvdevices = tvdev;
+				tvdevices_tail = tvdev;
+			}
 		}
-		tvdev->pdev = pdev;
-		tvdev->can_map = hca_dev_table[i].can_map;
-		if (tvdev->can_map)
+	}
+
+	for (tvdev = tvdevices; tvdev; tvdev = tvdev->next) {
+		if (tvdev->flags & FLAG_RECOVERY)
+			tvdev->num = pciconf_count++;
+		else
 			tvdev->num = pci_count++;
-		else
-			tvdev->num = pciconf_count++;
-		tvdev->next = tvdevices;
-		tvdevices = tvdev;
-		count++;
 	}
 
-	return count;
+	return pci_count + pciconf_count;
 }
 
 static struct tvdevice *find_device(int hca)
@@ -378,8 +604,8 @@
  * VPD code
  */
 
-static int READ_VPD(struct pci_dev *pdev, unsigned int vpd_off, unsigned int addr,
-		    unsigned int *data)
+static int read_vpd_data(struct pci_dev *pdev, unsigned int vpd_off,
+	unsigned int addr, unsigned int *data)
 {
 	int i;
 	unsigned int val;
@@ -398,20 +624,19 @@
 		}
 		gettimeofday(&tcur, NULL);
 		elapsed = ((tcur.tv_sec - tstart.tv_sec) * 1000L) +
-			((tcur.tv_usec - tstart.tv_usec) / 1000L);
+				((tcur.tv_usec - tstart.tv_usec) / 1000L);
 	} while (elapsed < 100);
 
 	if (verbose > 1)
-		fprintf(stderr, "READ_VPD: timed out at off %x\n", addr);
+		fprintf(stderr, "read_vpd_data: timed out at off %x\n", addr);
 
 	return 1;
 }
 
 static int vpd_exists(struct pci_dev *pdev, int *vpd_off)
 {
-	int	cap_ptr;
-	int   cap_id;
-	int   val;
+	int cap_ptr, cap_id;
+	int val;
 
 	cap_ptr = pci_read_long(pdev, PCI_CAPABILITY_LIST) & 0xff;
 	while (cap_ptr != 0) {
@@ -427,23 +652,27 @@
 	return 0;
 }
 
-static int vpd_read(struct tvdevice *tvdev, struct pci_dev *pdev)
+static int vpd_read(struct tvdevice *tvdev)
 {
 	int vpd_off;
 
-	tvdev->vpd = 0;
+	tvdev->vpd_present = 0;
 
-	if (vpd_exists(pdev, &vpd_off)) {
+	if (vpd_exists(tvdev->pdev, &vpd_off)) {
 		unsigned int *ptr;
-		int i;
+		int i, swap_endian = 0;
 
-		ptr = (unsigned int *)tvdev->vpd_data;
+		ptr = tvdev->vpd.vpd_int;
 
-		if (READ_VPD(pdev, vpd_off, 0, ptr++) != 0)
+		if (read_vpd_data(tvdev->pdev, vpd_off, 0, ptr++) != 0)
 			return 0;
 
+		/* Check to see if we got the endianess swapped on us */
+		if (tvdev->vpd.vpd_char[0] != 0x82 && tvdev->vpd.vpd_char[3] == 0x82)
+			swap_endian = 1;
+
 		for (i = 1; i < 64; i++) {
-			if (READ_VPD(pdev, vpd_off, (i * 4), ptr++) != 0) {
+			if (read_vpd_data(tvdev->pdev, vpd_off, (i * 4), ptr++) != 0) {
 				if (i < 32)
 					return 0;
 				else
@@ -451,339 +680,552 @@
 			}
 		}
 
-		tvdev->vpd = 1;
+		tvdev->vpd_present = 1;
+
+		if (swap_endian) {
+			ptr = tvdev->vpd.vpd_int;
+			for (i = 0; i < 64; i++) {
+				*ptr = swab32(*ptr);
+				ptr++;
+			}
+		}
 	}
 
-	return tvdev->vpd;
+	return tvdev->vpd_present;
 }
 
-static int open_hca(struct tvdevice *tvdev)
+/*
+ * Read/Write from the configuration space
+ */
+static unsigned int read_cfg(struct tvdevice *tvdev, unsigned int addr)
 {
-	cur_hca = tvdev->pdev;
+	unsigned int val;
 
-	if (!config && tvdev->can_map) {
-		int fd = open("/dev/mem", O_RDWR, O_SYNC);
-		if (fd < 0) {
-			perror("open /dev/mem");
-			return errno;
+	switch (tvdev->method) {
+	case METHOD_MMAP:
+		val = ntohl(*(uint32_t *)(tvdev->bar0 + addr));
+		break;
+	case METHOD_PCI_CFG:
+		if (!pci_write_long(tvdev->pdev, 22 * 4, addr)) {
+			fprintf(stderr, "read_cfg: pci_write_long failed\n");
+			exit(1);
 		}
-		bar0 = mmap(NULL,
-			    1 << 20,
-			    PROT_READ | PROT_WRITE,
-			    MAP_SHARED,
-			    fd,
-			    tvdev->pdev->base_addr[0] & ~0xfUL);
-		close(fd);
-		if (bar0 == MAP_FAILED) {
-			perror("mmap");
-			return errno;
-		}
-	} else
-		bar0 = NULL;
 
-	return 0;
+		val = pci_read_long(tvdev->pdev, 23 * 4);
+		break;
+	default:
+		abort();
+	}
+
+	return val;
 }
 
-static void close_hca(void)
+static void write_cfg(struct tvdevice *tvdev, unsigned int addr,
+	unsigned int data)
 {
-	if (bar0)
-		munmap(bar0, 1 << 20);
+	switch (tvdev->method) {
+	case METHOD_MMAP:
+		*(uint32_t *)(tvdev->bar0 + addr) = htonl(data);
+		break;
+	case METHOD_PCI_CFG:
+		if (!pci_write_long(tvdev->pdev, 22 * 4, addr) ||
+				!pci_write_long(tvdev->pdev, 23 * 4, data)) {
+			fprintf(stderr, "write_cfg: pci_write_long failed\n");
+			exit(1);
+		}
+		break;
+	default:
+		abort();
+	}
 }
 
-/* InfiniHost Read from Internal Configuration Space */
-static uint32_t READ_CFG(unsigned int addr)
-{
-	if (bar0)
-		return ntohl(*(uint32_t *) (bar0 + addr));
+#define NUM_SPIS	4
 
-	if (!pci_write_long(cur_hca, 22 * 4, addr)) {
-		fprintf(stderr, "READ_CFG failed\n");
-		exit(1);
-	}
+#define FLASH_GW	 0xF0400
+#define FLASH_ADDR 0xF0404
+#define FLASH_DATA 0xF0408
+#define FLASH_CS	 0xF0418
 
-	return pci_read_long(cur_hca, 23 * 4);
-} /* READ_CFG */
+#define READ_OP		 (1 << 0)
 
-/* InfiniHost Write to the Internal Configuration Space */
-static void WRITE_CFG(unsigned int addr, unsigned int data)
+#define SPI_NO_DATA (1 << 4)
+#define SPI_NO_ADDR (1 << 5)
+#define SPI_SPECIAL (1 << 6)
+#define BUSY				(1 << 30)
+
+#define WIP				 (1 << 24)
+#define WEL				 (1 << 25)
+
+#define FC_SE		0xD8
+#define FC_PP		0x02
+#define FC_RDSR	0x05
+#define FC_WREN	0x06
+
+#define WAIT_INTERVAL 10
+
+static void flash_set_bank(struct tvdevice *tvdev, unsigned int addr)
 {
-	if (bar0)
-		*(uint32_t *) (bar0 + addr) = htonl(data);
-	else if (!pci_write_long(cur_hca, 22 * 4, addr) ||
-		 !pci_write_long(cur_hca, 23 * 4, data)) {
-		fprintf(stderr, "WRITE_CFG failed\n");
-		exit(1);
+	unsigned char bank = addr >> tvdev->flash_bank_shift;
+
+	if (bank == tvdev->flash_bank)
+		return;
+
+	switch (tvdev->flash_command_set) {
+	case CS_SPI:
+		write_cfg(tvdev, FLASH_CS, bank << 30);
+		break;
+	default:
+		/* Set the appropriate data bits */
+		write_cfg(tvdev, GPIO_DAT + 4, (read_cfg(tvdev, GPIO_DAT + 4) & ~(0x07 << 4)) | (bank << 4));
+		break;
 	}
-} /* WRITE_CFG */
 
-static void flash_set_bank(unsigned char bank)
-{
-	/* Set the appropriate data bits */
-	WRITE_CFG(0xF0080 + 0x04,
-		  (READ_CFG(0xF0080 + 0x04) & ~(0x07 << 4)) | (bank << 4));
-
-	flash_bank = bank;
+	tvdev->flash_bank = bank;
 }
 
 /* read a dword from the flash, address must be 4 bytes aligned */
-static unsigned int flash_read(unsigned int addr)
+static unsigned int flash_read(struct tvdevice *tvdev, unsigned int addr)
 {
-	unsigned int cmd;
+	unsigned int cmd, status;
 
-	if ((addr >> 19) != flash_bank)
-		flash_set_bank(addr >> 19);
+	flash_set_bank(tvdev, addr);
 
-	WRITE_CFG(0xF01A4, (addr & (TV_FLASH_BANK_MASK & ~3)) | (1 << 29));
-	do {
-		cmd = READ_CFG(0xF01A4);
-	} while (cmd & 0xE0000000);
+	switch (tvdev->flash_command_set) {
+	case CS_SPI:
+		write_cfg(tvdev, FLASH_ADDR, (addr & tvdev->flash_bank_mask));
+		write_cfg(tvdev, FLASH_GW, READ_OP | BUSY | (2 << 8));
 
-	return READ_CFG(0xF01A8);
+		do {
+			status = read_cfg(tvdev, FLASH_GW);
+		} while (status & BUSY);
+
+		return read_cfg(tvdev, FLASH_DATA);
+	default:
+		write_cfg(tvdev, 0xF01A4, (addr & (tvdev->flash_bank_mask & ~3)) | (1 << 29));
+		do {
+			cmd = read_cfg(tvdev, 0xF01A4);
+		} while (cmd & 0xE0000000);
+
+		return read_cfg(tvdev, 0xF01A8);
+	}
 }
 
 /* read a byte from the flash */
-static unsigned char flash_byte_read(unsigned int addr)
+static unsigned char flash_byte_read(struct tvdevice *tvdev, unsigned int addr)
 {
 	unsigned int data;
 
-	data = flash_read(addr & ~3);
+	data = flash_read(tvdev, addr & ~3);
 	return ((data >> ((3 - (addr & 3)) * 8)) & 0xFF);
 }
 
 /* writes a command to the flash */
-static void flash_write_cmd(unsigned int addr, unsigned char data)
+static void flash_write_cmd(struct tvdevice *tvdev, unsigned int addr,
+	unsigned char data)
 {
 	unsigned int cmd;
 
-	WRITE_CFG(0xF01A8, data << 24);
-	WRITE_CFG(0xF01A4, (addr & TV_FLASH_BANK_MASK) | (2 << 29));
+	write_cfg(tvdev, 0xF01A8, data << 24);
+	write_cfg(tvdev, 0xF01A4, (addr & tvdev->flash_bank_mask) | (2 << 29));
 	do {
-		cmd = READ_CFG(0xF01A4);
+		cmd = read_cfg(tvdev, 0xF01A4);
 	} while (cmd & 0xE0000000);
 }
 
-static void flash_chip_reset(void)
+static void flash_chip_reset(struct tvdevice *tvdev)
 {
-	/* Issue Flash Reset Command*/
-	flash_write_cmd(0x0, 0xf0);
+	/* Issue Flash Reset Command */
+	switch (tvdev->flash_command_set) {
+	case CS_INTEL:
+		flash_write_cmd(tvdev, 0x555, 0xFF);
+		break;
+	case CS_AMD:
+		flash_write_cmd(tvdev, 0x555, 0xF0);
+		break;
+	default:
+		break;
+	}
 }
 
-#define WAIT_INTERVAL 10
+static void spi_wait_wip(struct tvdevice *tvdev)
+{
+	unsigned int status;
+	unsigned int count = 0;
 
-static void flash_erase_sector(unsigned int addr)
+	do {
+		status = read_cfg(tvdev, FLASH_GW);
+	} while (status & BUSY);
+
+	do {
+		if (++count > 5000)
+			usleep(WAIT_INTERVAL);
+
+		write_cfg(tvdev, FLASH_ADDR, FC_RDSR << 24);
+		write_cfg(tvdev, FLASH_GW, READ_OP | SPI_NO_ADDR | SPI_SPECIAL | BUSY);
+
+		do {
+			status = read_cfg(tvdev, FLASH_GW);
+		} while (status & BUSY);
+
+		status = read_cfg(tvdev, FLASH_DATA);
+	} while (status & WIP);
+}
+
+static void flash_erase_sector(struct tvdevice *tvdev, unsigned int addr)
 {
-	unsigned int stat;
+	unsigned int status;
 
-	if ((addr >> 19) != flash_bank)
-		flash_set_bank(addr >> 19);
+	flash_set_bank(tvdev, addr);
 
-	/* Issue Flash Sector Erase Command*/
-	flash_write_cmd(0x555, 0xAA);
-	flash_write_cmd(0x2AA, 0x55);
-	flash_write_cmd(0x555, 0x80);
-	flash_write_cmd(0x555, 0xAA);
-	flash_write_cmd(0x2AA, 0x55);
-	flash_write_cmd(addr & TV_FLASH_BANK_MASK, 0x30);
+	/* Issue Flash Sector Erase Command */
+	switch (tvdev->flash_command_set) {
+	case CS_SPI:
+		/* Issue Write Enable */
+		write_cfg(tvdev, FLASH_ADDR, FC_WREN << 24);
+		write_cfg(tvdev, FLASH_GW, SPI_NO_ADDR | SPI_NO_DATA | SPI_SPECIAL | BUSY);
 
-	/* Wait for sector erase completion */
-	do {
-		stat = flash_read(addr);
-		usleep(WAIT_INTERVAL);
-	} while (stat != 0xFFFFFFFF);
+		do {
+			status = read_cfg(tvdev, FLASH_GW);
+		} while (status & BUSY);
+
+		/* Issue Sector Erase */
+		write_cfg(tvdev, FLASH_ADDR, (FC_SE << 24) | (addr & tvdev->flash_bank_mask));
+		write_cfg(tvdev, FLASH_GW, SPI_NO_DATA | SPI_SPECIAL | BUSY);
+
+		/* Wait for sector erase completion */
+		spi_wait_wip(tvdev);
+		break;
+	case CS_INTEL:
+		flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, 0x20); /* Erase */
+		flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, 0xD0); /* Confirm */
+
+		/* Wait for sector erase completion */
+		do {
+			usleep(WAIT_INTERVAL);
+			status = flash_read(tvdev, addr);
+		} while (!(status & 0x80));
+		break;
+	case CS_AMD:
+		flash_write_cmd(tvdev, 0x555, 0xAA);
+		flash_write_cmd(tvdev, 0x2AA, 0x55);
+		flash_write_cmd(tvdev, 0x555, 0x80);
+		flash_write_cmd(tvdev, 0x555, 0xAA);
+		flash_write_cmd(tvdev, 0x2AA, 0x55);
+		flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, 0x30);
+
+		/* Wait for sector erase completion */
+		do {
+			usleep(WAIT_INTERVAL);
+			status = flash_read(tvdev, addr);
+		} while (status != 0xFFFFFFFF);
+		break;
+	default:
+		break;
+	}
+
+	flash_chip_reset(tvdev);
 }
 
-static void flash_write_byte(unsigned int addr, unsigned char data)
+static int log2up(unsigned long in)
 {
-	unsigned int stat;
+	unsigned int i;
 
-	if ((addr >> 19) != flash_bank)
-		flash_set_bank(addr >> 19);
+	for (i = 0; i < 32; i++) {
+		if (in <= (unsigned long)(1 << i))
+			break;
+	}
 
-	/* Issue Byte Program Command */
-	flash_write_cmd(0x555, 0xAA);
-	flash_write_cmd(0x2AA, 0x55);
-	flash_write_cmd(0x555, 0xA0);
-	flash_write_cmd(addr & TV_FLASH_BANK_MASK, data);
+	return i;
+}
 
-	/* Wait for the Byte Program to Complete (Verify Byte Program) */
+static void flash_spi_write_block(struct tvdevice *tvdev, unsigned int addr,
+	unsigned char *sector, unsigned int len)
+{
+	unsigned int i, status;
+
+	/* Enable write */
+	write_cfg(tvdev, FLASH_ADDR, FC_WREN << 24);
+	write_cfg(tvdev, FLASH_GW, SPI_NO_ADDR | SPI_NO_DATA | SPI_SPECIAL | BUSY);
+
 	do {
-		stat = flash_read(addr & ~3);
-	} while (data != ((stat >> ((3 - (addr & 3)) * 8)) & 0xFF));
-} /* flash_write_byte */
+		status = read_cfg(tvdev, FLASH_GW);
+	} while (status & BUSY);
 
-static void mtflash_init(void)
+	write_cfg(tvdev, FLASH_ADDR, (FC_PP << 24) | (addr & tvdev->flash_bank_mask));
+
+	for (i = 0; i < len; i += 4) {
+		uint32_t dword = *((uint32_t *)(sector + i));
+
+		write_cfg(tvdev, FLASH_DATA + i, be32_to_cpu(dword));
+	}
+
+	write_cfg(tvdev, FLASH_GW, SPI_SPECIAL | BUSY | (log2up(len) << 8));
+
+	/* Wait for erase to complete */
+	spi_wait_wip(tvdev);
+}
+
+static void flash_write_byte(struct tvdevice *tvdev, unsigned int addr,
+	unsigned char data)
 {
-	READ_CFG (0xF0150);
-	WRITE_CFG(0xF0150, 1 << 30);
+	unsigned int status;
+
+	switch (tvdev->flash_command_set) {
+	case CS_INTEL:
+		flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, 0x40);
+		flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, data);
+
+		/* Wait for the Byte Program to Complete (Verify Byte Program) */
+		do {
+			status = flash_read(tvdev, addr & ~3);
+		} while (!(status & 0x80));
+		break;
+	case CS_AMD:
+		/* Issue Byte Program Command */
+		flash_write_cmd(tvdev, 0x555, 0xAA);
+		flash_write_cmd(tvdev, 0x2AA, 0x55);
+		flash_write_cmd(tvdev, 0x555, 0xA0);
+		flash_write_cmd(tvdev, addr & tvdev->flash_bank_mask, data);
+
+		/* Wait for the Byte Program to Complete (Verify Byte Program) */
+		do {
+			status = flash_read(tvdev, addr & ~3);
+		} while (data != ((status >> ((3 - (addr & 3)) * 8)) & 0xFF));
+		break;
+	default:
+		/* Not possible, but compiler complains */
+		break;
+	}
 }
 
-static void grab_gpio(void)
+static void grab_gpio(struct tvdevice *tvdev)
 {
 	/* Grab the semaphore first */
-	while (READ_CFG(0xF03FC) == 1)
+	while (read_cfg(tvdev, 0xF03FC) == 1)
 		;
 
-	WRITE_CFG(0xF03FC, 1);
+	write_cfg(tvdev, 0xF03FC, 1);
 
 	/* Now copy out the values */
-	gpio_data[0] = READ_CFG(0xF0080) & 0xFF;
-	gpio_data[1] = READ_CFG(0xF0084);
+	tvdev->gpio_data[0] = read_cfg(tvdev, GPIO_DAT) & 0xFF;
+	tvdev->gpio_data[1] = read_cfg(tvdev, GPIO_DAT + 4);
 
-	gpio_direction[0] = READ_CFG(0xF0088) & 0xFF;
-	gpio_direction[1] = READ_CFG(0xF008C);
+	tvdev->gpio_direction[0] = read_cfg(tvdev, GPIO_DIR) & 0xFF;
+	tvdev->gpio_direction[1] = read_cfg(tvdev, GPIO_DIR + 4);
 
-	gpio_polarity[0] = READ_CFG(0xF0090) & 0xFF;
-	gpio_polarity[1] = READ_CFG(0xF0094);
+	tvdev->gpio_polarity[0] = read_cfg(tvdev, GPIO_POL) & 0xFF;
+	tvdev->gpio_polarity[1] = read_cfg(tvdev, GPIO_POL + 4);
 
-	gpio_output_mode[0] = READ_CFG(0xF0098) & 0xFF;
-	gpio_output_mode[1] = READ_CFG(0xF009C);
+	tvdev->gpio_output_mode[0] = read_cfg(tvdev, GPIO_MOD) & 0xFF;
+	tvdev->gpio_output_mode[1] = read_cfg(tvdev, GPIO_MOD + 4);
+}
 
-	/* Set the direction of the flash pins to output */
-	WRITE_CFG(0xF0080 + 0x0C, READ_CFG(0xF0080 + 0x0C) | (0x07 << 4));
+static void release_gpio(struct tvdevice *tvdev)
+{
+	if (tvdev->board->chip == CHIP_SINAI) {
+		flash_set_bank(tvdev, 0);
 
-	/* Clear the data for the flash pins to start at bank 0 */
-	WRITE_CFG(0xF0080 + 0x54, 0x07 << 4);
+		/* Unlock GPIO */
+		write_cfg(tvdev, GPIO_LOCK, 0xAAAA);
+	}
 
-	/* Clear the polarity for the flash pins */
-	WRITE_CFG(0xF0080 + 0x14, READ_CFG(0xF0080 + 0x14) & ~(0x07 << 4));
-
-	/* Clear the output mode for the flash pins */
-	WRITE_CFG(0xF0080 + 0x1C, READ_CFG(0xF0080 + 0x1C) & ~(0x07 << 4));
-
-	flash_bank = 0;
-}
-
-static void release_gpio(void)
-{
 	/* Write back the saved values */
-	WRITE_CFG(0xF0080, (READ_CFG(0xF0080) & ~0xFF) | gpio_data[0]);
-	WRITE_CFG(0xF0084, gpio_data[1]);
+	write_cfg(tvdev, GPIO_DAT, (read_cfg(tvdev, GPIO_DAT) & ~0xFF) | tvdev->gpio_data[0]);
+	write_cfg(tvdev, GPIO_DAT + 4, tvdev->gpio_data[1]);
 
-	WRITE_CFG(0xF0088, (READ_CFG(0xF0088) & ~0xFF) | gpio_direction[0]);
-	WRITE_CFG(0xF008C, gpio_direction[1]);
+	write_cfg(tvdev, GPIO_DIR, (read_cfg(tvdev, GPIO_DIR) & ~0xFF) | tvdev->gpio_direction[0]);
+	write_cfg(tvdev, GPIO_DIR + 4, tvdev->gpio_direction[1]);
 
-	WRITE_CFG(0xF0090, (READ_CFG(0xF0090) & ~0xFF) | gpio_polarity[0]);
-	WRITE_CFG(0xF0094, gpio_polarity[1]);
+	write_cfg(tvdev, GPIO_POL, (read_cfg(tvdev, GPIO_POL) & ~0xFF) | tvdev->gpio_polarity[0]);
+	write_cfg(tvdev, GPIO_POL + 4, tvdev->gpio_polarity[1]);
 
-	WRITE_CFG(0xF0098, (READ_CFG(0xF0098) & ~0xFF) | gpio_output_mode[0]);
-	WRITE_CFG(0xF009C, gpio_output_mode[1]);
+	write_cfg(tvdev, GPIO_MOD, (read_cfg(tvdev, GPIO_MOD) & ~0xFF) | tvdev->gpio_output_mode[0]);
+	write_cfg(tvdev, GPIO_MOD + 4, tvdev->gpio_output_mode[1]);
 
 	/* Release the semaphore */
-	WRITE_CFG(0xF03FC, 0);
+	write_cfg(tvdev, 0xF03FC, 0);
 }
 
-static int identify_board(struct tvdevice *tvdev)
+static struct board *vpd_identify(struct tvdevice *tvdev)
 {
-	unsigned char cougar;
+	char str[MAX_STR];
+	int i;
 
-	/* Check the PCI device id first */
-	if (tvdev->pdev->device_id == PCI_DEVICE_MELLANOX_MT25208        ||
-	    tvdev->pdev->device_id == PCI_DEVICE_MELLANOX_MT25208_COMPAT ||
-	    tvdev->pdev->device_id == PCI_DEVICE_MELLANOX_MT25208_PCICONF)
-		return BOARD_LIONCUB;
+	if (tvdev->vpd_present) {
+		if (tvdev->vpd.vpd_char[0] == 0x82) {
+			unsigned short len16;
+			char *p = (char *)&tvdev->vpd.vpd_char[3];
 
-	/* Set pin 12 to input and check the value */
-	WRITE_CFG(0xF0080 + 0x0C, READ_CFG(0xF0080 + 0x0C) & ~(1 << 12));
+			memcpy(&len16, tvdev->vpd.vpd_char + 1, sizeof(len16));
+			len16 = le16_to_cpu(len16);
 
-	usleep(10);
+			/* Skip leading whitespace */
+			for (; len16 > 0 && isspace(*p); len16--, p++)
+				;
 
-	cougar = !!(READ_CFG(0xF0080 + 0x04) & (1 << 12));
-	if (!cougar)
-		return BOARD_JAGUAR;
+			/* Make sure we don't copy too much */
+			if (len16 > sizeof(str))
+				len16 = sizeof(str);
 
-	if (tvdev->vpd) {
-		unsigned char str[MAX_STR];
-		unsigned short len16;
+			memcpy(str, p, len16);
+			str[len16] = 0;
 
-		if (tvdev->vpd_data[0] == 0x82) {
-			len16 = *(unsigned short *)&tvdev->vpd_data[1];
-			memcpy(str, &tvdev->vpd_data[3], len16);
-			str[len16] = 0;
-			if (strncasecmp(str, COUGARCUB_VPD_STR,
-					strlen(COUGARCUB_VPD_STR)) == 0)
-				return BOARD_COUGARCUB;
+			/* Strip off any trailing whitespace */
+			for (len16--; len16 > 0 && isspace(str[len16]); len16--)
+				str[len16] = 0;
 		} else
 			fprintf(stderr, " \nError. String Tag not present (found tag %02x instead)\n",
-				tvdev->vpd_data[0]);
+				tvdev->vpd.vpd_char[0]);
+	} else
+		str[0] = 0;
+
+	for (i = 0; i < sizeof(board_vpds) / sizeof(board_vpds[0]); i++) {
+		if (strcasecmp(str, board_vpds[i].str) == 0)
+			return board_vpds[i].board;
 	}
 
-	return BOARD_COUGAR;
+	return NULL;
 }
 
-/*
- * Mid level flash functions (firmware image)
- */
+static struct board *arbel_identify(struct tvdevice *tvdev)
+{
+	struct board *board;
 
-static void fixup_topspin_vsd(struct topspin_vsd *vsd, int do_boot)
+	board = vpd_identify(tvdev);
+	if (board)
+		return board;
+
+	return &genarbel;
+}
+
+static struct board *sinai_identify(struct tvdevice *tvdev)
 {
-	if (!(vsd->flags & htonl(VSD_FLAG_ALIGN_FIXED))) {
+	struct board *board;
+
+	board = vpd_identify(tvdev);
+	if (board)
+		return board;
+
+	return &gensinai;
+}
+
+static struct board *tavor_identify(struct tvdevice *tvdev)
+{
+	struct board *board;
+
+	/* Detect the difference between a Jaguar and Cougar via the GPIO pins */
+
+	/* Set GPIO pin 12 to input and check the value */
+	write_cfg(tvdev, GPIO_DIR + 4, read_cfg(tvdev, GPIO_DIR + 4) & ~(1 << 12));
+
+	usleep(10);
+
+	/* Check if board is a Jaguar by looking at GPIO pin 12 */
+	if (!(read_cfg(tvdev, GPIO_DAT + 4) & (1 << 12)))
+		return &jaguar;
+
+	/* Check the rest by VPD */
+	board = vpd_identify(tvdev);
+	if (board)
+		return board;
+
+	/*
+	 * FIXME: We shouldn't assume Cougar if the VPD is corrupt. The very
+	 * fact that there is a VPD probably means it's not a Cougar board.
+	 * It's only a Cougar if there is no VPD at all.
+	 */
+
+	return &cougar;
+}
+
+static void fixup_topspin_vsd(struct topspin_vsd *vsd)
+{
+	if (!(vsd->flags & cpu_to_be32(VSD_FLAG_ALIGN_FIXED))) {
 		/*
-		 * Some images have the hw_label field misaligned by
-		 * one byte. If this is an old image (the flag isn't
-		 * set), then move it back one character
+		 * Some images have the hw_label field misaligned by one byte.
+		 * If this is an old image (the flag isn't set), then move
+		 * it back one character
 		 */
-		memmove(vsd->hw_label, vsd->hw_label + 1, sizeof(vsd->hw_label) - 1);
-		vsd->flags |= htonl(VSD_FLAG_ALIGN_FIXED);
+		memmove(vsd->hw_label,
+			vsd->hw_label + 1,
+			sizeof(vsd->hw_label) - 1);
+		vsd->flags |= cpu_to_be32(VSD_FLAG_ALIGN_FIXED);
 	}
 
-	if (!(vsd->flags & htonl(VSD_FLAG_NEW_BUILD_NUM))) {
+	if (!(vsd->flags & cpu_to_be32(VSD_FLAG_NEW_BUILD_NUM))) {
 		/*
-		 * Some images have the hw_label field misaligned by
-		 * one byte. If this is an old image (the flag isn't
-		 * set), then move it back one character
+		 * build_num used to be an 8 bit field, but our build numbers
+		 * quickly outgrew that limitation, so expand to 16 bits and
+		 * a new location
 		 */
 		vsd->build_num = vsd->old_build_num;
-		vsd->flags |= htonl(VSD_FLAG_NEW_BUILD_NUM);
+		vsd->flags |= cpu_to_be32(VSD_FLAG_NEW_BUILD_NUM);
 	}
 
-	if (!do_boot)
-		return;
-
-	if ((vsd->flags & htonl(VSD_FLAG_BOOT_OPTIONS)) &&
-	    vsd->boot_version < BOOT_VERSION) {
+	if ((vsd->flags & cpu_to_be32(VSD_FLAG_BOOT_OPTIONS)) &&
+			((vsd->boot_version < 1) || (vsd->boot_version > BOOT_VERSION))) {
 		/* Invalid, reset to defaults */
 		vsd->boot_version = BOOT_VERSION;
 		vsd->boot_port = 0;
 		vsd->boot_ioc_num = 0;
-		memset(vsd->boot_dgid, 0,
-		       sizeof(vsd->boot_dgid));
-		vsd->boot_service_name[0] = 0;
-		vsd->boot_service_name[1] = 0;
+		memset(vsd->boot_dgid, 0, sizeof(vsd->boot_dgid));
+		memset(vsd->boot_service_name, 0, sizeof(vsd->boot_service_name));
+		vsd->boot_pxe_secs = BOOT_PXE_SECS_DEFAULT;
 
-		vsd->flags &= ~htonl(VSD_FLAG_BOOT_OPTIONS_MASK);
-		vsd->flags |=
-			htonl(VSD_FLAG_BOOT_ENABLE_PORT_1 |
-			      VSD_FLAG_BOOT_ENABLE_PORT_2 |
-			      VSD_FLAG_BOOT_ENABLE_SCAN |
-			      VSD_FLAG_BOOT_TYPE_WELL_KNOWN |
-			      VSD_FLAG_BOOT_GID_BIG);
+		vsd->flags &= ~cpu_to_be32(VSD_FLAG_BOOT_OPTIONS_MASK);
+		vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_1 |
+					VSD_FLAG_BOOT_ENABLE_PORT_2 |
+					VSD_FLAG_BOOT_ENABLE_SCAN |
+					VSD_FLAG_BOOT_TYPE_WELL_KNOWN |
+					VSD_FLAG_BOOT_GID_BIG);
 	}
 
-	if (!(vsd->flags & htonl(VSD_FLAG_BOOT_GID_BIG))) {
+	if (!(vsd->flags & cpu_to_be32(VSD_FLAG_BOOT_GID_BIG))) {
 		uint8_t dword[4];
 		int i;
 
 		for (i = 0; i < sizeof(vsd->boot_dgid); i += 4) {
-			memcpy(dword,&vsd->boot_dgid[i], 4);
+			memcpy(dword, &vsd->boot_dgid[i], 4);
 			vsd->boot_dgid[i + 0] = dword[3];
 			vsd->boot_dgid[i + 1] = dword[2];
 			vsd->boot_dgid[i + 2] = dword[1];
 			vsd->boot_dgid[i + 3] = dword[0];
 		}
- 
-		vsd->flags |= htonl(VSD_FLAG_BOOT_GID_BIG);
+
+		vsd->flags |= cpu_to_be32(VSD_FLAG_BOOT_GID_BIG);
 	}
+
+	if (vsd->boot_version < 2) {
+		uint8_t dword[4];
+		int i;
+
+		vsd->boot_version = BOOT_VERSION;
+		vsd->boot_pxe_secs = BOOT_PXE_SECS_DEFAULT;
+
+		for (i = 0; i < sizeof(vsd->boot_service_name); i += 4) {
+			memcpy(dword, &vsd->boot_service_name[i], 4);
+			vsd->boot_service_name[i + 0] = dword[3];
+			vsd->boot_service_name[i + 1] = dword[2];
+			vsd->boot_service_name[i + 2] = dword[1];
+			vsd->boot_service_name[i + 3] = dword[0];
+		}
+	}
 }
 
+/*
+ * Mid level flash functions (firmware image)
+ */
+
 static int flash_image_read_from_file(char *fname,
-				      unsigned char **isbuf, unsigned int *isbufsz,
-				      unsigned char **psbuf, unsigned int *psbufsz,
-				      unsigned char **ibuf, unsigned int *ibufsz)
+	unsigned char **isbuf, unsigned int *isbufsz,
+	unsigned char **psbuf, unsigned int *psbufsz,
+	unsigned char **ibuf, unsigned int *ibufsz)
 {
+	unsigned int sector_sz = 0;
+	uint32_t signature;
+	unsigned char *buf;
+	struct stat imgstat;
 	FILE *fimg;
-	struct stat imgstat;
-	char *buf;
-	unsigned int sector_sz;
 
 	/* Open and read image files */
 	fimg = fopen(fname, "r");
@@ -810,19 +1252,43 @@
 	}
 	fclose(fimg);
 
-	/* See if we find a sector size first */
-	sector_sz = ntohs(*(uint16_t *)(buf + 0x32));
+	/* Check the signature on the IS */
+	signature = be32_to_cpu(*(uint32_t *)(buf + 0x24));
+	if (signature == 0x5a445a44) {
+		unsigned int is_sz;
 
-	/*
-	 * Do some sanity checking of the result. Anything less than 4KB or more
-	 * than 1MB is suspicious and thrown out
-	 */
-	if (sector_sz < 12 || sector_sz > 20)
-		sector_sz = TV_FLASH_DEFAULT_SECTOR_SIZE;
-	else
-		sector_sz = 1 << sector_sz;
+		is_sz = be32_to_cpu(*(uint32_t *)(buf + 0x2c));
 
-	if (ntohl(*(uint32_t *)(buf + sector_sz + 8)) == 0x5a445a44) {
+		if (is_sz > 4 && is_sz < 1048576) {
+			uint16_t crc, img_crc;
+
+			/* is_sz is a count of dwords */
+			is_sz = is_sz * 4;
+			img_crc = be32_to_cpu(*(uint32_t *)(buf + 0x28 + is_sz + 12));
+
+			/* Verify the CRC of the IS */
+			crc = flash_crc16(buf + 0x28, is_sz + 16 - 4);
+			if (crc == img_crc) {
+				unsigned int sector_sz_ptr, log2_sector_sz;
+
+				/* Then grab the sector size */
+				sector_sz_ptr	= be16_to_cpu(*(uint16_t *)(buf + 0x16));
+				log2_sector_sz = be16_to_cpu(*(uint16_t *)(buf + sector_sz_ptr + 0x32));
+
+				/*
+				 * Do some sanity checking of the result.
+				 * Anything less than 4KB or more than
+				 * 1MB is suspicious and thrown out
+				 */
+				if (log2_sector_sz >= 12 && log2_sector_sz <= 20)
+					sector_sz = 1 << log2_sector_sz;
+			}
+		}
+	}
+
+	/* Check for PPS */
+	if (sector_sz &&
+	    be32_to_cpu(*(uint32_t *)(buf + sector_sz + 8)) == 0x5a445a44) {
 		union vsd *vsd;
 
 		/* Failsafe firmware image */
@@ -830,14 +1296,14 @@
 		*isbufsz = sector_sz;
 		*psbuf = buf + sector_sz;
 		*psbufsz = sector_sz;
-		*ibuf = buf + ntohl(*(uint32_t *)(buf + sector_sz + 0));
-		*ibufsz = ntohl(*(uint32_t *)(buf + sector_sz + 4));
+		*ibuf = buf + be32_to_cpu(*(uint32_t *)(buf + sector_sz + 0));
+		*ibufsz = be32_to_cpu(*(uint32_t *)(buf + sector_sz + 4));
 
 		/* Perform some image fixups */
 		vsd = (union vsd *)(buf + sector_sz + 0x20);
-
-		if (ntohs(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN)
-			fixup_topspin_vsd(&vsd->data.vendor.topspin, 0);
+		if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+		    be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN)
+			fixup_topspin_vsd(&vsd->data.vendor.topspin);
 	} else {
 		/* Non failsafe firmware image */
 		*isbuf = *psbuf = NULL;
@@ -849,143 +1315,180 @@
 	return 0;
 }
 
-static int validate_image(struct image *image, unsigned char *psbuf)
+static int validate_xps(struct image *image, unsigned char *psbuf)
 {
-	image->valid = (ntohl(*(uint32_t *)(psbuf + 0x8)) == 0x5a445a44);
+	/* Check for signature */
+	image->valid = (be32_to_cpu(*(uint32_t *)(psbuf + 0x8)) == 0x5a445a44);
 	if (image->valid) {
-		image->addr = ntohl(*(uint32_t *)(psbuf + 0x0));
-		image->size = ntohl(*(uint32_t *)(psbuf + 0x4));
-		image->valid = flash_crc16(psbuf, 0x104) == ntohs(*(uint16_t *)(psbuf + 0x106));
+		image->addr = be32_to_cpu(*(uint32_t *)(psbuf + 0x0));
+		image->size = be32_to_cpu(*(uint32_t *)(psbuf + 0x4));
+		/* Check CRC for xPS */
+		image->valid = (flash_crc16(psbuf, 0x104) == be16_to_cpu(*(uint16_t *)(psbuf + 0x106)));
 
-		memcpy(image->vsd.raw, psbuf + 0x20, sizeof image->vsd.raw);
+		memcpy(image->vsd.raw, psbuf + 0x20, sizeof(image->vsd.raw));
 
-		if (htons(image->vsd.data.signature) == VSD_SIGNATURE_TOPSPIN)
-			fixup_topspin_vsd(&image->vsd.data.vendor.topspin, 1);
+		if (be16_to_cpu(image->vsd.data.signature) == VSD_SIGNATURE_TOPSPIN &&
+		    be16_to_cpu(image->vsd.data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN)
+			fixup_topspin_vsd(&image->vsd.data.vendor.topspin);
 	}
 
 	return image->valid;
 }
 
-static int flash_check_failsafe(void)
+static int flash_check_failsafe(struct tvdevice *tvdev)
 {
-	unsigned short sector_sz_ptr;
-	unsigned short sector_sz;
-	char *psbuf;
+	unsigned int sector_sz = 0;
+	struct failsafe *failsafe = &tvdev->failsafe;
+	uint32_t signature;
+	unsigned char *psbuf;
 	int i;
 
-	/* Grab the sector size first */
-	sector_sz_ptr = (flash_byte_read(0x16) << 8) | flash_byte_read(0x17);
-	sector_sz     = (flash_byte_read(0x32 + sector_sz_ptr) << 8) |
-		flash_byte_read(0x33 + sector_sz_ptr);
+	/* Check the signature on the IS */
+	signature = flash_read(tvdev, 0x24);
+	if (signature == 0x5a445a44) {
+		unsigned char *is;
+		unsigned int is_sz;
 
-	/*
-	 * Do some sanity checking of the result. Anything less than 4KB or more
-	 * than 1MB is suspicious and thrown out
-	 */
-	if (sector_sz < 12 || sector_sz > 20) {
-		failsafe.sector_sz = TV_FLASH_DEFAULT_SECTOR_SIZE;
-		failsafe.valid     = 0;
-		return 0;
+		is_sz = flash_read(tvdev, 0x2c);
+		if (is_sz > 4 && is_sz < 1048576) {
+			uint16_t crc, img_crc;
+
+			/* is_sz is a count of dwords */
+			is_sz = is_sz * 4;
+			is = malloc(is_sz + 16);
+			if (!is) {
+				fprintf(stderr, "couldn't allocate %d bytes for sector buffer\n",
+					is_sz);
+				exit(1);
+			}
+
+			for (i = 0; i < is_sz + 16; i += 4)
+				*(uint32_t *)(is + i) = be32_to_cpu(flash_read(tvdev, 0x28 + i));
+
+			img_crc = flash_read(tvdev, 0x28 + is_sz + 12);
+
+			/* Verify the CRC of the IS */
+			crc = flash_crc16(is, is_sz + 16 - 4);
+			if (crc == img_crc) {
+				unsigned int sector_sz_ptr, log2_sector_sz;
+
+				/* Then grab the sector size */
+				sector_sz_ptr	= flash_read(tvdev, 0x14) & 0xffff;
+				log2_sector_sz = flash_read(tvdev, sector_sz_ptr + 0x30) & 0xffff;
+
+				/*
+				 * Do some sanity checking of the result.
+				 * Anything less than 4KB or more than
+				 * 1MB is suspicious and thrown out
+				 */
+				if (log2_sector_sz >= 12 && log2_sector_sz <= 20)
+					sector_sz = 1 << log2_sector_sz;
+			}
+
+			free(is);
+		}
 	}
 
-	failsafe.sector_sz = 1 << sector_sz;
+	if (!sector_sz)
+		return 0;
 
-	psbuf = malloc(failsafe.sector_sz);
+	psbuf = malloc(sector_sz);
 	if (!psbuf) {
 		fprintf(stderr, "couldn't allocate temp buffer for PPS/SPS (size = %d)\n",
-			failsafe.sector_sz);
+			sector_sz);
 		exit(1);
 	}
 
 	/* Check both PPS and SPS for valid signatures */
 
 	/* Read out the PPS */
-	for (i = 0; i < failsafe.sector_sz; i += 4)
-		*(uint32_t *)(psbuf + i) = ntohl(flash_read(failsafe.sector_sz + i));
+	for (i = 0; i < sector_sz; i += 4)
+		*(uint32_t *)(psbuf + i) = be32_to_cpu(flash_read(tvdev, sector_sz + i));
 
-	validate_image(&failsafe.images[0], psbuf);
+	validate_xps(&failsafe->images[0], psbuf);
 
 	/* Read out the SPS */
-	for (i = 0; i < failsafe.sector_sz; i += 4)
-		*(uint32_t *)(psbuf + i) = ntohl(flash_read(failsafe.sector_sz * 2 + i));
+	for (i = 0; i < sector_sz; i += 4)
+		*(uint32_t *)(psbuf + i) = be32_to_cpu(flash_read(tvdev, sector_sz * 2 + i));
 
-	validate_image(&failsafe.images[1], psbuf);
+	validate_xps(&failsafe->images[1], psbuf);
 
 	/*
 	 * Last sanity check. We can't say that the IS is programmed correctly
 	 * if we don't see a valid PPS or SPS.
 	 */
-	failsafe.valid = (failsafe.images[0].valid || failsafe.images[1].valid);
+	failsafe->valid = (failsafe->images[0].valid || failsafe->images[1].valid);
 
 	free(psbuf);
 
-	return failsafe.valid;
+	return failsafe->valid;
 }
 
 /* GUID section structure */
 struct guid_section {
-	uint8_t  gs_fw_reserved_1[16];
-	uint8_t  gs_node_guid  [GUID_LEN];
-	uint8_t  gs_port1_guid [GUID_LEN];
-	uint8_t  gs_port2_guid [GUID_LEN];
-	uint8_t  gs_sysimg_guid[8];
-	uint8_t  gs_fw_reserved_2[2];
+	uint8_t	gs_fw_reserved_1[16];
+	uint8_t	gs_node_guid	[GUID_LEN];
+	uint8_t	gs_port1_guid [GUID_LEN];
+	uint8_t	gs_port2_guid [GUID_LEN];
+	uint8_t	gs_sysimg_guid[8];
+	uint8_t	gs_fw_reserved_2[2];
 	uint16_t gs_crc16;
 };
 
 /* Get the GUIDs currently programmed in the flash */
-static int flash_get_curr_guids(unsigned char *guid_node, unsigned char *guid_port1,
-				unsigned char *guid_port2)
+static int flash_get_curr_guids(struct tvdevice *tvdev, unsigned char *guid_node,
+	unsigned char *guid_port1, unsigned char *guid_port2)
 {
 	unsigned int imageaddr = 0;
 	unsigned char *up;
 	unsigned int paddr;
 	int bcnt;
 
-	if (failsafe.valid) {
-		if (failsafe.images[0].valid)
-			imageaddr = failsafe.images[0].addr;
+	if (tvdev->failsafe.valid) {
+		if (tvdev->failsafe.images[0].valid)
+			imageaddr = tvdev->failsafe.images[0].addr;
 		else
-			imageaddr = failsafe.images[1].addr;
+			imageaddr = tvdev->failsafe.images[1].addr;
 	} else
 		imageaddr = 0;
 
-	paddr = flash_read(imageaddr + TV_FLASH_GUID_OFF) + imageaddr;
-	if (paddr > TV_FLASH_SIZE) {
+	paddr = flash_read(tvdev, imageaddr + TV_FLASH_GUID_OFF) + imageaddr;
+	if (paddr > tvdev->flash_size) {
 		fprintf(stderr, "GUID offset (0x%X) is larger than flash size (0x%X)!\n",
-			paddr, TV_FLASH_SIZE);
+			paddr, tvdev->flash_size);
 		return 1;
 	}
 
 	/* Read the Node GUID */
 	up = guid_node;
 	for (bcnt = 0; bcnt < GUID_LEN; bcnt++)
-		*up++ = flash_byte_read(paddr++);
+		*up++ = flash_byte_read(tvdev, paddr++);
 
 	/* Read the Port1 GUID */
 	up = guid_port1;
 	for (bcnt = 0; bcnt < GUID_LEN; bcnt++)
-		*up++ = flash_byte_read(paddr++);
+		*up++ = flash_byte_read(tvdev, paddr++);
 
 	/* Read the Port2 GUID */
 	up = guid_port2;
 	for (bcnt = 0; bcnt < GUID_LEN; bcnt++)
-		*up++ = flash_byte_read(paddr++);
+		*up++ = flash_byte_read(tvdev, paddr++);
 
 	return 0;
 }
 
 /* GUID update */
-static int flash_guids_update(unsigned char *ibuf, unsigned int ibufsz,
-			      unsigned char *guid_node, unsigned char *guid_port1,
-			      unsigned char *guid_port2)
+static int flash_guids_update(struct tvdevice *tvdev,
+	unsigned char *ibuf, unsigned int ibufsz,
+	unsigned char *guid_node, unsigned char *guid_port1,
+	unsigned char *guid_port2)
 {
 	unsigned int paddr;
 	struct guid_section *gsp;
 	uint16_t new_crc;
 
 	/* Endianess problems suck */
-	paddr = ntohl(*(uint32_t *)(ibuf + TV_FLASH_GUID_OFF));
+	paddr = be32_to_cpu(*(uint32_t *)(ibuf + TV_FLASH_GUID_OFF));
 	if (paddr > ibufsz) {
 		fprintf(stderr, "GUID pointer (0x%X) is larger than image size (0x%X)!\n",
 			paddr, ibufsz);
@@ -995,17 +1498,19 @@
 	/* Blend in the new GUIDs */
 	memcpy(&ibuf[paddr], guid_node, GUID_LEN);
 	memcpy(&ibuf[paddr + GUID_LEN], guid_port1, GUID_LEN);
-	memcpy(&ibuf[paddr + GUID_LEN * 2], guid_port2, GUID_LEN);
+	if (tvdev->board->num_ports > 1)
+		memcpy(&ibuf[paddr + GUID_LEN * 2], guid_port2, GUID_LEN);
 
 	printf("New Node  GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
-	       guid_node[0], guid_node[1], guid_node[2], guid_node[3],
-	       guid_node[4], guid_node[5], guid_node[6], guid_node[7]);
+		guid_node[0], guid_node[1], guid_node[2], guid_node[3],
+		guid_node[4], guid_node[5], guid_node[6], guid_node[7]);
 	printf("New Port1 GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
-	       guid_port1[0], guid_port1[1], guid_port1[2], guid_port1[3],
-	       guid_port1[4], guid_port1[5], guid_port1[6], guid_port1[7]);
-	printf("New Port2 GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
-	       guid_port2[0], guid_port2[1], guid_port2[2], guid_port2[3],
-	       guid_port2[4], guid_port2[5], guid_port2[6], guid_port2[7]);
+		guid_port1[0], guid_port1[1], guid_port1[2], guid_port1[3],
+		guid_port1[4], guid_port1[5], guid_port1[6], guid_port1[7]);
+	if (tvdev->board->num_ports > 1)
+		printf("New Port2 GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
+			guid_port2[0], guid_port2[1], guid_port2[2], guid_port2[3],
+			guid_port2[4], guid_port2[5], guid_port2[6], guid_port2[7]);
 
 	/* Get pointer to the GUID section in the image buffer */
 	gsp = (struct guid_section *)(ibuf + paddr - sizeof(gsp->gs_fw_reserved_1));
@@ -1013,7 +1518,7 @@
 	/* Recalculate GUID section CRC-16 - FW_Reserver_2 and CRC itself excluded */
 	new_crc = flash_crc16((uint8_t *)gsp, (uint32_t)&((struct guid_section *)0)->gs_fw_reserved_2);
 
-	gsp->gs_crc16 = htons(new_crc);
+	gsp->gs_crc16 = cpu_to_be16(new_crc);
 
 	return 0;
 }
@@ -1023,26 +1528,26 @@
  */
 
 /* Identify */
-static int create_ver_str(union vsd *vsd, unsigned char *buf, unsigned int buflen)
+static int create_ver_str(union vsd *vsd, char *buf, unsigned int buflen)
 {
 	if (vsd->data.vendor.topspin.revision_ver) {
 		if (vsd->data.vendor.topspin.revision_ver & 0x80)
-			snprintf(buf, buflen, "%d.%02d.%04d-rc%d",
-				 vsd->data.vendor.topspin.major_ver,
-				 vsd->data.vendor.topspin.minor_ver,
-				 ntohs(vsd->data.vendor.topspin.micro_ver),
-				 vsd->data.vendor.topspin.revision_ver & ~(-1 << 7));
+			snprintf(buf, buflen, "%d.%d.%03d-rc%d",
+				vsd->data.vendor.topspin.major_ver,
+				vsd->data.vendor.topspin.minor_ver,
+				be16_to_cpu(vsd->data.vendor.topspin.micro_ver),
+				vsd->data.vendor.topspin.revision_ver & ~(-1 << 7));
 		else
-			snprintf(buf, buflen, "%d.%02d.%04d_%d",
-				 vsd->data.vendor.topspin.major_ver,
-				 vsd->data.vendor.topspin.minor_ver,
-				 ntohs(vsd->data.vendor.topspin.micro_ver),
-				 vsd->data.vendor.topspin.revision_ver);
+			snprintf(buf, buflen, "%d.%d.%03d_%d",
+				vsd->data.vendor.topspin.major_ver,
+				vsd->data.vendor.topspin.minor_ver,
+				be16_to_cpu(vsd->data.vendor.topspin.micro_ver),
+				vsd->data.vendor.topspin.revision_ver);
 	} else
-		snprintf(buf, buflen, "%d.%02d.%04d",
-			 vsd->data.vendor.topspin.major_ver,
-			 vsd->data.vendor.topspin.minor_ver,
-			 ntohs(vsd->data.vendor.topspin.micro_ver));
+		snprintf(buf, buflen, "%d.%d.%03d",
+			vsd->data.vendor.topspin.major_ver,
+			vsd->data.vendor.topspin.minor_ver,
+			be16_to_cpu(vsd->data.vendor.topspin.micro_ver));
 
 	return strlen(buf);
 }
@@ -1051,242 +1556,423 @@
 {
 	char str[MAX_STR];
 	unsigned short i = 0, rlen;
-	unsigned char *ptr = tvdev->vpd_data;
-	unsigned short len16 = 0;
+	unsigned char *ptr = tvdev->vpd.vpd_char;
+	unsigned short len16;
 	unsigned char len8 = 0, cksum = 0;
 	int len = 0;
 	int pn = 0, ec = 0, sn = 0, fp = 0, dc = 0, rv = 0;
 
-	printf("\n  Vital Product Data");
+	printf("\n  Vital Product Data\n");
 
 	/* First field is string tag */
 	if (ptr[0] != 0x82) {
-		fprintf(stderr, " \nError. String Tag not present (found tag %02x instead)\n",
+		fprintf(stderr, "   Error. String Tag not present (found tag %02x instead)\n",
 			ptr[0]);
 		return;
 	}
 
 	/* print out String Tag */
-	len16 = *(unsigned short *)&ptr[1];
+	memcpy(&len16, ptr + 1, sizeof(len16));
+	len16 = le16_to_cpu(len16);
 	memcpy(str, &ptr[3], len16);
 	str[len16] = 0;
-	printf("\n    Product Name: %s", str);
+	printf("    Product Name: %s\n", str);
 
 	/* string len + 2 bytes of length field + 1 byte of tag */
 	ptr = &ptr[len16 + 3];
 
 	/* check for Read only tag */
 	if (ptr[0] != 0x90) {
-		fprintf(stderr, "\n    Error. R Tag not present\n");
+		fprintf(stderr, "    Error. R Tag not present\n");
 		return;
 	}
-	rlen = *(unsigned short *)&ptr[1]; /* Read only resource len */
+	memcpy(&rlen, ptr + 1, sizeof(rlen));	/* Read only resource len */
+	rlen = le16_to_cpu(rlen);
 
 	/* parse and print out each field, till we hit end tag */
-	ptr += 3;             /* 1 byte rtag + 2 bytes length field */
+	ptr += 3;		 /* 1 byte rtag + 2 bytes length field */
 	while (i < rlen) {
 		if ((ptr[0] == 'P') && (ptr[1] == 'N')) {
 			len8 = ptr[2];
 			memcpy(str, &ptr[3], len8);
 			str[len8] = 0;
-			printf("\n    P/N: %s", str);
+			printf("    P/N: %s\n", str);
 			pn = 1;
 		} else if ((ptr[0] == 'E') && (ptr[1] == 'C')) {
 			len8 = ptr[2];
 			memcpy(str, &ptr[3], len8);
 			str[len8] = 0;
-			printf("\n    E/C: %s", str);
+			printf("    E/C: %s\n", str);
 			ec = 1;
 		} else if ((ptr[0] == 'S') && (ptr[1] == 'N')) {
 			len8 = ptr[2];
 			memcpy(str, &ptr[3], len8);
 			str[len8] = 0;
-			printf("\n    S/N: %s", str);
+			printf("    S/N: %s\n", str);
 			sn = 1;
 		} else if ((ptr[0] == 'V') && (ptr[1] == '0')) {
 			len8 = ptr[2];
 			memcpy(str, &ptr[3], len8);
 			str[len8] = 0;
-			printf("\n    Freq/Power: %s", str);
+			printf("    Freq/Power: %s\n", str);
 			fp = 1;
 		} else if ((ptr[0] == 'V') && (ptr[1] == '2')) {
 			len8 = ptr[2];
 			memcpy(str, &ptr[3], len8);
 			str[len8] = 0;
-			printf("\n    Date Code: %s", str);
+			printf("    Date Code: %s\n", str);
 			dc = 1;
 		} else if ((ptr[0] == 'R') && (ptr[1] == 'V')) {
-			len = &ptr[2] - tvdev->vpd_data + 1;
+			len = &ptr[2] - tvdev->vpd.vpd_char + 1;
 
 			while (len >= 0) {
-				cksum += tvdev->vpd_data[len];
+				cksum += tvdev->vpd.vpd_char[len];
 				len--;
 			}
 
 			if (cksum == 0)
-				printf("\n    Checksum: Ok");
+				printf("    Checksum: Ok\n");
 			else
-				printf("\n    Checksum: Incorrect");
+				printf("    Checksum: Incorrect\n");
 
 			rv = 1;
 		} else if (ptr[0] == 0x78)	/* End Tag */
-			break;
+			 break;
 
 		i += (len8 + 3);
 		ptr += (len8 + 3);
 	}
 	if (!pn)
-		printf("\n    P/N: N/A");
+		printf("    P/N: N/A\n");
 	if (!ec)
-		printf("\n    E/C: N/A");
+		printf("    E/C: N/A\n");
 	if (!sn)
-		printf("\n    S/N: N/A");
+		printf("    S/N: N/A\n");
 	if (!dc)
-		printf("\n    Date Code: N/A");
+		printf("    Date Code: N/A\n");
 	if (!fp)
-		printf("\n    Freq/Power: N/A");
+		printf("    Freq/Power: N/A\n");
 	if (!rv)
-		printf("\n    Checksum: N/A");
-	printf("\n");
+		printf("    Checksum: N/A\n");
 }
 
-static int identify_hca(int num, struct tvdevice *tvdev,
-			enum identify_mode identify_mode)
+static int open_device(struct tvdevice *tvdev)
 {
-	unsigned char revision;
-	int err;
+#if defined(__PPC64__)
+	unsigned short command;
 
-	err = open_hca(tvdev);
-	if (err)
-		return err;
+	/* Enable memory regions if it's disabled */
+	command = pci_read_word(tvdev->pdev, 0x04);
+	if (!(command & 0x02))
+		pci_write_word(tvdev->pdev, 0x04, command | 0x02);
+#endif
 
-	mtflash_init();
-	flash_chip_reset();
-	grab_gpio();
+	if (!use_config_space && !(tvdev->flags & FLAG_RECOVERY)) {
+		int fd;
 
-	flash_check_failsafe();
+		fd = open("/dev/mem", O_RDWR, O_SYNC);
+		if (fd >= 0) {
+			tvdev->bar0 = mmap(NULL, 1 << 20, PROT_READ | PROT_WRITE, MAP_SHARED,
+					 fd, tvdev->pdev->base_addr[0] & PCI_ADDR_MEM_MASK);
+			close(fd);
+			if (tvdev->bar0 == MAP_FAILED)
+				tvdev->bar0 = NULL;
+		} else
+			tvdev->bar0 = NULL;
+	} else
+		tvdev->bar0 = NULL;
 
-	vpd_read(tvdev, tvdev->pdev);
+	if (tvdev->bar0) {
+		tvdev->method = METHOD_MMAP;
+		return 0;
+	}
 
-	revision = pci_read_word(tvdev->pdev, PCI_CLASS_REVISION) & 0xff;
+#if 0
+	/* FIXME: Test that we can do this first */
+	tvdev->method = METHOD_PCI_CFG;
 
-	/* According to the documentation, a revision of 0x00 is an A0 */
-	if (revision == 0x00)
-		revision = 0xA0;
+	return 0;
+#else
+	return 1;
+#endif
+}
 
-	switch (identify_mode) {
-	case IDENTIFY_EXTENDED:
-		switch (tvdev->pdev->device_id) {
-		case PCI_DEVICE_MELLANOX_MT23108_PCICONF:
-		case PCI_DEVICE_MELLANOX_MT23108_PCIBRIDGE:
-			printf("HCA #%d: Found MT23108 (recovery mode)", num);
+static void identify_flash_device(struct tvdevice *tvdev)
+{
+	char cfiq[1024], str[4];
+	int i, width = 0;
+
+	switch (tvdev->board->chip) {
+	case CHIP_SINAI:
+		/* SPI device */
+		tvdev->flash_size = 0x200000;	/* 2MB */
+		tvdev->flash_bank_shift = 20;
+		tvdev->flash_command_set = CS_SPI;
+		tvdev->flash_sector_sz = 0x10000;	/* 64KB */
+		break;
+	default:
+		tvdev->flash_size = 0x400000;	/* 4MB */
+		tvdev->flash_bank_shift = 19;
+		tvdev->flash_bank_mask = (1 << tvdev->flash_bank_shift) - 1;
+
+		/* Parallel flash chip */
+
+		/* Get CFI info for flash device */
+		flash_write_cmd(tvdev, 0x55, 0xFF);	/* Reset */
+		flash_write_cmd(tvdev, 0x55, 0x98);	/* CFI Query */
+
+		str[0] = flash_byte_read(tvdev, 0x10);
+		str[1] = flash_byte_read(tvdev, 0x11);
+		str[2] = flash_byte_read(tvdev, 0x12);
+		str[3] = 0;
+
+		if (strcmp(str, "QRY") == 0)
+			width = 1;
+		else {
+			str[0] = flash_byte_read(tvdev, 0x20);
+			str[1] = flash_byte_read(tvdev, 0x22);
+			str[2] = flash_byte_read(tvdev, 0x24);
+			str[3] = 0;
+
+			if (strcmp(str, "QRY") == 0)
+				width = 2;
+		}
+
+		if (!width) {
+			fprintf(stderr, "CFI query failed. Unknown flash device.\n");
+			exit(1);
+		}
+
+		for (i = 0; i < sizeof(cfiq); i++)
+			cfiq[i] = flash_byte_read(tvdev, i * width);
+
+		tvdev->flash_command_set = cfiq[0x13];
+
+		/*
+		 * FIXME: This is a hack for now. We should really get this
+		 * from the CFI query. Careful, MX chips have buggy
+		 * information.
+		 */
+		switch (tvdev->flash_command_set) {
+		case CS_INTEL:
+			tvdev->flash_sector_sz = 0x20000;	/* 128KB */
 			break;
-		case PCI_DEVICE_MELLANOX_MT25208_PCICONF:
-			printf("HCA #%d: Found MT25208 (recovery mode)", num);
+		case CS_AMD:
+			tvdev->flash_sector_sz = 0x10000;	/* 64KB */
 			break;
-		case PCI_DEVICE_MELLANOX_MT23108:
-			printf("HCA #%d: Found MT23108", num);
-			break;
-		case PCI_DEVICE_MELLANOX_MT25208:
-			printf("HCA #%d: Found MT25208", num);
-			break;
-		case PCI_DEVICE_MELLANOX_MT25208_COMPAT:
-			printf("HCA #%d: Found MT25208 (MT23108 mode)", num);
-			break;
+		default:
+			printf("Unknown flash command set.\n");
+			exit(1);
 		}
 
-		switch (identify_board(tvdev)) {
-		case BOARD_JAGUAR:
-			printf(", Jaguar");
+		break;
+	}
+
+	tvdev->flash_bank_mask = (1 << tvdev->flash_bank_shift) - 1;
+
+	flash_chip_reset(tvdev);
+
+	tvdev->flash_bank = -1;
+	flash_set_bank(tvdev, 0);
+}
+
+static int open_hca(struct tvdevice *tvdev)
+{
+	int ret;
+
+	ret = open_device(tvdev);
+	if (ret)
+		return ret;
+
+	read_cfg(tvdev, 0xF0150);
+	write_cfg(tvdev, 0xF0150, 1 << 30);
+
+	grab_gpio(tvdev);
+
+	tvdev->board = tvdev->pciid->identify(tvdev);
+	if (!tvdev->board) {
+		fprintf(stderr, "unable to identify board\n");
+		return 1;
+	}
+
+	identify_flash_device(tvdev);
+
+	if (tvdev->flash_command_set == CS_UNKNOWN) {
+		printf("Unknown flash device, cannot continue\n");
+		return 1;
+	}
+
+	/* RevC LionCub boards use Intel flash chips and use a different firmware */
+	if (tvdev->board == &lioncub && tvdev->flash_command_set == CS_INTEL)
+		tvdev->board = &lioncub_revc;
+
+	switch (tvdev->board->chip) {
+	case CHIP_SINAI:
+		/* SPI flash */
+
+		/* Unlock GPIO */
+		write_cfg(tvdev, GPIO_LOCK, 0xAAAA);
+
+#define SPI_ENABLE	((1 << (NUM_SPIS - 1)) - 1)
+		write_cfg(tvdev, GPIO_DIR + 4, SPI_ENABLE << 5);
+		write_cfg(tvdev, GPIO_POL + 4, (SPI_ENABLE ^ 0x07) << 5);
+		write_cfg(tvdev, GPIO_MOD + 4, (SPI_ENABLE ^ 0x07) << 5);
+		break;
+	default:
+		/* Parallel flash */
+
+		/* Set the direction of the flash pins to output */
+		write_cfg(tvdev, GPIO_DIR + 4, read_cfg(tvdev, GPIO_DIR + 4) | (0x07 << 4));
+
+		/* Clear the data for the flash pins to start at bank 0 */
+		write_cfg(tvdev, 0xF0080 + 0x54, 0x07 << 4);
+
+		/* Clear the polarity for the flash pins */
+		write_cfg(tvdev, GPIO_POL + 4, read_cfg(tvdev, GPIO_POL + 4) & ~(0x07 << 4));
+
+		/* Clear the output mode for the flash pins */
+		write_cfg(tvdev, GPIO_MOD + 4, read_cfg(tvdev, GPIO_MOD + 4) & ~(0x07 << 4));
+		break;
+	}
+
+	return 0;
+}
+
+static void close_hca(struct tvdevice *tvdev)
+{
+	release_gpio(tvdev);
+
+	if (tvdev->bar0)
+		munmap(tvdev->bar0, 1 << 20);
+}
+
+static int identify_hca(int num, struct tvdevice *tvdev,
+		 enum identify_mode identify_mode, int *unreliable)
+{
+	if (open_hca(tvdev)) {
+		fprintf(stderr, "couldn't open hca %d\n", num);
+		return 1;
+	}
+
+	flash_check_failsafe(tvdev);
+
+	switch (identify_mode) {
+	case IDENTIFY_EXTENDED:
+		printf("HCA #%d: ", num);
+		switch (tvdev->board->chip) {
+		case CHIP_TAVOR:
+			printf("MT23108");
 			break;
-		case BOARD_COUGAR:
-			printf(", Cougar");
+		case CHIP_ARBEL:
+			printf("MT25208");
+			if (tvdev->flags & FLAG_TAVOR_COMPAT)
+				printf(" Tavor Compat");
 			break;
-		case BOARD_COUGARCUB:
-			printf(", Cougar Cub");
+		case CHIP_SINAI:
+			printf("MT25204");
 			break;
-		case BOARD_LIONCUB:
-			printf(", Lion Cub");
+		default:
+			printf("Unknown");
 			break;
 		}
 
-		printf(", revision %02X", revision);
+		if (tvdev->flags & FLAG_RECOVERY)
+			printf(" (recovery mode)");
 
-		if (failsafe.valid && failsafe.images[0].valid &&
-		    (failsafe.images[0].vsd.data.vendor.topspin.flags &
-		     htonl(VSD_FLAG_AUTOUPGRADE)))
-			printf(" (firmware autoupgrade)");
+		printf(", %s", tvdev->board->name);
 
-		printf("\n");
+		if (tvdev->flags & FLAG_RECOVERY) {
+			printf("(*)");
+			*unreliable = 1;
+		}
 
-		if (failsafe.valid) {
-			if (failsafe.images[0].valid) {
-				if (ntohs(failsafe.images[0].vsd.data.signature) == 0x05ad &&
-				    ntohs(failsafe.images[0].vsd.data.vendor.topspin.signature2) == 0x05ad) {
-					unsigned char ver_str[40];
+		printf(", revision %02X\n", tvdev->revision);
 
-					create_ver_str(&failsafe.images[0].vsd, ver_str, sizeof(ver_str));
-					if (failsafe.images[0].vsd.data.vendor.topspin.build_rev[0])
+		if (tvdev->failsafe.valid) {
+			union vsd *vsd;
+
+			if (tvdev->failsafe.images[0].valid) {
+				vsd = &tvdev->failsafe.images[0].vsd;
+				if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+				    be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
+					char ver_str[40];
+
+					create_ver_str(vsd, ver_str, sizeof(ver_str));
+					if (vsd->data.vendor.topspin.build_rev[0])
 						printf("  Primary image is v%s build %s.%d, with label '%s'\n",
-						       ver_str,
-						       failsafe.images[0].vsd.data.vendor.topspin.build_rev,
-						       failsafe.images[0].vsd.data.vendor.topspin.build_num,
-						       failsafe.images[0].vsd.data.vendor.topspin.hw_label);
+							ver_str,
+							vsd->data.vendor.topspin.build_rev,
+							le16_to_cpu(tvdev->failsafe.images[0].vsd.data.vendor.topspin.build_num),
+							vsd->data.vendor.topspin.hw_label);
 					else
 						printf("  Primary image is v%s, with label '%s'\n",
-						       ver_str,
-						       failsafe.images[0].vsd.data.vendor.topspin.hw_label);
+							ver_str,
+							vsd->data.vendor.topspin.hw_label);
 				} else
 					printf("  Primary image is valid, unknown source\n");
+
+				if (verbose > 1)
+					printf("    0x%08x bytes @ 0x%08x\n",
+						tvdev->failsafe.images[0].size,
+						tvdev->failsafe.images[0].addr);
 			} else
 				printf("  Primary image is NOT valid\n");
 
-			if (failsafe.images[1].valid) {
-				if (ntohs(failsafe.images[1].vsd.data.signature) == 0x05ad &&
-				    ntohs(failsafe.images[1].vsd.data.vendor.topspin.signature2) == 0x05ad) {
-					unsigned char ver_str[40];
+			if (tvdev->failsafe.images[1].valid) {
+				vsd = &tvdev->failsafe.images[1].vsd;
+				if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+				    be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
+					char ver_str[40];
 
-					create_ver_str(&failsafe.images[1].vsd, ver_str, sizeof(ver_str));
-					if (failsafe.images[1].vsd.data.vendor.topspin.build_rev[0])
+					create_ver_str(vsd, ver_str, sizeof(ver_str));
+					if (vsd->data.vendor.topspin.build_rev[0])
 						printf("  Secondary image is v%s build %s.%d, with label '%s'\n",
-						       ver_str,
-						       failsafe.images[1].vsd.data.vendor.topspin.build_rev,
-						       failsafe.images[1].vsd.data.vendor.topspin.build_num,
-						       failsafe.images[1].vsd.data.vendor.topspin.hw_label);
+							ver_str,
+							vsd->data.vendor.topspin.build_rev,
+							le16_to_cpu(vsd->data.vendor.topspin.build_num),
+							vsd->data.vendor.topspin.hw_label);
 					else
 						printf("  Secondary image is v%s, with label '%s'\n",
-						       ver_str,
-						       failsafe.images[1].vsd.data.vendor.topspin.hw_label);
+							ver_str,
+							vsd->data.vendor.topspin.hw_label);
 				} else
 					printf("  Secondary image is valid, unknown source\n");
+
+				if (verbose > 1)
+					printf("    0x%08x bytes @ 0x%08x\n",
+						tvdev->failsafe.images[1].size,
+						tvdev->failsafe.images[1].addr);
 			} else
 				printf("  Secondary image is NOT valid\n");
 		} else
 			printf("  Firmware is NOT installed in failsafe mode\n");
 
 		/* If vpd is present, read it and print it */
-		if (tvdev->vpd)
+		if (tvdev->vpd_present)
 			print_vpd_info(tvdev);
 		break;
 	case IDENTIFY_PRIMARY_FIRMWARE_LABEL:
-		if (failsafe.valid) {
-			if (failsafe.images[0].valid) {
-				if (ntohs(failsafe.images[0].vsd.data.signature) == 0x05ad &&
-				    ntohs(failsafe.images[0].vsd.data.vendor.topspin.signature2) == 0x05ad) {
+		if (tvdev->failsafe.valid) {
+			union vsd *vsd;
+
+			if (tvdev->failsafe.images[0].valid) {
+				vsd = &tvdev->failsafe.images[0].vsd;
+				if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+				    be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
 					unsigned int build_major = 0, build_minor = 0, build_micro = 0;
 
-					sscanf(failsafe.images[0].vsd.data.vendor.topspin.build_rev, "%u.%u.%u",
-					       &build_major, &build_minor, &build_micro);
+					sscanf(vsd->data.vendor.topspin.build_rev, "%u.%u.%u",
+						 &build_major, &build_minor, &build_micro);
 
 					printf("%s:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
-					       failsafe.images[0].vsd.data.vendor.topspin.hw_label,
-					       (failsafe.images[0].vsd.data.vendor.topspin.flags & htonl(VSD_FLAG_AUTOUPGRADE)) ? 1 : 0,
-					       failsafe.images[0].vsd.data.vendor.topspin.major_ver,
-					       failsafe.images[0].vsd.data.vendor.topspin.minor_ver,
-					       ntohs(failsafe.images[0].vsd.data.vendor.topspin.micro_ver),
-					       failsafe.images[0].vsd.data.vendor.topspin.revision_ver,
-					       build_major, build_minor, build_micro,
-					       failsafe.images[0].vsd.data.vendor.topspin.build_num);
+						vsd->data.vendor.topspin.hw_label,
+						(vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_AUTOUPGRADE)) ? 1 : 0,
+						vsd->data.vendor.topspin.major_ver,
+						vsd->data.vendor.topspin.minor_ver,
+						be16_to_cpu(vsd->data.vendor.topspin.micro_ver),
+						vsd->data.vendor.topspin.revision_ver,
+						build_major, build_minor, build_micro,
+						le16_to_cpu(vsd->data.vendor.topspin.build_num));
 				} else
 					printf("Unknown\n");
 			} else
@@ -1297,26 +1983,15 @@
 		break;
 	case IDENTIFY_HARDWARE_LABEL:
 		/* Print out what we think the firmware label should be */
-		switch (identify_board(tvdev)) {
-		case BOARD_JAGUAR:
-			printf("HCA.Jaguar.%02X\n", revision);
-			break;
-		case BOARD_COUGAR:
-			printf("HCA.Cougar.%02X\n", revision);
-			break;
-		case BOARD_COUGARCUB:
-			printf("HCA.CougarCub.%02X\n", revision);
-			break;
-		case BOARD_LIONCUB:
-			printf("HCA.LionCub.%02X\n", revision);
-			break;
-		}
-
+		if (tvdev->board->fwlabel)
+			printf("%s.%02X",
+				tvdev->board->fwlabel, tvdev->revision);
+		else
+			printf("Unknown.%02X", tvdev->revision);
 		break;
 	}
 
-	release_gpio();
-	close_hca();
+	close_hca(tvdev);
 
 	return 0;
 }
@@ -1324,28 +1999,29 @@
 static int identify_hcas(int hca, enum identify_mode identify_mode)
 {
 	struct tvdevice *tvdev;
-	int count = 0;
-	int ret;
+	int ret = 0, count = 0, unreliable = 0;
 
 	if (hca >= 0) {
 		tvdev = find_device(hca);
 		if (!tvdev) {
-			fprintf(stderr, "couldn't find HCA #%d on the PCI bus\n", hca);
+			fprintf(stderr, "couldn't find HCA #%d on the PCI bus\n",
+				hca);
 			return 1;
 		}
 
-		ret = identify_hca(hca, tvdev, identify_mode);
-		if (ret)
-			return ret;
+		ret = identify_hca(hca, tvdev, identify_mode, &unreliable);
 	} else {
 		for (tvdev = tvdevices; tvdev; tvdev = tvdev->next) {
-			ret = identify_hca(count++, tvdev, identify_mode);
+			ret = identify_hca(count++, tvdev, identify_mode, &unreliable);
 			if (ret)
-				return ret;
+				break;
 		}
 	}
 
-	return 0;
+	if (unreliable)
+		printf("\n(*) Unreliable in recovery mode\n");
+
+	return ret;
 }
 
 static int identify_firmware(char *ifname, enum identify_mode identify_mode)
@@ -1355,8 +2031,8 @@
 	union vsd *vsd = NULL;
 
 	/* Read the flash image into the memory */
-	if (flash_image_read_from_file(ifname, &isbuf, &isbufsz, &psbuf, &psbufsz,
-				       &ibuf, &ibufsz))
+	if (flash_image_read_from_file(ifname, &isbuf, &isbufsz, &psbuf,
+					&psbufsz, &ibuf, &ibufsz))
 		return 1;
 
 	vsd = (union vsd *)(psbuf + 0x20);
@@ -1365,25 +2041,26 @@
 	case IDENTIFY_EXTENDED:
 		printf("Firmware image %s", ifname);
 
-		if (psbuf && vsd->data.vendor.topspin.flags & htonl(VSD_FLAG_AUTOUPGRADE))
+		if (psbuf && vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_AUTOUPGRADE))
 			printf(" (firmware autoupgrade)");
 
 		printf("\n");
 
 		if (psbuf) {
-			if (ntohs(vsd->data.signature) == 0x05ad &&
-			    ntohs(vsd->data.vendor.topspin.signature2) == 0x05ad) {
-				unsigned char ver_str[40];
+			if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+			    be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
+				char ver_str[40];
 
 				create_ver_str(vsd, ver_str, sizeof(ver_str));
 				if (vsd->data.vendor.topspin.build_rev[0])
 					printf("  Image is v%s build %s.%d, with label '%s'\n",
-					       ver_str, vsd->data.vendor.topspin.build_rev,
-					       vsd->data.vendor.topspin.build_num, vsd->data.vendor.topspin.hw_label);
+						ver_str, vsd->data.vendor.topspin.build_rev,
+						le16_to_cpu(vsd->data.vendor.topspin.build_num),
+						vsd->data.vendor.topspin.hw_label);
 				else
 					printf("  Image is v%s, with label '%s'\n",
-					       ver_str,
-					       vsd->data.vendor.topspin.hw_label);
+						ver_str,
+						vsd->data.vendor.topspin.hw_label);
 			} else
 				printf("  Image is valid, unknown source\n");
 		} else
@@ -1392,22 +2069,22 @@
 		break;
 	case IDENTIFY_PRIMARY_FIRMWARE_LABEL:
 		if (psbuf) {
-			if (ntohs(vsd->data.signature) == 0x05ad &&
-			    ntohs(vsd->data.vendor.topspin.signature2) == 0x05ad) {
+			if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+			    be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
 				unsigned int build_major = 0, build_minor = 0, build_micro = 0;
 
 				sscanf(vsd->data.vendor.topspin.build_rev, "%u.%u.%u",
-				       &build_major, &build_minor, &build_micro);
+					 &build_major, &build_minor, &build_micro);
 
 				printf("%s:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
-				       vsd->data.vendor.topspin.hw_label,
-				       (vsd->data.vendor.topspin.flags & htonl(VSD_FLAG_AUTOUPGRADE)) ? 1 : 0,
-				       vsd->data.vendor.topspin.major_ver,
-				       vsd->data.vendor.topspin.minor_ver,
-				       ntohs(vsd->data.vendor.topspin.micro_ver),
-				       vsd->data.vendor.topspin.revision_ver,
-				       build_major, build_minor, build_micro,
-				       vsd->data.vendor.topspin.build_num);
+					 vsd->data.vendor.topspin.hw_label,
+					 (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_AUTOUPGRADE)) ? 1 : 0,
+					 vsd->data.vendor.topspin.major_ver,
+					 vsd->data.vendor.topspin.minor_ver,
+					 be16_to_cpu(vsd->data.vendor.topspin.micro_ver),
+					 vsd->data.vendor.topspin.revision_ver,
+					 build_major, build_minor, build_micro,
+					 le16_to_cpu(vsd->data.vendor.topspin.build_num));
 			} else
 				printf("Unknown\n");
 		} else
@@ -1423,17 +2100,76 @@
 	return 0;
 }
 
+static int print_hca_guids(int num, struct tvdevice *tvdev)
+{
+	unsigned char guid_node[GUID_LEN];
+	unsigned char guid_port1[GUID_LEN];
+	unsigned char guid_port2[GUID_LEN];
+
+	if (open_hca(tvdev)) {
+		fprintf(stderr, "couldn't open hca %d\n", num);
+		return 1;
+	}
+
+	flash_check_failsafe(tvdev);
+
+	if (flash_get_curr_guids(tvdev, guid_node, guid_port1, guid_port2)) {
+		fprintf(stderr, "Cannot determine previous GUID. Corrupted flash?\n");
+		return 1;
+	}
+
+	printf("HCA #%d\n", num);
+	printf("Node  GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
+		guid_node[0], guid_node[1], guid_node[2], guid_node[3],
+		guid_node[4], guid_node[5], guid_node[6], guid_node[7]);
+	printf("Port1 GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
+		guid_port1[0], guid_port1[1], guid_port1[2], guid_port1[3],
+		guid_port1[4], guid_port1[5], guid_port1[6], guid_port1[7]);
+	if (tvdev->board->num_ports > 1)
+		printf("Port2 GUID = %02x%02x%02x%02x%02x%02x%02x%02x\n",
+			guid_port2[0], guid_port2[1], guid_port2[2], guid_port2[3],
+			guid_port2[4], guid_port2[5], guid_port2[6], guid_port2[7]);
+
+	close_hca(tvdev);
+
+	return 0;
+}
+
+static int print_guids(int hca)
+{
+	struct tvdevice *tvdev;
+	int ret = 0, count = 0;
+
+	if (hca >= 0) {
+		tvdev = find_device(hca);
+		if (!tvdev) {
+			fprintf(stderr, "couldn't find HCA #%d on the PCI bus\n", hca);
+			return 1;
+		}
+
+		ret = print_hca_guids(hca, tvdev);
+	} else {
+		for (tvdev = tvdevices; tvdev; tvdev = tvdev->next) {
+			ret = print_hca_guids(count++, tvdev);
+			if (ret)
+				break;
+		}
+	}
+
+	return ret;
+}
+
 /* Download (from HCA to host) */
-static int flash_image_write_to_file(char *fname)
+static int flash_image_write_to_file(struct tvdevice *tvdev, char *fname)
 {
 	char *buffer;
 	int i, fd;
 	unsigned int offset;
 
-	buffer = malloc(failsafe.sector_sz);
+	buffer = malloc(tvdev->flash_sector_sz);
 	if (!buffer) {
 		fprintf(stderr, "couldn't allocated %d bytes of memory for buffer\n",
-			failsafe.sector_sz);
+			tvdev->flash_sector_sz);
 		return 1;
 	}
 
@@ -1448,11 +2184,11 @@
 	}
 
 	offset = 0;
-	while (offset < TV_FLASH_SIZE) {
-		for (i = 0; i < failsafe.sector_sz; i += 4) {
+	while (offset < tvdev->flash_size) {
+		for (i = 0; i < tvdev->flash_sector_sz; i += 4) {
 			unsigned int data;
 
-			data = flash_read(offset + i);
+			data = flash_read(tvdev, offset + i);
 
 			buffer[i + 0] = (data >> 24) & 0xff;
 			buffer[i + 1] = (data >> 16) & 0xff;
@@ -1460,9 +2196,9 @@
 			buffer[i + 3] = data & 0xff;
 		}
 
-		write(fd, buffer, failsafe.sector_sz);
+		write(fd, buffer, tvdev->flash_sector_sz);
 
-		offset += failsafe.sector_sz;
+		offset += tvdev->flash_sector_sz;
 	}
 
 	close(fd);
@@ -1481,317 +2217,213 @@
 		return 1;
 	}
 
-	ret = open_hca(tvdev);
+	if (open_hca(tvdev)) {
+		fprintf(stderr, "couldn't open hca %d\n", hca);
+		return 1;
+	}
 
-	mtflash_init();
-	grab_gpio();
+	flash_check_failsafe(tvdev);
 
-	flash_check_failsafe();
+	ret = flash_image_write_to_file(tvdev, ofname);
 
-	ret = flash_image_write_to_file(ofname);
+	close_hca(tvdev);
 
-	release_gpio();
-	close_hca();
-
 	return ret;
 }
 
-/* Upload (from host to HCA) */
-static void flash_move_pps_to_sps(void)
+static void flash_write_block(struct tvdevice *tvdev, unsigned char status,
+	unsigned int addr, unsigned char *buffer, unsigned int buflen)
 {
-	unsigned int addr, curbar = -1;
+	unsigned int pos = 0, bufsz = buflen;
 
-	flash_chip_reset();
-
-	if (verbose)
-		curbar = update_status("Failsafe", 0, failsafe.sector_sz, curbar);
-
-	flash_erase_sector(failsafe.sector_sz * 2);
-
-	for (addr = 0; addr < failsafe.sector_sz; addr += 4) {
-		uint32_t data;
+	while (bufsz > 0) {
+		unsigned int len = 16;
 		int i;
 
-		if (verbose)
-			curbar = update_status("Failsafe", addr, failsafe.sector_sz, curbar);
+		flash_set_bank(tvdev, addr);
 
-		data = flash_read(failsafe.sector_sz + addr);
-		for (i = 0; i < 4; i++)
-			flash_write_byte(failsafe.sector_sz * 2 + addr + i,
-					 ((data >> ((3 - i) * 8)) & 0xFF));
-	}
+		if (len > bufsz)
+			bufsz = len;
 
-	flash_chip_reset();
+		switch (tvdev->flash_command_set) {
+		case CS_SPI:
+			flash_spi_write_block(tvdev, addr, buffer + pos, len);
+			break;
+		default:
+			for (i = 0; i < len; i++)
+				flash_write_byte(tvdev, addr + i, buffer[pos + i]);
+			break;
+		}
+		addr += len;
+		pos += len;
+		bufsz -= len;
 
-	if (verbose) {
-		update_status("Failsafe", failsafe.sector_sz, failsafe.sector_sz, curbar);
-		printf("\n");
+		if (status)
+			status_update(status, pos);
 	}
 }
 
-static void flash_write_invariant_sector(unsigned char *isbuf, unsigned int isbufsz)
+/* Upload (from host to HCA) */
+static int flash_compare_invariant_sector(struct tvdevice *tvdev, unsigned char *isbuf,
+	unsigned int isbufsz)
 {
-	unsigned int addr, curbar = -1;
+	unsigned int addr, data;
 
-	flash_chip_reset();
+	flash_chip_reset(tvdev);
 
-	if (verbose)
-		curbar = update_status("Failsafe", 0, isbufsz, curbar);
+	for (addr = 0; addr < isbufsz; addr += 4) {
+		int i;
 
-	flash_erase_sector(0);
-
-	for (addr = 0; addr < isbufsz; addr++) {
-		if (verbose)
-			curbar = update_status("Failsafe", addr, isbufsz, curbar);
-
-		flash_write_byte(addr, isbuf[addr]);
+		data = flash_read(tvdev, addr);
+		for (i = 0; i < 4; i++) {
+			if (isbuf[addr + i] != ((data >> ((3 - i) * 8)) & 0xFF))
+				return 1;
+		}
 	}
 
-	flash_chip_reset();
-
-	if (verbose) {
-		update_status("Failsafe", isbufsz, isbufsz, curbar);
-		printf("\n");
-	}
+	return 0;
 }
 
-static void flash_erase_failsafe_sectors(unsigned int psbufoff, unsigned int psbufsz,
-					 unsigned int ibufoff, unsigned int ibufsz)
+static void flash_move_pps_to_sps(struct tvdevice *tvdev)
 {
-	unsigned int addr, curbar = -1, totalsz = psbufsz + ibufsz;
+	unsigned int addr;
+	unsigned char *sector;
 
-	flash_chip_reset();
+	flash_chip_reset(tvdev);
 
-	for (addr = 0; addr < psbufsz; addr += failsafe.sector_sz) {
-		if (verbose)
-			curbar = update_status("Erasing", addr, totalsz, curbar);
-
-		flash_erase_sector(psbufoff + addr);
+	sector = malloc(tvdev->flash_sector_sz);
+	if (!sector) {
+		fprintf(stderr, "Unable to allocate %d bytes of memory for buffer\n",
+			tvdev->flash_sector_sz);
+		exit(1);
 	}
 
-	for (addr = 0; addr < ibufsz; addr += failsafe.sector_sz) {
-		if (verbose)
-			curbar = update_status("Erasing", psbufsz + addr, totalsz, curbar);
+	for (addr = 0; addr < tvdev->flash_sector_sz; addr += 4) {
+		uint32_t data;
+		int i;
 
-		flash_erase_sector(ibufoff + addr);
+		data = flash_read(tvdev, tvdev->flash_sector_sz + addr);
+		for (i = 0; i < 4; i++)
+			sector[addr + i] = ((data >> ((3 - i) * 8)) & 0xFF);
 	}
 
-	flash_chip_reset();
+	/* Erase the SPS sector */
+	status_update('E', 0);
+	flash_erase_sector(tvdev, tvdev->flash_sector_sz * 2);
 
-	if (verbose) {
-		update_status("Erasing", totalsz, totalsz, curbar);
-		printf("\n");
-	}
-}
+	/* Write the old PPS as the SPS */
+	flash_write_block(tvdev, 'F', tvdev->flash_sector_sz * 2, sector, tvdev->flash_sector_sz);
+	status_mark();
 
-static void flash_write_failsafe_image(unsigned int psbufoff, unsigned char *psbuf,
-				       unsigned int psbufsz, unsigned int ibufoff,
-				       unsigned char *ibuf, unsigned int ibufsz)
-{
-	unsigned int addr, curbar = -1, totalsz = psbufsz + ibufsz;
+	flash_chip_reset(tvdev);
 
-	flash_chip_reset();
-
-	/* Set the image offset and size */
-	*(uint32_t *)(psbuf + 0x0) = htonl(ibufoff);
-	*(uint32_t *)(psbuf + 0x4) = htonl(ibufsz);
-
-	/* Set CRC and Signature to something invalid for now */
-	*(uint32_t *)(psbuf + 0x8) = 0xFFFFFFFF;
-	*(uint16_t *)(psbuf + 0x106) = 0xFFFF;
-
-	for (addr = 0; addr < psbufsz; addr++) {
-		if (verbose)
-			curbar = update_status("Writing", addr, totalsz, curbar);
-
-		flash_write_byte(psbufoff + addr, psbuf[addr]);
-	}
-
-	for (addr = 0; addr < ibufsz; addr++) {
-		if (verbose)
-			curbar = update_status("Writing", psbufsz + addr, totalsz, curbar);
-
-		flash_write_byte(ibufoff + addr, ibuf[addr]);
-	}
-
-	flash_chip_reset();
-
-	if (verbose) {
-		update_status("Writing", totalsz, totalsz, curbar);
-		printf("\n");
-	}
+	free(sector);
 }
 
-static int flash_verify_failsafe_image(unsigned int psbufoff, unsigned char *psbuf,
-				       unsigned int psbufsz, unsigned int ibufoff,
-				       unsigned char *ibuf, unsigned int ibufsz)
+static void flash_write_invariant_sector(struct tvdevice *tvdev, unsigned char *isbuf,
+	unsigned int isbufsz)
 {
-	unsigned int addr, data, curbar = -1, totalsz = psbufsz + ibufsz;
+	flash_chip_reset(tvdev);
 
-	flash_chip_reset();
+	status_update('E', 0);
+	flash_erase_sector(tvdev, 0);
+	flash_write_block(tvdev, 'I', 0, isbuf, isbufsz);
+	status_mark();
 
-	for (addr = 0; addr < ibufsz; addr += 4) {
-		int i;
-
-		if (verbose)
-			curbar = update_status("Verifying", addr, totalsz, curbar);
-
-		data = flash_read(ibufoff + addr);
-
-		for (i = 0; i < 4; i++) {
-			if (ibuf[addr + i] != ((data >> ((3 - i) * 8)) & 0xFF)) {
-				if (verbose)
-					printf("\n");
-
-				return 1;
-			}
-		}
-	}
-
-	for (addr = 0; addr < psbufsz; addr += 4) {
-		int i;
-
-		if (verbose)
-			curbar = update_status("Verifying", ibufsz + addr, totalsz, curbar);
-
-		data = flash_read(psbufoff + addr);
-
-		for (i = 0; i < 4; i++) {
-			if (psbuf[addr + i] != ((data >> ((3 - i) * 8)) & 0xFF)) {
-				if (verbose)
-					printf("\n");
-
-				return 1;
-			}
-		}
-	}
-
-	if (verbose) {
-		update_status("Verifying", totalsz, totalsz, curbar);
-		printf("\n");
-	}
-
-	return 0;
+	flash_chip_reset(tvdev);
 }
 
-static void flash_finish_failsafe(unsigned int psbufoff, unsigned char *psbuf,
-				  unsigned int psbufsz)
+static void flash_write_pps(struct tvdevice *tvdev, unsigned int psbufoff,
+	unsigned char *psbuf, unsigned int psbufsz, unsigned int ibufoff,
+	unsigned int ibufsz)
 {
-	int i;
+	/* Set the image offset and size */
+	*(uint32_t *)(psbuf + 0x0) = cpu_to_be32(ibufoff);
+	*(uint32_t *)(psbuf + 0x4) = cpu_to_be32(ibufsz);
 
-	/* Set CRC and Signature to something invalid for now */
-	*(uint32_t *)(psbuf + 0x8) = htonl(0x5a445a44);
-	*(uint16_t *)(psbuf + 0x106) = htons(flash_crc16(psbuf, 0x104));
+	/* Set signature and CRC to all-ones for now */
+	*(uint32_t *)(psbuf + 0x8) = 0xFFFFFFFF;
+	*(uint16_t *)(psbuf + 0x106) = 0xFFFF;
 
-	/* Write the CRC */
-	for (i = 0; i < sizeof(uint16_t); i++)
-		flash_write_byte(psbufoff + 0x106 + i, psbuf[0x106 + i]);
+	/* Erase then write the PPS */
+	flash_chip_reset(tvdev);
 
-	/* Write the signature */
-	for (i = 0; i < sizeof(uint32_t); i++)
-		flash_write_byte(psbufoff + 0x8 + i, psbuf[0x8 + i]);
+	status_update('E', 0);
+	flash_erase_sector(tvdev, psbufoff);
+	flash_write_block(tvdev, 'P', psbufoff, psbuf, psbufsz);
+	status_mark();
+
+	flash_chip_reset(tvdev);
 }
 
-static void flash_erase_sectors(unsigned int ibufsz)
+static void flash_finish_failsafe(struct tvdevice *tvdev, unsigned int psbufoff,
+	unsigned char *psbuf, unsigned int psbufsz)
 {
-	unsigned int addr, curbar = -1;
+	/* Set signature and CRC to something valid */
+	*(uint32_t *)(psbuf + 0x8) = cpu_to_be32(0x5a445a44);
+	*(uint16_t *)(psbuf + 0x106) = cpu_to_be16(flash_crc16(psbuf, 0x104));
 
-	flash_chip_reset();
+	/* Write CRC and signature */
+	flash_chip_reset(tvdev);
 
-	for (addr = 0; addr < ibufsz; addr += failsafe.sector_sz) {
-		if (verbose)
-			curbar = update_status("Erasing", addr, ibufsz, curbar);
+	flash_write_block(tvdev, 0, psbufoff + 0x106, psbuf + 0x106, sizeof(uint16_t));
+	flash_write_block(tvdev, 0, psbufoff + 0x8, psbuf + 0x8, sizeof(uint32_t));
 
-		flash_erase_sector(addr);
-	}
-
-	flash_chip_reset();
-
-	if (verbose) {
-		update_status("Erasing", ibufsz, ibufsz, curbar);
-		printf("\n");
-	}
+	flash_chip_reset(tvdev);
 }
 
-static void flash_write_image(unsigned char *ibuf, unsigned int ibufsz)
+static void flash_write_image(struct tvdevice *tvdev, unsigned int ibufoff,
+	unsigned char *ibuf, unsigned int ibufsz)
 {
-	unsigned int addr, curbar = -1;
+	unsigned int addr;
 
-	flash_chip_reset();
+	/* Erase then write the firmware image */
+	for (addr = 0; addr < ibufsz; addr += tvdev->flash_sector_sz) {
+		unsigned int len = tvdev->flash_sector_sz;
 
-	for (addr = 0; addr < ibufsz; addr++) {
-		if (verbose)
-			curbar = update_status("Writing", addr, ibufsz, curbar);
+		if (len > ibufsz - addr)
+			len = ibufsz - addr;
 
-		flash_write_byte(addr, ibuf[addr]);
+		status_update('E', 0);
+		flash_erase_sector(tvdev, ibufoff + addr);
+		flash_write_block(tvdev, 'W', ibufoff + addr, ibuf + addr, len);
+		status_mark();
 	}
 
-	flash_chip_reset();
-
-	if (verbose) {
-		update_status("Writing", ibufsz, ibufsz, curbar);
-		printf("\n");
-	}
+	flash_chip_reset(tvdev);
 }
 
-static int flash_verify_image(unsigned char *ibuf, unsigned int ibufsz)
+static unsigned int flash_verify_image(struct tvdevice *tvdev, unsigned int off,
+	unsigned char *buf, unsigned int bufsz)
 {
-	unsigned int addr, data, curbar = -1;
+	unsigned int addr, data;
 
-	flash_chip_reset();
+	flash_chip_reset(tvdev);
 
-	for (addr = 0; addr < ibufsz; addr += 4) {
+	for (addr = 0; addr < bufsz; addr += 4) {
 		int i;
 
-		if (verbose)
-			curbar = update_status("Verifying", addr, ibufsz, curbar);
+		status_update('V', addr);
 
-		data = flash_read(addr);
-
+		data = flash_read(tvdev, off + addr);
 		for (i = 0; i < 4; i++) {
-			if (ibuf[addr + i] != ((data >> ((3 - i) * 8)) & 0xFF)) {
-				if (verbose)
-					printf("\n");
-
-				return 1;
-			}
+			if (buf[addr + i] != ((data >> ((3 - i) * 8)) & 0xFF))
+				return addr + i;
 		}
 	}
+	status_mark();
 
-	if (verbose) {
-		update_status("Verifying", ibufsz, ibufsz, curbar);
-		printf("\n");
-	}
-
-	return 0;
+	return addr;
 }
 
-static void usage(void)
+static int upload_firmware(int hca, char *ifname, char *guid, char *change_option_cmd)
 {
-	fprintf(stderr, "Usage: %s [OPTION]...\n", argv0);
-	fprintf(stderr, "  -q\t\tProduce less output (quieter)\n");
-	fprintf(stderr, "  -v\t\tProduce more output (verbose)\n");
-	fprintf(stderr, "  -f\t\tForce operation (use cautiously)\n\n");
-	fprintf(stderr, "  -c\t\tAlways use PCI config space\n\n");
-	fprintf(stderr, "  -h <num>\tSelect HCA to use for operation (default: 0)\n");
-	fprintf(stderr, "One operation mode must be specified:\n");
-	fprintf(stderr, "  -i\t\tIdentify HCAs\n");
-	fprintf(stderr, "  -s <filename>\n\t\tSave firmware programmed on flash device to local file\n");
-	fprintf(stderr, "  [-d] <filename> [<Node GUID>]\n\t\tDownload firmware to flash device from local file\n\n");
-	fprintf(stderr, "When specifying a GUID, use only the lower 24 bits in hexadecimal format.\n");
-
-	exit(1);
-}
-
-static int upload_firmware(int hca, char *ifname, char *guid, int autoupgrade)
-{
 	struct tvdevice *tvdev;
 	unsigned char *isbuf, *psbuf, *ibuf;
-	unsigned int isbufsz, psbufsz, ibufsz;
+	unsigned int isbufsz, psbufsz, ibufsz, addr, status_count;
 	unsigned char new_guid_node[GUID_LEN], new_guid_port1[GUID_LEN],
-                new_guid_port2[GUID_LEN];
-	int sector = 0;
-	int ret;
+	new_guid_port2[GUID_LEN];
+	int ret = 1, sector = 0, program_is = 0;
 
 	tvdev = find_device(hca);
 	if (!tvdev) {
@@ -1799,16 +2431,13 @@
 		return 1;
 	}
 
-	ret = open_hca(tvdev);
-	if (ret)
-		return ret;
+	if (open_hca(tvdev)) {
+		fprintf(stderr, "couldn't open hca %d\n", hca);
+		return 1;
+	}
 
-	mtflash_init();
-	flash_chip_reset();
-	grab_gpio();
+	flash_check_failsafe(tvdev);
 
-	flash_check_failsafe();
-
 	if (guid) {
 		/* GUIDs given to us on command line */
 		if (parse_guid(guid, new_guid_node)) {
@@ -1817,40 +2446,46 @@
 		}
 
 		inc_guid(new_guid_node, new_guid_port1);
-		inc_guid(new_guid_port1, new_guid_port2);
+		if (tvdev->board->num_ports > 1)
+			inc_guid(new_guid_port1, new_guid_port2);
 	} else {
 		/* Preserve the current GUIDs */
-		if (flash_get_curr_guids(new_guid_node, new_guid_port1, new_guid_port2)) {
+		if (flash_get_curr_guids(tvdev, new_guid_node, new_guid_port1,
+					 new_guid_port2)) {
 			fprintf(stderr, "Cannot determine previous GUID. Corrupted flash?\n");
 			fprintf(stderr, "GUID must be specified on command line.\n\n");
 			usage();
 		}
 
 		/*
-		 * Now we check the GUIDs to make sure they are valid or could possibly
-		 * cause some confusion (the default Mellanox GUID)
+		 * Now we check the GUIDs to make sure they are valid or
+		 * could possibly cause some confusion (the default Mellanox
+		 * GUID)
 		 */
-		if ((memcmp(new_guid_node,  "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) ||
-		    (memcmp(new_guid_port1, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) ||
-		    (memcmp(new_guid_port2, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0)) {
+		if (memcmp(new_guid_node,  "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0 ||
+		    memcmp(new_guid_port1, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0 ||
+		    (tvdev->board->num_ports > 1 &&
+		     memcmp(new_guid_port2, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0)) {
 			fprintf(stderr, "GUIDs read from flash are all zeros. Corrupted flash?\n");
 			fprintf(stderr, "GUID must be specified on command line.\n\n");
 			usage();
 		}
 
-		if ((memcmp(new_guid_node,  "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0) ||
-		    (memcmp(new_guid_port1, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0) ||
-		    (memcmp(new_guid_port2, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0)) {
+		if (memcmp(new_guid_node,  "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0 ||
+		    memcmp(new_guid_port1, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0 ||
+		    (tvdev->board->num_ports > 1 &&
+		     memcmp(new_guid_port2, "\xff\xff\xff\xff\xff\xff\xff\xff", 8) == 0)) {
 			fprintf(stderr, "GUIDs read from flash are all ones. Device access error?\n");
 			fprintf(stderr, "GUID must be specified on command line.\n\n");
 			usage();
 		}
 
-		if (((memcmp(new_guid_node,  "\x00\x02\xc9\x00\x01\x00\xd0\x50", 8) == 0) ||
-		     (memcmp(new_guid_port1, "\x00\x02\xc9\x00\x01\x00\xd0\x51", 8) == 0) ||
-		     (memcmp(new_guid_port2, "\x00\x02\xc9\x00\x01\x00\xd0\x52", 8) == 0)) &&
+		if ((memcmp(new_guid_node,  "\x00\x02\xc9\x00\x01\x00\xd0\x50", 8) == 0 ||
+		     memcmp(new_guid_port1, "\x00\x02\xc9\x00\x01\x00\xd0\x51", 8) == 0 ||
+		     (tvdev->board->num_ports > 1 &&
+		      memcmp(new_guid_port2, "\x00\x02\xc9\x00\x01\x00\xd0\x52", 8) == 0)) &&
 		    !force) {
-			fprintf(stderr, "GUIDs read from flash are vendor default GUIDs. It is not reccomended\n");
+			fprintf(stderr, "GUIDs read from flash are vendor default GUIDs. It is not recommended\n");
 			fprintf(stderr, "that these GUIDs be used because of a high chance of GUID conflict.\n");
 			fprintf(stderr, "Please specify new GUID on command line, or use -f option.\n");
 			usage();
@@ -1858,8 +2493,8 @@
 	}
 
 	/* Read the flash image into the memory */
-	if (flash_image_read_from_file(ifname, &isbuf, &isbufsz, &psbuf, &psbufsz,
-				       &ibuf, &ibufsz))
+	if (flash_image_read_from_file(ifname, &isbuf, &isbufsz, &psbuf,
+				       &psbufsz, &ibuf, &ibufsz))
 		return 1;
 
 	if (psbuf) {
@@ -1867,118 +2502,111 @@
 
 		vsd = (union vsd *)(psbuf + 0x20);
 
-		if (ntohs(vsd->data.signature) == 0x05ad &&
-		    ntohs(vsd->data.vendor.topspin.signature2) == 0x05ad) {
+		if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+		    be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN) {
+			union vsd *fvsd = &tvdev->failsafe.images[0].vsd;
+
 			/* Update the time the image was flashed */
-			vsd->data.vendor.topspin.flashtime = htonl(time(NULL));
+			vsd->data.vendor.topspin.flashtime = cpu_to_be32(time(NULL));
 
-			/* Set any flags */
-			if (autoupgrade)
-				vsd->data.vendor.topspin.flags |= htonl(VSD_FLAG_AUTOUPGRADE);
-			else
-				vsd->data.vendor.topspin.flags &= ~htonl(VSD_FLAG_AUTOUPGRADE);
+			/* Set default value, we'll overwrite this if we need to */
+			vsd->data.vendor.topspin.flags |= cpu_to_be32(VSD_FLAG_AUTOUPGRADE);
 
 			/* Copy over boot ROM options from old VSD */
-			vsd->data.vendor.topspin.flags &= ~htonl(VSD_FLAG_BOOT_OPTIONS);
-			vsd->data.vendor.topspin.flags |= (failsafe.images[0].vsd.data.vendor.topspin.flags & htonl(VSD_FLAG_BOOT_OPTIONS));
+			vsd->data.vendor.topspin.flags &= ~cpu_to_be32(VSD_FLAG_BOOT_OPTIONS);
+			vsd->data.vendor.topspin.flags |= (fvsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_OPTIONS));
 
-			if (vsd->data.vendor.topspin.flags & htonl(VSD_FLAG_BOOT_OPTIONS)) {
-				vsd->data.vendor.topspin.flags &= ~htonl(VSD_FLAG_BOOT_OPTIONS_MASK);
-				vsd->data.vendor.topspin.flags |= (failsafe.images[0].vsd.data.vendor.topspin.flags & htonl(VSD_FLAG_BOOT_OPTIONS_MASK));
+			if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_OPTIONS)) {
+				vsd->data.vendor.topspin.flags &= ~cpu_to_be32(VSD_FLAG_BOOT_OPTIONS_MASK);
+				vsd->data.vendor.topspin.flags |= (fvsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_OPTIONS_MASK));
 
-				vsd->data.vendor.topspin.boot_version = failsafe.images[0].vsd.data.vendor.topspin.boot_version;
-				vsd->data.vendor.topspin.boot_port = failsafe.images[0].vsd.data.vendor.topspin.boot_port;
-				vsd->data.vendor.topspin.boot_ioc_num = failsafe.images[0].vsd.data.vendor.topspin.boot_ioc_num;
-				memcpy(vsd->data.vendor.topspin.boot_dgid, failsafe.images[0].vsd.data.vendor.topspin.boot_dgid,
-				       sizeof(vsd->data.vendor.topspin.boot_dgid));
-				vsd->data.vendor.topspin.boot_service_name[0] = failsafe.images[0].vsd.data.vendor.topspin.boot_service_name[0];
-				vsd->data.vendor.topspin.boot_service_name[1] = failsafe.images[0].vsd.data.vendor.topspin.boot_service_name[1];
+				vsd->data.vendor.topspin.boot_version = fvsd->data.vendor.topspin.boot_version;
+				vsd->data.vendor.topspin.boot_port = fvsd->data.vendor.topspin.boot_port;
+				vsd->data.vendor.topspin.boot_ioc_num = fvsd->data.vendor.topspin.boot_ioc_num;
+				memcpy(vsd->data.vendor.topspin.boot_dgid,
+					fvsd->data.vendor.topspin.boot_dgid,
+					sizeof(vsd->data.vendor.topspin.boot_dgid));
+				memcpy(vsd->data.vendor.topspin.boot_service_name,
+					fvsd->data.vendor.topspin.boot_service_name,
+					sizeof(vsd->data.vendor.topspin.boot_service_name));
+				vsd->data.vendor.topspin.boot_pxe_secs = fvsd->data.vendor.topspin.boot_pxe_secs;
 			} else {
 				/* Set some sensible defaults */
-				vsd->data.vendor.topspin.flags |= htonl(VSD_FLAG_BOOT_OPTIONS |
-							 VSD_FLAG_BOOT_ENABLE_PORT_1 |
-							 VSD_FLAG_BOOT_ENABLE_PORT_2 |
-							 VSD_FLAG_BOOT_ENABLE_SCAN |
-							 VSD_FLAG_BOOT_TYPE_WELL_KNOWN);
+				vsd->data.vendor.topspin.flags |= cpu_to_be32(VSD_FLAG_BOOT_OPTIONS |
+					 VSD_FLAG_BOOT_ENABLE_PORT_1 |
+					 VSD_FLAG_BOOT_ENABLE_PORT_2 |
+					 VSD_FLAG_BOOT_ENABLE_SCAN |
+					 VSD_FLAG_BOOT_TYPE_WELL_KNOWN);
 				vsd->data.vendor.topspin.boot_version = BOOT_VERSION;
+				vsd->data.vendor.topspin.boot_pxe_secs = BOOT_PXE_SECS_DEFAULT;
 			}
 
+			if (change_option_cmd &&
+			    parse_change_options(&vsd->data.vendor.topspin, change_option_cmd))
+				return 1;
+
 			/* Calculate the VSD checksum */
 			vsd->data.checksum = 0;
-			vsd->data.checksum = htons(flash_crc16(vsd->raw, sizeof(vsd->raw)));
+			vsd->data.checksum = cpu_to_be16(flash_crc16(vsd->raw, sizeof(vsd->raw)));
 		}
 
-		/* Calculate the PPS checksum */
-		*(uint16_t *)(psbuf + 0x106) = htons(flash_crc16(psbuf, 0x104));
+		/* PPS checksum will be updated as a final step */
 
-		if (ntohs(vsd->data.signature) == 0x05ad &&
-		    ntohs(vsd->data.vendor.topspin.signature2) == 0x05ad &&
+		if (be16_to_cpu(vsd->data.signature) == VSD_SIGNATURE_TOPSPIN &&
+		    be16_to_cpu(vsd->data.vendor.topspin.signature2) == VSD_SIGNATURE_TOPSPIN &&
 		    !force) {
-			unsigned char revision;
-			char *incompatible = NULL;
-			int board;
+			if (tvdev->board->fwlabel) {
+				char hwlabel[64];
 
-			vpd_read(tvdev, tvdev->pdev);
+				/*
+				 * Check to make sure this file is correct for
+				 * the hardware. We check only as far as the
+				 * hwlabel since boot firmware will have extra
+				 * information appended to the label.
+				 */
+				snprintf(hwlabel, sizeof(hwlabel), "%s.%02X",
+					tvdev->board->fwlabel, tvdev->revision);
+				if (strncasecmp(vsd->data.vendor.topspin.hw_label, hwlabel, strlen(hwlabel)) != 0) {
+					fprintf(stderr, "Firmware image specified has hardware label '%s', but hardware\n",
+						vsd->data.vendor.topspin.hw_label);
+					fprintf(stderr, "is of type '%s'. Please confirm you are using the correct\n",
+						hwlabel);
+					fprintf(stderr, "firmware or use the force option (-f).\n");
+					return 1;
+				}
+			} else {
+				if (tvdev->flags & FLAG_RECOVERY) {
+					fprintf(stderr, "WARNING: Unable to verify firmware image is appropriate for hardware when\n");
+					fprintf(stderr, "hardware is in flash recovery mode.\n");
+				} else
+					fprintf(stderr, "WARNING: Unable to verify firmware image is appropriate for unknown hardware.\n");
 
-			revision = pci_read_word(tvdev->pdev, PCI_CLASS_REVISION) & 0xff;
-
-			/* According to the documentation, a revision of 0x00 is an A0 */
-			if (revision == 0x00)
-				revision = 0xA0;
-
-			board = identify_board(tvdev);
-
-			/* Check to make sure this file is correct for the hardware */
-			if (board == BOARD_JAGUAR && revision == 0xA0 &&
-			    strncmp(vsd->data.vendor.topspin.hw_label,
-				    BOARD_JAGUAR_A0_STR, strlen(BOARD_JAGUAR_A1_STR)) != 0)
-				incompatible = BOARD_JAGUAR_A0_STR;
-			else if (board == BOARD_JAGUAR && revision == 0xA1 &&
-				 strncmp(vsd->data.vendor.topspin.hw_label,
-					 BOARD_JAGUAR_A1_STR, strlen(BOARD_JAGUAR_A1_STR)) != 0)
-				incompatible = BOARD_JAGUAR_A1_STR;
-			else if (board == BOARD_COUGAR && revision == 0xA1 &&
-				 strncmp(vsd->data.vendor.topspin.hw_label,
-					 BOARD_COUGAR_A1_STR, strlen(BOARD_COUGAR_A1_STR)) != 0)
-				incompatible = BOARD_COUGAR_A1_STR;
-			else if (board == BOARD_COUGARCUB && revision == 0xA1 &&
-				 strncmp(vsd->data.vendor.topspin.hw_label,
-					 BOARD_COUGARCUB_A1_STR, strlen(BOARD_COUGARCUB_A1_STR)) != 0)
-				incompatible = BOARD_COUGARCUB_A1_STR;
-			else if (board == BOARD_LIONCUB && revision == 0xA0 &&
-				 strncmp(vsd->data.vendor.topspin.hw_label,
-					 BOARD_LIONCUB_A0_STR, strlen(BOARD_LIONCUB_A0_STR)) != 0)
-				incompatible = BOARD_LIONCUB_A0_STR;
-
-			if (incompatible) {
-				fprintf(stderr, "Firmware image specified has hardware label '%s', but hardware\n", vsd->data.vendor.topspin.hw_label);
-				fprintf(stderr, "is of type '%s'. Please confirm you are using the correct\n", incompatible);
-				fprintf(stderr, "firmware or use the force option (-f).\n");
-				return 1;
+				fprintf(stderr, "Will upload flash image in 20 seconds or hit Ctrl-C to exit.\n");
+				sleep(20);
 			}
 		}
 
-		if (failsafe.valid) {
+		if (tvdev->failsafe.valid) {
 			/* We'll always use the space opposite of the PPS */
-			if (failsafe.images[0].addr + failsafe.images[0].size < TV_FLASH_SIZE / 2)
-				sector = (TV_FLASH_SIZE / 2) / failsafe.sector_sz;
-			else if (failsafe.images[0].addr >= failsafe.sector_sz * 3 + ibufsz)
+			if (tvdev->failsafe.images[0].addr + tvdev->failsafe.images[0].size < tvdev->flash_size / 2)
+				sector = (tvdev->flash_size / 2) / tvdev->flash_sector_sz;
+			else if (tvdev->failsafe.images[0].addr >= tvdev->flash_sector_sz * 3 + ibufsz)
 				sector = 3;
 			else {
-				fprintf(stderr, "Unable to fit new image (size 0x%x) on flash in Failsafe mode\n", ibufsz);
+				fprintf(stderr, "Unable to fit new image (size 0x%x) on flash in Failsafe mode\n",
+					ibufsz);
 				exit(1);
 			}
-		} else {
+		} else
 			/* No Invariant Sector yet (will be programmed below) */
 			sector = 3;
-		}
-	} else if (ibufsz > TV_FLASH_SIZE) {
+	} else if (ibufsz > tvdev->flash_size) {
 		fprintf(stderr, "Image size is larger than size of flash (0x%X)\n",
-			TV_FLASH_SIZE);
+			tvdev->flash_size);
 		return 1;
 	}
 
-	if (failsafe.valid && !psbuf) {
+	if (tvdev->failsafe.valid && !psbuf) {
 		if (!force) {
 			/* Flash is in Failsafe mode, but image doesn't have Failsafe information */
 			printf("Flash is in failsafe mode, but image is not a failsafe firmware image.\n");
@@ -1992,59 +2620,292 @@
 		}
 	}
 
-	if (flash_guids_update(ibuf, ibufsz, new_guid_node, new_guid_port1, new_guid_port2))
+	if (flash_guids_update(tvdev, ibuf, ibufsz, new_guid_node,
+	new_guid_port1, new_guid_port2))
 		return 1;
 
-	printf("Programming HCA Microcode... Flash Image Size = %d\n", ibufsz);
+	/* Compare the currently programmed IS with the IS from the file */
+	if (isbuf) {
+		if (force > 1) {
+			/* User specified -ff, always upgrade IS */
+			if (tvdev->failsafe.valid) {
+				/* But warn if the firmware is already in failsafe mode, just in case */
+				printf("WARNING: Flash reprogramming won't be failsafe, continuing in 10 seconds\n");
+				sleep(10);
+			}
 
-	if (!failsafe.valid && isbuf)
+			program_is = 1;
+		} else if (flash_compare_invariant_sector(tvdev, isbuf, isbufsz) != 0) {
+			/* IS is out-of-date, so we need to upgrade it */
+			printf("WARNING: Out-of-date Invariant sector found. Flash reprogramming won't be\n");
+			printf("failsafe, continuing in 10 seconds\n");
+			sleep(10);
+			program_is = 1;
+		} else if (!tvdev->failsafe.valid)
+			/* Not in failsafe, so it's safe to silently program the IS */
+			program_is = 1;
+	}
+
+	printf("Programming HCA firmware... Flash Image Size = %d\n", ibufsz);
+
+	if (psbuf) {
+		status_count = psbufsz + ibufsz + psbufsz + ibufsz;
+		if (tvdev->failsafe.images[0].valid)
+			status_count += tvdev->flash_sector_sz;
+	} else
+		status_count = ibufsz + ibufsz;
+
+	if (program_is) {
 		/* Program the Invariant Sector first */
-		flash_write_invariant_sector(isbuf, isbufsz);
+		status_start(status_count + isbufsz + isbufsz);
+		flash_write_invariant_sector(tvdev, isbuf, isbufsz);
 
+		addr = flash_verify_image(tvdev, 0, isbuf, isbufsz);
+		if (addr < isbufsz) {
+			status_stop();
+			printf("Flash verify of IS FAILED @ %d (%d total)\n",
+				addr, isbufsz);
+			ret = 1;
+			goto verify_failed;
+		}
+	} else
+		status_start(status_count);
+
 	if (psbuf) {
-		if (failsafe.images[0].valid)
-			/* Move the PPS to the SPS */
-			flash_move_pps_to_sps();
+		if (tvdev->failsafe.images[0].valid)
+			flash_move_pps_to_sps(tvdev);
 
-		/* Erase all of the sectors we'll be writing into */
-		flash_erase_failsafe_sectors(failsafe.sector_sz, psbufsz,
-					     sector * failsafe.sector_sz, ibufsz);
-		/* Write the PPS and the image */
-		flash_write_failsafe_image(failsafe.sector_sz, psbuf, psbufsz,
-					   sector * failsafe.sector_sz, ibuf, ibufsz);
-		/* Verify the PPS and the image */
-		if (flash_verify_failsafe_image(failsafe.sector_sz, psbuf, psbufsz,
-						sector * failsafe.sector_sz, ibuf, ibufsz))
+		/* Write the PPS and image */
+		flash_write_pps(tvdev, tvdev->flash_sector_sz, psbuf, psbufsz,
+		sector * tvdev->flash_sector_sz, ibufsz);
+		flash_write_image(tvdev, sector * tvdev->flash_sector_sz, ibuf, ibufsz);
+
+		/* Verify the PPS and image */
+		addr = flash_verify_image(tvdev, tvdev->flash_sector_sz, psbuf, psbufsz);
+		if (addr < psbufsz) {
+			status_stop();
+			printf("Flash verify of PPS FAILED @ %d (%d total)\n",
+				addr, psbufsz);
+			ret = 1;
 			goto verify_failed;
+		}
 
+		addr = flash_verify_image(tvdev, sector * tvdev->flash_sector_sz, ibuf, ibufsz);
+		if (addr < ibufsz) {
+			status_stop();
+			printf("Flash verify of image FAILED @ %d (%d total)\n",
+				addr, ibufsz);
+			ret = 1;
+			goto verify_failed;
+		}
+
 		/* Finish writing the PPS */
-		flash_finish_failsafe(failsafe.sector_sz, psbuf, psbufsz);
+		flash_finish_failsafe(tvdev, tvdev->flash_sector_sz, psbuf, psbufsz);
 	} else {
-		flash_erase_sectors(ibufsz);
-		flash_write_image(ibuf, ibufsz);
-		if (flash_verify_image(ibuf, ibufsz))
+		flash_write_image(tvdev, 0, ibuf, ibufsz);
+		addr = flash_verify_image(tvdev, 0, ibuf, ibufsz);
+		if (addr < ibufsz) {
+			status_stop();
+			printf("Flash verify of image FAILED @ %d (%d total)\n",
+				addr, ibufsz);
+			ret = 1;
 			goto verify_failed;
+		}
 	}
 
+	status_stop();
+
+	ret = 0;
+
 	printf("Flash verify passed!\n");
 
-	release_gpio();
-	close_hca();
+verify_failed:
+	close_hca(tvdev);
 
+	return ret;
+}
+
+static int modify_options(int hca, char *change_option_cmd)
+{
+	struct tvdevice *tvdev;
+	union vsd *vsd;
+	unsigned char *psbuf;
+	int i;
+
+	tvdev = find_device(hca);
+	if (!tvdev) {
+		fprintf(stderr, "couldn't find HCA #%d on the PCI bus\n", hca);
+		return 1;
+	}
+
+	if (open_hca(tvdev)) {
+		fprintf(stderr, "couldn't open hca %d\n", hca);
+		return 1;
+	}
+
+	flash_check_failsafe(tvdev);
+
+	psbuf = malloc(tvdev->flash_sector_sz);
+	if (!psbuf) {
+		fprintf(stderr, "couldn't allocate temp buffer for PPS/SPS (size = %d)\n",
+			tvdev->flash_sector_sz);
+		exit(1);
+	}
+
+	for (i = 0; i < tvdev->flash_sector_sz; i += 4)
+		*(uint32_t *)(psbuf + i) = be32_to_cpu(flash_read(tvdev, tvdev->flash_sector_sz + i));
+
+	vsd = (union vsd *)(psbuf + 0x20);
+
+	if (be16_to_cpu(vsd->data.signature) != VSD_SIGNATURE_TOPSPIN ||
+	    be16_to_cpu(vsd->data.vendor.topspin.signature2) != VSD_SIGNATURE_TOPSPIN) {
+		/* Not out VSD format, so nothing to print */
+		printf("error: VSD not in Topspin format\n");
+		return 1;
+	}
+
+	fixup_topspin_vsd(&vsd->data.vendor.topspin);
+
+	if (change_option_cmd[0] == 0) {
+		if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_AUTOUPGRADE))
+			printf("  auto_upgrade=yes\n");
+		else
+			printf("  auto_upgrade=no\n");
+
+		if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_1))
+			printf("  boot_enable_port_1=yes\n");
+		else
+			printf("  boot_enable_port_1=no\n");
+
+		if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_ENABLE_PORT_2))
+			printf("  boot_enable_port_2=yes\n");
+		else
+			printf("  boot_enable_port_2=no\n");
+
+		if (!(vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_ENABLE_SCAN)))
+			printf("  boot_service_scan=no\n");
+
+		if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_WAIT_ON_ERROR))
+			printf("  boot_wait_on_error=yes\n");
+		else
+			printf("  boot_wait_on_error=no\n");
+
+		if (vsd->data.vendor.topspin.flags & cpu_to_be32(VSD_FLAG_BOOT_TRY_FOREVER))
+			printf("  boot_try_forever=yes\n");
+		else
+			printf("  boot_try_forever=no\n");
+
+		switch (be32_to_cpu(vsd->data.vendor.topspin.flags) & VSD_FLAG_BOOT_TYPE) {
+		case VSD_FLAG_BOOT_TYPE_WELL_KNOWN:
+			printf("  boot_type=well_known\n");
+			break;
+		case VSD_FLAG_BOOT_TYPE_SAVED:
+			printf("  boot_type=saved\n");
+			break;
+		case VSD_FLAG_BOOT_TYPE_PXE:
+			printf("  boot_type=pxe\n");
+			break;
+		case VSD_FLAG_BOOT_TYPE_DISABLE:
+			printf("  boot_type=disable\n");
+			break;
+		default:
+			printf("  boot_type=unknown\n");
+			break;
+		}
+
+		printf("  boot_saved_port=%d\n", vsd->data.vendor.topspin.boot_port);
+		printf("  boot_saved_ioc_num=%d\n", vsd->data.vendor.topspin.boot_ioc_num);
+		printf("  boot_saved_dgid=%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
+			vsd->data.vendor.topspin.boot_dgid[0],  vsd->data.vendor.topspin.boot_dgid[1],
+			vsd->data.vendor.topspin.boot_dgid[2],  vsd->data.vendor.topspin.boot_dgid[3],
+			vsd->data.vendor.topspin.boot_dgid[4],  vsd->data.vendor.topspin.boot_dgid[5],
+			vsd->data.vendor.topspin.boot_dgid[6],  vsd->data.vendor.topspin.boot_dgid[7],
+			vsd->data.vendor.topspin.boot_dgid[8],  vsd->data.vendor.topspin.boot_dgid[9],
+			vsd->data.vendor.topspin.boot_dgid[10], vsd->data.vendor.topspin.boot_dgid[11],
+			vsd->data.vendor.topspin.boot_dgid[12], vsd->data.vendor.topspin.boot_dgid[13],
+			vsd->data.vendor.topspin.boot_dgid[14], vsd->data.vendor.topspin.boot_dgid[15]);
+		printf("  boot_saved_service_name=%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
+			vsd->data.vendor.topspin.boot_service_name[0],
+			vsd->data.vendor.topspin.boot_service_name[1],
+			vsd->data.vendor.topspin.boot_service_name[2],
+			vsd->data.vendor.topspin.boot_service_name[3],
+			vsd->data.vendor.topspin.boot_service_name[4],
+			vsd->data.vendor.topspin.boot_service_name[5],
+			vsd->data.vendor.topspin.boot_service_name[6],
+			vsd->data.vendor.topspin.boot_service_name[7]);
+		printf("  boot_pxe_secs=%d\n", vsd->data.vendor.topspin.boot_pxe_secs);
+	} else {
+		if (parse_change_options(&vsd->data.vendor.topspin, change_option_cmd))
+			return 1;
+
+		/* Calculate the VSD checksum */
+		vsd->data.checksum = 0;
+		vsd->data.checksum = cpu_to_be16(flash_crc16(vsd->raw, sizeof(vsd->raw)));
+
+		/* Set signature and CRC to all-ones for now */
+		*(uint32_t *)(psbuf + 0x8) = 0xFFFFFFFF;
+		*(uint16_t *)(psbuf + 0x106) = 0xFFFF;
+
+		flash_chip_reset(tvdev);
+
+		status_start(tvdev->flash_sector_sz);
+
+		status_update('E', 0);
+		flash_erase_sector(tvdev, tvdev->flash_sector_sz);
+		flash_write_block(tvdev, 'F', tvdev->flash_sector_sz, psbuf, tvdev->flash_sector_sz);
+		status_mark();
+
+		flash_chip_reset(tvdev);
+
+		flash_finish_failsafe(tvdev, tvdev->flash_sector_sz, psbuf, tvdev->flash_sector_sz);
+
+		status_stop();
+	}
+
+	free(psbuf);
+
+	close_hca(tvdev);
+
 	return 0;
+}
 
-verify_failed:
-	printf("Flash verify failed!\n");
+static void usage(void)
+{
+	fprintf(stderr, "Usage: %s [OPTION]...\n", argv0);
+	fprintf(stderr, "  -q\t\tProduce less output (quieter)\n");
+	fprintf(stderr, "  -v\t\tProduce more output (verbose)\n");
+	fprintf(stderr, "  -f\t\tForce operation (use cautiously)\n");
+	fprintf(stderr, "  -p\t\tUser PCI config space access instead of memory mapping\n");
+	fprintf(stderr, "  -h <num>\tSelect HCA to use for operation (default: 0)\n");
+	fprintf(stderr, "  -o [<cmd>]\tChange options command (no command shows current values)\n");
+	fprintf(stderr, "    The following commands and values are accepted:\n");
+	fprintf(stderr, "      auto_upgrade              [yes|no]\n");
+	fprintf(stderr, "      boot_enable_port1         [yes|no]\n");
+	fprintf(stderr, "      boot_enable_port2         [yes|no]\n");
+	fprintf(stderr, "      boot_wait_on_error        [yes|no]\n");
+	fprintf(stderr, "      boot_try_forever          [yes|no]\n");
+	fprintf(stderr, "      boot_type                 [well_known|saved|pxe|disable]\n");
+	fprintf(stderr, "      boot_saved_port           [0|1|2]\n");
+	fprintf(stderr, "      boot_saved_ioc_num        ##\n");
+	fprintf(stderr, "      boot_saved_dgid           ####:####:####:####:####:####:####:####\n");
+	fprintf(stderr, "      boot_saved_service_name   ####:####:####:####\n");
+	fprintf(stderr, "      boot_pxe_secs             ##\n");
+	fprintf(stderr, "  -u\t\tDisable autoupgrade of firmware (-o auto_upgrade=no)\n\n");
 
-	release_gpio();
-	close_hca();
+	fprintf(stderr, "One operation mode must be specified:\n");
+	fprintf(stderr, "  -i\t\tIdentify HCAs\n");
+	fprintf(stderr, "  -g\t\tPrint GUIDs programmed into firmware\n");
+	fprintf(stderr, "  -s <filename>\n\t\tSave firmware programmed on flash device to local file\n");
+	fprintf(stderr, "  [-d] <filename> [<Node GUID>]\n\t\tDownload firmware to flash device from local file\n\n");
 
-	return 1;
+	fprintf(stderr, "When specifying a GUID, use only the lower 24 bits in hexadecimal format.\n");
+
+	exit(1);
 }
 
 int main(int argc, char *argv[])
 {
-	char *filename = NULL, *guid = NULL;
+	char *filename = NULL, *guid = NULL, *change_option_cmd = NULL;
 	struct winsize winsize;
 	struct pci_access *pacc;
 	enum operation operation = OP_NONE;
@@ -2057,13 +2918,14 @@
 
 		if (sizeof(vsd.data) != sizeof(vsd.raw)) {
 			extern void __sizeof_vsd_data_doesnt_equal_sizeof_vsd_raw();
+
 			__sizeof_vsd_data_doesnt_equal_sizeof_vsd_raw();
 		}
 	}
 
 	/* Figure out the size of the window, but fall back if we can't */
 	if (ioctl(0, TIOCGWINSZ, &winsize) < 0)
-		cols = 0;
+		cols = 80;
 	else
 		cols = winsize.ws_col;
 
@@ -2072,7 +2934,7 @@
 	while (1) {
 		int c;
 
-		c = getopt(argc, argv, "qvfcuh:i::s:d:");
+		c = getopt(argc, argv, "qvfupgh:i::s:d:o::");
 		if (c == -1)
 			break;
 
@@ -2084,14 +2946,14 @@
 			verbose++;
 			break;
 		case 'f':
-			force = 1;
+			force++;
 			break;
-		case 'c':
-			config = 1;
-			break;
 		case 'u':
 			autoupgrade = 0;
 			break;
+		case 'p':
+			use_config_space = 1;
+			break;
 		case 'h': {
 			char *p;
 
@@ -2103,7 +2965,7 @@
 
 			hca = (unsigned int)ret;
 			break;
-		}
+			}
 		case 'i':
 			if (operation != OP_NONE) {
 				fprintf(stderr, "multiple operations specified on command line\n");
@@ -2119,12 +2981,21 @@
 				else if (strcasecmp(optarg, "hwlabel") == 0)
 					identify_mode = IDENTIFY_HARDWARE_LABEL;
 				else {
-					fprintf(stderr, "unknown identify mode '%s'\n", optarg);
+					fprintf(stderr, "unknown identify mode '%s'\n",
+						optarg);
 					usage();
 				}
 			} else
 				identify_mode = IDENTIFY_EXTENDED;
 			break;
+		case 'g':
+			if (operation != OP_NONE) {
+				fprintf(stderr, "multiple operations specified on command line\n");
+				usage();
+			}
+
+			operation = OP_PRINT_GUIDS;
+			break;
 		case 's':
 			if (operation != OP_NONE) {
 				fprintf(stderr, "multiple operations specified on command line\n");
@@ -2135,7 +3006,7 @@
 			filename = optarg;
 			break;
 		case 'd':
-			if (operation != OP_NONE) {
+			if (operation != OP_NONE && operation != OP_MODIFY_OPTIONS) {
 				fprintf(stderr, "multiple operations specified on command line\n");
 				usage();
 			}
@@ -2143,24 +3014,41 @@
 			operation = OP_UPLOAD;	/* Download firmware to HCA */
 			filename = optarg;
 			break;
+		case 'o':
+			if (operation != OP_NONE && operation != OP_UPLOAD) {
+				fprintf(stderr, "multiple operations specified on command line\n");
+				usage();
+			}
+
+			if (optarg)
+				change_option_cmd = optarg;
+			else
+				change_option_cmd = "";
+
+			/* operation will be set below */
+			break;
 		}
 	}
 
 	if (operation == OP_NONE) {
-		/* Default to OP_UPLOAD, but we need a filename argument */
-		if (optind >= argc)
-			usage();
+		if (change_option_cmd) {
+			operation = OP_MODIFY_OPTIONS;
+		} else {
+			/* Default to OP_UPLOAD, but we need a filename argument */
+			if (optind >= argc)
+				usage();
 
-		operation = OP_UPLOAD;	/* Download firmware to HCA */
-		filename = argv[optind++];
+			operation = OP_UPLOAD;	/* Download firmware to HCA */
+			filename = argv[optind++];
+		}
 	}
 
 	/* The upload operation can take an optional GUID argument too */
-	if (optind < argc && (operation == OP_UPLOAD))
+	if (optind < argc && operation == OP_UPLOAD)
 		guid = argv[optind++];
 
 	/* Identify operation can take an optional filename argument here */
-	if (optind < argc && (operation == OP_IDENTIFY)) {
+	if (optind < argc && operation == OP_IDENTIFY) {
 		filename = argv[optind++];
 		if (filename && identify_mode == IDENTIFY_HARDWARE_LABEL) {
 			fprintf(stderr, "cannot print hardware label for firmware image file\n");
@@ -2168,25 +3056,59 @@
 		}
 	}
 
+	/* Change option command can take an optional filename argument here */
+	if (optind < argc && change_option_cmd && change_option_cmd[0] == 0)
+		change_option_cmd = argv[optind++];
+
+	/* Set change_option_cmd correctly */
+	if (!autoupgrade) {
+		if (change_option_cmd && change_option_cmd[0] != 0) {
+			size_t len = strlen(change_option_cmd) + strlen("auto_upgrade=off") + 1;
+			char *p;
+
+			p = malloc(len);
+			if (!p) {
+				fprintf(stderr, "Unable to allocate %Zd bytes for change_option_cmd\n",
+					len);
+				exit(1);
+			}
+
+			snprintf(p, len - 1, "%s,auto_upgrade=off",
+				change_option_cmd);
+			change_option_cmd = p;
+		} else
+			change_option_cmd = "auto_upgrade=off";
+	}
+
 	pacc = pci_alloc();
 	pci_init(pacc);
 	pci_scan_bus(pacc);
 
-	scan_devices(pacc);
-
 	switch (operation) {
 	case OP_IDENTIFY:
 		if (filename)
 			ret = identify_firmware(filename, identify_mode);
-		else
+		else {
+			scan_devices(pacc);
 			ret = identify_hcas(hca, identify_mode);
+		}
 		break;
+	case OP_PRINT_GUIDS:
+		scan_devices(pacc);
+		ret = print_guids(hca);
+		break;
 	case OP_DOWNLOAD:
+		scan_devices(pacc);
 		ret = download_firmware(hca >= 0 ? hca : 0, filename);
 		break;
 	case OP_UPLOAD:
-		ret = upload_firmware(hca >= 0 ? hca : 0, filename, guid, autoupgrade);
+		scan_devices(pacc);
+		ret = upload_firmware(hca >= 0 ? hca : 0, filename, guid, change_option_cmd);
 		break;
+	case OP_MODIFY_OPTIONS:
+		scan_devices(pacc);
+		ret = modify_options(hca >= 0 ? hca : 0, change_option_cmd);
+		break;
 	default:
 		fprintf(stderr, "ERROR: Invalid operation %d\n", operation);
 		ret = 1;



More information about the ewg mailing list