Send SCSI Buffer Data Safely with sg_write_buffer
You will use sg_write_buffer to send a controlled buffer payload to a SCSI device, with a dry run before the real command and smaller chunks for firmware downloads. Allow 15 minutes for a known input file and a device that is safe to test. A real firmware update can take longer and may require a maintenance window.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide is based on the installed sg3-utils package version 1.46-3ubuntu4. The command reports utility version 1.29 20181112, while the installed manual page identifies the sg3_utils interface as 1.45. Keep that distinction in mind when comparing another distribution. You need a readable input file, a SCSI generic device such as /dev/sg4, and device-vendor instructions for the mode, buffer identifier, offsets and activation sequence.
Safety checkpoint
This utility sends SCSI WRITE BUFFER commands. A wrong microcode file can make a device inoperable, and activation can disrupt service or require a power cycle. Do not experiment against a production device. Confirm the exact firmware, target device and rollback plan before omitting --dry-run. Opening a SCSI device may require elevated privileges, so use sudo only for the final command if ordinary access is denied.
1. Confirm the utility and target
Check the executable and record the target path. The command accepts one device argument. A SCSI generic node is usually the least ambiguous target, but use the path documented for your hardware:
$ command -v sg_write_buffer
/usr/bin/sg_write_buffer
$ sg_write_buffer --version
version: 1.29 20181112
$ ls -l /dev/sg4
crw-rw---- 1 root disk 21, 4 ... /dev/sg4
Do not guess a device from its number. Correlate it with your enclosure or host inventory first. The command has no option that discovers the correct target for you.
2. Inspect the input without sending a command
Use --dry-run while checking option spelling, input length and mode selection. It still opens the device and reads the input, but skips the WRITE BUFFER call. For a harmless test, /dev/null is a valid Unix device target:
$ sg_write_buffer --dry-run --verbose \
--mode=echo --in=/path/to/test-buffer.bin /dev/null
tried to read 8388608 bytes from /path/to/test-buffer.bin, got 16 bytes
will write 16 bytes
sending single write buffer, mode=0xa, mpsec=0, id=0, offset=0, len=16
skipping WRITE BUFFER(all in one) command due to --dry-run
The exact verbose wording can vary, but it should show the effective byte count, mode, identifier, offset and a skipped command. The default mode is zero, named combined header and data, which the manual marks obsolete in SPC-4. Select a mode explicitly rather than relying on that default.
Checkpoint
The dry run must read the file you intended and report the mode required by the device documentation. If it reads the wrong file or reports an unexpected length, stop and fix the command before selecting a real device.
3. Choose the data length deliberately
With --in=FILE, the utility reads from the start of a regular file. If you do not provide --length, it reads up to 8 MiB. A longer firmware image therefore needs an explicit length. If the requested length exceeds the available input, the remaining bytes are filled with 0xff; that is a device payload choice, not harmless padding.
$ stat --format='size=%s bytes' /path/to/firmware.bin
size=1048576 bytes
$ sg_write_buffer --dry-run --verbose \
--mode=dmc_offs_save --length=1048576 \
--in=/path/to/firmware.bin /dev/null
Use --skip=BYTES only with a regular file when the device protocol tells you to begin at a later point. It changes the input starting position, not the SCSI buffer offset. The --offset=BYTES option changes the BUFFER OFFSET field in the SCSI command. For a segmented download, these values normally need to advance together according to the vendor's procedure.
Input can also come from standard input with --read-stdin or --in=-. That form reads until EOF, so avoid an interactive terminal. Pipe a fixed file only when you have a reason not to name it directly:
$ cat /path/to/test-buffer.bin | \
sg_write_buffer --dry-run --verbose --mode=echo --read-stdin /dev/null
4. Split a firmware download into bounded writes
Large single SCSI commands can exceed a pass-through or device limit. For modes that download microcode with offsets, use --bpw=BYTES to cap the data in each WRITE BUFFER command. The manual specifically permits this for modes 0x6, 0x7, 0xd and 0xe. A 4 KiB chunk is a conservative example, not a universal device requirement:
$ sg_write_buffer --dry-run --verbose \
--bpw=4k --mode=dmc_offs_save \
--in=/path/to/firmware.bin /dev/sg4
With a real target, the command would issue several writes, advancing the buffer offset for each chunk. The --bpw=4k form is accepted as a size with a suffix. If you append ,activate or ,act, the utility sends an additional mode 0xf activation command after the chunks. Treat that as a separate service-disrupting action and use it only when the vendor requires it.
Do not use --bpw casually with modes that do not describe downloading microcode with offsets. If the device specifies a different maximum transfer size, use that documented value and validate it with a dry run.
5. Send the command during the approved window
Only after the dry run, checksum and target review should you remove --dry-run. This representative command uses the mode and chunking shown above:
$ sudo sg_write_buffer --verbose \
--bpw=4k --mode=dmc_offs_save \
--in=/path/to/firmware.bin /dev/sg4
$ printf '%s\n' "$?"
0
Exit status zero means the utility completed successfully. It does not prove that the device activated the image or that the firmware is suitable. Some deferred modes save the image for a later activation event. Follow the device's own verification and power-cycle procedure, then query its firmware identity with the vendor's supported tool.
The default timeout is 300 seconds per WRITE BUFFER command. Increase --timeout=SECONDS only when the device documentation or observed transfer time justifies it. A timeout change does not make an unsafe target safe and does not resume an interrupted device update.
6. Diagnose failures without making a second guess
An invalid field can produce an ILLEGAL REQUEST with INVALID FIELD IN CDB. A device rejecting the sequence can report COMMAND SEQUENCE ERROR. Pass-through failures may instead look like an invalid argument when a transfer is too large. First preserve the output, command line and device state. Do not immediately retry with a different mode.
- Re-run the dry run with
--verboseand verify the input length, mode, identifier and offset. - Check the firmware checksum against the vendor's release record.
- Reduce
--bpwfor a documented offset mode if the pass-through layer rejects a large transfer. - Ask the hardware vendor what recovery sequence applies before powering off or repeating activation.
If a command was interrupted, leave the device connected and record the last reported offset. Recovery may require a vendor service utility or a controlled power cycle. There is no generic undo command in sg_write_buffer, and overwriting the device with an arbitrary older image is not a rollback plan.
Done means
- The target device was positively identified and the firmware checksum was verified.
- A dry run showed the intended input length, mode, identifier and offset.
- Chunking was used for a supported offset-download mode where device or pass-through limits required it.
- The real command ran only in an approved maintenance window, with the required privilege.
- The device's own firmware identity and operational state were checked afterwards, with the original image and recovery plan retained.