summaryrefslogtreecommitdiff
path: root/utils/imxtools/scsitools/scsitool.c
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/scsitool.c
parentfb05b3e6983e08e0125e2156232b16e55fd571a5 (diff)
downloadrockbox-b86b0a1b44f88e74a82da81eebae02828d6d09fc.tar.gz
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/scsitool.c')
-rw-r--r--utils/imxtools/scsitools/scsitool.c310
1 files changed, 310 insertions, 0 deletions
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2012 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <stdint.h>
23#include <stdbool.h>
24#include <stdlib.h>
25#include <stddef.h>
26#include <string.h>
27#include <getopt.h>
28#include <stdarg.h>
29#include <ctype.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <unistd.h>
34#include <scsi/scsi.h>
35#include <scsi/sg_lib.h>
36#include <scsi/sg_pt.h>
37#include "misc.h"
38#include "stmp_scsi.h"
39
40bool g_debug = false;
41bool g_force = false;
42int g_dev_fd = 0;
43
44#define let_the_force_flow(x) do { if(!g_force) return x; } while(0)
45#define continue_the_force(x) if(x) let_the_force_flow(x)
46
47#define check_field(v_exp, v_have, str_ok, str_bad) \
48 if((v_exp) != (v_have)) \
49 { cprintf(RED, str_bad); let_the_force_flow(__LINE__); } \
50 else { cprintf(RED, str_ok); }
51
52#define errorf(...) do { cprintf(GREY, __VA_ARGS__); return __LINE__; } while(0)
53
54#if 0
55void *buffer_alloc(int sz)
56{
57#ifdef SG_LIB_MINGW
58 unsigned psz = getpagesize();
59#else
60 unsigned psz = sysconf(_SC_PAGESIZE); /* was getpagesize() */
61#endif
62 void *buffer = malloc(sz + psz);
63 return (void *)(((ptrdiff_t)(buffer + psz - 1)) & ~(psz - 1));
64}
65#else
66void *buffer_alloc(int sz)
67{
68 return malloc(sz);
69}
70#endif
71
72static void print_hex(void *_buffer, int buffer_size)
73{
74 uint8_t *buffer = _buffer;
75 for(int i = 0; i < buffer_size; i += 16)
76 {
77 for(int j = 0; j < 16; j++)
78 {
79 if(i + j < buffer_size)
80 cprintf(YELLOW, " %02x", buffer[i + j]);
81 else
82 cprintf(YELLOW, " ");
83 }
84 printf(" ");
85 for(int j = 0; j < 16; j++)
86 {
87 if(i + j < buffer_size)
88 cprintf(RED, "%c", isprint(buffer[i + j]) ? buffer[i + j] : '.');
89 else
90 cprintf(RED, " ");
91 }
92 printf("\n");
93 }
94}
95
96/* Do read */
97#define DO_READ (1 << 1)
98/* Do write */
99#define DO_WRITE (1 << 2)
100
101/* returns <0 on error and status otherwise */
102int do_scsi(uint8_t *cdb, int cdb_size, unsigned flags, void *sense, int *sense_size, void *buffer, int *buf_size)
103{
104 char error[256];
105 struct sg_pt_base *obj = construct_scsi_pt_obj();
106 if(obj == NULL)
107 {
108 cprintf(GREY, "construct_scsi_pt_obj failed\n");
109 return 1;
110 }
111 set_scsi_pt_cdb(obj, cdb, cdb_size);
112 if(sense)
113 set_scsi_pt_sense(obj, sense, *sense_size);
114 if(flags & DO_READ)
115 set_scsi_pt_data_in(obj, buffer, *buf_size);
116 if(flags & DO_WRITE)
117 set_scsi_pt_data_out(obj, buffer, *buf_size);
118 int ret = do_scsi_pt(obj, g_dev_fd, 1, 0);
119 switch(get_scsi_pt_result_category(obj))
120 {
121 case SCSI_PT_RESULT_SENSE:
122 case SCSI_PT_RESULT_GOOD:
123 ret = get_scsi_pt_status_response(obj);
124 break;
125 case SCSI_PT_RESULT_STATUS:
126 cprintf(GREY, "Status error: %d (", get_scsi_pt_status_response(obj));
127 sg_print_scsi_status(get_scsi_pt_status_response(obj));
128 printf(")\n");
129 break;
130 case SCSI_PT_RESULT_TRANSPORT_ERR:
131 cprintf(GREY, "Transport error: %s\n", get_scsi_pt_transport_err_str(obj, 256, error));
132 ret = -2;
133 break;
134 case SCSI_PT_RESULT_OS_ERR:
135 cprintf(GREY, "OS error: %s\n", get_scsi_pt_os_err_str(obj, 256, error));
136 ret = -3;
137 break;
138 default:
139 cprintf(GREY, "Unknown error\n");
140 break;
141 }
142
143 if(sense)
144 *sense_size = get_scsi_pt_sense_len(obj);
145 if(flags & (DO_WRITE | DO_READ))
146 *buf_size -= get_scsi_pt_resid(obj);
147
148 destruct_scsi_pt_obj(obj);
149 return ret;
150}
151
152int do_sense_analysis(int status, uint8_t *sense, int sense_size)
153{
154 if(status != GOOD || g_debug)
155 {
156 cprintf_field("Status:", " "); fflush(stdout);
157 sg_print_scsi_status(status);
158 cprintf_field("\nSense:", " "); fflush(stdout);
159 sg_print_sense(NULL, sense, sense_size, 0);
160 }
161 if(status == GOOD)
162 return 0;
163 return status;
164}
165
166int stmp_inquiry(uint8_t *dev_type, char vendor[9], char product[17])
167{
168 unsigned char buffer[56];
169 uint8_t cdb[10];
170 memset(cdb, 0, sizeof(cdb));
171 cdb[0] = 0x12;
172 cdb[4] = sizeof(buffer);
173
174 uint8_t sense[32];
175 int sense_size = sizeof(sense);
176
177 int buf_sz = sizeof(buffer);
178 int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, buffer, &buf_sz);
179 if(ret < 0)
180 return ret;
181 ret = do_sense_analysis(ret, sense, sense_size);
182 if(ret)
183 return ret;
184 if(buf_sz != sizeof(buffer))
185 return -1;
186 *dev_type = buffer[0];
187 memcpy(vendor, buffer + 8, 8);
188 vendor[8] = 0;
189 memcpy(product, buffer + 16, 16);
190 product[16] = 0;
191 return 0;
192}
193
194static int stmp_get_protocol_version(struct scsi_stmp_protocol_version_t *ver)
195{
196 uint8_t cdb[10];
197 memset(cdb, 0, sizeof(cdb));
198 cdb[0] = SCSI_STMP_READ;
199 cdb[1] = SCSI_STMP_CMD_GET_PROTOCOL_VERSION;
200
201 uint8_t sense[32];
202 int sense_size = sizeof(sense);
203
204 int buf_sz = sizeof(struct scsi_stmp_protocol_version_t);
205 int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, ver, &buf_sz);
206 if(ret < 0)
207 return ret;
208 ret = do_sense_analysis(ret, sense, sense_size);
209 if(ret)
210 return ret;
211 if(buf_sz != sizeof(struct scsi_stmp_protocol_version_t))
212 return -1;
213 return 0;
214}
215
216static int do_work(void)
217{
218 cprintf(BLUE, "Information\n");
219
220 uint8_t dev_type;
221 char vendor[9];
222 char product[17];
223 int ret = stmp_inquiry(&dev_type, vendor, product);
224 if(ret)
225 errorf("Cannot get inquiry data: %d\n", ret);
226 cprintf_field(" Vendor: ", "%s\n", vendor);
227 cprintf_field(" Product: ", "%s\n", product);
228
229 struct scsi_stmp_protocol_version_t ver;
230 ret = stmp_get_protocol_version(&ver);
231 if(ret)
232 errorf("Cannot get protocol version: %d\n", ret);
233
234 cprintf_field(" Protocol: ", "%x.%x\n", ver.major, ver.minor);
235
236 return 0;
237}
238
239static void usage(void)
240{
241 printf("Usage: scsitool [options] <dev>\n");
242 printf("Options:\n");
243 printf(" -f/--force\tForce to continue on errors\n");
244 printf(" -?/--help\tDisplay this message\n");
245 printf(" -d/--debug\tDisplay debug messages\n");
246 printf(" -c/--no-color\tDisable color output\n");
247 exit(1);
248}
249
250int main(int argc, char **argv)
251{
252 while(1)
253 {
254 static struct option long_options[] =
255 {
256 {"help", no_argument, 0, '?'},
257 {"debug", no_argument, 0, 'd'},
258 {"no-color", no_argument, 0, 'c'},
259 {"force", no_argument, 0, 'f'},
260 {0, 0, 0, 0}
261 };
262
263 int c = getopt_long(argc, argv, "?dcf", long_options, NULL);
264 if(c == -1)
265 break;
266 switch(c)
267 {
268 case -1:
269 break;
270 case 'c':
271 enable_color(false);
272 break;
273 case 'd':
274 g_debug = true;
275 break;
276 case 'f':
277 g_force = true;
278 break;
279 case '?':
280 usage();
281 break;
282 default:
283 abort();
284 }
285 }
286
287 if(argc - optind != 1)
288 {
289 usage();
290 return 1;
291 }
292
293 int ret = 0;
294 g_dev_fd = scsi_pt_open_device(argv[optind], false, true);
295 if(g_dev_fd < 0)
296 {
297 cprintf(GREY, "Cannot open device: %m\n");
298 ret = 1;
299 goto Lend;
300 }
301
302 do_work();
303
304 scsi_pt_close_device(g_dev_fd);
305Lend:
306 color(OFF);
307
308 return ret;
309}
310