1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
30 #include <sys/types.h>
35 #include <scsi/scsi.h>
37 #include <scsi/sg_lib.h>
38 #include <scsi/sg_pt.h>
40 #include "stmp_scsi.h"
42 /* the windows port doesn't have scsi.h and GOOD */
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)
62 void *buffer_alloc(int sz
)
65 unsigned psz
= getpagesize();
67 unsigned psz
= sysconf(_SC_PAGESIZE
); /* was getpagesize() */
69 void *buffer
= malloc(sz
+ psz
);
70 return (void *)(((ptrdiff_t)(buffer
+ psz
- 1)) & ~(psz
- 1));
73 void *buffer_alloc(int sz
)
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
]);
104 cprintf(YELLOW
, " ");
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
] : '.');
119 #define DO_READ (1 << 1)
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
)
127 struct sg_pt_base
*obj
= construct_scsi_pt_obj();
130 cprintf(GREY
, "construct_scsi_pt_obj failed\n");
133 set_scsi_pt_cdb(obj
, cdb
, cdb_size
);
135 set_scsi_pt_sense(obj
, sense
, *sense_size
);
137 set_scsi_pt_data_in(obj
, buffer
, *buf_size
);
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
);
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
));
152 case SCSI_PT_RESULT_TRANSPORT_ERR
:
153 cprintf(GREY
, "Transport error: %s\n", get_scsi_pt_transport_err_str(obj
, 256, error
));
156 case SCSI_PT_RESULT_OS_ERR
:
157 cprintf(GREY
, "OS error: %s\n", get_scsi_pt_os_err_str(obj
, 256, error
));
161 cprintf(GREY
, "Unknown error\n");
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
);
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);
188 int stmp_inquiry(uint8_t *dev_type
, char vendor
[9], char product
[17])
190 unsigned char buffer
[36];
192 memset(cdb
, 0, sizeof(cdb
));
194 cdb
[4] = sizeof(buffer
);
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
);
203 ret
= do_sense_analysis(ret
, sense
, sense_size
);
206 if(buf_sz
!= sizeof(buffer
))
208 *dev_type
= buffer
[0];
209 memcpy(vendor
, buffer
+ 8, 8);
211 memcpy(product
, buffer
+ 16, 16);
216 static int stmp_get_protocol_version(struct scsi_stmp_protocol_version_t
*ver
)
219 memset(cdb
, 0, sizeof(cdb
));
220 cdb
[0] = SCSI_STMP_READ
;
221 cdb
[1] = SCSI_STMP_CMD_GET_PROTOCOL_VERSION
;
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
);
230 ret
= do_sense_analysis(ret
, sense
, sense_size
);
233 if(buf_sz
!= sizeof(struct scsi_stmp_protocol_version_t
))
238 static int stmp_get_chip_major_rev_id(struct scsi_stmp_chip_major_rev_id_t
*ver
)
241 memset(cdb
, 0, sizeof(cdb
));
242 cdb
[0] = SCSI_STMP_READ
;
243 cdb
[1] = SCSI_STMP_CMD_GET_CHIP_MAJOR_REV_ID
;
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
);
252 ret
= do_sense_analysis(ret
, sense
, sense_size
);
255 if(buf_sz
!= sizeof(struct scsi_stmp_chip_major_rev_id_t
))
257 ver
->rev
= fix_endian16be(ver
->rev
);
261 static int stmp_get_rom_rev_id(struct scsi_stmp_rom_rev_id_t
*ver
)
264 memset(cdb
, 0, sizeof(cdb
));
265 cdb
[0] = SCSI_STMP_READ
;
266 cdb
[1] = SCSI_STMP_CMD_GET_ROM_REV_ID
;
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
);
275 ret
= do_sense_analysis(ret
, sense
, sense_size
);
278 if(buf_sz
!= sizeof(struct scsi_stmp_rom_rev_id_t
))
280 ver
->rev
= fix_endian16be(ver
->rev
);
284 static int stmp_get_logical_media_info(uint8_t info
, void *data
, int *len
)
287 memset(cdb
, 0, sizeof(cdb
));
288 cdb
[0] = SCSI_STMP_READ
;
289 cdb
[1] = SCSI_STMP_CMD_GET_LOGICAL_MEDIA_INFO
;
293 int sense_size
= sizeof(sense
);
295 int ret
= do_scsi(cdb
, sizeof(cdb
), DO_READ
, sense
, &sense_size
, data
, len
);
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
)
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
;
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
);
317 ret
= do_sense_analysis(ret
, sense
, sense_size
);
320 if((buf_sz
- sizeof(struct scsi_stmp_logical_table_t
)) % sizeof(struct scsi_stmp_logical_table_entry_t
))
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
);
329 static int stmp_get_logical_drive_info(uint8_t drive
, uint8_t info
, void *data
, int *len
)
332 memset(cdb
, 0, sizeof(cdb
));
333 cdb
[0] = SCSI_STMP_READ
;
334 cdb
[1] = SCSI_STMP_CMD_GET_LOGICAL_DRIVE_INFO
;
339 int sense_size
= sizeof(sense
);
341 int ret
= do_scsi(cdb
, sizeof(cdb
), DO_READ
, sense
, &sense_size
, data
, len
);
344 return do_sense_analysis(ret
, sense
, sense_size
);
347 static int do_work(void)
349 cprintf(BLUE
, "Information\n");
354 int ret
= stmp_inquiry(&dev_type
, vendor
, product
);
357 cprintf(GREY
, "Cannot get inquiry data: %d\n", ret
);
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
);
368 cprintf(GREY
, "Cannot get protocol version: %d\n", ret
);
370 cprintf_field(" Protocol: ", "%x.%x\n", ver
.major
, ver
.minor
);
384 ret
= stmp_get_logical_media_info(0, &u
.u16
, &len
);
387 u
.u16
= fix_endian16be(u
.u16
);
388 cprintf_field(" Logical Media Info (0): ", "%#x\n", u
.u16
);
392 ret
= stmp_get_logical_media_info(6, &u
.u32
, &len
);
395 u
.u32
= fix_endian32be(u
.u32
);
396 cprintf_field(" Logical Media Info (6): ", "%#x\n", u
.u32
);
400 ret
= stmp_get_logical_media_info(5, &u
.u8
, &len
);
402 cprintf_field(" Logical Media Info (5): ", "%#x\n", u
.u8
);
405 ret
= stmp_get_logical_media_info(1, &u
.u64
, &len
);
408 u
.u64
= fix_endian64be(u
.u64
);
409 cprintf_field(" Logical Media Info (1): ", "%#llx\n", u
.u64
);
413 ret
= stmp_get_logical_media_info(7, &u
.u32
, &len
);
416 u
.u32
= fix_endian32be(u
.u32
);
417 cprintf_field(" Logical Media Info (7): ", "%#x\n", u
.u32
);
421 ret
= stmp_get_logical_media_info(8, &u
.buf
, &len
);
424 cprintf(GREEN
, " Logical Media Info (8):");
426 for(int i = 0; i < len; i++)
427 cprintf(YELLOW, " %02x", u.buf[i]);
430 print_hex(u
.buf
, len
);
434 ret
= stmp_get_logical_media_info(9, &u
.u8
, &len
);
436 cprintf_field(" Logical Media Info (9): ", "%#x\n", u
.u8
);
439 ret
= stmp_get_logical_media_info(12, &u
.u32
, &len
);
442 u
.u32
= fix_endian32be(u
.u32
);
443 cprintf_field(" Logical Media Info (12): ", "%#x\n", u
.u32
);
447 ret
= stmp_get_logical_media_info(13, &u
.u64
, &len
);
450 u
.u64
= fix_endian64be(u
.u64
);
451 cprintf_field(" Logical Media Info (13): ", "%#llx\n", u
.u64
);
455 ret
= stmp_get_logical_media_info(11, &u
.u32
, &len
);
458 u
.u32
= fix_endian32be(u
.u32
);
459 cprintf_field(" Logical Media Info (11): ", "%#x\n", u
.u32
);
463 ret
= stmp_get_logical_media_info(14, &u
.u32
, &len
);
466 u
.u32
= fix_endian32be(u
.u32
);
467 cprintf_field(" Logical Media Info (14): ", "%#x\n", u
.u32
);
471 struct scsi_stmp_chip_major_rev_id_t chip_rev
;
472 ret
= stmp_get_chip_major_rev_id(&chip_rev
);
474 cprintf(GREY
, "Cannot get chip major revision id: %d\n", ret
);
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
);
481 cprintf(GREY
, "Cannot get rom revision id: %d\n", ret
);
483 cprintf_field(" ROM Rev ID: ", "%x\n", rom_rev
.rev
);
487 struct scsi_stmp_logical_table_t header
;
488 struct scsi_stmp_logical_table_entry_t entry
[20];
491 ret
= stmp_get_logical_table(&table
.header
, sizeof(table
.entry
) / sizeof(table
.entry
[0]));
493 cprintf(GREY
, "Cannot get logical table: %d\n", ret
);
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
;
509 static const char *suffix
[] = {"B", "KiB", "MiB", "GiB", "TiB"};
510 cprintf_field2(" Size: ", "%llu %s", size
, suffix
[order
]);
514 for(int i
= 0; i
< table
.header
.count
; i
++)
524 uint8_t drive
= table
.entry
[i
].drive_no
;
525 cprintf_field(" Drive ", "%02x\n", drive
);
528 ret
= stmp_get_logical_drive_info(drive
, 0, &u
.u32
, &len
);
531 u
.u32
= fix_endian32be(u
.u32
);
532 cprintf_field(" Info 0: ", "%#x\n", u
.u32
);
536 ret
= stmp_get_logical_drive_info(drive
, 1, &u
.u32
, &len
);
539 u
.u32
= fix_endian32be(u
.u32
);
540 cprintf_field(" Info 1: ", "%#x\n", u
.u32
);
544 ret
= stmp_get_logical_drive_info(drive
, 2, &u
.u64
, &len
);
547 u
.u64
= fix_endian64be(u
.u64
);
548 cprintf_field(" Info 2: ", "%#llx\n", u
.u64
);
552 ret
= stmp_get_logical_drive_info(drive
, 3, &u
.u32
, &len
);
555 u
.u32
= fix_endian32be(u
.u32
);
556 cprintf_field(" Info 3: ", "%#x\n", u
.u32
);
560 ret
= stmp_get_logical_drive_info(drive
, 4, &u
.u64
, &len
);
563 u
.u64
= fix_endian64be(u
.u64
);
564 cprintf_field(" Info 4: ", "%#llx\n", u
.u64
);
568 ret
= stmp_get_logical_drive_info(drive
, 5, &u
.u32
, &len
);
571 u
.u32
= fix_endian32be(u
.u32
);
572 cprintf_field(" Info 5: ", "%#x\n", u
.u32
);
576 ret
= stmp_get_logical_drive_info(drive
, 6, &u
.u8
, &len
);
579 cprintf_field(" Info 6: ", "%#x\n", u
.u8
);
583 ret
= stmp_get_logical_drive_info(drive
, 7, &u
.buf
, &len
);
586 cprintf(GREEN
, " Info 7:");
587 for(int i
= 0; i
< len
; i
++)
588 cprintf(YELLOW
, " %02x", u
.buf
[i
]);
593 ret
= stmp_get_logical_drive_info(drive
, 8, &u
.buf
, &len
);
596 cprintf(GREEN
, " Info 8:");
597 for(int i
= 0; i
< len
; i
++)
598 cprintf(YELLOW
, " %02x", u
.buf
[i
]);
603 ret
= stmp_get_logical_drive_info(drive
, 9, &u
.u8
, &len
);
606 cprintf_field(" Info 9: ", "%#x\n", u
.u8
);
610 ret
= stmp_get_logical_drive_info(drive
, 10, &u
.u16
, &len
);
613 u
.u16
= fix_endian16be(u
.u16
);
614 cprintf_field(" Info 10: ", "%#x\n", u
.u16
);
618 ret
= stmp_get_logical_drive_info(drive
, 11, &u
.buf
, &len
);
621 cprintf(GREEN
, " Info 11:");
622 for(int i
= 0; i
< len
; i
++)
623 cprintf(YELLOW
, " %02x", u
.buf
[i
]);
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");
643 int main(int argc
, char **argv
)
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'},
656 int c
= getopt_long(argc
, argv
, "?dcf", long_options
, NULL
);
680 if(argc
- optind
!= 1)
687 g_dev_fd
= scsi_pt_open_device(argv
[optind
], false, true);
690 cprintf(GREY
, "Cannot open device: %m\n");
697 scsi_pt_close_device(g_dev_fd
);