1 /* * This program reads various mode pages and bits of other
2 * information from a scsi device and interprets the raw data for you
3 * with a report written to stdout. Usage:
4 *
5 * ./sginfo [options] /dev/sg2 [replace parameters]
6 *
7 * Options are:
8 * -6 do 6 byte mode sense + select (default: 10 byte)
9 * -a display all mode pages reported by the device: equivalent to '-t 63'.
10 * -A display all mode pages and subpages reported by the device: equivalent
11 * to '-t 63,255'.
12 * -c access Cache control page.
13 * -C access Control Page.
14 * -d display defect lists (default format: index).
15 * -D access disconnect-reconnect page.
16 * -e access Read-Write error recovery page.
17 * -E access Control Extension page.
18 * -f access Format Device Page.
19 * -Farg defect list format (-Flogical, -flba64, -Fphysical, -Findex, -Fhead)
20 * -g access rigid disk geometry page.
21 * -G display only "grown" defect list (default format: index)
22 * -i display information from Inquiry command.
23 * -I access Informational Exceptions page.
24 * -l list known scsi devices on the system [deprecated]
25 * -n access notch parameters page.
26 * -N Negate (stop) storing to saved page (active with -R)
27 * -P access Power Condition Page.
28 * -r list known raw scsi devices on the system
29 * -s display serial number (from INQUIRY VPD page)
30 * -t <n[,spn]> access page number <n> [and subpage <spn>], try to decode
31 * -u <n[,spn]> access page number <n> [and subpage <spn>], output in hex
32 * -v show this program's version number
33 * -V access Verify Error Recovery Page.
34 * -T trace commands (for debugging, double for more debug)
35 * -z do a single fetch for mode pages (rather than double fetch)
36 *
37 * Only one of the following three options can be specified.
38 * None of these three implies the current values are returned.
39 * -m Display modifiable fields instead of current values
40 * -M Display manufacturer defaults instead of current values
41 * -S Display saved defaults instead of current values
42 *
43 * -X Display output values in a list.
44 * -R Replace parameters - best used with -X
45 *
46 * Eric Youngdale - 11/1/93. Version 1.0.
47 *
48 * Version 1.1: Ability to change parameters on cache page, support for
49 * X front end.
50 *
51 * This program is free software; you can redistribute it and/or modify
52 * it under the terms of the GNU General Public License as published by
53 * the Free Software Foundation; either version 2, or (at your option)
54 * any later version.
55 *
56 * This program is distributed in the hope that it will be useful,
57 * but WITHOUT ANY WARRANTY; without even the implied warranty of
58 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59 * GNU General Public License for more details.
60 *
61 * You should have received a copy of the GNU General Public License
62 * along with this program; if not, write to the Free Software
63 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
64 *
65 * SPDX-License-Identifier: GPL-2.0-or-later
66 *
67 * Michael Weller (eowmob at exp-math dot uni-essen dot de)
68 * 11/23/94 massive extensions from 1.4a
69 * 08/23/97 fix problems with defect lists
70 *
71 * Douglas Gilbert (dgilbert at interlog dot com)
72 * 990628 port to sg .... (version 1.81)
73 * up 4KB limit on defect list to 32KB
74 * 'sginfo -l' also shows sg devices and mapping to other
75 * scsi devices
76 * 'sginfo' commands can take either an sd, sr (scd), st
77 * or an sg device (all non-sg devices converted to a
78 * sg device)
79 *
80 * 001208 Add Kurt Garloff's "-uno" flag for displaying info
81 * from a page number. [version 1.90]
82 *
83 * Kurt Garloff
84 * 20000715 allow displaying and modification of vendor specific pages
85 * (unformatted - @ hexdatafield)
86 * accept vendor lengths for those pages
87 * enabled page saving
88 * cleaned parameter parsing a bit (it's still a terrible mess!)
89 * Use sr (instead of scd) and sg%d (instead of sga,b,...) in -l
90 * and support much more devs in -l (incl. nosst)
91 * Fix segfault in defect list (len=0xffff) and adapt formatting
92 * to large disks. Support up to 256kB defect lists with
93 * 0xB7 (12byte) command if necessary and fallback to 0x37
94 * (10byte) in case of failure. Report truncation.
95 * sizeof(buffer) (which is sizeof(char*) == 4 or 32 bit archs)
96 * was used incorrectly all over the place. Fixed.
97 * [version 1.95]
98 * Douglas Gilbert (dgilbert at interlog dot com)
99 * 20020113 snprintf() type cleanup [version 1.96]
100 * 20021211 correct sginfo MODE_SELECT, protect against block devices
101 * that answer sg's ioctls. [version 1.97]
102 * 20021228 scan for some "scd<n>" as well as "sr<n>" device names [1.98]
103 * 20021020 Update control page [1.99]
104 *
105 * Thomas Steudten (thomas at steudten dot com)
106 * 20040521 add -Fhead feature [version 2.04]
107 *
108 * Tim Hunt (tim at timhunt dot net)
109 * 20050427 increase number of mapped SCSI disks devices
110 *
111 * Dave Johnson (djj at ccv dot brown dot edu)
112 * 20051218 improve disk defect list handling
113 */
114
115
116 /*
117 * N.B. This utility is in maintenance mode only. This means that serious
118 * bugs will be fixed but no new features or mode page changes will be
119 * added. Please use the sdparm utility. D. Gilbert 20090316
120 */
121
122 #define _XOPEN_SOURCE 500
123 #ifndef _GNU_SOURCE
124 #define _GNU_SOURCE 1
125 #endif
126
127 static const char * version_str = "2.45 [20220425]";
128
129 #include <stdio.h>
130 #include <string.h>
131 #include <getopt.h>
132 #include <unistd.h>
133 #include <stdlib.h>
134 #include <fcntl.h>
135 #include <errno.h>
136 #include <stdlib.h>
137 #include <ctype.h>
138 #define __STDC_FORMAT_MACROS 1
139 #include <inttypes.h>
140 #include <sys/ioctl.h>
141 #include <sys/types.h>
142 #include <sys/stat.h>
143 #include <dirent.h>
144
145 #ifdef HAVE_CONFIG_H
146 #include "config.h"
147 #endif
148 #include "sg_io_linux.h"
149
150
151 static int glob_fd;
152 static char *device_name;
153
154 #define MAX_SG_DEVS 8192
155 #define MAX_RESP6_SIZE 252
156 #define MAX_RESP10_SIZE (4*1024)
157 #define MAX_BUFFER_SIZE MAX_RESP10_SIZE
158
159 #define INQUIRY_RESP_INITIAL_LEN 36
160 #define MAX_INQFIELD_LEN 17
161
162 #define MAX_HEADS 127
163 #define HEAD_SORT_TOKEN 0x55
164
165 #define SIZEOF_BUFFER (16*1024)
166 #define SIZEOF_BUFFER1 (16*1024)
167 static uint8_t cbuffer[SIZEOF_BUFFER];
168 static uint8_t cbuffer1[SIZEOF_BUFFER1];
169 static uint8_t cbuffer2[SIZEOF_BUFFER1];
170
171 static char defect = 0;
172 static char defectformat = 0x4;
173 static char grown_defect = 0;
174 static char negate_sp_bit = 0;
175 static char replace = 0;
176 static char serial_number = 0;
177 static char x_interface = 0;
178 static char single_fetch = 0;
179
180 static char mode6byte = 0; /* defaults to 10 byte mode sense + select */
181 static char trace_cmd = 0;
182
183 struct mpage_info {
184 int page;
185 int subpage;
186 int page_control;
187 int peri_type;
188 int inq_byte6; /* EncServ and MChngr bits of interest */
189 int resp_len;
190 };
191
192 /* declarations of functions decoding known mode pages */
193 static int common_disconnect_reconnect(struct mpage_info * mpi,
194 const char * prefix);
195 static int common_control(struct mpage_info * mpi, const char * prefix);
196 static int common_control_extension(struct mpage_info * mpi,
197 const char * prefix);
198 static int common_proto_spec_lu(struct mpage_info * mpi, const char * prefix);
199 static int common_proto_spec_port(struct mpage_info * mpi,
200 const char * prefix);
201 static int common_proto_spec_port_sp1(struct mpage_info * mpi,
202 const char * prefix);
203 static int common_proto_spec_port_sp2(struct mpage_info * mpi,
204 const char * prefix);
205 static int common_power_condition(struct mpage_info * mpi,
206 const char * prefix);
207 static int common_informational(struct mpage_info * mpi, const char * prefix);
208 static int disk_error_recovery(struct mpage_info * mpi, const char * prefix);
209 static int disk_format(struct mpage_info * mpi, const char * prefix);
210 static int disk_verify_error_recovery(struct mpage_info * mpi,
211 const char * prefix);
212 static int disk_geometry(struct mpage_info * mpi, const char * prefix);
213 static int disk_notch_parameters(struct mpage_info * mpi, const char * prefix);
214 static int disk_cache(struct mpage_info * mpi, const char * prefix);
215 static int disk_xor_control(struct mpage_info * mpi, const char * prefix);
216 static int disk_background(struct mpage_info * mpi, const char * prefix);
217 static int optical_memory(struct mpage_info * mpi, const char * prefix);
218 static int cdvd_error_recovery(struct mpage_info * mpi, const char * prefix);
219 static int cdvd_mrw(struct mpage_info * mpi, const char * prefix);
220 static int cdvd_write_param(struct mpage_info * mpi, const char * prefix);
221 static int cdvd_audio_control(struct mpage_info * mpi, const char * prefix);
222 static int cdvd_timeout(struct mpage_info * mpi, const char * prefix);
223 static int cdvd_device_param(struct mpage_info * mpi, const char * prefix);
224 static int cdvd_cache(struct mpage_info * mpi, const char * prefix);
225 static int cdvd_mm_capab(struct mpage_info * mpi, const char * prefix);
226 static int cdvd_feature(struct mpage_info * mpi, const char * prefix);
227 static int tape_data_compression(struct mpage_info * mpi, const char * prefix);
228 static int tape_dev_config(struct mpage_info * mpi, const char * prefix);
229 static int tape_medium_part1(struct mpage_info * mpi, const char * prefix);
230 static int tape_medium_part2_4(struct mpage_info * mpi, const char * prefix);
231 static int ses_services_manag(struct mpage_info * mpi, const char * prefix);
232 static int spi4_training_config(struct mpage_info * mpi, const char * prefix);
233 static int spi4_negotiated(struct mpage_info * mpi, const char * prefix);
234 static int spi4_report_xfer(struct mpage_info * mpi, const char * prefix);
235
236 enum page_class {PC_COMMON, PC_DISK, PC_TAPE, PC_CDVD, PC_SES, PC_SMC};
237
238 struct mpage_name_func {
239 int page;
240 int subpage;
241 enum page_class pg_class;
242 const char * name;
243 int (*func)(struct mpage_info *, const char *);
244 };
245
246 #define MP_LIST_PAGES 0x3f
247 #define MP_LIST_SUBPAGES 0xff
248
249 static struct mpage_name_func mpage_common[] =
250 {
251 { 0, 0, PC_COMMON, "Vendor (non-page format)", NULL},
252 { 2, 0, PC_COMMON, "Disconnect-Reconnect", common_disconnect_reconnect},
253 { 9, 0, PC_COMMON, "Peripheral device (obsolete)", NULL},
254 { 0xa, 0, PC_COMMON, "Control", common_control},
255 { 0xa, 1, PC_COMMON, "Control Extension", common_control_extension},
256 { 0x15, 0, PC_COMMON, "Extended", NULL},
257 { 0x16, 0, PC_COMMON, "Extended, device-type specific", NULL},
258 { 0x18, 0, PC_COMMON, "Protocol specific lu", common_proto_spec_lu},
259 { 0x19, 0, PC_COMMON, "Protocol specific port", common_proto_spec_port},
260 { 0x19, 1, PC_COMMON, "Protocol specific port, subpage 1 overload",
261 common_proto_spec_port_sp1},
262 { 0x19, 2, PC_COMMON, "Protocol specific port, subpage 2 overload",
263 common_proto_spec_port_sp2},
264 /* { 0x19, 2, PC_COMMON, "SPI-4 Saved Training configuration",
265 spi4_training_config}, */
266 { 0x19, 3, PC_COMMON, "SPI-4 Negotiated Settings", spi4_negotiated},
267 { 0x19, 4, PC_COMMON, "SPI-4 Report transfer capabilities",
268 spi4_report_xfer},
269 { 0x1a, 0, PC_COMMON, "Power Condition", common_power_condition},
270 { 0x1c, 0, PC_COMMON, "Informational Exceptions", common_informational},
271 { MP_LIST_PAGES, 0, PC_COMMON, "Return all pages", NULL},
272 };
273 static const int mpage_common_len = sizeof(mpage_common) /
274 sizeof(mpage_common[0]);
275
276 static struct mpage_name_func mpage_disk[] =
277 {
278 { 1, 0, PC_DISK, "Read-Write Error Recovery", disk_error_recovery},
279 { 3, 0, PC_DISK, "Format Device", disk_format},
280 { 4, 0, PC_DISK, "Rigid Disk Geometry", disk_geometry},
281 { 5, 0, PC_DISK, "Flexible Disk", NULL},
282 { 6, 0, PC_DISK, "Optical memory", optical_memory},
283 { 7, 0, PC_DISK, "Verify Error Recovery", disk_verify_error_recovery},
284 { 8, 0, PC_DISK, "Caching", disk_cache},
285 { 0xa, 0xf1, PC_DISK, "Parallel ATA control (SAT)", NULL},
286 { 0xb, 0, PC_DISK, "Medium Types Supported", NULL},
287 { 0xc, 0, PC_DISK, "Notch and Partition", disk_notch_parameters},
288 { 0x10, 0, PC_DISK, "XOR control", disk_xor_control},
289 { 0x1c, 1, PC_DISK, "Background control", disk_background},
290 };
291 static const int mpage_disk_len = sizeof(mpage_disk) / sizeof(mpage_disk[0]);
292
293 static struct mpage_name_func mpage_cdvd[] =
294 {
295 { 1, 0, PC_CDVD, "Read-Write Error Recovery (cdvd)",
296 cdvd_error_recovery},
297 { 3, 0, PC_CDVD, "MRW", cdvd_mrw},
298 { 5, 0, PC_CDVD, "Write parameters", cdvd_write_param},
299 { 8, 0, PC_CDVD, "Caching", cdvd_cache},
300 { 0xd, 0, PC_CDVD, "CD device parameters", cdvd_device_param},
301 { 0xe, 0, PC_CDVD, "CD audio control", cdvd_audio_control},
302 { 0x18, 0, PC_CDVD, "Feature set support & version", cdvd_feature},
303 { 0x1a, 0, PC_CDVD, "Power Condition", common_power_condition},
304 { 0x1c, 0, PC_CDVD, "Fault/failure reporting control",
305 common_informational},
306 { 0x1d, 0, PC_CDVD, "Time-out & protect", cdvd_timeout},
307 { 0x2a, 0, PC_CDVD, "MM capabilities & mechanical status", cdvd_mm_capab},
308 };
309 static const int mpage_cdvd_len = sizeof(mpage_cdvd) / sizeof(mpage_cdvd[0]);
310
311 static struct mpage_name_func mpage_tape[] =
312 {
313 { 1, 0, PC_TAPE, "Read-Write Error Recovery", disk_error_recovery},
314 { 0xf, 0, PC_TAPE, "Data compression", tape_data_compression},
315 { 0x10, 0, PC_TAPE, "Device configuration", tape_dev_config},
316 { 0x10, 1, PC_TAPE, "Device configuration extension", NULL},
317 { 0x11, 0, PC_TAPE, "Medium partition(1)", tape_medium_part1},
318 { 0x12, 0, PC_TAPE, "Medium partition(2)", tape_medium_part2_4},
319 { 0x13, 0, PC_TAPE, "Medium partition(3)", tape_medium_part2_4},
320 { 0x14, 0, PC_TAPE, "Medium partition(4)", tape_medium_part2_4},
321 { 0x1c, 0, PC_TAPE, "Informational Exceptions", common_informational},
322 { 0x1d, 0, PC_TAPE, "Medium configuration", NULL},
323 };
324 static const int mpage_tape_len = sizeof(mpage_tape) / sizeof(mpage_tape[0]);
325
326 static struct mpage_name_func mpage_ses[] =
327 {
328 { 0x14, 0, PC_SES, "Enclosure services management", ses_services_manag},
329 };
330 static const int mpage_ses_len = sizeof(mpage_ses) / sizeof(mpage_ses[0]);
331
332 static struct mpage_name_func mpage_smc[] =
333 {
334 { 0x1d, 0, PC_SMC, "Element address assignment", NULL},
335 { 0x1e, 0, PC_SMC, "Transport geometry parameters", NULL},
336 { 0x1f, 0, PC_SMC, "Device capabilities", NULL},
337 { 0x1f, 1, PC_SMC, "Extended device capabilities", NULL},
338 };
339 static const int mpage_smc_len = sizeof(mpage_smc) / sizeof(mpage_smc[0]);
340
341
342 #define MAXPARM 64
343
344 static int next_parameter;
345 static int n_replacement_values;
346 static uint64_t replacement_values[MAXPARM];
347 static char is_hex[MAXPARM];
348
349 #define SMODE_SENSE 0x1a
350 #define SMODE_SENSE_10 0x5a
351 #define SMODE_SELECT 0x15
352 #define SMODE_SELECT_10 0x55
353
354 #define MPHEADER6_LEN 4
355 #define MPHEADER10_LEN 8
356
357
358 /* forward declarations */
359 static void usage(const char *);
360 static void dump(void *buffer, unsigned int length);
361
362 #define DXFER_NONE 0
363 #define DXFER_FROM_DEVICE 1
364 #define DXFER_TO_DEVICE 2
365
366
367 struct scsi_cmnd_io
368 {
369 uint8_t * cmnd; /* ptr to SCSI command block (cdb) */
370 size_t cmnd_len; /* number of bytes in SCSI command */
371 int dxfer_dir; /* DXFER_NONE, DXFER_FROM_DEVICE, or
372 DXFER_TO_DEVICE */
373 uint8_t * dxferp; /* ptr to outgoing/incoming data */
374 size_t dxfer_len; /* bytes to be transferred to/from dxferp */
375 };
376
377 #define SENSE_BUFF_LEN 64
378 #define CMD_TIMEOUT 60000 /* 60,000 milliseconds (60 seconds) */
379 #define EBUFF_SZ 512
380
381
382 #define GENERAL_ERROR 1
383 #define UNKNOWN_OPCODE 2
384 #define BAD_CDB_FIELD 3
385 #define UNSUPPORTED_PARAM 4
386 #define DEVICE_ATTENTION 5
387 #define DEVICE_NOT_READY 6
388
389 #define DECODE_FAILED_TRY_HEX 9999
390
391 /* Returns 0 -> ok, 1 -> general error, 2 -> unknown opcode,
392 3 -> unsupported field in cdb, 4 -> unsupported param in data-in */
393 static int
do_scsi_io(struct scsi_cmnd_io * sio)394 do_scsi_io(struct scsi_cmnd_io * sio)
395 {
396 uint8_t sense_b[SENSE_BUFF_LEN] SG_C_CPP_ZERO_INIT;
397 struct sg_io_hdr io_hdr;
398 struct sg_scsi_sense_hdr ssh;
399 int res;
400
401 memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
402 io_hdr.interface_id = 'S';
403 io_hdr.cmd_len = sio->cmnd_len;
404 io_hdr.mx_sb_len = sizeof(sense_b);
405 if (DXFER_NONE == sio->dxfer_dir)
406 io_hdr.dxfer_direction = SG_DXFER_NONE;
407 else
408 io_hdr.dxfer_direction = (DXFER_TO_DEVICE == sio->dxfer_dir) ?
409 SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
410 io_hdr.dxfer_len = sio->dxfer_len;
411 io_hdr.dxferp = sio->dxferp;
412 io_hdr.cmdp = sio->cmnd;
413 io_hdr.sbp = sense_b;
414 io_hdr.timeout = CMD_TIMEOUT;
415
416 if (trace_cmd) {
417 printf(" cdb:");
418 dump(sio->cmnd, sio->cmnd_len);
419 }
420 if ((trace_cmd > 1) && (DXFER_TO_DEVICE == sio->dxfer_dir)) {
421 printf(" additional data:\n");
422 dump(sio->dxferp, sio->dxfer_len);
423 }
424
425 if (ioctl(glob_fd, SG_IO, &io_hdr) < 0) {
426 perror("do_scsi_cmd: SG_IO error");
427 return GENERAL_ERROR;
428 }
429 res = sg_err_category3(&io_hdr);
430 switch (res) {
431 case SG_LIB_CAT_RECOVERED:
432 sg_chk_n_print3("do_scsi_cmd, continuing", &io_hdr, true);
433 #if defined(__GNUC__)
434 #if (__GNUC__ >= 7)
435 __attribute__((fallthrough));
436 /* FALL THROUGH */
437 #endif
438 #endif
439 case SG_LIB_CAT_CLEAN:
440 return 0;
441 default:
442 if (trace_cmd) {
443 char ebuff[EBUFF_SZ];
444
445 snprintf(ebuff, EBUFF_SZ, "do_scsi_io: opcode=0x%x", sio->cmnd[0]);
446 sg_chk_n_print3(ebuff, &io_hdr, true);
447 }
448 if (sg_normalize_sense(&io_hdr, &ssh)) {
449 if (ILLEGAL_REQUEST == ssh.sense_key) {
450 if (0x20 == ssh.asc)
451 return UNKNOWN_OPCODE;
452 else if (0x24 == ssh.asc)
453 return BAD_CDB_FIELD;
454 else if (0x26 == ssh.asc)
455 return UNSUPPORTED_PARAM;
456 } else if (UNIT_ATTENTION == ssh.sense_key)
457 return DEVICE_ATTENTION;
458 else if (NOT_READY == ssh.sense_key)
459 return DEVICE_NOT_READY;
460 }
461 return GENERAL_ERROR;
462 }
463 }
464
get_mpage_info(int page_no,int subpage_no,struct mpage_name_func * mpp,int elems)465 struct mpage_name_func * get_mpage_info(int page_no, int subpage_no,
466 struct mpage_name_func * mpp, int elems)
467 {
468 int k;
469
470 for (k = 0; k < elems; ++k, ++mpp) {
471 if ((mpp->page == page_no) && (mpp->subpage == subpage_no))
472 return mpp;
473 if (mpp->page > page_no)
474 break;
475 }
476 return NULL;
477 }
478
get_page_class(struct mpage_info * mpi)479 enum page_class get_page_class(struct mpage_info * mpi)
480 {
481 switch (mpi->peri_type)
482 {
483 case 0:
484 case 4:
485 case 7:
486 case 0xe: /* should be RBC */
487 return PC_DISK;
488 case 1:
489 case 2:
490 return PC_TAPE;
491 case 8:
492 return PC_SMC;
493 case 5:
494 return PC_CDVD;
495 case 0xd:
496 return PC_SES;
497 default:
498 return PC_COMMON;
499 }
500 }
501
get_mpage_name_func(struct mpage_info * mpi)502 struct mpage_name_func * get_mpage_name_func(struct mpage_info * mpi)
503 {
504 struct mpage_name_func * mpf = NULL;
505
506 switch (get_page_class(mpi))
507 {
508 case PC_DISK:
509 mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_disk,
510 mpage_disk_len);
511 break;
512 case PC_CDVD:
513 mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_cdvd,
514 mpage_cdvd_len);
515 break;
516 case PC_TAPE:
517 mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_tape,
518 mpage_tape_len);
519 break;
520 case PC_SES:
521 mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_ses,
522 mpage_ses_len);
523 break;
524 case PC_SMC:
525 mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_smc,
526 mpage_smc_len);
527 break;
528 case PC_COMMON:
529 /* picked up it catch all next */
530 break;
531 }
532 if (NULL == mpf) {
533 if ((PC_SES != get_page_class(mpi)) && (mpi->inq_byte6 & 0x40)) {
534 /* check for attached enclosure services processor */
535 mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_ses,
536 mpage_ses_len);
537 }
538 if ((PC_SMC != get_page_class(mpi)) && (mpi->inq_byte6 & 0x8)) {
539 /* check for attached medium changer device */
540 mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_smc,
541 mpage_smc_len);
542 }
543 }
544 if (NULL == mpf)
545 mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_common,
546 mpage_common_len);
547 return mpf;
548 }
549
550
551 static char unkn_page_str[64];
552
553 static const char *
get_page_name(struct mpage_info * mpi)554 get_page_name(struct mpage_info * mpi)
555 {
556 struct mpage_name_func * mpf;
557
558 if (MP_LIST_PAGES == mpi->page) {
559 if (MP_LIST_SUBPAGES == mpi->subpage)
560 return "List supported pages and subpages";
561 else
562 return "List supported pages";
563 }
564 mpf = get_mpage_name_func(mpi);
565 if ((NULL == mpf) || (NULL == mpf->name)) {
566 if (mpi->subpage)
567 snprintf(unkn_page_str, sizeof(unkn_page_str),
568 "page number=0x%x, subpage number=0x%x",
569 mpi->page, mpi->subpage);
570 else
571 snprintf(unkn_page_str, sizeof(unkn_page_str),
572 "page number=0x%x", mpi->page);
573 return unkn_page_str;
574 }
575 return mpf->name;
576 }
577
578 static void
dump(void * buffer,unsigned int length)579 dump(void *buffer, unsigned int length)
580 {
581 unsigned int i;
582
583 printf(" ");
584 for (i = 0; i < length; i++) {
585 #if 0
586 if (((uint8_t *) buffer)[i] > 0x20)
587 printf(" %c ", (unsigned int) ((uint8_t *) buffer)[i]);
588 else
589 #endif
590 printf("%02x ", (unsigned int) ((uint8_t *) buffer)[i]);
591 if ((i % 16 == 15) && (i < (length - 1))) {
592 printf("\n ");
593 }
594 }
595 printf("\n");
596
597 }
598
599 static int
getnbyte(const uint8_t * pnt,int nbyte)600 getnbyte(const uint8_t *pnt, int nbyte)
601 {
602 unsigned int result;
603 int i;
604
605 if (nbyte > 4)
606 fprintf(stderr, "getnbyte() limited to 32 bits, nbyte=%d\n", nbyte);
607 result = 0;
608 for (i = 0; i < nbyte; i++)
609 result = (result << 8) | (pnt[i] & 0xff);
610 return result;
611 }
612
613 static int64_t
getnbyte_ll(const uint8_t * pnt,int nbyte)614 getnbyte_ll(const uint8_t *pnt, int nbyte)
615 {
616 int64_t result;
617 int i;
618
619 if (nbyte > 8)
620 fprintf(stderr, "getnbyte_ll() limited to 64 bits, nbyte=%d\n",
621 nbyte);
622 result = 0;
623 for (i = 0; i < nbyte; i++)
624 result = (result << 8) + (pnt[i] & 0xff);
625 return result;
626 }
627
628 static int
putnbyte(uint8_t * pnt,unsigned int value,unsigned int nbyte)629 putnbyte(uint8_t *pnt, unsigned int value,
630 unsigned int nbyte)
631 {
632 int i;
633
634 for (i = nbyte - 1; i >= 0; i--) {
635 pnt[i] = value & 0xff;
636 value = value >> 8;
637 }
638 return 0;
639 }
640
641 #define REASON_SZ 128
642
643 static void
check_parm_type(int i)644 check_parm_type(int i)
645 {
646 char reason[REASON_SZ];
647
648 if (i == 1 && is_hex[next_parameter] != 1) {
649 snprintf(reason, REASON_SZ,
650 "simple number (pos %i) instead of @ hexdatafield: %"
651 PRIu64 , next_parameter, replacement_values[next_parameter]);
652 usage(reason);
653 }
654 if (i != 1 && is_hex[next_parameter]) {
655 snprintf(reason, REASON_SZ,
656 "@ hexdatafield (pos %i) instead of a simple number: %"
657 PRIu64 , next_parameter, replacement_values[next_parameter]);
658 usage(reason);
659 }
660 }
661
662 static void
bitfield(uint8_t * pageaddr,const char * text,int mask,int shift)663 bitfield(uint8_t *pageaddr, const char * text, int mask, int shift)
664 {
665 if (x_interface && replace) {
666 check_parm_type(0);
667 *pageaddr = (*pageaddr & ~(mask << shift)) |
668 ((replacement_values[next_parameter++] & mask) << shift);
669 } else if (x_interface)
670 printf("%d ", (*pageaddr >> shift) & mask);
671 else
672 printf("%-35s%d\n", text, (*pageaddr >> shift) & mask);
673 }
674
675 #if 0
676 static void
677 notbitfield(uint8_t *pageaddr, char * text, int mask,
678 int shift)
679 {
680 if (modifiable) {
681 bitfield(pageaddr, text, mask, shift);
682 return;
683 }
684 if (x_interface && replace) {
685 check_parm_type(0);
686 *pageaddr = (*pageaddr & ~(mask << shift)) |
687 (((!replacement_values[next_parameter++]) & mask) << shift);
688 } else if (x_interface)
689 printf("%d ", !((*pageaddr >> shift) & mask));
690 else
691 printf("%-35s%d\n", text, !((*pageaddr >> shift) & mask));
692 }
693 #endif
694
695 static void
intfield(uint8_t * pageaddr,int nbytes,const char * text)696 intfield(uint8_t * pageaddr, int nbytes, const char * text)
697 {
698 if (x_interface && replace) {
699 check_parm_type(0);
700 putnbyte(pageaddr, replacement_values[next_parameter++], nbytes);
701 } else if (x_interface)
702 printf("%d ", getnbyte(pageaddr, nbytes));
703 else
704 printf("%-35s%d\n", text, getnbyte(pageaddr, nbytes));
705 }
706
707 static void
hexfield(uint8_t * pageaddr,int nbytes,const char * text)708 hexfield(uint8_t * pageaddr, int nbytes, const char * text)
709 {
710 if (x_interface && replace) {
711 check_parm_type(0);
712 putnbyte(pageaddr, replacement_values[next_parameter++], nbytes);
713 } else if (x_interface)
714 printf("%d ", getnbyte(pageaddr, nbytes));
715 else
716 printf("%-35s0x%x\n", text, getnbyte(pageaddr, nbytes));
717 }
718
719 static void
hexdatafield(uint8_t * pageaddr,int nbytes,const char * text)720 hexdatafield(uint8_t * pageaddr, int nbytes, const char * text)
721 {
722 if (x_interface && replace) {
723 uint8_t *ptr;
724 unsigned tmp;
725
726 /* Though in main we ensured that a @string has the right format,
727 we have to check that we are working on a @ hexdata field */
728
729 check_parm_type(1);
730
731 ptr = (uint8_t *) (unsigned long)
732 (replacement_values[next_parameter++]);
733 ptr++; /* Skip @ */
734
735 while (*ptr) {
736 if (!nbytes)
737 goto illegal;
738 tmp = (*ptr >= 'a') ? (*ptr - 'a' + 'A') : *ptr;
739 tmp -= (tmp >= 'A') ? 'A' - 10 : '0';
740
741 *pageaddr = tmp << 4;
742 ptr++;
743
744 tmp = (*ptr >= 'a') ? (*ptr - 'a' + 'A') : *ptr;
745 tmp -= (tmp >= 'A') ? 'A' - 10 : '0';
746
747 *pageaddr++ += tmp;
748 ptr++;
749 nbytes--;
750 }
751
752 if (nbytes) {
753 illegal:
754 fputs("sginfo: incorrect number of bytes in @hexdatafield.\n",
755 stdout);
756 exit(2);
757 }
758 } else if (x_interface) {
759 putchar('@');
760 while (nbytes-- > 0)
761 printf("%02x", *pageaddr++);
762 putchar(' ');
763 } else {
764 printf("%-35s0x", text);
765 while (nbytes-- > 0)
766 printf("%02x", *pageaddr++);
767 putchar('\n');
768 }
769 }
770
771
772 /* Offset into mode sense (6 or 10 byte) response that actual mode page
773 * starts at (relative to resp[0]). Returns -1 if problem */
774 static int
modePageOffset(const uint8_t * resp,int len,int modese_6)775 modePageOffset(const uint8_t * resp, int len, int modese_6)
776 {
777 int bd_len;
778 int resp_len = 0;
779 int offset = -1;
780
781 if (resp) {
782 if (modese_6) {
783 resp_len = resp[0] + 1;
784 bd_len = resp[3];
785 offset = bd_len + MPHEADER6_LEN;
786 } else {
787 resp_len = (resp[0] << 8) + resp[1] + 2;
788 bd_len = (resp[6] << 8) + resp[7];
789 /* LongLBA doesn't change this calculation */
790 offset = bd_len + MPHEADER10_LEN;
791 }
792 if ((offset + 2) > len) {
793 printf("modePageOffset: raw_curr too small, offset=%d "
794 "resp_len=%d bd_len=%d\n", offset, resp_len, bd_len);
795 offset = -1;
796 } else if ((offset + 2) > resp_len) {
797 printf("modePageOffset: response length too short, resp_len=%d"
798 " offset=%d bd_len=%d\n", resp_len, offset, bd_len);
799 offset = -1;
800 }
801 }
802 return offset;
803 }
804
805 /* Reads mode (sub-)page via 6 byte MODE SENSE, returns 0 if ok */
806 static int
get_mode_page6(struct mpage_info * mpi,int dbd,uint8_t * resp,int sngl_fetch)807 get_mode_page6(struct mpage_info * mpi, int dbd, uint8_t * resp,
808 int sngl_fetch)
809 {
810 int status, off;
811 uint8_t cmd[6];
812 struct scsi_cmnd_io sci;
813 int initial_len = (sngl_fetch ? MAX_RESP6_SIZE : 4);
814
815 memset(resp, 0, 4);
816 cmd[0] = SMODE_SENSE; /* MODE SENSE (6) */
817 cmd[1] = 0x00 | (dbd ? 0x8 : 0); /* disable block descriptors bit */
818 cmd[2] = (mpi->page_control << 6) | mpi->page;
819 cmd[3] = mpi->subpage; /* subpage code */
820 cmd[4] = initial_len;
821 cmd[5] = 0x00; /* control */
822
823 sci.cmnd = cmd;
824 sci.cmnd_len = sizeof(cmd);
825 sci.dxfer_dir = DXFER_FROM_DEVICE;
826 sci.dxfer_len = initial_len;
827 sci.dxferp = resp;
828 status = do_scsi_io(&sci);
829 if (status) {
830 if (mpi->subpage)
831 fprintf(stdout, ">>> Unable to read %s mode page 0x%x, subpage "
832 "0x%x [mode_sense_6]\n", get_page_name(mpi), mpi->page,
833 mpi->subpage);
834 else
835 fprintf(stdout, ">>> Unable to read %s mode page (0x%x) "
836 "[mode_sense_6]\n", get_page_name(mpi), mpi->page);
837 return status;
838 }
839 mpi->resp_len = resp[0] + 1;
840 if (sngl_fetch) {
841 if (trace_cmd > 1) {
842 off = modePageOffset(resp, mpi->resp_len, 1);
843 if (off >= 0) {
844 printf(" cdb response:\n");
845 dump(resp, mpi->resp_len);
846 }
847 }
848 return status;
849 }
850
851 cmd[4] = mpi->resp_len;
852 sci.cmnd = cmd;
853 sci.cmnd_len = sizeof(cmd);
854 sci.dxfer_dir = DXFER_FROM_DEVICE;
855 sci.dxfer_len = mpi->resp_len;
856 sci.dxferp = resp;
857 status = do_scsi_io(&sci);
858 if (status) {
859 if (mpi->subpage)
860 fprintf(stdout, ">>> Unable to read %s mode page 0x%x, subpage "
861 "0x%x [mode_sense_6]\n", get_page_name(mpi), mpi->page,
862 mpi->subpage);
863 else
864 fprintf(stdout, ">>> Unable to read %s mode page (0x%x) "
865 "[mode_sense_6]\n", get_page_name(mpi), mpi->page);
866 } else if (trace_cmd > 1) {
867 off = modePageOffset(resp, mpi->resp_len, 1);
868 if (off >= 0) {
869 printf(" cdb response:\n");
870 dump(resp, mpi->resp_len);
871 }
872 }
873 return status;
874 }
875
876 /* Reads mode (sub-)page via 10 byte MODE SENSE, returns 0 if ok */
877 static int
get_mode_page10(struct mpage_info * mpi,int llbaa,int dbd,uint8_t * resp,int sngl_fetch)878 get_mode_page10(struct mpage_info * mpi, int llbaa, int dbd,
879 uint8_t * resp, int sngl_fetch)
880 {
881 int status, off;
882 uint8_t cmd[10];
883 struct scsi_cmnd_io sci;
884 int initial_len = (sngl_fetch ? MAX_RESP10_SIZE : 4);
885
886 memset(resp, 0, 4);
887 cmd[0] = SMODE_SENSE_10; /* MODE SENSE (10) */
888 cmd[1] = 0x00 | (llbaa ? 0x10 : 0) | (dbd ? 0x8 : 0);
889 cmd[2] = (mpi->page_control << 6) | mpi->page;
890 cmd[3] = mpi->subpage;
891 cmd[4] = 0x00; /* (reserved) */
892 cmd[5] = 0x00; /* (reserved) */
893 cmd[6] = 0x00; /* (reserved) */
894 cmd[7] = (initial_len >> 8) & 0xff;
895 cmd[8] = initial_len & 0xff;
896 cmd[9] = 0x00; /* control */
897
898 sci.cmnd = cmd;
899 sci.cmnd_len = sizeof(cmd);
900 sci.dxfer_dir = DXFER_FROM_DEVICE;
901 sci.dxfer_len = initial_len;
902 sci.dxferp = resp;
903 status = do_scsi_io(&sci);
904 if (status) {
905 if (mpi->subpage)
906 fprintf(stdout, ">>> Unable to read %s mode page 0x%x, subpage "
907 "0x%x [mode_sense_10]\n", get_page_name(mpi), mpi->page,
908 mpi->subpage);
909 else {
910 fprintf(stdout, ">>> Unable to read %s mode page (0x%x) "
911 "[mode_sense_10]\n", get_page_name(mpi), mpi->page);
912 return status;
913 }
914 }
915 mpi->resp_len = (resp[0] << 8) + resp[1] + 2;
916 if (sngl_fetch) {
917 if (trace_cmd > 1) {
918 off = modePageOffset(resp, mpi->resp_len, 0);
919 if (off >= 0) {
920 printf(" cdb response:\n");
921 dump(resp, mpi->resp_len);
922 }
923 }
924 return status;
925 }
926
927 cmd[7] = (mpi->resp_len >> 8) & 0xff;
928 cmd[8] = (mpi->resp_len & 0xff);
929 sci.cmnd = cmd;
930 sci.cmnd_len = sizeof(cmd);
931 sci.dxfer_dir = DXFER_FROM_DEVICE;
932 sci.dxfer_len = mpi->resp_len;
933 sci.dxferp = resp;
934 status = do_scsi_io(&sci);
935 if (status) {
936 if (mpi->subpage)
937 fprintf(stdout, ">>> Unable to read %s mode page 0x%x, subpage "
938 "0x%x [mode_sense_10]\n", get_page_name(mpi), mpi->page,
939 mpi->subpage);
940 else
941 fprintf(stdout, ">>> Unable to read %s mode page (0x%x) "
942 "[mode_sense_10]\n", get_page_name(mpi), mpi->page);
943 } else if (trace_cmd > 1) {
944 off = modePageOffset(resp, mpi->resp_len, 0);
945 if (off >= 0) {
946 printf(" cdb response:\n");
947 dump(resp, mpi->resp_len);
948 }
949 }
950 return status;
951 }
952
953 static int
get_mode_page(struct mpage_info * mpi,int dbd,uint8_t * resp)954 get_mode_page(struct mpage_info * mpi, int dbd, uint8_t * resp)
955 {
956 int res;
957
958 if (mode6byte)
959 res = get_mode_page6(mpi, dbd, resp, single_fetch);
960 else
961 res = get_mode_page10(mpi, 0, dbd, resp, single_fetch);
962 if (UNKNOWN_OPCODE == res)
963 fprintf(stdout, ">>>>> Try command again with%s '-6' "
964 "argument\n", (mode6byte ? "out the" : " a"));
965 else if (mpi->subpage && (BAD_CDB_FIELD == res))
966 fprintf(stdout, ">>>>> device doesn't seem to support "
967 "subpages\n");
968 else if (DEVICE_ATTENTION == res)
969 fprintf(stdout, ">>>>> device reports UNIT ATTENTION, check it or"
970 " just try again\n");
971 else if (DEVICE_NOT_READY == res)
972 fprintf(stdout, ">>>>> device NOT READY, does it need media?\n");
973 return res;
974 }
975
976 /* Contents should point to the mode parameter header that we obtained
977 in a prior read operation. This way we do not have to work out the
978 format of the beast. Assume 0 or 1 block descriptors. */
979 static int
put_mode_page6(struct mpage_info * mpi,const uint8_t * msense6_resp,int sp_bit)980 put_mode_page6(struct mpage_info * mpi, const uint8_t * msense6_resp,
981 int sp_bit)
982 {
983 int status;
984 int bdlen, resplen;
985 uint8_t cmd[6];
986 struct scsi_cmnd_io sci;
987
988 bdlen = msense6_resp[3];
989 resplen = msense6_resp[0] + 1;
990
991 cmd[0] = SMODE_SELECT;
992 cmd[1] = 0x10 | (sp_bit ? 1 : 0); /* always set PF bit */
993 cmd[2] = 0x00;
994 cmd[3] = 0x00; /* (reserved) */
995 cmd[4] = resplen; /* parameter list length */
996 cmd[5] = 0x00; /* (reserved) */
997
998 memcpy(cbuffer1, msense6_resp, resplen);
999 cbuffer1[0] = 0; /* Mask off the mode data length
1000 - reserved field */
1001 cbuffer1[2] = 0; /* device-specific parameter is not defined
1002 and/or reserved for mode select */
1003
1004 #if 0 /* leave block descriptor alone */
1005 if (bdlen > 0) {
1006 memset(cbuffer1 + MPHEADER6_LEN, 0, 4); /* clear 'number of blocks'
1007 for DAD device */
1008 cbuffer1[MPHEADER6_LEN + 4] = 0; /* clear DAD density code. Why? */
1009 /* leave DAD block length */
1010 }
1011 #endif
1012 cbuffer1[MPHEADER6_LEN + bdlen] &= 0x7f; /* Mask PS bit */
1013
1014 sci.cmnd = cmd;
1015 sci.cmnd_len = sizeof(cmd);
1016 sci.dxfer_dir = DXFER_TO_DEVICE;
1017 sci.dxfer_len = resplen;
1018 sci.dxferp = cbuffer1;
1019 status = do_scsi_io(&sci);
1020 if (status) {
1021 if (mpi->subpage)
1022 fprintf(stdout, ">>> Unable to store %s mode page 0x%x,"
1023 " subpage 0x%x [msel_6]\n", get_page_name(mpi),
1024 mpi->page, mpi->subpage);
1025 else
1026 fprintf(stdout, ">>> Unable to store %s mode page 0x%x [msel_6]\n",
1027 get_page_name(mpi), mpi->page);
1028 }
1029 return status;
1030 }
1031
1032 /* Contents should point to the mode parameter header that we obtained
1033 in a prior read operation. This way we do not have to work out the
1034 format of the beast. Assume 0 or 1 block descriptors. */
1035 static int
put_mode_page10(struct mpage_info * mpi,const uint8_t * msense10_resp,int sp_bit)1036 put_mode_page10(struct mpage_info * mpi, const uint8_t * msense10_resp,
1037 int sp_bit)
1038 {
1039 int status;
1040 int bdlen, resplen;
1041 uint8_t cmd[10];
1042 struct scsi_cmnd_io sci;
1043
1044 bdlen = (msense10_resp[6] << 8) + msense10_resp[7];
1045 resplen = (msense10_resp[0] << 8) + msense10_resp[1] + 2;
1046
1047 cmd[0] = SMODE_SELECT_10;
1048 cmd[1] = 0x10 | (sp_bit ? 1 : 0); /* always set PF bit */
1049 cmd[2] = 0x00; /* (reserved) */
1050 cmd[3] = 0x00; /* (reserved) */
1051 cmd[4] = 0x00; /* (reserved) */
1052 cmd[5] = 0x00; /* (reserved) */
1053 cmd[6] = 0x00; /* (reserved) */
1054 cmd[7] = (resplen >> 8) & 0xff;
1055 cmd[8] = resplen & 0xff;
1056 cmd[9] = 0x00; /* (reserved) */
1057
1058 memcpy(cbuffer1, msense10_resp, resplen);
1059 cbuffer1[0] = 0; /* Mask off the mode data length */
1060 cbuffer1[1] = 0; /* Mask off the mode data length */
1061 cbuffer1[3] = 0; /* device-specific parameter is not defined
1062 and/or reserved for mode select */
1063 #if 0 /* leave block descriptor alone */
1064 if (bdlen > 0) {
1065 memset(cbuffer1 + MPHEADER10_LEN, 0, 4); /* clear 'number of blocks'
1066 for DAD device */
1067 cbuffer1[MPHEADER10_LEN + 4] = 0; /* clear DAD density code. Why? */
1068 /* leave DAD block length */
1069 }
1070 #endif
1071 cbuffer1[MPHEADER10_LEN + bdlen] &= 0x7f; /* Mask PS bit */
1072
1073 sci.cmnd = cmd;
1074 sci.cmnd_len = sizeof(cmd);
1075 sci.dxfer_dir = DXFER_TO_DEVICE;
1076 sci.dxfer_len = resplen;
1077 sci.dxferp = cbuffer1;
1078 status = do_scsi_io(&sci);
1079 if (status) {
1080 if (mpi->subpage)
1081 fprintf(stdout, ">>> Unable to store %s mode page 0x%x,"
1082 " subpage 0x%x [msel_10]\n", get_page_name(mpi),
1083 mpi->page, mpi->subpage);
1084 else
1085 fprintf(stdout, ">>> Unable to store %s mode page 0x%x "
1086 "[msel_10]\n", get_page_name(mpi), mpi->page);
1087 }
1088 return status;
1089 }
1090
1091 static int
put_mode_page(struct mpage_info * mpi,const uint8_t * msense_resp)1092 put_mode_page(struct mpage_info * mpi, const uint8_t * msense_resp)
1093 {
1094 if (mode6byte)
1095 return put_mode_page6(mpi, msense_resp, ! negate_sp_bit);
1096 else
1097 return put_mode_page10(mpi, msense_resp, ! negate_sp_bit);
1098 }
1099
1100 static int
setup_mode_page(struct mpage_info * mpi,int nparam,uint8_t * buff,uint8_t ** o_pagestart)1101 setup_mode_page(struct mpage_info * mpi, int nparam, uint8_t * buff,
1102 uint8_t ** o_pagestart)
1103 {
1104 int status, offset, rem_pglen;
1105 uint8_t * pgp;
1106
1107 status = get_mode_page(mpi, 0, buff);
1108 if (status) {
1109 printf("\n");
1110 return status;
1111 }
1112 offset = modePageOffset(buff, mpi->resp_len, mode6byte);
1113 if (offset < 0) {
1114 fprintf(stdout, "mode page=0x%x has bad page format\n", mpi->page);
1115 fprintf(stdout, " perhaps '-z' switch may help\n");
1116 return -1;
1117 }
1118 pgp = buff + offset;
1119 *o_pagestart = pgp;
1120 rem_pglen = (0x40 & pgp[0]) ? ((pgp[2] << 8) + pgp[3]) : pgp[1];
1121
1122 if (x_interface && replace) {
1123 if ((nparam && (n_replacement_values != nparam)) ||
1124 ((! nparam) && (n_replacement_values != rem_pglen))) {
1125 fprintf(stdout, "Wrong number of replacement values (%i instead "
1126 "of %i)\n", n_replacement_values,
1127 nparam ? nparam : rem_pglen);
1128 return 1;
1129 }
1130 next_parameter = 1;
1131 }
1132 return 0;
1133 }
1134
1135 static int
get_protocol_id(int port_not_lu,uint8_t * buff,int * proto_idp,int * offp)1136 get_protocol_id(int port_not_lu, uint8_t * buff, int * proto_idp,
1137 int * offp)
1138 {
1139 int status, off, proto_id, spf;
1140 struct mpage_info mp_i;
1141 char b[64];
1142
1143 memset(&mp_i, 0, sizeof(mp_i));
1144 mp_i.page = (port_not_lu ? 0x19 : 0x18);
1145 /* N.B. getting port or lu specific mode page (not subpage) */
1146 status = get_mode_page(&mp_i, 0, buff);
1147 if (status)
1148 return status;
1149 off = modePageOffset(buff, mp_i.resp_len, mode6byte);
1150 if (off < 0)
1151 return off;
1152 spf = (buff[off] & 0x40) ? 1 : 0; /* subpages won't happen here */
1153 proto_id = buff[off + (spf ? 5 : 2)] & 0xf;
1154 if (trace_cmd > 0)
1155 printf("Protocol specific %s, protocol_id=%s\n",
1156 (port_not_lu ? "port" : "lu"),
1157 sg_get_trans_proto_str(proto_id, sizeof(b), b));
1158 if (proto_idp)
1159 *proto_idp = proto_id;
1160 if (offp)
1161 *offp = off;
1162 return 0;
1163 }
1164
1165 static int
disk_geometry(struct mpage_info * mpi,const char * prefix)1166 disk_geometry(struct mpage_info * mpi, const char * prefix)
1167 {
1168 int status;
1169 uint8_t *pagestart;
1170
1171 status = setup_mode_page(mpi, 9, cbuffer, &pagestart);
1172 if (status)
1173 return status;
1174 if (prefix[0])
1175 printf("%s", prefix);
1176 if (!x_interface && !replace) {
1177 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1178 printf("-----------------------------------\n");
1179 };
1180 intfield(pagestart + 2, 3, "Number of cylinders");
1181 intfield(pagestart + 5, 1, "Number of heads");
1182 intfield(pagestart + 6, 3, "Starting cyl. write precomp");
1183 intfield(pagestart + 9, 3, "Starting cyl. reduced current");
1184 intfield(pagestart + 12, 2, "Device step rate");
1185 intfield(pagestart + 14, 3, "Landing Zone Cylinder");
1186 bitfield(pagestart + 17, "RPL", 3, 0);
1187 intfield(pagestart + 18, 1, "Rotational Offset");
1188 intfield(pagestart + 20, 2, "Rotational Rate");
1189 if (x_interface && replace)
1190 return put_mode_page(mpi, cbuffer);
1191 else
1192 printf("\n");
1193 return 0;
1194 }
1195
1196 static int
common_disconnect_reconnect(struct mpage_info * mpi,const char * prefix)1197 common_disconnect_reconnect(struct mpage_info * mpi,
1198 const char * prefix)
1199 {
1200 int status;
1201 uint8_t *pagestart;
1202
1203 status = setup_mode_page(mpi, 11, cbuffer, &pagestart);
1204 if (status)
1205 return status;
1206
1207 if (prefix[0])
1208 printf("%s", prefix);
1209 if (!x_interface && !replace) {
1210 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1211 printf("------------------------------------\n");
1212 };
1213 intfield(pagestart + 2, 1, "Buffer full ratio");
1214 intfield(pagestart + 3, 1, "Buffer empty ratio");
1215 intfield(pagestart + 4, 2, "Bus Inactivity Limit (SAS: 100us)");
1216 intfield(pagestart + 6, 2, "Disconnect Time Limit");
1217 intfield(pagestart + 8, 2, "Connect Time Limit (SAS: 100us)");
1218 intfield(pagestart + 10, 2, "Maximum Burst Size");
1219 bitfield(pagestart + 12, "EMDP", 1, 7);
1220 bitfield(pagestart + 12, "Fair Arbitration (fcp:faa,fab,fac)", 0x7, 4);
1221 bitfield(pagestart + 12, "DIMM", 1, 3);
1222 bitfield(pagestart + 12, "DTDC", 0x7, 0);
1223 intfield(pagestart + 14, 2, "First Burst Size");
1224 if (x_interface && replace)
1225 return put_mode_page(mpi, cbuffer);
1226 else
1227 printf("\n");
1228 return 0;
1229
1230 }
1231
1232 static int
common_control(struct mpage_info * mpi,const char * prefix)1233 common_control(struct mpage_info * mpi, const char * prefix)
1234 {
1235 int status;
1236 uint8_t *pagestart;
1237
1238 status = setup_mode_page(mpi, 21, cbuffer, &pagestart);
1239 if (status)
1240 return status;
1241
1242 if (prefix[0])
1243 printf("%s", prefix);
1244 if (!x_interface && !replace) {
1245 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1246 printf("-----------------------\n");
1247 }
1248 bitfield(pagestart + 2, "TST", 0x7, 5);
1249 bitfield(pagestart + 2, "TMF_ONLY", 1, 4);
1250 bitfield(pagestart + 2, "D_SENSE", 1, 2);
1251 bitfield(pagestart + 2, "GLTSD", 1, 1);
1252 bitfield(pagestart + 2, "RLEC", 1, 0);
1253 bitfield(pagestart + 3, "Queue Algorithm Modifier", 0xf, 4);
1254 bitfield(pagestart + 3, "QErr", 0x3, 1);
1255 bitfield(pagestart + 3, "DQue [obsolete]", 1, 0);
1256 bitfield(pagestart + 4, "TAS", 1, 7);
1257 bitfield(pagestart + 4, "RAC", 1, 6);
1258 bitfield(pagestart + 4, "UA_INTLCK_CTRL", 0x3, 4);
1259 bitfield(pagestart + 4, "SWP", 1, 3);
1260 bitfield(pagestart + 4, "RAERP [obs.]", 1, 2);
1261 bitfield(pagestart + 4, "UAAERP [obs.]", 1, 1);
1262 bitfield(pagestart + 4, "EAERP [obs.]", 1, 0);
1263 bitfield(pagestart + 5, "ATO", 1, 7);
1264 bitfield(pagestart + 5, "TAS", 1, 6);
1265 bitfield(pagestart + 5, "AUTOLOAD MODE", 0x7, 0);
1266 intfield(pagestart + 6, 2, "Ready AER Holdoff Period [obs.]");
1267 intfield(pagestart + 8, 2, "Busy Timeout Period");
1268 intfield(pagestart + 10, 2, "Extended self-test completion time");
1269 if (x_interface && replace)
1270 return put_mode_page(mpi, cbuffer);
1271 else
1272 printf("\n");
1273 return 0;
1274 }
1275
1276 static int
common_control_extension(struct mpage_info * mpi,const char * prefix)1277 common_control_extension(struct mpage_info * mpi, const char * prefix)
1278 {
1279 int status;
1280 uint8_t *pagestart;
1281
1282 status = setup_mode_page(mpi, 4, cbuffer, &pagestart);
1283 if (status)
1284 return status;
1285
1286 if (prefix[0])
1287 printf("%s", prefix);
1288 if (!x_interface && !replace) {
1289 printf("%s mode subpage (0x%x,0x%x)\n", get_page_name(mpi), mpi->page,
1290 mpi->subpage);
1291 printf("--------------------------------------------\n");
1292 }
1293 bitfield(pagestart + 4, "TCMOS", 1, 2);
1294 bitfield(pagestart + 4, "SCSIP", 1, 1);
1295 bitfield(pagestart + 4, "IALUAE", 1, 0);
1296 bitfield(pagestart + 5, "Initial Priority", 0xf, 0);
1297
1298 if (x_interface && replace)
1299 return put_mode_page(mpi, cbuffer);
1300 else
1301 printf("\n");
1302 return 0;
1303 }
1304
1305 static int
common_informational(struct mpage_info * mpi,const char * prefix)1306 common_informational(struct mpage_info * mpi, const char * prefix)
1307 {
1308 int status;
1309 uint8_t *pagestart;
1310
1311 status = setup_mode_page(mpi, 10, cbuffer, &pagestart);
1312 if (status)
1313 return status;
1314
1315 if (prefix[0])
1316 printf("%s", prefix);
1317 if (!x_interface && !replace) {
1318 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1319 printf("-----------------------------------------\n");
1320 }
1321 bitfield(pagestart + 2, "PERF", 1, 7);
1322 bitfield(pagestart + 2, "EBF", 1, 5);
1323 bitfield(pagestart + 2, "EWASC", 1, 4);
1324 bitfield(pagestart + 2, "DEXCPT", 1, 3);
1325 bitfield(pagestart + 2, "TEST", 1, 2);
1326 bitfield(pagestart + 2, "EBACKERR", 1, 1);
1327 bitfield(pagestart + 2, "LOGERR", 1, 0);
1328 bitfield(pagestart + 3, "MRIE", 0xf, 0);
1329 intfield(pagestart + 4, 4, "Interval Timer");
1330 intfield(pagestart + 8, 4, "Report Count");
1331 if (x_interface && replace)
1332 return put_mode_page(mpi, cbuffer);
1333 else
1334 printf("\n");
1335 return 0;
1336 }
1337
1338 static int
disk_error_recovery(struct mpage_info * mpi,const char * prefix)1339 disk_error_recovery(struct mpage_info * mpi, const char * prefix)
1340 {
1341 int status;
1342 uint8_t *pagestart;
1343
1344 status = setup_mode_page(mpi, 14, cbuffer, &pagestart);
1345 if (status)
1346 return status;
1347
1348 if (prefix[0])
1349 printf("%s", prefix);
1350 if (!x_interface && !replace) {
1351 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1352 printf("-----------------------------------------\n");
1353 }
1354 bitfield(pagestart + 2, "AWRE", 1, 7);
1355 bitfield(pagestart + 2, "ARRE", 1, 6);
1356 bitfield(pagestart + 2, "TB", 1, 5);
1357 bitfield(pagestart + 2, "RC", 1, 4);
1358 bitfield(pagestart + 2, "EER", 1, 3);
1359 bitfield(pagestart + 2, "PER", 1, 2);
1360 bitfield(pagestart + 2, "DTE", 1, 1);
1361 bitfield(pagestart + 2, "DCR", 1, 0);
1362 intfield(pagestart + 3, 1, "Read Retry Count");
1363 intfield(pagestart + 4, 1, "Correction Span");
1364 intfield(pagestart + 5, 1, "Head Offset Count");
1365 intfield(pagestart + 6, 1, "Data Strobe Offset Count");
1366 intfield(pagestart + 8, 1, "Write Retry Count");
1367 intfield(pagestart + 10, 2, "Recovery Time Limit (ms)");
1368 if (x_interface && replace)
1369 return put_mode_page(mpi, cbuffer);
1370 else
1371 printf("\n");
1372 return 0;
1373 }
1374
1375 static int
cdvd_error_recovery(struct mpage_info * mpi,const char * prefix)1376 cdvd_error_recovery(struct mpage_info * mpi, const char * prefix)
1377 {
1378 int status;
1379 uint8_t *pagestart;
1380
1381 status = setup_mode_page(mpi, 10, cbuffer, &pagestart);
1382 if (status)
1383 return status;
1384
1385 if (prefix[0])
1386 printf("%s", prefix);
1387 if (!x_interface && !replace) {
1388 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1389 printf("------------------------------------------------\n");
1390 }
1391 bitfield(pagestart + 2, "AWRE", 1, 7);
1392 bitfield(pagestart + 2, "ARRE", 1, 6);
1393 bitfield(pagestart + 2, "TB", 1, 5);
1394 bitfield(pagestart + 2, "RC", 1, 4);
1395 bitfield(pagestart + 2, "PER", 1, 2);
1396 bitfield(pagestart + 2, "DTE", 1, 1);
1397 bitfield(pagestart + 2, "DCR", 1, 0);
1398 intfield(pagestart + 3, 1, "Read Retry Count");
1399 bitfield(pagestart + 7, "EMCDR", 3, 0);
1400 intfield(pagestart + 8, 1, "Write Retry Count");
1401 if (x_interface && replace)
1402 return put_mode_page(mpi, cbuffer);
1403 else
1404 printf("\n");
1405 return 0;
1406 }
1407
1408 static int
cdvd_mrw(struct mpage_info * mpi,const char * prefix)1409 cdvd_mrw(struct mpage_info * mpi, const char * prefix)
1410 {
1411 int status;
1412 uint8_t *pagestart;
1413
1414 status = setup_mode_page(mpi, 1, cbuffer, &pagestart);
1415 if (status)
1416 return status;
1417
1418 if (prefix[0])
1419 printf("%s", prefix);
1420 if (!x_interface && !replace) {
1421 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1422 printf("------------------------------------------------\n");
1423 }
1424 bitfield(pagestart + 3, "LBA space", 1, 0);
1425 if (x_interface && replace)
1426 return put_mode_page(mpi, cbuffer);
1427 else
1428 printf("\n");
1429 return 0;
1430 }
1431
1432 static int
disk_notch_parameters(struct mpage_info * mpi,const char * prefix)1433 disk_notch_parameters(struct mpage_info * mpi, const char * prefix)
1434 {
1435 int status;
1436 uint8_t *pagestart;
1437
1438 status = setup_mode_page(mpi, 6, cbuffer, &pagestart);
1439 if (status) {
1440 fprintf(stdout, "Special case: only give 6 fields to '-XR' since"
1441 " 'Pages Notched' is unchangeable\n");
1442 return status;
1443 }
1444
1445 if (prefix[0])
1446 printf("%s", prefix);
1447 if (!x_interface && !replace) {
1448 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1449 printf("-----------------------------------\n");
1450 };
1451 bitfield(pagestart + 2, "Notched Drive", 1, 7);
1452 bitfield(pagestart + 2, "Logical or Physical Notch", 1, 6);
1453 intfield(pagestart + 4, 2, "Max # of notches");
1454 intfield(pagestart + 6, 2, "Active Notch");
1455 if (pagestart[2] & 0x40) {
1456 intfield(pagestart + 8, 4, "Starting Boundary");
1457 intfield(pagestart + 12, 4, "Ending Boundary");
1458 } else { /* Hex is more meaningful for physical notches */
1459 hexfield(pagestart + 8, 4, "Starting Boundary");
1460 hexfield(pagestart + 12, 4, "Ending Boundary");
1461 }
1462
1463 if (x_interface && !replace) {
1464 #if 1
1465 ; /* do nothing, skip this field */
1466 #else
1467 if (1 == mpi->page_control) /* modifiable */
1468 printf("0");
1469 else
1470 printf("0x%8.8x%8.8x", getnbyte(pagestart + 16, 4),
1471 getnbyte(pagestart + 20, 4));
1472 #endif
1473 };
1474 if (!x_interface)
1475 printf("Pages Notched %8.8x %8.8x\n",
1476 getnbyte(pagestart + 16, 4), getnbyte(pagestart + 20, 4));
1477 if (x_interface && replace)
1478 return put_mode_page(mpi, cbuffer);
1479 else
1480 printf("\n");
1481 return 0;
1482 }
1483
1484 static const char *
formatname(int format)1485 formatname(int format)
1486 {
1487 switch(format) {
1488 case 0x0: return "logical block addresses (32 bit)";
1489 case 0x3: return "logical block addresses (64 bit)";
1490 case 0x4: return "bytes from index [Cyl:Head:Off]\n"
1491 "Offset -1 marks whole track as bad.\n";
1492 case 0x5: return "physical blocks [Cyl:Head:Sect]\n"
1493 "Sector -1 marks whole track as bad.\n";
1494 }
1495 return "Weird, unknown format";
1496 }
1497
1498 static int
read_defect_list(int grown_only)1499 read_defect_list(int grown_only)
1500 {
1501 int i, len, reallen, table, k, defect_format;
1502 int status = 0;
1503 int header = 1;
1504 int sorthead = 0;
1505 uint8_t cmd[10];
1506 uint8_t cmd12[12];
1507 uint8_t *df = NULL;
1508 uint8_t *bp = NULL;
1509 uint8_t *heapp = NULL;
1510 unsigned int *headsp = NULL;
1511 int trunc;
1512 struct scsi_cmnd_io sci;
1513
1514 if (defectformat == HEAD_SORT_TOKEN) {
1515 defectformat = 0x04;
1516 sorthead = 1;
1517 headsp = (unsigned int *)calloc(MAX_HEADS, sizeof(unsigned int));
1518 if (headsp == NULL) {
1519 perror("malloc failed");
1520 return status;
1521 }
1522 }
1523 for (table = grown_only; table < 2; table++) {
1524 if (heapp) {
1525 free(heapp);
1526 heapp = NULL;
1527 }
1528 bp = cbuffer;
1529 memset(bp, 0, 4);
1530 trunc = 0;
1531 reallen = -1;
1532
1533 cmd[0] = 0x37; /* READ DEFECT DATA (10) */
1534 cmd[1] = 0x00;
1535 cmd[2] = (table ? 0x08 : 0x10) | defectformat; /* List, Format */
1536 cmd[3] = 0x00; /* (reserved) */
1537 cmd[4] = 0x00; /* (reserved) */
1538 cmd[5] = 0x00; /* (reserved) */
1539 cmd[6] = 0x00; /* (reserved) */
1540 cmd[7] = 0x00; /* Alloc len */
1541 cmd[8] = 0x04; /* Alloc len (size finder) */
1542 cmd[9] = 0x00; /* control */
1543
1544 sci.cmnd = cmd;
1545 sci.cmnd_len = sizeof(cmd);
1546 sci.dxfer_dir = DXFER_FROM_DEVICE;
1547 sci.dxfer_len = 4;
1548 sci.dxferp = bp;
1549 i = do_scsi_io(&sci);
1550 if (i) {
1551 fprintf(stdout, ">>> Unable to read %s defect data.\n",
1552 (table ? "grown (GLIST)" : "primary (PLIST)"));
1553 status |= i;
1554 continue;
1555 }
1556 if (trace_cmd > 1) {
1557 printf(" cdb response:\n");
1558 dump(bp, 4);
1559 }
1560 /*
1561 * Check validity of response:
1562 * bp[0] reserved, must be zero
1563 * bp[1] bits 7-5 reserved, must be zero
1564 * bp[1] bits 4-3 should match table requested
1565 */
1566 if (0 != bp[0] || (table ? 0x08 : 0x10) != (bp[1] & 0xf8)) {
1567 fprintf(stdout, ">>> Invalid header for %s defect list.\n",
1568 (table ? "grown (GLIST)" : "primary (PLIST)"));
1569 status |= 1;
1570 continue;
1571 }
1572 if (header) {
1573 printf("Defect Lists\n"
1574 "------------\n");
1575 header = 0;
1576 }
1577 len = (bp[2] << 8) + bp[3];
1578 if (len < 0xfff8)
1579 reallen = len;
1580 else {
1581 /*
1582 * List length is at or over capacity of READ DEFECT DATA (10)
1583 * Try to get actual length with READ DEFECT DATA (12)
1584 */
1585 bp = cbuffer;
1586 memset(bp, 0, 8);
1587 cmd12[0] = 0xB7; /* READ DEFECT DATA (12) */
1588 cmd12[1] = (table ? 0x08 : 0x10) | defectformat;/* List, Format */
1589 cmd12[2] = 0x00; /* (reserved) */
1590 cmd12[3] = 0x00; /* (reserved) */
1591 cmd12[4] = 0x00; /* (reserved) */
1592 cmd12[5] = 0x00; /* (reserved) */
1593 cmd12[6] = 0x00; /* Alloc len */
1594 cmd12[7] = 0x00; /* Alloc len */
1595 cmd12[8] = 0x00; /* Alloc len */
1596 cmd12[9] = 0x08; /* Alloc len (size finder) */
1597 cmd12[10] = 0x00; /* reserved */
1598 cmd12[11] = 0x00; /* control */
1599
1600 sci.cmnd = cmd12;
1601 sci.cmnd_len = sizeof(cmd12);
1602 sci.dxfer_dir = DXFER_FROM_DEVICE;
1603 sci.dxfer_len = 8;
1604 sci.dxferp = bp;
1605 i = do_scsi_io(&sci);
1606 if (i) {
1607 if (trace_cmd) {
1608 fprintf(stdout, ">>> No 12 byte command support, "
1609 "but list is too long for 10 byte version.\n"
1610 "List will be truncated at 8191 elements\n");
1611 }
1612 goto trytenbyte;
1613 }
1614 if (trace_cmd > 1) {
1615 printf(" cdb response:\n");
1616 dump(bp, 8);
1617 }
1618 /*
1619 * Check validity of response:
1620 * bp[0], bp[2] and bp[3] reserved, must be zero
1621 * bp[1] bits 7-5 reserved, must be zero
1622 * bp[1] bits 4-3 should match table we requested
1623 */
1624 if (0 != bp[0] || 0 != bp[2] || 0 != bp[3] ||
1625 ((table ? 0x08 : 0x10) != (bp[1] & 0xf8))) {
1626 if (trace_cmd)
1627 fprintf(stdout,
1628 ">>> Invalid header for %s defect list.\n",
1629 (table ? "grown (GLIST)" : "primary (PLIST)"));
1630 goto trytenbyte;
1631 }
1632 len = (bp[4] << 24) + (bp[5] << 16) + (bp[6] << 8) + bp[7];
1633 reallen = len;
1634 }
1635
1636 if (len > 0) {
1637 k = len + 8; /* length of defect list + header */
1638 if (k > (int)sizeof(cbuffer)) {
1639 heapp = (uint8_t *)malloc(k);
1640
1641 if (len > 0x80000 && NULL == heapp) {
1642 len = 0x80000; /* go large: 512 KB */
1643 k = len + 8;
1644 heapp = (uint8_t *)malloc(k);
1645 }
1646 if (heapp != NULL)
1647 bp = heapp;
1648 }
1649 if (len > 0xfff0 && heapp != NULL) {
1650 cmd12[0] = 0xB7; /* READ DEFECT DATA (12) */
1651 cmd12[1] = (table ? 0x08 : 0x10) | defectformat;
1652 /* List, Format */
1653 cmd12[2] = 0x00; /* (reserved) */
1654 cmd12[3] = 0x00; /* (reserved) */
1655 cmd12[4] = 0x00; /* (reserved) */
1656 cmd12[5] = 0x00; /* (reserved) */
1657 cmd12[6] = 0x00; /* Alloc len */
1658 cmd12[7] = (k >> 16) & 0xff; /* Alloc len */
1659 cmd12[8] = (k >> 8) & 0xff; /* Alloc len */
1660 cmd12[9] = (k & 0xff); /* Alloc len */
1661 cmd12[10] = 0x00; /* reserved */
1662 cmd12[11] = 0x00; /* control */
1663
1664 sci.cmnd = cmd12;
1665 sci.cmnd_len = sizeof(cmd12);
1666 sci.dxfer_dir = DXFER_FROM_DEVICE;
1667 sci.dxfer_len = k;
1668 sci.dxferp = bp;
1669 i = do_scsi_io(&sci);
1670 if (i)
1671 goto trytenbyte;
1672 if (trace_cmd > 1) {
1673 printf(" cdb response:\n");
1674 dump(bp, 8);
1675 }
1676 reallen = (bp[4] << 24) + (bp[5] << 16) + (bp[6] << 8) +
1677 bp[7];
1678 if (reallen > len) {
1679 trunc = 1;
1680 }
1681 df = (uint8_t *) (bp + 8);
1682 }
1683 else {
1684 trytenbyte:
1685 if (len > 0xfff8) {
1686 len = 0xfff8;
1687 trunc = 1;
1688 }
1689 k = len + 4; /* length of defect list + header */
1690 if (k > (int)sizeof(cbuffer) && NULL == heapp) {
1691 heapp = (uint8_t *)malloc(k);
1692 if (heapp != NULL)
1693 bp = heapp;
1694 }
1695 if (k > (int)sizeof(cbuffer) && NULL == heapp) {
1696 bp = cbuffer;
1697 k = sizeof(cbuffer);
1698 len = k - 4;
1699 trunc = 1;
1700 }
1701 cmd[0] = 0x37; /* READ DEFECT DATA (10) */
1702 cmd[1] = 0x00;
1703 cmd[2] = (table ? 0x08 : 0x10) | defectformat;
1704 /* List, Format */
1705 cmd[3] = 0x00; /* (reserved) */
1706 cmd[4] = 0x00; /* (reserved) */
1707 cmd[5] = 0x00; /* (reserved) */
1708 cmd[6] = 0x00; /* (reserved) */
1709 cmd[7] = (k >> 8); /* Alloc len */
1710 cmd[8] = (k & 0xff); /* Alloc len */
1711 cmd[9] = 0x00; /* control */
1712
1713 sci.cmnd = cmd;
1714 sci.cmnd_len = sizeof(cmd);
1715 sci.dxfer_dir = DXFER_FROM_DEVICE;
1716 sci.dxfer_len = k;
1717 sci.dxferp = bp;
1718 i = do_scsi_io(&sci);
1719 df = (uint8_t *) (bp + 4);
1720 }
1721 }
1722 if (i) {
1723 fprintf(stdout, ">>> Unable to read %s defect data.\n",
1724 (table ? "grown (GLIST)" : "primary (PLIST)"));
1725 status |= i;
1726 continue;
1727 }
1728 else {
1729 if (table && !status && !sorthead)
1730 printf("\n");
1731 defect_format = (bp[1] & 0x7);
1732 if (-1 == reallen) {
1733 printf("at least ");
1734 reallen = len;
1735 }
1736 printf("%d entries (%d bytes) in %s table.\n",
1737 reallen / ((0 == defect_format) ? 4 : 8), reallen,
1738 table ? "grown (GLIST)" : "primary (PLIST)");
1739 if (!sorthead)
1740 printf("Format (%x) is: %s\n", defect_format,
1741 formatname(defect_format));
1742 i = 0;
1743 switch (defect_format) {
1744 case 4: /* bytes from index */
1745 while (len > 0) {
1746 snprintf((char *)cbuffer1, 40, "%6d:%3u:%8d",
1747 getnbyte(df, 3), df[3], getnbyte(df + 4, 4));
1748 if (sorthead == 0)
1749 printf("%19s", (char *)cbuffer1);
1750 else
1751 if (df[3] < MAX_HEADS) headsp[df[3]]++;
1752 len -= 8;
1753 df += 8;
1754 i++;
1755 if (i >= 4 && !sorthead) {
1756 printf("\n");
1757 i = 0;
1758 }
1759 else if (!sorthead) printf("|");
1760 }
1761 break;
1762 case 5: /* physical sector */
1763 while (len > 0) {
1764 snprintf((char *)cbuffer1, 40, "%6d:%2u:%5d",
1765 getnbyte(df, 3),
1766 df[3], getnbyte(df + 4, 4));
1767 if (sorthead == 0)
1768 printf("%15s", (char *)cbuffer1);
1769 else
1770 if (df[3] < MAX_HEADS) headsp[df[3]]++;
1771 len -= 8;
1772 df += 8;
1773 i++;
1774 if (i >= 5 && !sorthead) {
1775 printf("\n");
1776 i = 0;
1777 }
1778 else if (!sorthead) printf("|");
1779 }
1780 break;
1781 case 0: /* lba (32 bit) */
1782 while (len > 0) {
1783 printf("%10d", getnbyte(df, 4));
1784 len -= 4;
1785 df += 4;
1786 i++;
1787 if (i >= 7) {
1788 printf("\n");
1789 i = 0;
1790 }
1791 else
1792 printf("|");
1793 }
1794 break;
1795 case 3: /* lba (64 bit) */
1796 while (len > 0) {
1797 printf("%15" PRId64 , getnbyte_ll(df, 8));
1798 len -= 8;
1799 df += 8;
1800 i++;
1801 if (i >= 5) {
1802 printf("\n");
1803 i = 0;
1804 }
1805 else
1806 printf("|");
1807 }
1808 break;
1809 default:
1810 printf("unknown defect list format: %d\n", defect_format);
1811 break;
1812 }
1813 if (i && !sorthead)
1814 printf("\n");
1815 }
1816 if (trunc)
1817 printf("[truncated]\n");
1818 }
1819 if (heapp) {
1820 free(heapp);
1821 heapp = NULL;
1822 }
1823 if (sorthead) {
1824 printf("Format is: [head:# entries for this head in list]\n\n");
1825 for (i=0; i<MAX_HEADS; i++) {
1826 if (headsp[i] > 0) {
1827 printf("%3d: %u\n", i, headsp[i]);
1828 }
1829 }
1830 free(headsp);
1831 }
1832 printf("\n");
1833 return status;
1834 }
1835
1836 static int
disk_cache(struct mpage_info * mpi,const char * prefix)1837 disk_cache(struct mpage_info * mpi, const char * prefix)
1838 {
1839 int status;
1840 uint8_t *pagestart;
1841
1842 status = setup_mode_page(mpi, 21, cbuffer, &pagestart);
1843 if (status)
1844 return status;
1845
1846 if (prefix[0])
1847 printf("%s", prefix);
1848 if (!x_interface && !replace) {
1849 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1850 printf("-----------------------\n");
1851 };
1852 bitfield(pagestart + 2, "Initiator Control", 1, 7);
1853 bitfield(pagestart + 2, "ABPF", 1, 6);
1854 bitfield(pagestart + 2, "CAP", 1, 5);
1855 bitfield(pagestart + 2, "DISC", 1, 4);
1856 bitfield(pagestart + 2, "SIZE", 1, 3);
1857 bitfield(pagestart + 2, "Write Cache Enabled", 1, 2);
1858 bitfield(pagestart + 2, "MF", 1, 1);
1859 bitfield(pagestart + 2, "Read Cache Disabled", 1, 0);
1860 bitfield(pagestart + 3, "Demand Read Retention Priority", 0xf, 4);
1861 bitfield(pagestart + 3, "Demand Write Retention Priority", 0xf, 0);
1862 intfield(pagestart + 4, 2, "Disable Pre-fetch Transfer Length");
1863 intfield(pagestart + 6, 2, "Minimum Pre-fetch");
1864 intfield(pagestart + 8, 2, "Maximum Pre-fetch");
1865 intfield(pagestart + 10, 2, "Maximum Pre-fetch Ceiling");
1866 bitfield(pagestart + 12, "FSW", 1, 7);
1867 bitfield(pagestart + 12, "LBCSS", 1, 6);
1868 bitfield(pagestart + 12, "DRA", 1, 5);
1869 bitfield(pagestart + 12, "NV_DIS", 1, 0);
1870 intfield(pagestart + 13, 1, "Number of Cache Segments");
1871 intfield(pagestart + 14, 2, "Cache Segment size");
1872 intfield(pagestart + 17, 3, "Non-Cache Segment size");
1873 if (x_interface && replace)
1874 return put_mode_page(mpi, cbuffer);
1875 else
1876 printf("\n");
1877 return 0;
1878 }
1879
1880 static int
disk_format(struct mpage_info * mpi,const char * prefix)1881 disk_format(struct mpage_info * mpi, const char * prefix)
1882 {
1883 int status;
1884 uint8_t *pagestart;
1885
1886 status = setup_mode_page(mpi, 13, cbuffer, &pagestart);
1887 if (status)
1888 return status;
1889
1890 if (prefix[0])
1891 printf("%s", prefix);
1892 if (!x_interface && !replace) {
1893 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1894 printf("-----------------------------\n");
1895 };
1896 intfield(pagestart + 2, 2, "Tracks per Zone");
1897 intfield(pagestart + 4, 2, "Alternate sectors per zone");
1898 intfield(pagestart + 6, 2, "Alternate tracks per zone");
1899 intfield(pagestart + 8, 2, "Alternate tracks per lu");
1900 intfield(pagestart + 10, 2, "Sectors per track");
1901 intfield(pagestart + 12, 2, "Data bytes per physical sector");
1902 intfield(pagestart + 14, 2, "Interleave");
1903 intfield(pagestart + 16, 2, "Track skew factor");
1904 intfield(pagestart + 18, 2, "Cylinder skew factor");
1905 bitfield(pagestart + 20, "Supports Soft Sectoring", 1, 7);
1906 bitfield(pagestart + 20, "Supports Hard Sectoring", 1, 6);
1907 bitfield(pagestart + 20, "Removable Medium", 1, 5);
1908 bitfield(pagestart + 20, "Surface", 1, 4);
1909 if (x_interface && replace)
1910 return put_mode_page(mpi, cbuffer);
1911 else
1912 printf("\n");
1913 return 0;
1914
1915 }
1916
1917 static int
disk_verify_error_recovery(struct mpage_info * mpi,const char * prefix)1918 disk_verify_error_recovery(struct mpage_info * mpi, const char * prefix)
1919 {
1920 int status;
1921 uint8_t *pagestart;
1922
1923 status = setup_mode_page(mpi, 7, cbuffer, &pagestart);
1924 if (status)
1925 return status;
1926
1927 if (prefix[0])
1928 printf("%s", prefix);
1929 if (!x_interface && !replace) {
1930 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1931 printf("-------------------------------------\n");
1932 }
1933 bitfield(pagestart + 2, "EER", 1, 3);
1934 bitfield(pagestart + 2, "PER", 1, 2);
1935 bitfield(pagestart + 2, "DTE", 1, 1);
1936 bitfield(pagestart + 2, "DCR", 1, 0);
1937 intfield(pagestart + 3, 1, "Verify Retry Count");
1938 intfield(pagestart + 4, 1, "Verify Correction Span (bits)");
1939 intfield(pagestart + 10, 2, "Verify Recovery Time Limit (ms)");
1940
1941 if (x_interface && replace)
1942 return put_mode_page(mpi, cbuffer);
1943 else
1944 printf("\n");
1945 return 0;
1946 }
1947
1948 #if 0
1949 static int
1950 peripheral_device_page(struct mpage_info * mpi, const char * prefix)
1951 {
1952 static char *idents[] =
1953 {
1954 "X3.131: Small Computer System Interface",
1955 "X3.91M-1987: Storage Module Interface",
1956 "X3.170: Enhanced Small Device Interface",
1957 "X3.130-1986; X3T9.3/87-002: IPI-2",
1958 "X3.132-1987; X3.147-1988: IPI-3"
1959 };
1960 int status;
1961 unsigned ident;
1962 uint8_t *pagestart;
1963 char *name;
1964
1965 status = setup_mode_page(mpi, 2, cbuffer, &pagestart);
1966 if (status)
1967 return status;
1968
1969 if (prefix[0])
1970 printf("%s", prefix);
1971 if (!x_interface && !replace) {
1972 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
1973 printf("---------------------------------\n");
1974 };
1975
1976 #if 0
1977 dump(pagestart, 20);
1978 pagestart[1] += 2; /*TEST */
1979 cbuffer[8] += 2; /*TEST */
1980 #endif
1981
1982 ident = getnbyte(pagestart + 2, 2);
1983 if (ident < (sizeof(idents) / sizeof(char *)))
1984 name = idents[ident];
1985 else if (ident < 0x8000)
1986 name = "Reserved";
1987 else
1988 name = "Vendor Specific";
1989
1990 #ifdef DPG_CHECK_THIS_OUT
1991 bdlen = pagestart[1] - 6;
1992 if (bdlen < 0)
1993 bdlen = 0;
1994 else {
1995 status = setup_mode_page(mpi, 2, cbuffer, &bdlen,
1996 &pagestart);
1997 if (status)
1998 return status;
1999 }
2000
2001 hexfield(pagestart + 2, 2, "Interface Identifier");
2002 if (!x_interface) {
2003 for (ident = 0; ident < 35; ident++)
2004 putchar(' ');
2005 puts(name);
2006 }
2007 hexdatafield(pagestart + 8, bdlen, "Vendor Specific Data");
2008 #endif
2009
2010 if (x_interface && replace)
2011 return put_mode_page(mpi, cbuffer);
2012 else
2013 printf("\n");
2014 if (x_interface)
2015 puts(name);
2016 return 0;
2017 }
2018 #endif
2019
2020 static int
common_power_condition(struct mpage_info * mpi,const char * prefix)2021 common_power_condition(struct mpage_info * mpi, const char * prefix)
2022 {
2023 int status;
2024 uint8_t *pagestart;
2025
2026 status = setup_mode_page(mpi, 4, cbuffer, &pagestart);
2027 if (status)
2028 return status;
2029
2030 if (prefix[0])
2031 printf("%s", prefix);
2032 if (!x_interface && !replace) {
2033 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2034 printf("--------------------------------\n");
2035 }
2036 bitfield(pagestart + 3, "Idle", 1, 1);
2037 bitfield(pagestart + 3, "Standby", 1, 0);
2038 intfield(pagestart + 4, 4, "Idle Condition counter (100ms)");
2039 intfield(pagestart + 8, 4, "Standby Condition counter (100ms)");
2040
2041 if (x_interface && replace)
2042 return put_mode_page(mpi, cbuffer);
2043 else
2044 printf("\n");
2045 return 0;
2046 }
2047
2048 static int
disk_xor_control(struct mpage_info * mpi,const char * prefix)2049 disk_xor_control(struct mpage_info * mpi, const char * prefix)
2050 {
2051 int status;
2052 uint8_t *pagestart;
2053
2054 status = setup_mode_page(mpi, 5, cbuffer, &pagestart);
2055 if (status)
2056 return status;
2057
2058 if (prefix[0])
2059 printf("%s", prefix);
2060 if (!x_interface && !replace) {
2061 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2062 printf("--------------------------------\n");
2063 }
2064 bitfield(pagestart + 2, "XORDS", 1, 1);
2065 intfield(pagestart + 4, 4, "Maximum XOR write size");
2066 intfield(pagestart + 12, 4, "Maximum regenerate size");
2067 intfield(pagestart + 16, 4, "Maximum rebuild transfer size");
2068 intfield(pagestart + 22, 2, "Rebuild delay");
2069
2070 if (x_interface && replace)
2071 return put_mode_page(mpi, cbuffer);
2072 else
2073 printf("\n");
2074 return 0;
2075 }
2076
2077 static int
disk_background(struct mpage_info * mpi,const char * prefix)2078 disk_background(struct mpage_info * mpi, const char * prefix)
2079 {
2080 int status;
2081 uint8_t *pagestart;
2082
2083 status = setup_mode_page(mpi, 4, cbuffer, &pagestart);
2084 if (status)
2085 return status;
2086
2087 if (prefix[0])
2088 printf("%s", prefix);
2089 if (!x_interface && !replace) {
2090 printf("%s mode subpage (0x%x,0x%x)\n", get_page_name(mpi), mpi->page,
2091 mpi->subpage);
2092 printf("--------------------------------------------\n");
2093 }
2094 bitfield(pagestart + 4, "Enable background medium scan", 1, 0);
2095 bitfield(pagestart + 5, "Enable pre-scan", 1, 0);
2096 intfield(pagestart + 6, 2, "BMS interval time (hour)");
2097 intfield(pagestart + 8, 2, "Pre-scan timeout value (hour)");
2098
2099 if (x_interface && replace)
2100 return put_mode_page(mpi, cbuffer);
2101 else
2102 printf("\n");
2103 return 0;
2104 }
2105
2106 static int
optical_memory(struct mpage_info * mpi,const char * prefix)2107 optical_memory(struct mpage_info * mpi, const char * prefix)
2108 {
2109 int status;
2110 uint8_t *pagestart;
2111
2112 status = setup_mode_page(mpi, 1, cbuffer, &pagestart);
2113 if (status)
2114 return status;
2115
2116 if (prefix[0])
2117 printf("%s", prefix);
2118 if (!x_interface && !replace) {
2119 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2120 printf("--------------------------------\n");
2121 }
2122 bitfield(pagestart + 2, "RUBR", 1, 0);
2123
2124 if (x_interface && replace)
2125 return put_mode_page(mpi, cbuffer);
2126 else
2127 printf("\n");
2128 return 0;
2129 }
2130
2131 static int
cdvd_write_param(struct mpage_info * mpi,const char * prefix)2132 cdvd_write_param(struct mpage_info * mpi, const char * prefix)
2133 {
2134 int status;
2135 uint8_t *pagestart;
2136
2137 status = setup_mode_page(mpi, 20, cbuffer, &pagestart);
2138 if (status)
2139 return status;
2140
2141 if (prefix[0])
2142 printf("%s", prefix);
2143 if (!x_interface && !replace) {
2144 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2145 printf("--------------------------------\n");
2146 }
2147 bitfield(pagestart + 2, "BUFE", 1, 6);
2148 bitfield(pagestart + 2, "LS_V", 1, 5);
2149 bitfield(pagestart + 2, "Test Write", 1, 4);
2150 bitfield(pagestart + 2, "Write Type", 0xf, 0);
2151 bitfield(pagestart + 3, "MultiSession", 3, 6);
2152 bitfield(pagestart + 3, "FP", 1, 5);
2153 bitfield(pagestart + 3, "Copy", 1, 4);
2154 bitfield(pagestart + 3, "Track Mode", 0xf, 0);
2155 bitfield(pagestart + 4, "Data Block type", 0xf, 0);
2156 intfield(pagestart + 5, 1, "Link size");
2157 bitfield(pagestart + 7, "Initiator app. code", 0x3f, 0);
2158 intfield(pagestart + 8, 1, "Session Format");
2159 intfield(pagestart + 10, 4, "Packet size");
2160 intfield(pagestart + 14, 2, "Audio Pause Length");
2161 hexdatafield(pagestart + 16, 16, "Media Catalog number");
2162 hexdatafield(pagestart + 32, 16, "Int. standard recording code");
2163 hexdatafield(pagestart + 48, 1, "Subheader byte 1");
2164 hexdatafield(pagestart + 49, 1, "Subheader byte 2");
2165 hexdatafield(pagestart + 50, 1, "Subheader byte 3");
2166 hexdatafield(pagestart + 51, 1, "Subheader byte 4");
2167
2168 if (x_interface && replace)
2169 return put_mode_page(mpi, cbuffer);
2170 else
2171 printf("\n");
2172 return 0;
2173 }
2174
2175 static int
cdvd_audio_control(struct mpage_info * mpi,const char * prefix)2176 cdvd_audio_control(struct mpage_info * mpi, const char * prefix)
2177 {
2178 int status;
2179 uint8_t *pagestart;
2180
2181 status = setup_mode_page(mpi, 10, cbuffer, &pagestart);
2182 if (status)
2183 return status;
2184
2185 if (prefix[0])
2186 printf("%s", prefix);
2187 if (!x_interface && !replace) {
2188 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2189 printf("--------------------------------\n");
2190 }
2191 bitfield(pagestart + 2, "IMMED", 1, 2);
2192 bitfield(pagestart + 2, "SOTC", 1, 1);
2193 bitfield(pagestart + 8, "CDDA out port 0, channel select", 0xf, 0);
2194 intfield(pagestart + 9, 1, "Channel port 0 volume");
2195 bitfield(pagestart + 10, "CDDA out port 1, channel select", 0xf, 0);
2196 intfield(pagestart + 11, 1, "Channel port 1 volume");
2197 bitfield(pagestart + 12, "CDDA out port 2, channel select", 0xf, 0);
2198 intfield(pagestart + 13, 1, "Channel port 2 volume");
2199 bitfield(pagestart + 14, "CDDA out port 3, channel select", 0xf, 0);
2200 intfield(pagestart + 15, 1, "Channel port 3 volume");
2201
2202 if (x_interface && replace)
2203 return put_mode_page(mpi, cbuffer);
2204 else
2205 printf("\n");
2206 return 0;
2207 }
2208
2209 static int
cdvd_timeout(struct mpage_info * mpi,const char * prefix)2210 cdvd_timeout(struct mpage_info * mpi, const char * prefix)
2211 {
2212 int status;
2213 uint8_t *pagestart;
2214
2215 status = setup_mode_page(mpi, 6, cbuffer, &pagestart);
2216 if (status)
2217 return status;
2218
2219 if (prefix[0])
2220 printf("%s", prefix);
2221 if (!x_interface && !replace) {
2222 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2223 printf("-----------------------------------\n");
2224 }
2225 bitfield(pagestart + 4, "G3Enable", 1, 3);
2226 bitfield(pagestart + 4, "TMOE", 1, 2);
2227 bitfield(pagestart + 4, "DISP", 1, 1);
2228 bitfield(pagestart + 4, "SWPP", 1, 0);
2229 intfield(pagestart + 6, 2, "Group 1 minimum time-out");
2230 intfield(pagestart + 8, 2, "Group 2 minimum time-out");
2231
2232 if (x_interface && replace)
2233 return put_mode_page(mpi, cbuffer);
2234 else
2235 printf("\n");
2236 return 0;
2237 }
2238
2239 static int
cdvd_device_param(struct mpage_info * mpi,const char * prefix)2240 cdvd_device_param(struct mpage_info * mpi, const char * prefix)
2241 {
2242 int status;
2243 uint8_t *pagestart;
2244
2245 status = setup_mode_page(mpi, 3, cbuffer, &pagestart);
2246 if (status)
2247 return status;
2248
2249 if (prefix[0])
2250 printf("%s", prefix);
2251 if (!x_interface && !replace) {
2252 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2253 printf("------------------------------------\n");
2254 }
2255 bitfield(pagestart + 3, "Inactivity timer multiplier", 0xf, 0);
2256 intfield(pagestart + 4, 2, "MSF-S units per MSF_M unit");
2257 intfield(pagestart + 6, 2, "MSF-F units per MSF_S unit");
2258
2259 if (x_interface && replace)
2260 return put_mode_page(mpi, cbuffer);
2261 else
2262 printf("\n");
2263 return 0;
2264 }
2265
2266 /* This is not a standard t10.org MMC mode page (it is now "protocol specific
2267 lu" mode page). This definition was found in Hitachi GF-2050/GF-2055
2268 DVD-RAM drive SCSI reference manual. */
2269 static int
cdvd_feature(struct mpage_info * mpi,const char * prefix)2270 cdvd_feature(struct mpage_info * mpi, const char * prefix)
2271 {
2272 int status;
2273 uint8_t *pagestart;
2274
2275 status = setup_mode_page(mpi, 12, cbuffer, &pagestart);
2276 if (status)
2277 return status;
2278
2279 if (prefix[0])
2280 printf("%s", prefix);
2281 if (!x_interface && !replace) {
2282 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2283 printf("----------------------------------------------\n");
2284 }
2285 intfield(pagestart + 2, 2, "DVD feature set");
2286 intfield(pagestart + 4, 2, "CD audio");
2287 intfield(pagestart + 6, 2, "Embedded changer");
2288 intfield(pagestart + 8, 2, "Packet SMART");
2289 intfield(pagestart + 10, 2, "Persistent prevent(MESN)");
2290 intfield(pagestart + 12, 2, "Event status notification");
2291 intfield(pagestart + 14, 2, "Digital output");
2292 intfield(pagestart + 16, 2, "CD sequential recordable");
2293 intfield(pagestart + 18, 2, "DVD sequential recordable");
2294 intfield(pagestart + 20, 2, "Random recordable");
2295 intfield(pagestart + 22, 2, "Key management");
2296 intfield(pagestart + 24, 2, "Partial recorded CD media read");
2297
2298 if (x_interface && replace)
2299 return put_mode_page(mpi, cbuffer);
2300 else
2301 printf("\n");
2302 return 0;
2303 }
2304
2305 static int
cdvd_mm_capab(struct mpage_info * mpi,const char * prefix)2306 cdvd_mm_capab(struct mpage_info * mpi, const char * prefix)
2307 {
2308 int status;
2309 uint8_t *pagestart;
2310
2311 status = setup_mode_page(mpi, 49, cbuffer, &pagestart);
2312 if (status)
2313 return status;
2314
2315 if (prefix[0])
2316 printf("%s", prefix);
2317 if (!x_interface && !replace) {
2318 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2319 printf("----------------------------------------------------\n");
2320 }
2321 bitfield(pagestart + 2, "DVD-RAM read", 1, 5);
2322 bitfield(pagestart + 2, "DVD-R read", 1, 4);
2323 bitfield(pagestart + 2, "DVD-ROM read", 1, 3);
2324 bitfield(pagestart + 2, "Method 2", 1, 2);
2325 bitfield(pagestart + 2, "CD-RW read", 1, 1);
2326 bitfield(pagestart + 2, "CD-R read", 1, 0);
2327 bitfield(pagestart + 3, "DVD-RAM write", 1, 5);
2328 bitfield(pagestart + 3, "DVD-R write", 1, 4);
2329 bitfield(pagestart + 3, "DVD-ROM write", 1, 3);
2330 bitfield(pagestart + 3, "Test Write", 1, 2);
2331 bitfield(pagestart + 3, "CD-RW write", 1, 1);
2332 bitfield(pagestart + 3, "CD-R write", 1, 0);
2333 bitfield(pagestart + 4, "BUF", 1, 7);
2334 bitfield(pagestart + 4, "MultiSession", 1, 6);
2335 bitfield(pagestart + 4, "Mode 2 Form 2", 1, 5);
2336 bitfield(pagestart + 4, "Mode 2 Form 1", 1, 4);
2337 bitfield(pagestart + 4, "Digital port (2)", 1, 3);
2338 bitfield(pagestart + 4, "Digital port (1)", 1, 2);
2339 bitfield(pagestart + 4, "Composite", 1, 1);
2340 bitfield(pagestart + 4, "Audio play", 1, 0);
2341 bitfield(pagestart + 5, "Read bar code", 1, 7);
2342 bitfield(pagestart + 5, "UPC", 1, 6);
2343 bitfield(pagestart + 5, "ISRC", 1, 5);
2344 bitfield(pagestart + 5, "C2 pointers supported", 1, 4);
2345 bitfield(pagestart + 5, "R-W de-interleaved & corrected", 1, 3);
2346 bitfield(pagestart + 5, "R-W supported", 1, 2);
2347 bitfield(pagestart + 5, "CD-DA stream is accurate", 1, 1);
2348 bitfield(pagestart + 5, "CD-DA commands supported", 1, 0);
2349 bitfield(pagestart + 6, "Loading mechanism type", 7, 5);
2350 bitfield(pagestart + 6, "Eject (individual or magazine)", 1, 3);
2351 bitfield(pagestart + 6, "Prevent jumper", 1, 2);
2352 bitfield(pagestart + 6, "Lock state", 1, 1);
2353 bitfield(pagestart + 6, "Lock", 1, 0);
2354 bitfield(pagestart + 7, "R-W in lead-in", 1, 5);
2355 bitfield(pagestart + 7, "Side change capable", 1, 4);
2356 bitfield(pagestart + 7, "S/W slot selection", 1, 3);
2357 bitfield(pagestart + 7, "Changer supports disc present", 1, 2);
2358 bitfield(pagestart + 7, "Separate channel mute", 1, 1);
2359 bitfield(pagestart + 7, "Separate volume levels", 1, 0);
2360 intfield(pagestart + 10, 2, "number of volume level supported");
2361 intfield(pagestart + 12, 2, "Buffer size supported");
2362 bitfield(pagestart + 17, "Length", 3, 4);
2363 bitfield(pagestart + 17, "LSBF", 1, 3);
2364 bitfield(pagestart + 17, "RCK", 1, 2);
2365 bitfield(pagestart + 17, "BCKF", 1, 1);
2366 intfield(pagestart + 22, 2, "Copy management revision supported");
2367 bitfield(pagestart + 27, "Rotation control selected", 3, 0);
2368 intfield(pagestart + 28, 2, "Current write speed selected");
2369 intfield(pagestart + 30, 2, "# of lu speed performance tables");
2370
2371 if (x_interface && replace)
2372 return put_mode_page(mpi, cbuffer);
2373 else
2374 printf("\n");
2375 return 0;
2376 }
2377
2378 static int
cdvd_cache(struct mpage_info * mpi,const char * prefix)2379 cdvd_cache(struct mpage_info * mpi, const char * prefix)
2380 {
2381 int status;
2382 uint8_t *pagestart;
2383
2384 status = setup_mode_page(mpi, 2, cbuffer, &pagestart);
2385 if (status)
2386 return status;
2387
2388 if (prefix[0])
2389 printf("%s", prefix);
2390 if (!x_interface && !replace) {
2391 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2392 printf("-----------------------\n");
2393 };
2394 bitfield(pagestart + 2, "Write Cache Enabled", 1, 2);
2395 bitfield(pagestart + 2, "Read Cache Disabled", 1, 0);
2396 if (x_interface && replace)
2397 return put_mode_page(mpi, cbuffer);
2398 else
2399 printf("\n");
2400 return 0;
2401 }
2402
2403 static int
tape_data_compression(struct mpage_info * mpi,const char * prefix)2404 tape_data_compression(struct mpage_info * mpi, const char * prefix)
2405 {
2406 int status;
2407 uint8_t *pagestart;
2408
2409 status = setup_mode_page(mpi, 6, cbuffer, &pagestart);
2410 if (status)
2411 return status;
2412
2413 if (prefix[0])
2414 printf("%s", prefix);
2415 if (!x_interface && !replace) {
2416 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2417 printf("----------------------------------------------------\n");
2418 }
2419 bitfield(pagestart + 2, "DCE", 1, 7);
2420 bitfield(pagestart + 2, "DCC", 1, 6);
2421 bitfield(pagestart + 3, "DDE", 1, 7);
2422 bitfield(pagestart + 3, "RED", 3, 5);
2423 intfield(pagestart + 4, 4, "Compression algorithm");
2424 intfield(pagestart + 8, 4, "Decompression algorithm");
2425
2426 if (x_interface && replace)
2427 return put_mode_page(mpi, cbuffer);
2428 else
2429 printf("\n");
2430 return 0;
2431 }
2432
2433 static int
tape_dev_config(struct mpage_info * mpi,const char * prefix)2434 tape_dev_config(struct mpage_info * mpi, const char * prefix)
2435 {
2436 int status;
2437 uint8_t *pagestart;
2438
2439 status = setup_mode_page(mpi, 25, cbuffer, &pagestart);
2440 if (status)
2441 return status;
2442
2443 if (prefix[0])
2444 printf("%s", prefix);
2445 if (!x_interface && !replace) {
2446 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2447 printf("----------------------------------------------------\n");
2448 }
2449 bitfield(pagestart + 2, "CAF", 1, 5);
2450 bitfield(pagestart + 2, "Active format", 0x1f, 0);
2451 intfield(pagestart + 3, 1, "Active partition");
2452 intfield(pagestart + 4, 1, "Write object cbuffer full ratio");
2453 intfield(pagestart + 5, 1, "Read object cbuffer full ratio");
2454 intfield(pagestart + 6, 2, "Wire delay time");
2455 bitfield(pagestart + 8, "OBR", 1, 7);
2456 bitfield(pagestart + 8, "LOIS", 1, 6);
2457 bitfield(pagestart + 8, "RSMK", 1, 5);
2458 bitfield(pagestart + 8, "AVC", 1, 4);
2459 bitfield(pagestart + 8, "SOCF", 3, 2);
2460 bitfield(pagestart + 8, "ROBO", 1, 1);
2461 bitfield(pagestart + 8, "REW", 1, 0);
2462 intfield(pagestart + 9, 1, "Gap size");
2463 bitfield(pagestart + 10, "EOD defined", 7, 5);
2464 bitfield(pagestart + 10, "EEG", 1, 4);
2465 bitfield(pagestart + 10, "SEW", 1, 3);
2466 bitfield(pagestart + 10, "SWP", 1, 2);
2467 bitfield(pagestart + 10, "BAML", 1, 1);
2468 bitfield(pagestart + 10, "BAM", 1, 0);
2469 intfield(pagestart + 11, 3, "Object cbuffer size at early warning");
2470 intfield(pagestart + 14, 1, "Select data compression algorithm");
2471 bitfield(pagestart + 15, "ASOCWP", 1, 2);
2472 bitfield(pagestart + 15, "PERSWO", 1, 1);
2473 bitfield(pagestart + 15, "PRMWP", 1, 0);
2474
2475 if (x_interface && replace)
2476 return put_mode_page(mpi, cbuffer);
2477 else
2478 printf("\n");
2479 return 0;
2480 }
2481
2482 static int
tape_medium_part1(struct mpage_info * mpi,const char * prefix)2483 tape_medium_part1(struct mpage_info * mpi, const char * prefix)
2484 {
2485 int status, off, len;
2486 uint8_t *pagestart;
2487
2488 /* variable length mode page, need to know its response length */
2489 status = get_mode_page(mpi, 0, cbuffer);
2490 if (status)
2491 return status;
2492 off = modePageOffset(cbuffer, mpi->resp_len, mode6byte);
2493 if (off < 0)
2494 return off;
2495 len = mpi->resp_len - off;
2496
2497 status = setup_mode_page(mpi, 12 + ((len - 10) / 2), cbuffer, &pagestart);
2498 if (status)
2499 return status;
2500
2501 if (prefix[0])
2502 printf("%s", prefix);
2503 if (!x_interface && !replace) {
2504 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2505 printf("----------------------------------------------------\n");
2506 }
2507 intfield(pagestart + 2, 1, "Maximum additional partitions");
2508 intfield(pagestart + 3, 1, "Additional partitions defined");
2509 bitfield(pagestart + 4, "FDP", 1, 7);
2510 bitfield(pagestart + 4, "SDP", 1, 6);
2511 bitfield(pagestart + 4, "IDP", 1, 5);
2512 bitfield(pagestart + 4, "PSUM", 3, 3);
2513 bitfield(pagestart + 4, "POFM", 1, 2);
2514 bitfield(pagestart + 4, "CLEAR", 1, 1);
2515 bitfield(pagestart + 4, "ADDP", 1, 0);
2516 intfield(pagestart + 5, 1, "Medium format recognition");
2517 bitfield(pagestart + 6, "Partition units", 0xf, 0);
2518 intfield(pagestart + 8, 2, "Partition size");
2519
2520 for (off = 10; off < len; off += 2)
2521 intfield(pagestart + off, 2, "Partition size");
2522
2523 if (x_interface && replace)
2524 return put_mode_page(mpi, cbuffer);
2525 else
2526 printf("\n");
2527 return 0;
2528 }
2529
2530 static int
tape_medium_part2_4(struct mpage_info * mpi,const char * prefix)2531 tape_medium_part2_4(struct mpage_info * mpi, const char * prefix)
2532 {
2533 int status, off, len;
2534 uint8_t *pagestart;
2535
2536 /* variable length mode page, need to know its response length */
2537 status = get_mode_page(mpi, 0, cbuffer);
2538 if (status)
2539 return status;
2540 off = modePageOffset(cbuffer, mpi->resp_len, mode6byte);
2541 if (off < 0)
2542 return off;
2543 len = mpi->resp_len - off;
2544
2545 status = setup_mode_page(mpi, 1 + ((len - 4) / 2), cbuffer, &pagestart);
2546 if (status)
2547 return status;
2548
2549 if (prefix[0])
2550 printf("%s", prefix);
2551 if (!x_interface && !replace) {
2552 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2553 printf("----------------------------------------------------\n");
2554 }
2555 intfield(pagestart + 2, 2, "Partition size");
2556
2557 for (off = 4; off < len; off += 2)
2558 intfield(pagestart + off, 2, "Partition size");
2559
2560 if (x_interface && replace)
2561 return put_mode_page(mpi, cbuffer);
2562 else
2563 printf("\n");
2564 return 0;
2565 }
2566
2567 static int
ses_services_manag(struct mpage_info * mpi,const char * prefix)2568 ses_services_manag(struct mpage_info * mpi, const char * prefix)
2569 {
2570 int status;
2571 uint8_t *pagestart;
2572
2573 status = setup_mode_page(mpi, 2, cbuffer, &pagestart);
2574 if (status)
2575 return status;
2576
2577 if (prefix[0])
2578 printf("%s", prefix);
2579 if (!x_interface && !replace) {
2580 printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page);
2581 printf("----------------------------------------------------\n");
2582 }
2583 bitfield(pagestart + 5, "ENBLTC", 1, 0);
2584 intfield(pagestart + 6, 2, "Maximum time to completion (100 ms units)");
2585
2586 if (x_interface && replace)
2587 return put_mode_page(mpi, cbuffer);
2588 else
2589 printf("\n");
2590 return 0;
2591 }
2592
2593 static int
fcp_proto_spec_lu(struct mpage_info * mpi,const char * prefix)2594 fcp_proto_spec_lu(struct mpage_info * mpi, const char * prefix)
2595 {
2596 int status;
2597 uint8_t *pagestart;
2598
2599 status = setup_mode_page(mpi, 1, cbuffer, &pagestart);
2600 if (status)
2601 return status;
2602
2603 if (prefix[0])
2604 printf("%s", prefix);
2605 if (!x_interface && !replace) {
2606 printf("%s mode page (0x%x)\n", "Fibre Channel logical unit",
2607 mpi->page);
2608 printf("----------------------------------------------------\n");
2609 }
2610 bitfield(pagestart + 3, "EPDC", 1, 0);
2611
2612 if (x_interface && replace)
2613 return put_mode_page(mpi, cbuffer);
2614 else
2615 printf("\n");
2616 return 0;
2617 }
2618
2619 static int
sas_proto_spec_lu(struct mpage_info * mpi,const char * prefix)2620 sas_proto_spec_lu(struct mpage_info * mpi, const char * prefix)
2621 {
2622 int status;
2623 uint8_t *pagestart;
2624
2625 status = setup_mode_page(mpi, 1, cbuffer, &pagestart);
2626 if (status)
2627 return status;
2628
2629 if (prefix[0])
2630 printf("%s", prefix);
2631 if (!x_interface && !replace) {
2632 printf("%s mode page (0x%x)\n", "SAS logical unit", mpi->page);
2633 printf("----------------------------------------------------\n");
2634 }
2635 bitfield(pagestart + 2, "Transport Layer Retries", 1, 4);
2636
2637 if (x_interface && replace)
2638 return put_mode_page(mpi, cbuffer);
2639 else
2640 printf("\n");
2641 return 0;
2642 }
2643
2644 static int
common_proto_spec_lu(struct mpage_info * mpi,const char * prefix)2645 common_proto_spec_lu(struct mpage_info * mpi, const char * prefix)
2646 {
2647 int status;
2648 int proto_id = 0;
2649
2650 status = get_protocol_id(0, cbuffer, &proto_id, NULL);
2651 if (status)
2652 return status;
2653 if (0 == proto_id)
2654 return fcp_proto_spec_lu(mpi, prefix);
2655 else if (6 == proto_id)
2656 return sas_proto_spec_lu(mpi, prefix);
2657 else
2658 return DECODE_FAILED_TRY_HEX;
2659 }
2660
2661 static int
fcp_proto_spec_port(struct mpage_info * mpi,const char * prefix)2662 fcp_proto_spec_port(struct mpage_info * mpi, const char * prefix)
2663 {
2664 int status;
2665 uint8_t *pagestart;
2666
2667 status = setup_mode_page(mpi, 10, cbuffer, &pagestart);
2668 if (status)
2669 return status;
2670
2671 if (prefix[0])
2672 printf("%s", prefix);
2673 if (!x_interface && !replace) {
2674 printf("%s mode page (0x%x)\n", "Fibre Channel port control",
2675 mpi->page);
2676 printf("----------------------------------------------------\n");
2677 }
2678 bitfield(pagestart + 3, "DTFD", 1, 7);
2679 bitfield(pagestart + 3, "PLPB", 1, 6);
2680 bitfield(pagestart + 3, "DDIS", 1, 5);
2681 bitfield(pagestart + 3, "DLM", 1, 4);
2682 bitfield(pagestart + 3, "RHA", 1, 3);
2683 bitfield(pagestart + 3, "ALWI", 1, 2);
2684 bitfield(pagestart + 3, "DTIPE", 1, 1);
2685 bitfield(pagestart + 3, "DTOLI", 1, 0);
2686 bitfield(pagestart + 6, "RR_TOV units", 7, 0);
2687 intfield(pagestart + 7, 1, "Resource recovery time-out");
2688
2689 if (x_interface && replace)
2690 return put_mode_page(mpi, cbuffer);
2691 else
2692 printf("\n");
2693 return 0;
2694 }
2695
2696 static int
spi4_proto_spec_port(struct mpage_info * mpi,const char * prefix)2697 spi4_proto_spec_port(struct mpage_info * mpi, const char * prefix)
2698 {
2699 int status;
2700 uint8_t *pagestart;
2701
2702 status = setup_mode_page(mpi, 1, cbuffer, &pagestart);
2703 if (status)
2704 return status;
2705
2706 if (prefix[0])
2707 printf("%s", prefix);
2708 if (!x_interface && !replace) {
2709 printf("%s mode page (0x%x)\n", "SPI-4 port control", mpi->page);
2710 printf("-----------------------------------\n");
2711 }
2712 intfield(pagestart + 4, 2, "Synchronous transfer time-out");
2713
2714 if (x_interface && replace)
2715 return put_mode_page(mpi, cbuffer);
2716 else
2717 printf("\n");
2718 return 0;
2719 }
2720
2721 /* Protocol specific mode page for SAS, short format (subpage 0) */
2722 static int
sas_proto_spec_port(struct mpage_info * mpi,const char * prefix)2723 sas_proto_spec_port(struct mpage_info * mpi, const char * prefix)
2724 {
2725 int status;
2726 uint8_t *pagestart;
2727
2728 status = setup_mode_page(mpi, 3, cbuffer, &pagestart);
2729 if (status)
2730 return status;
2731
2732 if (prefix[0])
2733 printf("%s", prefix);
2734 if (!x_interface && !replace) {
2735 printf("%s mode page (0x%x)\n", "SAS SSP port control", mpi->page);
2736 printf("-------------------------------------\n");
2737 }
2738 bitfield(pagestart + 2, "Ready LED meaning", 0x1, 4);
2739 intfield(pagestart + 4, 2, "I_T Nexus Loss time");
2740 intfield(pagestart + 6, 2, "Initiator response time-out");
2741
2742 if (x_interface && replace)
2743 return put_mode_page(mpi, cbuffer);
2744 else
2745 printf("\n");
2746 return 0;
2747 }
2748
2749 static int
common_proto_spec_port(struct mpage_info * mpi,const char * prefix)2750 common_proto_spec_port(struct mpage_info * mpi, const char * prefix)
2751 {
2752 int status;
2753 int proto_id = 0;
2754
2755 status = get_protocol_id(1, cbuffer, &proto_id, NULL);
2756 if (status)
2757 return status;
2758 if (0 == proto_id)
2759 return fcp_proto_spec_port(mpi, prefix);
2760 else if (1 == proto_id)
2761 return spi4_proto_spec_port(mpi, prefix);
2762 else if (6 == proto_id)
2763 return sas_proto_spec_port(mpi, prefix);
2764 else
2765 return DECODE_FAILED_TRY_HEX;
2766 }
2767
2768 static int
spi4_margin_control(struct mpage_info * mpi,const char * prefix)2769 spi4_margin_control(struct mpage_info * mpi, const char * prefix)
2770 {
2771 int status;
2772 uint8_t *pagestart;
2773
2774 status = setup_mode_page(mpi, 5, cbuffer, &pagestart);
2775 if (status)
2776 return status;
2777
2778 if (prefix[0])
2779 printf("%s", prefix);
2780 if (!x_interface && !replace) {
2781 printf("%s mode subpage (0x%x,0x%x)\n", "SPI-4 Margin control",
2782 mpi->page, mpi->subpage);
2783 printf("--------------------------------------------\n");
2784 }
2785 bitfield(pagestart + 5, "Protocol identifier", 0xf, 0);
2786 bitfield(pagestart + 7, "Driver Strength", 0xf, 4);
2787 bitfield(pagestart + 8, "Driver Asymmetry", 0xf, 4);
2788 bitfield(pagestart + 8, "Driver Precompensation", 0xf, 0);
2789 bitfield(pagestart + 9, "Driver Slew rate", 0xf, 4);
2790
2791 if (x_interface && replace)
2792 return put_mode_page(mpi, cbuffer);
2793 else
2794 printf("\n");
2795 return 0;
2796 }
2797
2798 /* Protocol specific mode page for SAS, phy control + discover (subpage 1) */
2799 static int
sas_phy_control_discover(struct mpage_info * mpi,const char * prefix)2800 sas_phy_control_discover(struct mpage_info * mpi, const char * prefix)
2801 {
2802 int status, off, num_phys, k;
2803 uint8_t *pagestart;
2804 uint8_t *p;
2805
2806 /* variable length mode page, need to know its response length */
2807 status = get_mode_page(mpi, 0, cbuffer);
2808 if (status)
2809 return status;
2810 off = modePageOffset(cbuffer, mpi->resp_len, mode6byte);
2811 if (off < 0)
2812 return off;
2813 num_phys = cbuffer[off + 7];
2814
2815 status = setup_mode_page(mpi, 1 + (16 * num_phys), cbuffer, &pagestart);
2816 if (status)
2817 return status;
2818
2819 if (prefix[0])
2820 printf("%s", prefix);
2821 if (!x_interface && !replace) {
2822 printf("%s mode subpage (0x%x,0x%x)\n", "SAS Phy Control and "
2823 "Discover", mpi->page, mpi->subpage);
2824 printf("--------------------------------------------\n");
2825 }
2826 intfield(pagestart + 7, 1, "Number of phys");
2827 for (k = 0, p = pagestart + 8; k < num_phys; ++k, p += 48) {
2828 intfield(p + 1, 1, "Phy Identifier");
2829 bitfield(p + 4, "Attached Device type", 0x7, 4);
2830 bitfield(p + 5, "Negotiated Logical Link rate", 0xf, 0);
2831 bitfield(p + 6, "Attached SSP Initiator port", 0x1, 3);
2832 bitfield(p + 6, "Attached STP Initiator port", 0x1, 2);
2833 bitfield(p + 6, "Attached SMP Initiator port", 0x1, 1);
2834 bitfield(p + 7, "Attached SSP Target port", 0x1, 3);
2835 bitfield(p + 7, "Attached STP Target port", 0x1, 2);
2836 bitfield(p + 7, "Attached SMP Target port", 0x1, 1);
2837 hexdatafield(p + 8, 8, "SAS address");
2838 hexdatafield(p + 16, 8, "Attached SAS address");
2839 intfield(p + 24, 1, "Attached Phy identifier");
2840 bitfield(p + 32, "Programmed Min Physical Link rate", 0xf, 4);
2841 bitfield(p + 32, "Hardware Min Physical Link rate", 0xf, 0);
2842 bitfield(p + 33, "Programmed Max Physical Link rate", 0xf, 4);
2843 bitfield(p + 33, "Hardware Max Physical Link rate", 0xf, 0);
2844 }
2845 if (x_interface && replace)
2846 return put_mode_page(mpi, cbuffer);
2847 else
2848 printf("\n");
2849 return 0;
2850 }
2851
2852
2853 static int
common_proto_spec_port_sp1(struct mpage_info * mpi,const char * prefix)2854 common_proto_spec_port_sp1(struct mpage_info * mpi, const char * prefix)
2855 {
2856 int status;
2857 int proto_id = 0;
2858
2859 status = get_protocol_id(1, cbuffer, &proto_id, NULL);
2860 if (status)
2861 return status;
2862 if (1 == proto_id)
2863 return spi4_margin_control(mpi, prefix);
2864 else if (6 == proto_id)
2865 return sas_phy_control_discover(mpi, prefix);
2866 else
2867 return DECODE_FAILED_TRY_HEX;
2868 }
2869
2870 static int
spi4_training_config(struct mpage_info * mpi,const char * prefix)2871 spi4_training_config(struct mpage_info * mpi, const char * prefix)
2872 {
2873 int status;
2874 uint8_t *pagestart;
2875
2876 status = setup_mode_page(mpi, 27, cbuffer, &pagestart);
2877 if (status)
2878 return status;
2879
2880 if (prefix[0])
2881 printf("%s", prefix);
2882 if (!x_interface && !replace) {
2883 printf("%s mode subpage (0x%x,0x%x)\n", "training configuration",
2884 mpi->page, mpi->subpage);
2885 printf("----------------------------------------------------------\n");
2886 }
2887 hexdatafield(pagestart + 10, 4, "DB(0) value");
2888 hexdatafield(pagestart + 14, 4, "DB(1) value");
2889 hexdatafield(pagestart + 18, 4, "DB(2) value");
2890 hexdatafield(pagestart + 22, 4, "DB(3) value");
2891 hexdatafield(pagestart + 26, 4, "DB(4) value");
2892 hexdatafield(pagestart + 30, 4, "DB(5) value");
2893 hexdatafield(pagestart + 34, 4, "DB(6) value");
2894 hexdatafield(pagestart + 38, 4, "DB(7) value");
2895 hexdatafield(pagestart + 42, 4, "DB(8) value");
2896 hexdatafield(pagestart + 46, 4, "DB(9) value");
2897 hexdatafield(pagestart + 50, 4, "DB(10) value");
2898 hexdatafield(pagestart + 54, 4, "DB(11) value");
2899 hexdatafield(pagestart + 58, 4, "DB(12) value");
2900 hexdatafield(pagestart + 62, 4, "DB(13) value");
2901 hexdatafield(pagestart + 66, 4, "DB(14) value");
2902 hexdatafield(pagestart + 70, 4, "DB(15) value");
2903 hexdatafield(pagestart + 74, 4, "P_CRCA value");
2904 hexdatafield(pagestart + 78, 4, "P1 value");
2905 hexdatafield(pagestart + 82, 4, "BSY value");
2906 hexdatafield(pagestart + 86, 4, "SEL value");
2907 hexdatafield(pagestart + 90, 4, "RST value");
2908 hexdatafield(pagestart + 94, 4, "REQ value");
2909 hexdatafield(pagestart + 98, 4, "ACK value");
2910 hexdatafield(pagestart + 102, 4, "ATN value");
2911 hexdatafield(pagestart + 106, 4, "C/D value");
2912 hexdatafield(pagestart + 110, 4, "I/O value");
2913 hexdatafield(pagestart + 114, 4, "MSG value");
2914
2915 if (x_interface && replace)
2916 return put_mode_page(mpi, cbuffer);
2917 else
2918 printf("\n");
2919 return 0;
2920 }
2921
2922 /* SAS(2) SSP, shared protocol specific port mode subpage (subpage 2) */
2923 static int
sas_shared_spec_port(struct mpage_info * mpi,const char * prefix)2924 sas_shared_spec_port(struct mpage_info * mpi, const char * prefix)
2925 {
2926 int status;
2927 uint8_t *pagestart;
2928
2929 status = setup_mode_page(mpi, 1, cbuffer, &pagestart);
2930 if (status)
2931 return status;
2932
2933 if (prefix[0])
2934 printf("%s", prefix);
2935 if (!x_interface && !replace) {
2936 printf("%s mode subpage (0x%x,0x%x)\n", "SAS SSP shared protocol "
2937 "specific port", mpi->page, mpi->subpage);
2938 printf("-----------------------------------------------------\n");
2939 }
2940 intfield(pagestart + 6, 2, "Power loss timeout(ms)");
2941
2942 if (x_interface && replace)
2943 return put_mode_page(mpi, cbuffer);
2944 else
2945 printf("\n");
2946 return 0;
2947 }
2948
2949 static int
common_proto_spec_port_sp2(struct mpage_info * mpi,const char * prefix)2950 common_proto_spec_port_sp2(struct mpage_info * mpi, const char * prefix)
2951 {
2952 int status;
2953 int proto_id = 0;
2954
2955 status = get_protocol_id(1, cbuffer, &proto_id, NULL);
2956 if (status)
2957 return status;
2958 if (1 == proto_id)
2959 return spi4_training_config(mpi, prefix);
2960 else if (6 == proto_id)
2961 return sas_shared_spec_port(mpi, prefix);
2962 else
2963 return DECODE_FAILED_TRY_HEX;
2964 }
2965
2966 static int
spi4_negotiated(struct mpage_info * mpi,const char * prefix)2967 spi4_negotiated(struct mpage_info * mpi, const char * prefix)
2968 {
2969 int status;
2970 uint8_t *pagestart;
2971
2972 status = setup_mode_page(mpi, 7, cbuffer, &pagestart);
2973 if (status)
2974 return status;
2975
2976 if (prefix[0])
2977 printf("%s", prefix);
2978 if (!x_interface && !replace) {
2979 printf("%s mode subpage (0x%x,0x%x)\n", get_page_name(mpi), mpi->page,
2980 mpi->subpage);
2981 printf("--------------------------------------------\n");
2982 }
2983 intfield(pagestart + 6, 1, "Transfer period");
2984 intfield(pagestart + 8, 1, "REQ/ACK offset");
2985 intfield(pagestart + 9, 1, "Transfer width exponent");
2986 bitfield(pagestart + 10, "Protocol option bits", 0x7f, 0);
2987 bitfield(pagestart + 11, "Transceiver mode", 3, 2);
2988 bitfield(pagestart + 11, "Sent PCOMP_EN", 1, 1);
2989 bitfield(pagestart + 11, "Received PCOMP_EN", 1, 0);
2990
2991 if (x_interface && replace)
2992 return put_mode_page(mpi, cbuffer);
2993 else
2994 printf("\n");
2995 return 0;
2996 }
2997
2998 static int
spi4_report_xfer(struct mpage_info * mpi,const char * prefix)2999 spi4_report_xfer(struct mpage_info * mpi, const char * prefix)
3000 {
3001 int status;
3002 uint8_t *pagestart;
3003
3004 status = setup_mode_page(mpi, 4, cbuffer, &pagestart);
3005 if (status)
3006 return status;
3007
3008 if (prefix[0])
3009 printf("%s", prefix);
3010 if (!x_interface && !replace) {
3011 printf("%s mode subpage (0x%x,0x%x)\n", get_page_name(mpi), mpi->page,
3012 mpi->subpage);
3013 printf("--------------------------------------------\n");
3014 }
3015 intfield(pagestart + 6, 1, "Minimum transfer period factor");
3016 intfield(pagestart + 8, 1, "Maximum REQ/ACK offset");
3017 intfield(pagestart + 9, 1, "Maximum transfer width exponent");
3018 bitfield(pagestart + 10, "Protocol option bits supported", 0xff, 0);
3019
3020 if (x_interface && replace)
3021 return put_mode_page(mpi, cbuffer);
3022 else
3023 printf("\n");
3024 return 0;
3025 }
3026
3027 static void
print_hex_page(struct mpage_info * mpi,const char * prefix,uint8_t * pagestart,int off,int len)3028 print_hex_page(struct mpage_info * mpi, const char * prefix,
3029 uint8_t *pagestart, int off, int len)
3030 {
3031 int k;
3032 const char * pg_name;
3033
3034 if (prefix[0])
3035 printf("%s", prefix);
3036 if (! x_interface) {
3037 pg_name = get_page_name(mpi);
3038 if (mpi->subpage) {
3039 if (pg_name && (unkn_page_str != pg_name))
3040 printf("mode page: 0x%02x subpage: 0x%02x [%s]\n",
3041 mpi->page, mpi->subpage, pg_name);
3042 else
3043 printf("mode page: 0x%02x subpage: 0x%02x\n", mpi->page,
3044 mpi->subpage);
3045 printf("------------------------------\n");
3046 } else {
3047 if (pg_name && (unkn_page_str != pg_name))
3048 printf("mode page: 0x%02x [%s]\n", mpi->page,
3049 pg_name);
3050 else
3051 printf("mode page: 0x%02x\n", mpi->page);
3052 printf("---------------\n");
3053 }
3054 }
3055 for (k = off; k < len; k++)
3056 {
3057 char nm[8];
3058
3059 snprintf(nm, sizeof(nm), "0x%02x", (unsigned char)k);
3060 hexdatafield(pagestart + k, 1, nm);
3061 }
3062 printf("\n");
3063 }
3064
3065 static int
do_user_page(struct mpage_info * mpi,int decode_in_hex)3066 do_user_page(struct mpage_info * mpi, int decode_in_hex)
3067 {
3068 int status = 0;
3069 int len, off, res, done;
3070 int offset = 0;
3071 uint8_t *pagestart;
3072 char prefix[96];
3073 struct mpage_info local_mp_i;
3074 struct mpage_name_func * mpf;
3075 int multiple = ((MP_LIST_PAGES == mpi->page) ||
3076 (MP_LIST_SUBPAGES == mpi->subpage));
3077
3078 if (replace && multiple) {
3079 printf("Can't list all (sub)pages and use replace (-R) together\n");
3080 return 1;
3081 }
3082 status = get_mode_page(mpi, 0, cbuffer2);
3083 if (status) {
3084 printf("\n");
3085 return status;
3086 } else {
3087 offset = modePageOffset(cbuffer2, mpi->resp_len, mode6byte);
3088 if (offset < 0) {
3089 fprintf(stdout, "mode page=0x%x has bad page format\n",
3090 mpi->page);
3091 fprintf(stdout, " perhaps '-z' switch may help\n");
3092 return -1;
3093 }
3094 pagestart = cbuffer2 + offset;
3095 }
3096
3097 memset(&local_mp_i, 0, sizeof(local_mp_i));
3098 local_mp_i.page_control = mpi->page_control;
3099 local_mp_i.peri_type = mpi->peri_type;
3100 local_mp_i.inq_byte6 = mpi->inq_byte6;
3101 local_mp_i.resp_len = mpi->resp_len;
3102
3103 do {
3104 local_mp_i.page = (pagestart[0] & 0x3f);
3105 local_mp_i.subpage = (pagestart[0] & 0x40) ? pagestart[1] : 0;
3106 if(0 == local_mp_i.page) { /* page==0 vendor (unknown) format */
3107 off = 0;
3108 len = mpi->resp_len - offset; /* should be last listed page */
3109 } else if (local_mp_i.subpage) {
3110 off = 4;
3111 len = (pagestart[2] << 8) + pagestart[3] + 4;
3112 } else {
3113 off = 2;
3114 len = pagestart[1] + 2;
3115 }
3116
3117 prefix[0] = '\0';
3118 done = 0;
3119 if ((! decode_in_hex) && ((mpf = get_mpage_name_func(&local_mp_i))) &&
3120 mpf->func) {
3121 if (multiple && x_interface && !replace) {
3122 if (local_mp_i.subpage)
3123 snprintf(prefix, sizeof(prefix), "sginfo -t 0x%x,0x%x"
3124 " -XR %s ", local_mp_i.page, local_mp_i.subpage,
3125 device_name);
3126 else
3127 snprintf(prefix, sizeof(prefix), "sginfo -t 0x%x -XR %s ",
3128 local_mp_i.page, device_name);
3129 }
3130 res = mpf->func(&local_mp_i, prefix);
3131 if (DECODE_FAILED_TRY_HEX != res) {
3132 done = 1;
3133 status |= res;
3134 }
3135 }
3136 if (! done) {
3137 if (x_interface && replace)
3138 return put_mode_page(&local_mp_i, cbuffer2);
3139 else {
3140 if (multiple && x_interface && !replace) {
3141 if (local_mp_i.subpage)
3142 snprintf(prefix, sizeof(prefix), "sginfo -u 0x%x,0x%x"
3143 " -XR %s ", local_mp_i.page,
3144 local_mp_i.subpage, device_name);
3145 else
3146 snprintf(prefix, sizeof(prefix), "sginfo -u 0x%x -XR "
3147 "%s ", local_mp_i.page, device_name);
3148 }
3149 print_hex_page(&local_mp_i, prefix, pagestart, off, len);
3150 }
3151 }
3152 offset += len;
3153 pagestart = cbuffer2 + offset;
3154 } while (multiple && (offset < mpi->resp_len));
3155 return status;
3156 }
3157
3158 static void
inqfieldname(uint8_t * deststr,const uint8_t * srcbuf,int maxlen)3159 inqfieldname(uint8_t *deststr, const uint8_t *srcbuf, int maxlen)
3160 {
3161 int i;
3162
3163 memset(deststr, '\0', MAX_INQFIELD_LEN);
3164 for (i = maxlen - 1; i >= 0 && isspace(srcbuf[i]); --i)
3165 ;
3166 memcpy(deststr, srcbuf, i + 1);
3167 }
3168
3169 static int
do_inquiry(int * peri_type,int * resp_byte6,int inquiry_verbosity)3170 do_inquiry(int * peri_type, int * resp_byte6, int inquiry_verbosity)
3171 {
3172 int status;
3173 uint8_t cmd[6];
3174 uint8_t fieldname[MAX_INQFIELD_LEN];
3175 uint8_t *pagestart;
3176 struct scsi_cmnd_io sci;
3177
3178 memset(cbuffer, 0, INQUIRY_RESP_INITIAL_LEN);
3179 cbuffer[0] = 0x7f;
3180
3181 cmd[0] = 0x12; /* INQUIRY */
3182 cmd[1] = 0x00; /* evpd=0 */
3183 cmd[2] = 0x00; /* page code = 0 */
3184 cmd[3] = 0x00; /* (reserved) */
3185 cmd[4] = INQUIRY_RESP_INITIAL_LEN; /* allocation length */
3186 cmd[5] = 0x00; /* control */
3187
3188 sci.cmnd = cmd;
3189 sci.cmnd_len = sizeof(cmd);
3190 sci.dxfer_dir = DXFER_FROM_DEVICE;
3191 sci.dxfer_len = INQUIRY_RESP_INITIAL_LEN;
3192 sci.dxferp = cbuffer;
3193 status = do_scsi_io(&sci);
3194 if (status) {
3195 printf("Error doing INQUIRY (1)\n");
3196 return status;
3197 }
3198 if (trace_cmd > 1) {
3199 printf(" inquiry response:\n");
3200 dump(cbuffer, INQUIRY_RESP_INITIAL_LEN);
3201 }
3202 pagestart = cbuffer;
3203 if (peri_type)
3204 *peri_type = pagestart[0] & 0x1f;
3205 if (resp_byte6)
3206 *resp_byte6 = pagestart[6];
3207 if (0 == inquiry_verbosity)
3208 return 0;
3209 if ((pagestart[4] + 5) < INQUIRY_RESP_INITIAL_LEN) {
3210 printf("INQUIRY response too short: expected 36 bytes, got %d\n",
3211 pagestart[4] + 5);
3212 return -EINVAL;
3213 }
3214
3215 if (!x_interface && !replace) {
3216 printf("INQUIRY response (cmd: 0x12)\n");
3217 printf("----------------------------\n");
3218 };
3219 bitfield(pagestart + 0, "Device Type", 0x1f, 0);
3220 if (2 == inquiry_verbosity) {
3221 bitfield(pagestart + 0, "Peripheral Qualifier", 0x7, 5);
3222 bitfield(pagestart + 1, "Removable", 1, 7);
3223 bitfield(pagestart + 2, "Version", 0xff, 0);
3224 bitfield(pagestart + 3, "NormACA", 1, 5);
3225 bitfield(pagestart + 3, "HiSup", 1, 4);
3226 bitfield(pagestart + 3, "Response Data Format", 0xf, 0);
3227 bitfield(pagestart + 5, "SCCS", 1, 7);
3228 bitfield(pagestart + 5, "ACC", 1, 6);
3229 bitfield(pagestart + 5, "ALUA", 3, 4);
3230 bitfield(pagestart + 5, "3PC", 1, 3);
3231 bitfield(pagestart + 5, "Protect", 1, 0);
3232 bitfield(pagestart + 6, "BQue", 1, 7);
3233 bitfield(pagestart + 6, "EncServ", 1, 6);
3234 bitfield(pagestart + 6, "MultiP", 1, 4);
3235 bitfield(pagestart + 6, "MChngr", 1, 3);
3236 bitfield(pagestart + 6, "Addr16", 1, 0);
3237 bitfield(pagestart + 7, "Relative Address", 1, 7);
3238 bitfield(pagestart + 7, "Wide bus 16", 1, 5);
3239 bitfield(pagestart + 7, "Synchronous neg.", 1, 4);
3240 bitfield(pagestart + 7, "Linked Commands", 1, 3);
3241 bitfield(pagestart + 7, "Command Queueing", 1, 1);
3242 }
3243 if (x_interface)
3244 printf("\n");
3245
3246 inqfieldname(fieldname, pagestart + 8, 8);
3247 printf("%s%s\n", (!x_interface ? "Vendor: " : ""),
3248 fieldname);
3249
3250 inqfieldname(fieldname, pagestart + 16, 16);
3251 printf("%s%s\n", (!x_interface ? "Product: " : ""),
3252 fieldname);
3253
3254 inqfieldname(fieldname, pagestart + 32, 4);
3255 printf("%s%s\n", (!x_interface ? "Revision level: " : ""),
3256 fieldname);
3257
3258 printf("\n");
3259 return status;
3260
3261 }
3262
3263 static int
do_serial_number(void)3264 do_serial_number(void)
3265 {
3266 int status, pagelen;
3267 uint8_t cmd[6];
3268 uint8_t *pagestart;
3269 struct scsi_cmnd_io sci;
3270 const uint8_t serial_vpd = 0x80;
3271 const uint8_t supported_vpd = 0x0;
3272
3273 /* check supported VPD pages + unit serial number well formed */
3274 cmd[0] = 0x12; /* INQUIRY */
3275 cmd[1] = 0x01; /* evpd=1 */
3276 cmd[2] = supported_vpd;
3277 cmd[3] = 0x00; /* (reserved) */
3278 cmd[4] = 0x04; /* allocation length */
3279 cmd[5] = 0x00; /* control */
3280
3281 sci.cmnd = cmd;
3282 sci.cmnd_len = sizeof(cmd);
3283 sci.dxfer_dir = DXFER_FROM_DEVICE;
3284 sci.dxfer_len = 4;
3285 sci.dxferp = cbuffer;
3286 status = do_scsi_io(&sci);
3287 if (status) {
3288 printf("No serial number (error doing INQUIRY, supported VPDs)\n\n");
3289 return status;
3290 }
3291 if (! ((supported_vpd == cbuffer[1]) && (0 == cbuffer[2]))) {
3292 printf("No serial number (bad format for supported VPDs)\n\n");
3293 return -1;
3294 }
3295
3296 cmd[0] = 0x12; /* INQUIRY */
3297 cmd[1] = 0x01; /* evpd=1 */
3298 cmd[2] = serial_vpd;
3299 cmd[3] = 0x00; /* (reserved) */
3300 cmd[4] = 0x04; /* allocation length */
3301 cmd[5] = 0x00; /* control */
3302
3303 sci.cmnd = cmd;
3304 sci.cmnd_len = sizeof(cmd);
3305 sci.dxfer_dir = DXFER_FROM_DEVICE;
3306 sci.dxfer_len = 4;
3307 sci.dxferp = cbuffer;
3308 status = do_scsi_io(&sci);
3309 if (status) {
3310 printf("No serial number (error doing INQUIRY, serial number)\n\n");
3311 return status;
3312 }
3313 if (! ((serial_vpd == cbuffer[1]) && (0 == cbuffer[2]))) {
3314 printf("No serial number (bad format for serial number)\n\n");
3315 return -1;
3316 }
3317
3318 pagestart = cbuffer;
3319
3320 pagelen = 4 + pagestart[3];
3321
3322 cmd[0] = 0x12; /* INQUIRY */
3323 cmd[1] = 0x01; /* evpd=1 */
3324 cmd[2] = serial_vpd;
3325 cmd[3] = 0x00; /* (reserved) */
3326 cmd[4] = (uint8_t)pagelen; /* allocation length */
3327 cmd[5] = 0x00; /* control */
3328
3329 sci.cmnd = cmd;
3330 sci.cmnd_len = sizeof(cmd);
3331 sci.dxfer_dir = DXFER_FROM_DEVICE;
3332 sci.dxfer_len = pagelen;
3333 sci.dxferp = cbuffer;
3334 status = do_scsi_io(&sci);
3335 if (status) {
3336 printf("No serial number (error doing INQUIRY, serial number)\n\n");
3337 return status;
3338 }
3339 if (trace_cmd > 1) {
3340 printf(" inquiry (vpd page 0x80) response:\n");
3341 dump(cbuffer, pagelen);
3342 }
3343
3344 pagestart[pagestart[3] + 4] = '\0';
3345 printf("Serial Number '%s'\n\n", pagestart + 4);
3346 return status;
3347 }
3348
3349
3350 typedef struct sg_map {
3351 int bus;
3352 int channel;
3353 int target_id;
3354 int lun;
3355 char * dev_name;
3356 } Sg_map;
3357
3358 typedef struct my_scsi_idlun
3359 {
3360 int mux4;
3361 int host_unique_id;
3362
3363 } My_scsi_idlun;
3364
3365 #define MDEV_NAME_SZ 256
3366
3367 static void
make_dev_name(char * fname,int k,int do_numeric)3368 make_dev_name(char * fname, int k, int do_numeric)
3369 {
3370 char buff[MDEV_NAME_SZ];
3371 size_t len;
3372
3373 strncpy(fname, "/dev/sg", MDEV_NAME_SZ);
3374 fname[MDEV_NAME_SZ - 1] = '\0';
3375 len = strlen(fname);
3376 if (do_numeric)
3377 snprintf(fname + len, MDEV_NAME_SZ - len, "%d", k);
3378 else {
3379 if (k <= 26) {
3380 buff[0] = 'a' + (char)k;
3381 buff[1] = '\0';
3382 strcat(fname, buff);
3383 }
3384 else
3385 strcat(fname, "xxxx");
3386 }
3387 }
3388
3389
3390 static Sg_map sg_map_arr[MAX_SG_DEVS + 1];
3391
3392 #define MAX_HOLES 4
3393
3394 /* Print out a list of the known devices on the system */
3395 static void
show_devices(int raw)3396 show_devices(int raw)
3397 {
3398 int k, j, fd, err, bus, n;
3399 My_scsi_idlun m_idlun;
3400 char name[MDEV_NAME_SZ];
3401 char dev_name[MDEV_NAME_SZ + 6];
3402 char ebuff[EBUFF_SZ];
3403 int do_numeric = 1;
3404 int max_holes = MAX_HOLES;
3405 DIR *dir_ptr;
3406 struct dirent *entry;
3407 char *tmpptr;
3408
3409 dir_ptr=opendir("/dev");
3410 if ( dir_ptr == NULL ) {
3411 perror("/dev");
3412 exit(1);
3413 }
3414
3415 j=0;
3416 while ( (entry=readdir(dir_ptr)) != NULL ) {
3417 switch(entry->d_type) {
3418 case DT_LNK:
3419 case DT_CHR:
3420 case DT_BLK:
3421 break;
3422 default:
3423 continue;
3424 }
3425
3426 switch(entry->d_name[0]) {
3427 case 's':
3428 case 'n':
3429 break;
3430 default:
3431 continue;
3432 }
3433
3434 if ( strncmp("sg",entry->d_name,2) == 0 ) {
3435 continue;
3436 }
3437 if ( strncmp("sd",entry->d_name,2) == 0 ) {
3438 continue;
3439 }
3440 if ( isdigit(entry->d_name[strlen(entry->d_name)-1]) ) {
3441 continue;
3442 }
3443 if ( strncmp("snapshot",entry->d_name,8) == 0 ) {
3444 continue;
3445 }
3446
3447 snprintf(dev_name, sizeof(dev_name),"/dev/%s",entry->d_name);
3448
3449 fd = open(dev_name, O_RDONLY | O_NONBLOCK);
3450 if (fd < 0)
3451 continue;
3452 err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &(sg_map_arr[j].bus));
3453 if (err < 0) {
3454 #if 0
3455 snprintf(ebuff, EBUFF_SZ,
3456 "SCSI(1) ioctl on %s failed", dev_name);
3457 perror(ebuff);
3458 #endif
3459 close(fd);
3460 continue;
3461 }
3462 err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun);
3463 if (err < 0) {
3464 snprintf(ebuff, EBUFF_SZ,
3465 "SCSI(2) ioctl on %s failed", dev_name);
3466 perror(ebuff);
3467 close(fd);
3468 continue;
3469 }
3470 sg_map_arr[j].channel = (m_idlun.mux4 >> 16) & 0xff;
3471 sg_map_arr[j].lun = (m_idlun.mux4 >> 8) & 0xff;
3472 sg_map_arr[j].target_id = m_idlun.mux4 & 0xff;
3473 n = strlen(dev_name);
3474 /* memory leak ... no free()s for this malloc() */
3475 tmpptr = (char *)malloc(n + 1);
3476 snprintf(tmpptr, n + 1, "%.*s", n, dev_name);
3477 /* strncpy(tmpptr,dev_name,strlen(dev_name)+1); */
3478
3479 sg_map_arr[j].dev_name = tmpptr;
3480 #if 0
3481 printf("[scsi%d ch=%d id=%d lun=%d %s] ", sg_map_arr[j].bus,
3482 sg_map_arr[j].channel, sg_map_arr[j].target_id, sg_map_arr[j].lun,
3483 sg_map_arr[j].dev_name);
3484 #endif
3485 printf("%s ", dev_name);
3486 close(fd);
3487 if (++j >= MAX_SG_DEVS)
3488 break;
3489 }
3490 closedir(dir_ptr);
3491
3492 printf("\n"); /* <<<<<<<<<<<<<<<<<<<<< */
3493 for (k = 0; k < MAX_SG_DEVS; k++) {
3494 if ( raw ) {
3495 sprintf(name,"/dev/raw/raw%d",k);
3496 fd = open(name, O_RDWR | O_NONBLOCK);
3497 if (fd < 0) {
3498 continue;
3499 }
3500 }
3501 else {
3502 make_dev_name(name, k, do_numeric);
3503 fd = open(name, O_RDWR | O_NONBLOCK);
3504 if (fd < 0) {
3505 if ((ENOENT == errno) && (0 == k)) {
3506 do_numeric = 0;
3507 make_dev_name(name, k, do_numeric);
3508 fd = open(name, O_RDWR | O_NONBLOCK);
3509 }
3510 if (fd < 0) {
3511 if (EBUSY == errno)
3512 continue; /* step over if O_EXCL already on it */
3513 else {
3514 #if 0
3515 snprintf(ebuff, EBUFF_SZ,
3516 "open on %s failed (%d)", name, errno);
3517 perror(ebuff);
3518 #endif
3519 if (max_holes-- > 0)
3520 continue;
3521 else
3522 break;
3523 }
3524 }
3525 }
3526 }
3527 max_holes = MAX_HOLES;
3528 err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus);
3529 if (err < 0) {
3530 if ( ! raw ) {
3531 snprintf(ebuff, EBUFF_SZ, "SCSI(3) ioctl on %s failed", name);
3532 perror(ebuff);
3533 }
3534 close(fd);
3535 continue;
3536 }
3537 err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun);
3538 if (err < 0) {
3539 if ( ! raw ) {
3540 snprintf(ebuff, EBUFF_SZ, "SCSI(3) ioctl on %s failed", name);
3541 perror(ebuff);
3542 }
3543 close(fd);
3544 continue;
3545 }
3546 #if 0
3547 printf("[scsi%d ch=%d id=%d lun=%d %s]", bus,
3548 (m_idlun.mux4 >> 16) & 0xff, m_idlun.mux4 & 0xff,
3549 (m_idlun.mux4 >> 8) & 0xff, name);
3550 #endif
3551 for (j = 0; sg_map_arr[j].dev_name; ++j) {
3552 if ((bus == sg_map_arr[j].bus) &&
3553 ((m_idlun.mux4 & 0xff) == sg_map_arr[j].target_id) &&
3554 (((m_idlun.mux4 >> 16) & 0xff) == sg_map_arr[j].channel) &&
3555 (((m_idlun.mux4 >> 8) & 0xff) == sg_map_arr[j].lun)) {
3556 printf("%s [=%s scsi%d ch=%d id=%d lun=%d]\n", name,
3557 sg_map_arr[j].dev_name, bus,
3558 ((m_idlun.mux4 >> 16) & 0xff), m_idlun.mux4 & 0xff,
3559 ((m_idlun.mux4 >> 8) & 0xff));
3560 break;
3561 }
3562 }
3563 if (NULL == sg_map_arr[j].dev_name)
3564 printf("%s [scsi%d ch=%d id=%d lun=%d]\n", name, bus,
3565 ((m_idlun.mux4 >> 16) & 0xff), m_idlun.mux4 & 0xff,
3566 ((m_idlun.mux4 >> 8) & 0xff));
3567 close(fd);
3568 }
3569 printf("\n");
3570 }
3571
3572 #define DEVNAME_SZ 256
3573
3574 static int
open_sg_io_dev(char * devname)3575 open_sg_io_dev(char * devname)
3576 {
3577 int fd, fdrw, err, bus, bbus, k, v;
3578 My_scsi_idlun m_idlun, mm_idlun;
3579 int do_numeric = 1;
3580 char name[DEVNAME_SZ];
3581 struct stat a_st;
3582 int block_dev = 0;
3583
3584 strncpy(name, devname, DEVNAME_SZ);
3585 name[DEVNAME_SZ - 1] = '\0';
3586 fd = open(name, O_RDONLY | O_NONBLOCK);
3587 if (fd < 0)
3588 return fd;
3589 if ((ioctl(fd, SG_GET_VERSION_NUM, &v) >= 0) && (v >= 30000)) {
3590 fdrw = open(name, O_RDWR | O_NONBLOCK);
3591 if (fdrw >= 0) {
3592 close(fd);
3593 return fdrw;
3594 }
3595 return fd;
3596 }
3597 if (fstat(fd, &a_st) < 0) {
3598 fprintf(stderr, "could do fstat() on fd ??\n");
3599 close(fd);
3600 return -9999;
3601 }
3602 if (S_ISBLK(a_st.st_mode))
3603 block_dev = 1;
3604
3605 if (block_dev || (ioctl(fd, SG_GET_TIMEOUT, 0) < 0)) {
3606 err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus);
3607 if (err < 0) {
3608 fprintf(stderr, "A device name that understands SCSI commands "
3609 "is required\n");
3610 close(fd);
3611 return -9999;
3612 }
3613 err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun);
3614 if (err < 0) {
3615 fprintf(stderr, "A SCSI device name is required(2)\n");
3616 close(fd);
3617 return -9999;
3618 }
3619 close(fd);
3620
3621 for (k = 0; k < MAX_SG_DEVS; k++) {
3622 make_dev_name(name, k, do_numeric);
3623 fd = open(name, O_RDWR | O_NONBLOCK);
3624 if (fd < 0) {
3625 if ((ENOENT == errno) && (0 == k)) {
3626 do_numeric = 0;
3627 make_dev_name(name, k, do_numeric);
3628 fd = open(name, O_RDWR | O_NONBLOCK);
3629 }
3630 if (fd < 0) {
3631 if (EBUSY == errno)
3632 continue; /* step over if O_EXCL already on it */
3633 else
3634 break;
3635 }
3636 }
3637 err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bbus);
3638 if (err < 0) {
3639 perror("sg ioctl failed");
3640 close(fd);
3641 fd = -9999;
3642 }
3643 err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &mm_idlun);
3644 if (err < 0) {
3645 perror("sg ioctl failed");
3646 close(fd);
3647 fd = -9999;
3648 }
3649 if ((bus == bbus) &&
3650 ((m_idlun.mux4 & 0xff) == (mm_idlun.mux4 & 0xff)) &&
3651 (((m_idlun.mux4 >> 8) & 0xff) ==
3652 ((mm_idlun.mux4 >> 8) & 0xff)) &&
3653 (((m_idlun.mux4 >> 16) & 0xff) ==
3654 ((mm_idlun.mux4 >> 16) & 0xff)))
3655 break;
3656 else {
3657 close(fd);
3658 fd = -9999;
3659 }
3660 }
3661 }
3662 if (fd >= 0) {
3663 if ((ioctl(fd, SG_GET_VERSION_NUM, &v) < 0) || (v < 30000)) {
3664 fprintf(stderr, "requires lk 2.4 (sg driver), lk 2.6 or lk 3 "
3665 "series\n");
3666 close(fd);
3667 return -9999;
3668 }
3669 close(fd);
3670 return open(name, O_RDWR | O_NONBLOCK);
3671 }
3672 else
3673 return fd;
3674 }
3675
3676 static void
usage(const char * errtext)3677 usage(const char *errtext)
3678 {
3679 if (errtext)
3680 fprintf(stderr, "Error: sginfo: %s\n", errtext);
3681 fprintf(stderr, "Usage: sginfo [-options] [device] "
3682 "[replacement_values]\n");
3683 fputs("\tAllowed options are:\n"
3684 "\t-6 Do 6 byte mode sense and select commands (def: 10 "
3685 "bytes).\n"
3686 "\t-a Display inquiry info, serial # and all mode pages.\n"
3687 "\t-A Similar to '-a' but displays all subpages as well.\n"
3688 "\t-c Access Caching Page.\n"
3689 "\t-C Access Control Mode Page.\n"
3690 "\t-d Display defect lists (default format: index).\n"
3691 "\t-D Access Disconnect-Reconnect Page.\n"
3692 "\t-e Access Read-Write Error Recovery page.\n"
3693 "\t-E Access Control Extension page.\n"
3694 "\t-f Access Format Device Page.\n"
3695 "\t-Farg Format of the defect list:\n"
3696 "\t\t-Flogical - logical block addresses (32 bit)\n"
3697 "\t\t-Flba64 - logical block addresses (64 bit)\n"
3698 "\t\t-Fphysical - physical blocks\n"
3699 "\t\t-Findex - defect bytes from index\n"
3700 "\t\t-Fhead - sort by head\n", stdout);
3701 fputs("\t-g Access Rigid Disk Drive Geometry Page.\n"
3702 "\t-G Display 'grown' defect list (default format: index).\n"
3703 "\t-i Display information from INQUIRY command.\n"
3704 "\t-I Access Informational Exception page.\n"
3705 "\t-l List known scsi devices on the system [DEPRECATED]\n"
3706 "\t-n Access Notch and Partition Page.\n"
3707 "\t-N Negate (stop) storing to saved page (active with -R).\n"
3708 "\t-P Access Power Condition Page.\n"
3709 "\t-r List known raw scsi devices on the system\n"
3710 "\t-s Display serial number (from INQUIRY VPD page).\n"
3711 "\t-t<pn[,sp]> Access mode page <pn> [subpage <sp>] and decode.\n"
3712 "\t-T Trace commands (for debugging, double for more)\n"
3713 "\t-u<pn[,sp]> Access mode page <pn> [subpage <sp>], output in hex\n"
3714 "\t-v Show version number\n"
3715 "\t-V Access Verify Error Recovery Page.\n"
3716 "\t-z single fetch mode pages (rather than double fetch)\n"
3717 "\n", stdout);
3718 fputs("\tOnly one of the following three options can be specified.\n"
3719 "\tNone of these three implies the current values are returned.\n", stdout);
3720 fputs("\t-m Access modifiable fields instead of current values\n"
3721 "\t-M Access manufacturer defaults instead of current values\n"
3722 "\t-S Access saved defaults instead of current values\n\n"
3723 "\t-X Use list (space separated values) rather than table.\n"
3724 "\t-R Replace parameters - best used with -X (expert use only)\n"
3725 "\t [replacement parameters placed after device on command line]\n\n",
3726 stdout);
3727 printf("\t sginfo version: %s; See man page for more details.\n",
3728 version_str);
3729 exit(2);
3730 }
3731
main(int argc,char * argv[])3732 int main(int argc, char *argv[])
3733 {
3734 int k, j, n;
3735 unsigned int unum, unum2;
3736 int decode_in_hex = 0;
3737 char c;
3738 char * cp;
3739 int status = 0;
3740 long tmp;
3741 struct mpage_info mp_i;
3742 int inquiry_verbosity = 0;
3743 int show_devs = 0, show_raw = 0;
3744 int found = 0;
3745
3746 if (argc < 2)
3747 usage(NULL);
3748 memset(&mp_i, 0, sizeof(mp_i));
3749 while ((k = getopt(argc, argv, "6aAcCdDeEfgGiIlmMnNPrRsSTvVXzF:t:u:")) !=
3750 EOF) {
3751 c = (char)k;
3752 switch (c) {
3753 case '6':
3754 mode6byte = 1;
3755 break;
3756 case 'a':
3757 inquiry_verbosity = 1;
3758 serial_number = 1;
3759 mp_i.page = MP_LIST_PAGES;
3760 break;
3761 case 'A':
3762 inquiry_verbosity = 1;
3763 serial_number = 1;
3764 mp_i.page = MP_LIST_PAGES;
3765 mp_i.subpage = MP_LIST_SUBPAGES;
3766 break;
3767 case 'c':
3768 mp_i.page = 0x8;
3769 break;
3770 case 'C':
3771 mp_i.page = 0xa;
3772 break;
3773 case 'd':
3774 defect = 1;
3775 break;
3776 case 'D':
3777 mp_i.page = 0x2;
3778 break;
3779 case 'e':
3780 mp_i.page = 0x1;
3781 break;
3782 case 'E':
3783 mp_i.page = 0xa;
3784 mp_i.subpage = 0x1;
3785 break;
3786 case 'f':
3787 mp_i.page = 0x3;
3788 break;
3789 case 'F':
3790 if (!strcasecmp(optarg, "logical"))
3791 defectformat = 0x0;
3792 else if (!strcasecmp(optarg, "lba64"))
3793 defectformat = 0x3;
3794 else if (!strcasecmp(optarg, "physical"))
3795 defectformat = 0x5;
3796 else if (!strcasecmp(optarg, "index"))
3797 defectformat = 0x4;
3798 else if (!strcasecmp(optarg, "head"))
3799 defectformat = HEAD_SORT_TOKEN;
3800 else
3801 usage("Illegal -F parameter, must be one of logical, "
3802 "physical, index or head");
3803 break;
3804 case 'g':
3805 mp_i.page = 0x4;
3806 break;
3807 case 'G':
3808 grown_defect = 1;
3809 break;
3810 case 'i': /* just vendor, product and revision for '-i -i' */
3811 inquiry_verbosity = (2 == inquiry_verbosity) ? 1 : 2;
3812 break;
3813 case 'I':
3814 mp_i.page = 0x1c;
3815 break;
3816 case 'l':
3817 show_devs = 1;
3818 break;
3819 case 'm': /* modifiable page control */
3820 if (0 == mp_i.page_control)
3821 mp_i.page_control = 1;
3822 else
3823 usage("can only have one of 'm', 'M' and 'S'");
3824 break;
3825 case 'M': /* manufacturer's==default page control */
3826 if (0 == mp_i.page_control)
3827 mp_i.page_control = 2;
3828 else
3829 usage("can only have one of 'M', 'm' and 'S'");
3830 break;
3831 case 'n':
3832 mp_i.page = 0xc;
3833 break;
3834 case 'N':
3835 negate_sp_bit = 1;
3836 break;
3837 case 'P':
3838 mp_i.page = 0x1a;
3839 break;
3840 case 'r':
3841 show_raw = 1;
3842 break;
3843 case 'R':
3844 replace = 1;
3845 break;
3846 case 's':
3847 serial_number = 1;
3848 break;
3849 case 'S': /* saved page control */
3850 if (0 == mp_i.page_control)
3851 mp_i.page_control = 3;
3852 else
3853 usage("can only have one of 'S', 'm' and 'M'");
3854 break;
3855 case 'T':
3856 trace_cmd++;
3857 break;
3858 case 't':
3859 case 'u':
3860 if ('u' == c)
3861 decode_in_hex = 1;
3862 while (' ' == *optarg)
3863 optarg++;
3864 if ('0' == *optarg) {
3865 unum = 0;
3866 unum2 = 0;
3867 j = sscanf(optarg, "0x%x,0x%x", &unum, &unum2);
3868 mp_i.page = unum;
3869 if (1 == j) {
3870 cp = strchr(optarg, ',');
3871 if (cp && (1 == sscanf(cp, ",%d", &mp_i.subpage)))
3872 j = 2;
3873 } else
3874 mp_i.subpage = unum2;
3875 } else
3876 j = sscanf(optarg, "%d,%d", &mp_i.page, &mp_i.subpage);
3877 if (1 == j)
3878 mp_i.subpage = 0;
3879 else if (j < 1)
3880 usage("argument following '-u' should be of form "
3881 "<pg>[,<subpg>]");
3882 if ((mp_i.page < 0) || (mp_i.page > MP_LIST_PAGES) ||
3883 (mp_i.subpage < 0) || (mp_i.subpage > MP_LIST_SUBPAGES))
3884 usage("mode pages range from 0 .. 63, subpages from "
3885 "1 .. 255");
3886 found = 1;
3887 break;
3888 case 'v':
3889 fprintf(stdout, "sginfo version: %s\n", version_str);
3890 return 0;
3891 case 'V':
3892 mp_i.page = 0x7;
3893 break;
3894 case 'X':
3895 x_interface = 1;
3896 break;
3897 case 'z':
3898 single_fetch = 1;
3899 break;
3900 case '?':
3901 usage("Unknown option");
3902 break;
3903 default:
3904 fprintf(stdout, "Unknown option '-%c' (ascii 0x%02x)\n", c, c);
3905 usage("bad option");
3906 }
3907 }
3908
3909 if (replace && !x_interface)
3910 usage("-R requires -X");
3911 if (replace && mp_i.page_control)
3912 usage("-R not allowed for -m, -M or -S");
3913 if (x_interface && replace && ((MP_LIST_PAGES == mp_i.page) ||
3914 (MP_LIST_SUBPAGES == mp_i.subpage)))
3915 usage("-XR can be used only with exactly one page.");
3916
3917 if (replace && (3 != mp_i.page_control)) {
3918 memset (is_hex, 0, 32);
3919 for (j = 1; j < argc - optind; j++) {
3920 if (strncmp(argv[optind + j], "0x", 2) == 0) {
3921 char *pnt = argv[optind + j] + 2;
3922 replacement_values[j] = 0;
3923 /* This is a kluge, but we can handle 64 bit quantities this way. */
3924 while (*pnt) {
3925 if (*pnt >= 'a' && *pnt <= 'f')
3926 *pnt -= 32;
3927 replacement_values[j] = (replacement_values[j] << 4) |
3928 (*pnt > '9' ? (*pnt - 'A' + 10) : (*pnt - '0'));
3929 pnt++;
3930 }
3931 continue;
3932 }
3933 if (argv[optind + j][0] == '@') {
3934 /*Ensure that this string contains an even number of hex-digits */
3935 int len = strlen(argv[optind + j] + 1);
3936
3937 if ((len & 1) || (len != (int)strspn(argv[optind + j] + 1,
3938 "0123456789ABCDEFabcdef")))
3939 usage("Odd number of chars or non-hex digit in "
3940 "@hexdatafield");
3941
3942 replacement_values[j] = (unsigned long) argv[optind + j];
3943 is_hex[j] = 1;
3944 continue;
3945 }
3946 /* Using a tmp here is silly but the most clean approach */
3947 n = sscanf(argv[optind + j], "%ld", &tmp);
3948 replacement_values[j] = ((1 == n) ? tmp : 0);
3949 }
3950 n_replacement_values = argc - optind - 1;
3951 }
3952 if (show_devs) {
3953 show_devices(0);
3954 exit(0);
3955 }
3956 if (show_raw) {
3957 show_devices(1);
3958 exit(0);
3959 }
3960 if (optind >= argc)
3961 usage("no device name given");
3962 glob_fd = open_sg_io_dev(device_name = argv[optind]);
3963 if (glob_fd < 0) {
3964 if (-9999 == glob_fd)
3965 fprintf(stderr, "Couldn't find sg device corresponding to %s\n",
3966 device_name);
3967 else {
3968 perror("sginfo(open)");
3969 fprintf(stderr, "file=%s, or no corresponding sg device found\n",
3970 device_name);
3971 fprintf(stderr, "Is sg driver loaded?\n");
3972 }
3973 exit(1);
3974 }
3975
3976 #if 0
3977 if (!x_interface)
3978 printf("\n");
3979 #endif
3980 if (! (found || mp_i.page || mp_i.subpage || inquiry_verbosity ||
3981 serial_number)) {
3982 if (trace_cmd > 0)
3983 fprintf(stdout, "nothing selected so do a short INQUIRY\n");
3984 inquiry_verbosity = 1;
3985 }
3986
3987 status |= do_inquiry(&mp_i.peri_type, &mp_i.inq_byte6,
3988 inquiry_verbosity);
3989 if (serial_number)
3990 do_serial_number(); /* ignore error */
3991 if (mp_i.page > 0)
3992 status |= do_user_page(&mp_i, decode_in_hex);
3993 if (defect)
3994 status |= read_defect_list(0);
3995 if (grown_defect)
3996 status |= read_defect_list(1);
3997
3998 return status ? 1 : 0;
3999 }
4000