aboutsummaryrefslogtreecommitdiff
path: root/archive
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2007-06-27 03:11:26 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2007-06-27 03:11:26 +0000
commitfcf5ebe761ef1192920d3df273358c95e9c9c289 (patch)
tree3a055b118f633b7e878072499340a3fa369a0c8e /archive
parentd0771aa6e58b5592a554f27b46f5a3ddee4866e0 (diff)
downloadsg3_utils-fcf5ebe761ef1192920d3df273358c95e9c9c289.tar.gz
Load sg3_utils-1.15 into trunk/.
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@55 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'archive')
-rw-r--r--archive/sdparm.8255
-rw-r--r--archive/sdparm.c1501
2 files changed, 0 insertions, 1756 deletions
diff --git a/archive/sdparm.8 b/archive/sdparm.8
deleted file mode 100644
index 49639fe5..00000000
--- a/archive/sdparm.8
+++ /dev/null
@@ -1,255 +0,0 @@
-.TH SDPARM "8" "April 2005" "sg3_utils-1.14" SG3_UTILS
-.SH NAME
-sdparm \- fetch and potentially change SCSI disk parameters
-.SH SYNOPSIS
-.B sdparm
-[\fI--all\fR] [\fI--clear=<str>\fR] [\fI--defaults\fR] [\fI--dummy\fR]
-[\fI--enumerate\fR] [\fI--get=<str>\fR] [\fI--help\fR] [\fI--hex\fR]
-[\fI--inquiry\fR] [\fI--long\fR] [\fI--page=<pg>[,<spg>]\fR]
-[\fI--save\fR] [\fI--set=<str>\fR] [\fI--six\fR] [\fI--verbose\fR]
-[\fI--version\fR] \fI<scsi_disk>\fR
-.SH DESCRIPTION
-.\" Add any additional description here
-.PP
-This utility primarily fetches and potentially changes SCSI disk
-mode pages. Inquiry data including Vital Product Data (VPD) pages
-can also be displayed.
-.PP
-If no options (other than <scsi_disk>) are given then a selection of
-common mode page parameters for that device are listed. If the '--long'
-option is also given then the description of the parameters is placed
-on the right of each line. If the '--all' option is given then all
-known mode page parameters for that device are listed.
-.PP
-Although this utility is primarily designed for SCSI disks (or storage
-devices that appear to the OS as SCSI disks) many of the mode pages
-are in common with other SCSI devices. These include CD/DVD players
-that use the ATAPI transport, SCSI tapes drives and SCSI enclosures.
-.TP
---all | -a
-by default when mode pages are being displayed only a small number of
-parameters are shown. When this option is given, all recognised parameters
-are output. The default action is to output a relatively small number
-of parameters from different pages. When a specific (mode) page number
-is given with the "--page=" option the all the parameters of that
-page are output (irrespective of the setting of this option).
-.TP
---clear=<str> | -c <str>
-The <str> contains a comma separated list of parameter acronyms whose
-values are to be set to zero. See the parameters section below.
-.TP
---defaults | -D
-sets the given mode page (via '--page=' option) to its default values.
-To make the default mode page values also the saved mode page values
-use the '--save' option as well.
-.TP
---dummy | -d
-when set inhibits changes being written back to a mode page. Instead
-the mode data that would have been sent to a MODE SELECT command,
-is output in ASCII hex to the console.
-.TP
---enumerate | -e
-lists out the mode pages and parameters known by this utility. Ignores
-the <scsi_device> argument and most other options apart from the '--page='
-and '-all' options. If '--enumerate' is given without other options
-then the known mode pages are listed. If it is given with a page
-number then all known parameters (fields) in that mode page are
-listed. If '--enumerate' is given with the '-all' option then all
-mode pages followed by all parameters within those mode pages are
-listed. See listings section below.
-.TP
---get=<str> | -g <str>
-The <str> contains a comma separated list of parameter acronyms whose
-values are to be fetched to zero. See the parameters section below.
-The '--long' and '--hex' options effect the output format. Also if
-a value of "1" is given (e.g. '--get=WCE=1') only the current value
-is output.
-.TP
---help | -h
-output the usage message then exit.
-.TP
---hex | -H
-rather than trying to decode mode (or VPD) pages, print them out in
-hex. When used with the '-get=' option the corresponding current,
-changeable, default and saveable values are output in hex, prefixed
-by "0x" and space separated. If a value of "1" is given with
-the '--get=' option (e.g. '--get=WCE=1') then only the current value
-is output in hex, prefixed by "0x".
-.TP
---inquiry | -i
-output INQUIRY VPD pages. The default is to output mode pages.
-.TP
---long | -l
-output extra information. In the case of mode page parameters a
-description (with units if applicable) is output to the right if
-it is known.
-.TP
---page=<pg>[,<spg>] | -p <pg>[,<spg>]
-supply the page number and optionally the sub page number of the mode
-page to output. These numbers re interpreted as decimal unless
-prefixed with "0x". Alternatively a two letter abbreviation for
-a (mode) page can be given (e.g. "--page=ca" for the caching control
-mode page). See the '--enumerate' option for available abbreviations.
-.TP
---page=<str> | -p <str>
-alternatively a two letter acronym for a mode page can be given.
-The '--enumerate' option can be used to list the mode page
-acronyms.
-.TP
---save | -S
-when a mode page is being modified (by using the '--clear=' and/or '--set="
-options) then the default action is to only modify the current mode page.
-When this option is given the corresponding value(s) in the saved mode
-page is also changed. The next time the device is power cycled (or reset)
-the saved mode page values become (i.e. are copied to) the current mode
-page. See notes section below.
-.TP
---set=<str> | -s <str>
-The <str> contains a comma separated list of parameter acronyms whose
-values are to be set to (all) ones. Alternatively each acronym may be
-followed by "=<n>" where <n> is the value to set that parameter to.
-See the parameters section below.
-.TP
---six | -6
-The default action of this utility is to issue MODE SENSE and MODE
-SELECT SCSI commands with 10 byte cdbs. When this option is given the
-6 byte cdb variants are used.
-.TP
---verbose | -v
-increase the level of verbosity, (i.e. debug output).
-.TP
---version | -V
-print the version string and then exit.
-.SH PARAMETERS
-The '--clear=', '--get=' and '--set=" options can take a string argument
-which is a comma separated list of parameters. Each parameter can
-be either an acronym name or a <start_byte>:<start_bit>:<num_bits> triple
-Either form can optionally be followed by "=<val>". Acronyms (e.g.
-WCE for "write cache enable") that this utility supports can be viewed
-with the '--enumerate' option. Alternatively the mode page parameters
-to be changed can be described in terms of a <start_byte> (origin 0)
-within the mode page, a <start_bit> (0 to 7 inclusive) and <num_bits> (1
-to 32 inclusive). The low level representation of the WCE bit (in
-the caching control mode page) is 2:2:1 . The <start_byte> and
-the <val> can optionally be given in hex (prefixed with "0x").
-.PP
-Both '--clear=' and '--set=" parameter lists can be given. The only
-difference is the value set in the absence of "=<val>". For '--clear='
-the default value is zero while for '--set' the default value is all
-ones (as many as <num_bits> permits).
-.PP
-When an acronym is given the mode page is imputed from that acronym (e.g.
-WCE is in the cache mode page). When only the start_byte:start_bit:num_bits
-representation is used then the '--page=' option must be given to establish
-which mode page is to be used. When multiple parameters are given, they
-must all be in the same mode page (except for '--get=').
-.SH LISTINGS
-When known mode pages are listed (via the '--enumerate' option) each
-line starts with a two letter acronym. This is followed by the page
-number (in hex prefixed by "0x") optionally followed by a comma and
-the subpage number. Finally the descriptive name of the mode
-page (i.e. as found in spc-3 or sbc-2) is output.
-.PP
-When known parameters (fields) of a mode page are listed each line
-starts with an acronym. This will match (or be an acronym for) the
-description for that field found in the draft standards. Next are
-three numbers, separated by colons, surrounded by brackets. These
-are the byte offset (in hex, prefixed by "0x") of the start of the
-field within the mode page; the starting bit (0 through 7 inclusive)
-and then the number of bits. The descriptive name of the
-parameter (field) is then given, with units where
-applicable (e.g. "(ms)" means the units are milliseconds).
-.PP
-Mode parameters for which the num_bits is greater than 1 can be
-viewed as unsigned integers. Often 16 and 32 bit fields are set
-to 0xffff and 0xffffffff respectively (all ones) which usually
-has a special meaning (see drafts). In listings such values are
-represented by "-1" to save space (rather than their unsigned
-integer equivalents).
-.SH NOTES
-The SPC-3 draft (rev 22a) says that devices that implement no
-distinction between current and saved pages can return an
-error (ILLEGAL REQUEST, invalid field in cdb) if the SP bit (which
-corresponds to the '--save' option) is _not_ set. In such cases
-the '--save' option needs to be given.
-.PP
-If the '--save' option is given but the existing mode page indicates (via
-its PS bit) that the page is not savable, then this utility generates
-an error message. That message suggests to try again without the '--save'
-option.
-.PP
-In the 2.4 series of Linux kernels the given device must be
-a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks
-and SCSI DVDs) can also be specified. For example "sdparm /dev/sda"
-will work in the 2.6 series kernels. From lk 2.6.6 other SCSI "char"
-device names may be used as well (e.g. "/dev/st0m").
-.SH EXAMPLES
-These examples assume a 2.6 series linux kernel. For the 2.4 series
-scsi generic (i.e. sg) device names would need to be used.
-To list the common (mode) parameters of a disk:
-.PP
- sdparm /dev/sda
-.PP
-To see all parameters for the caching control mode page:
-.PP
- sdparm --page=ca /dev/sda
-.PP
-To get the WCE values (current changeable default and saved) in hex:
-.PP
- sdparm -g WCE -H /dev/sda
-.br
-0x01 0x00 0x01 0x01
-.PP
-To get the WCE current value in hex:
-.PP
- sdparm -g WCE=1 -H /dev/sda
-.br
-0x01
-.PP
-To set the "write cache enable" bit in the current page:
-.PP
- sdparm --set=WCE /dev/sda
-.PP
-To set the "write cache enable" bit in the current and saved page:
-.PP
- sdparm --set=WCE --save /dev/sda
-.PP
-To set the "write cache enable" and clear "read cache disable":
-.PP
- sdparm --set=WCE --clear=RCD --save /dev/sda
-.PP
-The previous example can also by written as:
-.PP
- sdparm -s WCE=1,RCD=0 -S /dev/sda
-.PP
-To re-establish the manufacturer's defaults in the current and saved
-caching control mode page:
-.PP
- sdparm --page=ca --defaults -save /dev/sda
-.PP
-If an ATAPI cd/dvd player is at /dev/hdc then its common (mode) parameters
-could be listed with:
-.PP
- sdparm /dev/hdc
-.PP
-One disk vendor has a "performance mode" bit (PM) in the vendor specific
-unit attention mode page [0x0,0x0]. PM=0 is server mode (the default)
-while PM=1 is desktop mode. Desktop mode can be set (both current and
-saved) with:
-.PP
- sdparm --page=0 --set=2:7:1=1 --save /dev/sda
-.PP
-The resultant change can be viewed in hex with the '--hex' option as
-there are no acronyms for vendor extensions yet.
-.SH AUTHORS
-Written by Douglas Gilbert.
-.SH "REPORTING BUGS"
-Report bugs to <dgilbert at interlog dot com>.
-.SH COPYRIGHT
-Copyright \(co 2005 Douglas Gilbert
-.br
-This software is distributed under a FreeBSD license. There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-.SH "SEE ALSO"
-.B sg_modes(sg3_utils), sg_wr_mode(sg3_utils), sginfo(sg3_utils)
-.B sg_senddiag(sg3_utils), smartmontools(internet, sourceforge)
diff --git a/archive/sdparm.c b/archive/sdparm.c
deleted file mode 100644
index 6fa7f291..00000000
--- a/archive/sdparm.c
+++ /dev/null
@@ -1,1501 +0,0 @@
-/*
- * Copyright (c) 2005 Douglas Gilbert.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <ctype.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include "sg_include.h"
-#include "sg_lib.h"
-#include "sg_cmds.h"
-
-/* A utility program for the Linux OS SCSI subsystem.
- *
- * This utility fetches various parameters associated with a given
- * SCSI disk (or a disk that uses, or translates the SCSI command
- * set). In some cases these parameters can be changed.
- */
-
-static char * version_str = "0.90 20050411";
-
-#define ME "sdparm: "
-
-#define DEF_MODE_RESP_LEN 252
-#define RW_ERR_RECOVERY_MP 1
-#define DISCONNECT_MP 2
-#define V_ERR_RECOVERY_MP 7
-#define CACHING_MP 8
-#define CONTROL_MP 0xa
-#define POWER_MP 0x1a
-#define IEC_MP 0x1c
-#define PROT_SPEC_LU_MP 0x18
-#define PROT_SPEC_PORT_MP 0x19
-
-#define MODE_DATA_OVERHEAD 128
-#define EBUFF_SZ 256
-#define MAX_MP_IT_VAL 128
-#define MAX_MODE_DATA_LEN 2048
-
-
-static struct option long_options[] = {
- {"six", 0, 0, '6'},
- {"all", 0, 0, 'a'},
- {"clear", 1, 0, 'c'},
- {"defaults", 1, 0, 'D'},
- {"dummy", 1, 0, 'd'},
- {"enumerate", 0, 0, 'e'},
- {"get", 1, 0, 'g'},
- {"help", 0, 0, 'h'},
- {"hex", 0, 0, 'H'},
- {"inquiry", 0, 0, 'i'},
- {"long", 0, 0, 'l'},
- {"page", 1, 0, 'p'},
- {"set", 1, 0, 's'},
- {"save", 0, 0, 'S'},
- {"verbose", 0, 0, 'v'},
- {"version", 0, 0, 'V'},
- {0, 0, 0, 0},
-};
-
-static void usage()
-{
- fprintf(stderr, "Usage: "
- "sdparm [-all] [--clear=<str>] [--defaults] [-dummy] "
- "[--enumerate]\n"
- " [--get=<str>] [--help] [--hex] [--inquiry] "
- "[--long]\n"
- " [--page=<pg>] [--save] [--set=<str>] [--six] "
- "[--verbose]\n"
- " [--version] <scsi_disk>\n"
- " where:\n"
- " --all | -a list all known parameters for given "
- "disk\n"
- " --clear=<str> | -c <str> clear (zero) parameter value(s)\n"
- " --defaults | -D set a mode page to its default "
- "values\n"
- " --dummy | -d don't write back modified mode page\n"
- " --enumerate | -e list known pages and parameters "
- "(ignore disk)\n"
- " --get=<str> | -g <str> get (fetch) parameter value(s)\n"
- " --help | -h print out usage message\n"
- " --hex | -H output in hex rather than name/value "
- "pairs\n"
- " --inquiry | -i output INQUIRY VPD page(s) (def mode "
- "page(s))\n"
- " --long | -l add description to parameter output\n"
- " --page=<pg> | -p <pg> page ([,subpage]) number to output "
- "(or change)\n"
- " --save | -S place mode changes in saved page as "
- "well\n"
- " --set=<str> | -s <str> set parameter value(s)\n"
- " --six | -6 use 6 byte SCSI cdbs (def 10 byte)\n"
- " --verbose | -v increase verbosity\n"
- " --version | -V print version string and exit\n\n"
- "View or change parameters of a SCSI disk\n"
- );
-}
-
-struct values_name_t {
- int value;
- int subvalue;
- const char * acron;
- const char * name;
-};
-
-static struct values_name_t mode_nums_name[] = {
- {CACHING_MP, 0, "ca", "Caching"},
- {CONTROL_MP, 0, "co", "Control"},
- {DISCONNECT_MP, 0, "dr", "Disconnect-reconnect"},
- {IEC_MP, 0, "ie", "Informational exception control"},
- {PROT_SPEC_LU_MP, 0, "pl", "Protocol specific logical unit"},
- {POWER_MP, 0, "po", "Power condition"},
- {PROT_SPEC_PORT_MP, 0, "pp", "Protocol specific port"},
- {RW_ERR_RECOVERY_MP, 0, "rw", "Read write error recovery"},
- {V_ERR_RECOVERY_MP, 0, "ve", "Verify error recovery"},
-};
-
-static int mode_nums_name_len =
- (sizeof(mode_nums_name) / sizeof(mode_nums_name[0]));
-
-static void list_mps()
-{
- int k;
- const struct values_name_t * vnp;
-
- for (k = 0, vnp = mode_nums_name; k < mode_nums_name_len; ++k, ++vnp) {
- if (vnp->subvalue)
- printf(" %-4s 0x%02x,0x%02x %s\n", vnp->acron, vnp->value,
- vnp->subvalue, vnp->name);
- else
- printf(" %-4s 0x%02x %s\n", vnp->acron, vnp->value,
- vnp->name);
- }
-}
-
-static const char * get_mode_name(int page_num, int subpage_num)
-{
- int k;
- const struct values_name_t * vnp;
-
- for (k = 0, vnp = mode_nums_name; k < mode_nums_name_len; ++k, ++vnp) {
- if ((page_num == vnp->value) && (subpage_num == vnp->subvalue))
- return vnp->name;
- }
- return NULL;
-}
-
-static const struct values_name_t * find_mp_by_acron(const char * ap)
-{
- int k;
- const struct values_name_t * vnp;
-
- for (k = 0, vnp = mode_nums_name; k < mode_nums_name_len; ++k, ++vnp) {
- if (0 == strncmp(vnp->acron, ap, 2))
- return vnp;
- }
- return NULL;
-}
-
-struct mode_page_item {
- const char * acron;
- int page_num;
- int subpage_num;
- int start_byte;
- int start_bit;
- int num_bits;
- int common;
- const char * description;
-};
-
-struct mode_page_it_val {
- struct mode_page_item mpi;
- int val;
-};
-
-struct mode_page_settings {
- int page_num;
- int subpage_num;
- struct mode_page_it_val it_vals[MAX_MP_IT_VAL];
- int num_it_vals;
-};
-
-
-static struct mode_page_item mitem_arr[] = {
- {"AWRE", RW_ERR_RECOVERY_MP, 0, 2, 7, 1, 1, /* [0x1] sbc2 */
- "Automatic write reallocation enabled"},
- {"ARRE", RW_ERR_RECOVERY_MP, 0, 2, 6, 1, 1,
- "Automatic read reallocation enabled"},
- {"TB", RW_ERR_RECOVERY_MP, 0, 2, 5, 1, 0,
- "Transfer block"},
- {"RC", RW_ERR_RECOVERY_MP, 0, 2, 4, 1, 0,
- "Read continuous"},
- {"EER", RW_ERR_RECOVERY_MP, 0, 2, 3, 1, 0,
- "Enable early recover"},
- {"PER", RW_ERR_RECOVERY_MP, 0, 2, 2, 1, 1,
- "Post error"},
- {"DTE", RW_ERR_RECOVERY_MP, 0, 2, 1, 1, 0,
- "Data terminate on error"},
- {"DCR", RW_ERR_RECOVERY_MP, 0, 2, 0, 1, 0,
- "Disable correction"},
- {"RRC", RW_ERR_RECOVERY_MP, 0, 3, 7, 8, 0,
- "Read retry count"},
- {"WRC", RW_ERR_RECOVERY_MP, 0, 8, 7, 8, 0,
- "Write retry count"},
- {"RTL", RW_ERR_RECOVERY_MP, 0, 10, 7, 16, 0,
- "Recovery time limit (ms)"},
-
- {"BITL", DISCONNECT_MP, 0, 4, 7, 16, 0, /* [0x2] spc3,sas1 */
- "Bus inactivity time limit (sas: 100us)"},
- {"MCTL", DISCONNECT_MP, 0, 8, 7, 16, 0,
- "Maximum connect time limit (sas: 100us)"},
- {"MBS", DISCONNECT_MP, 0, 10, 7, 16, 0,
- "Maximum burst size"},
- {"FBS", DISCONNECT_MP, 0, 14, 7, 16, 0,
- "First burst size"},
-
- {"V_EER", V_ERR_RECOVERY_MP, 0, 2, 3, 1, 0, /* [0x8] sbc2 */
- "Enable early recover"},
- {"V_PER", V_ERR_RECOVERY_MP, 0, 2, 2, 1, 0,
- "Post error"},
- {"V_DTE", V_ERR_RECOVERY_MP, 0, 2, 1, 1, 0,
- "Data terminate on error"},
- {"V_DCR", V_ERR_RECOVERY_MP, 0, 2, 0, 1, 0,
- "Disable correction"},
- {"V_RC", V_ERR_RECOVERY_MP, 0, 3, 7, 8, 0,
- "Verify retry count"},
- {"V_RTL", V_ERR_RECOVERY_MP, 0, 10, 7, 16, 0,
- "Verify recovery time limit (ms)"},
-
- {"IC", CACHING_MP, 0, 2, 7, 1, 0, /* [0x8] sbc2 */
- "Initiator control"},
- {"ABPF", CACHING_MP, 0, 2, 6, 1, 0,
- "Abort pre-fetch"},
- {"CAP", CACHING_MP, 0, 2, 5, 1, 0,
- "Caching analysis permitted"},
- {"DISC", CACHING_MP, 0, 2, 4, 1, 0,
- "Discontinuity"},
- {"SIZE", CACHING_MP, 0, 2, 3, 1, 0,
- "Size"},
- {"WCE", CACHING_MP, 0, 2, 2, 1, 1,
- "Write cache enable"},
- {"MF", CACHING_MP, 0, 2, 1, 1, 0,
- "Multiplication factor"},
- {"RCD", CACHING_MP, 0, 2, 0, 1, 1,
- "Read cache disable"},
- {"DRRP", CACHING_MP, 0, 3, 7, 4, 0,
- "Demand read retension prioriry"},
- {"WRP", CACHING_MP, 0, 3, 3, 4, 0,
- "Write retension prioriry"},
- {"DPTL", CACHING_MP, 0, 4, 7, 16, 0,
- "Disable pre-fetch transfer length"},
- {"MIPF", CACHING_MP, 0, 6, 7, 16, 0,
- "Minimum pre-fetch"},
- {"MAPF", CACHING_MP, 0, 8, 7, 16, 0,
- "Maximum pre-fetch"},
- {"MAPFC", CACHING_MP, 0, 10, 7, 16, 0,
- "Maximum pre-fetch ceiling"},
- {"FSW", CACHING_MP, 0, 12, 7, 1, 0,
- "Force sequential write"},
- {"LBCSS", CACHING_MP, 0, 12, 5, 1, 0,
- "Logical block cache segment size"},
- {"DRA", CACHING_MP, 0, 12, 4, 1, 0,
- "disable read ahead"},
- {"NV_DIS", CACHING_MP, 0, 12, 0, 1, 0,
- "Non-volatile cache disbale"},
- {"NCS", CACHING_MP, 0, 13, 7, 8, 0,
- "Number of cache segments"},
- {"CSS", CACHING_MP, 0, 14, 7, 16, 0,
- "Cache segment size"},
-
- {"TST", CONTROL_MP, 0, 2, 7, 3, 0, /* [0xa] spc3 */
- "Task set type"},
- {"TMF_ONLY", CONTROL_MP, 0, 2, 4, 1, 0,
- "Task management functions only"},
- {"D_SENSE", CONTROL_MP, 0, 2, 2, 1, 0,
- "Descriptor format sense data"},
- {"GLTSD", CONTROL_MP, 0, 2, 1, 1, 0,
- "Global logging target save disable"},
- {"RLEC", CONTROL_MP, 0, 2, 0, 1, 0,
- "Report log exception condition"},
- {"QAM", CONTROL_MP, 0, 3, 7, 4, 0,
- "Queue algorithm modifier"},
- {"QERR", CONTROL_MP, 0, 3, 2, 2, 0,
- "Queue error management"},
- {"RAC", CONTROL_MP, 0, 4, 6, 1, 0,
- "Report a check"},
- {"UA_INTLCK", CONTROL_MP, 0, 4, 5, 2, 0,
- "Unit attention interlocks controls"},
- {"SWP", CONTROL_MP, 0, 4, 3, 1, 1,
- "Software write protect"},
- {"ATO", CONTROL_MP, 0, 5, 7, 1, 0,
- "Application tag owner"},
- {"TAS", CONTROL_MP, 0, 5, 6, 1, 0,
- "Task aborted status"},
- {"AUTOLOAD", CONTROL_MP, 0, 5, 2, 3, 0,
- "Autoload mode"},
- {"BTP", CONTROL_MP, 0, 8, 7, 16, 0,
- "Busy timeout period (100us)"},
- {"ESTCT", CONTROL_MP, 0, 10, 7, 16, 0,
- "Extended self test completion time (sec)"},
-
- {"PID", PROT_SPEC_PORT_MP, 0, 2, 3, 4, 0, /* [0x19] spc3 */
- "Protocol identifier"},
-
- {"LUPID", PROT_SPEC_LU_MP, 0, 2, 3, 4, 0, /* [0x18] spc3 */
- "Protocol identifier"},
-
- {"IDLE", POWER_MP, 0, 3, 1, 1, 0, /* [0x1a] spc3 */
- "Idle timer active"},
- {"STANDBY", POWER_MP, 0, 3, 0, 1, 0,
- "Standby timer active"},
- {"ICT", POWER_MP, 0, 4, 7, 32, 0,
- "Idle condition timer (100 ms)"},
- {"SCT", POWER_MP, 0, 8, 7, 32, 0,
- "Standby condition timer (100 ms)"},
-
- {"PERF", IEC_MP, 0, 2, 7, 1, 0, /* [0x1c] spc3 */
- "Performance"},
- {"EBF", IEC_MP, 0, 2, 5, 1, 0,
- "Enable background function"},
- {"EWASC", IEC_MP, 0, 2, 4, 1, 1,
- "Enable warning"},
- {"DEXCPT", IEC_MP, 0, 2, 3, 1, 1,
- "Disable exceptions"},
- {"TEST", IEC_MP, 0, 2, 2, 1, 0,
- "Test (simulate device failure"},
- {"LOGERR", IEC_MP, 0, 2, 0, 1, 0,
- "Log errors"},
- {"MRIE", IEC_MP, 0, 3, 3, 4, 1,
- "Method of reporting infomational exceptions"},
- {"INTT", IEC_MP, 0, 4, 7, 32, 0,
- "Interval timer (100 ms)"},
- {"REPC", IEC_MP, 0, 8, 7, 32, 0,
- "Report count"},
-};
-
-static int mitem_arr_len = (sizeof(mitem_arr) / sizeof(mitem_arr[0]));
-
-static void list_mitems(int pn, int spn)
-{
- int k, t_pn, t_spn;
- const struct mode_page_item * mpi;
- const char * name;
- int found = 0;
-
- t_pn = -1;
- t_spn = -1;
- for (k = 0, mpi = mitem_arr; k < mitem_arr_len; ++k, ++mpi) {
- if ((t_pn != mpi->page_num) || (t_spn != mpi->subpage_num)) {
- t_pn = mpi->page_num;
- t_spn = mpi->subpage_num;
- if ((pn >= 0) && ((pn != t_pn) || (spn != t_spn)))
- continue;
- name = get_mode_name(t_pn, t_spn);
- if (name) {
- if (t_spn)
- printf("%s mode page [0x%x,0x%x]:\n", name, t_pn, t_spn);
- else
- printf("%s mode page [0x%x]:\n", name, t_pn);
- } else if (0 == t_spn)
- printf("mode page 0x%x:\n", t_pn);
- else
- printf("mode page 0x%x,0x%x:\n", t_pn, t_spn);
- } else {
- if ((pn >= 0) && ((pn != t_pn) || (spn != t_spn)))
- continue;
- }
- printf(" %-10s [0x%02x:%d:%-2d] %s\n", mpi->acron, mpi->start_byte,
- mpi->start_bit, mpi->num_bits, mpi->description);
- found = 1;
- }
- if ((! found) && (pn >= 0)) {
- name = get_mode_name(pn, spn);
- if (name) {
- if (spn)
- printf("%s mode page [0x%x,0x%x]: no items found\n", name,
- pn, spn);
- else
- printf("%s mode page [0x%x]: no items found\n", name, pn);
- } else if (0 == spn)
- printf("mode page 0x%x: no items found\n", pn);
- else
- printf("mode page 0x%x,0x%x: no items found\n", pn, spn);
- }
-}
-
-static const struct mode_page_item * find_mitem_by_acron(const char * ap, int * from)
-{
- int k = 0;
- const struct mode_page_item * mpi;
-
- if (from) {
- k = *from;
- if (k < 0)
- k = 0;
- }
- for (mpi = mitem_arr + k; k < mitem_arr_len; ++k, ++mpi) {
- if (0 == strcmp(mpi->acron, ap))
- break;
- }
- if (k >= mitem_arr_len) {
- k = mitem_arr_len;
- mpi = NULL;
- }
- if (from)
- *from = k + 1;
- return mpi;
-}
-
-static const char * scsi_ptype_strs[] = {
- /* 0 */ "disk",
- "tape",
- "printer",
- "processor",
- "write once optical disk",
- /* 5 */ "cd/dvd",
- "scanner",
- "optical memory device",
- "medium changer",
- "communications",
- /* 0xa */ "graphics",
- "graphics",
- "storage array controller",
- "enclosure services device",
- "simplified direct access device",
- "optical card reader/writer device",
- /* 0x10 */ "bridge controller commands",
- "object based storage",
- "automation/driver interface",
- "0x13", "0x14", "0x15", "0x16", "0x17", "0x18",
- "0x19", "0x1a", "0x1b", "0x1c", "0x1d",
- "well known logical unit",
- "no physical device on this lu",
-};
-
-static unsigned int get_big_endian(const unsigned char * from, int start_bit,
- int num_bits)
-{
- unsigned int res;
- int sbit_o1 = start_bit + 1;
-
- res = (*from++ & ((1 << sbit_o1) - 1));
- num_bits -= sbit_o1;
- while (num_bits > 0) {
- res <<= 8;
- res |= *from++;
- num_bits -= 8;
- }
- if (num_bits < 0)
- res >>= (-num_bits);
- return res;
-}
-
-static void set_big_endian(unsigned int val, unsigned char * to,
- int start_bit, int num_bits)
-{
- int sbit_o1 = start_bit + 1;
- int mask, num, k, x;
-
- mask = (8 != sbit_o1) ? ((1 << sbit_o1) - 1) : 0xff;
- k = start_bit - ((num_bits - 1) % 8);
- if (0 != k)
- val <<= ((k > 0) ? k : (8 + k));
- num = (num_bits + 15 - sbit_o1) / 8;
- for (k = 0; k < num; ++k) {
- if ((sbit_o1 - num_bits) > 0)
- mask &= ~((1 << (sbit_o1 - num_bits)) - 1);
- if (k < (num - 1))
- x = (val >> ((num - k - 1) * 8)) & 0xff;
- else
- x = val & 0xff;
- to[k] = (to[k] & ~mask) | (x & mask);
- mask = 0xff;
- num_bits -= sbit_o1;
- sbit_o1 = 8;
- }
-}
-
-static unsigned int mp_get_value(const struct mode_page_item *mpi,
- const unsigned char * mp)
-{
- return get_big_endian(mp + mpi->start_byte, mpi->start_bit,
- mpi->num_bits);
-}
-
-static unsigned int mp_get_value_check(const struct mode_page_item *mpi,
- const unsigned char * mp,
- int * all_set)
-{
- unsigned int res;
-
- res = get_big_endian(mp + mpi->start_byte, mpi->start_bit,
- mpi->num_bits);
- if (all_set) {
- if ((16 == mpi->num_bits) && (0xffff == res))
- *all_set = 1;
- else if ((32 == mpi->num_bits) && (0xffffffff == res))
- *all_set = 1;
- else
- *all_set = 0;
- }
- return res;
-}
-
-static void mp_set_value(unsigned int val, struct mode_page_item *mpi,
- unsigned char * mp)
-{
- set_big_endian(val, mp + mpi->start_byte, mpi->start_bit, mpi->num_bits);
-}
-
-static void print_mp_entry(const char * pre, int smask,
- const struct mode_page_item *mpi,
- const unsigned char * cur_mp,
- const unsigned char * cha_mp,
- const unsigned char * def_mp,
- const unsigned char * sav_mp,
- int long_out)
-{
- int sep = 0;
- int all_set;
- unsigned int u;
- const char * acron;
-
- all_set = 0;
- acron = (mpi->acron ? mpi->acron : "");
- u = mp_get_value_check(mpi, cur_mp, &all_set);
- if (all_set)
- printf("%s%-10s -1", pre, acron);
- else
- printf("%s%-10s %u", pre, acron, u);
- if (smask & 0xe) {
- printf(" [");
- if (smask & 2) {
- printf("Changeable: %s",
- (mp_get_value(mpi, cha_mp) ? "y" : "n"));
- sep = 1;
- }
- if (smask & 4) {
- all_set = 0;
- u = mp_get_value_check(mpi, def_mp, &all_set);
- if (all_set)
- printf("%sdef: -1", (sep ? ", " : " "));
- else
- printf("%sdef: %u", (sep ? ", " : " "), u);
- sep = 1;
- }
- if (smask & 8) {
- all_set = 0;
- u = mp_get_value_check(mpi, sav_mp, &all_set);
- if (all_set)
- printf("%ssaved: -1", (sep ? ", " : " "));
- else
- printf("%ssaved: %u", (sep ? ", " : " "), u);
- }
- printf("]");
- }
- if (long_out && mpi->description)
- printf(" %s", mpi->description);
- printf("\n");
-}
-
-static void print_mode_info(int sg_fd, int mode6, int pn, int spn, int all,
- int long_out, int hex, int verbose)
-{
- int k, res, len, verb, smask, single, fetch;
- const struct mode_page_item * mpi;
- unsigned char cur_mp[DEF_MODE_RESP_LEN];
- unsigned char cha_mp[DEF_MODE_RESP_LEN];
- unsigned char def_mp[DEF_MODE_RESP_LEN];
- unsigned char sav_mp[DEF_MODE_RESP_LEN];
- const char * name;
-
- verb = (verbose > 0) ? verbose - 1 : 0;
- if (pn >= 0) {
- single = 1;
- fetch = 1;
- for (k = 0, mpi = mitem_arr; k < mitem_arr_len; ++k, ++mpi) {
- if ((pn == mpi->page_num) && (spn == mpi->subpage_num))
- break;
- }
- if (k >= mitem_arr_len) {
- if (verbose) {
- if (0 == spn)
- printf("mode page 0x%x, attributes not found\n", pn);
- else
- printf("mode page 0x%x,0x%x, attributes not found\n",
- pn, spn);
- }
- if (hex) {
- k = 0;
- mpi = mitem_arr; /* trick to enter main loop once */
- }
- }
- } else {
- single = 0;
- fetch = 0;
- mpi = mitem_arr;
- k = 0;
- }
- name = "";
- smask = 0;
- for (; k < mitem_arr_len; ++k, ++mpi, fetch = 0) {
- if (0 == fetch) {
- if (! (all || mpi->common))
- continue;
- if ((pn != mpi->page_num) || (spn != mpi->subpage_num)) {
- if (single)
- break;
- fetch = 1;
- pn = mpi->page_num;
- spn = mpi->subpage_num;
- }
- }
- if (fetch) {
- smask = 0;
- res = sg_get_mode_page_types(sg_fd, mode6, pn, spn,
- DEF_MODE_RESP_LEN, &smask, cur_mp,
- cha_mp, def_mp, sav_mp, verb);
- if (SG_LIB_CAT_INVALID_OP == res) {
- if (mode6)
- fprintf(stderr, "6 byte MODE SENSE cdb not supported, "
- "try again without '-6' option\n");
- else
- fprintf(stderr, "10 byte MODE SENSE cdb not supported, "
- "try again with '-6' option\n");
- return;
- }
- if ((smask & 1)) {
- name = get_mode_name(pn, spn);
- if (name) {
- if (0 == spn)
- printf("%s mode page [0x%x]:\n", name, pn);
- else
- printf("%s mode page [0x%x,0x%x]:\n", name, pn, spn);
- } else if (0 == spn)
- printf("mode page 0x%x:\n", pn);
- else
- printf("mode page 0x%x,0x%x:\n", pn, spn);
- if (hex) {
- if (cur_mp[0] & 0x40)
- len = (cur_mp[2] << 8) + cur_mp[3] + 4;
- else
- len = cur_mp[1] + 2;
- printf(" Current:\n");
- dStrHex((const char *)cur_mp, len, 1);
- if (smask & 2) {
- printf(" Changeable:\n");
- dStrHex((const char *)cha_mp, len, 1);
- }
- if (smask & 4) {
- printf(" Default:\n");
- dStrHex((const char *)def_mp, len, 1);
- }
- if (smask & 8) {
- printf(" Saved:\n");
- dStrHex((const char *)sav_mp, len, 1);
- }
- }
- } else {
- if (verbose || single) {
- name = get_mode_name(pn, spn);
- if (name)
- printf(">> %s mode page not supported\n", name);
- else if (0 == spn)
- printf(">> mode page 0x%x not supported\n", pn);
- else
- printf(">> mode page 0x%x,0x%x not supported\n",
- pn, spn);
- }
- }
- }
- if (smask && (! hex))
- print_mp_entry(" ", smask, mpi, cur_mp, cha_mp,
- def_mp, sav_mp, long_out);
- }
-}
-
-static void get_mode_info(int sg_fd, int mode6,
- struct mode_page_settings * mps, int long_out,
- int hex, int verbose)
-{
- int k, res, verb, smask, pn, spn;
- unsigned int u, val;
- const struct mode_page_item * mpi;
- unsigned char cur_mp[DEF_MODE_RESP_LEN];
- unsigned char cha_mp[DEF_MODE_RESP_LEN];
- unsigned char def_mp[DEF_MODE_RESP_LEN];
- unsigned char sav_mp[DEF_MODE_RESP_LEN];
- const struct mode_page_it_val * ivp;
-
- verb = (verbose > 0) ? verbose - 1 : 0;
- for (k = 0, pn = 0, spn = 0; k < mps->num_it_vals; ++k) {
- ivp = &mps->it_vals[k];
- val = ivp->val;
- mpi = &ivp->mpi;
- if ((0 == k) || (pn != mpi->page_num) || (spn != mpi->subpage_num)) {
- pn = mpi->page_num;
- spn = mpi->subpage_num;
- smask = 0;
- switch (val) {
- case 0:
- res = sg_get_mode_page_types(sg_fd, mode6, pn, spn,
- DEF_MODE_RESP_LEN, &smask,
- cur_mp, cha_mp, def_mp, sav_mp,
- verb);
- break;
- case 1:
- res = sg_get_mode_page_types(sg_fd, mode6, pn, spn,
- DEF_MODE_RESP_LEN, &smask,
- cur_mp, NULL, NULL, NULL, verb);
- break;
- default:
- if (mpi->acron)
- fprintf(stderr, "bad format 'val' given to %s\n",
- mpi->acron);
- else
- fprintf(stderr, "bad format 'val' given to 0x%x:%d:%d\n",
- mpi->start_byte, mpi->start_bit, mpi->num_bits);
- return;
- }
- if (SG_LIB_CAT_INVALID_OP == res) {
- if (mode6)
- fprintf(stderr, "6 byte MODE SENSE cdb not supported, "
- "try again without '-6' option\n");
- else
- fprintf(stderr, "10 byte MODE SENSE cdb not supported, "
- "try again with '-6' option\n");
- return;
- }
- }
- if (0 == val) {
- if (hex) {
- if (smask & 1) {
- u = mp_get_value(mpi, cur_mp);
- printf("0x%02x ", u);
- } else
- printf("- ");
- if (smask & 2) {
- u = mp_get_value(mpi, cha_mp);
- printf("0x%02x ", u);
- } else
- printf("- ");
- if (smask & 4) {
- u = mp_get_value(mpi, def_mp);
- printf("0x%02x ", u);
- } else
- printf("- ");
- if (smask & 8) {
- u = mp_get_value(mpi, sav_mp);
- printf("0x%02x ", u);
- } else
- printf("- ");
- printf("\n");
- } else
- print_mp_entry("", smask, mpi, cur_mp, cha_mp,
- def_mp, sav_mp, long_out);
- } else if (1 == val) {
- if (hex) {
- if (smask & 1) {
- u = mp_get_value(mpi, cur_mp);
- printf("0x%02x ", u);
- } else
- printf("- ");
- printf("\n");
- } else
- print_mp_entry("", smask, mpi, cur_mp, NULL,
- NULL, NULL, long_out);
- }
- }
-}
-
-/* Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ ->
- * bad field in cdb, -1 -> other failure */
-static int change_mode_page(int sg_fd, int save, int mode_6,
- struct mode_page_settings * mps, int dummy,
- int verbose)
-{
- int k, len, off, md_len, res;
- char ebuff[EBUFF_SZ];
- unsigned char mdpg[MAX_MODE_DATA_LEN];
- struct mode_page_it_val * ivp;
-
- len = MAX_MODE_DATA_LEN;
- memset(mdpg, 0, len);
- if (mode_6)
- res = sg_ll_mode_sense6(sg_fd, 0 /* dbd */, 0 /*current */,
- mps->page_num, mps->subpage_num,
- mdpg, ((len > 252) ? 252 : len), 1,
- verbose);
- else
- res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, 0 /* dbd */,
- 0 /* current */, mps->page_num,
- mps->subpage_num, mdpg, len, 1, verbose);
- if (0 != res) {
- fprintf(stderr, "change_mode_page: failed fetching page: 0x%x,0x%x\n",
- mps->page_num, mps->subpage_num);
- return -1;
- }
- off = sg_mode_page_offset(mdpg, len, mode_6, ebuff, EBUFF_SZ);
- if (off < 0) {
- fprintf(stderr, "change_mode_page: page offset failed: %s\n", ebuff);
- return -1;
- }
- if (mode_6)
- md_len = mdpg[0] + 1;
- else
- md_len = (mdpg[0] << 8) + mdpg[1] + 2;
- mdpg[0] = 0; /* mode data length reserved for mode select */
- if (! mode_6)
- mdpg[1] = 0; /* mode data length reserved for mode select */
- if (md_len > len) {
- fprintf(stderr, "change_mode_page: mode data length=%d exceeds "
- "allocation length=%d\n", md_len, len);
- return -1;
- }
-
- for (k = 0; k < mps->num_it_vals; ++k) {
- ivp = &mps->it_vals[k];
- mp_set_value(ivp->val, &ivp->mpi, mdpg + off);
- }
-
- if ((! (mdpg[off] & 0x80)) && save) {
- fprintf(stderr, "change_mode_page: mode page indicates it is not "
- "savable but\n '--save' option given (try without "
- "it)\n");
- return -1;
- }
- mdpg[off] &= 0x7f; /* mask out PS bit, reserved in mode select */
- if (dummy) {
- printf("Mode data that would have been written:\n");
- dStrHex((const char *)mdpg, md_len, 1);
- return 0;
- }
- if (verbose) {
- printf("Mode data about to be written:\n");
- dStrHex((const char *)mdpg, md_len, 1);
- }
- if (mode_6)
- res = sg_ll_mode_select6(sg_fd, 1, save, mdpg, md_len, 1,
- verbose);
- else
- res = sg_ll_mode_select10(sg_fd, 1, save, mdpg, md_len, 1,
- verbose);
- if (0 != res) {
- fprintf(stderr, "change__mode_page: failed setting page: 0x%x,0x%x\n",
- mps->page_num, mps->subpage_num);
- return -1;
- }
- return 0;
-}
-
-/* Return of 0 -> success,
- * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ ->
- * bad field in cdb, -1 -> other failure */
-static int set_mode_page(int sg_fd, int pn, int spn, int save, int mode_6,
- unsigned char * mode_pg, int mode_pg_len,
- int dummy, int verbose)
-{
- int len, off, md_len;
- unsigned char * mdp;
- char ebuff[EBUFF_SZ];
- int ret = -1;
-
- len = mode_pg_len + MODE_DATA_OVERHEAD;
- mdp = malloc(len);
- if (NULL ==mdp) {
- fprintf(stderr, "set_mode_page: malloc failed, out of memory\n");
- return -1;
- }
- memset(mdp, 0, len);
- if (mode_6)
- ret = sg_ll_mode_sense6(sg_fd, 0 /* dbd */, 0 /*current */, pn,
- spn, mdp, ((len > 252) ? 252 : len), 1,
- verbose);
- else
- ret = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, 0 /* dbd */,
- 0 /* current */, pn, spn, mdp, len, 1,
- verbose);
- if (0 != ret) {
- fprintf(stderr, "set_mode_page: failed fetching page: 0x%x,0x%x\n",
- pn, spn);
- goto err_out;
- }
- off = sg_mode_page_offset(mdp, len, mode_6, ebuff, EBUFF_SZ);
- if (off < 0) {
- fprintf(stderr, "set_mode_page: page offset failed: %s\n", ebuff);
- ret = -1;
- goto err_out;
- }
- if (mode_6)
- md_len = mdp[0] + 1;
- else
- md_len = (mdp[0] << 8) + mdp[1] + 2;
- mdp[0] = 0; /* mode data length reserved for mode select */
- if (! mode_6)
- mdp[1] = 0; /* mode data length reserved for mode select */
- if (md_len > len) {
- fprintf(stderr, "set_mode_page: mode data length=%d exceeds "
- "allocation length=%d\n", md_len, len);
- ret = -1;
- goto err_out;
- }
- if ((md_len - off) > mode_pg_len) {
- fprintf(stderr, "set_mode_page: mode length length=%d exceeds "
- "new contents length=%d\n", md_len - off, mode_pg_len);
- ret = -1;
- goto err_out;
- }
- memcpy(mdp + off, mode_pg, md_len - off);
- mdp[off] &= 0x7f; /* mask out PS bit, reserved in mode select */
- if (dummy) {
- printf("Mode data that would have been written:\n");
- dStrHex((const char *)mdp, md_len, 1);
- ret = 0;
- goto err_out;
- }
- if (verbose) {
- printf("Mode data about to be written:\n");
- dStrHex((const char *)mdp, md_len, 1);
- }
- if (mode_6)
- ret = sg_ll_mode_select6(sg_fd, 1, save, mdp, md_len, 1,
- verbose);
- else
- ret = sg_ll_mode_select10(sg_fd, 1, save, mdp, md_len, 1,
- verbose);
- if (0 != ret) {
- fprintf(stderr, "set_mode_page: failed setting page: 0x%x,0x%x\n",
- pn, spn);
- goto err_out;
- }
-
-err_out:
- free(mdp);
- return ret;
-}
-
-static int set_mp_defaults(int sg_fd, int pn, int spn, int saved,
- int mode_6, int dummy, int verbose)
-{
- int smask, res, len;
- unsigned char cur_mp[DEF_MODE_RESP_LEN];
- unsigned char def_mp[DEF_MODE_RESP_LEN];
- const char * name;
-
-
- smask = 0;
- res = sg_get_mode_page_types(sg_fd, mode_6, pn, spn, DEF_MODE_RESP_LEN,
- &smask, cur_mp, NULL, def_mp, NULL,
- verbose);
- if (SG_LIB_CAT_INVALID_OP == res) {
- if (mode_6)
- fprintf(stderr, "6 byte MODE SENSE cdb not supported, "
- "try again without '-6' option\n");
- else
- fprintf(stderr, "10 byte MODE SENSE cdb not supported, "
- "try again with '-6' option\n");
- return -1;
- }
- if ((smask & 1)) {
- if ((smask & 4)) {
- if (cur_mp[0] & 0x40)
- len = (cur_mp[2] << 8) + cur_mp[3] + 4; /* spf set */
- else
- len = cur_mp[1] + 2; /* spf clear (not subpage) */
- return set_mode_page(sg_fd, pn, spn, saved, mode_6, def_mp,
- len, dummy, verbose);
- }
- else {
- name = get_mode_name(pn, spn);
- if (name)
- printf(">> %s mode page (default) not supported\n", name);
- else if (0 == spn)
- printf(">> mode page 0x%x (default) not supported\n", pn);
- else
- printf(">> mode page 0x%x,0x%x (default) not supported\n",
- pn, spn);
- return -1;
- }
- } else {
- name = get_mode_name(pn, spn);
- if (name)
- printf(">> %s mode page not supported\n", name);
- else if (0 == spn)
- printf(">> mode page 0x%x not supported\n", pn);
- else
- printf(">> mode page 0x%x,0x%x not supported\n", pn, spn);
- return -1;
- }
-}
-
-/* Trying to decode multipliers as sg_get_num() [in sg_libs does] would
- * only confuse things here, so use this local trimmed version */
-static int get_num(const char * buf)
-{
- int res;
- int num;
- unsigned int unum;
-
- if ((NULL == buf) || ('\0' == buf[0]))
- return -1;
- if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) {
- res = sscanf(buf + 2, "%x", &unum);
- num = unum;
- } else
- res = sscanf(buf, "%d", &num);
- if (1 == res)
- return num;
- else
- return -1;
-}
-
-static int build_mp_settings(const char * arg,
- struct mode_page_settings * mps, int clear,
- int get)
-{
- int len, b_sz, num, from, cont;
- unsigned int u;
- char buff[64];
- char acron[64];
- char vb[64];
- const char * cp;
- const char * ncp;
- const char * ecp;
- struct mode_page_it_val * ivp;
- const struct mode_page_item * mpi;
- const struct mode_page_item * prev_mpi;
-
- b_sz = sizeof(buff) - 1;
- cp = arg;
- while (mps->num_it_vals < MAX_MP_IT_VAL) {
- memset(buff, 0, sizeof(buff));
- ivp = &mps->it_vals[mps->num_it_vals];
- if ('\0' == *cp)
- break;
- ncp = strchr(cp, ',');
- if (ncp) {
- len = ncp - cp;
- if (len <= 0) {
- ++cp;
- continue;
- }
- strncpy(buff, cp, (len < b_sz ? len : b_sz));
- } else
- strncpy(buff, cp, b_sz);
- if (isalpha(buff[0])) {
- ecp = strchr(buff, '=');
- if (ecp) {
- strncpy(acron, buff, ecp - buff);
- acron[ecp - buff] = '\0';
- strcpy(vb, ecp + 1);
- if (0 == strcmp("-1", vb))
- ivp->val = -1;
- else {
- ivp->val = get_num(vb);
- if (-1 == ivp->val) {
- fprintf(stderr, "build_mp_settings: unable to "
- "decode: %s value\n", buff);
- fprintf(stderr, " expected: <acronym>[=<val>]\n");
- return -1;
- }
- }
- } else {
- strcpy(acron, buff);
- ivp->val = ((clear || get) ? 0 : -1);
- }
- from = 0;
- cont = 0;
- prev_mpi = NULL;
- if (get) {
- do {
- mpi = find_mitem_by_acron(acron, &from);
- if (NULL == mpi) {
- if (cont) {
- mpi = prev_mpi;
- break;
- } else
- fprintf(stderr, "build_mp_settings: couldn't "
- "find acronym: %s\n", acron);
- return -1;
- }
- if (mps->page_num < 0) {
- mps->page_num = mpi->page_num;
- mps->subpage_num = mpi->subpage_num;
- break;
- }
- cont = 1;
- prev_mpi = mpi;
- } while ((mps->page_num != mpi->page_num) ||
- (mps->subpage_num != mpi->subpage_num));
- } else {
- do {
- mpi = find_mitem_by_acron(acron, &from);
- if (NULL == mpi) {
- if (cont) {
- fprintf(stderr, "build_mp_settings: mode page "
- "of acronym: %s [0x%x,0x%x] doesn't "
- "match prior\n", acron,
- prev_mpi->page_num,
- prev_mpi->subpage_num);
- fprintf(stderr, " mode page: 0x%x,0x%x\n",
- mps->page_num, mps->subpage_num);
- } else
- fprintf(stderr, "build_mp_settings: couldn't "
- "find acronym: %s\n", acron);
- return -1;
- }
- if (mps->page_num < 0) {
- mps->page_num = mpi->page_num;
- mps->subpage_num = mpi->subpage_num;
- break;
- }
- cont = 1;
- prev_mpi = mpi;
- } while ((mps->page_num != mpi->page_num) ||
- (mps->subpage_num != mpi->subpage_num));
- }
- if (mpi->num_bits < 32)
- ivp->val &= (1 << mpi->num_bits) - 1;
- ivp->mpi = *mpi; /* struct assignment */
- } else { /* expect "byte_off:bit_off:num_bits[=<val>]" */
- if ((0 == strncmp("0x", buff, 2)) ||
- (0 == strncmp("0X", buff, 2))) {
- num = sscanf(buff + 2, "%x:%d:%d=%s", &u,
- &ivp->mpi.start_bit, &ivp->mpi.num_bits, vb);
- ivp->mpi.start_byte = u;
- } else
- num = sscanf(buff, "%d:%d:%d=%s", &ivp->mpi.start_byte,
- &ivp->mpi.start_bit, &ivp->mpi.num_bits, vb);
- if (num < 3) {
- fprintf(stderr, "build_mp_settings: unable to decode: %s\n",
- buff);
- fprintf(stderr, " expected: byte_off:bit_off:num_bits[="
- "<val>]\n");
- return -1;
- }
- if (3 == num)
- ivp->val = ((clear || get) ? 0 : -1);
- else {
- if (0 == strcmp("-1", vb))
- ivp->val = -1;
- else {
- ivp->val = get_num(vb);
- if (-1 == ivp->val) {
- fprintf(stderr, "build_mp_settings: unable to "
- "decode byte_off:bit_off:num_bits value\n");
- return -1;
- }
- }
- }
- if (ivp->mpi.start_byte < 0) {
- fprintf(stderr, "build_mp_settings: need positive start "
- "byte offset\n");
- return -1;
- }
- if ((ivp->mpi.start_bit < 0) || (ivp->mpi.start_bit > 7)) {
- fprintf(stderr, "build_mp_settings: need start bit in "
- "0..7 range (inclusive)\n");
- return -1;
- }
- if ((ivp->mpi.num_bits < 1) || (ivp->mpi.num_bits > 32)) {
- fprintf(stderr, "build_mp_settings: need number of bits in "
- "1..32 range (inclusive)\n");
- return -1;
- }
- if (mps->page_num < 0) {
- fprintf(stderr, "build_mp_settings: need '--page=' option "
- "for mode page number\n");
- return -1;
- } else if (get) {
- ivp->mpi.page_num = mps->page_num;
- ivp->mpi.subpage_num = mps->subpage_num;
- }
- if (ivp->mpi.num_bits < 32)
- ivp->val &= (1 << ivp->mpi.num_bits) - 1;
- }
- ++mps->num_it_vals;
- if (ncp)
- cp = ncp + 1;
- else
- break;
- }
- return 0;
-}
-
-int main(int argc, char * argv[])
-{
- int sg_fd, res, c, pdt, flags;
- int six_byte_cdb = 0;
- int all = 0;
- const char * clear_str = NULL;
- const char * get_str = NULL;
- const char * set_str = NULL;
- int defaults = 0;
- int dummy = 0;
- int enumerate = 0;
- int hex = 0;
- int inquiry = 0;
- int long_out = 0;
- int saved = 0;
- int verbose = 0;
- char device_name[256];
- int pn = -1;
- int spn = -1;
- int rw = 0;
- struct sg_simple_inquiry_resp sir;
- const struct values_name_t * vnp;
- struct mode_page_settings mp_settings;
- char * cp;
- int ret = 1;
-
- memset(device_name, 0, sizeof(device_name));
- memset(&mp_settings, 0, sizeof(mp_settings));
- while (1) {
- int option_index = 0;
-
- c = getopt_long(argc, argv, "6ac:Ddeg:hHilp:s:SvV", long_options,
- &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case '6':
- six_byte_cdb = 1;
- break;
- case 'a':
- all = 1;
- break;
- case 'c':
- clear_str = optarg;
- rw = 1;
- break;
- case 'd':
- dummy = 1;
- break;
- case 'D':
- defaults = 1;
- rw = 1;
- break;
- case 'e':
- enumerate = 1;
- break;
- case 'g':
- get_str = optarg;
- break;
- case 'h':
- case '?':
- usage();
- return 0;
- case 'H':
- hex = 1;
- break;
- case 'i':
- inquiry = 1;
- break;
- case 'l':
- long_out = 1;
- break;
- case 'p':
- if (isalpha(optarg[0])) {
- vnp = find_mp_by_acron(optarg);
- if (NULL == vnp) {
- fprintf(stderr, "mode page acronym not found\n");
- return 1;
- }
- pn = vnp->value;
- spn = vnp->subvalue;
- } else {
- cp = strchr(optarg, ',');
- pn = get_num(optarg);
- if ((pn < 0) || (pn > 255)) {
- fprintf(stderr, "Bad page code value after '-p' "
- "switch\n");
- return 1;
- }
- if (cp) {
- spn = get_num(cp + 1);
- if ((spn < 0) || (spn > 255)) {
- fprintf(stderr, "Bad page code value after "
- "'-p' switch\n");
- return 1;
- }
- } else
- spn = 0;
- }
- break;
- case 's':
- set_str = optarg;
- rw = 1;
- break;
- case 'S':
- saved = 1;
- rw = 1;
- break;
- case 'v':
- ++verbose;
- break;
- case 'V':
- fprintf(stderr, ME "version: %s\n", version_str);
- return 0;
- default:
- fprintf(stderr, "unrecognised switch code 0x%x ??\n", c);
- usage();
- return 1;
- }
- }
- if (optind < argc) {
- if ('\0' == device_name[0]) {
- strncpy(device_name, argv[optind], sizeof(device_name) - 1);
- device_name[sizeof(device_name) - 1] = '\0';
- ++optind;
- }
- if (optind < argc) {
- for (; optind < argc; ++optind)
- fprintf(stderr, "Unexpected extra argument: %s\n",
- argv[optind]);
- usage();
- return 1;
- }
- }
-/* think about --get= with --enumerate */
- if (pn < 0) {
- mp_settings.page_num = -1;
- mp_settings.subpage_num = -1;
- } else {
- mp_settings.page_num = pn;
- mp_settings.subpage_num = spn;
- }
- if (get_str) {
- if (set_str || clear_str) {
- fprintf(stderr, "'--get=' can't be used with '--set=' or "
- "'--clear='\n");
- return 1;
- }
- if (build_mp_settings(get_str, &mp_settings, 0, 1))
- return 1;
- }
- if (enumerate) {
- if (device_name[0] || set_str || clear_str || get_str || saved)
- printf("Most option including <scsi_disk> are ignored when "
- "'--enumerate' is given\n");
- if (pn < 0) {
- printf("Mode pages:\n");
- list_mps();
- }
- if (all || (pn >= 0))
- list_mitems(pn, spn);
- return 0;
- }
- if (0 == device_name[0]) {
- fprintf(stderr, "missing device name!\n");
- usage();
- return 1;
- }
-
- if (inquiry) {
- fprintf(stderr, "INQUIRY VPD pages not supported yet\n");
- return 1;
- }
- if (defaults && (set_str || clear_str || get_str)) {
- fprintf(stderr, "'--get=', '--set=' or '--clear=' can't be used "
- "with '--defaults'\n");
- return 1;
- }
-
- if (set_str) {
- if (build_mp_settings(set_str, &mp_settings, 0, 0))
- return 1;
- }
- if (clear_str) {
- if (build_mp_settings(clear_str, &mp_settings, 1, 0))
- return 1;
- }
-
- if (verbose && (mp_settings.num_it_vals > 0)) {
- struct mode_page_it_val * ivp;
- int k;
-
- printf("mp_settings: page,subpage=0x%x,0x%x num=%d\n",
- mp_settings.page_num, mp_settings.subpage_num,
- mp_settings.num_it_vals);
- for (k = 0; k < mp_settings.num_it_vals; ++k) {
- ivp = &mp_settings.it_vals[k];
- if (get_str)
- printf(" [0x%x,0x%x] byte_off=0x%x, bit_off=%d, num_bits"
- "=%d val=%d acronym: %s\n", ivp->mpi.page_num,
- ivp->mpi.subpage_num, ivp->mpi.start_byte,
- ivp->mpi.start_bit, ivp->mpi.num_bits, ivp->val,
- (ivp->mpi.acron ? ivp->mpi.acron : ""));
- else
- printf(" byte_off=0x%x, bit_off=%d, num_bits=%d "
- " val=%d acronym: %s\n", ivp->mpi.start_byte,
- ivp->mpi.start_bit, ivp->mpi.num_bits, ivp->val,
- (ivp->mpi.acron ? ivp->mpi.acron : ""));
- }
- }
-
- if (defaults && (pn < 0)) {
- fprintf(stderr, "to set defaults, the '--page=' option must "
- "be used\n");
- return 1;
- }
-
- flags = (O_NONBLOCK | (rw ? O_RDWR : O_RDONLY));
- sg_fd = open(device_name, flags);
- if (sg_fd < 0) {
- fprintf(stderr, ME "open error: %s, flags=0x%x: ", device_name,
- flags);
- perror("");
- return 1;
- }
-
- if (sg_simple_inquiry(sg_fd, &sir, 0, verbose)) {
- fprintf(stderr, "SCSI INQUIRY command failed on %s\n", device_name);
- goto err_out;
- }
- pdt = sir.peripheral_type;
- if (0 == hex) {
- printf(" %s: %.8s %.16s %.4s",
- device_name, sir.vendor, sir.product, sir.revision);
- if (0 != pdt)
- printf(" [pdt=%d]", pdt);
- printf("\n");
- if (! ((0 == pdt) || (4 == pdt) || (7 == pdt) || (0xe == pdt))) {
- fprintf(stderr, " expected disk device type, got %s\n",
- scsi_ptype_strs[pdt]);
- }
- }
-
- if ((pn > 0x3e) || (spn > 0xfe)) {
- fprintf(stderr, "Allowable mode page numbers are 0 to 62\n");
- fprintf(stderr, " Allowable mode subpage numbers are 0 to 254\n");
- goto err_out;
- }
- if (defaults) {
- res = set_mp_defaults(sg_fd, pn, spn, saved, six_byte_cdb, dummy,
- verbose);
- if (0 != res)
- goto err_out;
- } else if (set_str || clear_str) {
- if (mp_settings.num_it_vals < 1) {
- fprintf(stderr, "no parameters found to set or clear\n");
- goto err_out;
- }
- res = change_mode_page(sg_fd, saved, six_byte_cdb, &mp_settings,
- dummy, verbose);
- if (0 != res)
- goto err_out;
- } else if (get_str) {
- if (mp_settings.num_it_vals < 1) {
- fprintf(stderr, "no parameters found to get\n");
- goto err_out;
- }
- get_mode_info(sg_fd, six_byte_cdb, &mp_settings, long_out, hex,
- verbose);
- } else
- print_mode_info(sg_fd, six_byte_cdb, pn, spn, ((pn >= 0) ? 1 : all),
- long_out, hex, verbose);
- ret = 0;
-
-err_out:
- res = close(sg_fd);
- if (res < 0) {
- perror(ME "close error");
- return 1;
- }
- return ret;
-}