SG_READ(8)

πŸ“¦
version 1.49 Β· 3 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_READ(8) πŸŽ€

Okay bestie, welcome to sg_read, the manual page for SG_READ(8) from SG3_UTILS πŸ’– Let's get into it ✨

✨ NAME ✨

sg_read - read multiple blocks of data, optionally with SCSI READ commands πŸ¦‹

✨ SYNOPSIS ✨

sg_read [blk_sgio=0|1] [bpt=BPT] [bs=BS] [cdbsz=6|10|12|16] count=COUNT
[dio=0|1] [dpo=0|1] [fua=0|1] if=IFILE [mmap=0|1] [no_dxfer=0|1]
[odir=0|1] [skip=SKIP] [time=TI] [verbose=VERB] [--help] [--version]

✨ DESCRIPTION ✨

Okay so sg_read reads data from a Linux SCSI generic (sg) device, a block device, or a normal file. Every read command goes to the same offset or logical block address (lba), which is seriously iconic for testing or timing disk caching πŸ”₯ It can also show you SCSI (or some other) transport throughput and/or SCSI command overhead. Main character energy, literally πŸ’…

When COUNT is positive, up to BPT blocks get read at a time until COUNT is used up. Every read starts at the same lba, which is the beginning of the file or device unless you pass SKIP 🌸

