SG_PERSIST(8)

πŸ¦‹ sg_persist(8) β€” the sg3_utils icon we all needed ✨

okay bestie, listen up πŸ’– this is sg_persist from sg3_utils, and she is that girl β€” the SCSI PERSISTENT RESERVE command wrapper who handles all the registration and reservation drama so you don't have to. grab a snack, this one's a long read πŸ“


🌸 NAME 🌸

sg_persist β€” use the SCSI PERSISTENT RESERVE command to access registrations and reservations, no cap πŸ’…


✨ SYNOPSIS ✨

sg_persist [OPTIONS] DEVICE

sg_persist [OPTIONS] --device=DEVICE

sg_persist --help | --version

like, that's it. that's the whole vibe 😌


πŸ’œ DESCRIPTION πŸ’œ

okay so here's the tea πŸ«– this utility lets you query and change Persistent reservations and registrations. Querying happens through sub-commands (SPC-4 calls these "service actions", iykyk) of the SCSI PERSISTENT RESERVE IN (PRIN) command. Changing them happens through sub-commands of the SCSI PERSISTENT RESERVE OUT (PROUT) command. two commands, one little utility, iconic behaviour fr fr 🌈

so getting a persistent reservation is a two stage situation, lowkey like getting into a club πŸ‘‘ first, an application (fancy standard-speak: an I_T nexus) has to register a reservation key. if that key gets accepted β€” and it should, unless some other I_T nexus already registered that same key πŸ™ˆ β€” then the application can go ahead and try to reserve the device. the reserve operation has to specify both the reservation key and a "type" (peep the --prout-type=TYPE option for that one).

ngl, just querying the state of persistent reservations and registrations is relatively safe β€” you're not out here breaking anything πŸ’€ with no options at all, this utility defaults to the READ KEYS sub-command of the PRIN command. the other PRIN sub-commands are READ RESERVATION, REPORT CAPABILITIES and READ FULL STATUS. cute little family πŸŽ€

but before you go changing Persistent reservations and registrations, bestie, you really need to know what you're doing ⚠️ the relevant sections of the SCSI Primary Commands document (that's SPC-5 ANSI INCITS 502-2020 babes) are section 8.14 (titled "Reservations"), section 9.16 (for the PRIN command) and section 9.17 (for the PROUT command). and to safeguard against accidental use β€” because we all have clumsy thumbs 😭 β€” the --out option must be given whenever you use a PROUT sub-command (like --register). safety first, always πŸ’…

the older SCSI RESERVE and RELEASE commands (both the 6 and 10 byte variants) are not supported by this utility, sorry not sorry. in SPC-3, RESERVE and RELEASE are deprecated β€” replaced by Persistent Reservations ✨. RESERVE and RELEASE have been fully removed from SPC-4, and Annex B is provided showing how to convert over to persistent reservation commands. if you need support for the SCSI RESERVE and RELEASE commands, go check out a utility called scsires πŸ¦‹

DEVICE needs to be specified for every single variant of this utility apart from --help and --version. you can hand over the DEVICE either as an argument (typically β€” but not necessarily! β€” after the options) or through the --device=DEVICE option. your call, main character πŸ’β€β™€οΈ

one lil terminology moment 🧚 SPC-4 doesn't actually use the term "sub-command". it uses "service action" for that, and also for part of a field's name in the parameter block that goes with the PROUT command (specifically "service action reservation key"). to lessen the potential confusion, the term "sub-command" was introduced here. so when you see "sub-command", just know it's the same vibe πŸ’œ


πŸŽ€ OPTIONS πŸŽ€

