diff options
Diffstat (limited to 'utils/imxtools/scsitools/scsitool.c')
-rw-r--r-- | utils/imxtools/scsitools/scsitool.c | 310 |
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 | |||
40 | bool g_debug = false; | ||
41 | bool g_force = false; | ||
42 | int 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 | ||
55 | void *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 | ||
66 | void *buffer_alloc(int sz) | ||
67 | { | ||
68 | return malloc(sz); | ||
69 | } | ||
70 | #endif | ||
71 | |||
72 | static 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 */ | ||
102 | int 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 | |||
152 | int 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 | |||
166 | int 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 | |||
194 | static 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 | |||
216 | static 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 | |||
239 | static 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 | |||
250 | int 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); | ||
305 | Lend: | ||
306 | color(OFF); | ||
307 | |||
308 | return ret; | ||
309 | } | ||
310 | |||