Now the spicy part 🌢️ COUNT can go negative when IFILE is an sg device or a block device with blk_sgio=1 set. You can also give bpt=0 instead. In those cases you get |COUNT| "zero block" SCSI READ commands. "Zero block" means "do nothing" for SCSI READ 10, 12 and 16 byte commands (but NOT the 6 byte one, so don't get it twisted πŸ™ˆ). In practice these have super low latency, which makes them a lowkey perfect way to measure SCSI command overhead ✨

πŸ’€ Heads up bestie: this is a very old utility. It uses 32 bit integers for disk LBAs and the count, so it can't address beyond 2 Terabytes on a disk with logical blocks that are 512 bytes long. If you need more, the alternatives are the sg_dd and ddpt utilities 🫢

✨ OPTIONS ✨

  • blk_sgio=0 | 1 β€” By default this utility uses the Unix read() command when IFILE is a block device. In lk 2.6 a lot of block devices can handle SCSI commands sent through the SG_IO ioctl, so when you set this option, the SG_IO ioctl sends SCSI READ commands to IFILE if it's a block device πŸŽ€
  • bpt=BPT β€” BPT is the max number of blocks each read operation fetches. If the leftover COUNT is less than BPT, you get fewer blocks. The default BPT is 128. Each read still starts at the same lba (set by skip=SKIP, or 0). If you do bpt=0, then COUNT is treated as the number of zero block SCSI READ commands to issue 🧚
  • bs=BS β€” BS is the size (in bytes) of each block read. This has to match the block size of the physical device (defaults to 512) if SCSI commands are going to IFILE πŸ“
  • cdbsz=6 | 10 | 12 | 16 β€” the size of the SCSI READ commands sent to sg device names, or to block devices if blk_sgio=1 is given. The default is 10 byte SCSI READ cdbs πŸ’œ
  • count=COUNT β€” when COUNT is positive, read that many blocks, usually with several read operations. When COUNT is negative, you get |COUNT| SCSI READ commands asking for zero blocks to be transferred. This one is mandatory, no skipping it 😭
  • dio=0 | 1 β€” default is 0, which picks indirect IO. A value of 1 tries direct IO. If that's not available, it falls back to indirect IO and tells you about it when it's done. This option only works if IFILE is an sg device. If you pick direct IO and /sys/module/sg/parameters/allow_dio has the value 0, you get a warning and indirect IO happens anyway ⚠️
  • dpo=0 | 1 β€” when set, the disable page out (DPO) bit goes into SCSI READ commands. Otherwise the DPO bit is cleared, which is the default πŸ“
  • fua=0 | 1 β€” when set, the force unit access (FUA) bit goes into SCSI READ commands. Otherwise the FUA bit is cleared, which is the default 🌈
  • if=IFILE β€” read from this IFILE. This argument is mandatory. If IFILE is a normal file, it has to be seekable (if COUNT > BPT or skip=SKIP is given). So no stdin, and passing - as the IFILE argument gets reported as an error πŸ™…β€β™€οΈ
  • mmap=0 | 1 β€” default is 0, which picks indirect IO. A value of 1 does memory mapped IO. Picking both dio and mmap is an error. This option only works if IFILE is an sg device πŸ¦‹
  • no_dxfer=0 | 1 β€” when set, DMA transfers from the device go into kernel buffers and stop there (no second copy into user space). The default is 0, where transfers go into user space. When neither mmap nor dio is set, data gets copied through kernel buffers (a double copy). This is mainly for testing πŸ§ͺ
  • odir=0 | 1 β€” when set, opens an IFILE that's a block device with the extra O_DIRECT flag. The default is 0, so block devices don't get opened O_DIRECT πŸ”’
  • skip=SKIP β€” every read operation starts offset by SKIP bs-sized blocks from the start of the input file (or device) ⏭️
  • time=TI β€” when TI is 0 (the default), no timing happens. When 1, it times the transfer and calculates throughput, starting at the first issued command and going until completion. When 2, it does the same but starts at the second issued command. When 3, it starts from the third command, and so on. It also prints an average number of commands (SCSI READs or Unix read()s) executed per second ⏱️
  • verbose=VERB β€” as VERB goes up, so does the amount of debug output sent to stderr. The default is zero, which gives the minimum amount of debug output. A value of 1 reports extra info that isn't repetitive πŸ“£
  • --help β€” outputs the usage message, then exits πŸ†˜
  • --version β€” outputs the version string, then exits πŸ”–

✨ NOTES ✨

Some numeric arguments (like SKIP) can include multiplicative suffixes or be given in hexadecimal. Check the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page for the deets πŸ”’

Data usually gets to user space in a 2 stage process. First the SCSI adapter DMAs into kernel buffers, then the sg driver copies that data into user memory. This is called "indirect IO". There's a dio option to select "direct IO", which DMAs straight into user memory. Due to some issues, "direct IO" is disabled in the sg driver and needs a config change to turn on. This is typically done with echo 1 > /sys/module/sg/parameters/allow_dio. Another way to skip the 2 stage copy is memory mapped IO with mmap=1 🫧

✨ SIGNALS ✨

The signal handling was borrowed from dd πŸ’… SIGINT, SIGQUIT and SIGPIPE output the number of remaining blocks to be transferred, then they do their default action. SIGUSR1 outputs that same info, but the copy keeps going. All output caused by signals goes to stderr πŸ“¨

✨ EXAMPLES ✨

Okay, let's say /dev/sg0 is a disk and we want to time the disk's cache performance πŸ‘‘

sg_read if=/dev/sg0 bs=512 count=1MB mmap=1 time=2

This command will keep reading 128 512 byte blocks from block 0. The 128 is the default for bpt, and block 0 is picked because the skip argument wasn't given. It keeps going until 1,000,000 blocks are read. The idea behind time=2 is that the first 64 KiB read operation will involve reading the magnetic media, while the rest of the read operations will "hit" the disk's cache 🧠 The output of third command will look like this:

time from second command to end was 4.50 secs, 113.70 MB/sec
Average number of READ commands per second was 1735.27
1000000+0 records in, SCSI commands issued: 7813

✨ EXIT STATUS ✨

The exit status of sg_read is 0 when it works. Otherwise, see the sg3_utils(8) man page 🎯

✨ AUTHORS ✨

Written by Douglas Gilbert 🫢

✨ REPORTING BUGS ✨

Report bugs to <dgilbert at interlog dot com> πŸ›

Copyright Β© 2000-2019 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 ✨

To time streaming media read or write time, see sg_dd, which is in the sg3_utils package, and ddpt, which is in a package of the same name. The lmbench package contains lmdd, which is also interesting 🌟 Also check out raw(8) and dd(1) πŸ’–


Ta-da, you're officially an sg_read expert now, bestie 🌈 SG3_UTILS sg3_utils-1.45, September 2019 πŸ’œ Stay iconic πŸ’…βœ¨

πŸ“¦ where this page comes from