SG_WRITE_LONG(8)

๐Ÿ“ฆ
version 1.49 ยท 2 versions
, in alpine 3.24, arch rolling, centos-stream 10, debian trixie, fedora 43, fedora 44, nixos 26.05, nixpkgs unstable, ubuntu questing, ubuntu resolute, ubuntu stonking

๐ŸŽ€ SG_WRITE_LONG(8) ๐ŸŽ€

sg3_utils manual, the cute edition ๐Ÿ’–

โœจ NAME โœจ

sg_write_long - send SCSI WRITE LONG command ๐Ÿ’…

๐Ÿฆ‹ SYNOPSIS ๐Ÿฆ‹

sg_write_long [--16] [--cor_dis] [--help] [--in=IF] [--lba=LBA]
[--pblock] [--verbose] [--version] [--wr_uncor] [--xfer_len=BTL] DEVICE

๐ŸŒธ DESCRIPTION ๐ŸŒธ

okay so bestie, sg_write_long sends the SCSI WRITE LONG command (10 or 16 byte version) to DEVICE ๐Ÿ’Œ The buffer it writes is either filled with 0xff bytes or read from the IF file. That buffer holds the logical data (like 512 bytes) and the ECC bytes, so it's literally the whole sector including the error-correction stuff ๐Ÿงš

This utility can be used to generate a MEDIUM ERROR at a specific logical block address, which is super useful for testing error handling ๐Ÿ™ˆ Before you do that, you can use the sg_dd utility to copy the original contents of that LBA somewhere safe. After the test, use sg_dd again to write the original contents back. An alternate strategy is to read the "long" contents of the LBA with the sg_read_long utility before testing, then restore it with this utility after testing ๐Ÿ“

โš ๏ธ Take care, bestie! If you're injecting recoverable errors (like flipping only one or a few bits so the ECC can fix the data), you need to watch the settings in the "read write error recovery" mode page ๐Ÿฅบ Specifically, if ARRE (for reads) and/or AWRE (for writes) are set, recovered errors will cause the LBA to get reassigned, and the old location gets added to the grown defect list (PLIST). That's not easily reversed and it uses up one of the finite spare sectors set aside for this purpose ๐Ÿ’€ If you're not sure, it's probably safest to clear the ARRE and AWRE bits. You can check and change these bits with the sdparm utility. For example: "sdparm -c AWRE,ARRE /dev/sda" will clear the bits until the disk is power cycled โœจ

In SBC-4 revision 7, all uses of SCSI WRITE LONG (10 and 16 byte) commands were made obsolete, except for the case where the WR_UNCOR bit is set ๐Ÿ˜ญ The SCSI READ LONG (10 and 16 byte) commands were made obsolete in that same revision too, so it's a whole era shift ๐ŸŒˆ

๐ŸŽ€ OPTIONS ๐ŸŽ€

Arguments to long options are mandatory for short options as well, no exceptions, periodt ๐Ÿ’…

  • -S, --16 โ€” sends a SCSI WRITE LONG (16) command to DEVICE. If you don't include this one, the default is a SCSI WRITE LONG (10) command, so you're good ๐Ÿ‘‘
  • -c, --cor_dis โ€” sets the correction disabled (aka COR_DIS) bit ๐Ÿซถ This stops a bunch of other mechanisms from kicking in, like automatic block reallocation, error recovery, and various informational exception conditions. Fair warning: this bit is relatively new in SBC-3 .
  • -h, --help โ€” outputs the usage message, then exits ๐Ÿงš
  • -i, --in=IF โ€” reads binary data from the file named IF and uses it for the SCSI WRITE LONG command ๐Ÿ“‚ If IF is -, stdin gets read instead. If you don't give this option, 0xff bytes are used as the fill ๐ŸŒธ
  • -l, --lba=LBA โ€” LBA is the logical block address of the sector you want to overwrite ๐ŸŽฏ It defaults to LBA 0, which is a dangerous block to overwrite on a disk that's in use ๐Ÿ˜ฑ LBA is assumed to be decimal unless you prefix it with 0x or add a trailing h. If your LBA is bigger than 32 bits can hold, use the --16 option instead.
  • -p, --pblock โ€” sets the physical block (aka PBLOCK) bit ๐Ÿ’œ This tells DEVICE to use the given data (unless --wr_uncor is also given) to write to the physical block specified by LBA. By default it writes to the logical block that matches the given LBA. Also relatively new in SBC-3 .
  • -v, --verbose โ€” cranks up the verbosity, so you get more debug messages ๐Ÿ”
  • -V, --version โ€” outputs the version string, then exits ๐Ÿท๏ธ
  • -w, --wr_uncor โ€” sets the "write uncorrected" (aka WR_UNCOR) bit โญ This tells DEVICE to flag the given LBA (or the physical block containing it, if --pblock is also given) as having an unrecoverable error attached to it ๐Ÿฅ€ Note: no data gets transferred to DEVICE, just the command (the cdb). Without this option, the default is to use your provided data (or 0xff bytes, --xfer_len=BTL in length) and write it to DEVICE. This bit is also relatively new in SBC-3 .
  • -x, --xfer_len=BTL โ€” BTL is the byte transfer length, defaulting to 520 ๐ŸŽ€ If the value you give (or the default) doesn't match the "long" block size of the device, nothing gets written to DEVICE ๐Ÿ™…โ€โ™€๏ธ Instead, the right xfer_len value can be figured out from the error response that gets printed to stderr.

๐Ÿ“ NOTES ๐Ÿ“

Various numeric arguments (like LBA) can include multiplicative suffixes or be given in hexadecimal. Check out the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page for the deets ๐Ÿค“

The 10 byte SCSI WRITE LONG command limits the logical block address to a 32 bit quantity. For larger LBAs, use the --16 option for the SCSI WRITE LONG (16) command ๐Ÿฆ„

๐Ÿงš EXAMPLES ๐Ÿงš

This section walks through setting up a block with corrupted data, checking the error condition, and then restoring useful contents to that sector. It's giving full science experiment vibes ๐Ÿงช

First, if the data in a sector is important, save it with the sg_read_long utility:

sg_read_long --lba=0x1234 --out=0x1234_1.img -x BTL /dev/sda

You might need to run this a few times to figure out the correct value for BTL ๐Ÿฅน Next, use this utility to "corrupt" that sector. You can do that with:

sg_write_long --lba=0x1234 -x BTL /dev/sda

This writes a sector (and its ECC data) full of 0xff bytes. Some disks might reject this (at least one of the author's does ๐Ÿ’€). Another approach is to copy the 0x1234_1.img file (to 0x1234_2.img in this example), change some values with a hex editor, and then write the changed image with:

sg_write_long --lba=0x1234 --in=0x1234_2.img -x BTL /dev/sda

Yet another approach, if it's supported, is to use the --wr_uncor option:

sg_write_long --lba=0x1234 --wr_uncor /dev/sda

Next, we use the sg_dd utility to check that the sector is corrupted. Here's an example:

sg_dd if=/dev/sda blk_sgio=1 skip=0x1234 of=. bs=512 count=1 verbose=4

Notice that the blk_sgio=1 option is given. This makes sure that only that sector gets read and the error is fully reported ๐Ÿ‘€ The blk_sgio=1 option makes sg_dd use the SG_IO ioctl instead of the block subsystem.

Finally, we should restore sector 0x1234 to a non-corrupted state ๐Ÿซถ A sector full of zeros can be written with:

sg_dd if=/dev/zero of=/dev/sda blk_sgio=1 seek=0x1234 bs=512 count=1

This results in a sector (block) with 512 bytes of 0x0 and no MEDIUM ERROR, since the ECC and associated data get regenerated and are thus well formed โœจ The blk_sgio=1 option is even more important in this case, because it may stop the block subsystem from doing a read before the write (since that read will most likely fail) ๐Ÿ˜ฌ Another approach is to write back the original contents:

sg_write_long --lba=0x1234 --in=0x1234_1.img -x BTL /dev/sda

๐ŸŒท EXIT STATUS ๐ŸŒท

The exit status of sg_write_long is 0 when it's successful ๐ŸŽ‰ Otherwise, check out the sg3_utils(8) man page.

๐Ÿ’œ AUTHORS ๐Ÿ’œ

Written by Saeed Bishara. Further work by Douglas Gilbert ๐Ÿซถ

๐Ÿž REPORTING BUGS ๐Ÿž

Report bugs to <dgilbert at interlog dot com> ๐Ÿ“ฎ

Copyright ยฉ 2004-2016 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 ๐Ÿ“œ

๐Ÿ”— SEE ALSO ๐Ÿ”—

sg_read_long, sg_dd (both in sg3_utils), sdparm(sdparm) ๐Ÿ’•


Thanks for hanging with me, bestie! ๐ŸŒˆ That's the whole tea from sg3_utils 1.42, January 2016 โœจ๐Ÿ’…

๐Ÿ“ฆ where this page comes from