aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog2
-rw-r--r--doc/sg3_utils.82
-rw-r--r--doc/sg_ses_microcode.867
-rw-r--r--src/sg_ses_microcode.c70
4 files changed, 112 insertions, 29 deletions
diff --git a/ChangeLog b/ChangeLog
index f9fad72a..a85d08f1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,7 +2,7 @@ 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 [20140930] [svn: r611]
+Changelog for sg3_utils-1.40 [20141002] [svn: r612]
- sg_write_verify: new utility for WRITE AND VERIFY
- sg_ses_microcode: new utility
- sg_senddiag: add --maxlen= option
diff --git a/doc/sg3_utils.8 b/doc/sg3_utils.8
index bbe3483c..100ebe2a 100644
--- a/doc/sg3_utils.8
+++ b/doc/sg3_utils.8
@@ -1,4 +1,4 @@
-.TH SG3_UTILS "8" "September 2014" "sg3_utils\-1.40" SG3_UTILS
+.TH SG3_UTILS "8" "October 2014" "sg3_utils\-1.40" SG3_UTILS
.SH NAME
sg3_utils \- a package of utilities for sending SCSI commands
.SH SYNOPSIS
diff --git a/doc/sg_ses_microcode.8 b/doc/sg_ses_microcode.8
index f3a7ff7b..303d6f41 100644
--- a/doc/sg_ses_microcode.8
+++ b/doc/sg_ses_microcode.8
@@ -1,4 +1,4 @@
-.TH SG_SES_MICROCODE "8" "September 2014" "sg3_utils\-1.39" SG3_UTILS
+.TH SG_SES_MICROCODE "8" "October 2014" "sg3_utils\-1.39" SG3_UTILS
.SH NAME
sg_ses_microcode \- send microcode to a SCSI enclosure
.SH SYNOPSIS
@@ -16,10 +16,10 @@ 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.
+DIAGNOSTIC command followed optionally 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 to fetch the Download microcode status dpage and decode it. This does
@@ -133,12 +133,36 @@ dmc_offs_defer [14, 0xe]
Download microcode with offsets, save, and defer activate.
.TP
activate_mc [15, 0xf]
-Activate deferred microcode.
+Activate deferred microcode. There is no follow-up RECEIVE DIAGNOSTIC RESULTS
+to fetch the Download microcode status dpage since the \fIDEVICE\fR might be
+resetting.
.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 WHEN THE DOWNLOAD FAILS
+Firstly, if it succeeds, this utility should stay silent and return.
+Typically vendors will change the "revision" string (which is 4 characters
+long) whenever they release new firmware. That can be seen in the response
+to a SCSI INQUIRY command, for example by using the sg_inq utility.
+It is possible that the device needs to be power cycled before the new
+microcode becomes active. Also if mode dmc_offs_defer [0xe] is used to
+download the microcode, then another invocation with activate_mc may
+be needed.
+.PP
+If something goes wrong, there will typically be messages printed out
+by this utility. The first thing to check is the microcode (firmware)
+file itself. Is it designed for the device model; has it been corrupted,
+and if downgrading (i.e. trying to re-instate older firmware), does
+the vendor allow that?
+.PP
+Getting new firmware on a device is a delicate operation that is not
+always well defined by T10's standards and drafts. One might speculate
+that they are deliberately vague. In testing this utility one vendor's
+interpretation of the standard was somewhat surprising. The \fI\-\-non\fR
+option was added to cope with their interpretation. So if the above
+suggestions don't help, try adding the \fI\-\-non\fR option.
.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
@@ -156,6 +180,10 @@ 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
+The exact error from the non\-standard implementation was a sense key of
+ILLEGAL REQUEST and an asc/ascq code of 0x26,0x0 which is "Invalid field in
+parameter list". If that is seen try again with the \fI\-\-non\fR option.
+.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.
@@ -167,7 +195,32 @@ 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
+If no microcode/firmware file is given then this utility fetches and decodes
+the Download microcode status dpage which could possibly show another
+initiator in the process of updating the microcode. Even if that is
+happening, fetching the status page should not cause any problems:
+.PP
+ sg_ses_microcode /dev/sg3
+.br
+Download microcode status diagnostic page:
+.br
+ number of secondary subenclosures: 0
+.br
+ generation code: 0x0
+.br
+ subenclosure identifier: 0 [primary]
+.br
+ download microcode status: No download microcode operation in progress [0x0]
+.br
+ download microcode additional status: 0x0
+.br
+ download microcode maximum size: 1048576 bytes
+.br
+ download microcode expected buffer id: 0x0
+.br
+ download microcode expected buffer id offset: 0
+.PP
+The following sends new microcode/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:
diff --git a/src/sg_ses_microcode.c b/src/sg_ses_microcode.c
index 54d45062..e6cabe4b 100644
--- a/src/sg_ses_microcode.c
+++ b/src/sg_ses_microcode.c
@@ -36,7 +36,7 @@
* RESULTS commands in order to send microcode to the given SES device.
*/
-static const char * version_str = "1.00 20140830"; /* ses3r06 */
+static const char * version_str = "1.01 20141002"; /* ses3r06 */
#define ME "sg_ses_microcode: "
#define MAX_XFER_LEN (128 * 1024 * 1024)
@@ -282,15 +282,16 @@ 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 last, const struct opts_t * op)
{
- int do_len, rem, res, rsp_len, k, num, mc_status;
+ int do_len, rem, res, rsp_len, k, num, mc_status, verb;
int send_data = 0;
int ret = 0;
uint32_t rec_gen_code;
const unsigned char * ucp;
const char * cp;
+ verb = (op->verbose > 1) ? op->verbose - 1 : 0;
switch (op->mc_mode) {
case MODE_DNLD_MC_OFFS:
case MODE_DNLD_MC_OFFS_SAVE:
@@ -335,18 +336,40 @@ send_then_receive(int sg_fd, uint32_t gen_code, int off_off,
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);
+ 1 /* noisy */, verb);
if (op->mc_non) {
/* If non-standard, only call RDR after failed SD */
if (0 == res)
return 0;
/* If RDR error after SD error, prefer reporting SD error */
ret = res;
- } else if (res)
- return res;
+ } else {
+ switch (op->mc_mode) {
+ case MODE_DNLD_MC_OFFS:
+ case MODE_DNLD_MC_OFFS_SAVE:
+ if (res)
+ return res;
+ else if (last)
+ return 0; /* RDR after last may hit a device reset */
+ break;
+ case MODE_DNLD_MC_OFFS_DEFER:
+ if (res)
+ return res;
+ break;
+ case MODE_ACTIVATE_MC:
+ if (0 == res)
+ return 0; /* RDR after ACTIVATE_MC may hit a device reset */
+ /* SD has failed, so do a RDR but return SD's error */
+ ret = res;
+ break;
+ default:
+ pr2serr("send_then_receive: mc_mode=0x%x\n", op->mc_mode);
+ return SG_LIB_SYNTAX_ERROR;
+ }
+ }
res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip,
- DEF_DI_LEN, 1, op->verbose);
+ DEF_DI_LEN, 1, verb);
if (res)
return ret ? ret : res;
rsp_len = sg_get_unaligned_be16(dip + 2) + 4;
@@ -375,6 +398,10 @@ send_then_receive(int sg_fd, uint32_t gen_code, int off_off,
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 (op->verbose > 1)
+ pr2serr(" subenc_id=%d, expected_buffer_id=%d, "
+ "expected_offset=0x%" PRIx32 "\n", ucp[1], ucp[11],
+ sg_get_unaligned_be32(ucp + 12));
if (mc_status >= 0x80)
ret = ret ? ret : SG_LIB_CAT_OTHER;
}
@@ -386,7 +413,7 @@ send_then_receive(int sg_fd, uint32_t gen_code, int off_off,
int
main(int argc, char * argv[])
{
- int sg_fd, res, c, len, k, n, got_stdin, is_reg, rsp_len;
+ int sg_fd, res, c, len, k, n, got_stdin, is_reg, rsp_len, verb, last;
int infd = -1;
int do_help = 0;
const char * device_name = NULL;
@@ -400,7 +427,7 @@ main(int argc, char * argv[])
struct opts_t opts;
struct opts_t * op;
const struct mode_s * mp;
- uint32_t gen_code;
+ uint32_t gen_code = 0;
int ret = 0;
op = &opts;
@@ -682,9 +709,10 @@ main(int argc, char * argv[])
goto fini;
}
memset(dip, 0, DEF_DI_LEN);
+ verb = (op->verbose > 1) ? op->verbose - 1 : 0;
/* Fetch Download microcode status dpage for generation code ++ */
res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip,
- DEF_DI_LEN, 1, op->verbose);
+ DEF_DI_LEN, 1, verb);
if (0 == res) {
rsp_len = sg_get_unaligned_be16(dip + 2) + 4;
if (rsp_len > DEF_DI_LEN) {
@@ -707,22 +735,25 @@ main(int argc, char * argv[])
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);
+ res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, 1,
+ op);
ret = res;
goto fini;
}
res = 0;
if (op->bpw > 0) {
- for (k = 0; k < op->mc_len; k += n) {
+ for (k = 0, last = 0; k < op->mc_len; k += n) {
n = op->mc_len - k;
if (n > op->bpw)
n = op->bpw;
+ else
+ last = 1;
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);
+ pr2serr("bpw loop: mode=0x%x, id=%d, off_off=%d, len=%d, "
+ "last=%d\n", op->mc_mode, op->mc_id, k, n, last);
res = send_then_receive(sg_fd, gen_code, k, dmp + k, n, &dout,
- dip, op);
+ dip, last, op);
if (res)
break;
}
@@ -731,15 +762,14 @@ main(int argc, char * argv[])
if (op->verbose)
pr2serr("sending Activate deferred microcode [0xf]\n");
res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout,
- dip, op);
+ dip, 1, 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);
+ pr2serr("single: 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);
+ dip, 1, op);
}
if (res)
ret = res;