aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COVERAGE8
-rw-r--r--ChangeLog3
-rw-r--r--README8
-rw-r--r--README.win3211
-rw-r--r--debian/changelog2
-rw-r--r--doc/Makefile.am37
-rw-r--r--doc/Makefile.in37
-rw-r--r--doc/sg_ses.85
-rw-r--r--doc/sg_ses_microcode.8187
-rw-r--r--sg3_utils.spec2
-rw-r--r--src/Makefile.am46
-rw-r--r--src/Makefile.in30
-rw-r--r--src/sg_ses.c61
-rw-r--r--src/sg_ses_microcode.c748
-rw-r--r--src/sg_write_buffer.c70
15 files changed, 1138 insertions, 117 deletions
diff --git a/COVERAGE b/COVERAGE
index b998aefc..b32abd9f 100644
--- a/COVERAGE
+++ b/COVERAGE
@@ -53,7 +53,7 @@ RECEIVE COPY DATA(LID1) sg_copy_results, ++
RECEIVE COPY FAILURE DETAILS(LID1) sg_copy_results, ++
RECEIVE COPY OPERATING PARAMETERS ddpt, sg_copy_results, sg_xcopy, ++
RECEIVE COPY STATUS(LID1) sg_copy_results, ++
-RECEIVE DIAGNOSTIC RESULTS sg_senddiag, sg_ses, ++
+RECEIVE DIAGNOSTIC RESULTS sg_senddiag, sg_ses, sg_ses_microcode ++
RECEIVE ROD TOKEN INFORMATION ddpt, ddptctl ++
REPORT ALL ROD TOKENS ddptctl ++
REPORT IDENTIFYING INFORMATION sg_ident, ++ (2)
@@ -66,7 +66,7 @@ REPORT ZONES sg_rep_zones
REQUEST SENSE sg_requests, ++
RESET WRITE POINTER sg_reset_wp
SANITIZE sg_sanitize
-SEND DIAGNOSTIC sg_senddiag, sg_ses, ++
+SEND DIAGNOSTIC sg_senddiag, sg_ses, sg_ses_microcode ++
SET IDENTIFYING INFORMATION sg_ident, ++ (3)
SET TARGET PORT GROUPS sg_stpg, ++
START STOP sg_start, ++
@@ -80,6 +80,8 @@ WRITE(6) sg_dd, sgm_dd, sgp_dd
WRITE(10) sg_dd, sgm_dd, sgp_dd
WRITE(12) sg_dd, sgm_dd, sgp_dd
WRITE(16) sg_dd, sgm_dd, sgp_dd
+WRITE AND VERIFY(10) sg_write_verify
+WRITE AND VERIFY(16) sg_write_verify
WRITE ATOMIC(16) ddpt
WRITE BUFFER sg_test_rwbuf, sg_write_buffer, ++
WRITE LONG(10) sg_write_long, ++
@@ -118,4 +120,4 @@ THIRD PARTY COPY IN (0x83).
Douglas Gilbert
-10th June 2014
+29th September 2014
diff --git a/ChangeLog b/ChangeLog
index e1f82cbb..b68c6569 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,8 +2,9 @@ Each utility has its own version number, date of last change and
some description at the top of its ".c" file. All utilities in the main
directory have their own "man" pages. There is also a sg3_utils man page.
-Changelog for sg3_utils-1.40 [20140923] [svn: r609]
+Changelog for sg3_utils-1.40 [20140929] [svn: r610]
- sg_write_verify: new utility for WRITE AND VERIFY
+ - sg_ses_microcode: new utility
- sg_senddiag: add --maxlen= option
- sg_copy_results: correct response length calculations
- sg_format: make '-FFF' bypass mode sense/select
diff --git a/README b/README
index 9d9ec095..c2c1c990 100644
--- a/README
+++ b/README
@@ -236,9 +236,9 @@ subdirectory of the sg3_utils package:
sg_read, sg_readcap, sg_read_block_limits, sg_read_buffer, sg_read_long,
sg_reassign, sg_referrals, sg_request, sg_reset, sg_rmsn, sg_rtpg,
sg_safte, sg_sanitize, sg_sat_identify, sg_sat_phy_event,
- sg_sat_set_features, sg_scan, sg_senddiag, sg_ses, sg_start, sg_stpg,
- sg_sync, sg_test_rwbuff, sg_turs, sg_unmap, sg_verify, sg_vpd,
- sg_write_buffer, sg_write_long, sg_write_same, sg_write_verify
+ sg_sat_set_features, sg_scan, sg_senddiag, sg_ses, sg_ses_microcode,
+ sg_start, sg_stpg, sg_sync, sg_test_rwbuff, sg_turs, sg_unmap, sg_verify,
+ sg_vpd, sg_write_buffer, sg_write_long, sg_write_same, sg_write_verify
sg_wr_mode, sg_xcopy
Each of the above utilities depends on header files found in the 'include'
@@ -411,4 +411,4 @@ See http://sg.danny.cz/sg/tools.html
Douglas Gilbert
-21st September 2014
+29th September 2014
diff --git a/README.win32 b/README.win32
index f609e691..cfce3ed3 100644
--- a/README.win32
+++ b/README.win32
@@ -208,6 +208,15 @@ MSYS or "cmd" shell. Various build options are available by giving
command line options to "./configure", see the INSTALL file for generic
information about the build infrastructure.
+MinGW can be used to cross built on some Redhat (Linux) platforms. After
+loading the cross build packages, the ./configure call in the normal
+autotools sequence should be replaced by either mingw32-configure or
+mingw64-configure. These scripts will set up the environment for
+the cross build and then call ./configure (so this invocation should be
+made in the top level of the untarred source). Options given to either
+script (e.g. --enable-win32-spt-direct) will be passed through to
+./configure .
+
Binary and Text files
=====================
A problem has been reported with binary output being written in a MinGW
@@ -221,4 +230,4 @@ mode" with the setmode() Windows command.
Douglas Gilbert
-7th August 2014
+24th September 2014
diff --git a/debian/changelog b/debian/changelog
index 9ec56d70..f3c41a6e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,7 +2,7 @@ sg3-utils (1.40-0.1) unstable; urgency=low
* New upstream version
- -- Douglas Gilbert <dgilbert@interlog.com> Sun, 21 Sep 2014 12:00:00 -0400
+ -- Douglas Gilbert <dgilbert@interlog.com> Mon, 29 Sep 2014 13:00:00 -0400
sg3-utils (1.39-0.1) unstable; urgency=low
diff --git a/doc/Makefile.am b/doc/Makefile.am
index f7411a7b..8b9d824c 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -21,9 +21,10 @@ man_MANS = \
sg_rep_zones.8 sg_requests.8 sg_reset.8 sg_reset_wp.8 sg_rmsn.8 \
sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
sg_sat_phy_event.8 sg_sat_set_features.8 sg_scan.8 sg_senddiag.8 \
- sg_ses.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_test_rwbuf.8 sg_turs.8 \
- sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \
- sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 sg_xcopy.8
+ sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 \
+ sg_test_rwbuf.8 sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 \
+ sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \
+ sg_write_verify.8 sg_wr_mode.8 sg_xcopy.8
distclean-local:
rm -f sg_scan.8
@@ -48,9 +49,9 @@ man_MANS = \
sg_requests.8 sg_reset_wp.8 sg_rmsn.8 \
sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
sg_sat_phy_event.8 sg_sat_set_features.8 sg_scan.8 sg_senddiag.8 \
- sg_ses.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 sg_unmap.8 \
- sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \
- sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
+ sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 \
+ sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 \
+ sg_write_long.8 sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
distclean-local:
rm -f sg_scan.8
@@ -75,9 +76,9 @@ man_MANS = \
sg_requests.8 sg_reset_wp.8 sg_rmsn.8 \
sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
sg_sat_phy_event.8 sg_sat_set_features.8 sg_scan.8 sg_senddiag.8 \
- sg_ses.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 sg_unmap.8 \
- sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \
- sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
+ sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 \
+ sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 \
+ sg_write_long.8 sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
distclean-local:
rm -f sg_scan.8
@@ -99,9 +100,9 @@ man_MANS = \
sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \
sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \
sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \
- sg_requests.8 sg_reset_wp.8 sg_rmsn.8 \
- sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
- sg_sat_phy_event.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \
+ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \
+ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \
+ sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 sg_ses_microcode.8 \
sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 sg_unmap.8 sg_verify.8 \
sg_vpd.8 sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \
sg_write_verify.8 sg_wr_mode.8
@@ -123,9 +124,9 @@ man_MANS = \
sg_requests.8 sg_reset_wp.8 sg_rmsn.8 \
sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
sg_sat_phy_event.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \
- sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 sg_unmap.8 sg_verify.8 \
- sg_vpd.8 sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \
- sg_write_verify.8 sg_wr_mode.8
+ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 \
+ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \
+ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
endif
@@ -144,9 +145,9 @@ man_MANS = \
sg_requests.8 sg_reset_wp.8 sg_rmsn.8 \
sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
sg_sat_phy_event.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \
- sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 sg_unmap.8 sg_verify.8 \
- sg_vpd.8 sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \
- sg_write_verify.8 sg_wr_mode.8
+ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 \
+ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \
+ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
endif
diff --git a/doc/Makefile.in b/doc/Makefile.in
index f4df4c2a..2e079ecf 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -266,9 +266,9 @@ top_srcdir = @top_srcdir@
@OS_FREEBSD_TRUE@ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \
@OS_FREEBSD_TRUE@ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \
@OS_FREEBSD_TRUE@ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \
-@OS_FREEBSD_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 \
-@OS_FREEBSD_TRUE@ sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
-@OS_FREEBSD_TRUE@ sg_sat_phy_event.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \
+@OS_FREEBSD_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \
+@OS_FREEBSD_TRUE@ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \
+@OS_FREEBSD_TRUE@ sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 sg_ses_microcode.8 \
@OS_FREEBSD_TRUE@ sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 sg_unmap.8 sg_verify.8 \
@OS_FREEBSD_TRUE@ sg_vpd.8 sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \
@OS_FREEBSD_TRUE@ sg_write_verify.8 sg_wr_mode.8
@@ -293,9 +293,10 @@ top_srcdir = @top_srcdir@
@OS_LINUX_TRUE@ sg_rep_zones.8 sg_requests.8 sg_reset.8 sg_reset_wp.8 sg_rmsn.8 \
@OS_LINUX_TRUE@ sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
@OS_LINUX_TRUE@ sg_sat_phy_event.8 sg_sat_set_features.8 sg_scan.8 sg_senddiag.8 \
-@OS_LINUX_TRUE@ sg_ses.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_test_rwbuf.8 sg_turs.8 \
-@OS_LINUX_TRUE@ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \
-@OS_LINUX_TRUE@ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 sg_xcopy.8
+@OS_LINUX_TRUE@ sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 \
+@OS_LINUX_TRUE@ sg_test_rwbuf.8 sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 \
+@OS_LINUX_TRUE@ sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \
+@OS_LINUX_TRUE@ sg_write_verify.8 sg_wr_mode.8 sg_xcopy.8
@OS_OSF_TRUE@man_MANS = \
@OS_OSF_TRUE@ sg3_utils.8 sg_decode_sense.8 \
@@ -309,9 +310,9 @@ top_srcdir = @top_srcdir@
@OS_OSF_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 \
@OS_OSF_TRUE@ sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
@OS_OSF_TRUE@ sg_sat_phy_event.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \
-@OS_OSF_TRUE@ sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 sg_unmap.8 sg_verify.8 \
-@OS_OSF_TRUE@ sg_vpd.8 sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \
-@OS_OSF_TRUE@ sg_write_verify.8 sg_wr_mode.8
+@OS_OSF_TRUE@ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 \
+@OS_OSF_TRUE@ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \
+@OS_OSF_TRUE@ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
@OS_SOLARIS_TRUE@man_MANS = \
@OS_SOLARIS_TRUE@ sg3_utils.8 sg_decode_sense.8 \
@@ -325,9 +326,9 @@ top_srcdir = @top_srcdir@
@OS_SOLARIS_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 \
@OS_SOLARIS_TRUE@ sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
@OS_SOLARIS_TRUE@ sg_sat_phy_event.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \
-@OS_SOLARIS_TRUE@ sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 sg_unmap.8 sg_verify.8 \
-@OS_SOLARIS_TRUE@ sg_vpd.8 sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \
-@OS_SOLARIS_TRUE@ sg_write_verify.8 sg_wr_mode.8
+@OS_SOLARIS_TRUE@ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 \
+@OS_SOLARIS_TRUE@ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \
+@OS_SOLARIS_TRUE@ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
@OS_WIN32_CYGWIN_TRUE@man_MANS = \
@OS_WIN32_CYGWIN_TRUE@ sg3_utils.8 sg_decode_sense.8 \
@@ -341,9 +342,9 @@ top_srcdir = @top_srcdir@
@OS_WIN32_CYGWIN_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 \
@OS_WIN32_CYGWIN_TRUE@ sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
@OS_WIN32_CYGWIN_TRUE@ sg_sat_phy_event.8 sg_sat_set_features.8 sg_scan.8 sg_senddiag.8 \
-@OS_WIN32_CYGWIN_TRUE@ sg_ses.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 sg_unmap.8 \
-@OS_WIN32_CYGWIN_TRUE@ sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \
-@OS_WIN32_CYGWIN_TRUE@ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
+@OS_WIN32_CYGWIN_TRUE@ sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 \
+@OS_WIN32_CYGWIN_TRUE@ sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 \
+@OS_WIN32_CYGWIN_TRUE@ sg_write_long.8 sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
@OS_WIN32_MINGW_TRUE@man_MANS = \
@OS_WIN32_MINGW_TRUE@ sg3_utils.8 sg_decode_sense.8 \
@@ -357,9 +358,9 @@ top_srcdir = @top_srcdir@
@OS_WIN32_MINGW_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 \
@OS_WIN32_MINGW_TRUE@ sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \
@OS_WIN32_MINGW_TRUE@ sg_sat_phy_event.8 sg_sat_set_features.8 sg_scan.8 sg_senddiag.8 \
-@OS_WIN32_MINGW_TRUE@ sg_ses.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 sg_unmap.8 \
-@OS_WIN32_MINGW_TRUE@ sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \
-@OS_WIN32_MINGW_TRUE@ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
+@OS_WIN32_MINGW_TRUE@ sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 \
+@OS_WIN32_MINGW_TRUE@ sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 \
+@OS_WIN32_MINGW_TRUE@ sg_write_long.8 sg_write_same.8 sg_write_verify.8 sg_wr_mode.8
all: all-am
diff --git a/doc/sg_ses.8 b/doc/sg_ses.8
index 07955317..a8bdc4bf 100644
--- a/doc/sg_ses.8
+++ b/doc/sg_ses.8
@@ -37,7 +37,8 @@ to flash on a disk carrier in an array) is typically done using a
read\-modify\-write cycle. See the section on CHANGING STATE below.
.PP
There is a web page discussing this utility at
-http://sg.danny.cz/sg/sg_ses.html .
+http://sg.danny.cz/sg/sg_ses.html . Support for downloading microcode to
+a SES device has been placed in a separate utility called sg_ses_microcode.
.PP
In the following sections "page" refers to a diagnostic page, either
fetched with a SCSI RECEIVE DIAGNOSTIC RESULTS command or sent to the
@@ -550,5 +551,5 @@ Copyright \(co 2004\-2014 Douglas Gilbert
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_inq, sg_safte, sg_senddiag, sg3_utils (in sg3_utils package);
+.B sg_inq, sg_safte, sg_senddiag, sg_ses_microcode, sg3_utils (sg3_utils);
.B safte\-monitor (Internet)
diff --git a/doc/sg_ses_microcode.8 b/doc/sg_ses_microcode.8
new file mode 100644
index 00000000..b7ead358
--- /dev/null
+++ b/doc/sg_ses_microcode.8
@@ -0,0 +1,187 @@
+.TH SG_SES_MICROCODE "8" "September 2014" "sg3_utils\-1.39" SG3_UTILS
+.SH NAME
+sg_ses_microcode \- send microcode to a SCSI enclosure
+.SH SYNOPSIS
+.B sg_ses_microcode
+[\fI\-\-bpw=CS\fR] [\fI\-\-help\fR] [\fI\-\-id=ID\fR] [\fI\-\-in=FILE\fR]
+[\fI\-\-length=LEN\fR] [\fI\-\-mode=MO\fR] [\fI\-\-offset=OFF\fR]
+[\fI\-\-skip=SKIP\fR] [\fI\-\-subenc=MS\fR] [\fI\-\-tlength=TLEN\fR]
+[\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR
+.SH DESCRIPTION
+.\" Add any additional description here
+.PP
+This utility attempts to download microcode to an enclosure (or an
+associated sub\-enclosure) associated with the \fIDEVICE\fR. The
+process for doing this is defined in the SCSI Enclosure Services (SES)
+standards and drafts maintained by the T10 committee.
+.PP
+The process is to send one or more sequences containing a SCSI SEND
+DIAGNOSTIC command followed by a RECEIVE DIAGNOSTIC RESULTS command. The
+former sends a Download microcode Control diagnostic page (dpage) and
+the latter fetches a Download microcode status dpage which can be viewed
+as a report on the former command.
+.PP
+The default action (i.e. when the \fI\-\-mode=MO\fR option is not given)
+is fetch the Download microcode status dpage and print it to the console.
+This does not need any additional data so the \fI\-\-in=FILE\fR option
+is not required.
+.PP
+The most recent reference for this utility is the draft SCSI Enclosure
+Services 3 (SES\-3) document T10/2149\-D Revision 6 at http://www.t10.org .
+Existing standards for SES and SES\-2 are ANSI INCITS 305\-1998 and ANSI
+INCITS 448\-2008 respectively.
+.PP
+Most other support for SES in this package (apart from downloading
+microcode) can be found in the sg_ses package. Another way of downloading
+firmware to a SCSI device is with the WRITE BUFFER command defined in
+SPC\-4, see the sg_write_buffer utility.
+.SH OPTIONS
+Arguments to long options are mandatory for short options as well.
+.TP
+\fB\-b\fR, \fB\-\-bpw\fR=\fICS\fR
+where \fICS\fR is the chunk size in bytes and should be a multiple of 4.
+This will be the maximum number of bytes sent per SEND DIAGNOSTIC command.
+So if \fICS\fR is less than the effective length of the microcode then
+multiple SEND DIAGNOSTIC commands are sent, each taking the next chunk
+from the read data and inceasing the buffer offset field in the Download
+microcode control dpage by the appropriate amount. The default is
+a chunk size of 0 which is interpreted as a very large number hence only
+one SEND DIAGNOSTIC command will be sent.
+.br
+The number in \fICS\fR can optionally be followed by ",act" or ",activate".
+In this case after the microcode has been successfuly sent to the
+\fIDEVICE\fR, an additional Download microcode control dpage with its mode
+set to "Activate deferred microcode" [0xf] is sent.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+output the usage message then exit. If used multiple times also prints
+the mode names and their acronyms.
+.TP
+\fB\-i\fR, \fB\-\-id\fR=\fIID\fR
+this option sets the BUFFER ID field in the Download microcode control
+dpage. \fIID\fR is a value between 0 (default) and 255 inclusive.
+.TP
+\fB\-I\fR, \fB\-\-in\fR=\fIFILE\fR
+read data from file \fIFILE\fR that will be sent with the SEND DIAGNOSTIC
+command. If \fIFILE\fR is '\-' then stdin is read until an EOF is
+detected (this is the same action as \fI\-\-raw\fR). Data is read from
+the beginning of \fIFILE\fR except in the case when it is a regular file
+and the \fI\-\-skip=SKIP\fR option is given.
+.TP
+\fB\-l\fR, \fB\-\-length\fR=\fILEN\fR
+where \fILEN\fR is the length, in bytes, of data to be written to the device.
+If not given (and the length cannot be deduced from \fI\-\-in=FILE\fR or
+\fI\-\-raw\fR) then defaults to zero. If the option is given and the length
+deduced from \fI\-\-in=FILE\fR or \fI\-\-raw\fR is less (or no data is
+provided), then bytes of 0xff are used as fill bytes.
+.TP
+\fB\-m\fR, \fB\-\-mode\fR=\fIMO\fR
+this option sets the MODE. \fIMO\fR is a value between
+0 (which is dmc_status and the default) and 255 inclusive. Alternatively
+an abbreviation can be given. See the MODES section below. To list the
+available mode abbreviations at run time give an invalid
+one (e.g. '\-\-mode=xxx') or use the '\-h' option.
+.TP
+\fB\-o\fR, \fB\-\-offset\fR=\fIOFF\fR
+this option sets the BUFFER OFFSET field in the Download microcode control
+dpage. \fIOFF\fR is a value between 0 (default) and 2**32\-1 . It is a
+byte offset.
+.TP
+\fB\-s\fR, \fB\-\-skip\fR=\fISKIP\fR
+this option is only active when \fI\-\-in=FILE\fR is given and \fIFILE\fR is
+a regular file, rather than stdin. Data is read starting at byte offset
+\fISKIP\fR to the end of file (or the amount given by \fI\-\-length=LEN\fR).
+If not given the byte offset defaults to 0 (i.e. the start of the file).
+.TP
+\fB\-S\fR, \fB\-\-subenc\fR=\fISEID\fR
+\fISEID\fR is the subenclosure identify. It defaults to 0 which is the
+primary enclosure identifier.
+.TP
+\fB\-t\fR, \fB\-\-tlength\fR=\fITLEN\fR
+\fITLEN\fR is the total length in bytes of the microcode to be (or being)
+downloaded. It defaults to 0 which is okay in most cases. This option is
+only needed when sections of microcode and being sent in separate invocations
+of this utility.
+.TP
+\fB\-v\fR, \fB\-\-verbose\fR
+increase the level of verbosity, (i.e. debug output).
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+print the version string and then exit.
+.SH MODES
+Following is a list accepted by the \fIMO\fR argument of this utility.
+First shown is an acronym followed in square brackets by the corresponding
+decimal and hex values that may also be given for \fIMO\fR.
+.TP
+dmc_status [0, 0x0]
+Use RECEIVE DIAGNOSTIC RESULTS to fetch the Download microcode status dpage
+and print it out.
+.TP
+dmc_offs [6, 0x6]
+Download microcode with offsets and activate.
+.TP
+dmc_offs_save [7, 0x7]
+Download microcode with offsets, save, and activate.
+.TP
+dmc_offs_defer [14, 0xe]
+Download microcode with offsets, save, and defer activate.
+.TP
+activate_mc [15, 0xf]
+Activate deferred microcode.
+.PP
+Apart from dmc_status, these are placed in the Download microcode mode
+field in the Download microcode control dpage. In the case of dmc_status
+the Download microcode status dpage is fetch with the RECEIVE DIAGNOSTIC
+RESULTS command and decoded.
+.SH NOTES
+This utility can handle a maximum size of 128 MB of microcode which
+should be sufficient for most purposes. In a system that is memory
+constrained, such large allocations of memory may fail.
+.PP
+The user should be aware that most operating systems have limits on the
+amount of data that can be sent with one SCSI command. In Linux this
+depends on the pass through mechanism used (e.g. block SG_IO or the sg
+driver) and various setting in sysfs in the Linux lk 2.6/3
+series (e.g. /sys/block/sda/queue/max_sectors_kb). Devices (i.e. logical
+units) also typically have limits on the maximum amount of data they can
+handle in one command. These two limitations suggest that modes
+containing the word "offset" together with the \fI\-\-bpw=CS\fR option
+are required as firmware files get larger and larger. And \fICS\fR
+can be quite small, for example 4096 bytes, resulting in many SEND
+DIAGNOSTIC commands being sent.
+.PP
+Downloading incorrect microcode into a device has the ability to render
+that device inoperable. One would hope that the device vendor verifies
+the data before activating it.
+.PP
+A long (operating system) timeout of 7200 seconds is set on each SEND
+DIAGNOSTIC command.
+.PP
+All numbers given with options are assumed to be decimal.
+Alternatively numerical values can be given in hexadecimal preceded by
+either "0x" or "0X" (or has a trailing "h" or "H").
+.SH EXAMPLES
+The following sends new firmware to an enclosure. Sending a 1.5 MB
+file in one command caused the enclosure to lock up temporarily and did
+not update the firmware. Breaking the firmware file into 4 KB chunks (an
+educated guess) was more successful:
+.PP
+ sg_ses_microcode \-b 4k \-m dmc_offs_save \-I firmware.bin /dev/sg4
+.PP
+The firmware update occurred in the following enclosure power cycle. With
+a modern enclosure the Extended Inquiry VPD page gives indications in which
+situations a firmware upgrade will take place.
+.SH EXIT STATUS
+The exit status of sg_ses_microcode is 0 when it is successful. Otherwise
+see the sg3_utils(8) man page.
+.SH AUTHORS
+Written by Douglas Gilbert.
+.SH "REPORTING BUGS"
+Report bugs to <dgilbert at interlog dot com>.
+.SH COPYRIGHT
+Copyright \(co 2014 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_ses, sg_write_buffer(sg3_utils)
diff --git a/sg3_utils.spec b/sg3_utils.spec
index 4450ba34..0d21eff1 100644
--- a/sg3_utils.spec
+++ b/sg3_utils.spec
@@ -79,7 +79,7 @@ fi
%{_libdir}/*.la
%changelog
-* Sun Sep 21 2014 - dgilbert at interlog dot com
+* Mon Sep 29 2014 - dgilbert at interlog dot com
- track t10 changes
* sg3_utils-1.40
diff --git a/src/Makefile.am b/src/Makefile.am
index b5c774ec..2293d1ec 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,9 +16,9 @@ bin_PROGRAMS = \
sg_read_long sg_reassign sg_referrals sg_rep_zones sg_requests \
sg_reset sg_reset_wp sg_rmsn sg_rtpg sg_safte sg_sanitize \
sg_sat_identify sg_sat_phy_event sg_sat_set_features sg_scan \
- sg_senddiag sg_ses sg_start sg_stpg sg_sync sg_test_rwbuf sg_turs \
- sg_unmap sg_verify sg_vpd sg_write_buffer sg_write_long \
- sg_write_same sg_write_verify sg_wr_mode sg_xcopy
+ sg_senddiag sg_ses sg_ses_microcode sg_start sg_stpg sg_sync \
+ sg_test_rwbuf sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer \
+ sg_write_long sg_write_same sg_write_verify sg_wr_mode sg_xcopy
distclean-local:
rm -f sg_scan.c
@@ -38,9 +38,10 @@ bin_PROGRAMS = \
sg_read_block_limits sg_read_buffer sg_read_long sg_reassign \
sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn \
sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \
- sg_sat_set_features sg_scan sg_senddiag sg_ses sg_start sg_stpg \
- sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer \
- sg_write_long sg_write_same sg_write_verify sg_wr_mode
+ sg_sat_set_features sg_scan sg_senddiag sg_ses sg_ses_microcode \
+ sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify sg_vpd \
+ sg_write_buffer sg_write_long sg_write_same sg_write_verify \
+ sg_wr_mode
distclean-local:
rm -f sg_scan.c
@@ -60,9 +61,10 @@ bin_PROGRAMS = \
sg_read_block_limits sg_read_buffer sg_read_long sg_reassign \
sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn \
sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \
- sg_sat_set_features sg_scan sg_senddiag sg_ses sg_start sg_stpg \
- sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer \
- sg_write_long sg_write_same sg_write_verify sg_wr_mode
+ sg_sat_set_features sg_scan sg_senddiag sg_ses sg_ses_microcode \
+ sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify sg_vpd \
+ sg_write_buffer sg_write_long sg_write_same sg_write_verify \
+ sg_wr_mode
distclean-local:
rm -f sg_scan.c
@@ -82,9 +84,10 @@ bin_PROGRAMS = \
sg_read_block_limits sg_read_buffer sg_read_long sg_reassign \
sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn \
sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \
- sg_sat_set_features sg_senddiag sg_ses sg_start sg_stpg sg_sync \
- sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer sg_write_long \
- sg_write_same sg_write_verify sg_wr_mode
+ sg_sat_set_features sg_senddiag sg_ses sg_ses_microcode \
+ sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify sg_vpd \
+ sg_write_buffer sg_write_long sg_write_same sg_write_verify \
+ sg_wr_mode
endif
@@ -98,9 +101,9 @@ bin_PROGRAMS = \
sg_read_block_limits sg_read_buffer sg_read_long sg_reassign \
sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn \
sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \
- sg_sat_set_features sg_senddiag sg_ses sg_start sg_stpg sg_sync \
- sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer sg_write_long \
- sg_write_same sg_write_verify sg_wr_mode
+ sg_sat_set_features sg_senddiag sg_ses sg_ses_microcode sg_start \
+ sg_stpg sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer \
+ sg_write_long sg_write_same sg_write_verify sg_wr_mode
endif
@@ -112,11 +115,11 @@ bin_PROGRAMS = \
sg_get_lba_status sg_ident sg_inq sg_logs sg_luns sg_modes \
sg_opcodes sg_persist sg_prevent sg_raw sg_rdac sg_readcap \
sg_read_block_limits sg_read_buffer sg_read_long sg_reassign \
- sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn \
- sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \
- sg_sat_set_features sg_senddiag sg_ses sg_start sg_stpg sg_sync \
- sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer sg_write_long \
- sg_write_same sg_write_verify sg_wr_mode
+ sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn sg_rtpg \
+ sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \
+ sg_sat_set_features sg_senddiag sg_ses sg_ses_microcode sg_start \
+ sg_stpg sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_write_buffer \
+ sg_write_long sg_write_same sg_write_verify sg_wr_mode
endif
@@ -254,6 +257,9 @@ sg_senddiag_LDADD = ../lib/libsgutils2.la @os_libs@
sg_ses_SOURCES = sg_ses.c
sg_ses_LDADD = ../lib/libsgutils2.la @os_libs@
+sg_ses_microcode_SOURCES = sg_ses_microcode.c
+sg_ses_microcode_LDADD = ../lib/libsgutils2.la @os_libs@
+
sg_start_SOURCES = sg_start.c
sg_start_LDADD = ../lib/libsgutils2.la @os_libs@
diff --git a/src/Makefile.in b/src/Makefile.in
index 999b3ec4..d90ad410 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -112,6 +112,7 @@ host_triplet = @host@
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_scan$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_senddiag$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_ses$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_ses_microcode$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_start$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_stpg$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_sync$(EXEEXT) \
@@ -158,6 +159,7 @@ host_triplet = @host@
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_scan$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_senddiag$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_ses$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_ses_microcode$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_start$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_stpg$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_sync$(EXEEXT) \
@@ -203,6 +205,7 @@ host_triplet = @host@
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_sat_set_features$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_senddiag$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_ses$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_ses_microcode$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_start$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_stpg$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_sync$(EXEEXT) \
@@ -248,6 +251,7 @@ host_triplet = @host@
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_sat_set_features$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_senddiag$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_ses$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_ses_microcode$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_start$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_stpg$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_sync$(EXEEXT) \
@@ -305,6 +309,7 @@ host_triplet = @host@
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_scan$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_senddiag$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_ses$(EXEEXT) \
+@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_ses_microcode$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_start$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_stpg$(EXEEXT) \
@OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_sync$(EXEEXT) \
@@ -338,10 +343,11 @@ host_triplet = @host@
@OS_FREEBSD_TRUE@ sg_sat_phy_event$(EXEEXT) \
@OS_FREEBSD_TRUE@ sg_sat_set_features$(EXEEXT) \
@OS_FREEBSD_TRUE@ sg_senddiag$(EXEEXT) sg_ses$(EXEEXT) \
-@OS_FREEBSD_TRUE@ sg_start$(EXEEXT) sg_stpg$(EXEEXT) \
-@OS_FREEBSD_TRUE@ sg_sync$(EXEEXT) sg_turs$(EXEEXT) \
-@OS_FREEBSD_TRUE@ sg_unmap$(EXEEXT) sg_verify$(EXEEXT) \
-@OS_FREEBSD_TRUE@ sg_vpd$(EXEEXT) sg_write_buffer$(EXEEXT) \
+@OS_FREEBSD_TRUE@ sg_ses_microcode$(EXEEXT) sg_start$(EXEEXT) \
+@OS_FREEBSD_TRUE@ sg_stpg$(EXEEXT) sg_sync$(EXEEXT) \
+@OS_FREEBSD_TRUE@ sg_turs$(EXEEXT) sg_unmap$(EXEEXT) \
+@OS_FREEBSD_TRUE@ sg_verify$(EXEEXT) sg_vpd$(EXEEXT) \
+@OS_FREEBSD_TRUE@ sg_write_buffer$(EXEEXT) \
@OS_FREEBSD_TRUE@ sg_write_long$(EXEEXT) sg_write_same$(EXEEXT) \
@OS_FREEBSD_TRUE@ sg_write_verify$(EXEEXT) sg_wr_mode$(EXEEXT)
subdir = src
@@ -487,6 +493,9 @@ sg_senddiag_DEPENDENCIES = ../lib/libsgutils2.la
am_sg_ses_OBJECTS = sg_ses.$(OBJEXT)
sg_ses_OBJECTS = $(am_sg_ses_OBJECTS)
sg_ses_DEPENDENCIES = ../lib/libsgutils2.la
+am_sg_ses_microcode_OBJECTS = sg_ses_microcode.$(OBJEXT)
+sg_ses_microcode_OBJECTS = $(am_sg_ses_microcode_OBJECTS)
+sg_ses_microcode_DEPENDENCIES = ../lib/libsgutils2.la
am_sg_start_OBJECTS = sg_start.$(OBJEXT)
sg_start_OBJECTS = $(am_sg_start_OBJECTS)
sg_start_DEPENDENCIES = ../lib/libsgutils2.la
@@ -589,7 +598,8 @@ SOURCES = $(sg_compare_and_write_SOURCES) $(sg_copy_results_SOURCES) \
$(sg_rtpg_SOURCES) $(sg_safte_SOURCES) $(sg_sanitize_SOURCES) \
$(sg_sat_identify_SOURCES) $(sg_sat_phy_event_SOURCES) \
$(sg_sat_set_features_SOURCES) $(sg_scan_SOURCES) \
- $(sg_senddiag_SOURCES) $(sg_ses_SOURCES) $(sg_start_SOURCES) \
+ $(sg_senddiag_SOURCES) $(sg_ses_SOURCES) \
+ $(sg_ses_microcode_SOURCES) $(sg_start_SOURCES) \
$(sg_stpg_SOURCES) $(sg_sync_SOURCES) $(sg_test_rwbuf_SOURCES) \
$(sg_turs_SOURCES) $(sg_unmap_SOURCES) $(sg_verify_SOURCES) \
$(sg_vpd_SOURCES) $(sg_wr_mode_SOURCES) \
@@ -615,7 +625,8 @@ DIST_SOURCES = $(sg_compare_and_write_SOURCES) \
$(sg_rtpg_SOURCES) $(sg_safte_SOURCES) $(sg_sanitize_SOURCES) \
$(sg_sat_identify_SOURCES) $(sg_sat_phy_event_SOURCES) \
$(sg_sat_set_features_SOURCES) $(sg_scan_SOURCES) \
- $(sg_senddiag_SOURCES) $(sg_ses_SOURCES) $(sg_start_SOURCES) \
+ $(sg_senddiag_SOURCES) $(sg_ses_SOURCES) \
+ $(sg_ses_microcode_SOURCES) $(sg_start_SOURCES) \
$(sg_stpg_SOURCES) $(sg_sync_SOURCES) $(sg_test_rwbuf_SOURCES) \
$(sg_turs_SOURCES) $(sg_unmap_SOURCES) $(sg_verify_SOURCES) \
$(sg_vpd_SOURCES) $(sg_wr_mode_SOURCES) \
@@ -855,6 +866,8 @@ sg_senddiag_SOURCES = sg_senddiag.c
sg_senddiag_LDADD = ../lib/libsgutils2.la @os_libs@
sg_ses_SOURCES = sg_ses.c
sg_ses_LDADD = ../lib/libsgutils2.la @os_libs@
+sg_ses_microcode_SOURCES = sg_ses_microcode.c
+sg_ses_microcode_LDADD = ../lib/libsgutils2.la @os_libs@
sg_start_SOURCES = sg_start.c
sg_start_LDADD = ../lib/libsgutils2.la @os_libs@
sg_stpg_SOURCES = sg_stpg.c
@@ -1143,6 +1156,10 @@ sg_ses$(EXEEXT): $(sg_ses_OBJECTS) $(sg_ses_DEPENDENCIES) $(EXTRA_sg_ses_DEPENDE
@rm -f sg_ses$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(sg_ses_OBJECTS) $(sg_ses_LDADD) $(LIBS)
+sg_ses_microcode$(EXEEXT): $(sg_ses_microcode_OBJECTS) $(sg_ses_microcode_DEPENDENCIES) $(EXTRA_sg_ses_microcode_DEPENDENCIES)
+ @rm -f sg_ses_microcode$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sg_ses_microcode_OBJECTS) $(sg_ses_microcode_LDADD) $(LIBS)
+
sg_start$(EXEEXT): $(sg_start_OBJECTS) $(sg_start_DEPENDENCIES) $(EXTRA_sg_start_DEPENDENCIES)
@rm -f sg_start$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(sg_start_OBJECTS) $(sg_start_LDADD) $(LIBS)
@@ -1260,6 +1277,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_scan.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_senddiag.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_ses.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_ses_microcode.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_start.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_stpg.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sync.Po@am__quote@
diff --git a/src/sg_ses.c b/src/sg_ses.c
index 246e24eb..cf03bbab 100644
--- a/src/sg_ses.c
+++ b/src/sg_ses.c
@@ -29,7 +29,7 @@
* commands tailored for SES (enclosure) devices.
*/
-static const char * version_str = "1.93 20140921"; /* ses3r06 */
+static const char * version_str = "1.94 20140929"; /* ses3r06 */
#define MX_ALLOC_LEN ((64 * 1024) - 4) /* max allowable for big enclosures */
#define MX_ELEM_HDR 1024
@@ -634,10 +634,11 @@ usage(int help_num)
" --version|-V print version string and exit\n"
" --warn|-w warn about join (and other) issues\n\n"
"If no options are given then DEVICE's supported diagnostic "
- "pages are\noutput. STR can be '<acronym>[=val]' or\n"
- "'<start_byte>:<start_bit>[:<num_bits>][=<val>]'. Element "
- "type\nabbreviations may be followed by a number (e.g. 'ps1' "
- "is the second\npower supply element type).\n\n"
+ "pages are\nlisted. STR can be '<start_byte>:<start_bit>"
+ "[:<num_bits>][=<val>]'\nor '<acronym>[=val]'. Element type "
+ "abbreviations may be followed by a\nnumber (e.g. 'ps1' is "
+ "the second power supply element type). Use\n'sg_ses -e' and "
+ "'sg_ses -ee' for more information.\n\n"
);
pr2serr(
"Low level indexing can be done with one of the two '--index=' "
@@ -1383,7 +1384,7 @@ ses_configuration_sdg(const unsigned char * resp, int resp_len)
el = ucp[3] + 4;
sum_elem_types += ucp[2];
printf(" Subenclosure identifier: %d%s\n", ucp[1],
- (ucp[1] ? "" : " (primary)"));
+ (ucp[1] ? "" : " [primary]"));
printf(" relative ES process id: %d, number of ES processes"
": %d\n", ((ucp[0] & 0x70) >> 4), (ucp[0] & 0x7));
printf(" number of type descriptor headers: %d\n", ucp[2]);
@@ -2668,6 +2669,38 @@ ses_supported_pages_sdg(const char * leadin, const unsigned char * resp,
}
}
+/* An array of Download microcode status field values and descriptions */
+static struct diag_page_code mc_status_arr[] = {
+ {0x0, "No download microcode operation in progress"},
+ {0x1, "Download in progress, awaiting more"},
+ {0x2, "Download complete, updating storage"},
+ {0x3, "Updating storage with deferred microcode"},
+ {0x10, "Complete, no error, starting now"},
+ {0x11, "Complete, no error, start after hard reset or power cycle"},
+ {0x12, "Complete, no error, start after power cycle"},
+ {0x13, "Complete, no error, start after activate_mc, hard reset or "
+ "power cycle"},
+ {0x80, "Error, discarded, see additional status"},
+ {0x81, "Error, discarded, image error"},
+ {0x82, "Timeout, discarded"},
+ {0x83, "Internal error, need new microcode before reset"},
+ {0x84, "Internal error, need new microcode, reset safe"},
+ {0x85, "Unexpected activate_mc received"},
+ {0x1000, NULL},
+};
+
+static const char *
+get_mc_status(unsigned char status_val)
+{
+ const struct diag_page_code * mcsp;
+
+ for (mcsp = mc_status_arr; mcsp->desc; ++mcsp) {
+ if (status_val == mcsp->page_code)
+ return mcsp->desc;
+ }
+ return "";
+}
+
/* DPC_DOWNLOAD_MICROCODE [0xe] */
static void
ses_download_code_sdg(const unsigned char * resp, int resp_len)
@@ -2676,6 +2709,7 @@ ses_download_code_sdg(const unsigned char * resp, int resp_len)
unsigned int gen_code;
const unsigned char * ucp;
const unsigned char * last_ucp;
+ const char * cp;
printf("Download microcode status diagnostic page:\n");
if (resp_len < 4)
@@ -2691,9 +2725,16 @@ ses_download_code_sdg(const unsigned char * resp, int resp_len)
for (k = 0; k < num_subs; ++k, ucp += 16) {
if ((ucp + 3) > last_ucp)
goto truncated;
- printf(" subenclosure identifier: %d\n", ucp[1]);
- printf(" download microcode status: 0x%x [additional status: "
- "0x%x]\n", ucp[2], ucp[3]);
+ cp = (0 == ucp[1]) ? " [primary]" : "";
+ printf(" subenclosure identifier: %d%s\n", ucp[1], cp);
+ cp = get_mc_status(ucp[2]);
+ if (strlen(cp) > 0) {
+ printf(" download microcode status: %s [0x%x]\n", cp, ucp[2]);
+ printf(" download microcode additional status: 0x%x\n",
+ ucp[3]);
+ } else
+ printf(" download microcode status: 0x%x [additional "
+ "status: 0x%x]\n", ucp[2], ucp[3]);
printf(" download microcode maximum size: %d bytes\n",
(ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]);
printf(" download microcode expected buffer id: 0x%x\n", ucp[11]);
@@ -4144,6 +4185,8 @@ main(int argc, char * argv[])
case DPC_DOWNLOAD_MICROCODE: /* Download Microcode Control [0xe] */
printf("Sending Download Microcode Control [0x%x] page, with "
"page length=%d bytes\n", op->page_code, op->arr_len);
+ printf(" Perhaps it would be better to use the sg_ses_microcode "
+ "utility\n");
ret = do_senddiag(sg_fd, 1, op->data_arr, op->arr_len + 4, 1,
op->verbose);
if (ret) {
diff --git a/src/sg_ses_microcode.c b/src/sg_ses_microcode.c
new file mode 100644
index 00000000..aa9d196f
--- /dev/null
+++ b/src/sg_ses_microcode.c
@@ -0,0 +1,748 @@
+/*
+ * Copyright (c) 2014 Douglas Gilbert.
+ * All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the BSD_LICENSE file.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "sg_lib.h"
+#include "sg_cmds_basic.h"
+#include "sg_cmds_extra.h"
+#ifdef SG_LIB_WIN32
+#ifdef SG_LIB_WIN32_DIRECT
+#include "sg_pt.h" /* needed for scsi_pt_win32_direct() */
+#endif
+#endif
+#include "sg_unaligned.h"
+
+/*
+ * This utility issues the SCSI SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC
+ * RESULTS commands in order to send microcode to the given SES device.
+ */
+
+static const char * version_str = "1.00 20140829"; /* ses3r06 */
+
+#define ME "sg_ses_microcode: "
+#define MAX_XFER_LEN (128 * 1024 * 1024)
+#define DEF_XFER_LEN (8 * 1024 * 1024)
+#define DEF_DI_LEN (8 * 1024)
+#define EBUFF_SZ 256
+
+#define DPC_DOWNLOAD_MICROCODE 0xe
+
+struct opts_t {
+ int bpw;
+ int bpw_then_activate;
+ int mc_id;
+ int mc_len;
+ int mc_len_given;
+ int mc_mode;
+ int mc_offset;
+ int mc_skip;
+ int mc_subenc;
+ int mc_tlen;
+ int verbose;
+};
+
+static struct option long_options[] = {
+ {"bpw", required_argument, 0, 'b'},
+ {"help", no_argument, 0, 'h'},
+ {"id", required_argument, 0, 'i'},
+ {"in", required_argument, 0, 'I'},
+ {"length", required_argument, 0, 'l'},
+ {"mode", required_argument, 0, 'm'},
+ {"offset", required_argument, 0, 'o'},
+ {"skip", required_argument, 0, 's'},
+ {"subenc", required_argument, 0, 'S'},
+ {"tlength", required_argument, 0, 't'},
+ {"verbose", no_argument, 0, 'v'},
+ {"version", no_argument, 0, 'V'},
+ {0, 0, 0, 0},
+};
+
+
+#ifdef __GNUC__
+static int pr2serr(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+#else
+static int pr2serr(const char * fmt, ...);
+#endif
+
+
+static int
+pr2serr(const char * fmt, ...)
+{
+ va_list args;
+ int n;
+
+ va_start(args, fmt);
+ n = vfprintf(stderr, fmt, args);
+ va_end(args);
+ return n;
+}
+
+static void
+usage()
+{
+ pr2serr("Usage: "
+ "sg_ses_microcode [--bpw=CS] [--help] [--id=ID] [--in=FILE]\n"
+ " [--length=LEN] [--mode=MO] "
+ "[--offset=OFF]\n"
+ " [--skip=SKIP] [--subenc=SEID] "
+ "[--tlength=TLEN]\n"
+ " [--verbose] [--version] DEVICE\n"
+ " where:\n"
+ " --bpw=CS|-b CS CS is chunk size: bytes per send "
+ "diagnostic\n"
+ " command (def: 0 -> as many as "
+ "possible)\n"
+ " --help|-h print out usage message then exit\n"
+ " --id=ID|-i ID buffer identifier (0 (default) to "
+ "255)\n"
+ " --in=FILE|-I FILE read from FILE ('-I -' read "
+ "from stdin)\n"
+ " --length=LEN|-l LEN length in bytes to send; may be "
+ "deduced from\n"
+ " FILE\n"
+ " --mode=MO|-m MO download microcode mode, MO is "
+ "number or\n"
+ " acronym (def: 0 -> 'dmc_status')\n"
+ " --offset=OFF|-o OFF buffer offset (unit: bytes, def: "
+ "0);\n"
+ " ignored if --bpw=CS given\n"
+ " --skip=SKIP|-s SKIP bytes in file FILE to skip before "
+ "reading\n"
+ " --subenc=SEID|-S SEID subenclosure identifier (def: 0 "
+ "(primary))\n"
+ " --tlength=TLEN|-t TLEN total length of firmware in "
+ "bytes\n"
+ " (def: 0). Only needed if "
+ "TLEN>LEN\n"
+ " --verbose|-v increase verbosity\n"
+ " --version|-V print version string and exit\n\n"
+ "Does one or more SCSI SEND DIAGNOSTIC followed by RECEIVE "
+ "DIAGNOSTIC\nRESULTS command sequences in order to download "
+ "microcode. Use '-m xxx'\nto list available modes. With only "
+ "DEVICE given, the Download Microcode\nStatus dpage is output.\n"
+ );
+}
+
+#define MODE_DNLD_STATUS 0
+#define MODE_DNLD_MC_OFFS 6
+#define MODE_DNLD_MC_OFFS_SAVE 7
+#define MODE_DNLD_MC_OFFS_DEFER 0x0E
+#define MODE_ACTIVATE_MC 0x0F
+
+struct mode_s {
+ const char *mode_string;
+ int mode;
+ const char *comment;
+};
+
+static struct mode_s mode_arr[] = {
+ {"dmc_status", MODE_DNLD_STATUS, "report status of microcode "
+ "download"},
+ {"dmc_offs", MODE_DNLD_MC_OFFS, "download microcode with offsets "
+ "and activate"},
+ {"dmc_offs_save", MODE_DNLD_MC_OFFS_SAVE, "download microcode with "
+ "offsets, save and\n\t\t\t\tactivate"},
+ {"dmc_offs_defer", MODE_DNLD_MC_OFFS_DEFER, "download microcode "
+ "with offsets, save and\n\t\t\t\tdefer activation"},
+ {"activate_mc", MODE_ACTIVATE_MC, "activate deferred microcode"},
+ {NULL, 0, NULL},
+};
+
+
+static void
+print_modes(void)
+{
+ const struct mode_s * mp;
+
+ pr2serr("The modes parameter argument can be numeric (hex or decimal)\n"
+ "or symbolic:\n");
+ for (mp = mode_arr; mp->mode_string; ++mp) {
+ pr2serr(" %2d (0x%02x) %-18s%s\n", mp->mode, mp->mode,
+ mp->mode_string, mp->comment);
+ }
+ pr2serr("\nAdditionally '--bpw=<val>,act' does a activate deferred "
+ "microcode after a\nsuccessful multipart dmc_offs_defer mode "
+ "download.\n");
+}
+
+struct diag_page_code {
+ int page_code;
+ const char * desc;
+};
+
+/* An array of Download microcode status field values and descriptions */
+static struct diag_page_code mc_status_arr[] = {
+ {0x0, "No download microcode operation in progress"},
+ {0x1, "Download in progress, awaiting more"},
+ {0x2, "Download complete, updating storage"},
+ {0x3, "Updating storage with deferred microcode"},
+ {0x10, "Complete, no error, starting now"},
+ {0x11, "Complete, no error, start after hard reset or power cycle"},
+ {0x12, "Complete, no error, start after power cycle"},
+ {0x13, "Complete, no error, start after activate_mc, hard reset or "
+ "power cycle"},
+ {0x80, "Error, discarded, see additional status"},
+ {0x81, "Error, discarded, image error"},
+ {0x82, "Timeout, discarded"},
+ {0x83, "Internal error, need new microcode before reset"},
+ {0x84, "Internal error, need new microcode, reset safe"},
+ {0x85, "Unexpected activate_mc received"},
+ {0x1000, NULL},
+};
+
+static const char *
+get_mc_status_str(unsigned char status_val)
+{
+ const struct diag_page_code * mcsp;
+
+ for (mcsp = mc_status_arr; mcsp->desc; ++mcsp) {
+ if (status_val == mcsp->page_code)
+ return mcsp->desc;
+ }
+ return "";
+}
+
+/* DPC_DOWNLOAD_MICROCODE [0xe] */
+static void
+ses_download_code_sdg(const unsigned char * resp, int resp_len,
+ uint32_t gen_code)
+{
+ int k, num_subs, num;
+ const unsigned char * ucp;
+ const char * cp;
+
+ printf("Download microcode status diagnostic page:\n");
+ if (resp_len < 8)
+ goto truncated;
+ num_subs = resp[1]; /* primary is additional one) */
+ num = (resp_len - 8) / 16;
+ if ((resp_len - 8) % 16)
+ pr2serr("Found %d Download microcode status descriptors, but there "
+ "is residual\n", num);
+ printf(" number of secondary subenclosures: %d\n", num_subs);
+ printf(" generation code: 0x%" PRIx32 "\n", gen_code);
+ ucp = resp + 8;
+ for (k = 0; k < num; ++k, ucp += 16) {
+ cp = (0 == ucp[1]) ? " [primary]" : "";
+ printf(" subenclosure identifier: %d%s\n", ucp[1], cp);
+ cp = get_mc_status_str(ucp[2]);
+ if (strlen(cp) > 0) {
+ printf(" download microcode status: %s [0x%x]\n", cp, ucp[2]);
+ printf(" download microcode additional status: 0x%x\n",
+ ucp[3]);
+ } else
+ printf(" download microcode status: 0x%x [additional "
+ "status: 0x%x]\n", ucp[2], ucp[3]);
+ printf(" download microcode maximum size: %" PRIu32 " bytes\n",
+ sg_get_unaligned_be32(ucp + 4));
+ printf(" download microcode expected buffer id: 0x%x\n", ucp[11]);
+ printf(" download microcode expected buffer id offset: %" PRIu32
+ "\n", sg_get_unaligned_be32(ucp + 12));
+ }
+ return;
+truncated:
+ pr2serr(" <<<download status: response too short>>>\n");
+ return;
+}
+
+struct dout_buff_t {
+ unsigned char * doutp;
+ int dout_len;
+};
+
+static int
+send_then_receive(int sg_fd, uint32_t gen_code, int off_off,
+ const unsigned char * dmp, int dmp_len,
+ struct dout_buff_t * wp, unsigned char * dip,
+ const struct opts_t * op)
+{
+ int do_len, rem, res, rsp_len, k, num, mc_status;
+ int send_data = 0;
+ int ret = 0;
+ uint32_t rec_gen_code;
+ const unsigned char * ucp;
+ const char * cp;
+
+ switch (op->mc_mode) {
+ case MODE_DNLD_MC_OFFS:
+ case MODE_DNLD_MC_OFFS_SAVE:
+ case MODE_DNLD_MC_OFFS_DEFER:
+ send_data = 1;
+ do_len = 24 + dmp_len;
+ rem = do_len % 4;
+ if (rem)
+ do_len += (4 - rem);
+ break;
+ case MODE_ACTIVATE_MC:
+ do_len = 24;
+ break;
+ default:
+ pr2serr("send_then_receive: unexpected mc_mode=0x%x\n", op->mc_mode);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (do_len > wp->dout_len) {
+ if (wp->doutp)
+ free(wp->doutp);
+ wp->doutp = (unsigned char *)malloc(do_len);
+ if (! wp->doutp) {
+ pr2serr("send_then_receive: unable to malloc %d bytes\n", do_len);
+ return SG_LIB_CAT_OTHER;
+ }
+ wp->dout_len = do_len;
+ }
+ memset(wp->doutp, 0, do_len);
+ wp->doutp[0] = DPC_DOWNLOAD_MICROCODE;
+ wp->doutp[1] = op->mc_subenc;
+ sg_put_unaligned_be16(do_len - 4, wp->doutp + 2);
+ sg_put_unaligned_be32(gen_code, wp->doutp + 4);
+ wp->doutp[8] = op->mc_mode;
+ wp->doutp[11] = op->mc_id;
+ if (send_data)
+ sg_put_unaligned_be32(op->mc_offset + off_off, wp->doutp + 12);
+ sg_put_unaligned_be32(op->mc_tlen, wp->doutp + 16);
+ sg_put_unaligned_be32(dmp_len, wp->doutp + 20);
+ if (send_data && (dmp_len > 0))
+ memcpy(wp->doutp + 24, dmp, dmp_len);
+ /* select long duration timeout (7200 seconds) */
+ res = sg_ll_send_diag(sg_fd, 0 /* sf_code */, 1 /* pf */, 0 /* sf */,
+ 0 /* devofl */, 0 /* unitofl */,
+ 1 /* long_duration */, wp->doutp, do_len,
+ 1 /* noisy */, op->verbose);
+ if (res)
+ return res;
+ res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip,
+ DEF_DI_LEN, 1, op->verbose);
+ if (res)
+ return res;
+ rsp_len = sg_get_unaligned_be16(dip + 2) + 4;
+ if (rsp_len > DEF_DI_LEN) {
+ pr2serr("<<< warning response buffer too small [%d but need "
+ "%d]>>>\n", DEF_DI_LEN, rsp_len);
+ rsp_len = DEF_DI_LEN;
+ }
+ if (rsp_len < 8) {
+ pr2serr("Download microcode status dpage too short\n");
+ return SG_LIB_CAT_OTHER;
+ }
+ rec_gen_code = sg_get_unaligned_be32(dip + 4);
+ if (rec_gen_code != gen_code)
+ pr2serr("gen_code changed from %" PRIu32 " to %" PRIu32
+ ", continuing but may fail\n", gen_code, rec_gen_code);
+ num = (rsp_len - 8) / 16;
+ if ((rsp_len - 8) % 16)
+ pr2serr("Found %d Download microcode status descriptors, but there "
+ "is residual\n", num);
+ ucp = dip + 8;
+ for (k = 0; k < num; ++k, ucp += 16) {
+ if ((unsigned int)op->mc_subenc == (unsigned int)ucp[1]) {
+ mc_status = ucp[2];
+ cp = get_mc_status_str(mc_status);
+ if ((mc_status >= 0x80) || op->verbose)
+ pr2serr("mc offset=%d: status: %s [0x%x, additional=0x%x]\n",
+ off_off, cp, mc_status, ucp[3]);
+ if (mc_status >= 0x80)
+ ret = SG_LIB_CAT_OTHER;
+ }
+ }
+ return ret;
+}
+
+
+int
+main(int argc, char * argv[])
+{
+ int sg_fd, res, c, len, k, n, got_stdin, is_reg, rsp_len;
+ int infd = -1;
+ int do_help = 0;
+ const char * device_name = NULL;
+ const char * file_name = NULL;
+ unsigned char * dmp = NULL;
+ unsigned char * dip = NULL;
+ char * cp;
+ char ebuff[EBUFF_SZ];
+ struct stat a_stat;
+ struct dout_buff_t dout;
+ struct opts_t opts;
+ struct opts_t * op;
+ const struct mode_s * mp;
+ uint32_t gen_code;
+ int ret = 0;
+
+ op = &opts;
+ memset(op, 0, sizeof(opts));
+ memset(&dout, 0, sizeof(dout));
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "b:hi:I:l:m:o:s:S:t:vV", long_options,
+ &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'b':
+ op->bpw = sg_get_num(optarg);
+ if (op->bpw < 0) {
+ pr2serr("argument to '--bpw' should be in a positive "
+ "number\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if ((cp = strchr(optarg, ','))) {
+ if (0 == strncmp("act", cp + 1, 3))
+ ++op->bpw_then_activate;
+ }
+ break;
+ case 'h':
+ case '?':
+ ++do_help;
+ break;
+ case 'i':
+ op->mc_id = sg_get_num(optarg);
+ if ((op->mc_id < 0) || (op->mc_id > 255)) {
+ pr2serr("argument to '--id' should be in the range 0 to "
+ "255\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 'I':
+ file_name = optarg;
+ break;
+ case 'l':
+ op->mc_len = sg_get_num(optarg);
+ if (op->mc_len < 0) {
+ pr2serr("bad argument to '--length'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ op->mc_len_given = 1;
+ break;
+ case 'm':
+ if (isdigit(*optarg)) {
+ op->mc_mode = sg_get_num(optarg);
+ if ((op->mc_mode < 0) || (op->mc_mode > 255)) {
+ pr2serr("argument to '--mode' should be in the range 0 "
+ "to 255\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ } else {
+ len = strlen(optarg);
+ for (mp = mode_arr; mp->mode_string; ++mp) {
+ if (0 == strncmp(mp->mode_string, optarg, len)) {
+ op->mc_mode = mp->mode;
+ break;
+ }
+ }
+ if (! mp->mode_string) {
+ print_modes();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ break;
+ case 'o':
+ op->mc_offset = sg_get_num(optarg);
+ if (op->mc_offset < 0) {
+ pr2serr("bad argument to '--offset'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ if (0 != (op->mc_offset % 4)) {
+ pr2serr("'--offset' value needs to be a multiple of 4\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 's':
+ op->mc_skip = sg_get_num(optarg);
+ if (op->mc_skip < 0) {
+ pr2serr("bad argument to '--skip'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 'S':
+ op->mc_subenc = sg_get_num(optarg);
+ if ((op->mc_subenc < 0) || (op->mc_subenc > 255)) {
+ pr2serr("expected argument to '--subenc' to be 0 to 255\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 't':
+ op->mc_tlen = sg_get_num(optarg);
+ if (op->mc_tlen < 0) {
+ pr2serr("bad argument to '--tlength'\n");
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ break;
+ case 'v':
+ ++op->verbose;
+ break;
+ case 'V':
+ pr2serr(ME "version: %s\n", version_str);
+ return 0;
+ default:
+ pr2serr("unrecognised option code 0x%x ??\n", c);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+ if (do_help) {
+ if (do_help > 1) {
+ usage();
+ pr2serr("\n");
+ print_modes();
+ } else
+ usage();
+ return 0;
+ }
+ if (optind < argc) {
+ if (NULL == device_name) {
+ device_name = argv[optind];
+ ++optind;
+ }
+ if (optind < argc) {
+ for (; optind < argc; ++optind)
+ pr2serr("Unexpected extra argument: %s\n", argv[optind]);
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
+
+ if (NULL == device_name) {
+ pr2serr("missing device name!\n");
+ usage();
+ return SG_LIB_SYNTAX_ERROR;
+ }
+
+ if ((op->mc_len > 0) && (op->bpw > op->mc_len)) {
+ pr2serr("trim chunk size (CS) to be the same as LEN\n");
+ op->bpw = op->mc_len;
+ }
+
+#ifdef SG_LIB_WIN32
+#ifdef SG_LIB_WIN32_DIRECT
+ if (op->verbose > 4)
+ pr2serr("Initial win32 SPT interface state: %s\n",
+ scsi_pt_win32_spt_state() ? "direct" : "indirect");
+ scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */);
+#endif
+#endif
+
+ sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, op->verbose);
+ if (sg_fd < 0) {
+ pr2serr(ME "open error: %s: %s\n", device_name,
+ safe_strerror(-sg_fd));
+ return SG_LIB_FILE_ERROR;
+ }
+
+ if (file_name && ((MODE_DNLD_STATUS == op->mc_mode) ||
+ (MODE_ACTIVATE_MC == op->mc_mode)))
+ pr2serr("ignoring --in=FILE option\n");
+ else if (file_name) {
+ got_stdin = (0 == strcmp(file_name, "-")) ? 1 : 0;
+ if (got_stdin)
+ infd = STDIN_FILENO;
+ else {
+ if ((infd = open(file_name, O_RDONLY)) < 0) {
+ snprintf(ebuff, EBUFF_SZ,
+ ME "could not open %s for reading", file_name);
+ perror(ebuff);
+ ret = SG_LIB_FILE_ERROR;
+ goto fini;
+ } else if (sg_set_binary_mode(infd) < 0)
+ perror("sg_set_binary_mode");
+ }
+ if ((0 == fstat(infd, &a_stat)) && S_ISREG(a_stat.st_mode)) {
+ is_reg = 1;
+ if (0 == op->mc_len) {
+ if (op->mc_skip >= a_stat.st_size) {
+ pr2serr("skip exceeds file size of %d bytes\n",
+ (int)a_stat.st_size);
+ ret = SG_LIB_FILE_ERROR;
+ goto fini;
+ }
+ op->mc_len = (int)(a_stat.st_size) - op->mc_skip;
+ }
+ } else {
+ is_reg = 0;
+ if (0 == op->mc_len)
+ op->mc_len = DEF_XFER_LEN;
+ }
+ if (op->mc_len > MAX_XFER_LEN) {
+ pr2serr("file size or requested length (%d) exceeds "
+ "MAX_XFER_LEN of %d bytes\n", op->mc_len,
+ MAX_XFER_LEN);
+ ret = SG_LIB_FILE_ERROR;
+ goto fini;
+ }
+ if (NULL == (dmp = (unsigned char *)malloc(op->mc_len))) {
+ pr2serr(ME "out of memory (to hold microcode)\n");
+ ret = SG_LIB_CAT_OTHER;
+ goto fini;
+ }
+ /* Don't remember why this is preset to 0xff, from write_buffer */
+ memset(dmp, 0xff, op->mc_len);
+ if (op->mc_skip > 0) {
+ if (! is_reg) {
+ if (got_stdin)
+ pr2serr("Can't skip on stdin\n");
+ else
+ pr2serr(ME "not a 'regular' file so can't apply skip\n");
+ ret = SG_LIB_FILE_ERROR;
+ goto fini;
+ }
+ if (lseek(infd, op->mc_skip, SEEK_SET) < 0) {
+ snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to "
+ "required position on %s", file_name);
+ perror(ebuff);
+ ret = SG_LIB_FILE_ERROR;
+ goto fini;
+ }
+ }
+ res = read(infd, dmp, op->mc_len);
+ if (res < 0) {
+ snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s",
+ file_name);
+ perror(ebuff);
+ ret = SG_LIB_FILE_ERROR;
+ goto fini;
+ }
+ if (res < op->mc_len) {
+ if (op->mc_len_given) {
+ pr2serr("tried to read %d bytes from %s, got %d bytes\n",
+ op->mc_len, file_name, res);
+ pr2serr("pad with 0xff bytes and continue\n");
+ } else {
+ if (op->verbose) {
+ pr2serr("tried to read %d bytes from %s, got %d "
+ "bytes\n", op->mc_len, file_name, res);
+ pr2serr("will send %d bytes", res);
+ if ((op->bpw > 0) && (op->bpw < op->mc_len))
+ pr2serr(", %d bytes per WRITE BUFFER command\n",
+ op->bpw);
+ else
+ pr2serr("\n");
+ }
+ op->mc_len = res;
+ }
+ }
+ if (! got_stdin)
+ close(infd);
+ infd = -1;
+ } else if (! ((MODE_DNLD_STATUS == op->mc_mode) ||
+ (MODE_ACTIVATE_MC == op->mc_mode))) {
+ pr2serr("need --in=FILE option with given mode\n");
+ ret = SG_LIB_SYNTAX_ERROR;
+ goto fini;
+ }
+ if (op->mc_tlen < op->mc_len)
+ op->mc_tlen = op->mc_len;
+
+ if (NULL == (dip = (unsigned char *)malloc(DEF_DI_LEN))) {
+ pr2serr(ME "out of memory (data-in buffer)\n");
+ ret = SG_LIB_CAT_OTHER;
+ goto fini;
+ }
+ memset(dip, 0, DEF_DI_LEN);
+ /* Fetch Download microde status dpage for generation code ++ */
+ res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip,
+ DEF_DI_LEN, 1, op->verbose);
+ if (0 == res) {
+ rsp_len = sg_get_unaligned_be16(dip + 2) + 4;
+ if (rsp_len > DEF_DI_LEN) {
+ pr2serr("<<< warning response buffer too small [%d but need "
+ "%d]>>>\n", DEF_DI_LEN, rsp_len);
+ rsp_len = DEF_DI_LEN;
+ }
+ if (rsp_len < 8) {
+ pr2serr("Download microcode status dpage too short\n");
+ ret = SG_LIB_CAT_OTHER;
+ goto fini;
+ }
+ } else {
+ ret = res;
+ goto fini;
+ }
+ gen_code = sg_get_unaligned_be32(dip + 4);
+
+ if (MODE_DNLD_STATUS == op->mc_mode) {
+ ses_download_code_sdg(dip, rsp_len, gen_code);
+ goto fini;
+ } else if (MODE_ACTIVATE_MC == op->mc_mode) {
+ res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, op);
+ ret = res;
+ goto fini;
+ }
+
+ res = 0;
+ if (op->bpw > 0) {
+ for (k = 0; k < op->mc_len; k += n) {
+ n = op->mc_len - k;
+ if (n > op->bpw)
+ n = op->bpw;
+ if (op->verbose)
+ pr2serr("send_then_receive: mode=0x%x, id=%d, off_off=%d, "
+ "len=%d\n", op->mc_mode, op->mc_id, k, n);
+ res = send_then_receive(sg_fd, gen_code, k, dmp + k, n, &dout,
+ dip, op);
+ if (res)
+ break;
+ }
+ if (op->bpw_then_activate && (0 == res)) {
+ op->mc_mode = MODE_ACTIVATE_MC;
+ if (op->verbose)
+ pr2serr("sending Activate deferred microcode [0xf]\n");
+ res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout,
+ dip, op);
+ }
+ } else {
+ if (op->verbose)
+ pr2serr("single send_then_receive: mode=0x%x, id=%d, offset=%d, "
+ "len=%d\n", op->mc_mode, op->mc_id,
+ op->mc_offset, op->mc_len);
+ res = send_then_receive(sg_fd, gen_code, 0, dmp, op->mc_len, &dout,
+ dip, op);
+ }
+ if (res)
+ ret = res;
+
+fini:
+ if ((infd >= 0) && (! got_stdin))
+ close(infd);
+ if (dmp)
+ free(dmp);
+ if (dout.doutp)
+ free(dout.doutp);
+ res = sg_cmds_close_device(sg_fd);
+ if (res < 0) {
+ pr2serr("close error: %s\n", safe_strerror(-res));
+ if (0 == ret)
+ return SG_LIB_FILE_ERROR;
+ }
+ if (ret && (0 == op->verbose)) {
+ if (SG_LIB_CAT_INVALID_OP == ret)
+ pr2serr("%sRECEIVE DIAGNOSTIC RESULTS command not supported\n",
+ ((MODE_DNLD_STATUS == op->mc_mode) ?
+ "" : "SEND DIAGNOSTIC or "));
+ else if (ret > 0)
+ fprintf(stderr, "Failed, exit status %d\n", ret);
+ else if (ret < 0)
+ fprintf(stderr, "Some error occurred\n");
+ }
+ return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
+}
diff --git a/src/sg_write_buffer.c b/src/sg_write_buffer.c
index 59d35ef4..ff864aa9 100644
--- a/src/sg_write_buffer.c
+++ b/src/sg_write_buffer.c
@@ -26,7 +26,7 @@
* This utility issues the SCSI WRITE BUFFER command to the given device.
*/
-static const char * version_str = "1.16 20140817"; /* spc4r37 */
+static const char * version_str = "1.17 20140928"; /* spc4r37 */
#define ME "sg_write_buffer: "
#define DEF_XFER_LEN (8 * 1024 * 1024)
@@ -101,7 +101,7 @@ usage()
"acronym\n"
" (def: 0 -> 'combined header and "
"data' (obs))\n"
- " --off=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n"
+ " --offset=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n"
" --raw|-r read from stdin (same as '-I -')\n"
" --skip=SKIP|-s SKIP bytes in file FILE to skip before "
"reading\n"
@@ -132,51 +132,54 @@ usage()
#define MODE_DNLD_ERR_HISTORY 0x1C
-static struct mode_s {
+struct mode_s {
const char *mode_string;
int mode;
const char *comment;
-} modes[] = {
- { "hd", MODE_HEADER_DATA, "combined header and data "
+};
+
+static struct mode_s mode_arr[] = {
+ {"hd", MODE_HEADER_DATA, "combined header and data "
"(obsolete)"},
- { "vendor", MODE_VENDOR, "vendor specific"},
- { "data", MODE_DATA, "data"},
- { "dmc", MODE_DNLD_MC, "download microcode and activate"},
- { "dmc_save", MODE_DNLD_MC_SAVE, "download microcode, save and "
+ {"vendor", MODE_VENDOR, "vendor specific"},
+ {"data", MODE_DATA, "data"},
+ {"dmc", MODE_DNLD_MC, "download microcode and activate"},
+ {"dmc_save", MODE_DNLD_MC_SAVE, "download microcode, save and "
"activate"},
- { "dmc_offs", MODE_DNLD_MC_OFFS, "download microcode with offsets "
+ {"dmc_offs", MODE_DNLD_MC_OFFS, "download microcode with offsets "
"and activate"},
- { "dmc_offs_save", MODE_DNLD_MC_OFFS_SAVE, "download microcode with "
+ {"dmc_offs_save", MODE_DNLD_MC_OFFS_SAVE, "download microcode with "
"offsets, save and\n\t\t\t\tactivate"},
- { "echo", MODE_ECHO_BUFFER, "write data to echo buffer"},
- { "dmc_offs_ev_defer", MODE_DNLD_MC_EV_OFFS_DEFER, "download "
+ {"echo", MODE_ECHO_BUFFER, "write data to echo buffer"},
+ {"dmc_offs_ev_defer", MODE_DNLD_MC_EV_OFFS_DEFER, "download "
"microcode with offsets, select\n\t\t\t\tactivation event, "
"save and defer activation"},
- { "dmc_offs_defer", MODE_DNLD_MC_OFFS_DEFER, "download microcode "
- "with offsets, save and defer\n\t\t\t\tactivation"},
- { "activate_mc", MODE_ACTIVATE_MC,
- "activate deferred microcode"},
- { "en_ex", MODE_EN_EX_ECHO, "enable expander communications "
- "protocol and echo\n\t\t\t\tbuffer (obsolete)"},
- { "dis_ex", MODE_DIS_EX, "disable expander communications "
+ {"dmc_offs_defer", MODE_DNLD_MC_OFFS_DEFER, "download microcode "
+ "with offsets, save and\n\t\t\t\tdefer activation"},
+ {"activate_mc", MODE_ACTIVATE_MC, "activate deferred microcode"},
+ {"en_ex", MODE_EN_EX_ECHO, "enable expander communications "
+ "protocol and\n\t\t\t\techo buffer (obsolete)"},
+ {"dis_ex", MODE_DIS_EX, "disable expander communications "
"protocol\n\t\t\t\t(obsolete)"},
- { "deh", MODE_DNLD_ERR_HISTORY, "download application client "
+ {"deh", MODE_DNLD_ERR_HISTORY, "download application client "
"error history "},
+ {NULL, 0, NULL},
};
-#define NUM_MODES ((int)(sizeof(modes)/sizeof(modes[0])))
-
static void
print_modes(void)
{
- int k;
+ const struct mode_s * mp;
pr2serr("The modes parameter argument can be numeric (hex or decimal)\n"
"or symbolic:\n");
- for (k = 0; k < NUM_MODES; k++) {
- pr2serr(" %2d (0x%02x) %-18s%s\n", modes[k].mode, modes[k].mode,
- modes[k].mode_string, modes[k].comment);
+ for (mp = mode_arr; mp->mode_string; ++mp) {
+ pr2serr(" %2d (0x%02x) %-18s%s\n", mp->mode, mp->mode,
+ mp->mode_string, mp->comment);
}
+ pr2serr("\nAdditionally '--bpw=<val>,act' does a activate deferred "
+ "microcode after\nsuccessful dmc_offs_defer and "
+ "dmc_offs_ev_defer mode downloads.\n");
}
/* <<<< This function will be moved to the library in the future >>> */
@@ -268,6 +271,7 @@ main(int argc, char * argv[])
const char * file_name = NULL;
unsigned char * dop = NULL;
char * cp;
+ const struct mode_s * mp;
char ebuff[EBUFF_SZ];
int ret = 0;
@@ -325,13 +329,13 @@ main(int argc, char * argv[])
}
} else {
len = strlen(optarg);
- for (k = 0; k < NUM_MODES; ++k) {
- if (0 == strncmp(modes[k].mode_string, optarg, len)) {
- wb_mode = modes[k].mode;
+ for (mp = mode_arr; mp->mode_string; ++mp) {
+ if (0 == strncmp(mp->mode_string, optarg, len)) {
+ wb_mode = mp->mode;
break;
}
}
- if (NUM_MODES == k) {
+ if (! mp->mode_string) {
print_modes();
return SG_LIB_SYNTAX_ERROR;
}
@@ -512,8 +516,8 @@ main(int argc, char * argv[])
if (bpw_then_activate) {
if (verbose)
pr2serr("sending Activate deferred microcode [0xf]\n");
- res = sg_ll_write_buffer_v2(sg_fd, 0xf, 0, 0, 0, NULL, 0, 1,
- verbose);
+ res = sg_ll_write_buffer_v2(sg_fd, MODE_ACTIVATE_MC, 0, 0, 0,
+ NULL, 0, 1, verbose);
}
} else {
if (verbose)