SG_RAW(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_RAW(8) Β· SG3_UTILS πŸ’–

✨ NAME ✨

sg_raw - send arbitrary SCSI or NVMe command to a device πŸŽ€

πŸ¦‹ SYNOPSIS πŸ¦‹

sg_raw [--binary] [--cmdfile=CF] [--cmdset=CS] [--enumerate] [--help]
[--infile=IFILE] [--nosense] [--nvm] [--outfile=OFILE] [--raw]
[--readonly] [--request=RLEN] [--scan=FO,LO] [--send=SLEN] [--skip=KLEN]
[--timeout=SECS] [--verbose] [--version] DEVICE [CDB0 CDB1 ...]

🌸 DESCRIPTION 🌸

okay so sg_raw lets you send an arbitrary SCSI command (anywhere from 6 to 256 bytes) to a DEVICE πŸ’… there might be no data transfer at all, or you can read data from a file and send it over, or you can receive data from the device and then display it or write it to a file. no cap, that's a lot of options bestie 😭

if the pass through supports it, you can even send bidirectional commands, the ones that carry data going to the DEVICE and data coming back from it, all in one go πŸ”₯

the SCSI command is between 6 and 256 bytes long, and each command byte is written in plain hex (00..FF) with no prefix or suffix. you can hand the command over on the command line or through the --cmdfile=CF option. check the EXAMPLES section below if you want to see it in action ✨

the commands travel through a generic SCSI interface that's been built for several operating systems, including Linux, FreeBSD and Windows. iconic, right? 🌈

experimental support has also landed for sending NVMe Admin and NVM commands to the DEVICE 🧚 since every NVMe command is 64 bytes long, it's way easier to use --cmdfile=CF than to type all 64 bytes on the command line. see the section on NVME below for the tea β˜•

the tool uses a heuristic based on command length to decide whether your command is SCSI or NVMe. if it guesses wrong, you can override it with the --cmdset=CS option πŸ™ˆ

πŸŽ€ OPTIONS πŸŽ€

ngl the options are the main event here, so buckle up πŸ’œ arguments to long options are mandatory for short options as well, so if the long form needs a value, the short form needs one too. the options are arranged in alphabetical order based on the long option name ✨

  • -b, --binary β€” dump data in binary form, even when you're writing to stdout πŸ“
  • -c, --cmdfile=CF β€” CF is the name of a file that holds the command to run. without this option, the command has to be typed on the command line, after the options and the DEVICE πŸ“
  • -C, --cmdset=CS β€” CS picks which command set to use (SCSI or NVMe) πŸ”₯ the default, 0, lets the command-length heuristic decide. use 1 to force the SCSI command set, or 2 to force the NVMe command set πŸ’…
  • -h, --help β€” shows usage info and exits 🫢
  • -i, --infile=IFILE β€” reads binary data from IFILE instead of stdin πŸ“‚ this is ignored unless --send is specified. if used, that data becomes the command's "data-out" buffer πŸ’–
  • -n, --nosense β€” hides SCSI Sense information πŸ™ˆ
  • -N, --nvm β€” when sending NVMe commands, the Admin command set is assumed by default. if you want the NVM command set instead (like the Read and Write user data commands), you need to give this option 🧚
  • -o, --outfile=OFILE β€” writes the data received from the DEVICE to OFILE πŸ¦‹ that data is the command's "data-in" buffer, and it gets written in binary. by default the data is dumped in hex to stdout. if OFILE is -, the data is dumped in binary to stdout instead. this option is ignored unless --request is specified 🌸
  • -w, --raw β€” treats CF (the command file) as containing binary. the default assumption is ASCII hexadecimal, so use this if your file is raw bytes πŸ€“
  • -R, --readonly β€” opens the DEVICE read-only πŸ‘€ without this option, it opens read-write πŸ’…
  • -r, --request=RLEN β€” you're expecting up to RLEN bytes of data back from the DEVICE ✨ you can add a k suffix to count in kilobytes (1024 bytes) instead of bytes. RLEN is decimal unless it has a leading 0x or a trailing h πŸ”’
⚠️ bestie, if RLEN is too small (smaller than what the cdb asks for in its "allocation length" field, and/or smaller than what the DEVICE tries to send back), the HBA driver may complain 😭 going bigger than needed should cause no problems at all. most SCSI "data-in" commands return a data block that has a length in its early bytes, which is what the DEVICE would "like" to send back if the cdb's "allocation length" field is big enough. in practice, the DEVICE never returns more bytes than the "allocation length" field in the cdb says πŸ’œ
  • -Q, --scan=FO,LO β€” scans a range of opcodes (the first byte of each command) πŸ” the first opcode is FO (decimal unless it has a 0x prefix or h suffix), and the last one is LO. the max value of LO is 255. the rest of the SCSI/NVMe command stays exactly as you supplied it at invocation 🌈
🚨 warning, this one can be dangerous!! sending somewhat arbitrary commands to a device can have unexpected results πŸ’€ it's recommended to use this with --cmdset=CS where CS is 1 or 2, so the command set can't switch around mid-scan.
  • -s, --send=SLEN β€” reads SLEN bytes of data, either from stdin or a file, and sends them to the DEVICE πŸ“€ on the SCSI transport, SLEN becomes the length in bytes of the "data-out" buffer. SLEN is decimal unless it has a leading 0x or a trailing h πŸ“

it's on you to make sure the "data-out" length implied or stated in the cdb matches SLEN 🫢 heads up that some common SCSI commands, like WRITE(10), have a "transfer length" field measured in logical blocks (usually 512 or 4096 bytes long), not bytes 🧐

  • -k, --skip=KLEN β€” skips the first KLEN bytes of the input file or stream ⏭️ this is ignored unless --send is specified. if you give --send but not this option, zero bytes get skipped πŸ”₯
  • -t, --timeout=SECS β€” waits up to SECS seconds for the command to finish (default: 20) ⏱️ if a command times out, the operating system may start by aborting it, and if that doesn't work it may try to reset the device 😬 the alternate long form is --tmo=SECS πŸ¦‹
  • -v, --verbose β€” cranks up the verbosity πŸ“’ you can use it more than once πŸ’…
  • -V, --version β€” shows version and license info, then exits 🌸

✨ EXAMPLES ✨

These examples, apart from the last one, use Linux device names 🐧. For suitable device names in other supported Operating Systems, check out the sg3_utils(8) man page πŸ’–.

sg_raw /dev/scd0 1b 00 00 00 02 00

Eject the medium in CD drive /dev/scd0 πŸ’Ώβœ¨

sg_raw -r 1k /dev/sg0 12 00 00 00 60 00

Perform an INQUIRY on /dev/sg0 and dump the response data (up to 1024 bytes) to stdout πŸ–¨οΈπŸŒΈ

sg_raw -s 512 -i i512.bin /dev/sda 3b 02 00 00 00 00 00 02 00 00

Okay so writing 512 bytes to a sector on a disk is lowkey dangerous πŸ’€ so we're not doing that. Instead this one reads i512.bin (assumed to be 512 bytes long) and uses the SCSI WRITE BUFFER command to send it to the "data" buffer (that's mode 2). This is a safe operation πŸ«ΆπŸŽ€

