diff options
Diffstat (limited to 'utils/nwztools')
-rw-r--r-- | utils/nwztools/scsitools/Makefile | 20 | ||||
-rw-r--r-- | utils/nwztools/scsitools/misc.c | 53 | ||||
-rw-r--r-- | utils/nwztools/scsitools/misc.h | 50 | ||||
-rw-r--r-- | utils/nwztools/scsitools/scsitool.c | 516 |
4 files changed, 639 insertions, 0 deletions
diff --git a/utils/nwztools/scsitools/Makefile b/utils/nwztools/scsitools/Makefile new file mode 100644 index 0000000000..ed4bc88d0b --- /dev/null +++ b/utils/nwztools/scsitools/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | DEFINES= | ||
2 | CC=gcc | ||
3 | LD=gcc | ||
4 | CFLAGS=-g -std=c99 -W -Wall $(DEFINES) | ||
5 | LDFLAGS=-lsgutils2 | ||
6 | BINS=scsitool | ||
7 | |||
8 | all: $(BINS) | ||
9 | |||
10 | %.o: %.c | ||
11 | $(CC) $(CFLAGS) -c -o $@ $< | ||
12 | |||
13 | scsitool: scsitool.o misc.o | ||
14 | $(LD) -o $@ $^ $(LDFLAGS) | ||
15 | |||
16 | clean: | ||
17 | rm -fr *.o | ||
18 | |||
19 | veryclean: | ||
20 | rm -rf $(BINS) | ||
diff --git a/utils/nwztools/scsitools/misc.c b/utils/nwztools/scsitools/misc.c new file mode 100644 index 0000000000..108235e7fd --- /dev/null +++ b/utils/nwztools/scsitools/misc.c | |||
@@ -0,0 +1,53 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 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 <stdlib.h> | ||
22 | #include <stdio.h> | ||
23 | #include <time.h> | ||
24 | #include <ctype.h> | ||
25 | #include "misc.h" | ||
26 | |||
27 | char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' }; | ||
28 | |||
29 | char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' }; | ||
30 | char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' }; | ||
31 | char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' }; | ||
32 | char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' }; | ||
33 | char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; | ||
34 | |||
35 | static bool g_color_enable = true; | ||
36 | |||
37 | void *xmalloc(size_t s) | ||
38 | { | ||
39 | void * r = malloc(s); | ||
40 | if(!r) bugp("malloc"); | ||
41 | return r; | ||
42 | } | ||
43 | |||
44 | void enable_color(bool enable) | ||
45 | { | ||
46 | g_color_enable = enable; | ||
47 | } | ||
48 | |||
49 | void color(color_t c) | ||
50 | { | ||
51 | if(g_color_enable) | ||
52 | printf("%s", (char *)c); | ||
53 | } | ||
diff --git a/utils/nwztools/scsitools/misc.h b/utils/nwztools/scsitools/misc.h new file mode 100644 index 0000000000..035b0ef8c1 --- /dev/null +++ b/utils/nwztools/scsitools/misc.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 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 | #ifndef __MISC_H__ | ||
22 | #define __MISC_H__ | ||
23 | |||
24 | #include <stdbool.h> | ||
25 | #include <stdio.h> | ||
26 | |||
27 | #define _STR(a) #a | ||
28 | #define STR(a) _STR(a) | ||
29 | |||
30 | #define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0) | ||
31 | #define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0) | ||
32 | |||
33 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) | ||
34 | |||
35 | typedef char color_t[]; | ||
36 | |||
37 | extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; | ||
38 | void *xmalloc(size_t s); | ||
39 | void color(color_t c); | ||
40 | void enable_color(bool enable); | ||
41 | |||
42 | #ifndef MIN | ||
43 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) | ||
44 | #endif | ||
45 | |||
46 | #define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0) | ||
47 | |||
48 | #define cprintf_field(str1, ...) do{ cprintf(GREEN, str1); cprintf(YELLOW, __VA_ARGS__); }while(0) | ||
49 | |||
50 | #endif /* __MISC_H__ */ | ||
diff --git a/utils/nwztools/scsitools/scsitool.c b/utils/nwztools/scsitools/scsitool.c new file mode 100644 index 0000000000..6848fb90de --- /dev/null +++ b/utils/nwztools/scsitools/scsitool.c | |||
@@ -0,0 +1,516 @@ | |||
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 | |||
39 | bool g_debug = false; | ||
40 | bool g_force = false; | ||
41 | char *g_out_prefix = NULL; | ||
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 | cprintf_field("Status:", " "); fflush(stdout); | ||
155 | sg_print_scsi_status(status); | ||
156 | cprintf_field("\nSense:", " "); fflush(stdout); | ||
157 | sg_print_sense(NULL, sense, sense_size, 0); | ||
158 | if(status == GOOD) | ||
159 | return 0; | ||
160 | return status; | ||
161 | } | ||
162 | |||
163 | int do_dnk_cmd(uint32_t cmd, uint8_t sub_cmd, void *buffer, int *buffer_size) | ||
164 | { | ||
165 | uint8_t cdb[12] = {0xdd, 0, 0, 0, 0, 0, 0, 0xbc, 0, 0, 0, 0}; | ||
166 | cdb[10] = cmd; | ||
167 | cdb[11] = sub_cmd; | ||
168 | cdb[8] = (*buffer_size) >> 8; | ||
169 | cdb[9] = (*buffer_size) & 0xff; | ||
170 | |||
171 | uint8_t sense[32]; | ||
172 | int sense_size = 32; | ||
173 | |||
174 | int ret = do_scsi(cdb, 12, DO_READ, sense, &sense_size, buffer, buffer_size); | ||
175 | if(ret < 0) | ||
176 | return ret; | ||
177 | ret = do_sense_analysis(ret, sense, sense_size); | ||
178 | if(ret) | ||
179 | return ret; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | #define DNK_EXACT_LENGTH (1 << 0) | ||
184 | #define DNK_STRING (1 << 1) | ||
185 | #define DNK_UINT32 (1 << 2) | ||
186 | |||
187 | struct dnk_prop_t | ||
188 | { | ||
189 | char *name; | ||
190 | uint8_t cmd; | ||
191 | uint8_t subcmd; | ||
192 | int size; | ||
193 | unsigned flags; | ||
194 | }; | ||
195 | |||
196 | struct dnk_prop_t dnk_prop_list[] = | ||
197 | { | ||
198 | { "serial_num", 0x23, 1, 8, DNK_STRING}, | ||
199 | { "model_id", 0x23, 4, 4, DNK_EXACT_LENGTH | DNK_UINT32}, | ||
200 | { "product_id", 0x23, 6, 12, DNK_STRING}, | ||
201 | { "destination", 0x23, 8, 4, DNK_EXACT_LENGTH | DNK_UINT32}, | ||
202 | { "model_id2", 0x23, 9, 4, DNK_EXACT_LENGTH | DNK_UINT32}, | ||
203 | { "dev_info", 0x12, 0, 64, DNK_STRING}, | ||
204 | }; | ||
205 | |||
206 | #define NR_DNK_PROPS (sizeof(dnk_prop_list) / sizeof(dnk_prop_list[0])) | ||
207 | |||
208 | int get_dnk_prop(int argc, char **argv) | ||
209 | { | ||
210 | if(argc != 1 && argc != 4) | ||
211 | { | ||
212 | printf("You must specify a known property name or a full property specification:\n"); | ||
213 | printf("Full usage: <cmd> <subcmd> <size> <flags>\n"); | ||
214 | printf("Property usage: <prop>\n"); | ||
215 | printf("Properties:"); | ||
216 | for(unsigned i = 0; i < NR_DNK_PROPS; i++) | ||
217 | printf(" %s", dnk_prop_list[i].name); | ||
218 | printf("\n"); | ||
219 | return 1; | ||
220 | } | ||
221 | |||
222 | struct dnk_prop_t prop; | ||
223 | memset(&prop, 0, sizeof(prop)); | ||
224 | if(argc == 1) | ||
225 | { | ||
226 | for(unsigned i = 0; i < NR_DNK_PROPS; i++) | ||
227 | if(strcmp(dnk_prop_list[i].name, argv[0]) == 0) | ||
228 | prop = dnk_prop_list[i]; | ||
229 | if(prop.name == NULL) | ||
230 | { | ||
231 | cprintf(GREY, "Unknown property '%s'\n", argv[0]); | ||
232 | return 1; | ||
233 | } | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | prop.cmd = strtoul(argv[0], NULL, 0); | ||
238 | prop.subcmd = strtoul(argv[1], NULL, 0); | ||
239 | prop.size = strtoul(argv[2], NULL, 0); | ||
240 | prop.flags = strtoul(argv[3], NULL, 0); | ||
241 | } | ||
242 | |||
243 | char *buffer = buffer_alloc(prop.size + 1); | ||
244 | int buffer_size = prop.size; | ||
245 | int ret = do_dnk_cmd(prop.cmd, prop.subcmd, buffer, &buffer_size); | ||
246 | if(ret) | ||
247 | return ret; | ||
248 | if(buffer_size == 0) | ||
249 | { | ||
250 | cprintf(GREY, "Device didn't send any data\n"); | ||
251 | return 1; | ||
252 | } | ||
253 | if((prop.flags & DNK_EXACT_LENGTH) && buffer_size != prop.size) | ||
254 | { | ||
255 | cprintf(GREY, "Device didn't send the expected amount of data\n"); | ||
256 | return 2; | ||
257 | } | ||
258 | buffer[buffer_size] = 0; | ||
259 | if(prop.flags & DNK_STRING) | ||
260 | cprintf_field("Property: ", "%s\n", buffer); | ||
261 | else if(prop.flags & DNK_UINT32) | ||
262 | cprintf_field("Property: ", "0x%x\n", *(uint32_t *)buffer); | ||
263 | else | ||
264 | { | ||
265 | cprintf(GREEN, "Property:\n"); | ||
266 | print_hex(buffer, buffer_size); | ||
267 | } | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | struct dpcc_prop_t | ||
272 | { | ||
273 | char *user_name; | ||
274 | char name[7]; | ||
275 | uint8_t cdb1; | ||
276 | int size; | ||
277 | }; | ||
278 | |||
279 | struct dpcc_prop_t dpcc_prop_list[] = | ||
280 | { | ||
281 | { "dev_info", "DEVINFO", 0, 0x80 }, | ||
282 | }; | ||
283 | |||
284 | #define NR_DPCC_PROPS (sizeof(dpcc_prop_list) / sizeof(dpcc_prop_list[0])) | ||
285 | |||
286 | int do_dpcc_cmd(uint32_t cmd, struct dpcc_prop_t *prop, void *buffer, int *buffer_size) | ||
287 | { | ||
288 | uint8_t cdb[12] = {0xfb, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
289 | cdb[2] = cmd; | ||
290 | if(cmd == 0) | ||
291 | { | ||
292 | strncpy((char *)(cdb + 3), prop->name, 7); // warning: erase cdb[10] ! | ||
293 | cdb[1] = prop->cdb1; | ||
294 | if(prop->cdb1 & 1) | ||
295 | cdb[10] = (*buffer_size + 15) / 16; | ||
296 | else | ||
297 | cdb[10] = *buffer_size; | ||
298 | } | ||
299 | |||
300 | uint8_t sense[32]; | ||
301 | int sense_size = 32; | ||
302 | |||
303 | int ret = do_scsi(cdb, 12, DO_READ, sense, &sense_size, buffer, buffer_size); | ||
304 | if(ret < 0) | ||
305 | return ret; | ||
306 | ret = do_sense_analysis(ret, sense, sense_size); | ||
307 | if(ret) | ||
308 | return ret; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | int get_dpcc_prop(int argc, char **argv) | ||
313 | { | ||
314 | if(argc != 1 && argc != 3) | ||
315 | { | ||
316 | printf("You must specify a known property name or a full property specification:\n"); | ||
317 | printf("Full usage: <prop code> <large> <size>\n"); | ||
318 | printf("Property usage: <prop>\n"); | ||
319 | printf("Properties:"); | ||
320 | for(unsigned i = 0; i < NR_DPCC_PROPS; i++) | ||
321 | printf(" %s", dpcc_prop_list[i].user_name); | ||
322 | printf("\n"); | ||
323 | return 1; | ||
324 | } | ||
325 | |||
326 | struct dpcc_prop_t prop; | ||
327 | memset(&prop, 0, sizeof(prop)); | ||
328 | if(argc == 1) | ||
329 | { | ||
330 | for(unsigned i = 0; i < NR_DPCC_PROPS; i++) | ||
331 | if(strcmp(dpcc_prop_list[i].user_name, argv[0]) == 0) | ||
332 | prop = dpcc_prop_list[i]; | ||
333 | if(prop.user_name[0] == 0) | ||
334 | { | ||
335 | cprintf(GREY, "Unknown property '%s'\n", argv[0]); | ||
336 | return 1; | ||
337 | } | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | strncpy(prop.name, argv[0], 7); | ||
342 | prop.cdb1 = strtoul(argv[1], NULL, 0); | ||
343 | prop.size = strtoul(argv[2], NULL, 0); | ||
344 | } | ||
345 | |||
346 | char *buffer = buffer_alloc(prop.size); | ||
347 | int buffer_size = prop.size; | ||
348 | int ret = do_dpcc_cmd(0, &prop, buffer, &buffer_size); | ||
349 | if(ret) | ||
350 | return ret; | ||
351 | if(buffer_size < prop.size) | ||
352 | buffer[buffer_size] = 0; | ||
353 | cprintf_field("Property: ", "%s\n", buffer); | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | struct user_timer_t | ||
358 | { | ||
359 | uint16_t magic; | ||
360 | uint8_t res[6]; | ||
361 | uint8_t year[2]; // bcd | ||
362 | uint8_t month; // bcd | ||
363 | uint8_t day; // bcd | ||
364 | uint8_t hour; // bcd | ||
365 | uint8_t min; // bcd | ||
366 | uint8_t sec; // bcd | ||
367 | uint8_t res2[17]; | ||
368 | } __attribute__((packed)); | ||
369 | |||
370 | int get_user_time(int argc, char **argv) | ||
371 | { | ||
372 | (void) argc; | ||
373 | (void )argv; | ||
374 | |||
375 | void *buffer = buffer_alloc(32); | ||
376 | int buffer_size = 32; | ||
377 | int ret = do_dpcc_cmd(1, NULL, buffer, &buffer_size); | ||
378 | if(ret) | ||
379 | return ret; | ||
380 | struct user_timer_t *time = buffer; | ||
381 | cprintf_field("User Time: ", "%02x/%02x/%02x%02x %02x:%02x:%02x\n", | ||
382 | time->day, time->month, time->year[0], time->year[1], time->hour, | ||
383 | time->min, time->sec); | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | int get_dev_info(int argc, char **argv) | ||
388 | { | ||
389 | (void) argc; | ||
390 | (void )argv; | ||
391 | uint8_t cdb[12] = {0xfc, 0, 0x20, 'd', 'b', 'm', 'n', 0, 0x80, 0, 0, 0}; | ||
392 | |||
393 | char *buffer = buffer_alloc(0x81); | ||
394 | int buffer_size = 0x80; | ||
395 | uint8_t sense[32]; | ||
396 | int sense_size = 32; | ||
397 | |||
398 | int ret = do_scsi(cdb, 12, DO_READ, sense, &sense_size, buffer, &buffer_size); | ||
399 | if(ret < 0) | ||
400 | return ret; | ||
401 | ret = do_sense_analysis(ret, sense, sense_size); | ||
402 | if(ret) | ||
403 | return ret; | ||
404 | buffer[buffer_size] = 0; | ||
405 | cprintf_field("Device Info:", "\n"); | ||
406 | print_hex(buffer, buffer_size); | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | typedef int (*cmd_fn_t)(int argc, char **argv); | ||
411 | |||
412 | struct cmd_t | ||
413 | { | ||
414 | const char *name; | ||
415 | const char *desc; | ||
416 | cmd_fn_t fn; | ||
417 | }; | ||
418 | |||
419 | struct cmd_t cmd_list[] = | ||
420 | { | ||
421 | { "get_dnk_prop", "Get DNK property", get_dnk_prop }, | ||
422 | { "get_dpcc_prop", "Get DPCC property", get_dpcc_prop }, | ||
423 | { "get_user_time", "Get user time", get_user_time }, | ||
424 | { "get_dev_info", "Get device info", get_dev_info }, | ||
425 | }; | ||
426 | |||
427 | #define NR_CMDS (sizeof(cmd_list) / sizeof(cmd_list[0])) | ||
428 | |||
429 | int process_cmd(const char *cmd, int argc, char **argv) | ||
430 | { | ||
431 | for(unsigned i = 0; i < NR_CMDS; i++) | ||
432 | if(strcmp(cmd_list[i].name, cmd) == 0) | ||
433 | return cmd_list[i].fn(argc, argv); | ||
434 | cprintf(GREY, "Unknown command '%s'\n", cmd); | ||
435 | return 1; | ||
436 | } | ||
437 | |||
438 | static void usage(void) | ||
439 | { | ||
440 | printf("Usage: emmctool [options] <dev> <command> [arguments]\n"); | ||
441 | printf("Options:\n"); | ||
442 | printf(" -o <prefix>\tSet output prefix\n"); | ||
443 | printf(" -f/--force\tForce to continue on errors\n"); | ||
444 | printf(" -?/--help\tDisplay this message\n"); | ||
445 | printf(" -d/--debug\tDisplay debug messages\n"); | ||
446 | printf(" -c/--no-color\tDisable color output\n"); | ||
447 | printf("Commands:\n"); | ||
448 | for(unsigned i = 0; i < NR_CMDS; i++) | ||
449 | printf(" %s\t%s\n", cmd_list[i].name, cmd_list[i].desc); | ||
450 | exit(1); | ||
451 | } | ||
452 | |||
453 | int main(int argc, char **argv) | ||
454 | { | ||
455 | while(1) | ||
456 | { | ||
457 | static struct option long_options[] = | ||
458 | { | ||
459 | {"help", no_argument, 0, '?'}, | ||
460 | {"debug", no_argument, 0, 'd'}, | ||
461 | {"no-color", no_argument, 0, 'c'}, | ||
462 | {"force", no_argument, 0, 'f'}, | ||
463 | {0, 0, 0, 0} | ||
464 | }; | ||
465 | |||
466 | int c = getopt_long(argc, argv, "?dcfo:", long_options, NULL); | ||
467 | if(c == -1) | ||
468 | break; | ||
469 | switch(c) | ||
470 | { | ||
471 | case -1: | ||
472 | break; | ||
473 | case 'c': | ||
474 | enable_color(false); | ||
475 | break; | ||
476 | case 'd': | ||
477 | g_debug = true; | ||
478 | break; | ||
479 | case 'f': | ||
480 | g_force = true; | ||
481 | break; | ||
482 | case '?': | ||
483 | usage(); | ||
484 | break; | ||
485 | case 'o': | ||
486 | g_out_prefix = optarg; | ||
487 | break; | ||
488 | default: | ||
489 | abort(); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | if(argc - optind < 2) | ||
494 | { | ||
495 | usage(); | ||
496 | return 1; | ||
497 | } | ||
498 | |||
499 | int ret = 0; | ||
500 | g_dev_fd = scsi_pt_open_device(argv[optind], false, true); | ||
501 | if(g_dev_fd < 0) | ||
502 | { | ||
503 | cprintf(GREY, "Cannot open device: %m\n"); | ||
504 | ret = 1; | ||
505 | goto Lend; | ||
506 | } | ||
507 | |||
508 | ret = process_cmd(argv[optind + 1], argc - optind - 2, argv + optind + 2); | ||
509 | |||
510 | scsi_pt_close_device(g_dev_fd); | ||
511 | Lend: | ||
512 | color(OFF); | ||
513 | |||
514 | return ret; | ||
515 | } | ||
516 | |||