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