sg_raw -r 512 -o o512.bin /dev/sda 3c 02 00 00 00 00 00 02 00 00

This one uses the SCSI READ BUFFER command to read 512 bytes from the "data" buffer (aka mode 2) and then writes it to the o512.bin file πŸ“. If you pair it with the previous example and both commands work, then cmp i512.bin o512.bin should show a match πŸ”₯πŸ‘‘

sg_raw --infile=urandom.bin --send=512 --request=512 --outfile=out.bin
"/dev/bsg/7:0:0:0" 53 00 00 00 00 00 00 00 01 00

This is a bidirectional XDWRITEREAD(10) command being sent through a Linux bsg device πŸ¦‹. Data gets read from urandom.bin and sent to the device (data-out), while the resulting data (data-in) lands in the out.bin file. Also note that the length of both is 512 bytes, which lines up with the transfer length of 1 (block) in the cdb (aka the second last byte) 🧚. The urandom.bin file can be made like this:

dd if=/dev/urandom bs=512 count=1 of=urandom.bin
sg_raw.exe PhysicalDrive1 a1 0c 0e 00 00 00 00 00 00 e0 00 00

This one is from Windows πŸͺŸ and shows an ATA STANDBY IMMEDIATE command being sent to PhysicalDrive1. That ATA command is wrapped inside the SCSI ATA PASS-THROUGH(12) command (check out the SAT or SAT-2 standard at https://www.t10.org) πŸ“œ. Notice that STANDBY IMMEDIATE doesn't send or receive any extra data, but if it fails, sense data should be returned and displayed πŸ™ˆ

For NVME examples, peep the files in this package's inhex directory that start with nvme_, such as inhex/nvme_identify_ctl.hex πŸ’œ

✨ EXIT STATUS ✨

The exit status of sg_raw is 0 when it's successful πŸ’…. Otherwise, check out the sg3_utils(8) man page 🌈

✨ AUTHOR ✨

Written by Ingo van Lil 🫢

✨ REPORTING BUGS ✨

Report bugs to <inguin at gmx dot de> or to <dgilbert at interlog dot com> πŸ›πŸ’Œ

Copyright Β© 2001-2023 Ingo van Lil 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_inq, sg_vpd, sg3_utils (sg3_utils), plscsi πŸ”—βœ¨


Thanks for hanging with me through the whole SG_RAW(8) glow-up, bestie! πŸŒΈπŸ’– Source: sg3_utils 1.48, dated May 2023. Stay iconic, stay curious, and don't forget to hydrate πŸ’…πŸ¦‹

πŸ“¦ where this page comes from