summaryrefslogtreecommitdiffstats
path: root/utils/imxtools/scsitools
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2017-01-04 00:26:52 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2017-01-07 15:52:33 +0100
commit7fafbe1fc13bec744d1fcc70ba431fa77472680a (patch)
tree51e41b48e59f5f5e49dc3c051241eff09bac22d0 /utils/imxtools/scsitools
parent0fd869423ab3456288fcd323cff3206f37363153 (diff)
downloadrockbox-7fafbe1fc13bec744d1fcc70ba431fa77472680a.tar.gz
rockbox-7fafbe1fc13bec744d1fcc70ba431fa77472680a.zip
imxtools/scsitools: rework stmp scsi API
Sanitize the whole library by hiding most of the horrible details of the implementation. This means that all logical/drive/table attributes are exported in structures that are internally filled by higher-level API functions. This makes the code much more readable and prepares for a split between scsitool and the stmp scsi library. Change-Id: Id85d450b25cf99cd7c0896c6fc35bcd00babe9e1
Diffstat (limited to 'utils/imxtools/scsitools')
-rw-r--r--utils/imxtools/scsitools/scsitool.c810
-rw-r--r--utils/imxtools/scsitools/stmp_scsi.h169
2 files changed, 604 insertions, 375 deletions
diff --git a/utils/imxtools/scsitools/scsitool.c b/utils/imxtools/scsitools/scsitool.c
index 86956d0910..a1f1b7a2ba 100644
--- a/utils/imxtools/scsitools/scsitool.c
+++ b/utils/imxtools/scsitools/scsitool.c
@@ -47,19 +47,32 @@ struct stmp_device_t
stmp_printf_t printf;
};
-static uint16_t fix_endian16be(uint16_t w)
+static inline int little_endian(void)
{
- return w << 8 | w >> 8;
+ static int g_endian = -1;
+ if(g_endian == -1)
+ {
+ int i = 1;
+ g_endian = (int)*((unsigned char *)&i) == 1;
+ }
+ return g_endian;
+}
+
+uint16_t stmp_fix_endian16be(uint16_t w)
+{
+ return little_endian() ? w << 8 | w >> 8 : w;
}
-static uint32_t fix_endian32be(uint32_t w)
+uint32_t stmp_fix_endian32be(uint32_t w)
{
- return __builtin_bswap32(w);
+ return !little_endian() ? w :
+ (uint32_t)stmp_fix_endian16be(w) << 16 | stmp_fix_endian16be(w >> 16);
}
-static uint64_t fix_endian64be(uint64_t w)
+uint64_t stmp_fix_endian64be(uint64_t w)
{
- return __builtin_bswap64(w);
+ return !little_endian() ? w :
+ (uint64_t)stmp_fix_endian32be(w) << 32 | stmp_fix_endian32be(w >> 32);
}
static void print_hex(void *_buffer, int buffer_size)
@@ -84,6 +97,8 @@ static void print_hex(void *_buffer, int buffer_size)
}
printf("\n");
}
+ if(buffer_size == 0)
+ printf("\n");
}
static void misc_std_printf(void *user, const char *fmt, ...)
@@ -231,7 +246,7 @@ int stmp_get_chip_major_rev_id(stmp_device_t dev, uint16_t *ver)
int ret = stmp_scsi_get_chip_major_rev_id(dev, ver, &len);
if(ret || len != sizeof(*ver))
return -1;
- *ver = fix_endian16be(*ver);
+ *ver = stmp_fix_endian16be(*ver);
return 0;
}
@@ -246,7 +261,7 @@ int stmp_get_rom_rev_id(stmp_device_t dev, uint16_t *ver)
int ret = stmp_scsi_get_rom_rev_id(dev, ver, &len);
if(ret || len != sizeof(*ver))
return -1;
- *ver = fix_endian16be(*ver);
+ *ver = stmp_fix_endian16be(*ver);
return 0;
}
@@ -260,19 +275,23 @@ int stmp_scsi_get_logical_table(stmp_device_t dev, int entry_count, void *buf, i
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_TABLE, entry_count, 0, buf, len);
}
-int stmp_get_logical_table(stmp_device_t dev, struct scsi_stmp_logical_table_t *table, int entry_count)
+int stmp_get_logical_media_table(stmp_device_t dev, struct stmp_logical_media_table_t **table)
{
- int buf_sz = sizeof(struct scsi_stmp_logical_table_t) +
- entry_count * sizeof(struct scsi_stmp_logical_table_entry_t);
- int ret = stmp_scsi_get_logical_table(dev, entry_count, table, &buf_sz);
- if(ret != 0)
- return ret;
- if((buf_sz - sizeof(struct scsi_stmp_logical_table_t)) % sizeof(struct scsi_stmp_logical_table_entry_t))
+ struct scsi_stmp_logical_table_header_t header;
+ int len = sizeof(header);
+ int ret = stmp_scsi_get_logical_table(dev, 0, &header, &len);
+ if(ret || len != sizeof(header))
+ return -1;
+ header.count = stmp_fix_endian16be(header.count);
+ int sz = sizeof(header) + header.count * sizeof(struct scsi_stmp_logical_table_entry_t);
+ len = sz;
+ *table = malloc(sz);
+ ret = stmp_scsi_get_logical_table(dev, header.count, &(*table)->header, &len);
+ if(ret || len != sz)
return -1;
- table->count = fix_endian16be(table->count);
- struct scsi_stmp_logical_table_entry_t *entry = (void *)(table + 1);
- for(int i = 0; i < entry_count; i++)
- entry[i].size = fix_endian64be(entry[i].size);
+ (*table)->header.count = stmp_fix_endian16be((*table)->header.count);
+ for(unsigned i = 0; i < (*table)->header.count; i++)
+ (*table)->entry[i].size = stmp_fix_endian64be((*table)->entry[i].size);
return 0;
}
@@ -299,9 +318,9 @@ int stmp_scsi_read_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint6
cdb[0] = SCSI_STMP_READ;
cdb[1] = SCSI_STMP_CMD_READ_LOGICAL_DRIVE_SECTOR;
cdb[2] = drive;
- address = fix_endian64be(address);
+ address = stmp_fix_endian64be(address);
memcpy(&cdb[3], &address, sizeof(address));
- count = fix_endian32be(count);
+ count = stmp_fix_endian32be(count);
memcpy(&cdb[11], &count, sizeof(count));
uint8_t sense[32];
@@ -321,9 +340,9 @@ int stmp_scsi_write_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint
cdb[0] = SCSI_STMP_WRITE;
cdb[1] = SCSI_STMP_CMD_WRITE_LOGICAL_DRIVE_SECTOR;
cdb[2] = drive;
- address = fix_endian64be(address);
+ address = stmp_fix_endian64be(address);
memcpy(&cdb[3], &address, sizeof(address));
- count = fix_endian32be(count);
+ count = stmp_fix_endian32be(count);
memcpy(&cdb[11], &count, sizeof(count));
uint8_t sense[32];
@@ -335,7 +354,133 @@ int stmp_scsi_write_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint
return stmp_sense_analysis(dev, ret, sense, sense_size);
}
-static const char *stmp_get_logical_media_type_string(uint32_t type)
+int stmp_read_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
+ uint32_t count, void *buffer, int buffer_size)
+{
+ int len = buffer_size;
+ int ret = stmp_scsi_read_logical_drive_sectors(dev, drive, address, count, buffer, &len);
+ if(ret || len != buffer_size)
+ return -1;
+ return 0;
+}
+
+int stmp_write_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
+ uint32_t count, void *buffer, int buffer_size)
+{
+ int len = buffer_size;
+ int ret = stmp_scsi_write_logical_drive_sectors(dev, drive, address, count, buffer, &len);
+ if(ret || len != buffer_size)
+ return -1;
+ return 0;
+}
+
+#define check_len(l) if(len != l) return -1;
+#define fixn(n, p) *(uint##n##_t *)(p) = stmp_fix_endian##n##be(*(uint##n##_t *)(p))
+#define fix16(p) fixn(16, p)
+#define fix32(p) fixn(32, p)
+#define fix64(p) fixn(64, p)
+
+int stmp_fix_logical_media_info(uint8_t info, void *data, int len)
+{
+ switch(info)
+ {
+ case SCSI_STMP_MEDIA_INFO_NR_DRIVES:
+ check_len(2);
+ fix16(data);
+ return 0;
+ case SCSI_STMP_MEDIA_INFO_TYPE:
+ case SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER_SIZE:
+ case SCSI_STMP_MEDIA_INFO_VENDOR:
+ case SCSI_STMP_MEDIA_INFO_ALLOC_UNIT_SIZE:
+ case SCSI_STMP_MEDIA_INFO_PAGE_SIZE:
+ case SCSI_STMP_MEDIA_INFO_NR_DEVICES:
+ check_len(4);
+ fix32(data);
+ return 0;
+ case SCSI_STMP_MEDIA_INFO_SIZE:
+ case SCSI_STMP_MEDIA_INFO_NAND_ID:
+ check_len(8);
+ fix64(data);
+ return 0;
+ case SCSI_STMP_MEDIA_INFO_IS_INITIALISED:
+ case SCSI_STMP_MEDIA_INFO_STATE:
+ case SCSI_STMP_MEDIA_INFO_IS_WRITE_PROTECTED:
+ case SCSI_STMP_MEDIA_INFO_IS_SYSTEM_MEDIA:
+ case SCSI_STMP_MEDIA_INFO_IS_MEDIA_PRESENT:
+ check_len(1);
+ return 0;
+ case SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER:
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+static void stmp_fix_version(struct scsi_stmp_logical_drive_info_version_t *w)
+{
+ w->major = stmp_fix_endian16be(w->major);
+ w->minor = stmp_fix_endian16be(w->minor);
+ w->revision = stmp_fix_endian16be(w->revision);
+}
+
+int stmp_fix_logical_drive_info(uint8_t info, void *data, int len)
+{
+ switch(info)
+ {
+ case SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER_SIZE:
+ check_len(2);
+ fix16(data);
+ return 0;
+ case SCSI_STMP_DRIVE_INFO_SECTOR_SIZE:
+ case SCSI_STMP_DRIVE_INFO_ERASE_SIZE:
+ case SCSI_STMP_DRIVE_INFO_SIZE_MEGA:
+ case SCSI_STMP_DRIVE_INFO_TYPE:
+ case SCSI_STMP_DRIVE_INFO_SECTOR_ALLOCATION:
+ check_len(4);
+ fix32(data);
+ return 0;
+ case SCSI_STMP_DRIVE_INFO_SIZE:
+ case SCSI_STMP_DRIVE_INFO_SECTOR_COUNT:
+ check_len(8);
+ fix64(data);
+ return 0;
+ case SCSI_STMP_DRIVE_INFO_TAG:
+ case SCSI_STMP_DRIVE_INFO_IS_WRITE_PROTETED:
+ case SCSI_STMP_DRIVE_INFO_MEDIA_PRESENT:
+ case SCSI_STMP_DRIVE_INFO_MEDIA_CHANGE:
+ check_len(1);
+ return 0;
+ case SCSI_STMP_DRIVE_INFO_COMPONENT_VERSION:
+ case SCSI_STMP_DRIVE_INFO_PROJECT_VERSION:
+ check_len(6)
+ stmp_fix_version(data);
+ return 0;
+ case SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER:
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+int stmp_fix_device_info(uint8_t info, void *data, int len)
+{
+ switch(info)
+ {
+ case 0: case 1:
+ check_len(4);
+ fix32(data);
+ return 0;
+ default:
+ return -1;
+ }
+}
+#undef fix64
+#undef fix32
+#undef fix16
+#undef fixn
+#undef checl_len
+
+const char *stmp_get_logical_media_type_string(uint32_t type)
{
switch(type)
{
@@ -406,6 +551,106 @@ const char *stmp_get_logical_media_state_string(uint8_t state)
}
}
+int stmp_get_device_serial(stmp_device_t dev, uint8_t **buffer, int *len)
+{
+ *len = 2;
+ uint16_t len16;
+ int ret = stmp_scsi_get_serial_number(dev, 0, &len16, len);
+ if(!ret && *len == 2)
+ {
+ len16 = stmp_fix_endian16be(len16);
+ *len = len16;
+ *buffer = malloc(*len);
+ ret = stmp_scsi_get_serial_number(dev, 1, *buffer, len);
+ }
+ else
+ ret = -1;
+ return ret;
+}
+
+#define ARRAYLEN(x) (int)(sizeof(x)/sizeof((x)[0]))
+
+int stmp_get_logical_media_info(stmp_device_t dev, struct stmp_logical_media_info_t *info)
+{
+ memset(info, 0, sizeof(struct stmp_logical_media_info_t));
+ int len, ret;
+#define entry(name, def) \
+ len = sizeof(info->name); \
+ ret = stmp_scsi_get_logical_media_info(dev, SCSI_STMP_MEDIA_INFO_##def, &info->name, &len); \
+ if(!ret) \
+ ret = stmp_fix_logical_media_info(SCSI_STMP_MEDIA_INFO_##def, &info->name, len); \
+ if(!ret) \
+ info->has.name = true;
+
+ entry(nr_drives, NR_DRIVES);
+ entry(size, SIZE);
+ entry(alloc_size, ALLOC_UNIT_SIZE);
+ entry(initialised, IS_INITIALISED);
+ entry(state, STATE);
+ entry(write_protected, IS_WRITE_PROTECTED);
+ entry(type, TYPE);
+ entry(serial_len, SERIAL_NUMBER_SIZE);
+ entry(system, IS_SYSTEM_MEDIA);
+ entry(present, IS_MEDIA_PRESENT);
+ entry(page_size, PAGE_SIZE);
+ entry(vendor, VENDOR);
+ entry(nand_id, NAND_ID);
+ entry(nr_devices, NR_DEVICES);
+#undef entry
+ if(info->has.serial_len)
+ {
+ info->serial = malloc(info->serial_len);
+ int len = info->serial_len;
+ ret = stmp_scsi_get_logical_media_info(dev, SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER,
+ info->serial, &len);
+ if(ret || len != (int)info->serial_len)
+ free(info->serial);
+ else
+ info->has.serial = true;
+ }
+ return 0;
+}
+
+int stmp_get_logical_drive_info(stmp_device_t dev, uint8_t drive, struct stmp_logical_drive_info_t *info)
+{
+ memset(info, 0, sizeof(struct stmp_logical_drive_info_t));
+ int len, ret;
+#define entry(name, def) \
+ len = sizeof(info->name); \
+ ret = stmp_scsi_get_logical_drive_info(dev, drive, SCSI_STMP_DRIVE_INFO_##def, &info->name, &len); \
+ if(!ret) \
+ ret = stmp_fix_logical_drive_info(SCSI_STMP_DRIVE_INFO_##def, &info->name, len); \
+ if(!ret) \
+ info->has.name = true;
+
+ entry(sector_size, SECTOR_SIZE);
+ entry(erase_size, ERASE_SIZE);
+ entry(size, SIZE);
+ entry(sector_count, SECTOR_COUNT);
+ entry(type, TYPE);
+ entry(tag, TAG);
+ entry(component_version, COMPONENT_VERSION);
+ entry(project_version, PROJECT_VERSION);
+ entry(write_protected, IS_WRITE_PROTECTED);
+ entry(serial_len, SERIAL_NUMBER_SIZE);
+ entry(present, MEDIA_PRESENT);
+ entry(change, MEDIA_CHANGE);
+ entry(sector_alloc, SECTOR_ALLOCATION);
+#undef entry
+ if(info->has.serial_len)
+ {
+ info->serial = malloc(info->serial_len);
+ int len = info->serial_len;
+ ret = stmp_scsi_get_logical_media_info(dev, SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER,
+ info->serial, &len);
+ if(ret || len != (int)info->serial_len)
+ free(info->serial);
+ else
+ info->has.serial = true;
+ }
+ return 0;
+}
+
static const char *get_size_suffix(unsigned long long size)
{
int order = 0;
@@ -426,6 +671,11 @@ static float get_size_natural(unsigned long long size)
return res;
}
+static void print_ver(struct scsi_stmp_logical_drive_info_version_t *ver)
+{
+ cprintf(YELLOW, "%x.%x.%x\n", ver->major, ver->minor, ver->revision);
+}
+
static int do_info(void)
{
cprintf(BLUE, "Information\n");
@@ -439,347 +689,181 @@ static int do_info(void)
cprintf_field(" Vendor: ", "%s\n", vendor);
cprintf_field(" Product: ", "%s\n", product);
}
+ else if(g_debug)
+ cprintf(GREY, "Cannot get inquiry data: %d\n", ret);
struct scsi_stmp_protocol_version_t ver;
ret = stmp_get_protocol_version(g_dev_fd, &ver);
if(ret == 0)
cprintf_field(" Protocol: ", "%x.%x\n", ver.major, ver.minor);
+ else if(g_debug)
+ cprintf(GREY, "Cannot get protocol version: %d\n", ret);
- do
- {
- union
- {
- uint8_t u8;
- uint16_t u16;
- uint32_t u32;
- uint64_t u64;
- uint8_t buf[1024];
- }u;
-
- cprintf(GREEN, " Device\n");
- int len = 4;
- ret = stmp_scsi_get_device_info(g_dev_fd, 0, &u.u32, &len);
- if(!ret && len == 4)
- {
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Info 0: ", "%lu\n", (unsigned long)u.u32);
- }
-
- len = 4;
- ret = stmp_scsi_get_device_info(g_dev_fd, 1, &u.u32, &len);
- if(!ret && len == 4)
- {
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Info 1: ", "%lu\n", (unsigned long)u.u32);
- }
-
- len = 2;
- ret = stmp_scsi_get_serial_number(g_dev_fd, 0, &u.u16, &len);
- if(!ret && len == 2)
- {
- u.u16 = fix_endian16be(u.u16);
- len = MIN(u.u16, sizeof(u.buf));
- ret = stmp_scsi_get_serial_number(g_dev_fd, 1, u.buf, &len);
- cprintf_field(" Serial Number:", " ");
- print_hex(u.buf, len);
- cprintf(OFF, "\n");
- }
-
- len = 2;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_NR_DRIVES, &u.u16, &len);
- if(!ret && len == 2)
- {
- u.u16 = fix_endian16be(u.u16);
- cprintf_field(" Number of Drives: ", "%d\n", u.u16);
- }
+ cprintf(BLUE, "Device\n");
- len = 4;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_TYPE, &u.u32, &len);
- if(!ret && len == 4)
- {
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Media Type: ", "%#x", u.u32);
- cprintf(RED, " (%s)\n", stmp_get_logical_media_type_string(u.u32));
- }
-
- len = 1;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_IS_INITIALISED, &u.u8, &len);
- if(!ret && len == 1)
- cprintf_field(" Is Initialised: ", "%d\n", u.u8);
-
- len = 1;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_STATE, &u.u8, &len);
- if(!ret && len == 1)
- cprintf_field(" State: ", "%s\n", stmp_get_logical_media_state_string(u.u8));
+ uint8_t *serial;
+ int serial_len;
+ if(!stmp_get_device_serial(g_dev_fd, &serial, &serial_len))
+ {
+ cprintf_field(" Serial Number:", " ");
+ print_hex(serial, serial_len);
+ free(serial);
+ }
- len = 1;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_IS_WRITE_PROTECTED, &u.u8, &len);
- if(!ret && len == 1)
- cprintf_field(" Is Write Protected: ", "%#x\n", u.u8);
+ uint16_t chip_rev;
+ ret = stmp_get_chip_major_rev_id(g_dev_fd, &chip_rev);
+ if(ret)
+ cprintf(GREY, "Cannot get chip major revision id: %d\n", ret);
+ else
+ cprintf_field(" Chip Major Rev ID: ", "%x\n", chip_rev);
- len = 8;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_SIZE, &u.u64, &len);
- if(!ret && len == 8)
- {
- u.u64 = fix_endian64be(u.u64);
- cprintf_field(" Media Size: ", "%llu B (%.3f %s)\n", (unsigned long long)u.u64,
- get_size_natural(u.u64), get_size_suffix(u.u64));
- }
+ uint16_t rom_rev;
+ ret = stmp_get_rom_rev_id(g_dev_fd, &rom_rev);
+ if(ret)
+ cprintf(GREY, "Cannot get rom revision id: %d\n", ret);
+ else
+ cprintf_field(" ROM Rev ID: ", "%x\n", rom_rev);
- int serial_number_size = 0;
- len = 4;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER_SIZE, &u.u32, &len);
- if(!ret && len == 4)
+ cprintf(BLUE, "Logical Media\n");
+ struct stmp_logical_media_info_t info;
+ ret = stmp_get_logical_media_info(g_dev_fd, &info);
+ if(!ret)
+ {
+ if(info.has.nr_drives)
+ cprintf_field(" Number of drives:", " %u\n", info.nr_drives);
+ if(info.has.size)
{
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Serial Number Size: ", "%d\n", u.u32);
- serial_number_size = u.u32;
+ cprintf_field(" Media size:", " %llu ", (unsigned long long)info.size);
+ cprintf(RED, "(%.3f %s)\n", get_size_natural(info.size), get_size_suffix(info.size));
}
-
- len = serial_number_size;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_SERIAL_NUMBER, &u.buf, &len);
- if(!ret && len != 0)
+ if(info.has.alloc_size)
{
- cprintf(GREEN, " Serial Number:");
- print_hex(u.buf, len);
+ cprintf_field(" Allocation unit size:", " %lu ", (unsigned long)info.alloc_size);
+ cprintf(RED, "(%.3f %s)\n", get_size_natural(info.alloc_size), get_size_suffix(info.alloc_size));
}
-
- len = 1;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_IS_SYSTEM_MEDIA, &u.u8, &len);
- if(!ret && len == 1)
- cprintf_field(" Is System Media: ", "%d\n", u.u8);
-
- len = 1;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_IS_MEDIA_PRESENT, &u.u8, &len);
- if(!ret && len == 1)
- cprintf_field(" Is Media Present: ", "%d\n", u.u8);
-
- len = 4;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_VENDOR, &u.u32, &len);
- if(!ret && len == 4)
+ if(info.has.initialised)
+ cprintf_field(" Initialised:", " %u\n", info.initialised);
+ if(info.has.state)
+ cprintf_field(" State:", " %u\n", info.state);
+ if(info.has.write_protected)
+ cprintf_field(" Write protected:", " %u\n", info.write_protected);
+ if(info.has.type)
{
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Media Vendor: ", "%#x", u.u32);
- cprintf(RED, " (%s)\n", stmp_get_logical_media_vendor_string(u.u32));
+ cprintf_field(" Type:", " %u ", info.type);
+ cprintf(RED, "(%s)\n", stmp_get_logical_media_type_string(info.type));
}
-
- len = 8;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, 13, &u.u64, &len);
- if(!ret && len == 8)
+ if(info.has.serial)
{
- u.u64 = fix_endian64be(u.u64);
- cprintf_field(" Logical Media Info (13): ", "%#llx\n", (unsigned long long)u.u64);
+ cprintf_field(" Serial:", " ");
+ print_hex(info.serial, info.serial_len);
+ free(info.serial);
}
-
- len = 4;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, 11, &u.u32, &len);
- if(!ret && len == 4)
+ if(info.has.system)
+ cprintf_field(" System:", " %u\n", info.system);
+ if(info.has.present)
+ cprintf_field(" Present:", " %u\n", info.present);
+ if(info.has.page_size)
{
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Logical Media Info (11): ", "%#x\n", u.u32);
+ cprintf_field(" Page size:", " %lu ", (unsigned long)info.page_size);
+ cprintf(RED, "(%.3f %s)\n", get_size_natural(info.page_size), get_size_suffix(info.page_size));
}
-
- len = 4;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, 14, &u.u32, &len);
- if(!ret && len == 4)
+ if(info.has.vendor)
{
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Logical Media Info (14): ", "%#x\n", u.u32);
+ cprintf_field(" Vendor:", " %u ", info.vendor);
+ cprintf(RED, "(%s)\n", stmp_get_logical_media_vendor_string(info.vendor));
}
-
- len = 4;
- ret = stmp_scsi_get_logical_media_info(g_dev_fd, SCSI_STMP_MEDIA_INFO_ALLOC_UNIT_SIZE, &u.u32, &len);
- if(!ret && len == 4)
+ if(info.has.nand_id)
{
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Allocation Unit Size: ", "%d B\n", u.u32);
+ cprintf_field(" Nand ID:", " ");
+ print_hex(info.nand_id, sizeof(info.nand_id));
}
- }while(0);
-
- uint16_t chip_rev;
- ret = stmp_get_chip_major_rev_id(g_dev_fd, &chip_rev);
- if(ret)
- cprintf(GREY, "Cannot get chip major revision id: %d\n", ret);
- else
- cprintf_field(" Chip Major Rev ID: ", "%x\n", chip_rev);
-
- uint16_t rom_rev;
- ret = stmp_get_rom_rev_id(g_dev_fd, &rom_rev);
- if(ret)
- cprintf(GREY, "Cannot get rom revision id: %d\n", ret);
+ if(info.has.nr_devices)
+ cprintf_field(" Number of devices:", " %lu\n", (unsigned long)info.nr_devices);
+ }
else
- cprintf_field(" ROM Rev ID: ", "%x\n", rom_rev);
+ cprintf(GREY, "Cannot get media info: %d\n", ret);
- struct
+ struct stmp_logical_media_table_t *table;
+ ret = stmp_get_logical_media_table(g_dev_fd, &table);
+ if(!ret)
{
- struct scsi_stmp_logical_table_t header;
- struct scsi_stmp_logical_table_entry_t entry[20];
- }__attribute__((packed)) table;
-
- ret = stmp_get_logical_table(g_dev_fd, &table.header, sizeof(table.entry) / sizeof(table.entry[0]));
- if(ret)
- cprintf(GREY, "Cannot get logical table: %d\n", ret);
- else
- {
- cprintf_field(" Logical Table: ", "%d entries\n", table.header.count);
- for(int i = 0; i < table.header.count; i++)
+ cprintf(BLUE, "Logical Media Table\n");
+ for(int i = 0; i < table->header.count; i++)
{
- cprintf(BLUE, " Drive ");
- cprintf_field("No: ", "%2x", table.entry[i].drive_no);
- cprintf_field(" Type: ", "%#x ", table.entry[i].type);
- cprintf(RED, "(%s)", stmp_get_logical_drive_type_string(table.entry[i].type));
- cprintf_field(" Tag: ", "%#x ", table.entry[i].tag);
- cprintf(RED, "(%s)", stmp_get_logical_drive_tag_string(table.entry[i].tag));
- unsigned long long size = table.entry[i].size;
- int order = 0;
- while(size >= 1024)
- {
- size /= 1024;
- order++;
- }
- static const char *suffix[] = {"B", "KiB", "MiB", "GiB", "TiB"};
- cprintf_field(" Size: ", "%llu %s", size, suffix[order]);
+ cprintf(RED, " Drive ");
+ cprintf_field("No: ", "%2x", table->entry[i].drive_no);
+ cprintf_field(" Type: ", "%#x ", table->entry[i].type);
+ cprintf(RED, "(%s)", stmp_get_logical_drive_type_string(table->entry[i].type));
+ cprintf_field(" Tag: ", "%#x ", table->entry[i].tag);
+ cprintf(RED, "(%s)", stmp_get_logical_drive_tag_string(table->entry[i].tag));
+ unsigned long long size = table->entry[i].size;
+ cprintf_field(" Size: ", "%.3f %s", get_size_natural(size), get_size_suffix(size));
cprintf(OFF, "\n");
}
- for(int i = 0; i < table.header.count; i++)
+ for(int i = 0; i < table->header.count; i++)
{
- union
- {
- uint8_t u8;
- uint16_t u16;
- uint32_t u32;
- uint64_t u64;
- uint8_t buf[52];
- }u;
- uint8_t drive = table.entry[i].drive_no;
- cprintf_field(" Drive ", "%02x\n", drive);
-
- int len = 4;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_SECTOR_SIZE, &u.u32, &len);
- if(!ret && len == 4)
- {
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Sector Size: ", "%lu B (%.3f %s)\n", (unsigned long)u.u32,
- get_size_natural(u.u32), get_size_suffix(u.u32));
- }
-
- len = 4;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVe_INFO_ERASE_SIZE, &u.u32, &len);
- if(!ret && len == 4)
- {
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Erase Size: ", "%lu B (%.3f %s)\n", (unsigned long)u.u32,
- get_size_natural(u.u32), get_size_suffix(u.u32));
- }
-
- len = 8;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_SIZE, &u.u64, &len);
- if(!ret && len == 8)
- {
- u.u64 = fix_endian64be(u.u64);
- cprintf_field(" Total Size: ", "%llu B (%.3f %s)\n",
- (unsigned long long)u.u64, get_size_natural(u.u32),
- get_size_suffix(u.u32));
- }
-
- len = 4;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_SIZE_MEGA, &u.u32, &len);
- if(!ret && len == 4)
- {
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Total Size (MB): ", "%lu MB\n", (unsigned long)u.u32);
- }
-
- len = 8;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_SECTOR_COUNT, &u.u64, &len);
- if(!ret && len == 8)
- {
- u.u64 = fix_endian64be(u.u64);
- cprintf_field(" Sector Count: ", "%llu\n", (unsigned long long)u.u64);
- }
-
- len = 4;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive,SCSI_STMP_DRIVE_INFO_TYPE, &u.u32, &len);
- if(!ret && len == 4)
- {
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Type: ", "%#x", u.u32);
- cprintf(RED, " (%s)\n", stmp_get_logical_drive_type_string(u.u32));
- }
-
- len = 1;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_TAG, &u.u8, &len);
- if(!ret && len == 1)
- {
- cprintf_field(" Tag: ", "%#x", u.u8);
- cprintf(RED, " (%s)\n", stmp_get_logical_drive_tag_string(u.u8));
- }
-
- len = 52;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_COMPONENT_VERSION, &u.buf, &len);
- if(!ret && len != 0)
+ uint8_t drive = table->entry[i].drive_no;
+ cprintf(BLUE, "Drive ");
+ cprintf(YELLOW, "%02x\n", drive);
+ struct stmp_logical_drive_info_t info;
+ ret = stmp_get_logical_drive_info(g_dev_fd, drive, &info);
+ if(ret)
+ continue;
+ if(info.has.sector_size)
{
- cprintf(GREEN, " Component Version:");
- print_hex(u.buf, len);
+ cprintf_field(" Sector size:", " %llu ", (unsigned long long)info.sector_size);
+ cprintf(RED, "(%.3f %s)\n", get_size_natural(info.sector_size), get_size_suffix(info.sector_size));
}
-
- len = 52;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_PROJECT_VERSION, &u.buf, &len);
- if(!ret && len != 0)
+ if(info.has.erase_size)
{
- cprintf(GREEN, " Project Version:");
- print_hex(u.buf, len);
+ cprintf_field(" Erase size:", " %llu ", (unsigned long long)info.erase_size);
+ cprintf(RED, "(%.3f %s)\n", get_size_natural(info.erase_size), get_size_suffix(info.erase_size));
}
-
- len = 1;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_IS_WRITE_PROTETED, &u.u8, &len);
- if(!ret && len == 1)
+ if(info.has.size)
{
- cprintf_field(" Is Writed Protected: ", "%d\n", u.u8);
+ cprintf_field(" Drive size:", " %llu ", (unsigned long long)info.size);
+ cprintf(RED, "(%.3f %s)\n", get_size_natural(info.size), get_size_suffix(info.size));
}
-
- len = 2;
- int serial_number_size = 0;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER_SIZE, &u.u16, &len);
- if(!ret && len == 2)
+ if(info.has.sector_count)
+ cprintf_field(" Sector count:", " %lu\n", (unsigned long)info.sector_count);
+ if(info.has.type)
{
- u.u16 = fix_endian16be(u.u16);
- cprintf_field(" Serial Number Size: ", "%d\n", u.u16);
- serial_number_size = u.u16;
+ cprintf_field(" Type:", " %u ", info.type);
+ cprintf(RED, "(%s)\n", stmp_get_logical_drive_type_string(info.type));
}
-
- len = serial_number_size;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER, &u.buf, &len);
- if(!ret && len != 0)
+ if(info.has.tag)
{
- cprintf(GREEN, " Serial Number:");
- print_hex(u.buf, len);
+ cprintf_field(" Tag:", " %u ", info.tag);
+ cprintf(RED, "(%s)\n", stmp_get_logical_drive_tag_string(info.tag));
}
-
- len = 1;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_MEDIA_PRESENT, &u.u8, &len);
- if(!ret && len == 1)
+ if(info.has.component_version)
{
- cprintf_field(" Is Media Present: ", "%d\n", u.u8);
+ cprintf_field(" Component version:", " ");
+ print_ver(&info.component_version);
}
-
- len = 1;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_MEDIA_CHANGE, &u.u8, &len);
- if(!ret && len == 1)
+ if(info.has.project_version)
{
- cprintf_field(" Media Change: ", "%d\n", u.u8);
+ cprintf_field(" Project version:", " ");
+ print_ver(&info.project_version);
}
-
- len = 4;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive, SCSI_STMP_DRIVE_INFO_SECTOR_ALLOCATION, &u.u32, &len);
- if(!ret && len == 4)
+ if(info.has.write_protected)
+ cprintf_field(" Write protected:", " %u\n", info.write_protected);
+ if(info.has.serial)
{
- u.u32 = fix_endian32be(u.u32);
- cprintf_field(" Sector Allocation: ", "%lu\n", (unsigned long)u.u32);
+ cprintf_field(" Serial:", " ");
+ print_hex(info.serial, info.serial_len);
+ free(info.serial);
}
+ if(info.has.change)
+ cprintf_field(" Change:", " %u\n", info.change);
+ if(info.has.present)
+ cprintf_field(" Present:", " %u\n", info.present);
}
+ free(table);
}
+ else
+ cprintf(GREY, "Cannot get logical table: %d\n", ret);
return 0;
}
@@ -789,32 +873,27 @@ void do_extract(const char *file)
FILE *f = NULL;
cprintf(BLUE, "Extracting firmware...\n");
- struct
- {
- struct scsi_stmp_logical_table_t header;
- struct scsi_stmp_logical_table_entry_t entry[20];
- }__attribute__((packed)) table;
-
- int ret = stmp_get_logical_table(g_dev_fd, &table.header, sizeof(table.entry) / sizeof(table.entry[0]));
+ struct stmp_logical_media_table_t *table = NULL;
+ int ret = stmp_get_logical_media_table(g_dev_fd, &table);
if(ret)
{
cprintf(GREY, "Cannot get logical table: %d\n", ret);
goto Lend;
}
int entry = 0;
- while(entry < table.header.count)
- if(table.entry[entry].type == SCSI_STMP_DRIVE_TYPE_SYSTEM &&
- table.entry[entry].tag == SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT)
+ while(entry < table->header.count)
+ if(table->entry[entry].type == SCSI_STMP_DRIVE_TYPE_SYSTEM &&
+ table->entry[entry].tag == SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT)
break;
else
entry++;
- if(entry == table.header.count)
+ if(entry == table->header.count)
{
cprintf(GREY, "Cannot find firmware partition\n");
goto Lend;
}
- uint8_t drive_no = table.entry[entry].drive_no;
- uint64_t drive_sz = table.entry[entry].size;
+ uint8_t drive_no = table->entry[entry].drive_no;
+ uint64_t drive_sz = table->entry[entry].size;
if(g_debug)
{
cprintf(RED, "* ");
@@ -822,27 +901,25 @@ void do_extract(const char *file)
cprintf(RED, "* ");
cprintf_field("Size: ", "%#llx\n", (unsigned long long)drive_sz);
}
- int len = 4;
- uint32_t sector_size;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive_no, SCSI_STMP_DRIVE_INFO_SECTOR_SIZE, &sector_size, &len);
- if(ret || len != 4)
+ struct stmp_logical_drive_info_t info;
+ ret = stmp_get_logical_drive_info(g_dev_fd, drive_no, &info);
+ if(ret || !info.has.sector_size)
{
cprintf(GREY, "Cannot get sector size\n");
goto Lend;
}
- sector_size = fix_endian32be(sector_size);
+ unsigned sector_size = info.sector_size;
if(g_debug)
{
cprintf(RED, "* ");
cprintf_field("Sector size: ", "%lu\n", (unsigned long)sector_size);
}
uint8_t *sector = malloc(sector_size);
- len = sector_size;
- ret = stmp_scsi_read_logical_drive_sectors(g_dev_fd, drive_no, 0, 1, sector, &len);
- if(ret || len != (int)sector_size)
+ ret = stmp_read_logical_drive_sectors(g_dev_fd, drive_no, 0, 1, sector, sector_size);
+ if(ret)
{
- cprintf(GREY, "Cannot read first sector\n");
- return;
+ cprintf(GREY, "Cannot read first sector: %d\n", ret);
+ goto Lend;
}
uint32_t fw_size = *(uint32_t *)(sector + 0x1c) * 16;
if(g_debug)
@@ -860,10 +937,10 @@ void do_extract(const char *file)
for(int sec = 0; sec * sector_size < fw_size; sec++)
{
- ret = stmp_scsi_read_logical_drive_sectors(g_dev_fd, drive_no, sec, 1, sector, &len);
- if(ret || len != (int)sector_size)
+ ret = stmp_read_logical_drive_sectors(g_dev_fd, drive_no, sec, 1, sector, sector_size);
+ if(ret)
{
- cprintf(GREY, "Cannot read sector %d\n", sec);
+ cprintf(GREY, "Cannot read sector %d: %d\n", sec, ret);
goto Lend;
}
if(fwrite(sector, sector_size, 1, f) != 1)
@@ -874,6 +951,7 @@ void do_extract(const char *file)
}
cprintf(BLUE, "Done\n");
Lend:
+ free(table);
if(f)
fclose(f);
}
@@ -890,33 +968,27 @@ void do_write(const char *file, int want_a_brick)
FILE *f = NULL;
cprintf(BLUE, "Writing firmware...\n");
- struct
- {
- struct scsi_stmp_logical_table_t header;
- struct scsi_stmp_logical_table_entry_t entry[20];
- }__attribute__((packed)) table;
-
- int len = sizeof(table);
- int ret = stmp_scsi_get_logical_table(g_dev_fd, sizeof(table.entry) / sizeof(table.entry[0]), &table.header, &len);
+ struct stmp_logical_media_table_t *table = NULL;
+ int ret = stmp_get_logical_media_table(g_dev_fd, &table);
if(ret)
{
cprintf(GREY, "Cannot get logical table: %d\n", ret);
goto Lend;
}
int entry = 0;
- while(entry < table.header.count)
- if(table.entry[entry].type == SCSI_STMP_DRIVE_TYPE_SYSTEM &&
- table.entry[entry].tag == SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT)
+ while(entry < table->header.count)
+ if(table->entry[entry].type == SCSI_STMP_DRIVE_TYPE_SYSTEM &&
+ table->entry[entry].tag == SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT)
break;
else
entry++;
- if(entry == table.header.count)
+ if(entry == table->header.count)
{
cprintf(GREY, "Cannot find firmware partition\n");
goto Lend;
}
- uint8_t drive_no = table.entry[entry].drive_no;
- uint64_t drive_sz = table.entry[entry].size;
+ uint8_t drive_no = table->entry[entry].drive_no;
+ uint64_t drive_sz = table->entry[entry].size;
if(g_debug)
{
cprintf(RED, "* ");
@@ -924,28 +996,21 @@ void do_write(const char *file, int want_a_brick)
cprintf(RED, "* ");
cprintf_field("Size: ", "%#llx\n", (unsigned long long)drive_sz);
}
- len = 4;
- uint32_t sector_size;
- ret = stmp_scsi_get_logical_drive_info(g_dev_fd, drive_no, SCSI_STMP_DRIVE_INFO_SECTOR_SIZE, &sector_size, &len);
- if(ret || len != 4)
+ struct stmp_logical_drive_info_t info;
+ ret = stmp_get_logical_drive_info(g_dev_fd, drive_no, &info);
+ if(ret || !info.has.sector_size)
{
cprintf(GREY, "Cannot get sector size\n");
goto Lend;
}
- sector_size = fix_endian32be(sector_size);
- if(g_debug)
- {
- cprintf(RED, "* ");
- cprintf_field("Sector size: ", "%lu\n", (unsigned long)sector_size);
- }
+ unsigned sector_size = info.sector_size;
uint8_t *sector = malloc(sector_size);
/* sanity check by reading first sector */
- len = sector_size;
- ret = stmp_scsi_read_logical_drive_sectors(g_dev_fd, drive_no, 0, 1, sector, &len);
- if(ret || len != (int)sector_size)
+ ret = stmp_read_logical_drive_sectors(g_dev_fd, drive_no, 0, 1, sector, sector_size);
+ if(ret)
{
- cprintf(GREY, "Cannot read first sector\n");
+ cprintf(GREY, "Cannot read first sector: %d\n", ret);
return;
}
uint32_t sig = *(uint32_t *)(sector + 0x14);
@@ -998,11 +1063,10 @@ void do_write(const char *file, int want_a_brick)
* partial sectors */
if(xfer_len < (int)sector_size)
memset(sector + xfer_len, 0, sector_size - xfer_len);
- len = sector_size;
- ret = stmp_scsi_write_logical_drive_sectors(g_dev_fd, drive_no, sec, 1, sector, &len);
- if(ret || len != (int)sector_size)
+ ret = stmp_write_logical_drive_sectors(g_dev_fd, drive_no, sec, 1, sector, sector_size);
+ if(ret)
{
- cprintf(GREY, "Cannot write sector %d\n", sec);
+ cprintf(GREY, "Cannot write sector %d: %d\n", sec, ret);
goto Lend;
}
}
diff --git a/utils/imxtools/scsitools/stmp_scsi.h b/utils/imxtools/scsitools/stmp_scsi.h
index 1a035cc649..68d77daeec 100644
--- a/utils/imxtools/scsitools/stmp_scsi.h
+++ b/utils/imxtools/scsitools/stmp_scsi.h
@@ -84,7 +84,7 @@ struct scsi_stmp_logical_table_entry_t
#define SCSI_STMP_DRIVE_TAG_USER_STORAGE 0xa
#define SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT 0x50
-struct scsi_stmp_logical_table_t
+struct scsi_stmp_logical_table_header_t
{
uint16_t count; /* big-endian */
} __attribute__((packed));
@@ -135,7 +135,7 @@ struct scsi_stmp_logical_media_info_manufacturer_t
} __attribute__((packed));
#define SCSI_STMP_DRIVE_INFO_SECTOR_SIZE 0 /** Sector Size (bytes) */
-#define SCSI_STMP_DRIVe_INFO_ERASE_SIZE 1 /** Erase Size (bytes) */
+#define SCSI_STMP_DRIVE_INFO_ERASE_SIZE 1 /** Erase Size (bytes) */
#define SCSI_STMP_DRIVE_INFO_SIZE 2 /** Total Size (bytes) */
#define SCSI_STMP_DRIVE_INFO_SIZE_MEGA 3 /** Total Size (mega-bytes) */
#define SCSI_STMP_DRIVE_INFO_SECTOR_COUNT 4 /** Sector Count */
@@ -187,6 +187,14 @@ struct scsi_stmp_logical_drive_info_type_t
uint8_t type;
} __attribute__((packed));
+struct scsi_stmp_logical_drive_info_version_t
+{
+ uint16_t major;
+ uint16_t minor;
+ uint16_t revision;
+} __attribute__((packed));
+
+struct stmp_device_t;
typedef struct stmp_device_t *stmp_device_t;
typedef void (*stmp_printf_t)(void *user, const char *fmt, ...);
@@ -197,4 +205,161 @@ typedef void (*stmp_printf_t)(void *user, const char *fmt, ...);
#define STMP_READ (1 << 1)
#define STMP_WRITE (1 << 2)
+uint16_t stmp_fix_endian16be(uint16_t w);
+uint32_t stmp_fix_endian32be(uint32_t w);
+uint64_t stmp_fix_endian64be(uint64_t w);
+/* returns NULL on error */
+stmp_device_t stmp_open(rb_scsi_device_t dev, unsigned flags, void *user, stmp_printf_t printf);
+void stmp_close(stmp_device_t dev);
+/* returns <0 on error and status otherwise */
+int stmp_scsi(stmp_device_t dev, uint8_t *cdb, int cdb_size, unsigned flags,
+ void *sense, int *sense_size, void *buffer, int *buf_size);
+/* returns != 0 on error */
+int stmp_sense_analysis(stmp_device_t dev, int status, uint8_t *sense, int sense_size);
+void stmp_printf(rb_scsi_device_t dev, const char *fmt, ...);
+void stmp_debugf(rb_scsi_device_t dev, const char *fmt, ...);
+
+/**
+ * Mid-level API
+ */
+
+/* returns !=0 on error */
+int stmp_scsi_inquiry(stmp_device_t dev, uint8_t *dev_type, char vendor[9], char product[17]);
+
+int stmp_scsi_get_protocol_version(stmp_device_t dev, void *buf, int *len);
+int stmp_scsi_get_chip_major_rev_id(stmp_device_t dev, void *buf, int *len);
+int stmp_scsi_get_rom_rev_id(stmp_device_t dev, void *buf, int *len);
+int stmp_scsi_read_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
+ uint32_t count, void *buffer, int *buffer_size);
+int stmp_scsi_write_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
+ uint32_t count, void *buffer, int *buffer_size);
+/* the following functions *DO NOT* fix the endianness of the structures */
+int stmp_scsi_get_logical_table(stmp_device_t dev, int entry_count, void *buf, int *len);
+int stmp_scsi_get_serial_number(stmp_device_t dev, uint8_t info, void *data, int *len);
+int stmp_scsi_get_logical_media_info(stmp_device_t dev, uint8_t info, void *data, int *len);
+int stmp_scsi_get_logical_drive_info(stmp_device_t dev, uint8_t drive, uint8_t info, void *data, int *len);
+int stmp_scsi_get_device_info(stmp_device_t dev, uint8_t info, void *data, int *len);
+/* these helper functions fix the endianness for the previous calls, or returns != 0
+ * if they don't know about this info or the size doesn't match */
+int stmp_fix_logical_media_info(uint8_t info, void *data, int len);
+int stmp_fix_logical_drive_info(uint8_t info, void *data, int len);
+int stmp_fix_device_info(uint8_t info, void *data, int len);
+
+/**
+ * High-Level API
+ */
+
+struct stmp_logical_media_table_t
+{
+ struct scsi_stmp_logical_table_header_t header;
+ struct scsi_stmp_logical_table_entry_t entry[];
+}__attribute__((packed)) table;
+
+struct stmp_logical_media_info_t
+{
+ struct
+ {
+ bool nr_drives;
+ bool size;
+ bool alloc_size;
+ bool initialised;
+ bool state;
+ bool write_protected;
+ bool type;
+ bool serial_len;
+ bool serial;
+ bool system;
+ bool present;
+ bool page_size;
+ bool vendor;
+ bool nand_id;
+ bool nr_devices;
+ }has;
+ uint16_t nr_drives;
+ uint64_t size;
+ uint32_t alloc_size;
+ uint8_t initialised;
+ uint8_t state;
+ uint8_t write_protected;
+ uint8_t type;
+ uint32_t serial_len;
+ uint8_t *serial; /* must be released with free() */
+ uint8_t system;
+ uint8_t present;
+ uint32_t page_size;
+ uint32_t vendor;
+ uint8_t nand_id[6];
+ uint32_t nr_devices;
+};
+
+#define SCSI_STMP_DRIVE_INFO_SECTOR_SIZE 0 /** Sector Size (bytes) */
+#define SCSI_STMP_DRIVE_INFO_ERASE_SIZE 1 /** Erase Size (bytes) */
+#define SCSI_STMP_DRIVE_INFO_SIZE 2 /** Total Size (bytes) */
+#define SCSI_STMP_DRIVE_INFO_SIZE_MEGA 3 /** Total Size (mega-bytes) */
+#define SCSI_STMP_DRIVE_INFO_SECTOR_COUNT 4 /** Sector Count */
+#define SCSI_STMP_DRIVE_INFO_TYPE 5 /** Drive Type */
+#define SCSI_STMP_DRIVE_INFO_TAG 6 /** Drive Tag */
+#define SCSI_STMP_DRIVE_INFO_COMPONENT_VERSION 7 /** Component Version */
+#define SCSI_STMP_DRIVE_INFO_PROJECT_VERSION 8 /** Project Version */
+#define SCSI_STMP_DRIVE_INFO_IS_WRITE_PROTECTED 9 /** Is Write Protected */
+#define SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER_SIZE 10 /** Serial Number Size */
+#define SCSI_STMP_DRIVE_INFO_SERIAL_NUMBER 11 /** Serial Number */
+#define SCSI_STMP_DRIVE_INFO_MEDIA_PRESENT 12 /** Is Media Present */
+#define SCSI_STMP_DRIVE_INFO_MEDIA_CHANGE 13 /** Media Change */
+#define SCSI_STMP_DRIVE_INFO_SECTOR_ALLOCATION 14 /** Sector Allocation */
+
+struct stmp_logical_drive_info_t
+{
+ struct
+ {
+ bool sector_size;
+ bool erase_size;
+ bool size;
+ bool sector_count;
+ bool type;
+ bool tag;
+ bool component_version;
+ bool project_version;
+ bool write_protected;
+ bool serial_len;
+ bool serial;
+ bool present;
+ bool change;
+ bool sector_alloc;
+ }has;
+ uint32_t sector_size;
+ uint32_t erase_size;
+ uint64_t size;
+ uint64_t sector_count;
+ uint32_t type;
+ uint8_t tag;
+ struct scsi_stmp_logical_drive_info_version_t component_version;
+ struct scsi_stmp_logical_drive_info_version_t project_version;
+ uint8_t write_protected;
+ uint32_t serial_len;
+ uint8_t *serial;
+ uint8_t present;
+ uint8_t change;
+ uint32_t sector_alloc;
+};
+
+int stmp_get_protocol_version(stmp_device_t dev, struct scsi_stmp_protocol_version_t *ver);
+int stmp_get_chip_major_rev_id(stmp_device_t dev, uint16_t *ver);
+int stmp_get_rom_rev_id(stmp_device_t dev, uint16_t *ver);
+/* return 0 on success, buffers must be released with free() */
+int stmp_get_device_serial(stmp_device_t dev, uint8_t **buffer, int *len);
+int stmp_get_logical_media_info(stmp_device_t dev, struct stmp_logical_media_info_t *info);
+int stmp_get_logical_media_table(stmp_device_t dev, struct stmp_logical_media_table_t **table);
+int stmp_get_logical_drive_info(stmp_device_t dev, uint8_t drive, struct stmp_logical_drive_info_t *info);
+int stmp_read_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
+ uint32_t count, void *buffer, int buffer_size);
+int stmp_write_logical_drive_sectors(stmp_device_t dev, uint8_t drive, uint64_t address,
+ uint32_t count, void *buffer, int buffer_size);
+/* string helpers */
+const char *stmp_get_logical_media_type_string(uint32_t type);
+const char *stmp_get_logical_media_vendor_string(uint32_t type);
+const char *stmp_get_logical_drive_type_string(uint32_t type);
+const char *stmp_get_logical_drive_tag_string(uint32_t type);
+const char *stmp_get_logical_media_state_string(uint8_t state);
+
#endif /* __STMP_SCSI__ */