forked from len0rd/rockbox
imxtools/scsitools: move stmp scsi api to its own file
No code modification code, just moving code around. Change-Id: I30744d3994aa7540f4b5b158f31b51959d5d8586
This commit is contained in:
parent
7fafbe1fc1
commit
0778184782
3 changed files with 618 additions and 587 deletions
|
|
@ -12,7 +12,8 @@ all: $(BINS)
|
|||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
scsitool: scsitool.o misc.o
|
||||
scsitool: scsitool.o misc.o stmp_scsi.o
|
||||
$(MAKE) -C $(TOOLS_DIR)
|
||||
$(LD) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
|
|
|
|||
|
|
@ -39,42 +39,6 @@ bool g_debug = false;
|
|||
bool g_force = false;
|
||||
stmp_device_t g_dev_fd;
|
||||
|
||||
struct stmp_device_t
|
||||
{
|
||||
rb_scsi_device_t dev;
|
||||
unsigned flags;
|
||||
void *user;
|
||||
stmp_printf_t printf;
|
||||
};
|
||||
|
||||
static inline int little_endian(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
uint32_t stmp_fix_endian32be(uint32_t w)
|
||||
{
|
||||
return !little_endian() ? w :
|
||||
(uint32_t)stmp_fix_endian16be(w) << 16 | stmp_fix_endian16be(w >> 16);
|
||||
}
|
||||
|
||||
uint64_t stmp_fix_endian64be(uint64_t 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)
|
||||
{
|
||||
uint8_t *buffer = _buffer;
|
||||
|
|
@ -101,556 +65,6 @@ static void print_hex(void *_buffer, int buffer_size)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
static void misc_std_printf(void *user, const char *fmt, ...)
|
||||
{
|
||||
(void) user;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define stmp_printf(dev, ...) \
|
||||
dev->printf(dev->user, __VA_ARGS__)
|
||||
|
||||
#define stmp_debugf(dev, ...) \
|
||||
do{ if(dev->flags & STMP_DEBUG) stmp_printf(dev, __VA_ARGS__); }while(0)
|
||||
|
||||
stmp_device_t stmp_open(rb_scsi_device_t rdev, unsigned flags, void *user, stmp_printf_t printf)
|
||||
{
|
||||
if(printf == NULL)
|
||||
printf = misc_std_printf;
|
||||
stmp_device_t sdev = malloc(sizeof(struct stmp_device_t));
|
||||
memset(sdev, 0, sizeof(struct stmp_device_t));
|
||||
sdev->dev = rdev;
|
||||
sdev->flags = flags;
|
||||
sdev->user = user;
|
||||
sdev->printf = printf;
|
||||
return sdev;
|
||||
}
|
||||
|
||||
void stmp_close(stmp_device_t dev)
|
||||
{
|
||||
free(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)
|
||||
{
|
||||
struct rb_scsi_raw_cmd_t cmd;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.dir = RB_SCSI_NONE;
|
||||
if(flags & STMP_READ)
|
||||
cmd.dir = RB_SCSI_READ;
|
||||
if(flags & STMP_WRITE)
|
||||
cmd.dir = RB_SCSI_WRITE;
|
||||
cmd.cdb = cdb;
|
||||
cmd.cdb_len = cdb_size;
|
||||
cmd.sense = sense;
|
||||
cmd.sense_len = *sense_size;
|
||||
cmd.buf = buffer;
|
||||
cmd.buf_len = *buf_size;
|
||||
cmd.tmo = 1;
|
||||
int ret = rb_scsi_raw_xfer(dev->dev, &cmd);
|
||||
*sense_size = cmd.sense_len;
|
||||
*buf_size = cmd.buf_len;
|
||||
return ret == RB_SCSI_OK || ret == RB_SCSI_SENSE ? cmd.status : -ret;
|
||||
}
|
||||
|
||||
int stmp_sense_analysis(stmp_device_t dev, int status, uint8_t *sense, int sense_size)
|
||||
{
|
||||
if(status != 0 && (dev->flags & STMP_DEBUG))
|
||||
{
|
||||
stmp_printf(dev, "Status: %d\n", status);
|
||||
stmp_printf(dev, "Sense:");
|
||||
for(int i = 0; i < sense_size; i++)
|
||||
stmp_printf(dev, " %02x", sense[i]);
|
||||
stmp_printf(dev, "\n");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int stmp_scsi_read_cmd(stmp_device_t dev, uint8_t cmd, uint8_t subcmd,
|
||||
uint8_t subsubcmd, void *buf, int *len)
|
||||
{
|
||||
uint8_t cdb[16];
|
||||
memset(cdb, 0, sizeof(cdb));
|
||||
cdb[0] = SCSI_STMP_READ;
|
||||
cdb[1] = cmd;
|
||||
cdb[2] = subcmd;
|
||||
cdb[3] = subsubcmd;
|
||||
|
||||
uint8_t sense[32];
|
||||
int sense_size = sizeof(sense);
|
||||
|
||||
int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buf, len);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = stmp_sense_analysis(dev, ret, sense, sense_size);
|
||||
if(ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmp_scsi_inquiry(stmp_device_t dev, uint8_t *dev_type, char vendor[9], char product[17])
|
||||
{
|
||||
unsigned char buffer[36];
|
||||
uint8_t cdb[10];
|
||||
memset(cdb, 0, sizeof(cdb));
|
||||
cdb[0] = 0x12;
|
||||
cdb[4] = sizeof(buffer);
|
||||
|
||||
uint8_t sense[32];
|
||||
int sense_size = sizeof(sense);
|
||||
|
||||
int buf_sz = sizeof(buffer);
|
||||
int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buffer, &buf_sz);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = stmp_sense_analysis(dev, ret, sense, sense_size);
|
||||
if(ret)
|
||||
return ret;
|
||||
if(buf_sz != sizeof(buffer))
|
||||
return -1;
|
||||
*dev_type = buffer[0];
|
||||
memcpy(vendor, buffer + 8, 8);
|
||||
vendor[8] = 0;
|
||||
memcpy(product, buffer + 16, 16);
|
||||
product[16] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmp_scsi_get_protocol_version(stmp_device_t dev, void *buf, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_PROTOCOL_VERSION, 0, 0, buf, len);
|
||||
}
|
||||
|
||||
int stmp_get_protocol_version(stmp_device_t dev, struct scsi_stmp_protocol_version_t *ver)
|
||||
{
|
||||
int len = sizeof(*ver);
|
||||
int ret = stmp_scsi_get_protocol_version(dev, ver, &len);
|
||||
if(ret || len != sizeof(*ver))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmp_scsi_get_chip_major_rev_id(stmp_device_t dev, void *buf, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_CHIP_MAJOR_REV_ID, 0, 0, buf, len);
|
||||
}
|
||||
|
||||
int stmp_get_chip_major_rev_id(stmp_device_t dev, uint16_t *ver)
|
||||
{
|
||||
int len = sizeof(*ver);
|
||||
int ret = stmp_scsi_get_chip_major_rev_id(dev, ver, &len);
|
||||
if(ret || len != sizeof(*ver))
|
||||
return -1;
|
||||
*ver = stmp_fix_endian16be(*ver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmp_scsi_get_rom_rev_id(stmp_device_t dev, void *buf, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_ROM_REV_ID, 0, 0, buf, len);
|
||||
}
|
||||
|
||||
int stmp_get_rom_rev_id(stmp_device_t dev, uint16_t *ver)
|
||||
{
|
||||
int len = sizeof(*ver);
|
||||
int ret = stmp_scsi_get_rom_rev_id(dev, ver, &len);
|
||||
if(ret || len != sizeof(*ver))
|
||||
return -1;
|
||||
*ver = stmp_fix_endian16be(*ver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmp_scsi_get_logical_media_info(stmp_device_t dev, uint8_t info, void *data, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_MEDIA_INFO, info, 0, data, len);
|
||||
}
|
||||
|
||||
int stmp_scsi_get_logical_table(stmp_device_t dev, int entry_count, void *buf, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_TABLE, entry_count, 0, buf, len);
|
||||
}
|
||||
|
||||
int stmp_get_logical_media_table(stmp_device_t dev, struct stmp_logical_media_table_t **table)
|
||||
{
|
||||
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)->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;
|
||||
}
|
||||
|
||||
int stmp_scsi_get_logical_drive_info(stmp_device_t dev, uint8_t drive, uint8_t info, void *data, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_DRIVE_INFO, drive, info, data, len);
|
||||
}
|
||||
|
||||
int stmp_scsi_get_device_info(stmp_device_t dev, uint8_t info, void *data, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_DEVICE_INFO, info, 0, data, len);
|
||||
}
|
||||
|
||||
int stmp_scsi_get_serial_number(stmp_device_t dev, uint8_t info, void *data, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_CHIP_SERIAL_NUMBER, info, 0, data, 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)
|
||||
{
|
||||
uint8_t cdb[16];
|
||||
memset(cdb, 0, sizeof(cdb));
|
||||
cdb[0] = SCSI_STMP_READ;
|
||||
cdb[1] = SCSI_STMP_CMD_READ_LOGICAL_DRIVE_SECTOR;
|
||||
cdb[2] = drive;
|
||||
address = stmp_fix_endian64be(address);
|
||||
memcpy(&cdb[3], &address, sizeof(address));
|
||||
count = stmp_fix_endian32be(count);
|
||||
memcpy(&cdb[11], &count, sizeof(count));
|
||||
|
||||
uint8_t sense[32];
|
||||
int sense_size = sizeof(sense);
|
||||
|
||||
int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buffer, buffer_size);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return stmp_sense_analysis(dev, ret, sense, sense_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)
|
||||
{
|
||||
uint8_t cdb[16];
|
||||
memset(cdb, 0, sizeof(cdb));
|
||||
cdb[0] = SCSI_STMP_WRITE;
|
||||
cdb[1] = SCSI_STMP_CMD_WRITE_LOGICAL_DRIVE_SECTOR;
|
||||
cdb[2] = drive;
|
||||
address = stmp_fix_endian64be(address);
|
||||
memcpy(&cdb[3], &address, sizeof(address));
|
||||
count = stmp_fix_endian32be(count);
|
||||
memcpy(&cdb[11], &count, sizeof(count));
|
||||
|
||||
uint8_t sense[32];
|
||||
int sense_size = sizeof(sense);
|
||||
|
||||
int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_WRITE, sense, &sense_size, buffer, buffer_size);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return stmp_sense_analysis(dev, ret, sense, sense_size);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
case SCSI_STMP_MEDIA_TYPE_NAND: return "NAND";
|
||||
case SCSI_STMP_MEDIA_TYPE_SDMMC: return "SD/MMC";
|
||||
case SCSI_STMP_MEDIA_TYPE_HDD: return "HDD";
|
||||
case SCSI_STMP_MEDIA_TYPE_RAM: return "RAM";
|
||||
case SCSI_STMP_MEDIA_TYPE_iNAND: return "iNAND";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
const char *stmp_get_logical_media_vendor_string(uint32_t type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SCSI_STMP_MEDIA_VENDOR_SAMSUNG: return "Samsung";
|
||||
case SCSI_STMP_MEDIA_VENDOR_STMICRO: return "ST Micro";
|
||||
case SCSI_STMP_MEDIA_VENDOR_HYNIX: return "Hynix";
|
||||
case SCSI_STMP_MEDIA_VENDOR_MICRON: return "Micron";
|
||||
case SCSI_STMP_MEDIA_VENDOR_TOSHIBA: return "Toshiba";
|
||||
case SCSI_STMP_MEDIA_VENDOR_RENESAS: return "Renesas";
|
||||
case SCSI_STMP_MEDIA_VENDOR_INTEL: return "Intel";
|
||||
case SCSI_STMP_MEDIA_VENDOR_SANDISK: return "Sandisk";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
const char *stmp_get_logical_drive_type_string(uint32_t type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SCSI_STMP_DRIVE_TYPE_DATA: return "Data";
|
||||
case SCSI_STMP_DRIVE_TYPE_SYSTEM: return "System";
|
||||
case SCSI_STMP_DRIVE_TYPE_HIDDEN: return "Hidden";
|
||||
case SCSI_STMP_DRIVE_TYPE_UNKNOWN: return "Unknown";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
const char *stmp_get_logical_drive_tag_string(uint32_t type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SCSI_STMP_DRIVE_TAG_STMPSYS_S: return "System";
|
||||
case SCSI_STMP_DRIVE_TAG_HOSTLINK_S: return "Hostlink";
|
||||
case SCSI_STMP_DRIVE_TAG_RESOURCE_BIN: return "Resource";
|
||||
case SCSI_STMP_DRIVE_TAG_EXTRA_S: return "Extra";
|
||||
case SCSI_STMP_DRIVE_TAG_RESOURCE1_BIN: return "Resource1";
|
||||
case SCSI_STMP_DRIVE_TAG_OTGHOST_S: return "OTG";
|
||||
case SCSI_STMP_DRIVE_TAG_HOSTRSC_BIN: return "Host Resource";
|
||||
case SCSI_STMP_DRIVE_TAG_DATA: return "Data";
|
||||
case SCSI_STMP_DRIVE_TAG_HIDDEN: return "Hidden";
|
||||
case SCSI_STMP_DRIVE_TAG_BOOTMANAGER_S: return "Boot";
|
||||
case SCSI_STMP_DRIVE_TAG_UPDATER_S: return "Updater";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
const char *stmp_get_logical_media_state_string(uint8_t state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case SCSI_STMP_MEDIA_STATE_UNKNOWN: return "Unknown";
|
||||
case SCSI_STMP_MEDIA_STATE_ERASED: return "Erased";
|
||||
case SCSI_STMP_MEDIA_STATE_ALLOCATED: return "Allocated";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
|||
616
utils/imxtools/scsitools/stmp_scsi.c
Normal file
616
utils/imxtools/scsitools/stmp_scsi.c
Normal file
|
|
@ -0,0 +1,616 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2012 Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#define _BSD_SOURCE
|
||||
#include <endian.h>
|
||||
#include "stmp_scsi.h"
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
static int g_endian = -1;
|
||||
|
||||
struct stmp_device_t
|
||||
{
|
||||
rb_scsi_device_t dev;
|
||||
unsigned flags;
|
||||
void *user;
|
||||
stmp_printf_t printf;
|
||||
};
|
||||
|
||||
static inline int little_endian(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
uint32_t stmp_fix_endian32be(uint32_t w)
|
||||
{
|
||||
return !little_endian() ? w :
|
||||
(uint32_t)stmp_fix_endian16be(w) << 16 | stmp_fix_endian16be(w >> 16);
|
||||
}
|
||||
|
||||
uint64_t stmp_fix_endian64be(uint64_t w)
|
||||
{
|
||||
return !little_endian() ? w :
|
||||
(uint64_t)stmp_fix_endian32be(w) << 32 | stmp_fix_endian32be(w >> 32);
|
||||
}
|
||||
|
||||
static void misc_std_printf(void *user, const char *fmt, ...)
|
||||
{
|
||||
(void) user;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define stmp_printf(dev, ...) \
|
||||
dev->printf(dev->user, __VA_ARGS__)
|
||||
|
||||
#define stmp_debugf(dev, ...) \
|
||||
do{ if(dev->flags & STMP_DEBUG) stmp_printf(dev, __VA_ARGS__); }while(0)
|
||||
|
||||
stmp_device_t stmp_open(rb_scsi_device_t rdev, unsigned flags, void *user, stmp_printf_t printf)
|
||||
{
|
||||
if(printf == NULL)
|
||||
printf = misc_std_printf;
|
||||
stmp_device_t sdev = malloc(sizeof(struct stmp_device_t));
|
||||
memset(sdev, 0, sizeof(struct stmp_device_t));
|
||||
sdev->dev = rdev;
|
||||
sdev->flags = flags;
|
||||
sdev->user = user;
|
||||
sdev->printf = printf;
|
||||
return sdev;
|
||||
}
|
||||
|
||||
void stmp_close(stmp_device_t dev)
|
||||
{
|
||||
free(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)
|
||||
{
|
||||
struct rb_scsi_raw_cmd_t cmd;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.dir = RB_SCSI_NONE;
|
||||
if(flags & STMP_READ)
|
||||
cmd.dir = RB_SCSI_READ;
|
||||
if(flags & STMP_WRITE)
|
||||
cmd.dir = RB_SCSI_WRITE;
|
||||
cmd.cdb = cdb;
|
||||
cmd.cdb_len = cdb_size;
|
||||
cmd.sense = sense;
|
||||
cmd.sense_len = *sense_size;
|
||||
cmd.buf = buffer;
|
||||
cmd.buf_len = *buf_size;
|
||||
cmd.tmo = 1;
|
||||
int ret = rb_scsi_raw_xfer(dev->dev, &cmd);
|
||||
*sense_size = cmd.sense_len;
|
||||
*buf_size = cmd.buf_len;
|
||||
return ret == RB_SCSI_OK || ret == RB_SCSI_SENSE ? cmd.status : -ret;
|
||||
}
|
||||
|
||||
int stmp_sense_analysis(stmp_device_t dev, int status, uint8_t *sense, int sense_size)
|
||||
{
|
||||
if(status != 0 && (dev->flags & STMP_DEBUG))
|
||||
{
|
||||
stmp_printf(dev, "Status: %d\n", status);
|
||||
stmp_printf(dev, "Sense:");
|
||||
for(int i = 0; i < sense_size; i++)
|
||||
stmp_printf(dev, " %02x", sense[i]);
|
||||
stmp_printf(dev, "\n");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int stmp_scsi_read_cmd(stmp_device_t dev, uint8_t cmd, uint8_t subcmd,
|
||||
uint8_t subsubcmd, void *buf, int *len)
|
||||
{
|
||||
uint8_t cdb[16];
|
||||
memset(cdb, 0, sizeof(cdb));
|
||||
cdb[0] = SCSI_STMP_READ;
|
||||
cdb[1] = cmd;
|
||||
cdb[2] = subcmd;
|
||||
cdb[3] = subsubcmd;
|
||||
|
||||
uint8_t sense[32];
|
||||
int sense_size = sizeof(sense);
|
||||
|
||||
int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buf, len);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = stmp_sense_analysis(dev, ret, sense, sense_size);
|
||||
if(ret)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmp_scsi_inquiry(stmp_device_t dev, uint8_t *dev_type, char vendor[9], char product[17])
|
||||
{
|
||||
unsigned char buffer[36];
|
||||
uint8_t cdb[10];
|
||||
memset(cdb, 0, sizeof(cdb));
|
||||
cdb[0] = 0x12;
|
||||
cdb[4] = sizeof(buffer);
|
||||
|
||||
uint8_t sense[32];
|
||||
int sense_size = sizeof(sense);
|
||||
|
||||
int buf_sz = sizeof(buffer);
|
||||
int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buffer, &buf_sz);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
ret = stmp_sense_analysis(dev, ret, sense, sense_size);
|
||||
if(ret)
|
||||
return ret;
|
||||
if(buf_sz != sizeof(buffer))
|
||||
return -1;
|
||||
*dev_type = buffer[0];
|
||||
memcpy(vendor, buffer + 8, 8);
|
||||
vendor[8] = 0;
|
||||
memcpy(product, buffer + 16, 16);
|
||||
product[16] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmp_scsi_get_protocol_version(stmp_device_t dev, void *buf, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_PROTOCOL_VERSION, 0, 0, buf, len);
|
||||
}
|
||||
|
||||
int stmp_get_protocol_version(stmp_device_t dev, struct scsi_stmp_protocol_version_t *ver)
|
||||
{
|
||||
int len = sizeof(*ver);
|
||||
int ret = stmp_scsi_get_protocol_version(dev, ver, &len);
|
||||
if(ret || len != sizeof(*ver))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmp_scsi_get_chip_major_rev_id(stmp_device_t dev, void *buf, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_CHIP_MAJOR_REV_ID, 0, 0, buf, len);
|
||||
}
|
||||
|
||||
int stmp_get_chip_major_rev_id(stmp_device_t dev, uint16_t *ver)
|
||||
{
|
||||
int len = sizeof(*ver);
|
||||
int ret = stmp_scsi_get_chip_major_rev_id(dev, ver, &len);
|
||||
if(ret || len != sizeof(*ver))
|
||||
return -1;
|
||||
*ver = stmp_fix_endian16be(*ver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmp_scsi_get_rom_rev_id(stmp_device_t dev, void *buf, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_ROM_REV_ID, 0, 0, buf, len);
|
||||
}
|
||||
|
||||
int stmp_get_rom_rev_id(stmp_device_t dev, uint16_t *ver)
|
||||
{
|
||||
int len = sizeof(*ver);
|
||||
int ret = stmp_scsi_get_rom_rev_id(dev, ver, &len);
|
||||
if(ret || len != sizeof(*ver))
|
||||
return -1;
|
||||
*ver = stmp_fix_endian16be(*ver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmp_scsi_get_logical_media_info(stmp_device_t dev, uint8_t info, void *data, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_MEDIA_INFO, info, 0, data, len);
|
||||
}
|
||||
|
||||
int stmp_scsi_get_logical_table(stmp_device_t dev, int entry_count, void *buf, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_TABLE, entry_count, 0, buf, len);
|
||||
}
|
||||
|
||||
int stmp_get_logical_media_table(stmp_device_t dev, struct stmp_logical_media_table_t **table)
|
||||
{
|
||||
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)->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;
|
||||
}
|
||||
|
||||
int stmp_scsi_get_logical_drive_info(stmp_device_t dev, uint8_t drive, uint8_t info, void *data, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_LOGICAL_DRIVE_INFO, drive, info, data, len);
|
||||
}
|
||||
|
||||
int stmp_scsi_get_device_info(stmp_device_t dev, uint8_t info, void *data, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_DEVICE_INFO, info, 0, data, len);
|
||||
}
|
||||
|
||||
int stmp_scsi_get_serial_number(stmp_device_t dev, uint8_t info, void *data, int *len)
|
||||
{
|
||||
return stmp_scsi_read_cmd(dev, SCSI_STMP_CMD_GET_CHIP_SERIAL_NUMBER, info, 0, data, 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)
|
||||
{
|
||||
uint8_t cdb[16];
|
||||
memset(cdb, 0, sizeof(cdb));
|
||||
cdb[0] = SCSI_STMP_READ;
|
||||
cdb[1] = SCSI_STMP_CMD_READ_LOGICAL_DRIVE_SECTOR;
|
||||
cdb[2] = drive;
|
||||
address = stmp_fix_endian64be(address);
|
||||
memcpy(&cdb[3], &address, sizeof(address));
|
||||
count = stmp_fix_endian32be(count);
|
||||
memcpy(&cdb[11], &count, sizeof(count));
|
||||
|
||||
uint8_t sense[32];
|
||||
int sense_size = sizeof(sense);
|
||||
|
||||
int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_READ, sense, &sense_size, buffer, buffer_size);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return stmp_sense_analysis(dev, ret, sense, sense_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)
|
||||
{
|
||||
uint8_t cdb[16];
|
||||
memset(cdb, 0, sizeof(cdb));
|
||||
cdb[0] = SCSI_STMP_WRITE;
|
||||
cdb[1] = SCSI_STMP_CMD_WRITE_LOGICAL_DRIVE_SECTOR;
|
||||
cdb[2] = drive;
|
||||
address = stmp_fix_endian64be(address);
|
||||
memcpy(&cdb[3], &address, sizeof(address));
|
||||
count = stmp_fix_endian32be(count);
|
||||
memcpy(&cdb[11], &count, sizeof(count));
|
||||
|
||||
uint8_t sense[32];
|
||||
int sense_size = sizeof(sense);
|
||||
|
||||
int ret = stmp_scsi(dev, cdb, sizeof(cdb), STMP_WRITE, sense, &sense_size, buffer, buffer_size);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
return stmp_sense_analysis(dev, ret, sense, sense_size);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
case SCSI_STMP_MEDIA_TYPE_NAND: return "NAND";
|
||||
case SCSI_STMP_MEDIA_TYPE_SDMMC: return "SD/MMC";
|
||||
case SCSI_STMP_MEDIA_TYPE_HDD: return "HDD";
|
||||
case SCSI_STMP_MEDIA_TYPE_RAM: return "RAM";
|
||||
case SCSI_STMP_MEDIA_TYPE_iNAND: return "iNAND";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
const char *stmp_get_logical_media_vendor_string(uint32_t type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SCSI_STMP_MEDIA_VENDOR_SAMSUNG: return "Samsung";
|
||||
case SCSI_STMP_MEDIA_VENDOR_STMICRO: return "ST Micro";
|
||||
case SCSI_STMP_MEDIA_VENDOR_HYNIX: return "Hynix";
|
||||
case SCSI_STMP_MEDIA_VENDOR_MICRON: return "Micron";
|
||||
case SCSI_STMP_MEDIA_VENDOR_TOSHIBA: return "Toshiba";
|
||||
case SCSI_STMP_MEDIA_VENDOR_RENESAS: return "Renesas";
|
||||
case SCSI_STMP_MEDIA_VENDOR_INTEL: return "Intel";
|
||||
case SCSI_STMP_MEDIA_VENDOR_SANDISK: return "Sandisk";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
const char *stmp_get_logical_drive_type_string(uint32_t type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SCSI_STMP_DRIVE_TYPE_DATA: return "Data";
|
||||
case SCSI_STMP_DRIVE_TYPE_SYSTEM: return "System";
|
||||
case SCSI_STMP_DRIVE_TYPE_HIDDEN: return "Hidden";
|
||||
case SCSI_STMP_DRIVE_TYPE_UNKNOWN: return "Unknown";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
const char *stmp_get_logical_drive_tag_string(uint32_t type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SCSI_STMP_DRIVE_TAG_STMPSYS_S: return "System";
|
||||
case SCSI_STMP_DRIVE_TAG_HOSTLINK_S: return "Hostlink";
|
||||
case SCSI_STMP_DRIVE_TAG_RESOURCE_BIN: return "Resource";
|
||||
case SCSI_STMP_DRIVE_TAG_EXTRA_S: return "Extra";
|
||||
case SCSI_STMP_DRIVE_TAG_RESOURCE1_BIN: return "Resource1";
|
||||
case SCSI_STMP_DRIVE_TAG_OTGHOST_S: return "OTG";
|
||||
case SCSI_STMP_DRIVE_TAG_HOSTRSC_BIN: return "Host Resource";
|
||||
case SCSI_STMP_DRIVE_TAG_DATA: return "Data";
|
||||
case SCSI_STMP_DRIVE_TAG_HIDDEN: return "Hidden";
|
||||
case SCSI_STMP_DRIVE_TAG_BOOTMANAGER_S: return "Boot";
|
||||
case SCSI_STMP_DRIVE_TAG_UPDATER_S: return "Updater";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
const char *stmp_get_logical_media_state_string(uint8_t state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case SCSI_STMP_MEDIA_STATE_UNKNOWN: return "Unknown";
|
||||
case SCSI_STMP_MEDIA_STATE_ERASED: return "Erased";
|
||||
case SCSI_STMP_MEDIA_STATE_ALLOCATED: return "Allocated";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue