Check SCSI Device Capacity Safely with sg_readcap
sg_readcap reads a SCSI device's block count and block size, the numbers behind its reported capacity. You will finish with a repeatable way to read them, check the calculated capacity, and decide when to request the extended READ CAPACITY(16) response. Allow about ten minutes. You need the sg3-utils package, a device path, and permission to open that device. The examples only ask the device for capacity data; they do not format, resize or write to it.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Confirm the installed command
Start with ordinary, read-only checks. They do not need elevated privileges:
$ command -v sg_readcap
/usr/bin/sg_readcap
$ dpkg-query -W -f='${Package} ${Version}\n' sg3-utils
sg3-utils 1.46-3ubuntu4
$ sg_readcap --version
Version string: 4.05 20200122
Version output can look inconsistent because the Debian package version, the manpage revision and the utility's own version string are separate pieces of information. On this installation the manpage is marked sg3_utils-1.45, the package manager reports 1.46-3ubuntu4, and the binary prints the version string shown above. Use the local help and manpage as the contract for this host:
$ sg_readcap --help
Usage: sg_readcap [--16] [--brief] [--help] [--hex] [--lba=LBA] [--long]
[--pmi] [--raw] [--readonly] [--verbose] [--version]
[--zbc] DEVICE
Checkpoint: you have identified the binary and recorded the version information before interpreting its output.
2. Identify the correct device
sg_readcap accepts one device. Prefer a stable path that you have already mapped to the intended disk, such as a device under /dev/disk/by-id/. A generic SCSI device such as /dev/sg0 may change after hardware discovery, so do not guess its identity.
Use your normal inventory tools to map the path. For example, if lsscsi is installed, its generic-device column can help:
$ lsscsi -g
[HOST:CHANNEL:TARGET:LUN] disk VENDOR MODEL ... /dev/sdX /dev/sgY
The row and names are host-specific. Replace /dev/disk/by-id/REPLACE_WITH_THE_DEVICE in the next commands with a path you have checked. Never use a partition path when you mean to inspect the whole device.
Opening a device can fail even for a read-only SCSI command. If you see Permission denied, first check ownership and groups:
$ ls -l /dev/sgY
$ id
Only if your system policy allows it, rerun the eventual capacity command with sudo. Elevated privileges are a workaround for device access, not a requirement for the SCSI operation itself.
3. Read the normal capacity report
The default sends READ CAPACITY(10). Add --readonly explicitly when you want the safety boundary visible in a script or review:
$ sg_readcap --readonly /dev/disk/by-id/REPLACE_WITH_THE_DEVICE
Read Capacity results:
Last logical block address: 0x1234567 (19088743)
Logical block length: 512 bytes
Hence:
Device capacity: 9763 MB, 9.76 GB, 0.00976 TB
The exact formatting and numbers depend on the device. The important detail is that the command reports the address of the last block, not a block count. SCSI blocks start at zero, so the number of blocks is the last logical block address plus one. Capacity is that block count multiplied by the logical block length. This is the common source of an off-by-one calculation.
If your device is too large for READ CAPACITY(10), a compliant device can return 0xffffffff. Without --hex, this utility then requests READ CAPACITY(16) and prints that response. A device that does not respond well to READ CAPACITY(16) is a known compatibility boundary, so keep the first run at the default unless you need the extended response.
Checkpoint: the command exits successfully and you have recorded both the last block address and the block length. Do not turn the displayed decimal or GB value into a partitioning decision until you have confirmed the device identity.
4. Request READ CAPACITY(16) deliberately
Use --long, or its equivalent --16, when you need the 16-byte command response. It removes the READ CAPACITY(10) address limit and can expose protection, logical-block-provisioning and physical-block information:
$ sg_readcap --long --readonly /dev/disk/by-id/REPLACE_WITH_THE_DEVICE
Read Capacity results:
Protection: prot_en=0, p_type=0, p_i_exponent=0
Logical block provisioning: lbpme=0, lbprz=0
Last logical block address: 0x123456789
Logical block length: 4096 bytes
Field names and values vary with the device and the installed utility. Do not treat a missing protection or provisioning field as proof that the underlying storage lacks those features; first establish which command response you requested.
Some devices have poor READ CAPACITY(16) implementations and can misbehave when sent that command. If the default command works, prefer it for a basic capacity check. If you need the extra fields, test --long against the actual device during a suitable maintenance window and watch the command's exit status.
5. Produce machine-friendly output
For a script that needs only the block count and block size, use --brief. It writes two hexadecimal values to standard output: the number of blocks first, then the size of each block:
$ sg_readcap --brief --readonly /dev/disk/by-id/REPLACE_WITH_THE_DEVICE
0x1234568 0x200
A failed operation writes 0x0 0x0, so a script must check the exit status as well as the values. Keep stderr separate if another program consumes stdout:
device='/dev/disk/by-id/REPLACE_WITH_THE_DEVICE'
if ! capacity=$(sg_readcap --brief --readonly "$device"); then
printf 'sg_readcap failed for %s\n' "$device" >&2
exit 1
fi
set -- $capacity
if [ "$1" = 0x0 ] && [ "$2" = 0x0 ]; then
printf 'capacity response was empty\n' >&2
exit 1
fi
printf 'blocks=%s block_bytes=%s\n' "$1" "$2"
The shell snippet intentionally does not convert the hexadecimal numbers or change the device. Use a language with checked integer arithmetic if you need to calculate byte totals, especially for large devices.
6. Inspect raw or diagnostic responses only when needed
--hex prints the READ CAPACITY response as ASCII hexadecimal, while --raw writes binary response data. These modes are useful when comparing a device response with a protocol trace or passing it to a tool that expects bytes. They are not suitable for casual terminal output:
$ sg_readcap --hex --readonly /dev/disk/by-id/REPLACE_WITH_THE_DEVICE
$ sg_readcap --raw --readonly /dev/disk/by-id/REPLACE_WITH_THE_DEVICE > response.bin
The second command creates a local file. Remove that file after reviewing it if it contains information you do not need to retain:
$ rm -- response.bin
This is the only state-changing example in the guide, and it changes only your local output file. Do not redirect --raw to a device or feed it into a write-capable utility.
Done means
- You confirmed the installed
sg_readcapbinary and version details. - You mapped the device path to the intended whole SCSI device.
- A read-only capacity check returned the last block address and block size.
- You accounted for the zero-based last-block address when calculating block count.
- You used READ CAPACITY(16) only when its additional range or fields were required.
- Any script checks both the exit status and the
--briefvalues.