Inspect Zoned SCSI Media Safely with sg_rep_zones
sg_rep_zones asks a zoned SCSI device for its zone descriptors and decodes whatever comes back, from the full report down to a single write pointer. The examples use sg_rep_zones from sg3-utils 1.46-3ubuntu4; the installed utility reports version 1.23 (20201216), so check your own --help if a newer package presents additional reporting modes.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need the sg3-utils package, the correct SCSI generic device node, and permission to open that node. This command sends a SCSI REPORT ZONES request to hardware or a pass-through device. It does not format media or reset write pointers, but querying the wrong device can still expose storage you did not mean to look at, so identify the device before you run anything.
1. Confirm the installed tool
Start with read-only local checks. These do not contact a storage device and do not require elevated privileges:
$ command -v sg_rep_zones
/usr/bin/sg_rep_zones
$ sg_rep_zones --version
version: 1.23 20201216
$ dpkg-query -W -f='${Package} ${Version}\n' sg3-utils
sg3-utils 1.46-3ubuntu4
The package version and the utility version are separate pieces of information. Record both when documenting a storage check. The manpage shipped with this package is dated March 2021 and describes the command as sending REPORT ZONES and decoding the returned data.
Checkpoint
If command -v finds nothing, stop and install or enable the package through your normal system-management process. Do not substitute a similarly named utility without checking its own manual first.
2. Identify the exact device node
Use your existing inventory to map the zoned drive to a SCSI generic node such as /dev/sg4. List the nodes and inspect their links:
$ ls -l /dev/sg*
$ udevadm info --query=property --name=/dev/sg4 | grep -E '^(ID_MODEL|ID_SERIAL|ID_WWN)='
Only replace /dev/sg4 after checking the model, serial or WWN against your inventory. The generic node is not necessarily the same path as a block device such as /dev/sdb. If the node cannot be opened, fix the device permissions or group membership through your normal administration process, not by guessing another node.
The command opens the device read-write by default, which is unnecessary for a report query. Use --readonly throughout the examples below: it changes how the node is opened, not whether a write-capable device becomes read-only hardware.
3. Request the normal zone report
This is the basic query. It starts at LBA zero, asks for all zones, and requests the default maximum response length:
$ sg_rep_zones --readonly --report=0 --start=0 /dev/sg4
Run it with the correct device and, if the node requires it, the necessary privileges. A successful exit status is zero. The decoded output comes from the target itself, so its zone count, capacity, zone types, conditions and write-pointer values cannot be predicted in advance. Do not use a made-up output block as a test oracle.
The installed command uses an allocation length of 8192 bytes when --maxlen is omitted or set to zero. That is a maximum response buffer, not a guarantee the device only has 8192 bytes, or only a handful of zones.
Checkpoint
Capture the status immediately if you are scripting the query:
$ sg_rep_zones --readonly --report=0 --start=0 /dev/sg4
$ status=$?
$ printf 'sg_rep_zones exit status: %s\n' "$status"
sg_rep_zones exit status: 0
If the status is non-zero, keep the diagnostic output and check the device identity, permissions, target support for REPORT ZONES and the SCSI sense information. A transport or media error is not evidence that the target is simply unzoned.
4. Limit the report before you inspect it
Large zoned devices can return a lot of descriptors. --num=NUM limits how many descriptors the utility prints. --start=LBA chooses the starting area; the device reports from the preceding zone start when the supplied LBA sits inside a zone rather than exactly at its start:
$ sg_rep_zones --readonly --report=0 --start=0x100000 --num=4 /dev/sg4
LBAs are decimal unless prefixed with 0x or written with a trailing h. The default start is zero and the default number is zero, meaning all descriptors the command returns. Use --num when you are exploring, or collecting a bounded diagnostic sample.
--report filters the zones selected by condition. The documented values include 1 for empty, 2 for implicitly opened, 3 for explicitly opened, 4 for closed, 5 for full, 6 for read-only and 7 for offline zones. Values 0x10, 0x11 and 0x3f select the documented write-resource, non-sequential-resource and not-write-pointer cases. Use the numeric value only when you have a clear question in mind; --report=0 is the all-zones default.
5. Print write pointers only
For a quick check of write-pointer positions, add --wp. With no errors, the command prints one hexadecimal LBA per zone. Combine it with the same bounds used for a small report:
$ sg_rep_zones --readonly --start=0 --num=8 --wp /dev/sg4
This is a display mode, not a write operation. Do not confuse it with tools that reset a zone write pointer. If you need the descriptors as well, drop --wp and use the normal decoded report.
A common mistake is reading the number printed by --wp as a byte offset. It is an LBA shown in hexadecimal. Interpret it with the device's logical block size and zone geometry from your storage documentation.
6. Choose an output format deliberately
Use the normal decoded output for a human-readable inspection. Add --hex when you need the response in hexadecimal: one occurrence prints the whole response with leading addresses, two occurrences print each zone descriptor separately, and three occurrences print the whole response without leading addresses:
$ sg_rep_zones --readonly --num=2 --hex /dev/sg4
$ sg_rep_zones --readonly --num=2 --hex --hex /dev/sg4
Do not rely on a single --hex output as a stable machine-readable format unless you have pinned the utility version and tested the parser. The manpage defines the display levels, but later sg3-utils releases can add fields or modes.
--raw writes the SCSI response buffer as binary to standard output. Redirect it to a deliberately new file, never your terminal:
$ umask 077
$ sg_rep_zones --readonly --num=4 --raw /dev/sg4 > report-zones.bin
$ test -s report-zones.bin && echo 'binary response saved'
The redirection happens in the shell before the command even runs. If report-zones.bin already exists, > truncates it. Choose a new filename, or use a temporary file and rename it only after the command succeeds. If this example created a file you did not want, remove that specific file after checking its path: there is no undo for an overwritten capture.
7. Diagnose failures without changing the device
First repeat the smallest safe query with --readonly, the verified node and a bounded result:
$ sg_rep_zones --readonly --start=0 --num=1 /dev/sg4
$ printf 'status=%s\n' "$?"
If this fails, check that the target is a SCSI device that supports REPORT ZONES, that the SCSI generic node is present, and that your account can open it. --verbose adds debugging output and helps when reviewing a failure, but it does not repair the target:
$ sg_rep_zones --readonly --verbose --start=0 --num=1 /dev/sg4
Do not add --partial merely to make an error disappear. It sets the PARTIAL bit in the SCSI command and changes the report request semantics. Use it only when the target or your protocol-level investigation actually requires that bit.
Likewise, do not reach for sudo as a first response to an unexpected device. Elevated access may be needed for a correctly identified node, but it cannot make an unsupported REPORT ZONES command valid. Save the exact command, utility version, device identity and error text for the storage administrator or vendor.
Done means
- Versions recorded. The installed
sg_rep_zonesandsg3-utilsversions are noted. - Node matched to device. The SCSI generic node was matched to the intended device using inventory data.
- Report run read-only. The report ran with
--readonly, an explicit start LBA and a sensible descriptor limit while exploring. - Write pointers read with purpose. Write pointers were read with
--wponly when hexadecimal LBAs were actually useful. - Binary output kept clean. Any binary output went to a new capture file, never a terminal or an unverified existing path.
- Success confirmed, not assumed. A zero exit status and the target's actual response were checked; no failed query was treated as proof of a different device state.