Inventory and Decode SCSI LUNs with sg_luns

sg_luns is your read-only way to list the logical units visible through a SCSI device. It also asks for well-known LUNs, decodes T10 LUN values, and translates them to Linux integers. The installed command is from sg3-utils 1.46-3ubuntu4. The local manpage identifies its interface as sg3_utils 1.45, so output details can differ on newer builds.

Allow about fifteen minutes. You need the sg3-utils package and a SCSI generic device such as /dev/sg1. You must have access to the target, and the target must support REPORT LUNS. The examples that use --test are safe on any machine because they decode a value and do not open a device. Device mode sends a SCSI command, so use it during a suitable maintenance window if the target is sensitive.

1. Check the installed command

Confirm the package and binary before relying on option details. These are ordinary read-only commands and do not need elevated privileges:

$ dpkg-query -W -f='${Package} ${Version}\n' sg3-utils
sg3-utils 1.46-3ubuntu4
$ sg_luns --version
version: 1.45 20200708

The package version and utility version are not the same string here. Record both when comparing output between hosts. Check the local option spelling if a distribution has backported changes:

$ sg_luns --help

Checkpoint: You have a working binary and know which version produced your notes.

2. Decode a LUN without touching hardware

Use test mode when you already have a hexadecimal T10 LUN and only need to understand it. This command ignores the device argument because it is not sending REPORT LUNS:

$ sg_luns --test=0002000000000000
Decoded LUN:
  Peripheral device addressing: lun=2

The value can be prefixed with 0x, grouped with hyphens, or quoted when spaces separate bytes. A shorter hexadecimal value is padded to the right to make a 64-bit LUN. Ask for component fields in hexadecimal with --hex:

$ sg_luns --test=0x023a004b --hex
Decoded LUN:
  Peripheral device addressing: bus_id=0x02, target=0x3a
  >>Second level addressing:
    Peripheral device addressing: lun=0x4b

Do not confuse the option with a request to query a device. --test is a decoder and is the best first step when investigating a value copied from logs.

3. Translate between T10 and Linux LUN forms

Linux uses a word-flipped integer representation for some LUN work. Prefix a decimal Linux value with L to convert it to T10 format:

$ sg_luns --test=L49409
64 bit LUN in T10 preferred (hex) format:  c1 01 00 00 00 00 00 00
Decoded LUN:
  REPORT LUNS well known logical unit

For the reverse conversion, put a trailing L on the hexadecimal value:

$ sg_luns --test=c101L
Linux 'word flipped' integer LUN representation: 49409
Decoded LUN:
  REPORT LUNS well known logical unit

The letter L has meaning only in this test-mode syntax. It is not a general shell option and it does not identify a Linux block device.

4. Query the target's ordinary LUN inventory

Find the correct SCSI generic node first. On Linux, lsscsi -g can show the generic device beside each SCSI logical unit:

$ lsscsi -g
[6:0:0:1]    disk    Linux    scsi_debug       0004  /dev/sdb   /dev/sg1

Use the generic node that represents the target you intend to inspect. Device mode opens it read-write by default, although REPORT LUNS is an inventory command. Add --readonly to request a read-only open:

$ sg_luns --readonly --quiet /dev/sg1
0001000000000000
0002000000000000

--quiet removes the explanatory header and prints one ASCII-hex LUN per line, which is easier to feed into a review script. Without it, expect a report length and a selected-report header before the values. A successful command exits with status 0.

Safety boundary: Replace /dev/sg1 only with the verified device node. Do not point this command at a storage device selected by guesswork, and do not use --raw in a terminal: it writes binary response data to standard output.

5. Select the report you actually need

The default selection is 0, which reports LUNs apart from well-known logical units. Use selection 1 to ask only for well-known units:

$ sg_luns --readonly --quiet --select=1 /dev/sg1
c101000000000000

Use selection 2 for all LUNs visible to the current I_T nexus:

$ sg_luns --readonly --quiet --select=2 --decode --linux /dev/sg1
0001000000000000    [1]
        Peripheral device addressing: lun=1
0002000000000000    [2]
        Peripheral device addressing: lun=2
c101000000000000    [49409]
        REPORT LUNS well known logical unit

The exact list is target-specific. Selection values 0x10, 0x11 and 0x12 have administrative meanings and device restrictions documented by the manpage. Do not try them merely to make a missing LUN appear: for 0x10 and 0x11 the device must be LUN 0 or the REPORT LUNS well-known LUN, and 0x12 requires an administrative LUN.

6. Handle failures without changing storage state

A missing or unsuitable generic node, permissions, an unsupported command, and an invalid selection can all produce a non-zero exit status. Capture it immediately instead of trusting partial output:

$ sg_luns --readonly --quiet /dev/sg1
$ status=$?
$ printf 'sg_luns exit status: %s\n' "$status"
sg_luns exit status: 0

If access is denied, check the node and its group membership first. Use sudo only when your host's device policy requires it:

$ ls -l /dev/sg1
$ sudo sg_luns --readonly --quiet /dev/sg1

Elevated privileges do not repair a wrong node or an unsupported target. If the response is truncated, increase --maxlen, whose default is 8192 bytes and maximum is 1048576:

$ sg_luns --readonly --quiet --maxlen=65536 /dev/sg1

Use --verbose for diagnostics. Treat a report as a snapshot: another administrator or a fabric change can alter the visible inventory after the command returns.

Done means