summaryrefslogtreecommitdiffstats
path: root/utils/imxtools/scsitools
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2012-12-11 20:15:51 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2012-12-11 20:20:49 +0100
commitb86b0a1b44f88e74a82da81eebae02828d6d09fc (patch)
tree461e27b71dde3a476e951a67d0b2f4cee5ad782a /utils/imxtools/scsitools
parentfb05b3e6983e08e0125e2156232b16e55fd571a5 (diff)
downloadrockbox-b86b0a1b44f88e74a82da81eebae02828d6d09fc.tar.gz
rockbox-b86b0a1b44f88e74a82da81eebae02828d6d09fc.tar.bz2
rockbox-b86b0a1b44f88e74a82da81eebae02828d6d09fc.zip
imxtools: introduce the new scsitool
It appears that all devices based on the Sigmaltel SDK support a common vendor specific SCSI interface when in UMS mode. This applies to the STMP36xx and the STMP37xx. This interface supports many operations: - get device info - get device paritionning - get janus/drm info - read/write/allocate/erase any partition - reset (chip or to updater and/or recovery) This includes the ability to do a firmware upgrade by rewriting the firmware partition. The tool currently does mostly nothing but will be enhanced depending on the reverse engineering efforts and the use of it. It has been tested on the Fuze+ and the Zen X-Fi2/3. Change-Id: Ibd4b2ad364c03ada4f9001573ef4cc87cfb041d1
Diffstat (limited to 'utils/imxtools/scsitools')
-rw-r--r--utils/imxtools/scsitools/Makefile20
-rw-r--r--utils/imxtools/scsitools/misc.c53
-rw-r--r--utils/imxtools/scsitools/misc.h50
-rw-r--r--utils/imxtools/scsitools/scsitool.c310
-rw-r--r--utils/imxtools/scsitools/stmp_scsi.h42
5 files changed, 475 insertions, 0 deletions
diff --git a/utils/imxtools/scsitools/Makefile b/utils/imxtools/scsitools/Makefile
new file mode 100644
index 0000000000..ed4bc88d0b
--- /dev/null
+++ b/utils/imxtools/scsitools/Makefile
@@ -0,0 +1,20 @@
+DEFINES=
+CC=gcc
+LD=gcc
+CFLAGS=-g -std=c99 -W -Wall $(DEFINES)
+LDFLAGS=-lsgutils2
+BINS=scsitool
+
+all: $(BINS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+scsitool: scsitool.o misc.o
+ $(LD) -o $@ $^ $(LDFLAGS)
+
+clean:
+ rm -fr *.o
+
+veryclean:
+ rm -rf $(BINS)
diff --git a/utils/imxtools/scsitools/misc.c b/utils/imxtools/scsitools/misc.c
new file mode 100644
index 0000000000..108235e7fd
--- /dev/null
+++ b/utils/imxtools/scsitools/misc.c
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 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 <stdio.h>
+#include <time.h>
+#include <ctype.h>
+#include "misc.h"
+
+char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' };
+
+char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' };
+char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
+char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
+char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
+char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
+
+static bool g_color_enable = true;
+
+void *xmalloc(size_t s)
+{
+ void * r = malloc(s);
+ if(!r) bugp("malloc");
+ return r;
+}
+
+void enable_color(bool enable)
+{
+ g_color_enable = enable;
+}
+
+void color(color_t c)
+{
+ if(g_color_enable)
+ printf("%s", (char *)c);
+}
diff --git a/utils/imxtools/scsitools/misc.h b/utils/imxtools/scsitools/misc.h
new file mode 100644
index 0000000000..035b0ef8c1
--- /dev/null
+++ b/utils/imxtools/scsitools/misc.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 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.
+ *
+ ****************************************************************************/
+#ifndef __MISC_H__
+#define __MISC_H__
+
+#include <stdbool.h>
+#include <stdio.h>
+
+#define _STR(a) #a
+#define STR(a) _STR(a)
+
+#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0)
+#define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0)
+
+#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
+
+typedef char color_t[];
+
+extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE;
+void *xmalloc(size_t s);
+void color(color_t c);
+void enable_color(bool enable);
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0)
+
+#define cprintf_field(str1, ...) do{ cprintf(GREEN, str1); cprintf(YELLOW, __VA_ARGS__); }while(0)
+
+#endif /* __MISC_H__ */
diff --git a/utils/imxtools/scsitools/scsitool.c b/utils/imxtools/scsitools/scsitool.c
new file mode 100644
index 0000000000..7fc68f8c37
--- /dev/null
+++ b/utils/imxtools/scsitools/scsitool.c
@@ -0,0 +1,310 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <scsi/scsi.h>
+#include <scsi/sg_lib.h>
+#include <scsi/sg_pt.h>
+#include "misc.h"
+#include "stmp_scsi.h"
+
+bool g_debug = false;
+bool g_force = false;
+int g_dev_fd = 0;
+
+#define let_the_force_flow(x) do { if(!g_force) return x; } while(0)
+#define continue_the_force(x) if(x) let_the_force_flow(x)
+
+#define check_field(v_exp, v_have, str_ok, str_bad) \
+ if((v_exp) != (v_have)) \
+ { cprintf(RED, str_bad); let_the_force_flow(__LINE__); } \
+ else { cprintf(RED, str_ok); }
+
+#define errorf(...) do { cprintf(GREY, __VA_ARGS__); return __LINE__; } while(0)
+
+#if 0
+void *buffer_alloc(int sz)
+{
+#ifdef SG_LIB_MINGW
+ unsigned psz = getpagesize();
+#else
+ unsigned psz = sysconf(_SC_PAGESIZE); /* was getpagesize() */
+#endif
+ void *buffer = malloc(sz + psz);
+ return (void *)(((ptrdiff_t)(buffer + psz - 1)) & ~(psz - 1));
+}
+#else
+void *buffer_alloc(int sz)
+{
+ return malloc(sz);
+}
+#endif
+
+static void print_hex(void *_buffer, int buffer_size)
+{
+ uint8_t *buffer = _buffer;
+ for(int i = 0; i < buffer_size; i += 16)
+ {
+ for(int j = 0; j < 16; j++)
+ {
+ if(i + j < buffer_size)
+ cprintf(YELLOW, " %02x", buffer[i + j]);
+ else
+ cprintf(YELLOW, " ");
+ }
+ printf(" ");
+ for(int j = 0; j < 16; j++)
+ {
+ if(i + j < buffer_size)
+ cprintf(RED, "%c", isprint(buffer[i + j]) ? buffer[i + j] : '.');
+ else
+ cprintf(RED, " ");
+ }
+ printf("\n");
+ }
+}
+
+/* Do read */
+#define DO_READ (1 << 1)
+/* Do write */
+#define DO_WRITE (1 << 2)
+
+/* returns <0 on error and status otherwise */
+int do_scsi(uint8_t *cdb, int cdb_size, unsigned flags, void *sense, int *sense_size, void *buffer, int *buf_size)
+{
+ char error[256];
+ struct sg_pt_base *obj = construct_scsi_pt_obj();
+ if(obj == NULL)
+ {
+ cprintf(GREY, "construct_scsi_pt_obj failed\n");
+ return 1;
+ }
+ set_scsi_pt_cdb(obj, cdb, cdb_size);
+ if(sense)
+ set_scsi_pt_sense(obj, sense, *sense_size);
+ if(flags & DO_READ)
+ set_scsi_pt_data_in(obj, buffer, *buf_size);
+ if(flags & DO_WRITE)
+ set_scsi_pt_data_out(obj, buffer, *buf_size);
+ int ret = do_scsi_pt(obj, g_dev_fd, 1, 0);
+ switch(get_scsi_pt_result_category(obj))
+ {
+ case SCSI_PT_RESULT_SENSE:
+ case SCSI_PT_RESULT_GOOD:
+ ret = get_scsi_pt_status_response(obj);
+ break;
+ case SCSI_PT_RESULT_STATUS:
+ cprintf(GREY, "Status error: %d (", get_scsi_pt_status_response(obj));
+ sg_print_scsi_status(get_scsi_pt_status_response(obj));
+ printf(")\n");
+ break;
+ case SCSI_PT_RESULT_TRANSPORT_ERR:
+ cprintf(GREY, "Transport error: %s\n", get_scsi_pt_transport_err_str(obj, 256, error));
+ ret = -2;
+ break;
+ case SCSI_PT_RESULT_OS_ERR:
+ cprintf(GREY, "OS error: %s\n", get_scsi_pt_os_err_str(obj, 256, error));
+ ret = -3;
+ break;
+ default:
+ cprintf(GREY, "Unknown error\n");
+ break;
+ }
+
+ if(sense)
+ *sense_size = get_scsi_pt_sense_len(obj);
+ if(flags & (DO_WRITE | DO_READ))
+ *buf_size -= get_scsi_pt_resid(obj);
+
+ destruct_scsi_pt_obj(obj);
+ return ret;
+}
+
+int do_sense_analysis(int status, uint8_t *sense, int sense_size)
+{
+ if(status != GOOD || g_debug)
+ {
+ cprintf_field("Status:", " "); fflush(stdout);
+ sg_print_scsi_status(status);
+ cprintf_field("\nSense:", " "); fflush(stdout);
+ sg_print_sense(NULL, sense, sense_size, 0);
+ }
+ if(status == GOOD)
+ return 0;
+ return status;
+}
+
+int stmp_inquiry(uint8_t *dev_type, char vendor[9], char product[17])
+{
+ unsigned char buffer[56];
+ 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 = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, buffer, &buf_sz);
+ if(ret < 0)
+ return ret;
+ ret = do_sense_analysis(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;
+}
+
+static int stmp_get_protocol_version(struct scsi_stmp_protocol_version_t *ver)
+{
+ uint8_t cdb[10];
+ memset(cdb, 0, sizeof(cdb));
+ cdb[0] = SCSI_STMP_READ;
+ cdb[1] = SCSI_STMP_CMD_GET_PROTOCOL_VERSION;
+
+ uint8_t sense[32];
+ int sense_size = sizeof(sense);
+
+ int buf_sz = sizeof(struct scsi_stmp_protocol_version_t);
+ int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, ver, &buf_sz);
+ if(ret < 0)
+ return ret;
+ ret = do_sense_analysis(ret, sense, sense_size);
+ if(ret)
+ return ret;
+ if(buf_sz != sizeof(struct scsi_stmp_protocol_version_t))
+ return -1;
+ return 0;
+}
+
+static int do_work(void)
+{
+ cprintf(BLUE, "Information\n");
+
+ uint8_t dev_type;
+ char vendor[9];
+ char product[17];
+ int ret = stmp_inquiry(&dev_type, vendor, product);
+ if(ret)
+ errorf("Cannot get inquiry data: %d\n", ret);
+ cprintf_field(" Vendor: ", "%s\n", vendor);
+ cprintf_field(" Product: ", "%s\n", product);
+
+ struct scsi_stmp_protocol_version_t ver;
+ ret = stmp_get_protocol_version(&ver);
+ if(ret)
+ errorf("Cannot get protocol version: %d\n", ret);
+
+ cprintf_field(" Protocol: ", "%x.%x\n", ver.major, ver.minor);
+
+ return 0;
+}
+
+static void usage(void)
+{
+ printf("Usage: scsitool [options] <dev>\n");
+ printf("Options:\n");
+ printf(" -f/--force\tForce to continue on errors\n");
+ printf(" -?/--help\tDisplay this message\n");
+ printf(" -d/--debug\tDisplay debug messages\n");
+ printf(" -c/--no-color\tDisable color output\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ while(1)
+ {
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, '?'},
+ {"debug", no_argument, 0, 'd'},
+ {"no-color", no_argument, 0, 'c'},
+ {"force", no_argument, 0, 'f'},
+ {0, 0, 0, 0}
+ };
+
+ int c = getopt_long(argc, argv, "?dcf", long_options, NULL);
+ if(c == -1)
+ break;
+ switch(c)
+ {
+ case -1:
+ break;
+ case 'c':
+ enable_color(false);
+ break;
+ case 'd':
+ g_debug = true;
+ break;
+ case 'f':
+ g_force = true;
+ break;
+ case '?':
+ usage();
+ break;
+ default:
+ abort();
+ }
+ }
+
+ if(argc - optind != 1)
+ {
+ usage();
+ return 1;
+ }
+
+ int ret = 0;
+ g_dev_fd = scsi_pt_open_device(argv[optind], false, true);
+ if(g_dev_fd < 0)
+ {
+ cprintf(GREY, "Cannot open device: %m\n");
+ ret = 1;
+ goto Lend;
+ }
+
+ do_work();
+
+ scsi_pt_close_device(g_dev_fd);
+Lend:
+ color(OFF);
+
+ return ret;
+}
+
diff --git a/utils/imxtools/scsitools/stmp_scsi.h b/utils/imxtools/scsitools/stmp_scsi.h
new file mode 100644
index 0000000000..14f651f6dd
--- /dev/null
+++ b/utils/imxtools/scsitools/stmp_scsi.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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.
+ *
+ ****************************************************************************/
+#ifndef __STMP_SCSI__
+#define __STMP_SCSI__
+
+#include <stdint.h>
+
+#define SCSI_STMP_READ 0xc0
+#define SCSI_STMP_WRITE 0xc1
+/** STMP: Command */
+#define SCSI_STMP_CMD_GET_PROTOCOL_VERSION 0
+#define SCSI_STMP_CMD_GET_LOGICAL_MEDIA_INFO 2
+#define SCSI_STMP_CMD_GET_LOGICAL_TABLE 5
+#define SCSI_STMP_CMD_GET_LOGICAL_DRIVE_INFO 0x12
+#define SCSI_STMP_CMD_GET_CHIP_MAJOR_REV_ID 0x30
+#define SCSI_STMP_CMD_GET_ROM_REV_ID 0x37
+
+struct scsi_stmp_protocol_version_t
+{
+ uint8_t major;
+ uint8_t minor;
+} __attribute__((packed));
+
+#endif /* __STMP_SCSI__ */