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>
34 #include <scsi/scsi.h>
35 #include <scsi/sg_lib.h>
36 #include <scsi/sg_pt.h>
38 #include "stmp_scsi.h"
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)
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); }
52 #define errorf(...) do { cprintf(GREY, __VA_ARGS__); return __LINE__; } while(0)
55 void *buffer_alloc(int sz
)
58 unsigned psz
= getpagesize();
60 unsigned psz
= sysconf(_SC_PAGESIZE
); /* was getpagesize() */
62 void *buffer
= malloc(sz
+ psz
);
63 return (void *)(((ptrdiff_t)(buffer
+ psz
- 1)) & ~(psz
- 1));
66 void *buffer_alloc(int sz
)
72 static void print_hex(void *_buffer
, int buffer_size
)
74 uint8_t *buffer
= _buffer
;
75 for(int i
= 0; i
< buffer_size
; i
+= 16)
77 for(int j
= 0; j
< 16; j
++)
79 if(i
+ j
< buffer_size
)
80 cprintf(YELLOW
, " %02x", buffer
[i
+ j
]);
85 for(int j
= 0; j
< 16; j
++)
87 if(i
+ j
< buffer_size
)
88 cprintf(RED
, "%c", isprint(buffer
[i
+ j
]) ? buffer
[i
+ j
] : '.');
97 #define DO_READ (1 << 1)
99 #define DO_WRITE (1 << 2)
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
)
105 struct sg_pt_base
*obj
= construct_scsi_pt_obj();
108 cprintf(GREY
, "construct_scsi_pt_obj failed\n");
111 set_scsi_pt_cdb(obj
, cdb
, cdb_size
);
113 set_scsi_pt_sense(obj
, sense
, *sense_size
);
115 set_scsi_pt_data_in(obj
, buffer
, *buf_size
);
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
))
121 case SCSI_PT_RESULT_SENSE
:
122 case SCSI_PT_RESULT_GOOD
:
123 ret
= get_scsi_pt_status_response(obj
);
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
));
130 case SCSI_PT_RESULT_TRANSPORT_ERR
:
131 cprintf(GREY
, "Transport error: %s\n", get_scsi_pt_transport_err_str(obj
, 256, error
));
134 case SCSI_PT_RESULT_OS_ERR
:
135 cprintf(GREY
, "OS error: %s\n", get_scsi_pt_os_err_str(obj
, 256, error
));
139 cprintf(GREY
, "Unknown error\n");
144 *sense_size
= get_scsi_pt_sense_len(obj
);
145 if(flags
& (DO_WRITE
| DO_READ
))
146 *buf_size
-= get_scsi_pt_resid(obj
);
148 destruct_scsi_pt_obj(obj
);
152 int do_sense_analysis(int status
, uint8_t *sense
, int sense_size
)
154 if(status
!= GOOD
|| g_debug
)
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);
166 int stmp_inquiry(uint8_t *dev_type
, char vendor
[9], char product
[17])
168 unsigned char buffer
[56];
170 memset(cdb
, 0, sizeof(cdb
));
172 cdb
[4] = sizeof(buffer
);
175 int sense_size
= sizeof(sense
);
177 int buf_sz
= sizeof(buffer
);
178 int ret
= do_scsi(cdb
, sizeof(cdb
), DO_READ
, sense
, &sense_size
, buffer
, &buf_sz
);
181 ret
= do_sense_analysis(ret
, sense
, sense_size
);
184 if(buf_sz
!= sizeof(buffer
))
186 *dev_type
= buffer
[0];
187 memcpy(vendor
, buffer
+ 8, 8);
189 memcpy(product
, buffer
+ 16, 16);
194 static int stmp_get_protocol_version(struct scsi_stmp_protocol_version_t
*ver
)
197 memset(cdb
, 0, sizeof(cdb
));
198 cdb
[0] = SCSI_STMP_READ
;
199 cdb
[1] = SCSI_STMP_CMD_GET_PROTOCOL_VERSION
;
202 int sense_size
= sizeof(sense
);
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
);
208 ret
= do_sense_analysis(ret
, sense
, sense_size
);
211 if(buf_sz
!= sizeof(struct scsi_stmp_protocol_version_t
))
216 static int do_work(void)
218 cprintf(BLUE
, "Information\n");
223 int ret
= stmp_inquiry(&dev_type
, vendor
, product
);
225 errorf("Cannot get inquiry data: %d\n", ret
);
226 cprintf_field(" Vendor: ", "%s\n", vendor
);
227 cprintf_field(" Product: ", "%s\n", product
);
229 struct scsi_stmp_protocol_version_t ver
;
230 ret
= stmp_get_protocol_version(&ver
);
232 errorf("Cannot get protocol version: %d\n", ret
);
234 cprintf_field(" Protocol: ", "%x.%x\n", ver
.major
, ver
.minor
);
239 static void usage(void)
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");
250 int main(int argc
, char **argv
)
254 static struct option long_options
[] =
256 {"help", no_argument
, 0, '?'},
257 {"debug", no_argument
, 0, 'd'},
258 {"no-color", no_argument
, 0, 'c'},
259 {"force", no_argument
, 0, 'f'},
263 int c
= getopt_long(argc
, argv
, "?dcf", long_options
, NULL
);
287 if(argc
- optind
!= 1)
294 g_dev_fd
= scsi_pt_open_device(argv
[optind
], false, true);
297 cprintf(GREY
, "Cannot open device: %m\n");
304 scsi_pt_close_device(g_dev_fd
);