arguments to long options are mandatory for short options as well, periodt. the following options are sorted in alphabetical order, based on their long option name 😌

  • -l, --alloc-length=LEN β€” specify the allocation length of the PRIN command. LEN is a hex value. by default this is set to the size of the data-in buffer (8192). this parameter is useful for verifying that the response to PRIN commands with various allocation lengths follows section 4.3.5.6 of SPC-4 revision 18. valid LEN values are 0–8192 βœ…
  • -C, --clear β€” Clear is a sub-command of the PROUT command πŸ’₯ it releases the persistent reservation (if there even is one) and clears all registrations from the device. you're required to supply a reservation key that's registered for this I_T_L nexus (identified via --param-rk=RK). this option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to CLEAR [0x3].
  • -d, --device=DEVICE β€” the DEVICE to send SCSI commands to. you can provide it via this option or as a freestanding argument. like, these two are literally equivalent: sg_persist --device=/dev/sg2 and sg_persist /dev/sg2 🫢
  • -h, --help β€” output a usage message showing the main options. use it twice (like '-hh') to get the other options and more help 😌
  • -H, --hex β€” the response to a valid PRIN sub-command gets output in hexadecimal. by default (i.e. without this option), if the PRIN sub-command is recognised, the response is decoded as per SPC-4. you can use this more than once for more hex and less text πŸ”₯
  • -i, --in β€” specify that a SCSI PERSISTENT RESERVE IN command is required. this is the default πŸ’…
  • -m, --maxlen=LEN β€” LEN is used as the ALLOCATION LENGTH field of the PRIN command. LEN is a decimal value by default. to give a hex value use a '0x' or '0X' prefix, or a 'h' (or 'H') suffix. it can also take multipliers β€” see the --maxlen=LEN option in the sg3_utils manual page for that 🧚 this option is the same as --alloc-length=LEN apart from how LEN is represented. it defaults to decimal while --alloc-length=LEN only takes hex. same energy, different outfit πŸ’β€β™€οΈ
  • -n, --no-inquiry β€” the default action is to do a standard SCSI INQUIRY command and output the make, product and revision strings plus the peripheral device type, before executing a PRIN or PROUT command. with this option, that INQUIRY command is skipped πŸ™ˆ
  • -o, --out β€” specify that a SCSI PERSISTENT RESERVE OUT command is required. (remember, you need this for any PROUT sub-command! 🚨)
  • -Y, --param-alltgpt β€” set the 'all target ports' (ALL_TG_PT) flag in the parameter block of the PROUT command. only relevant for the 'register' and 'register and ignore existing key' sub-commands 🎯
  • -Z, --param-aptpl β€” set the 'activate persist through power loss' (APTPL) flag in the parameter block of the PROUT command. relevant for the 'register', 'register and ignore existing key' and 'register and move' sub-commands ⚑
  • -K, --param-rk=RK β€” specify the reservation key found in the parameter block of the PROUT command. RK is assumed to be hex (up to 8 bytes long). default value is 0. most PROUT sub-commands need this one πŸ’–
  • -S, --param-sark=SARK β€” specify the service action reservation key found in the parameter block of the PROUT command. SARK is assumed to be hex (up to 8 bytes long). default value is 0. some PROUT sub-commands need this one 🌸
  • -P, --preempt β€” Preempt is a sub-command of the PROUT command πŸ‘‘ it preempts the existing persistent reservation (identified by --param-sark=SARK) with the registration key that's registered for this I_T_L nexus (identified by --param-rk=RK). if a new reservation gets established as a result of the preemption, then the supplied --prout-type=TYPE is used as the type for that new reservation. this option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to PREEMPT [0x4].
  • -A, --preempt-abort β€” Preempt and Abort is a sub-command of the PROUT command πŸ’€ it preempts the existing persistent reservation (identified by --param-sark=SARK) with the registration key that's registered for this I_T_L nexus (identified by --param-rk=RK). if a new reservation gets established as a result of the preemption, then the supplied --prout-type=TYPE is used as the type for that new reservation. ACA and other pending tasks are aborted. this option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to PREEMPT AND ABORT [0x5].
  • -T, --prout-type=TYPE β€” specify the PROUT command's 'type' argument. required by the 'register-move', 'reserve', 'release' and 'preempt (and abort)' sub-commands. valid TYPE values are: 1 β†’ write exclusive, 3 β†’ exclusive access, 5 β†’ write exclusive - registrants only, 6 β†’ exclusive access - registrants only, 7 β†’ write exclusive - all registrants, 8 β†’ exclusive access - all registrants. default value is 0 (which is an invalid type, fyi πŸ™ƒ). each "persistent reservation type" is explained in more detail in a subsection of that name in the read reservation section of the PRIN command (section 6.15.3.3 of SPC-4 revision 37) πŸ“š
  • -s, --read-full-status β€” Read Full Status is a sub-command of the PRIN command. for each registration with the given SCSI device, it lists the reservation key and associated information. TransportIDs, if supplied in the response, are decoded ✨ this option issues the PERSISTENT RESERVE IN SCSI command with its service action field set to READ FULL STATUS [0x3].
  • -k, --read-keys β€” Read Keys is a sub-command of the PRIN command. it lists all the reservation keys registered (i.e. the registrations) with the given SCSI device. this is the default sub-command for the SCSI PRIN command πŸ‘‘ this option issues the PERSISTENT RESERVE IN SCSI command with its service action field set to READ KEYS [0x0].
  • -y, --readonly β€” open DEVICE read-only. may be useful with PRIN commands if there are unwanted side effects with the default read-write open 😬 when given twice, it's interpreted as forcing a read-write open, which overrides the SG_PERSIST_IN_RDONLY environment variable if present. see the ENVIRONMENT VARIABLES section for more πŸ’œ
  • -r, --read-reservation β€” Read Reservation is a sub-command of the PRIN command. it lists info about the current holder of the reservation on the DEVICE. if there's no current reservation, that gets noted πŸ“ info about the current holder includes its reservation key, scope and type. this option issues the PERSISTENT RESERVE IN SCSI command with its service action field set to READ RESERVATION [0x1].
  • -s, --read-status β€” same as --read-full-status. that's it, that's the whole bullet πŸŽ€
  • -G, --register β€” Register is a sub-command of the PROUT command, and she has 3 different actions depending on the associated parameters, multi-talented queen πŸ‘‘:
    • a) add a new registration with '--param-rk=0' and '--param-sark=<new_rk>';
    • b) change an existing registration with '--param-rk=<old_rk>' and '--param-sark=<new_rk>'; or
    • c) delete an existing registration with '--param-rk=<old_rk>' and '--param-sark=0'.

