Verify SCSI Disk Blocks Safely with sg_verify
You will run a SCSI VERIFY operation against a block device, either asking the device to check its own medium or comparing blocks with data you provide. The examples use sg_verify from the Ubuntu sg3-utils package, version 1.46-3ubuntu4; the installed program reports version 1.27 20201029. Allow 10 minutes for a single, already identified device. This guide does not write user data, but VERIFY is an I/O operation against real storage, so do not experiment on an important device.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Confirm the tool and identify the device
Run the checks as your normal user first. You need the SCSI device path, such as /dev/sg2 or a path supplied by your storage administrator. Do not guess a device name from its position in /dev.
$ command -v sg_verify
/usr/bin/sg_verify
$ sg_verify --version
sg_verify: version: 1.27 20201029
$ sg_verify --help
Usage: sg_verify [--16] [--bpc=BPC] [--count=COUNT] ... DEVICE
The exact help layout can vary slightly, but it should identify DEVICE as a required argument. If you need to discover a SCSI device, use your normal inventory process, or inspect it with a read-only tool such as sg_inq. Check the result before continuing.
2. Run a small device-side verification
By default, sg_verify starts at logical block address 0 and checks one block. With no data-out buffer, the device performs its own medium verification. The manual describes this as checking the logical contents against additional error-correction data, but the exact verification work is device-specific.
Replace the example path only after you have confirmed it is the intended device:
$ sg_verify --lba=0 --count=1 /dev/sg2
$ printf 'exit status: %s\n' "$?"
exit status: 0
Success is intentionally quiet: no verification error is sent to standard error and the exit status is 0. The command does not print a report saying that one block was checked. A non-zero result needs investigation, not an automatic retry loop.
Checkpoint
Stop here if your requirement is only a device-side check. You have not requested a comparison with a file or a fill pattern.
3. Extend the check with explicit ranges
Use --lba for the first logical block and --count for the number of blocks. Values are decimal unless written with a 0x prefix or a trailing h. The default count is one block.
$ sg_verify --lba=1048576 --count=128 --bpc=128 /dev/sg2
$ test "$?" -eq 0 && echo "VERIFY completed successfully"
VERIFY completed successfully
--bpc limits the number of blocks sent in one SCSI VERIFY command. It defaults to 128 blocks, so a larger count can produce several commands. It is ignored when --ndo is used. The device may impose a smaller transfer limit, and the default VERIFY(10) form has a maximum --bpc value of 65535. Use --16 for VERIFY(16), or let a sufficiently large LBA cause that form to be selected.
Before scanning a large range, confirm the logical block size and device capacity with your storage documentation or sg_readcap. An LBA beyond the device is not a useful test.
4. Compare blocks with known data
To make the device compare its blocks with bytes you supply, set --ndo. This issues one VERIFY command, ignores --bpc, and takes the data from --in=FILE or standard input. The number of bytes must match the comparison you intend, including the logical block size and count.
For a one-block comparison on a device with 512-byte logical blocks, prepare exactly 512 bytes. This example uses a temporary file and removes it after the check:
$ tmp_file=$(mktemp)
$ trap 'rm -f "$tmp_file"' EXIT
$ dd if=/dev/zero of="$tmp_file" bs=512 count=1 status=none
$ sg_verify --lba=0 --count=1 --ndo=512 --in="$tmp_file" /dev/sg2
$ verify_status=$?
$ printf 'exit status: %s\n' "$verify_status"
exit status: 0
This checks whether the first block matches 512 zero bytes. The command does not replace the block with those bytes. If the comparison fails, the program returns exit status 14, the SCSI MISCOMPARE sense-key value, and normally prints sense information to standard error.
5. Use fill patterns deliberately
--0 supplies an --ndo-sized buffer of zero bytes without reading standard input. --ff does the same with 0xff bytes. Both are useful for checking whether known areas are filled with a pattern, but they still require a correct --ndo length and can make a very large comparison request.
$ sg_verify --lba=0 --count=1 --ndo=512 --0 /dev/sg2
$ case "$?" in
0) echo "all compared bytes matched" ;;
14) echo "MISCOMPARE: the bytes did not match" ;;
*) echo "sg_verify failed" ;;
esac
Do not combine --0 or --ff with --in; the manual says that supplying both is an error. A comparison mismatch is not proof that the medium is unusable: it means the supplied data and the device contents differed.
6. Diagnose failures without hiding them
Leave diagnostic output enabled while investigating. --quiet suppresses sense-buffer messages for MISCOMPARE but still returns status 14, which is easy to miss in a script that only logs standard output. --verbose increases debug output and is useful when a device rejects a command, but it does not make a rejected VERIFY safe to ignore.
The Linux SCSI generic driver normally needs read-write access for VERIFY even though the operation is a verification rather than a data write. Therefore, do not add --readonly just because the purpose sounds read-only. The option opens the device read-only, and the manual warns that this may not work with the Linux sg driver. If permissions prevent access, ask for the appropriate device access or use elevated privileges only for the command that needs it:
$ sudo sg_verify --lba=0 --count=1 /dev/sg2
$ printf 'exit status: %s\n' "$?"
Check the device path, its logical block size, the requested byte count, and the kernel or device error before repeating a failed operation. There is no undo command because sg_verify is a check, not a repair operation. Keep any input comparison file until you have recorded which test it represents.
Done means
- You confirmed the installed
sg_verifyversion and the exact target device. - Your LBA, block count and comparison byte count match the device geometry.
- A device-side success returned
0and did not rely on output text. - A data comparison treats
14as MISCOMPARE, not as a generic success. - You left diagnostics enabled while troubleshooting and did not hide a mismatch with
--quiet.