Prepare new maemo release
[maemo-rb.git] / utils / imxtools / scsitools / scsitool.c
blob8ef2774f3225f0b7f82bf35803783c80e5ab30ed
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2012 Amaury Pouly
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
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 #ifndef _WIN32
35 #include <scsi/scsi.h>
36 #endif
37 #include <scsi/sg_lib.h>
38 #include <scsi/sg_pt.h>
39 #include "misc.h"
40 #include "stmp_scsi.h"
42 /* the windows port doesn't have scsi.h and GOOD */
43 #ifndef GOOD
44 #define GOOD 0x00
45 #endif
47 bool g_debug = false;
48 bool g_force = false;
49 int g_dev_fd = 0;
51 #define let_the_force_flow(x) do { if(!g_force) return x; } while(0)
52 #define continue_the_force(x) if(x) let_the_force_flow(x)
54 #define check_field(v_exp, v_have, str_ok, str_bad) \
55 if((v_exp) != (v_have)) \
56 { cprintf(RED, str_bad); let_the_force_flow(__LINE__); } \
57 else { cprintf(RED, str_ok); }
59 #define errorf(...) do { cprintf(GREY, __VA_ARGS__); return __LINE__; } while(0)
61 #if 0
62 void *buffer_alloc(int sz)
64 #ifdef SG_LIB_MINGW
65 unsigned psz = getpagesize();
66 #else
67 unsigned psz = sysconf(_SC_PAGESIZE); /* was getpagesize() */
68 #endif
69 void *buffer = malloc(sz + psz);
70 return (void *)(((ptrdiff_t)(buffer + psz - 1)) & ~(psz - 1));
72 #else
73 void *buffer_alloc(int sz)
75 return malloc(sz);
77 #endif
79 static uint16_t fix_endian16be(uint16_t w)
81 return w << 8 | w >> 8;
84 static uint32_t fix_endian32be(uint32_t w)
86 return __builtin_bswap32(w);
89 static uint64_t fix_endian64be(uint64_t w)
91 return __builtin_bswap64(w);
94 static void print_hex(void *_buffer, int buffer_size)
96 uint8_t *buffer = _buffer;
97 for(int i = 0; i < buffer_size; i += 16)
99 for(int j = 0; j < 16; j++)
101 if(i + j < buffer_size)
102 cprintf(YELLOW, " %02x", buffer[i + j]);
103 else
104 cprintf(YELLOW, " ");
106 printf(" ");
107 for(int j = 0; j < 16; j++)
109 if(i + j < buffer_size)
110 cprintf(RED, "%c", isprint(buffer[i + j]) ? buffer[i + j] : '.');
111 else
112 cprintf(RED, " ");
114 printf("\n");
118 /* Do read */
119 #define DO_READ (1 << 1)
120 /* Do write */
121 #define DO_WRITE (1 << 2)
123 /* returns <0 on error and status otherwise */
124 int do_scsi(uint8_t *cdb, int cdb_size, unsigned flags, void *sense, int *sense_size, void *buffer, int *buf_size)
126 char error[256];
127 struct sg_pt_base *obj = construct_scsi_pt_obj();
128 if(obj == NULL)
130 cprintf(GREY, "construct_scsi_pt_obj failed\n");
131 return 1;
133 set_scsi_pt_cdb(obj, cdb, cdb_size);
134 if(sense)
135 set_scsi_pt_sense(obj, sense, *sense_size);
136 if(flags & DO_READ)
137 set_scsi_pt_data_in(obj, buffer, *buf_size);
138 if(flags & DO_WRITE)
139 set_scsi_pt_data_out(obj, buffer, *buf_size);
140 int ret = do_scsi_pt(obj, g_dev_fd, 1, 0);
141 switch(get_scsi_pt_result_category(obj))
143 case SCSI_PT_RESULT_SENSE:
144 case SCSI_PT_RESULT_GOOD:
145 ret = get_scsi_pt_status_response(obj);
146 break;
147 case SCSI_PT_RESULT_STATUS:
148 cprintf(GREY, "Status error: %d (", get_scsi_pt_status_response(obj));
149 sg_print_scsi_status(get_scsi_pt_status_response(obj));
150 printf(")\n");
151 break;
152 case SCSI_PT_RESULT_TRANSPORT_ERR:
153 cprintf(GREY, "Transport error: %s\n", get_scsi_pt_transport_err_str(obj, 256, error));
154 ret = -2;
155 break;
156 case SCSI_PT_RESULT_OS_ERR:
157 cprintf(GREY, "OS error: %s\n", get_scsi_pt_os_err_str(obj, 256, error));
158 ret = -3;
159 break;
160 default:
161 cprintf(GREY, "Unknown error\n");
162 break;
165 if(sense)
166 *sense_size = get_scsi_pt_sense_len(obj);
167 if(flags & (DO_WRITE | DO_READ))
168 *buf_size -= get_scsi_pt_resid(obj);
170 destruct_scsi_pt_obj(obj);
171 return ret;
174 int do_sense_analysis(int status, uint8_t *sense, int sense_size)
176 if(status != GOOD && g_debug)
178 cprintf_field("Status:", " "); fflush(stdout);
179 sg_print_scsi_status(status);
180 cprintf_field("\nSense:", " "); fflush(stdout);
181 sg_print_sense(NULL, sense, sense_size, 0);
183 if(status == GOOD)
184 return 0;
185 return status;
188 int stmp_inquiry(uint8_t *dev_type, char vendor[9], char product[17])
190 unsigned char buffer[36];
191 uint8_t cdb[10];
192 memset(cdb, 0, sizeof(cdb));
193 cdb[0] = 0x12;
194 cdb[4] = sizeof(buffer);
196 uint8_t sense[32];
197 int sense_size = sizeof(sense);
199 int buf_sz = sizeof(buffer);
200 int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, buffer, &buf_sz);
201 if(ret < 0)
202 return ret;
203 ret = do_sense_analysis(ret, sense, sense_size);
204 if(ret)
205 return ret;
206 if(buf_sz != sizeof(buffer))
207 return -1;
208 *dev_type = buffer[0];
209 memcpy(vendor, buffer + 8, 8);
210 vendor[8] = 0;
211 memcpy(product, buffer + 16, 16);
212 product[16] = 0;
213 return 0;
216 static int stmp_get_protocol_version(struct scsi_stmp_protocol_version_t *ver)
218 uint8_t cdb[16];
219 memset(cdb, 0, sizeof(cdb));
220 cdb[0] = SCSI_STMP_READ;
221 cdb[1] = SCSI_STMP_CMD_GET_PROTOCOL_VERSION;
223 uint8_t sense[32];
224 int sense_size = sizeof(sense);
226 int buf_sz = sizeof(struct scsi_stmp_protocol_version_t);
227 int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, ver, &buf_sz);
228 if(ret < 0)
229 return ret;
230 ret = do_sense_analysis(ret, sense, sense_size);
231 if(ret)
232 return ret;
233 if(buf_sz != sizeof(struct scsi_stmp_protocol_version_t))
234 return -1;
235 return 0;
238 static int stmp_get_chip_major_rev_id(struct scsi_stmp_chip_major_rev_id_t *ver)
240 uint8_t cdb[16];
241 memset(cdb, 0, sizeof(cdb));
242 cdb[0] = SCSI_STMP_READ;
243 cdb[1] = SCSI_STMP_CMD_GET_CHIP_MAJOR_REV_ID;
245 uint8_t sense[32];
246 int sense_size = sizeof(sense);
248 int buf_sz = sizeof(struct scsi_stmp_chip_major_rev_id_t);
249 int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, ver, &buf_sz);
250 if(ret < 0)
251 return ret;
252 ret = do_sense_analysis(ret, sense, sense_size);
253 if(ret)
254 return ret;
255 if(buf_sz != sizeof(struct scsi_stmp_chip_major_rev_id_t))
256 return -1;
257 ver->rev = fix_endian16be(ver->rev);
258 return 0;
261 static int stmp_get_rom_rev_id(struct scsi_stmp_rom_rev_id_t *ver)
263 uint8_t cdb[16];
264 memset(cdb, 0, sizeof(cdb));
265 cdb[0] = SCSI_STMP_READ;
266 cdb[1] = SCSI_STMP_CMD_GET_ROM_REV_ID;
268 uint8_t sense[32];
269 int sense_size = sizeof(sense);
271 int buf_sz = sizeof(struct scsi_stmp_rom_rev_id_t);
272 int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, ver, &buf_sz);
273 if(ret < 0)
274 return ret;
275 ret = do_sense_analysis(ret, sense, sense_size);
276 if(ret)
277 return ret;
278 if(buf_sz != sizeof(struct scsi_stmp_rom_rev_id_t))
279 return -1;
280 ver->rev = fix_endian16be(ver->rev);
281 return 0;
284 static int stmp_get_logical_media_info(uint8_t info, void *data, int *len)
286 uint8_t cdb[16];
287 memset(cdb, 0, sizeof(cdb));
288 cdb[0] = SCSI_STMP_READ;
289 cdb[1] = SCSI_STMP_CMD_GET_LOGICAL_MEDIA_INFO;
290 cdb[2] = info;
292 uint8_t sense[32];
293 int sense_size = sizeof(sense);
295 int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, data, len);
296 if(ret < 0)
297 return ret;
298 return do_sense_analysis(ret, sense, sense_size);
301 static int stmp_get_logical_table(struct scsi_stmp_logical_table_t *table, int entry_count)
303 uint8_t cdb[16];
304 memset(cdb, 0, sizeof(cdb));
305 cdb[0] = SCSI_STMP_READ;
306 cdb[1] = SCSI_STMP_CMD_GET_LOGICAL_TABLE;
307 cdb[2] = entry_count;
309 uint8_t sense[32];
310 int sense_size = sizeof(sense);
312 int buf_sz = sizeof(struct scsi_stmp_logical_table_t) +
313 entry_count * sizeof(struct scsi_stmp_logical_table_entry_t);
314 int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, table, &buf_sz);
315 if(ret < 0)
316 return ret;
317 ret = do_sense_analysis(ret, sense, sense_size);
318 if(ret)
319 return ret;
320 if((buf_sz - sizeof(struct scsi_stmp_logical_table_t)) % sizeof(struct scsi_stmp_logical_table_entry_t))
321 return -1;
322 table->count = fix_endian16be(table->count);
323 struct scsi_stmp_logical_table_entry_t *entry = (void *)(table + 1);
324 for(int i = 0; i < entry_count; i++)
325 entry[i].size = fix_endian64be(entry[i].size);
326 return 0;
329 static int stmp_get_logical_drive_info(uint8_t drive, uint8_t info, void *data, int *len)
331 uint8_t cdb[16];
332 memset(cdb, 0, sizeof(cdb));
333 cdb[0] = SCSI_STMP_READ;
334 cdb[1] = SCSI_STMP_CMD_GET_LOGICAL_DRIVE_INFO;
335 cdb[2] = drive;
336 cdb[3] = info;
338 uint8_t sense[32];
339 int sense_size = sizeof(sense);
341 int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, data, len);
342 if(ret < 0)
343 return ret;
344 return do_sense_analysis(ret, sense, sense_size);
347 static int do_work(void)
349 cprintf(BLUE, "Information\n");
351 uint8_t dev_type;
352 char vendor[9];
353 char product[17];
354 int ret = stmp_inquiry(&dev_type, vendor, product);
355 if(ret)
357 cprintf(GREY, "Cannot get inquiry data: %d\n", ret);
359 else
361 cprintf_field(" Vendor: ", "%s\n", vendor);
362 cprintf_field(" Product: ", "%s\n", product);
365 struct scsi_stmp_protocol_version_t ver;
366 ret = stmp_get_protocol_version(&ver);
367 if(ret)
368 cprintf(GREY, "Cannot get protocol version: %d\n", ret);
369 else
370 cprintf_field(" Protocol: ", "%x.%x\n", ver.major, ver.minor);
374 union
376 uint8_t u8;
377 uint16_t u16;
378 uint32_t u32;
379 uint64_t u64;
380 uint8_t buf[52];
383 int len = 2;
384 ret = stmp_get_logical_media_info(0, &u.u16, &len);
385 if(!ret && len == 2)
387 u.u16 = fix_endian16be(u.u16);
388 cprintf_field(" Logical Media Info (0): ", "%#x\n", u.u16);
391 len = 4;
392 ret = stmp_get_logical_media_info(6, &u.u32, &len);
393 if(!ret && len == 4)
395 u.u32 = fix_endian32be(u.u32);
396 cprintf_field(" Logical Media Info (6): ", "%#x\n", u.u32);
399 len = 1;
400 ret = stmp_get_logical_media_info(5, &u.u8, &len);
401 if(!ret && len == 1)
402 cprintf_field(" Logical Media Info (5): ", "%#x\n", u.u8);
404 len = 8;
405 ret = stmp_get_logical_media_info(1, &u.u64, &len);
406 if(!ret && len == 8)
408 u.u64 = fix_endian64be(u.u64);
409 cprintf_field(" Logical Media Info (1): ", "%#llx\n", u.u64);
412 len = 4;
413 ret = stmp_get_logical_media_info(7, &u.u32, &len);
414 if(!ret && len == 4)
416 u.u32 = fix_endian32be(u.u32);
417 cprintf_field(" Logical Media Info (7): ", "%#x\n", u.u32);
420 len = 52;
421 ret = stmp_get_logical_media_info(8, &u.buf, &len);
422 if(!ret && len != 0)
424 cprintf(GREEN, " Logical Media Info (8):");
426 for(int i = 0; i < len; i++)
427 cprintf(YELLOW, " %02x", u.buf[i]);
428 printf("\n");
430 print_hex(u.buf, len);
433 len = 1;
434 ret = stmp_get_logical_media_info(9, &u.u8, &len);
435 if(!ret && len == 1)
436 cprintf_field(" Logical Media Info (9): ", "%#x\n", u.u8);
438 len = 4;
439 ret = stmp_get_logical_media_info(12, &u.u32, &len);
440 if(!ret && len == 4)
442 u.u32 = fix_endian32be(u.u32);
443 cprintf_field(" Logical Media Info (12): ", "%#x\n", u.u32);
446 len = 8;
447 ret = stmp_get_logical_media_info(13, &u.u64, &len);
448 if(!ret && len == 8)
450 u.u64 = fix_endian64be(u.u64);
451 cprintf_field(" Logical Media Info (13): ", "%#llx\n", u.u64);
454 len = 4;
455 ret = stmp_get_logical_media_info(11, &u.u32, &len);
456 if(!ret && len == 4)
458 u.u32 = fix_endian32be(u.u32);
459 cprintf_field(" Logical Media Info (11): ", "%#x\n", u.u32);
462 len = 4;
463 ret = stmp_get_logical_media_info(14, &u.u32, &len);
464 if(!ret && len == 4)
466 u.u32 = fix_endian32be(u.u32);
467 cprintf_field(" Logical Media Info (14): ", "%#x\n", u.u32);
469 }while(0);
471 struct scsi_stmp_chip_major_rev_id_t chip_rev;
472 ret = stmp_get_chip_major_rev_id(&chip_rev);
473 if(ret)
474 cprintf(GREY, "Cannot get chip major revision id: %d\n", ret);
475 else
476 cprintf_field(" Chip Major Rev ID: ", "%x\n", chip_rev.rev);
478 struct scsi_stmp_rom_rev_id_t rom_rev;
479 ret = stmp_get_rom_rev_id(&rom_rev);
480 if(ret)
481 cprintf(GREY, "Cannot get rom revision id: %d\n", ret);
482 else
483 cprintf_field(" ROM Rev ID: ", "%x\n", rom_rev.rev);
485 struct
487 struct scsi_stmp_logical_table_t header;
488 struct scsi_stmp_logical_table_entry_t entry[20];
489 }table;
491 ret = stmp_get_logical_table(&table.header, sizeof(table.entry) / sizeof(table.entry[0]));
492 if(ret)
493 cprintf(GREY, "Cannot get logical table: %d\n", ret);
494 else
496 cprintf_field(" Logical Table: ", "%d entries\n", table.header.count);
497 for(int i = 0; i < table.header.count; i++)
499 cprintf_field2(" Drive No: ", "%2x", table.entry[i].drive_no);
500 cprintf_field2(" Type: ", "%2x", table.entry[i].type);
501 cprintf_field2(" Tag: ", "%2x", table.entry[i].tag);
502 unsigned long long size = table.entry[i].size;
503 int order = 0;
504 while(size >= 1024)
506 size /= 1024;
507 order++;
509 static const char *suffix[] = {"B", "KiB", "MiB", "GiB", "TiB"};
510 cprintf_field2(" Size: ", "%llu %s", size, suffix[order]);
511 cprintf(OFF, "\n");
514 for(int i = 0; i < table.header.count; i++)
516 union
518 uint8_t u8;
519 uint16_t u16;
520 uint32_t u32;
521 uint64_t u64;
522 uint8_t buf[52];
524 uint8_t drive = table.entry[i].drive_no;
525 cprintf_field(" Drive ", "%02x\n", drive);
527 int len = 4;
528 ret = stmp_get_logical_drive_info(drive, 0, &u.u32, &len);
529 if(!ret && len == 4)
531 u.u32 = fix_endian32be(u.u32);
532 cprintf_field(" Info 0: ", "%#x\n", u.u32);
535 len = 4;
536 ret = stmp_get_logical_drive_info(drive, 1, &u.u32, &len);
537 if(!ret && len == 4)
539 u.u32 = fix_endian32be(u.u32);
540 cprintf_field(" Info 1: ", "%#x\n", u.u32);
543 len = 8;
544 ret = stmp_get_logical_drive_info(drive, 2, &u.u64, &len);
545 if(!ret && len == 8)
547 u.u64 = fix_endian64be(u.u64);
548 cprintf_field(" Info 2: ", "%#llx\n", u.u64);
551 len = 4;
552 ret = stmp_get_logical_drive_info(drive, 3, &u.u32, &len);
553 if(!ret && len == 4)
555 u.u32 = fix_endian32be(u.u32);
556 cprintf_field(" Info 3: ", "%#x\n", u.u32);
559 len = 8;
560 ret = stmp_get_logical_drive_info(drive, 4, &u.u64, &len);
561 if(!ret && len == 8)
563 u.u64 = fix_endian64be(u.u64);
564 cprintf_field(" Info 4: ", "%#llx\n", u.u64);
567 len = 4;
568 ret = stmp_get_logical_drive_info(drive, 5, &u.u32, &len);
569 if(!ret && len == 4)
571 u.u32 = fix_endian32be(u.u32);
572 cprintf_field(" Info 5: ", "%#x\n", u.u32);
575 len = 1;
576 ret = stmp_get_logical_drive_info(drive, 6, &u.u8, &len);
577 if(!ret && len == 1)
579 cprintf_field(" Info 6: ", "%#x\n", u.u8);
582 len = 52;
583 ret = stmp_get_logical_drive_info(drive, 7, &u.buf, &len);
584 if(!ret && len != 0)
586 cprintf(GREEN, " Info 7:");
587 for(int i = 0; i < len; i++)
588 cprintf(YELLOW, " %02x", u.buf[i]);
589 printf("\n");
592 len = 52;
593 ret = stmp_get_logical_drive_info(drive, 8, &u.buf, &len);
594 if(!ret && len != 0)
596 cprintf(GREEN, " Info 8:");
597 for(int i = 0; i < len; i++)
598 cprintf(YELLOW, " %02x", u.buf[i]);
599 printf("\n");
602 len = 1;
603 ret = stmp_get_logical_drive_info(drive, 9, &u.u8, &len);
604 if(!ret && len == 1)
606 cprintf_field(" Info 9: ", "%#x\n", u.u8);
609 len = 2;
610 ret = stmp_get_logical_drive_info(drive, 10, &u.u16, &len);
611 if(!ret && len == 2)
613 u.u16 = fix_endian16be(u.u16);
614 cprintf_field(" Info 10: ", "%#x\n", u.u16);
617 len = 52;
618 ret = stmp_get_logical_drive_info(drive, 11, &u.buf, &len);
619 if(!ret && len != 0)
621 cprintf(GREEN, " Info 11:");
622 for(int i = 0; i < len; i++)
623 cprintf(YELLOW, " %02x", u.buf[i]);
624 printf("\n");
629 return 0;
632 static void usage(void)
634 printf("Usage: scsitool [options] <dev>\n");
635 printf("Options:\n");
636 printf(" -f/--force\tForce to continue on errors\n");
637 printf(" -?/--help\tDisplay this message\n");
638 printf(" -d/--debug\tDisplay debug messages\n");
639 printf(" -c/--no-color\tDisable color output\n");
640 exit(1);
643 int main(int argc, char **argv)
645 while(1)
647 static struct option long_options[] =
649 {"help", no_argument, 0, '?'},
650 {"debug", no_argument, 0, 'd'},
651 {"no-color", no_argument, 0, 'c'},
652 {"force", no_argument, 0, 'f'},
653 {0, 0, 0, 0}
656 int c = getopt_long(argc, argv, "?dcf", long_options, NULL);
657 if(c == -1)
658 break;
659 switch(c)
661 case -1:
662 break;
663 case 'c':
664 enable_color(false);
665 break;
666 case 'd':
667 g_debug = true;
668 break;
669 case 'f':
670 g_force = true;
671 break;
672 case '?':
673 usage();
674 break;
675 default:
676 abort();
680 if(argc - optind != 1)
682 usage();
683 return 1;
686 int ret = 0;
687 g_dev_fd = scsi_pt_open_device(argv[optind], false, true);
688 if(g_dev_fd < 0)
690 cprintf(GREY, "Cannot open device: %m\n");
691 ret = 1;
692 goto Lend;
695 do_work();
697 scsi_pt_close_device(g_dev_fd);
698 Lend:
699 color(OFF);
701 return ret;