Home / Alt manpages / sg_raw(8)

  • sg_raw(8)
  • Admin command
  • linux

Send a Carefully Bounded SCSI Command with sg_raw

You will finish with a repeatable way to send a known SCSI command, capture its response, and interpret the result without accidentally scanning or writing to a real device. The examples use sg_raw 0.4.34 from sg3-utils package 1.46-3ubuntu4, as installed on this machine.

Allow about fifteen minutes. You need a shell, the sg3-utils package, a command documented for the particular device, and permission to open its generic SCSI device. Most read-only inspection examples can be run as an ordinary user if device permissions allow it. Use sudo only when the device node requires it.

Checkpoint

This guide sends arbitrary low-level commands. Do not substitute a disk or tape device for the placeholders until you have checked the command against the device documentation and confirmed its direction and transfer length.

1. Confirm the installed tool

Check the binary and version first. These commands are read-only:

$ command -v sg_raw
/usr/bin/sg_raw
$ sg_raw --version
sg_raw 0.4.34 (2021-01-03)
Copyright (C) 2007-2021 Ingo van Lil

The package version and the program version are related but not identical labels. Record both when reporting a problem:

$ dpkg-query -W -f='${Package} ${Version}\n' sg3-utils
sg3-utils 1.46-3ubuntu4

Ask for the usage summary if you need to check an option spelling. Long options take a value, and their short forms do too:

$ sg_raw --help

2. Choose the device and command set

The final positional arguments are the device followed by command bytes. Each byte is two hexadecimal digits without a 0x prefix. SCSI commands are between 6 and 260 bytes in this installed build. Common Linux device choices include a generic SCSI node such as /dev/sg0 and a block device such as /dev/sda, but the correct choice depends on the pass-through interface and your hardware.

For normal SCSI work, make the command set explicit with --cmdset=1 when there is any possibility that command length could be mistaken for NVMe. The default, --cmdset=0, uses a length heuristic. NVMe commands are 64 bytes long; use --cmdset=2 for NVMe and --nvm for the NVM command set rather than the default Admin command set.

Do not guess a command from an example for a different device. An INQUIRY command is a useful read-only starting point for a SCSI target:

$ sg_raw --cmdset=1 --request=1k /dev/sg0 12 00 00 00 60 00

The 12 opcode is INQUIRY. The command asks the device for up to 1024 bytes, while the command's allocation length asks for 96 bytes. The response is printed as hexadecimal by default. The exact data and any sense information are device-specific.

Checkpoint

The command exited with status 0 only if the pass-through completed successfully. Confirm the status immediately when scripting:

$ printf 'sg_raw status: %s\n' "$?"
sg_raw status: 0

3. Test decoding without touching hardware

When you are checking a CDB's shape, use --enumerate. It decodes the command name and exits, while requiring a device argument but ignoring the device itself:

$ sg_raw --enumerate /dev/null 12 00 00 00 60 00
Inquiry

For more detail, --verbose can show the decoded command. Using /dev/null with --verbose is only a decoding check; it is not a successful device operation because /dev/null does not implement SCSI pass-through. A diagnostic such as Inappropriate ioctl for device is therefore expected if you omit --enumerate.

4. Save returned data as binary

Use --outfile when another tool needs the response as bytes rather than a terminal hexdump. The file is written in binary and can overwrite an existing path, so choose a new path or make a backup first. This example keeps the output in a temporary working directory:

$ workdir=$(mktemp -d)
$ sg_raw --cmdset=1 --request=1k --outfile="$workdir/inquiry.bin" /dev/sg0 12 00 00 00 60 00
$ file "$workdir/inquiry.bin"
$ od -Ax -tx1 -N 16 "$workdir/inquiry.bin"

If --outfile=- is used, binary data goes to standard output. Do not send that form to a terminal. The --binary option also makes standard output binary, even without an output file.

Remove the temporary directory only after checking the result:

$ rm -rf "$workdir"

This cleanup is reversible only if you retained another copy. Do not use a broad path in place of the variable.

5. Send data only when the CDB requires it

--send=SLEN reads exactly the requested number of bytes from standard input, or from --infile, and sends them to the device. The data length must agree with the CDB and with the device's documented transfer units. A mismatch can fail, hang, or have unintended effects.

The manpage's WRITE BUFFER example uses mode 2, which is a safer demonstration than writing a disk sector:

$ sg_raw --cmdset=1 --send=512 --infile=payload.bin /dev/sda \
    3b 02 00 00 00 00 00 02 00 00

This is still a device command and may alter device state. Confirm that the target supports the command and that payload.bin is exactly the intended 512 bytes before running it. Do not use this pattern for a disk write unless the device documentation explicitly calls for it.

For a command that returns data, --request is the receive limit. The value is decimal unless it has a leading 0x or a trailing h; a trailing k means 1024-byte kilobytes. Keep the CDB's allocation length and the request limit large enough for the documented response.

6. Keep dangerous features out of first tests

The default device open mode is read-write. Add --readonly when the command only needs a read-only open:

$ sg_raw --readonly --cmdset=1 --request=1k /dev/sg0 \
    12 00 00 00 60 00

This flag does not turn a write CDB into a read operation. It only requests a read-only device open, so use it as an additional boundary rather than as proof that a command is harmless.

Do not begin with --scan=FO,LO. It sends a range of opcodes with the remaining bytes held constant, and the manpage explicitly warns that arbitrary commands can have unexpected results. There is no general undo for a command that changes media or device state. If a command times out, the default wait is 20 seconds; the operating system may abort it and then attempt to reset the device. Use a longer or shorter --timeout only when the device documentation supports that decision, and schedule disruptive tests for a maintenance window.

7. Diagnose failures without hiding sense data

On a failed SCSI command, leave sense output enabled. It often contains the device's explanation. Use --nosense only when a caller cannot accept the extra diagnostic output. Increase verbosity with repeated --verbose options when you need the CDB and pass-through details.

Separate three common outcomes:

  • A non-zero exit status means sg_raw did not complete successfully; preserve its diagnostic output.
  • A successful exit status means the pass-through reported success, not that the returned bytes describe the object you expected.
  • An operating-system error such as an ioctl failure usually means the chosen device node does not provide the required pass-through interface, rather than that the CDB itself is valid.

Check the device type and its supported commands with the related sg3-utils tools when available:

$ sg_inq /dev/sg0
$ sg_vpd /dev/sg0

These commands are also device operations, so use the correct generic node and permissions. If the device is busy, belongs to a mounted storage path, or is part of a redundant array, stop and identify the operational impact before continuing.

Done means

  • You recorded the installed sg_raw and sg3-utils versions.
  • You identified the target device and selected SCSI or NVMe explicitly where needed.
  • You decoded or reviewed the CDB before sending it to hardware.
  • You matched request and send lengths to the device documentation.
  • You preserved sense output and checked the exit status and returned data.
  • You avoided opcode scans and destructive commands until there is a tested recovery plan.