this option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to REGISTER [0x0] πŸ¦‹

  • -I, --register-ignore β€” "Register and Ignore Existing Key" bestie, and it's a sub-command of the PROUT command πŸ’… It's basically --register except when you're changing a reservation key the old key is not specified. You should also hand it --param-sark=<new_rk>. This one issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to REGISTER AND IGNORE EXISTING KEY [0x6].
  • -M, --register-move β€” register (another initiator) and move (the reservation held by the current initiator to that other initiator), and yes it's a sub-command of the PROUT command. It needs the transportID of that other initiator. [The standard uses the term I_T nexus but the point to stress is that there are two initiators (the one sending this command and another one) but only one logical unit.] The --prout-type=TYPE and --param-rk=RK options need to match that of the existing reservation, while the --param-sark=SARK option specifies the reservation key of the new (i.e. destination) registration. This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to REGISTER AND MOVE [0x7].
  • -Q, --relative-target-port=RTPI β€” the relative target port identifier that the reservation is to be moved to by the PROUT 'register and move' sub-command 🎯 RTPI is assumed to be hex in the range 0 to ffff inclusive. Defaults to 0.
  • -L, --release β€” Release is a sub-command of the PROUT command, and it literally just releases the current persistent reservation 🫢 The --prout-type=TYPE and --param-rk=RK options, matching the reservation, must also be specified. This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to RELEASE [0x2].
  • -z, --replace-lost β€” Replace Lost Reservation is a sub-command of the PROUT command. It "begins a recovery process for the lost persistent reservation that is managed by application clients". It also stops the device server terminating commands due to a lost persistent reservation. The options should be --param-rk=0 (or not given), --param-sark=<new_rk> and --prout-type=TYPE. This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to REPLACE LOST RESERVATION [0x8].
  • -c, --report-capabilities β€” Report Capabilities is a sub-command of the PRIN command, and it lists the info about the aspects of persistent reservations that the DEVICE supports πŸ‘‘ This option issues the PERSISTENT RESERVE IN SCSI command with its service action field set to REPORT CAPABILITIES [0x2].
  • -R, --reserve β€” Reserve is a sub-command of the PROUT command. It creates a new persistent reservation (if permitted, no cap). The --prout-type=TYPE and --param-rk=RK options must also be specified. This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to RESERVE [0x1].
  • -X, --transport-id=TIDS β€” okay so the TIDS argument is giving flexible, it can take one of several forms πŸ’« It can be a comma (or a single space) separated list of ASCII hex bytes representing a single TransportID as defined in SPC-5. They are usually 24 bytes long apart from in iSCSI. The TIDS argument may be a transport specific form ( e.g. "sas,5000c50005b32001" is clearer than an equivalent to the hex byte form: "6,0,0,0,5,0,c5,0,5,b3,20,1"). The TIDS argument may be "-" in which case one or more TransportIDs can be read from stdin. The TIDS argument may be of the form "file=<name>" in which case one or more TransportIDs can be read from a file called <name>. See the "TRANSPORT IDs" section below for more info πŸ“–
  • -U, --unreg β€” optional when the PROUT register and move sub-command is invoked. If given it will unregister the current initiator (I_T nexus) after the other initiator has been registered and the reservation moved to it. When not given, the initiator (I_T nexus) that sent the PROUT command remains registered. This option issues the PERSISTENT RESERVE OUT SCSI command with its service action field set to REGISTER AND MOVE [0x7]. The UNREG bit is set in the associated parameter list.
  • -v, --verbose β€” print out the cdb of issued commands prior to execution. If used twice it prints out the parameter block associated with the PROUT command prior to its execution as well. If used thrice it decodes the given transportID(s) as well. To see the response to a PRIN command in low level form use the --hex option πŸ™ˆ
  • -V, --version β€” print out version string. Ignore all other parameters. Periodt.
  • -? β€” output usage message. Ignore all other parameters.

