26
static char * version_str = "0.27 20040822";
24
static char * version_str = "1.16 20060623";
28
26
#define ME "sg_modes: "
30
#define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
31
#define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */
33
#define MODE_SENSE6_CMD 0x1a
34
#define MODE_SENSE6_CMDLEN 6
35
#define MODE_SENSE10_CMD 0x5a
36
#define MODE_SENSE10_CMDLEN 10
37
#define INQUIRY_CMD 0x12
38
#define INQUIRY_CMDLEN 6
39
#define INQUIRY_RESPLEN 36
40
28
#define MX_ALLOC_LEN (1024 * 4)
42
29
#define PG_CODE_ALL 0x3f
43
30
#define PG_CODE_MASK 0x3f
44
31
#define PG_CODE_MAX 0x3f
45
32
#define SPG_CODE_ALL 0xff
33
#define PROTO_SPECIFIC_1 0x18
34
#define PROTO_SPECIFIC_2 0x19
47
36
#define EBUFF_SZ 256
50
struct simple_inquiry_t {
51
unsigned char peripheral_qualifier;
52
unsigned char peripheral_type;
54
unsigned char version; /* as per recent drafts: whole of byte 2 */
64
/* Returns 0 when successful, else -1 */
65
static int do_simple_inq(int sg_fd, int noisy,
66
struct simple_inquiry_t * inq_data, int verbose)
69
unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0};
70
unsigned char sense_b[SENSE_BUFF_LEN];
71
struct sg_io_hdr io_hdr;
72
unsigned char inq_resp[INQUIRY_RESPLEN];
75
memset(inq_data, 0, sizeof(* inq_data));
76
inq_data->peripheral_qualifier = 0x3;
77
inq_data->peripheral_type = 0x1f;
79
inqCmdBlk[4] = (unsigned char)sizeof(inq_resp);
81
fprintf(stderr, " inquiry cdb: ");
82
for (k = 0; k < INQUIRY_CMDLEN; ++k)
83
fprintf(stderr, "%02x ", inqCmdBlk[k]);
84
fprintf(stderr, "\n");
86
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
87
io_hdr.interface_id = 'S';
88
io_hdr.cmd_len = sizeof(inqCmdBlk);
89
io_hdr.mx_sb_len = sizeof(sense_b);
90
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
91
io_hdr.dxfer_len = sizeof(inq_resp);
92
io_hdr.dxferp = inq_resp;
93
io_hdr.cmdp = inqCmdBlk;
95
io_hdr.timeout = DEF_TIMEOUT;
97
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
98
perror("SG_IO (inquiry) error");
101
res = sg_err_category3(&io_hdr);
103
case SG_ERR_CAT_CLEAN:
104
case SG_ERR_CAT_RECOVERED:
106
inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7;
107
inq_data->peripheral_type = inq_resp[0] & 0x1f;
108
inq_data->rmb = (inq_resp[1] & 0x80) ? 1 : 0;
109
inq_data->version = inq_resp[2];
110
inq_data->byte_3 = inq_resp[3];
111
inq_data->byte_5 = inq_resp[5];
112
inq_data->byte_6 = inq_resp[6];
113
inq_data->byte_7 = inq_resp[7];
114
memcpy(inq_data->vendor, inq_resp + 8, 8);
115
memcpy(inq_data->product, inq_resp + 16, 16);
116
memcpy(inq_data->revision, inq_resp + 32, 4);
121
char ebuff[EBUFF_SZ];
122
snprintf(ebuff, EBUFF_SZ, "Inquiry error ");
123
sg_chk_n_print3(ebuff, &io_hdr);
129
static int do_modes(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
130
void * resp, int mx_resp_len, int noisy, int mode6,
134
unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] =
135
{MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0};
136
unsigned char sense_b[SENSE_BUFF_LEN];
137
struct sg_io_hdr io_hdr;
140
cmd_len = mode6 ? MODE_SENSE6_CMDLEN : MODE_SENSE10_CMDLEN;
141
modesCmdBlk[1] = (unsigned char)(dbd ? 0x8 : 0);
142
modesCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) |
143
(pg_code & PG_CODE_MASK));
144
modesCmdBlk[3] = (unsigned char)(sub_pg_code & 0xff);
145
if (mx_resp_len > (mode6 ? 0xff : 0xffff)) {
146
printf( ME "mx_resp_len too big\n");
150
modesCmdBlk[0] = MODE_SENSE6_CMD;
151
modesCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff);
153
modesCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
154
modesCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff);
157
fprintf(stderr, " mode sense cdb: ");
158
for (k = 0; k < cmd_len; ++k)
159
fprintf(stderr, "%02x ", modesCmdBlk[k]);
160
fprintf(stderr, "\n");
163
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
164
memset(sense_b, 0, sizeof(sense_b));
165
io_hdr.interface_id = 'S';
166
io_hdr.cmd_len = cmd_len;
167
io_hdr.mx_sb_len = sizeof(sense_b);
168
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
169
io_hdr.dxfer_len = mx_resp_len;
170
io_hdr.dxferp = resp;
171
io_hdr.cmdp = modesCmdBlk;
172
io_hdr.sbp = sense_b;
173
io_hdr.timeout = DEF_TIMEOUT;
175
if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
176
perror("SG_IO (mode sense) error");
179
res = sg_err_category3(&io_hdr);
181
case SG_ERR_CAT_CLEAN:
182
case SG_ERR_CAT_RECOVERED:
186
char ebuff[EBUFF_SZ];
187
struct sg_scsi_sense_hdr ssh;
190
snprintf(ebuff, EBUFF_SZ, "Mode sense error, dbd=%d "
191
"pc=%d page_code=%x sub_page_code=%x\n ", dbd,
192
pc, pg_code, sub_pg_code);
193
sg_chk_n_print3(ebuff, &io_hdr);
195
if (sg_normalize_sense(&io_hdr, &ssh)) {
196
if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) {
198
fprintf(stderr, ">>>>>> try again without the '-6' "
199
"switch for a 10 byte MODE SENSE command\n");
201
fprintf(stderr, ">>>>>> try again with a '-6' "
202
"switch for a 6 byte MODE SENSE command\n");
210
const char * scsi_ptype_strs[] = {
215
"write once optical disk",
218
"optical memory device",
223
"storage array controller",
224
"enclosure services device",
225
"simplified direct access device",
226
"optical card reader/writer device",
229
const char * get_ptype_str(int scsi_ptype)
231
int num = sizeof(scsi_ptype_strs) / sizeof(scsi_ptype_strs[0]);
233
return (scsi_ptype < num) ? scsi_ptype_strs[scsi_ptype] : "";
39
static const char * transport_proto_arr[] =
41
"Fibre Channel (FCP-2)",
42
"Parallel SCSI (SPI-4)",
45
"Remote Direct Memory Access (SRP)",
46
"Internet SCSI (iSCSI)",
47
"Serial Attached SCSI (SAS)",
48
"Automation/Drive Interface (ADT)",
49
"ATA Packet Interface (ATA/ATAPI-7)",
50
"Ox9", "Oxa", "Oxb", "Oxc", "Oxd", "Oxe",
51
"No specific protocol"
236
54
struct page_code_desc {
239
57
const char * desc;
242
static struct page_code_desc pc_desc_all[] = {
243
{0x0, 0x0, "Unit Attention condition [vendor: page format not required]"},
60
static struct page_code_desc pc_desc_common[] = {
61
{0x0, 0x0, "Unit Attention condition [vendor specific format]"},
244
62
{0x2, 0x0, "Disconnect-Reconnect"},
63
{0x9, 0x0, "Peripheral device (obsolete)"},
245
64
{0xa, 0x0, "Control"},
246
65
{0xa, 0x1, "Control extension"},
247
66
{0x15, 0x0, "Extended"},
248
67
{0x16, 0x0, "Extended device-type specific"},
249
{0x18, 0x0, "Protocol specific LUN"},
68
{0x18, 0x0, "Protocol specific lu"},
250
69
{0x19, 0x0, "Protocol specific port"},
251
70
{0x1a, 0x0, "Power condition"},
252
71
{0x1c, 0x0, "Informational exceptions control"},
253
72
{PG_CODE_ALL, 0x0, "[yields all supported pages]"},
73
{PG_CODE_ALL, SPG_CODE_ALL, "[yields all supported pages and subpages]"},
256
76
static struct page_code_desc pc_desc_disk[] = {
257
77
{0x1, 0x0, "Read-Write error recovery"},
258
{0x3, 0x0, "Format"},
259
{0x4, 0x0, "Rigid disk geometry"},
260
{0x5, 0x0, "Flexible geometry"},
78
{0x3, 0x0, "Format (obsolete)"},
79
{0x4, 0x0, "Rigid disk geometry (obsolete)"},
80
{0x5, 0x0, "Flexible geometry (obsolete)"},
261
81
{0x7, 0x0, "Verify error recovery"},
262
82
{0x8, 0x0, "Caching"},
263
{0x9, 0x0, "Peripheral device (spc-2 ?)"},
264
{0xb, 0x0, "Medium types supported"},
265
{0xc, 0x0, "Notch and partition"},
266
{0xd, 0x0, "Power condition (obsolete)"},
83
{0xa, 0xf1, "Parallel ATA control (SAT)"},
84
{0xa, 0xf2, "Reserved (SATA control) (SAT)"},
85
{0xb, 0x0, "Medium types supported (obsolete)"},
86
{0xc, 0x0, "Notch and partition (obsolete)"},
87
{0xd, 0x0, "Power condition (obsolete, moved to 0x1a)"},
267
88
{0x10, 0x0, "XOR control"},
89
{0x1c, 0x1, "Background control"},
270
92
static struct page_code_desc pc_desc_tape[] = {
271
93
{0xf, 0x0, "Data Compression"},
272
{0x10, 0x0, "Device config"},
94
{0x10, 0x0, "Device configuration"},
95
{0x10, 0x1, "Device configuration extension"},
273
96
{0x11, 0x0, "Medium Partition [1]"},
274
97
{0x12, 0x0, "Medium Partition [2]"},
275
98
{0x13, 0x0, "Medium Partition [3]"},
276
99
{0x14, 0x0, "Medium Partition [4]"},
277
100
{0x1c, 0x0, "Informational exceptions control (tape version)"},
101
{0x1d, 0x0, "Medium configuration"},
280
104
static struct page_code_desc pc_desc_cddvd[] = {
331
171
case 0xd: /* enclosure services devices */
332
172
*size = sizeof(pc_desc_ses) / sizeof(pc_desc_ses[0]);
333
173
return &pc_desc_ses[0];
339
const char * find_page_code_desc(int page_num, int subpage_num,
174
case 0xe: /* simplified direct access device */
175
*size = sizeof(pc_desc_rbc) / sizeof(pc_desc_rbc[0]);
176
return &pc_desc_rbc[0];
177
case 0x12: /* automation device/interface */
178
*size = sizeof(pc_desc_adt) / sizeof(pc_desc_adt[0]);
179
return &pc_desc_adt[0];
185
static struct page_code_desc pc_desc_t_fcp[] = {
186
{0x18, 0x0, "LU control"},
187
{0x19, 0x0, "Port control"},
190
static struct page_code_desc pc_desc_t_spi4[] = {
191
{0x18, 0x0, "LU control"},
192
{0x19, 0x0, "Port control short format"},
193
{0x19, 0x1, "Margin control"},
194
{0x19, 0x2, "Saved training configuration value"},
195
{0x19, 0x3, "Negotiated settings"},
196
{0x19, 0x4, "Report transfer capabilities"},
199
static struct page_code_desc pc_desc_t_sas[] = {
200
{0x18, 0x0, "LU SSP, short format"},
201
{0x19, 0x0, "Port SSP, short format"},
202
{0x19, 0x1, "Port SSP, phy control and discover"},
203
{0x19, 0x2, "Port SSP, shared"},
206
static struct page_code_desc pc_desc_t_adt[] = {
207
{0xe, 0x1, "Target device"},
208
{0xe, 0x2, "DT device primary port"},
209
{0xe, 0x3, "Logical unit"},
210
{0x18, 0x0, "Protocol specific lu"},
211
{0x19, 0x0, "Protocol specific port"},
214
static struct page_code_desc * mode_page_transp_table(int t_proto,
219
case 0: /* Fibre channel */
220
*size = sizeof(pc_desc_t_fcp) / sizeof(pc_desc_t_fcp[0]);
221
return &pc_desc_t_fcp[0];
223
*size = sizeof(pc_desc_t_spi4) / sizeof(pc_desc_t_spi4[0]);
224
return &pc_desc_t_spi4[0];
225
case 6: /* SAS-1.1 */
226
*size = sizeof(pc_desc_t_sas) / sizeof(pc_desc_t_sas[0]);
227
return &pc_desc_t_sas[0];
228
case 7: /* ADT/ADC */
229
*size = sizeof(pc_desc_t_adt) / sizeof(pc_desc_t_adt[0]);
230
return &pc_desc_t_adt[0];
236
static const char * find_page_code_desc(int page_num, int subpage_num,
237
int scsi_ptype, int inq_byte6,
344
242
const struct page_code_desc * pcdp;
346
pcdp = find_mode_page_table(scsi_ptype, &num);
245
pcdp = mode_page_transp_table(t_proto, &num);
247
for (k = 0; k < num; ++k, ++pcdp) {
248
if ((page_num == pcdp->page_code) &&
249
(subpage_num == pcdp->subpage_code))
251
else if (page_num < pcdp->page_code)
256
pcdp = mode_page_cs_table(scsi_ptype, &num);
348
258
for (k = 0; k < num; ++k, ++pcdp) {
349
259
if ((page_num == pcdp->page_code) &&
368
static void list_page_codes(int scsi_ptype)
371
int num = sizeof(pc_desc_all) / sizeof(pc_desc_all[0]);
372
const struct page_code_desc * pcdp = &pc_desc_all[0];
374
const struct page_code_desc * pcd_ptypep;
376
pcd_ptypep = find_mode_page_table(scsi_ptype, &num_ptype);
377
printf("Page_Code Description\n");
378
for (k = 0; k <= PG_CODE_MAX; ++k) {
379
if (pcd_ptypep && (num_ptype > 0)) {
380
if (k == pcd_ptypep->page_code) {
381
printf(" 0x%02x %s\n", pcd_ptypep->page_code,
386
} else if (k > pcd_ptypep->page_code) {
391
if (pcdp && (num > 0)) {
392
if (k == pcdp->page_code) {
393
printf(" 0x%02x %s\n", pcdp->page_code, pcdp->desc);
397
} else if (k > pcdp->page_code) {
303
static void list_page_codes(int scsi_ptype, int inq_byte6, int t_proto)
305
int num, num_ptype, pg, spg, c, d, valid_transport;
306
const struct page_code_desc * dp;
307
const struct page_code_desc * pe_dp;
309
valid_transport = ((t_proto >= 0) && (t_proto <= 0xf)) ? 1 : 0;
310
printf("Page[,subpage] Name\n");
311
printf("=====================\n");
312
dp = mode_page_cs_table(-1, &num);
313
pe_dp = mode_page_cs_table(scsi_ptype, &num_ptype);
315
pg = dp ? dp->page_code : PG_CODE_ALL + 1;
316
spg = dp ? dp->subpage_code : SPG_CODE_ALL;
318
pg = pe_dp ? pe_dp->page_code : PG_CODE_ALL + 1;
319
spg = pe_dp ? pe_dp->subpage_code : SPG_CODE_ALL;
321
if (valid_transport &&
322
((PROTO_SPECIFIC_1 == c) || (PROTO_SPECIFIC_2 == c)))
323
dp = (--num <= 0) ? NULL : (dp + 1); /* skip protocol specific */
325
if (pe_dp->subpage_code)
326
printf(" 0x%02x,0x%02x * %s\n", pe_dp->page_code,
327
pe_dp->subpage_code, pe_dp->desc);
329
printf(" 0x%02x * %s\n", pe_dp->page_code,
331
dp = (--num <= 0) ? NULL : (dp + 1);
332
pe_dp = (--num_ptype <= 0) ? NULL : (pe_dp + 1);
334
if (dp->subpage_code)
335
printf(" 0x%02x,0x%02x %s\n", dp->page_code,
336
dp->subpage_code, dp->desc);
338
printf(" 0x%02x %s\n", dp->page_code,
340
dp = (--num <= 0) ? NULL : (dp + 1);
342
if (pe_dp->subpage_code)
343
printf(" 0x%02x,0x%02x %s\n", pe_dp->page_code,
344
pe_dp->subpage_code, pe_dp->desc);
346
printf(" 0x%02x %s\n", pe_dp->page_code,
348
pe_dp = (--num_ptype <= 0) ? NULL : (pe_dp + 1);
350
if ((NULL == dp) && (NULL == pe_dp))
353
if ((0xd != scsi_ptype) && (inq_byte6 & 0x40)) {
354
/* check for attached enclosure services processor */
355
printf("\n Attached enclosure services processor\n");
356
dp = mode_page_cs_table(0xd, &num);
358
if (dp->subpage_code)
359
printf(" 0x%02x,0x%02x %s\n", dp->page_code,
360
dp->subpage_code, dp->desc);
362
printf(" 0x%02x %s\n", dp->page_code,
364
dp = (--num <= 0) ? NULL : (dp + 1);
367
if ((0x8 != scsi_ptype) && (inq_byte6 & 0x8)) {
368
/* check for attached medium changer device */
369
printf("\n Attached medium changer device\n");
370
dp = mode_page_cs_table(0x8, &num);
372
if (dp->subpage_code)
373
printf(" 0x%02x,0x%02x %s\n", dp->page_code,
374
dp->subpage_code, dp->desc);
376
printf(" 0x%02x %s\n", dp->page_code,
378
dp = (--num <= 0) ? NULL : (dp + 1);
381
if (valid_transport) {
382
printf("\n Transport protocol: %s\n",
383
transport_proto_arr[t_proto]);
384
dp = mode_page_transp_table(t_proto, &num);
386
if (dp->subpage_code)
387
printf(" 0x%02x,0x%02x %s\n", dp->page_code,
388
dp->subpage_code, dp->desc);
390
printf(" 0x%02x %s\n", dp->page_code,
392
dp = (--num <= 0) ? NULL : (dp + 1);
397
static int examine_pages(int sg_fd, int do_mode6, int inq_pdt, int inq_byte6,
401
unsigned char rbuf[4];
404
for (header = 0, k = 0; k < 0x3f; ++k) {
406
res = sg_ll_mode_sense6(sg_fd, 0, 0, k, 0,
407
rbuf, sizeof(rbuf), 0, verbose);
408
if (SG_LIB_CAT_INVALID_OP == res) {
409
fprintf(stderr, ">>>>>> try again without the '-6' "
410
"switch for a 10 byte MODE SENSE command\n");
414
res = sg_ll_mode_sense10(sg_fd, 0, 0, 0, k,
415
0, rbuf, sizeof(rbuf), 1, verbose);
416
if (SG_LIB_CAT_INVALID_OP == res) {
417
fprintf(stderr, ">>>>>> try again with a '-6' "
418
"switch for a 6 byte MODE SENSE command\n");
424
printf("Discovered mode pages:\n");
427
cp = find_page_code_desc(k, 0, inq_pdt, inq_byte6, -1);
431
printf(" [0x%x]\n", k);
432
} else if (SG_LIB_CAT_NOT_READY == res)
433
fprintf(stderr, "MODE SENSE failed, device not ready\n");
405
438
static const char * pg_control_str_arr[] = {
411
445
static void usage()
413
printf("Usage: 'sg_modes [-a] [-c=<page_control] [-d] [-h] [-l] "
414
"[-p=<page_number>]\n\t\t [-subp=<sub_page_code>] [-v] [-V] "
415
"[-6] [<sg_device>]'\n"
416
" where -a get all mode pages\n"
447
printf("Usage: sg_modes [-a] [-A] [-c=<page_control] [-d] [-D] [-f] "
448
"[-e] [-h] [-H]\n\t\t"
449
" [-l] [-L] [-p=<page_number>[,<sub_page_code>]] [-r]"
450
"\n\t\t [-subp=<sub_page_code>] [-v] [-V] [-6] [<scsi_device>]\n"
451
" where -a get all mode pages supported by device\n"
452
" -A get all mode pages and subpages supported by device\n"
417
453
" -c=<page_control> page control (def: 0 [current],"
418
454
" 1 [changeable],\n 2 [default], 3 [saved])\n"
419
" -d disable block descriptors\n"
420
" -h output in hex\n"
421
" -l list common page codes\n"
422
" -p=<page_code> page code (in hex, def: 0)\n"
455
" -d disable block descriptors (DBD field in cdb)\n"
456
" -e examine pages # 0 through to 0x3e, note if found\n"
457
" -D disable block descriptor output\n"
458
" -f be flexible, cope with MODE SENSE 6/10 response "
460
printf(" -h output page number and header in hex\n"
461
" -H output page number and header in hex (same as '-h')\n"
462
" -l list common page codes for device peripheral type,\n"
463
" if no device given then assume disk type\n"
464
" -L set Long LBA Accepted (LLBAA field in mode sense "
466
" -p=<page_code> page code in hex (def: 0)\n"
467
" -p=<page_code>,<sub_page_code> both in hex, (defs: 0)\n"
468
" -r mode page output to stdout, a byte per line in "
423
470
" -subp=<sub_page_code> (in hex, def: 0)\n"
425
472
" -V output version string\n"
426
" -6 Use MODE SENSE(6) instead of MODE SENSE(10)\n"
427
" -? output this usage message\n");
473
" -6 Use MODE SENSE(6), by default uses MODE SENSE(10)\n"
474
" -? output this usage message\n\n"
475
"Performs a SCSI MODE SENSE commmand\n");
431
479
int main(int argc, char * argv[])
433
int sg_fd, k, num, len, md_len, bd_len, longlba, page_num, spf;
434
char * file_name = 0;
481
int sg_fd, k, num, len, res, md_len, bd_len, longlba, page_num, spf;
482
const char * file_name = 0;
435
483
char ebuff[EBUFF_SZ];
436
484
const char * descp;
437
486
unsigned char rsp_buff[MX_ALLOC_LEN];
438
487
int rsp_buff_size = MX_ALLOC_LEN;
440
489
int pg_code = -1;
441
490
int sub_pg_code = 0;
491
int sub_pg_code_set = 0;
446
501
int do_mode6 = 0; /* Use MODE SENSE(6) instead of MODE SENSE(10) */
448
504
int do_verbose = 0;
449
int oflags = O_RDONLY | O_NONBLOCK;
450
int density_code_off;
506
int density_code_off, t_proto, inq_pdt, inq_byte6, resp_mode6;
507
int num_ua_pages, plen, jmp_out;
451
508
unsigned char * ucp;
452
509
unsigned char uc;
453
struct simple_inquiry_t inq_out;
510
struct sg_simple_inquiry_resp inq_out;
455
513
for (k = 1; k < argc; ++k) {
456
if (0 == strncmp("-p=", argv[k], 3)) {
457
num = sscanf(argv[k] + 3, "%x", &u);
458
if ((1 != num) || (u > 63)) {
459
printf("Bad page code after '-p' switch\n");
465
else if (0 == strncmp("-subp=", argv[k], 6)) {
466
num = sscanf(argv[k] + 6, "%x", &u);
467
if ((1 != num) || (u > 255)) {
468
printf("Bad sub page code after '-subp' switch\n");
476
else if (0 == strncmp("-c=", argv[k], 3)) {
477
num = sscanf(argv[k] + 3, "%x", &u);
478
if ((1 != num) || (u > 3)) {
479
printf("Bad page control after '-c' switch\n");
485
else if (0 == strcmp("-d", argv[k]))
487
else if (0 == strcmp("-a", argv[k]))
489
else if (0 == strcmp("-h", argv[k]))
491
else if (0 == strcmp("-6", argv[k]))
493
else if (0 == strcmp("-l", argv[k]))
495
else if (0 == strcmp("-v", argv[k]))
497
else if (0 == strcmp("-?", argv[k])) {
501
else if (0 == strcmp("-V", argv[k])) {
502
printf("Version string: %s\n", version_str);
505
else if (*argv[k] == '-') {
506
printf("Unrecognized switch: %s\n", argv[k]);
510
else if (0 == file_name)
519
for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) {
560
fprintf(stderr, "Version string: %s\n", version_str);
574
if (0 == strncmp("c=", cp, 2)) {
575
num = sscanf(cp + 2, "%x", &u);
576
if ((1 != num) || (u > 3)) {
577
fprintf(stderr, "Bad page control after 'c=' option\n");
579
return SG_LIB_SYNTAX_ERROR;
582
} else if (0 == strncmp("p=", cp, 2)) {
583
if (NULL == strchr(cp + 2, ',')) {
584
num = sscanf(cp + 2, "%x", &u);
585
if ((1 != num) || (u > 63)) {
586
fprintf(stderr, "Bad page code value after 'p=' "
589
return SG_LIB_SYNTAX_ERROR;
592
} else if (2 == sscanf(cp + 2, "%x,%x", &u, &uu)) {
594
fprintf(stderr, "Bad sub page code value after 'p=' "
597
return SG_LIB_SYNTAX_ERROR;
603
fprintf(stderr, "Bad page code, subpage code sequence "
604
"after 'p=' option\n");
606
return SG_LIB_SYNTAX_ERROR;
608
} else if (0 == strncmp("subp=", cp, 5)) {
609
num = sscanf(cp + 5, "%x", &u);
610
if ((1 != num) || (u > 255)) {
611
fprintf(stderr, "Bad sub page code after 'subp=' "
614
return SG_LIB_SYNTAX_ERROR;
620
} else if (jmp_out) {
621
fprintf(stderr, "Unrecognized option: %s\n", cp);
623
return SG_LIB_SYNTAX_ERROR;
625
} else if (0 == file_name)
513
printf("too many arguments\n");
628
fprintf(stderr, "too many arguments, got: %s, not expecting: "
629
"%s\n", file_name, cp);
631
return SG_LIB_SYNTAX_ERROR;
518
635
if (0 == file_name) {
520
printf("Assume 'disk' device type\n");
637
if ((pg_code < 0) || (pg_code > 0x1f)) {
638
printf(" Assume peripheral device type: disk\n");
639
list_page_codes(0, 0, -1);
641
printf(" peripheral device type: %s\n",
642
sg_get_pdt_str(pg_code, sizeof(pdt_name), pdt_name));
644
list_page_codes(pg_code, 0, sub_pg_code);
646
list_page_codes(pg_code, 0, -1);
650
fprintf(stderr, "No <scsi_device> argument given\n");
652
return SG_LIB_SYNTAX_ERROR;
655
if (do_examine && (pg_code >= 0)) {
656
fprintf(stderr, "can't give '-e' and a page number\n");
657
return SG_LIB_SYNTAX_ERROR;
528
660
/* The 6 bytes command only allows up to 252 bytes of response data */
663
fprintf(stderr, "LLBAA not defined for MODE SENSE 6, try "
665
return SG_LIB_SYNTAX_ERROR;
530
667
rsp_buff_size = 252;
531
669
/* If no pages or list selected than treat as 'a' */
532
if (! ((pg_code >= 0) || do_all || do_list))
670
if (! ((pg_code >= 0) || do_all || do_list || do_examine))
535
if ((sg_fd = open(file_name, oflags)) < 0) {
536
snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s", file_name);
541
if (do_simple_inq(sg_fd, 1, &inq_out, do_verbose)) {
542
printf(ME "%s doesn't respond to a SCSI INQUIRY\n", file_name);
546
printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n",
547
inq_out.vendor, inq_out.product, inq_out.revision,
548
get_ptype_str(inq_out.peripheral_type), inq_out.peripheral_type);
673
if ((sg_fd = sg_cmds_open_device(file_name, 1 /* ro */, do_verbose)) < 0) {
674
fprintf(stderr, ME "error opening file: %s: %s\n", file_name,
675
safe_strerror(-sg_fd));
676
return SG_LIB_FILE_ERROR;
679
if (sg_simple_inquiry(sg_fd, &inq_out, 1, do_verbose)) {
680
fprintf(stderr, ME "%s doesn't respond to a SCSI INQUIRY\n",
682
sg_cmds_close_device(sg_fd);
683
return SG_LIB_CAT_OTHER;
685
inq_pdt = inq_out.peripheral_type;
686
inq_byte6 = inq_out.byte_6;
688
printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n",
689
inq_out.vendor, inq_out.product, inq_out.revision,
690
sg_get_pdt_str(inq_pdt, sizeof(pdt_name), pdt_name), inq_pdt);
551
list_page_codes(inq_out.peripheral_type);
693
list_page_codes(inq_pdt, inq_byte6, sub_pg_code);
695
list_page_codes(inq_pdt, inq_byte6, -1);
699
ret = examine_pages(sg_fd, do_mode6, inq_pdt, inq_byte6, do_verbose);
554
702
if (PG_CODE_ALL == pg_code)
557
705
pg_code = PG_CODE_ALL;
559
if (0 == do_modes(sg_fd, do_dbd, pc, pg_code, sub_pg_code,
560
rsp_buff, rsp_buff_size, 1, do_mode6, do_verbose)) {
706
if (do_all && do_all_sub)
707
sub_pg_code = SPG_CODE_ALL;
711
fprintf(stderr, "'-r' requires a given (sub)page (not all)\n");
713
return SG_LIB_SYNTAX_ERROR;
716
fprintf(stderr, "'-r' and '-h' clash");
718
return SG_LIB_SYNTAX_ERROR;
722
memset(rsp_buff, 0, sizeof(rsp_buff));
724
res = sg_ll_mode_sense6(sg_fd, do_dbd, pc, pg_code, sub_pg_code,
725
rsp_buff, rsp_buff_size, 1, do_verbose);
726
if (SG_LIB_CAT_INVALID_OP == res)
727
fprintf(stderr, ">>>>>> try again without the '-6' "
728
"switch for a 10 byte MODE SENSE command\n");
729
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
730
fprintf(stderr, "invalid field in cdb (perhaps subpages "
731
"or page control (PC) not supported)\n");
733
res = sg_ll_mode_sense10(sg_fd, do_llbaa, do_dbd, pc, pg_code,
734
sub_pg_code, rsp_buff, rsp_buff_size, 1,
736
if (SG_LIB_CAT_INVALID_OP == res)
737
fprintf(stderr, ">>>>>> try again with a '-6' "
738
"switch for a 6 byte MODE SENSE command\n");
739
else if (SG_LIB_CAT_ILLEGAL_REQ == res)
740
fprintf(stderr, "invalid field in cdb (perhaps subpages "
741
"or page control (PC) not supported)\n");
743
if (SG_LIB_CAT_ILLEGAL_REQ == res)
744
fprintf(stderr, "invalid field in cdb (perhaps subpages "
745
"or page control (PC) not supported)\n");
746
else if (SG_LIB_CAT_NOT_READY == res)
747
fprintf(stderr, "device not ready\n");
748
else if (SG_LIB_CAT_UNIT_ATTENTION == res)
749
fprintf(stderr, "unit attention\n");
561
752
int medium_type, specific, headerlen;
563
printf("Mode parameter header from %s byte MODE SENSE:\n",
564
(do_mode6 ? "6" : "10"));
755
resp_mode6 = do_mode6;
758
if (do_mode6 && (num < 3))
760
if ((0 == do_mode6) && (num > 5)) {
761
if ((num > 11) && (0 == (num % 2)) && (0 == rsp_buff[4]) &&
762
(0 == rsp_buff[5]) && (0 == rsp_buff[6])) {
765
fprintf(stderr, ">>> msense(10) but resp[0]=%d and "
766
"not msense(6) response so fix length\n", num);
772
if (resp_mode6 == do_mode6)
773
printf("Mode parameter header from %s byte MODE SENSE:\n",
774
(do_mode6 ? "6" : "10"));
776
printf(" >>> Mode parameter header from %s byte MODE "
777
"SENSE,\n decoded as %s byte response:\n",
778
(do_mode6 ? "6" : "10"), (resp_mode6 ? "6" : "10"));
567
md_len = rsp_buff[0]+1;
782
md_len = rsp_buff[0] + 1;
568
783
bd_len = rsp_buff[3];
569
784
medium_type = rsp_buff[1];
570
785
specific = rsp_buff[2];
571
longlba = 0; /* what is this field? */
574
789
md_len = (rsp_buff[0] << 8) + rsp_buff[1] + 2;