xref: /aosp_15_r20/external/sg3_utils/src/sginfo.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
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