πŸ¦‹ TRANSPORT IDs πŸ¦‹

TransportIDs are used in persistent reservations to identify initiators, iconic behaviour honestly. The format of a TransportID differs depending on the type of transport being used. Their format is described in SPC-4 (in draft revision 37 see section 7.6.4) ✨

A TransportID is required for the PROUT 'register and move' sub-command, and the PROUT 'register' sub-command can have zero, one or more TransportIDs πŸ‘―

When the --transport-id=TIDS option is given then the TIDS argument may be a comma (or single space) separated list of ASCII hex bytes that represent a single TransportID as defined in SPC-4. Alternatively the TIDS argument may be a transport specific string starting with either "fcp,", "spi,", "sbp,", "srp,", "iqn", "sas," or "sop,". The "iqn" form is an iSCSI qualified name. Apart from "iqn" the other transport specific leadin string may be given in upper case (e.g. "FCP,") πŸ’…

The "fcp," form should be followed by 16 ASCII hex digits that represent an initiator's N_PORT_NAME (e.g. "fcp,10000000C9F3A571"). The "spi," form should be followed by "<scsi_address>,<relative_target_port_identifier>" (both decimal numbers). The "sbp," form should be followed by 16 ASCII hex digits that represent an initiator's EUI-64 name. The "srp," form should be followed by 32 ASCII hex digits that represent an initiator port identifier. The "sas," form should be followed by 16 ASCII hex digits that represent an initiator's port SAS address (e.g. "sas,5000c50005b32001"). The "sop," form takes a hex number that represents a routing id 🌈

There are two iSCSI qualified name forms, yes two πŸ’€ The shorter form contains the iSCSI name of the initiator port (e.g. "iqn.5886.com.acme.diskarrays-sn-a8675309"). The longer form adds the initiator session id (ISID in hex) separated by ",i,0x". For example "iqn.5886.com.acme.diskarrays-sn-a8675309,i,0x1234567890ab". On the command line, to stop punctuation in an iSCSI name being (mis)-interpreted by the shell, putting the option argument containing the iSCSI name in double quotes is advised. iSCSI names are encoded in UTF-8 so if non (7 bit) ASCII characters appear in the iSCSI name on the command line, there will be difficulties if they are not encoded in UTF-8. The locale can be changed temporarily by prefixing the command line invocation of sg_persist with "LANG=en_US.utf-8" for example 🌸

Alternatively the TIDS argument may specify a file (or pipe) from which one or more TransportIDs may be read. If the TIDS argument is "-" then stdin (standard input) is read. If the TIDS argument is of the form "file=<name>" then a file called <name> is read. A valid SPC-4 TransportID is built from the transport specific string outlined in the previous paragraphs. The parsing of the data read is relatively simple. Empty lines are ignored. Everything from and including a "#" on a line is ignored. Leading spaces and tabs are ignored. There can be one transportID per line. The transportID can either be a comma, space or tab separated list of ASCII hex bytes that represent a TransportID as defined in SPC-4. Padding with zero bytes to a minimum length of 24 bytes is performed if necessary. The transportID may also be transport specific string type discussed above πŸŽ€

Careful bestie β€” in SPC-3 the SPEC_I_PT bit set to one and TransportIDs were allowed for the PROUT register and ignore existing key sub-command. In SPC-4 that is disallowed, yielding a CHECK CONDITION status with an ILLEGAL REQUEST sense key and an additional sense code set to INVALID FIELD IN PARAMETER LIST 😭

