Inspect SCSI Devices Safely with sg3_utils on Linux

Send the wrong SCSI command to the wrong device with sg3_utils and you can format a disk you meant only to look at. This guide finds the right device name, runs a read-only inquiry, saves decoded output for later, and turns a non-zero exit status into an actual diagnosis. Allow about 10 minutes if the device is already attached. You need the sg3-utils package and access to a SCSI generic device, usually under /dev/sg*.

Before you start

This guide is based on sg3_utils 1.46, provided here by Debian package version 1.46-3ubuntu4. The package bundles many separate programs, and their names usually describe the SCSI command they send: sg_inq sends INQUIRY, sg_readcap reads capacity, sg_logs fetches log pages.

Most commands need permission to open the device, so check group membership and the device nodes first:

command -v sg_inq
sg_inq --version
ls -l /dev/sg*

On this release, sg_inq --version prints a utility version string. Device nodes are commonly owned by root:disk; being able to see a node does not mean your account can use it.

Checkpoint: find the right device

  1. List generic SCSI devices with the package scanner.
sg_scan -i

The -i option asks the scanner to issue INQUIRY and show identifying information. It is a read-only discovery operation, but it still opens each device, so a permission error here means you need an approved group or sudo just to run the discovery itself.

Linux also exposes disk-style names such as /dev/sda and optical names such as /dev/sr0, and the manpage notes that current kernels will normally accept almost any suitable device name for these utilities. The generic name is what you want when you need the SCSI pass-through interface explicitly. Do not guess from the number: map it with discovery first, and note the mapping somewhere.

Checkpoint: inspect identity without changing the medium

  1. Replace the placeholder with the device you identified, then run INQUIRY.
DEVICE=/dev/sg0
sg_inq "$DEVICE"

Expect vendor, product and revision information when the target accepts INQUIRY; exact lines depend on target and transport. This command does not format, write or start a disk. It can still fail if the device is busy, unavailable, behind a restricted pass-through interface, or simply does not support the requested command.

For a stable, machine-friendly identity page, ask for the device identification VPD page instead:

sg_inq --id "$DEVICE"

Keep that output alongside the host name and device path. A path like /dev/sg0 is assigned by discovery order and can change after reboot; the identifier the device itself returns is a far better basis for an inventory record.

Checkpoint: separate fetching from decoding

  1. Capture hexadecimal response data, then decode it from a file if you need repeatable analysis.
DEVICE=/dev/sg0
sg_inq --hex "$DEVICE" > inquiry.hex
sg_inq --inhex=inquiry.hex "$DEVICE"

--hex writes an ASCII hexadecimal response, and the matching input option tells a utility to decode a saved response rather than fetch a fresh one. For utilities where the input file supplies all response data, the device argument may be ignored, so check that particular utility's own usage message. Treat a captured response as evidence, not as a file to edit casually.

If another program needs raw bytes rather than text, keep that output separate from diagnostic messages:

sg_inq --raw "$DEVICE" > inquiry.bin
file inquiry.bin

Do not open a binary capture in a text editor, and do not redirect raw output straight to a terminal.

Decode a failure before retrying

sg3_utils returns zero for success and non-zero for failure, and the non-zero value is not a generic shell error: many of them describe SCSI sense conditions directly. Status 2 means the device is not ready, 5 commonly means an illegal request, 9 means an unsupported command, and 33 means a command timeout.

sg_decode_sense --err=2
sg_decode_sense --err=33

On this installation the first command reports the device as not ready, the second a SCSI command timeout. Capture standard error alongside standard output when you're diagnosing a real command:

if ! sg_inq "$DEVICE" > inquiry.txt 2> inquiry.err; then
    status=$?
    printf 'sg_inq failed with status %s\n' "$status" >&2
    sg_decode_sense --err="$status"
    sed -n '1,80p' inquiry.err >&2
fi

Watch for a shell trap here: inside if ! command, $? is the status of !, not the original command. For a script that must keep the exact code, run the command first, save $?, then test the saved value.

Options that cause confusion

Safety boundary: INQUIRY, scans and log reads are generally observational. Other programs in the package can write blocks, alter modes, start or stop media, download firmware, or format a device outright. Treat sg_dd, sg_format, sg_modes with select write actions, and any firmware tool as a change operation. Confirm the device by its stable identity, check that utility's own manpage, and use --dry-run where that utility documents it; a dry run is not universal and is not a substitute for an offline backup.

Do not reach for sudo as a reflex. Elevation only changes access permission; it does not make a guessed device safe. If a write command has already changed state, stop and follow the target manufacturer's recovery procedure rather than improvising a second write or format command.

Done means