Decode SCSI Sense Bytes Safely with sg_decode_sense
You will turn a SCSI sense byte sequence from a kernel log or storage diagnostic into a readable sense key, additional sense text and, where available, an information field. You can also identify a SCSI command descriptor block (CDB), decode a SCSI status byte and save a byte sequence for later inspection. Allow about ten minutes. The commands below only read or convert supplied data; they do not open a SCSI device.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide uses the installed sg3-utils package, version 1.46-3ubuntu4. On this machine, sg_decode_sense --version reports utility version 1.21 20190602. That reported utility version is the useful compatibility detail for the examples, because package and utility version strings are not the same thing.
1. Confirm the tool and keep the raw bytes
First check that the command is installed. No elevated privileges are needed:
$ command -v sg_decode_sense
/usr/bin/sg_decode_sense
$ sg_decode_sense --version
version: 1.21 20190602
Copy the original log line somewhere safe before editing it. Sense data is often shown as bytes beginning with 70, 71, 72, 73, f0 or f1. It may be as short as 18 bytes in the older fixed format, but the SCSI data can be longer. Do not trim bytes merely to make the line look tidy.
Checkpoint: the input should be hexadecimal bytes, not the timestamp, device name or explanatory text surrounding them. If you copied a whole kernel-log line, extract only the byte sequence before running the decoder.
2. Decode bytes copied from a log
Pass space-separated hexadecimal bytes as positional arguments. This example is the fixed-format medium-error sample documented by the installed manual:
$ sg_decode_sense f0 00 03 00 00 12 34 0a 00 00 00 00 11 00 00 00 00 00
Fixed format, current; Sense key: Medium Error
Additional sense: Unrecovered read error
Info fld=0x1234 [4660]
The sense key gives the broad class of failure. Additional sense information narrows it down. Here, the information field is 0x1234, or decimal 4660. For this medium-error example, the manual describes that field as the lowest logical block address that the related command could not read, verify or write. Treat that interpretation as specific to the command and sense data, not as a universal meaning for every SCSI response.
A successful decoder run normally exits with status zero. Check it immediately if a script will make a decision from the result:
$ sg_decode_sense f0 00 03 00 00 12 34 0a 00 00 00 00 11 00 00 00 00 00 >/tmp/sg-sense.txt
$ printf '%s\n' "$?"
0
3. Read a longer or commented capture from a file
Use --file when the data spans several lines or you want to retain comments describing where it came from. The file contains ASCII hexadecimal, with bytes separated by spaces, commas, tabs or newlines. A hash character starts a comment to the end of that line:
$ cat > /tmp/sense-capture.txt <<'EOF'
# copied from the storage host log
f0 00 03 00 00 12 34 0a 00 00 00 00
11 00 00 00 00 00
EOF
$ sg_decode_sense --file=/tmp/sense-capture.txt
Fixed format, current; Sense key: Medium Error
Additional sense: Unrecovered read error
Info fld=0x1234 [4660]
The here-document creates a temporary input file and does not change system configuration. If the result differs from the command-line version, compare the bytes, separators and comment boundary. A common trap is copying a log prefix or leaving punctuation attached to a byte.
For an unbroken hexadecimal string, use --nospace. It consumes two hexadecimal digits per byte and therefore requires an even number of digits:
$ sg_decode_sense --nospace f00003000012340a000000001100000000
Fixed format, current; Sense key: Medium Error
Additional sense: Unrecovered read error
Info fld=0x1234 [4660]
4. Decode a CDB or a SCSI status byte
A CDB is a command, not sense data. Add --cdb when you want the command name for a hexadecimal CDB:
$ sg_decode_sense --cdb 12 00 00 00 24 00
Inquiry
The decoder uses the first byte, the opcode, and may use a service-action field as well. Do not put --cdb on a sense-data command: it changes the interpretation of every supplied byte.
A SCSI status byte is related to sense data but is distinct from it. Supply the byte in hexadecimal with --status:
$ sg_decode_sense --status=02
SCSI status: Check Condition
Check Condition usually means that sense data should be examined too. The status byte alone does not replace the sense response.
5. Translate an sg3-utils exit status
When another utility in the package returns an exit status, --err prints the package's short description of that value. This is a separate action: other decoder arguments are ignored, apart from --verbose:
$ sg_decode_sense --err=5
Illegal request
$ sg_decode_sense --err=64
Bad address
$ sg_decode_sense --err=255
Utility returned 255 or higher
Use this for a human-readable diagnostic, not as a substitute for preserving the original numeric status. The installed program returns zero after printing the description, so a script that needs the original failure status must save that status before invoking sg_decode_sense.
6. Save a converted copy without losing the source
--write writes the decoded input bytes to a named file. Without --hex, the output is binary. With --hex, it is ASCII hexadecimal formatted for use by a C compiler:
$ sg_decode_sense --write=/tmp/sense.bin f0 00 03 00 00 12 34 0a 00 00 00 00 11 00 00 00 00 00
$ wc -c /tmp/sense.bin
18 /tmp/sense.bin
$ sg_decode_sense --hex --write=/tmp/sense.cbytes f0 00 03 00 00 12 34 0a 00 00 00 00 11 00 00 00 00 00
$ head -n 2 /tmp/sense.cbytes
0xf0,0x00,0x03,0x00,0x00,0x12,0x34,0x0a,0x00,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00
Warning: an existing --write destination is truncated before the new data is written. Choose a new path or copy the old file first. The command creates the destination if necessary, so do not point it at an original capture you still need. No undo is provided by sg_decode_sense; recovery means restoring your backup or recapturing the bytes.
7. Handle the common mistakes
If the output says the format is invalid or the fields look implausible, check that each byte has exactly two hexadecimal digits and that you did not mix a CDB with sense data. Try the same bytes from a file so whitespace and comments are visible. With --nospace, count the digits and confirm that the total is even.
Do not run this command with sudo just because the data came from a storage error. The utility does not access a SCSI logical unit, and decoding a copied byte string is an unprivileged operation. Elevated access may be needed to read the original log or capture new device data, but that is a separate task.
Keep the raw capture alongside the decoded text when escalating a storage fault. A readable phrase is useful for triage, while the original bytes allow another operator to verify the interpretation and inspect fields that this version does not print.
Done means
- The installed
sg_decode_senseversion was checked before relying on its output. - The original hexadecimal bytes were preserved and decoded as sense data, a CDB or a status byte according to their actual type.
- A file or
--nospaceinput was used when the capture format required it. - Any
--writedestination was new or backed up before conversion. - The decoder was run without unnecessary elevated privileges, and the numeric status was preserved when using
--err.