🌟 NOTES 🌟

In the 2.4 series of Linux kernels the DEVICE must be a SCSI generic (sg) device. In the 2.6 series any SCSI device name (e.g. /dev/sdc, /dev/st1m or /dev/sg3) can be specified. For example "sg_persist --read-keys /dev/sdb" will work in the 2.6 series kernels 🫢

The only scope for PROUT commands supported in the current draft of SPC-4 is "LU_SCOPE". Hence there seems to be no point in offering an option to set scope to another value, so they didn't πŸ’…

Most errors with the PROUT sub-commands (e.g. missing or mismatched --prout-type=TYPE) will result in a RESERVATION CONFLICT status. This can be a bit confusing when you know there is only one (active) initiator: the "conflict" is with the SPC standard, not another initiator 😭 iykyk.

Some recent disks accept some PRIN and PROUT sub-commands when the media is stopped. One exception was setting the APTPL flag (with the --param-aptpl option) during a key register operation β€” it complained if the disk one stopped. The error indicated it wanted the disk spun up and when that happened, the registration was successful ⭐

🌈 EXAMPLES 🌈

Okay bestie, these examples all use Linux device names πŸ’–. If you're on some other supported Operating System and need to know what to call your device, go peek at the sg3_utils(8) man page β€” it's got you.

Because of all the various option defaults doing their thing, the simplest example just runs the 'read keys' sub-command of the PRIN command:

sg_persist /dev/sdb

And that, my friend, is literally the exact same as this long-winded icon:

sg_persist --in --read-keys --device=/dev/sdb

Same energy, fewer words. Slay. ✨


Wanna read the current reservation? You can use either the whole --read-reservation form or the short little -r:

sg_persist -r /dev/sdb

To register a brand new reservation key 0x123abc, this is the vibe:

sg_persist --out --register --param-sark=123abc /dev/sdb

So assuming that registration above actually went through πŸ‘‘, to then reserve the DEVICE (with type 'write exclusive') you'd do:

sg_persist --out --reserve --param-rk=123abc
           --prout-type=1 /dev/sdb

And to release that reservation, here's the move β€” heads up though, the --param-rk and --prout-type arguments must match the ones from the reservation you made:

sg_persist --out --release --param-rk=123abc
           --prout-type=1 /dev/sdb

Finally, to unregister a reservation key (and not touch the other registrations β€” that's what --clear would go and do), the command is a little surprising ngl πŸ™ˆ:

sg_persist --out --register --param-rk=123abc /dev/sdb

Fr fr, go have a close look at the difference between the register and unregister examples up there. It's giving subtle. πŸ’…


There's also an example file that's already suitably formatted for passing transportIDs via a --transport-id=file=transport_ids.txt option β€” you'll find it in the examples sub-directory of the sg3_utils package. There's a cute simple test script called sg_persist_tst.sh hanging out in that same directory too. πŸŽ€

The whole sequence of commands above was tested successfully on a Seagate Savvio 10K.3 disk and a 1200 SSD, both of which have SAS interfaces. So yes, it works, bestie. 😌


πŸ’« EXIT STATUS πŸ’«

The exit status of sg_persist is 0 when it's successful 🌸. Otherwise, go see the sg3_utils(8) man page for what's up.


πŸ¦‹ ENVIRONMENT VARIABLES πŸ¦‹

Right now there's exactly one recognised environment variable, and it's this one:

  • SG_PERSIST_IN_RDONLY β€” if it's present, and only if a PRIN command has been selected, then the given DEVICE gets opened read-only (in Unix that means with the O_RDONLY flag, iykyk). Also check out the --readonly option.

πŸŽ€ AUTHOR πŸŽ€

Written by Douglas Gilbert πŸ’œ


⭐ REPORTING BUGS ⭐

Report bugs to <dgilbert at interlog dot com>.


Copyright Β© 2004-2023 Douglas Gilbert

This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Like, none. Zero. Don't come for them. 😭


🌈 SEE ALSO 🌈

  • sg3_utils(sg3_utils)
  • scsires(internet)

That's the whole page, bestie β€” no cap, you made it to the end 🫢. This little masterpiece is from sg3_utils-1.48, dated March 2023, and it's filed under SG_PERSIST(8). Go forth and persist (respectfully). πŸ’…βœ¨πŸ“

πŸ“¦ where this page comes from