Commands¶
- class squishy.scsi.command.GroupCode(value)¶
 SCSI Command Group Code
Each SCSI command belongs to a group that defines its characteristics. It also defines which commands are optional (
o), mandatory (m), reserved (r), shared (s), or vendor specific (v).If a command is optional (
o) then the target does not need to implement it. If the command is mandatory (m) then it must be implemented by the target. If a command is reserved (r) then it should not be implemented by the target, if a command is shared (s) then the opcode depends on the target device class, and may have multiple meanings. Finally, if the command is vendor specific (v) then the command might be implemented depending on the target vendor and its meaning is not standardized.Each group code is three-bits long, allowing for a maximum of eight groups, with the remaining five-bits in the command opcode for the command identifier itself.
Groupe Code
Group Description
0b000Six-byte Commands
0b001Ten-byte Commands
0b010Reserved Groups
0b0110b1000b101Twelve-byte Commands
0b110Vendor Specific
0b111- GROUP0 = 0¶
 Six-byte Commands
opcode
Type
Command
0x00oTest Unit Ready
0x01s0x02v0x03mRequest Sense
0x04&0x05s0x06v0x07&0x08s0x09v0x0A&0x0Bs0x0Cto0x0Ev0x0Fto0x11s0x12mInquiry
0x13to0x17s0x18oCopy
0x19to0x`Bs0x1CoRecv Diagnostic
0x1DSend Diagnostic
0x1Es0x1Fr
- GROUP1 = 1¶
 Ten-byte Commands
opcode
Type
Command
0x00to0x04v0x05s0x06&0x07v0x08s0x09v0x0A&0x0Bs0x0C&0x0Dv0x0Eto0x13s0x14to0x18r0x19oCompare
0x1ACopy and Verify
0x1Bto0x1Fr
- GROUP2 = 2¶
 Reserved Group
opcode
Type
Command
0x00to0x0Fr
- GROUP3 = 3¶
 Reserved Group
opcode
Type
Command
0x00to0x0Fr
- GROUP4 = 4¶
 Reserved Group
opcode
Type
Command
0x00to0x0Fr
- GROUP5 = 5¶
 Twelve-byte Commands
opcode
Type
Command
0x00to0x0Fv0x10to0x1Fr
- GROUP6 = 6¶
 Vendor Specific Commands
opcode
Type
Command
0x00to0x1Fv
- GROUP7 = 7¶
 Vendor Specific Commands
opcode
Type
Command
0x00to0x1Fv
- class squishy.scsi.command.SCSICommand(opcode: int, group_code: GroupCode, *subcons, size: int | None = None, **subconskw) None¶
 SCSI Command Structure
Creates a
construct.Structfor arbitrary SCSI Commands. This wraps the structure and gives it some useful common operations needed to consume and generate SCSI commands.This class automatically creates the opcode and control sections of the command and surrounds the provided
*subconswith them.The rough layout of a SCSI command looks like this:
Byte
7
6
5
4
3
2
1
0
0opcodendatan+1controlBoth the
opcodeandcontrolfields of the command are fixed size at 8 bits, but thedatasection may span multiple bytes and is command dependent.The size of the command represents the full size of the structure, where the size of the command data itself is
sizeof(data) - 2to account for theopcodeandcontrolbytes. Therefore a Six-byte command has four-bytes of actual command data for example.The layout of the
opcodeitself is a ‘sub structure’ which describes the group the command is in as well as the command itself.7
6
5
4
3
2
1
0
group codecommand codeThe
group code(GroupCode) is the top three bits of the opcode, followed by thecommand codewhich is the remaining seven bits.Due to the split between
group codeandcommand codeas well as the different classes that implement commands, there is a large re-use ofopcode’s, this complicates things, as we need to know ahead of time what the device is in order to succesfully dispatch and parse commands.The
controlbyte also has it’s own ‘sub structure’.7
6
5
4
3
2
1
0
vendorreservedflaglinkThe
vendorfield makes up the top two bits of the control byte, and is vendor unique.The
reservedfield follows and is made up of the next four bits.The
flagbit can only be set if thelinkbit is set. Iflinkis set and the command completes successfully then the target sends aLINKED COMMAND COMPLETEmessage ifflagis zero and aLINKED COMMAND COMPLETE WITH FLAGmessage ifflagis set. This behavior is commonly used to trigger an interrupt in the initiator.The
linkbit represents an automatic link to the next command is requested by the initiator if the command is successful. Implementation of this is optional, and depending on if it is supported or not, one of the following two behaviors is expected if thelinkflag is set.If supported, when a command completes successfully. The target will return a
INTERMEDIATEstatus and then send a message depending on the state offlag.If unsupported, the target will return a
CHECK CONDITIONstatus and depending if extended sense is implemented, it will set the sense key toILLEGAL REQUESTif eitherflagorlinkare set.
Examples
You can define a new
SCSICommandlike any other construct structure.Command = SCSICommand( # Final command opcode is calculated by ``opcode | group_code`` # And then prefixed prior to the given fields 0x01, # Command Opcode GroupCode.GROUP0, # Command Group 'Foo' / construct.Int8ul, 'Bar' / construct.BitStruct( 'Nya', construct.BitsInteger(3), 'UwU', construct.BitsInteger(5) ) # The SCSI 'control' byte is then added after. )
You can also use the special
SCSICommandFieldclass to simply attach defaults, descriptions, and automatically compute sizes.Command = SCSICommand( 0x01, GroupCode.GROUP0, 'Foo' / SCSICommandField('This is a field', default = 0, length = 3), 'Bar' / SCSICommandField('This is also a field', length = 5) )
- Parameters:
 opcode (int) – The operation code (opcode) for the given command.
group_code (GroupCode) – The specific SCSI group code for this command.
size (None, int) – The size of the command, if not provided, this is inferred from the
group_codeif possible. (default:None)*subcons (list[construct.Subconstruct]) – The collection of construct
construct.Subconstructmembers representing the command.
- Attributes:
 group_code (GroupCode) – The SCSI commands group code.
size (int) – The total size of the SCSI command.
Note
The result of the
sizeof()call returns the size of the SCSI command in bits. To get the size in bytes either call thelen()method or divide the result of thesizeof()call by8.- parse(data, **ctxkw)¶
 Parse an in-memory buffer (often bytes object). Strings, buffers, memoryviews, and other complete buffers can be parsed with this method.
Whenever data cannot be read, ConstructError or its derivative is raised. This method is NOT ALLOWED to raise any other exceptions although (1) user-defined lambdas can raise arbitrary exceptions which are propagated (2) external libraries like numpy can raise arbitrary exceptions which are propagated (3) some list and dict lookups can raise IndexError and KeyError which are propagated.
Context entries are passed only as keyword parameters **contextkw.
- Parameters:
 **contextkw – context entries, usually empty
- Returns:
 some value, usually based on bytes read from the stream but sometimes it is computed from nothing or from the context dictionary, sometimes its non-deterministic
- Raises:
 ConstructError – raised for any reason
- class squishy.scsi.command.SCSICommand6(opcode: int, *subcons, **subconmskw) None¶
 Six-byte SCSI Command
This is a specialization of the
SCSICommandclass that deals with six-byte SCSI commands. It automatically sets the group code to Group 0.The rough layout of the six-byte SCSI commands are the
opcodefollowed by fourdatabytes, and then thecontrolbyte.Byte
7
6
5
4
3
2
1
0
0opcode1data2345control- Parameters:
 opcode (int) – The operation code (opcode) for the given command.
*subcons (list[construct.Subconstruct]) –
The collection of construct
construct.Subconstructmembers representing the command.
- Attributes:
 group_code (GroupCode) – The SCSI commands group code.
size (int) – The total size of the SCSI command.
Note
The result of the
sizeof()call returns the size of the SCSI command in bits. To get the size in bytes either call thelen()method or divide the result of thesizeof()call by8.
- class squishy.scsi.command.SCSICommand10(opcode: int, *subcons, **subconmskw) None¶
 Ten-byte SCSI Command
This is a specialization of the
SCSICommandclass that deals with ten-byte SCSI commands. It automatically sets the group code to Group 1.The rough layout of the ten-byte SCSI commands are the
opcodefollowed by eightdatabytes, and then thecontrolbyte.Byte
7
6
5
4
3
2
1
0
0opcode1data23456789control- Parameters:
 opcode (int) – The operation code (opcode) for the given command.
*subcons (list[construct.Subconstruct]) –
The collection of construct
construct.Subconstructmembers representing the command.
- Attributes:
 group_code (GroupCode) – The SCSI commands group code.
size (int) – The total size of the SCSI command.
Note
The result of the
sizeof()call returns the size of the SCSI command in bits. To get the size in bytes either call thelen()method or divide the result of thesizeof()call by8.
- class squishy.scsi.command.SCSICommand12(opcode: int, *subcons, **subconmskw) None¶
 Twelve-byte SCSI Command
This is a specialization of the
SCSICommandclass that deals with twelve-byte SCSI commands. It automatically sets the group code to Group 5.The rough layout of the ten-byte SCSI commands are the
opcodefollowed by tendatabytes, and then thecontrolbyte.Byte
7
6
5
4
3
2
1
0
0opcode1data23456789ABcontrol- Parameters:
 opcode (int) – The operation code (opcode) for the given command.
*subcons (list[construct.Subconstruct]) –
The collection of construct
construct.Subconstructmembers representing the command.
- Attributes:
 group_code (GroupCode) – The SCSI commands group code.
size (int) – The total size of the SCSI command.
Note
The result of the
sizeof()call returns the size of the SCSI command in bits. To get the size in bytes either call thelen()method or divide the result of thesizeof()call by8.
- class squishy.scsi.command.SCSICommandField(description: str = '', default: Any = None, *, length: int | None = None) None¶
 SCSI Command Field
This is a wrapper
construct.Subconstructto allow for some metadata and automatic type deduction to be preformed based on the field name.By default SCSI Command fields don’t have any type prefixing in their name, however this class allows for names with a prefix to automatically set the size and type.
The following table lists the field name prefixes and their type information:
Prefix
Type
u8lconstruct.Int8ulu16lconstruct.Int16ulu24lconstruct.Int24ulu32lconstruct.Int32ulu64lconstruct.Int64uls8lconstruct.Int8sls16lconstruct.Int16sls24lconstruct.Int24sls32lconstruct.Int32sls64lconstruct.Int64slu8bconstruct.Int8ubu16bconstruct.Int16ubu24bconstruct.Int24ubu32bconstruct.Int32ubu64bconstruct.Int64ubs8bconstruct.Int8sbs16bconstruct.Int16sbs24bconstruct.Int24bls32bconstruct.Int32sbs64bconstruct.Int64sbb#construct.BitsIntegerAn example prefixed field name would be
u8lAllocLenwhich would define an unsigned eight-bit unsigned little-endian integer calledAllocLen.However, if the
lengthargument is passed, that will override the prefix calculated by the name if any is present.
- class squishy.scsi.command.CommandEmitter(command: SCSICommand) None¶
 Creates an emitter based on the specified SCSI command.
Given a SCSI command like the following:
Command = SCSICommand6(0x00, 'Foo' / SCSICommandField(default = 0, length = 8), 'Bar' / SCSICommandField(length = 8) )
You are then able to construct an emitter and use it like so:
e = CommandEmitter(Command) e.Bar = 0xab # b'\x00\xab' data = e.emit()
It is also possible to use it within a context like the following:
with CommandEmitter(Command) as cmd: cmd.Bar = 0x15 # b'\x00\x15' cmd.emit()
- Parameters:
 command (SCSICommand) – The
SCSICommandto wrap.
- emit() bytes¶
 Emit bytes
Takes the assigned fields and generates a byte string from the specified format.
Warning
This method wraps the internal
construct.Subconstructin aconstruct.Bitwise()to serialize the structure to bytes.