RFC 3720
Internet Small Computer Systems Interface (iSCSI)
Internet Small Computer Systems Interface (iSCSI) ๐
okay bestie, let's get the vibes straight first ๐ this is RFC 3720, a Standards Track doc from the Network Working Group, dated April 2004 ๐ธ. The authors are J. Satran, K. Meth, and E. Zeidner from IBM, C. Sapuntzakis from Cisco Systems, and M. Chadalapaka from Hewlett-Packard Co. ๐ The title block doesn't say it obsoletes or updates anything, so it's giving main character energy ๐ฆ
Status of this Memo โจ
okay so this section is the official disclaimer ๐ It specifies an Internet standards track protocol for the whole Internet community, and the authors are literally asking for discussion and suggestions for improvements ๐ซถ For the current standardization state and status of this protocol, check the "Internet Official Protocol Standards" (STD 1) list ๐ And yes, distribution of this memo is unlimited, no cap ๐
Copyright Notice ๐
the copyright line is Copyright (C) The Internet Society (2003). All Rights Reserved. and that's the whole tea ๐ซ
Abstract ๐ฆ
so this doc describes a transport protocol for Internet Small Computer Systems Interface (iSCSI) that runs on top of TCP ๐ The iSCSI protocol is aiming to be fully compliant with the standardized SCSI architecture model, which is so iconic ๐
SCSI is a popular family of protocols that let systems talk to I/O devices, especially storage devices ๐พ SCSI protocols are request/response application protocols. They share a common standardized architecture model and basic command set, plus standardized command sets for different device classes (disks, tapes, media-changers etc.) ๐
as system interconnects move from the classic bus structure to a network structure, SCSI has to get mapped onto network transport protocols ๐ IP networks now meet the performance requirements of fast system interconnects, so they're good candidates to "carry" SCSI ๐ง
Table of Contents ๐ธ
Part 2 should start at Section 1, but the text you sent is the table of contents, which was already covered in part 1. I don't have the body text from Section 1 onward, and I can't rewrite it reliably from memory without risking changes to requirements, numbers, or examples.
Could you paste the RFC 3720 text starting at "1. Introduction" and continuing as far as you'd like for this part? I'll pick up right there in the same format.
okay bestie, the table of contents keeps going, and it's giving a lot of sections ๐โจ
9.1. Multiple Network Adapters. . . . . . . . . . . . . . . 106
9.1.1. Conservative Reuse of ISIDs. . . . . . . . . 107
9.1.2. iSCSI Name, ISID, and TPGT Use . . . . . . . 107
9.2. Autosense and Auto Contingent Allegiance (ACA) . . . . 109
9.3. iSCSI Timeouts . . . . . . . . . . . . . . . . . . . . 109
9.4. Command Retry and Cleaning Old Command Instances . . . 110
9.5. Synch and Steering Layer and Performance . . . . . . . 110
9.6. Considerations for State-dependent Devices and
Long-lasting SCSI Operations . . . . . . . . . . . . . 111
9.6.1. Determining the Proper ErrorRecoveryLevel. . 112
10. iSCSI PDU Formats . . . . . . . . . . . . . . . . . . . . . . 112
10.1. iSCSI PDU Length and Padding . . . . . . . . . . . . . 113
10.2. PDU Template, Header, and Opcodes. . . . . . . . . . . 113
10.2.1. Basic Header Segment (BHS) . . . . . . . . . 114
10.2.1.1. I . . . . . . . . . . . . . . . . 115
10.2.1.2. Opcode. . . . . . . . . . . . . . 115
10.2.1.3. Final (F) bit . . . . . . . . . . 116
10.2.1.4. Opcode-specific Fields. . . . . . 116
10.2.1.5. TotalAHSLength. . . . . . . . . . 116
10.2.1.6. DataSegmentLength . . . . . . . . 116
10.2.1.7. LUN . . . . . . . . . . . . . . . 116
10.2.1.8. Initiator Task Tag. . . . . . . . 117
10.2.2. Additional Header Segment (AHS) . . . . . . . 117
10.2.2.1. AHSType . . . . . . . . . . . . . 117
10.2.2.2. AHSLength . . . . . . . . . . . . 117
10.2.2.3. Extended CDB AHS. . . . . . . . . 118
10.2.2.4. Bidirectional Expected Read-Data
Length AHS. . . . . . . . . . . . 118
10.2.3. Header Digest and Data Digest. . . . . . . . 118
10.2.4. Data Segment . . . . . . . . . . . . . . . . 119
10.3. SCSI Command . . . . . . . . . . . . . . . . . . . . . 119
10.3.1. Flags and Task Attributes (byte 1) . . . . . 120
10.3.2. CmdSN - Command Sequence Number. . . . . . . 120
10.3.3. ExpStatSN. . . . . . . . . . . . . . . . . . 120
10.3.4. Expected Data Transfer Length. . . . . . . . 121
10.3.5. CDB - SCSI Command Descriptor Block. . . . . 121
10.3.6. Data Segment - Command Data. . . . . . . . . 121
10.4. SCSI Response. . . . . . . . . . . . . . . . . . . . . 122
10.4.1. Flags (byte 1) . . . . . . . . . . . . . . . 123
10.4.2. Status . . . . . . . . . . . . . . . . . . . 123
10.4.3. Response . . . . . . . . . . . . . . . . . . 124
10.4.4. SNACK Tag. . . . . . . . . . . . . . . . . . 125
10.4.5. Residual Count . . . . . . . . . . . . . . . 125
10.4.6. Bidirectional Read Residual Count. . . . . . 125
10.4.7. Data Segment - Sense and Response Data
Segment. . . . . . . . . . . . . . . . . . . 125
10.4.7.1. SenseLength . . . . . . . . . . . 126
10.4.7.2. Sense Data. . . . . . . . . . . . 126
10.4.8. ExpDataSN. . . . . . . . . . . . . . . . . . 127
10.4.9. StatSN - Status Sequence Number. . . . . . . 127
10.4.10. ExpCmdSN - Next Expected CmdSN from this
Initiator. . . . . . . . . . . . . . . . . . 128
10.4.11. MaxCmdSN - Maximum CmdSN from this Initiator 128
10.5. Task Management Function Request . . . . . . . . . . . 129
10.5.1. Function . . . . . . . . . . . . . . . . . . 129
10.5.2. TotalAHSLength and DataSegmentLength . . . . 132
10.5.3. LUN. . . . . . . . . . . . . . . . . . . . . 132
10.5.4. Referenced Task Tag. . . . . . . . . . . . . 132
10.5.5. RefCmdSN . . . . . . . . . . . . . . . . . . 132
10.5.6. ExpDataSN. . . . . . . . . . . . . . . . . . 133
10.6. Task Management Function Response. . . . . . . . . . . 134
10.6.1. Response . . . . . . . . . . . . . . . . . . 134
10.6.2. Task Management Actions on Task Sets . . . . 136
10.6.3. TotalAHSLength and DataSegmentLength . . . . 137
10.7. SCSI Data-Out & SCSI Data-In . . . . . . . . . . . . . 137
10.7.1. F (Final) Bit. . . . . . . . . . . . . . . . 139
10.7.2. A (Acknowledge) Bit. . . . . . . . . . . . . 139
10.7.3. Flags (byte 1) . . . . . . . . . . . . . . . 140
10.7.4. Target Transfer Tag and LUN. . . . . . . . . 140
10.7.5. DataSN . . . . . . . . . . . . . . . . . . . 141
10.7.6. Buffer Offset. . . . . . . . . . . . . . . . 141
10.7.7. DataSegmentLength. . . . . . . . . . . . . . 141
10.8. Ready To Transfer (R2T). . . . . . . . . . . . . . . . 142
10.8.1. TotalAHSLength and DataSegmentLength . . . . 143
10.8.2. R2TSN. . . . . . . . . . . . . . . . . . . . 143
10.8.3. StatSN . . . . . . . . . . . . . . . . . . . 144
10.8.4. Desired Data Transfer Length and Buffer
Offset . . . . . . . . . . . . . . . . . . . 144
10.8.5. Target Transfer Tag. . . . . . . . . . . . . 144
10.9. Asynchronous Message . . . . . . . . . . . . . . . . . 145
10.9.1. AsyncEvent . . . . . . . . . . . . . . . . . 146
10.9.2. AsyncVCode . . . . . . . . . . . . . . . . . 147
10.9.3. LUN. . . . . . . . . . . . . . . . . . . . . 147
10.9.4. Sense Data and iSCSI Event Data. . . . . . . 148
10.9.4.1. SenseLength . . . . . . . . . . . 148
10.10. Text Request . . . . . . . . . . . . . . . . . . . . . 149
10.10.1. F (Final) Bit. . . . . . . . . . . . . . . . 150
10.10.2. C (Continue) Bit . . . . . . . . . . . . . . 150
10.10.3. Initiator Task Tag . . . . . . . . . . . . . 150
10.10.4. Target Transfer Tag. . . . . . . . . . . . . 150
10.10.5. Text . . . . . . . . . . . . . . . . . . . . 151
10.11. Text Response. . . . . . . . . . . . . . . . . . . . . 152
10.11.1. F (Final) Bit. . . . . . . . . . . . . . . . 152
10.11.2. C (Continue) Bit . . . . . . . . . . . . . . 153
10.11.3. Initiator Task Tag . . . . . . . . . . . . . 153
10.11.4. Target Transfer Tag. . . . . . . . . . . . . 153
10.11.5. StatSN . . . . . . . . . . . . . . . . . . . 154
10.11.6. Text Response Data . . . . . . . . . . . . . 154
10.12. Login Request. . . . . . . . . . . . . . . . . . . . . 154
10.12.1. T (Transit) Bit. . . . . . . . . . . . . . . 155
10.12.2. C (Continue) Bit . . . . . . . . . . . . . . 155
10.12.3. CSG and NSG. . . . . . . . . . . . . . . . . 156
10.12.4. Version. . . . . . . . . . . . . . . . . . . 156
10.12.4.1. Version-max. . . . . . . . . . . 156
10.12.4.2. Version-min. . . . . . . . . . . 156
10.12.5. ISID . . . . . . . . . . . . . . . . . . . . 157
10.12.6. TSIH . . . . . . . . . . . . . . . . . . . . 158
10.12.7. Connection ID - CID. . . . . . . . . . . . . 158
10.12.8. CmdSN. . . . . . . . . . . . . . . . . . . . 159
10.12.9. ExpStatSN. . . . . . . . . . . . . . . . . . 159
10.12.10. Login Parameters . . . . . . . . . . . . . . 159
10.13. Login Response . . . . . . . . . . . . . . . . . . . . 160
10.13.1. Version-max. . . . . . . . . . . . . . . . . 160
10.13.2. Version-active . . . . . . . . . . . . . . . 161
10.13.3. TSIH . . . . . . . . . . . . . . . . . . . . 161
10.13.4. StatSN . . . . . . . . . . . . . . . . . . . 161
10.13.5. Status-Class and Status-Detail . . . . . . . 161
10.13.6. T (Transit) Bit. . . . . . . . . . . . . . . 164
10.13.7. C (Continue) Bit . . . . . . . . . . . . . . 164
10.13.8. Login Parameters . . . . . . . . . . . . . . 164
10.14. Logout Request . . . . . . . . . . . . . . . . . . . . 165
10.14.1. Reason Code. . . . . . . . . . . . . . . . . 167
10.14.2. TotalAHSLength and DataSegmentLength . . . . 168
10.14.3. CID. . . . . . . . . . . . . . . . . . . . . 168
10.14.4. ExpStatSN. . . . . . . . . . . . . . . . . . 168
10.14.5. Implicit termination of tasks. . . . . . . . 168
10.15. Logout Response. . . . . . . . . . . . . . . . . . . . 169
10.15.1. Response . . . . . . . . . . . . . . . . . . 170
10.15.2. TotalAHSLength and DataSegmentLength . . . . 170
10.15.3. Time2Wait. . . . . . . . . . . . . . . . . . 170
10.15.4. Time2Retain. . . . . . . . . . . . . . . . . 170
10.16. SNACK Request. . . . . . . . . . . . . . . . . . . . . 171
10.16.1. Type . . . . . . . . . . . . . . . . . . . . 172
10.16.2. Data Acknowledgement . . . . . . . . . . . . 173
10.16.3. Resegmentation . . . . . . . . . . . . . . . 173
10.16.4. Initiator Task Tag . . . . . . . . . . . . . 174
10.16.5. Target Transfer Tag or SNACK Tag . . . . . . 174
10.16.6. BegRun . . . . . . . . . . . . . . . . . . . 174
10.16.7. RunLength. . . . . . . . . . . . . . . . . . 174
10.17. Reject . . . . . . . . . . . . . . . . . . . . . . . . 175
10.17.1. Reason . . . . . . . . . . . . . . . . . . . 176
10.17.2. DataSN/R2TSN . . . . . . . . . . . . . . . . 177
10.17.3. StatSN, ExpCmdSN and MaxCmdSN. . . . . . . . 177
10.17.4. Complete Header of Bad PDU . . . . . . . . . 177
1. Introduction โจ
Okay bestie, let's start with the big picture ๐ฆ The Small Computer Systems Interface (SCSI) is a super popular family of protocols for talking to I/O devices, especially storage devices ๐พ It's a client-server architecture, and the clients are called "initiators" ๐ Initiators send SCSI "commands" to request services from components, which are logical units of a server called a "target" ๐ฏ A "SCSI transport" is what maps that client-server SCSI protocol onto a specific interconnect ๐ So an initiator is one endpoint of a SCSI transport, and a target is the other endpoint ๐ซถ
SCSI has been mapped over lots of transports, including Parallel SCSI, IPI, IEEE-1394 (firewire), and Fibre Channel ๐ But these transports are I/O specific and have limited distance capabilities ๐ญ
Now the main event ๐ The iSCSI protocol defined in this document describes a way to carry SCSI packets over TCP/IP (see [RFC791], [RFC793], [RFC1035], [RFC1122]) โจ That gives us an interoperable solution that can use the existing Internet infrastructure and Internet management facilities, and it can tackle those distance limitations too ๐ง It's giving main character energy for storage networking, no cap ๐
2. Definitions and Acronyms ๐
2.1. Definitions โจ
okay bestie, this is the vocab list everything else in the spec leans on, so let's get it right ๐ ๐
- Alias: an alias string can also be attached to an iSCSI Node ๐ฆ it lets an organization pin a user-friendly string to the iSCSI Name, but the alias is literally not a substitute for the iSCSI Name ๐
- CID (Connection ID): connections inside a session get identified by a connection ID ๐ธ it's a unique ID for that connection within the session, from the initiator's side. The initiator generates it and presents it to the target during login requests and during logouts that close connections โจ
- Connection: a connection is a TCP connection ๐ the initiator and target talk over one or more TCP connections, and those carry control messages, SCSI commands, parameters, and data inside iSCSI Protocol Data Units (iSCSI PDUs) ๐ซถ
- iSCSI Device: a SCSI Device using an iSCSI service delivery subsystem ๐ง the Service Delivery Subsystem is defined by [SAM2] as a transport mechanism for SCSI commands and responses
- iSCSI Initiator Name: the worldwide unique name of the initiator ๐
- iSCSI Initiator Node: this is "the initiator" ๐ the word "initiator" gets qualified as either a port or a device in the rest of the document when the context is confusing. Any unqualified "initiator" means an initiator port (or device), depending on the context ๐ค
- iSCSI Layer: this layer builds and receives iSCSI PDUs, then relays them to and from one or more TCP connections that form an initiator-target "session" ๐
- iSCSI Name: the name of an iSCSI initiator or iSCSI target โจ
- iSCSI Node: a single iSCSI initiator or iSCSI target ๐ there are one or more iSCSI Nodes within a Network Entity, and each is reachable through one or more Network Portals. An iSCSI Node is identified by its iSCSI Name ๐ฆ because the Name is separate from the addresses, multiple iSCSI Nodes can share one address, and one iSCSI Node can use multiple addresses. iconic ๐
- iSCSI Target Name: the worldwide unique name of the target ๐
- iSCSI Target Node: the "target" ๐ฏ
- iSCSI Task: an iSCSI request for which a response is expected ๐ฌ
- iSCSI Transfer Direction: defined with regard to the initiator. Outbound or outgoing transfers go from the initiator to the target, and inbound or incoming transfers go from the target to the initiator ๐ฅ
- ISID: the initiator part of the Session Identifier, explicitly specified by the initiator during Login ๐ธ
- I_T nexus: according to [SAM2], the I_T nexus is a relationship between a SCSI Initiator Port and a SCSI Target Port. For iSCSI, this relationship is a session, defined as a relationship between an iSCSI Initiator's end of the session (SCSI Initiator Port) and the iSCSI Target's Portal Group. The I_T nexus can be identified by the conjunction of the SCSI port names, so the I_T nexus identifier is the tuple
(iSCSI Initiator Name + ',i,'+ ISID, iSCSI Target Name + ',t,'+ Portal Group Tag)๐งฉ - Network Entity: a device or gateway that is accessible from the IP network ๐ง a Network Entity has one or more Network Portals, and each of those can be used to get onto the IP network by some iSCSI Nodes inside that Network Entity ๐
- Network Portal: a component of a Network Entity that has a TCP/IP network address and that an iSCSI Node inside that entity may use for the connection(s) within one of its iSCSI sessions. In an initiator, a Network Portal is identified by its IP address. In a target, it's identified by its IP address and its listening TCP port ๐ช
- Originator: in a negotiation or exchange, the party that starts it ๐
- PDU (Protocol Data Unit): the initiator and target split their communications into messages, and these messages are called "iSCSI protocol data units" (iSCSI PDUs) ๐ฆ
- Portal Groups: iSCSI supports multiple connections within the same session, and some implementations can combine connections in a session across multiple Network Portals ๐ฆ a Portal Group defines a set of Network Portals within an iSCSI Network Entity that together can coordinate a session with connections spanning those portals. Not every Network Portal in a Portal Group needs to take part in every session connected through that group. One or more Portal Groups may provide access to an iSCSI Node, and each Network Portal, as used by a given iSCSI Node, belongs to exactly one portal group within that node ๐งบ
- Portal Group Tag: this 16-bit quantity identifies a Portal Group within an iSCSI Node. All Network Portals with the same portal group tag in the context of a given iSCSI Node are in the same Portal Group ๐ท๏ธ
- Recovery R2T: an R2T generated by a target after it detects the loss of one or more Data-Out PDUs through a digest error, a sequence error, or a sequence reception timeout ๐ a recovery R2T carries the next unused R2TSN, but it requests all or part of the data burst that an earlier R2T (with a lower R2TSN) had already requested ๐
- Responder: in a negotiation or exchange, the party that answers the originator of that negotiation or exchange ๐ซฑ
- SCSI Device: this is the SAM2 term for an entity that contains one or more SCSI ports connected to a service delivery subsystem and supports a SCSI application protocol ๐ for example, a SCSI Initiator Device contains one or more SCSI Initiator Ports and zero or more application clients, while a Target Device contains one or more SCSI Target Ports and one or more device servers and associated logical units. For iSCSI, the SCSI Device is the component within an iSCSI Node that provides the SCSI functionality, so there can be at most, one SCSI Device within a given iSCSI Node. Access to the SCSI Device can only be achieved in an iSCSI normal operational session. The SCSI Device Name is defined to be the iSCSI Name of the node ๐
- SCSI Layer: this layer builds and receives SCSI CDBs (Command Descriptor Blocks) and relays them, along with the remaining command execute [SAM2] parameters, to and from the iSCSI Layer ๐ฌ
- Session: the group of TCP connections that link an initiator with a target forms a session, which is loosely equivalent to a SCSI I-T nexus ๐งต TCP connections can be added to and removed from a session. Across all connections within a session, an initiator sees one and the same target ๐ฏ
- SCSI Initiator Port: this maps to the endpoint of an iSCSI normal operational session. That session is negotiated through the login process between an iSCSI initiator node and an iSCSI target node. When that process completes successfully, a SCSI Initiator Port is created within the SCSI Initiator Device ๐ the SCSI Initiator Port Name and SCSI Initiator Port Identifier are both defined to be the iSCSI Initiator Name together with (a) a label that identifies it as an initiator port name/identifier and (b) the ISID portion of the session identifier ๐ธ
- SCSI Port: this is the SAM2 term for an entity in a SCSI Device that provides the SCSI functionality needed to interface with a service delivery subsystem ๐ for iSCSI, the definition of the SCSI Initiator Port and the SCSI Target Port are different ๐
- SCSI Port Name: a name made up of UTF-8 [RFC2279] characters that includes the iSCSI Name + 'i' or 't' + ISID or Portal Group Tag ๐ท๏ธ
- SCSI Target Port: this maps to an iSCSI Target Portal Group ๐ฏ
- SCSI Target Port Name and SCSI Target Port Identifier: both are defined to be the iSCSI Target Name together with (a) a label that identifies it as a target port name/identifier and (b) the portal group tag ๐
- SSID (Session ID): a session between an iSCSI initiator and an iSCSI target is defined by a session ID, which is a tuple made of an initiator part (ISID) and a target part (Target Portal Group Tag) ๐งฉ the ISID is explicitly specified by the initiator at session establishment. The Target Portal Group Tag is implied by the initiator through its selection of the TCP endpoint at connection establishment. The
TargetPortalGroupTagkey must also be returned by the target as a confirmation during connection establishment whenTargetNameis given ๐ซถ - Target Portal Group Tag: a numerical identifier (16-bit) for an iSCSI Target Portal Group ๐ข
- TSIH (Target Session Identifying Handle): a target assigned tag for a session with a specific named initiator ๐ง the target generates it during session establishment. Its internal format and content are not defined by this protocol, except for the value 0, which is reserved and used by the initiator to indicate a new session. It is given to the target during additional connection establishment for the same session โจ
2.2. Acronyms
okay this list is LONG bestie ๐ญ but every single acronym is here, no cap:
Acronym Definition
------------------------------------------------------------
3DES Triple Data Encryption Standard
ACA Auto Contingent Allegiance
AEN Asynchronous Event Notification
AES Advanced Encryption Standard
AH Additional Header (not the IPsec AH!)
AHS Additional Header Segment
API Application Programming Interface
ASC Additional Sense Code
ASCII American Standard Code for Information Interchange
ASCQ Additional Sense Code Qualifier
BHS Basic Header Segment
CBC Cipher Block Chaining
CD Compact Disk
CDB Command Descriptor Block
CHAP Challenge Handshake Authentication Protocol
CID Connection ID
CO Connection Only
CRC Cyclic Redundancy Check
CRL Certificate Revocation List
CSG Current Stage
CSM Connection State Machine
DES Data Encryption Standard
DNS Domain Name Server
DOI Domain of Interpretation
DVD Digital Versatile Disk
ESP Encapsulating Security Payload
EUI Extended Unique Identifier
FFP Full Feature Phase
FFPO Full Feature Phase Only
FIM Fixed Interval Marker
Gbps Gigabits per Second
HBA Host Bus Adapter
HMAC Hashed Message Authentication Code
I_T Initiator_Target
I_T_L Initiator_Target_LUN
IANA Internet Assigned Numbers Authority
ID Identifier
IDN Internationalized Domain Name
IEEE Institute of Electrical & Electronics Engineers
IETF Internet Engineering Task Force
IKE Internet Key Exchange
I/O Input - Output
IO Initialize Only
IP Internet Protocol
IPsec Internet Protocol Security
IPv4 Internet Protocol Version 4
IPv6 Internet Protocol Version 6
IQN iSCSI Qualified Name
ISID Initiator Session ID
ITN iSCSI Target Name
ITT Initiator Task Tag
KRB5 Kerberos V5
LFL Lower Functional Layer
LTDS Logical-Text-Data-Segment
LO Leading Only
LU Logical Unit
LUN Logical Unit Number
MAC Message Authentication Codes
NA Not Applicable
NIC Network Interface Card
NOP No Operation
NSG Next Stage
OS Operating System
PDU Protocol Data Unit
PKI Public Key Infrastructure
R2T Ready To Transfer
R2TSN Ready To Transfer Sequence Number
RDMA Remote Direct Memory Access
RFC Request For Comments
SAM SCSI Architecture Model
SAM2 SCSI Architecture Model - 2
SAN Storage Area Network
SCSI Small Computer Systems Interface
SN Sequence Number
SNACK Selective Negative Acknowledgment - also
Sequence Number Acknowledgement for data
SPKM Simple Public-Key Mechanism
SRP Secure Remote Password
SSID Session ID
SW Session Wide
TCB Task Control Block
TCP Transmission Control Protocol
TPGT Target Portal Group Tag
TSIH Target Session Identifying Handle
TTT Target Transfer Tag
UFL Upper Functional Layer
ULP Upper Level Protocol
URN Uniform Resource Names [RFC2396]
UTF Universal Transformation Format
WG Working Group
2.3. Conventions
in the examples, I-> and T-> are how we show which iSCSI PDUs come from the initiator and which come from the target ๐ง
the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119]. these words are doing a LOT of work so pay attention ๐
iSCSI messages (PDUs) get drawn with diagrams like this one ๐
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| Basic Header Segment (BHS) |
+---------------+---------------+---------------+---------------+
----------
+| |
+---------------+---------------+---------------+---------------+
the diagrams include byte and bit numbering, so you can always tell exactly where everything sits ๐ฆ
these are the representation and ordering rules this document follows:
- Word Rule
- Half-word Rule
- Byte Rule
2.3.1. Word Rule
a word holds four consecutive bytes โจ when a word has numeric content, it's read as an unsigned number in base 2 positional representation. the lowest numbered byte (for example, byte 0) has bit 0 representing 231 and bit 1 representing 230, all the way through the lowest numbered byte + 3 (for example, byte 3), where bit 7 represents 2**0. the math is mathing ๐งฎ
decimal and hexadecimal representations of word values map this same representation onto decimal or hexadecimal positional notation, so the numbers match up no matter how you write them ๐ธ
2.3.2. Half-Word Rule
a half-word holds two consecutive bytes ๐ when a half-word has numeric content, it's an unsigned number in base 2 positional representation. the lowest numbered byte (for example, byte 0) has bit 0 representing 215 and bit 1 representing 214, all the way through the lowest numbered byte + 1 (for example, byte 1), where bit 7 represents 2**0. it's giving very precise ๐
decimal and hexadecimal representations of half-word values map this representation onto decimal or hexadecimal positional notation, same energy as the word rule ๐
2.3.3. Byte Rule
for every PDU, bytes get sent and received in increasing numbered order, which is called network order ๐ whenever a byte has numerical content, it's an unsigned number in base 2 positional representation, with bit 0 representing 27, bit 1 representing 26, and so on through bit 7 representing 2**0. ok the byte rule is literally the simplest one and I'm obsessed ๐ญ
3. Overview
3.1. SCSI Concepts
the SCSI Architecture Model-2 [SAM2] is the big official doc that describes the architecture of the SCSI family of I/O protocols in full detail ๐ this section is just a quick background so you get the terminology before we go deeper ๐ซถ
at the highest level, SCSI is a family of interfaces for requesting services from I/O devices. that includes hard drives, tape drives, CD and DVD drives, printers, and scanners ๐จ๏ธ in SCSI language, each individual I/O device is called a "logical unit" (LU).
SCSI is a client-server architecture. the clients of a SCSI interface are called "initiators", and they issue SCSI "commands" to ask for services from components (logical units) that live on a server known as a "target". the "device server" on the logical unit is the thing that accepts SCSI commands and processes them ๐
a "SCSI transport" maps the client-server SCSI protocol onto a specific interconnect. initiators are one endpoint of a SCSI transport, and the "target" is the other endpoint ๐ฆ a target can hold multiple Logical Units (LUs), and each one has an address inside its target called a Logical Unit Number (LUN) ๐ฅ
a SCSI task is a SCSI command, or possibly a linked set of SCSI commands. some LUs support multiple pending (queued) tasks, but the logical unit is the one managing that queue, not you ๐ the target uses an initiator provided "task tag" to tell tasks apart. only one command in a task can be outstanding at any given time, so no multitasking chaos here ๐ โโ๏ธ
each SCSI command results in an optional data phase and a required response phase. in the data phase, info can travel from initiator to target (like a WRITE), from target to initiator (like a READ), or in both directions ๐ in the response phase, the target sends back the final status of the operation, including any errors ๐
Command Descriptor Blocks (CDB) are the data structures that hold the command parameters an initiator sends to a target. the CDB content and structure is defined by [SAM2] and by device-type specific SCSI standards ๐
3.2. iSCSI Concepts and Functional Overview
the iSCSI protocol maps the SCSI remote procedure invocation model (see [SAM2]) over the TCP protocol. SCSI commands get carried by iSCSI requests, and SCSI responses and status get carried by iSCSI responses. iSCSI also uses that same request response mechanism for its own iSCSI protocol mechanisms ๐ธ
for the rest of this document, the terms "initiator" and "target" mean "iSCSI initiator node" and "iSCSI target node", respectively (see Section 3.4.1 iSCSI Architecture Model), unless otherwise qualified โจ
like similar protocols, the initiator and target split their communications into messages. this document calls these messages "iSCSI protocol data units" (iSCSI PDUs) ๐ง
for performance reasons, iSCSI allows a "phase-collapse". a command and its associated data may be shipped together from initiator to target, and data and responses may be shipped together from targets. efficiency is giving ๐
the iSCSI transfer direction is defined with respect to the initiator. outbound or outgoing transfers go from an initiator to a target, while inbound or incoming transfers go from a target to an initiator ๐
an iSCSI task is an iSCSI request for which a response is expected ๐
in this document, "iSCSI request", "iSCSI command", request, and (unqualified) command all mean the same thing. also, unless otherwise specified, status, response, and numbered response mean the same thing too ๐ซถ
3.2.1. Layers and Sessions
the following conceptual layering model is used to specify initiator and target actions, and how they relate to the PDUs that get sent and received ๐ง
a) the SCSI layer builds and receives SCSI CDBs (Command Descriptor Blocks), and passes them along with the remaining command execute parameters ([SAM2]) to and from
b) the iSCSI layer, which builds and receives iSCSI PDUs and relays them to and from one or more TCP connections. the group of connections forms an initiator-target "session" ๐
communication between the initiator and target happens over one or more TCP connections. those TCP connections carry control messages, SCSI commands, parameters, and data inside iSCSI Protocol Data Units (iSCSI PDUs) ๐ฆ the group of TCP connections that link an initiator with a target forms a session (loosely equivalent to a SCSI I_T nexus, see Section 3.4.2 SCSI Architecture Model). a session is defined by a session ID made up of an initiator part and a target part. TCP connections can be added to and removed from a session, and each connection within a session is identified by a connection ID (CID) ๐ฅ
across all connections within a session, an initiator sees one "target image". all target identifying elements, such as LUN, stay the same. a target also sees one "initiator image" across all connections in a session. initiator identifying elements, such as the Initiator Task Tag, are global across the session no matter which connection they're sent or received on ๐
iSCSI targets and initiators MUST support at least one TCP connection and MAY support several connections in a session. for error recovery, targets and initiators that support a single active connection in a session SHOULD support two connections during recovery ๐ ๏ธ ๐
3.2.2. Ordering and iSCSI Numbering โจ
okay so iSCSI runs three numbering systems at once ๐ง: Command, Status, and Data sequencing. each one has its own job, bestie ๐
Command numbering is session-wide ๐ and keeps commands in order even when they're spread across multiple connections. it can also act as a way to control command flow over a session.
Status numbering is per connection ๐ธ. it helps spot missing statuses and recover from errors, whether they're temporary glitches or permanent breaks.
Data sequencing is per command, or per part of a command (the R2T triggered sequence) ๐ฆ. it catches missing data and missing R2T PDUs, including ones lost to header digest errors.
usually, fields inside the iSCSI PDUs carry these sequence numbers back and forth between the initiator and target ๐. and when traffic only flows one way on a connection, iSCSI NOP-Out/In PDUs may be used to keep the command and status counters on the target and initiator in sync ๐ซถ
the iSCSI session is basically the same thing as the SCSI I_T nexus โจ, and it gives you ordered command delivery from the SCSI initiator to the SCSI target ๐. if you want the deep design reasons behind the session model, and how it links up with SCSI command ordering, go read [CORD] ๐ค
3.2.2.1. Command Numbering and Acknowledging ๐
iSCSI does ordered command delivery inside a session ๐. every command (initiator-to-target PDU) on its way from the initiator to the target gets a number ๐ข
the target creates a task for every request the initiator sends ๐ง. a bunch of task management operations, including abort and reassign (see Section 10.5 Task Management Function Request), can be run on any iSCSI task ๐
some iSCSI tasks are SCSI tasks, and lots of SCSI activity is tied to a SCSI task ([SAM2]). either way, the task is identified by the Initiator Task Tag for its whole life ๐ท๏ธ
the command number rides along in the iSCSI PDU as CmdSN (Command Sequence Number) ๐. it's session-wide, and every outgoing iSCSI PDU carries it. the iSCSI initiator hands out CmdSN values from a 32-bit unsigned counter (modulo 2**32) ๐ข. comparisons and arithmetic on CmdSN use Serial Number Arithmetic as defined in [RFC1982] where SERIAL_BITS = 32 ๐ค
commands meant for immediate delivery get marked with an immediate delivery flag ๐ฅ. they MUST also carry the current CmdSN. and CmdSN does not go up after an immediate command is sent ๐
command numbering kicks off with the first login request on the first connection of a session (the leading login on the leading connection) โจ. after that, every non-immediate command gets its number bumped by 1 ๐
immediate task management commands can reach the target before the tasks they're meant to act on ๐ญ. but their CmdSN still marks where they sit in the command stream, so the initiator and target must make sure the task management commands act the way [SAM2] says. both commands and responses look like they were delivered in order, periodt ๐
whenever an outgoing PDU's CmdSN isn't set by an explicit rule, it just carries the current value of the local CmdSN variable (more on that later in this section) ๐ง
how an implementation decides to mark a PDU for immediate delivery, or how iSCSI decides that on its own, is out of scope for this document ๐
the number of immediate commands isn't limited ๐ฆ. their delivery for execution isn't acknowledged through the numbering scheme ๐. immediate commands MAY be rejected by the iSCSI target layer if it's short on resources ๐ฌ. an iSCSI target MUST be able to handle at least one immediate task management command and one immediate non-task-management iSCSI command per connection at any time ๐ซถ
quick definition ๐: in this document, "delivery for execution" means delivery to the SCSI execution engine, or to an iSCSI protocol specific execution engine (for example, text requests with public or private extension keys that involve an execution component) ๐ง . apart from the commands marked for immediate delivery, the iSCSI target layer MUST deliver commands for execution in the order given by CmdSN ๐. immediate commands can be handed off for execution as soon as they're detected โก. iSCSI can hold back some commands from the SCSI target layer when a prior SCSI or iSCSI action requires it (for example, a CLEAR TASK SET Task Management request that shows up before all the commands it's supposed to act on) ๐
on any connection, the iSCSI initiator MUST send commands in increasing order of CmdSN, except for commands being retransmitted because of digest error recovery and connection recovery ๐
for the numbering mechanism, the initiator and target each keep these three variables per session ๐ง:
CmdSN- the current command Sequence Number ๐. it goes up by 1 on each command shipped, except for commands marked for immediate delivery.CmdSNalways holds the number that gets assigned to the next Command PDU.ExpCmdSN- the next command the target expects ๐ธ. the target acknowledges every command up to, but not including, this number. the initiator treats every command with aCmdSNbelowExpCmdSNas acknowledged. the target iSCSI layer setsExpCmdSNto the largest non-immediateCmdSNit can deliver for execution, plus 1 (no holes in theCmdSNsequence) โจMaxCmdSN- the maximum number that can be shipped ๐ข. the queuing capacity of the receiving iSCSI layer isMaxCmdSN - ExpCmdSN + 1๐งบ
the initiator's ExpCmdSN and MaxCmdSN come from target-to-initiator PDU fields ๐ฌ. comparisons and arithmetic on ExpCmdSN and MaxCmdSN MUST use Serial Number Arithmetic as defined in [RFC1982] where SERIAL_BITS = 32 ๐ค
the target MUST NOT send aMaxCmdSNthat is less thanExpCmdSN-1๐ซ. for non-immediate commands, theCmdSNfield can be any value fromExpCmdSNtoMaxCmdSNinclusive ๐ฏ. the target MUST silently ignore any non-immediate command outside of this range, or any non-immediate duplicates inside the range ๐ซฅ. theCmdSNon immediate commands may fall outside theExpCmdSNtoMaxCmdSNrange ๐ฆ
for example, if the initiator has already sent a non-immediate command with CmdSN equal to MaxCmdSN, then the target window is closed ๐ช. for group task management commands sent as immediate commands, CmdSN shows the scope of the group action (for example, an ABORT TASK SET shows which commands get aborted) ๐งน
the initiator handles the MaxCmdSN and ExpCmdSN fields like this ๐
:
- if the PDU
MaxCmdSNis less than the PDUExpCmdSN-1(in the Serial Arithmetic sense), both get ignored ๐ โโ๏ธ - if the PDU
MaxCmdSNis greater than the localMaxCmdSN(in the Serial Arithmetic sense), it updates the localMaxCmdSN. otherwise, it gets ignored ๐ - if the PDU
ExpCmdSNis greater than the localExpCmdSN(in the Serial Arithmetic sense), it updates the localExpCmdSN. otherwise, it gets ignored ๐
this sequence is needed because updates can show up out of order (for example, when the updates get sent on different TCP connections) ๐
iSCSI initiators and targets MUST support the command numbering scheme ๐.
a numbered iSCSI request keeps its CmdSN no matter how many times, or in what circumstances, it gets reissued (see Section 6.2.1 Usage of Retry) ๐. at the target, CmdSN only matters while the command hasn't created any state tied to its execution (execution state). after that, CmdSN stops mattering ๐. checking for the execution state (found by identifying the Initiator Task Tag) MUST come before any other action at the target ๐. if no execution state is found, ordering and delivery come next. if an execution state is found, delivery comes next ๐
if an initiator retries a command withCmdSNR on a connection while the sessionCmdSNvalue is Q, it MUST NOT advanceCmdSNpastR + 2**31 -1๐. the only exceptions are when the connection is no longer operational (meaning it has gone back to the FREE state, see Section 7.1.3 Standard Connection State Diagram for an Initiator), when the connection has been reinstated (see Section 5.3.4 Connection Reinstatement), or when a non-immediate command withCmdSNequal to or greater than Q was issued after the command retry on the same connection and the target has acknowledged its reception (see Section 9.4 Command Retry and Cleaning Old Command Instances) ๐
a target MUST NOT issue a command response or Data-In PDU with status before it acknowledges the command ๐ โโ๏ธ. the acknowledgement can ride inside the response or Data-In PDU though ๐
3.2.2.2. Response/Status Numbering and Acknowledging ๐ธ
responses going from the target back to the initiator are numbered too ๐ฆ. the StatSN (Status Sequence Number) does this job ๐ข. StatSN is a counter kept per connection. the initiator uses ExpStatSN to acknowledge status ๐ซถ. the status sequence number space is 32-bit unsigned-integers, and the arithmetic is regular mod(2**32) arithmetic ๐งฎ
status numbering starts with the Login response to the first Login request on the connection. the Login response includes an initial value for status numbering (any initial value is valid) โจ
to make command recovery possible, the target MAY keep enough state information for data and status recovery after a connection failure ๐ง . a target that does this can safely throw out all the state it kept for recovering a command once the status for that command (numbered StatSN) gets acknowledged through ExpStatSN ๐๏ธ
a big absolute difference between StatSN and ExpStatSN may mean the connection has failed ๐จ. initiators MUST start recovery actions if the difference is greater than an implementation defined constant that MUST NOT exceed 2**31-1 ๐ฌ
initiators and targets MUST support the response-numbering scheme ๐.
3.2.2.3. Data Sequencing ๐งฉ
Data and R2T PDUs that are transferred as part of some command execution MUST be sequenced ๐. the DataSN field handles data sequencing ๐ข. for input (read) data PDUs, DataSN starts at 0 for the first data PDU of an input command and goes up by 1 for each data PDU after that ๐. for output data PDUs, DataSN starts at 0 for the first data PDU of a sequence (the initial unsolicited sequence, or any data PDU sequence sent to satisfy an R2T) and goes up by 1 for each data PDU after that โ๏ธ
R2Ts are sequenced per command too ๐. for example, the first R2T has an R2TSN of 0 and goes up by 1 for each R2T after it ๐งฎ. for bidirectional commands, the target uses the DataSN/R2TSN to sequence Data-In and R2T PDUs in one continuous, undifferentiated sequence ๐
unlike command and status, data PDUs and R2Ts don't get acknowledged by a field in regular outgoing PDUs ๐. Data-In PDUs can be acknowledged on demand by a special form of the SNACK PDU ๐. data and R2T PDUs are implicitly acknowledged by the status for the command ๐ซถ. the DataSN/R2TSN field lets the initiator spot missing data or R2T PDUs ๐ต๏ธโโ๏ธ
for any read or bidirectional command, a target MUST issue fewer than 2**32 combined R2T and Data-In PDUs ๐ข. any output data sequence MUST contain fewer than 2**32 Data-Out PDUs ๐
3.2.3. iSCSI Login โจ
okay so the whole point of the iSCSI login is to get a TCP connection ready for iSCSI business ๐. It handles authentication of both parties, negotiates the session's parameters, and marks the connection as part of an iSCSI session ๐ .
A session is how a target keeps track of all the connections from one initiator that belong to the same I_T nexus ๐ฆ. (For the deets on how a session relates to an I_T nexus, check Section 3.4.2 SCSI Architecture Model.)
Targets listen on a well-known TCP port (or some other TCP port) for incoming connections. The initiator starts the login by connecting to one of those ports ๐ง.
As part of login, the initiator and target SHOULD authenticate each other, and they MAY set a security association protocol for the session. There are lots of ways to do this and it's all negotiable ๐ซถ.
To protect the TCP connection, an IPsec security association MAY be established before the Login request. For info on using IPsec security with iSCSI, see Chapter 8 and [RFC3723] ๐.
The iSCSI Login Phase runs on Login requests and responses. Once suitable authentication has happened and the operational parameters are set, the session moves to the Full Feature Phase and the initiator can start sending SCSI commands ๐. Whether and how a target decides to authorize an initiator is a security policy call that's beyond this document ๐. For a more detailed look at the Login Phase, see Chapter 5.
The login PDU includes the ISID part of the session ID (SSID) ๐. The target portal group that handles the login is implied by which connection endpoint you hit. For a new session, the TSIH is zero, and the target generates a TSIH as part of the response โจ.
During session establishment, the target identifies the SCSI initiator port (the "I" in the "I_T nexus") with the value pair (InitiatorName, ISID). We'll get to InitiatorName later in this section ๐. Any persistent state on the target tied to a SCSI initiator port (like persistent reservations) is identified using this pair. Any state tied to the SCSI target port (the "T" in the "I_T nexus") is identified externally by the TargetName and portal group tag (see Section 3.4.1 iSCSI Architecture Model). ISID is subject to reuse restrictions because it's used to identify persistent state (see Section 3.4.3 Consequences of the Model) ๐ง .
Before the Full Feature Phase is established, only Login Request and Login Response PDUs are allowed. Login requests and responses MUST be used exclusively during Login. On any connection, the login phase MUST immediately follow TCP connection establishment, and a subsequent Login Phase MUST NOT occur before tearing down a connection ๐ซ.
A target that receives any PDU except a Login request before the Login phase has started MUST immediately terminate the connection on which the PDU was received. Once the Login phase has started, if the target receives any PDU except a Login request, it MUST send a Login reject (with Status "invalid during login") and then disconnect. If the initiator receives any PDU except a Login response, it MUST immediately terminate the connection ๐.
3.2.4. iSCSI Full Feature Phase ๐
Once the initiator is authorized to do so, the iSCSI session is in the iSCSI Full Feature Phase ๐. A session is in Full Feature Phase after successfully finishing the Login Phase on the first (leading) connection of a session. A connection is in Full Feature Phase if the session is in Full Feature Phase and the connection login has completed successfully.
An iSCSI connection is NOT in Full Feature Phase in either of these cases:
- a) when it does not have an established transport connection,
OR
- b) when it has a valid transport connection, but a successful login was not performed or the connection is currently logged out.
In a normal Full Feature Phase, the initiator may send SCSI commands and data to the various LUs on the target by wrapping them in iSCSI PDUs that go over the established iSCSI session ๐ .
3.2.4.1. Command Connection Allegiance ๐
For any iSCSI request issued over a TCP connection, the corresponding response and/or other related PDU(s) MUST be sent over the same connection. We call this "connection allegiance" ๐ฆ. If the original connection fails before the command is completed, the connection allegiance of the command may be explicitly reassigned to a different transport connection, as described in detail in Section 6.2 Retry and Reassign in Recovery ๐.
So, if an initiator issues a READ command, the target MUST send the requested data, if any, followed by the status to the initiator over the same TCP connection that was used to deliver the SCSI command. If an initiator issues a WRITE command, the initiator MUST send the data, if any, for that command over the same TCP connection that was used to deliver the SCSI command. The target MUST return Ready To Transfer (R2T), if any, and the status over the same TCP connection that was used to deliver the SCSI command. Retransmission requests (SNACK PDUs) and the data and status that they generate MUST also use the same connection ๐ซถ.
However, consecutive commands that are part of a SCSI linked command-chain task (see [SAM2]) MAY use different connections ๐ง. Connection allegiance is strictly per-command and not per-task. During the iSCSI Full Feature Phase, the initiator and target MAY interleave unrelated SCSI commands, their SCSI Data, and responses over the session โจ.
3.2.4.2. Data Transfer Overview ๐
Outgoing SCSI data (initiator to target user data or command parameters) is sent as either solicited data or unsolicited data. Solicited data is sent in response to R2T PDUs. Unsolicited data can be sent as part of an iSCSI command PDU ("immediate data") or in separate iSCSI data PDUs ๐ฆ.
Immediate data is assumed to originate at offset 0 in the initiator SCSI write-buffer (outgoing data buffer). All other Data PDUs have the buffer offset set explicitly in the PDU header ๐ฏ.
An initiator may send unsolicited data up to FirstBurstLength as immediate (up to the negotiated maximum PDU length), in a separate PDU sequence, or both. All subsequent data MUST be solicited. The maximum length of an individual data PDU or the immediate part of the first unsolicited burst MAY be negotiated at login ๐ฅ.
The maximum amount of unsolicited data that can be sent with a command is negotiated at login through the FirstBurstLength key. A target MAY separately enable immediate data (through the ImmediateData key) without enabling the more general (separate data PDUs) form of unsolicited data (through the InitialR2T key) ๐ง.
Unsolicited data on write is meant to reduce the effect of latency on throughput (no R2T is needed to start sending data). Immediate data is also meant to reduce protocol overhead (both bandwidth and execution time) ๐ธ.
An iSCSI initiator MAY choose not to send unsolicited data, or to send only immediate data or FirstBurstLength bytes of unsolicited data with a command. If any non-immediate unsolicited data is sent, the total unsolicited data MUST be either FirstBurstLength, or all of the data if the total amount is less than FirstBurstLength ๐.
It's considered an error for an initiator to send unsolicited data PDUs to a target that operates in R2T mode (only solicited data is allowed) ๐ . It's also an error for an initiator to send more unsolicited data, whether immediate or as separate PDUs, than FirstBurstLength ๐.
An initiator MUST honor an R2T data request for a valid outstanding command (i.e., one carrying a valid Initiator Task Tag) and deliver all the requested data, provided the command is supposed to deliver outgoing data and the R2T specifies data within the command bounds. The initiator action is unspecified for receiving an R2T request that specifies data, all or part, outside of the bounds of the command ๐คทโโ๏ธ.
A target SHOULD NOT silently discard data and then request retransmission through R2T. Initiators SHOULD NOT keep track of the data transferred to or from the target (scoreboarding) ๐. SCSI targets perform residual count calculation to check how much data was actually transferred to or from the device by a command. This may differ from the amount the initiator sent and/or received, for reasons such as retransmissions and errors. Read or bidirectional commands implicitly solicit the transmission of the entire amount of data covered by the command. SCSI data packets are matched to their corresponding SCSI commands by using tags specified in the protocol ๐.
In addition, iSCSI initiators and targets MUST enforce some ordering rules. When unsolicited data is used, the order of the unsolicited data on each connection MUST match the order in which the commands on that connection are sent. Command and unsolicited data PDUs may be interleaved on a single connection as long as the ordering requirements of each are maintained. For example, command N+1 MAY be sent before the unsolicited Data-Out PDUs for command N, but the unsolicited Data-Out PDUs for command N MUST precede the unsolicited Data-Out PDUs of command N+1. A target that receives data out of order MAY terminate the session ๐จ.
3.2.4.3. Tags and Integrity Checks ๐
Initiator tags for pending commands are unique initiator-wide for a session. Target tags are not strictly specified by the protocol. It's assumed that target tags are used by the target to tag (alone or in combination with the LUN) the solicited data. Target tags are generated by the target and "echoed" by the initiator. These mechanisms are designed to accomplish efficient data delivery, along with a large degree of control over the data flow ๐.
Because the Initiator Task Tag is used to identify a task during its execution, the iSCSI initiator and target MUST verify that all other fields used in task-related PDUs have values that are consistent with the values used at task instantiation, based on the Initiator Task Tag. For example, the LUN used in an R2T PDU MUST be the same as the one used in the SCSI command PDU that instantiated the task. Using inconsistent field values is considered a protocol error ๐ซ.
3.2.4.4. Task Management ๐งโโ๏ธ
SCSI task management assumes that individual tasks and task groups can be aborted solely based on the task tags (for individual tasks) or the timing of the task management command (for task groups). It also assumes the task management action is executed synchronously, i.e., no message involving an aborted task will be seen by the SCSI initiator after receiving the task management response. In iSCSI, initiators and targets interact asynchronously over several connections. iSCSI specifies the protocol mechanism and implementation requirements needed to present a synchronous view while using an asynchronous infrastructure ๐โจ.
3.2.5. iSCSI Connection Termination ๐โจ
Okay so an iSCSI connection can end in one of two ways: a transport connection shutdown or a transport reset. Bestie, the reset is the dramatic one ๐ญ It's assumed to be an exceptional event, not the everyday exit.
A graceful shutdown happens when TCP sends FINs ๐. A graceful transport connection shutdown SHOULD only be initiated by either party when the connection is not in iSCSI Full Feature Phase. So the vibe is: say goodbye politely outside of Full Feature Phase ๐ .
Targets get a little wiggle room here. A target MAY terminate a Full Feature Phase connection on internal exception events ๐ซฃ, but it SHOULD announce the fact through an Asynchronous Message PDU. No ghosting, just announce it ๐ฃ. And heads up: connection termination with outstanding commands may require recovery actions ๐
If a connection gets terminated while it's in Full Feature Phase, connection cleanup (see section 7) is required before recovery starts ๐งน. Doing the cleanup first means the initiator and target won't receive stale PDUs after recovery. Main character energy is cleaning up before the sequel ๐ฆ
3.2.6. iSCSI Names ๐ท๏ธ
Both targets and initiators need names so they can be identified ๐ชช. Names also let iSCSI storage resources be managed no matter where they live (their address). Fun fact: an iSCSI node name is also the SCSI device name of an iSCSI device ๐ง. The iSCSI name of a SCSI device is the principal object used in authentication, meaning targets authenticate initiators and initiators authenticate targets with it ๐. It's also how you identify and manage storage resources ๐
iSCSI names have to be unique within the operational domain of the end user. But an IP network's operational domain can be worldwide, so the name formats are built to be worldwide unique ๐. To help naming authorities build worldwide unique names, iSCSI gives them two name formats for different kinds of naming authorities ๐
Names are tied to iSCSI nodes, not to network adapter cards ๐. This way, swapping out a NIC doesn't mean reconfiguring all the SCSI and iSCSI resource allocation info. Iconic, honestly ๐ค
Some SCSI commands need protocol-specific identifiers sent inside SCSI CDBs. For the definition of the SCSI port name/identifier for iSCSI ports, check out Section 3.4.2 SCSI Architecture Model ๐
An initiator can discover the iSCSI Target Names it has access to, plus their addresses, using the SendTargets text request, or other techniques discussed in [RFC3721] ๐
3.2.6.1. iSCSI Name Properties ๐ธ
Each iSCSI node, whether it's an initiator or a target, MUST have an iSCSI name. No exceptions, no cap ๐งข
Initiators and targets MUST support receiving iSCSI names up to the maximum length of 223 bytes ๐
The initiator MUST present both its iSCSI Initiator Name and the iSCSI Target Name it wants to connect to in the first login request of a new session or connection ๐๏ธ. The only exception is a discovery session (see Section 2.3 iSCSI Session Types). For that one, the iSCSI Initiator Name is still required, but the iSCSI Target Name MAY be omitted ๐ซถ
Now the properties. iSCSI names have these:
- a) iSCSI names are globally unique. No two initiators or targets can have the same name ๐
- b) iSCSI names are permanent. An iSCSI initiator node or target node keeps the same name for its entire lifetime ๐
- c) iSCSI names do not imply a location or address. An iSCSI initiator or target can move, or have multiple addresses. A change of address does not imply a change of name ๐
- d) iSCSI names do not rely on a central name broker. The naming authority is distributed ๐ธ๏ธ
- e) iSCSI names support integration with existing unique naming schemes ๐ค
- f) iSCSI names rely on existing naming authorities. iSCSI does not create any new naming authority ๐ โโ๏ธ
The encoding of an iSCSI name has these properties:
- a) iSCSI names use the same encoding method regardless of the underlying protocols ๐
- b) iSCSI names are relatively simple to compare. The algorithm for comparing two iSCSI names for equivalence does not rely on an external server ๐งฎ
- c) iSCSI names are made only of displayable characters. They allow international character sets but are not case sensitive. No whitespace characters are used in iSCSI names โจ
- d) iSCSI names may be transported using both binary and ASCII-based protocols ๐ฆ
An iSCSI name really names a logical software entity. It isn't tied to a port or any hardware that could get swapped out ๐ง. For example, an initiator name should name the iSCSI initiator node, not a particular NIC or HBA. When there are multiple NICs, they should generally all present the same iSCSI initiator name to the targets, since they're just paths to the same SCSI layer ๐ค๏ธ. On most operating systems, the named entity is the operating system image ๐ฅ๏ธ
Targets are the same: a target name shouldn't be tied to hardware interfaces that can change ๐ โโ๏ธ. A target name should identify the logical target and must be the same no matter which physical portion is being addressed. That's how initiators figure out that the two targets they discovered are really two paths to the same target ๐งฉ
The iSCSI name is designed to meet the functional requirements for Uniform Resource Names (URN) [RFC1737] ๐. So the name needs global scope, has to be independent of address or location, and has to be persistent and globally unique. Names must be extensible and scalable with naming authorities. The name encoding should be readable by both humans and machines ๐ค. Check [RFC1737] for more requirements ๐
3.2.6.2. iSCSI Name Encoding ๐ค
An iSCSI name MUST be a UTF-8 encoding of a string of Unicode characters with these properties:
- It is in Normalization Form C (see "Unicode Normalization Forms" [UNICODE]).
- It only contains characters allowed by the output of the iSCSI stringprep template (described in [RFC3722]).
- The following characters are used for formatting iSCSI names:
- dash (
'-'=U+002d) - dot (
'.'=U+002e) - colon (
':'=U+003a)
- dash (
- The UTF-8 encoding of the name is not larger than 223 bytes.
The stringprep process is described in [RFC3454], and iSCSI's use of it is described in [RFC3722] ๐. Stringprep is a method the Internationalized Domain Name (IDN) working group designed to turn human-typed strings into something you can compare as opaque strings ๐ . Strings MUST NOT include punctuation, spacing, diacritical marks, or other characters that could get in the way of readability ๐ซ. Stringprep also converts strings into equivalent lower-case strings ๐ก
The stringprep process doesn't need to be implemented if names are only generated using numeric and lower-case alphabetic characters (any character set) ๐
Once iSCSI names encoded in UTF-8 are "normalized", they can be safely compared byte-for-byte ๐ฅฐ
3.2.6.3. iSCSI Name Structure ๐งฑ
An iSCSI name has two parts: a type designator followed by a unique name string ๐
The iSCSI name doesn't define any new naming authorities. Instead, it supports two existing ways of designating them: an iSCSI-Qualified Name, which uses domain names to identify a naming authority, and the EUI format, where the IEEE Registration Authority helps form worldwide unique names (EUI-64 format) ๐
The type designator strings currently defined are:
iqn.- iSCSI Qualified nameeui.- Remainder of the string is an IEEE EUI-64 identifier, in ASCII-encoded hexadecimal.
These two naming authority designators were considered sufficient when this document was written. Additional naming type designators for iSCSI may be considered by the IETF and detailed in separate RFCs ๐ฎ
3.2.6.3.1. Type "iqn." (iSCSI Qualified Name) ๐
Any organization that owns a domain name can use this iSCSI name type ๐ข. It's super useful when an end user or service provider wants to assign iSCSI names for targets and/or initiators ๐
To generate names of this type, the person or organization generating the name must own a registered domain name. The domain name doesn't have to be active, and it doesn't have to resolve to an address. It just needs to be reserved so nobody else can generate iSCSI names with the same domain name ๐
Here's the tea: a domain name can expire, get acquired by another entity, or even be used by both owners to generate iSCSI names. So the domain name also has to be qualified by a date during which the naming authority owned it. That's why there's a date code in the iqn. format ๐
The iSCSI qualified name string consists of:
- The string
iqn., used to tell these names apart fromeui.formatted names. - A date code in yyyy-mm format. This date MUST be a date during which the naming authority owned the domain name used in this format, and SHOULD be the first month the naming authority owned the domain name, at 00:01 GMT on the first day of that month. The date code uses the Gregorian calendar. All four digits of the year must be present. Both digits of the month must be present, with January == "01" and December == "12". The dash must be included ๐๏ธ
- A dot
. - The reversed domain name of the naming authority (person or organization) creating this iSCSI name.
- An optional string, prefixed by a colon (
:), within the character set and length boundaries that the domain name owner thinks are appropriate. It can contain product types, serial numbers, host identifiers, or software keys (for example, it may include colons to separate organization boundaries). Apart from the colon prefix, the domain name owner can assign everything after the reversed domain name however they like. The entity that is the naming authority is responsible for making sure the iSCSI names it assigns are worldwide unique ๐ซก. For example, "Example Storage Arrays, Inc.", might own the domain name "example.com" ๐๏ธ
Here are some iSCSI qualified names that "EXAMPLE Storage Arrays, Inc." might generate ๐:
Naming String defined by
Type Date Auth "example.com" naming authority
+--++-----+ +---------+ +--------------------------------+
| || | | | | |
iqn.2001-04.com.example:storage:diskarrays-sn-a8675309
iqn.2001-04.com.example
iqn.2001-04.com.example:storage.tape1.sys1.xyz
iqn.2001-04.com.example:storage.disk2.sys1.xyz
3.2.6.3.2. Type "eui." (IEEE EUI-64 format) ๐
Okay bestie, so the IEEE Registration Authority runs a service that hands out globally unique identifiers [EUI] ๐ The EUI-64 format is what other network protocols use to build a global identifier. Fibre Channel, for example, has a method for encoding it into a WorldWideName, which is so iconic ๐ If you want to register for EUI identifiers, check out [OUI] โจ
The format is "eui." followed by an EUI-64 identifier (16 ASCII-encoded hexadecimal digits) ๐
Example iSCSI name:
Type EUI-64 identifier (ASCII-encoded hexadecimal)
+--++--------------+
| || |
eui.02004567A425678D
The IEEE EUI-64 iSCSI name format might be used when a manufacturer is already registered with the IEEE Registration Authority and uses EUI-64 formatted worldwide unique names for its products ๐ญ๐ฆ
More examples of name construction are discussed in [RFC3721] ๐
3.2.7. Persistent State ๐ธ
iSCSI does not require any persistent state maintenance across sessions. Lowkey a relief, right? ๐ However, in some cases, SCSI requires persistent identification of the SCSI initiator port name (See Section 3.4.2 SCSI Architecture Model and Section 3.4.3 Consequences of the Model) ๐ง
iSCSI sessions do not persist through power cycles and boot operations ๐๐
All iSCSI session and connection parameters are re-initialized upon session and connection creation. Fresh start every time, no cap โจ
Commands persist beyond connection termination if the session persists and command recovery within the session is supported. However, when a connection is dropped, command execution, as perceived by iSCSI (i.e., involving iSCSI protocol exchanges for the affected task), is suspended until a new allegiance is established by the 'task reassign' task management function. (See Section 10.5 Task Management Function Request.) ๐ซถ
3.2.8. Message Synchronization and Steering ๐ง
iSCSI presents a mapping of the SCSI protocol onto TCP. This encapsulation is accomplished by sending iSCSI PDUs of varying lengths. Unfortunately, TCP does not have a built-in mechanism for signaling message boundaries at the TCP layer ๐ญ iSCSI gets around this by placing the message length in the iSCSI message header. This serves to delineate the end of the current message as well as the beginning of the next message. Main character energy ๐
In situations where IP packets are delivered in order from the network, iSCSI message framing is not an issue and messages are processed one after the other. In the presence of IP packet reordering (i.e., frames being dropped), legacy TCP implementations store the "out of order" TCP segments in temporary buffers until the missing TCP segments arrive, upon which the data must be copied to the application buffers. In iSCSI, it is desirable to steer the SCSI data within these out of order TCP segments into the pre-allocated SCSI buffers rather than store them in temporary buffers. This decreases the need for dedicated reassembly buffers as well as the latency and bandwidth related to extra copies ๐ฅ
Relying solely on the "message length" information from the iSCSI message header may make it impossible to find iSCSI message boundaries in subsequent TCP segments due to the loss of a TCP segment that contains the iSCSI message length. The missing TCP segment(s) must be received before any of the following segments can be steered to the correct SCSI buffers (due to the inability to determine the iSCSI message boundaries). Since these segments cannot be steered to the correct location, they must be saved in temporary buffers that must then be copied to the SCSI buffers ๐
Different schemes can be used to recover synchronization. To make these schemes work, iSCSI implementations have to make sure that the appropriate protocol layers are provided with enough information to implement a synchronization and/or data steering mechanism. One of these schemes is detailed in Appendix A. - Sync and Steering with Fixed Interval Markers -. ๐
The Fixed Interval Markers (FIM) scheme works by inserting markers in the payload stream at fixed intervals that contain the offset for the start of the next iSCSI PDU ๐
Under normal circumstances (no PDU loss or data reception out of order), iSCSI data steering can be accomplished by using the identifying tag and the data offset fields in the iSCSI header in addition to the TCP sequence number from the TCP header. The identifying tag helps associate the PDU with a SCSI buffer address while the data offset and TCP sequence number are used to determine the offset within the buffer ๐ฏ
When the part of the TCP data stream containing an iSCSI PDU header is delayed or lost, markers may be used to minimize the damage as follows:
- Markers indicate where the next iSCSI PDU starts and enable continued processing when iSCSI headers have to be dropped due to data errors discovered at the iSCSI level (e.g., iSCSI header CRC errors). ๐ฉน
- Markers help minimize the amount of data that has to be kept by the TCP/iSCSI layer while waiting for a late TCP packet arrival or recovery, because later they might help find iSCSI PDU headers and use the information contained in those to steer data to SCSI buffers. ๐
3.2.8.1. Sync/Steering and iSCSI PDU Length ๐
When a large iSCSI message is sent, the TCP segment(s) that contain the iSCSI header may be lost. The remaining TCP segment(s), up to the next iSCSI message, must be buffered (in temporary buffers) because the iSCSI header that indicates to which SCSI buffers the data are to be steered was lost ๐ฉ To minimize the amount of buffering, it is recommended that the iSCSI PDU length be restricted to a small value (perhaps a few TCP segments in length). During login, each end of the iSCSI session specifies the maximum iSCSI PDU length it will accept ๐ซถ
3.3. iSCSI Session Types ๐
iSCSI defines two types of sessions:
a) Normal operational session - an unrestricted session. b) Discovery-session - a session only opened for target discovery. The target MUST ONLY accept text requests with the SendTargets key and a logout request with the reason "close the session". All other requests MUST be rejected.
The session type is defined during login with the key=value parameter in the login command ๐
3.4. SCSI to iSCSI Concepts Mapping Model โจ
The following diagram shows an example of how multiple iSCSI Nodes (targets in this case) can coexist within the same Network Entity and can share Network Portals (IP addresses and TCP ports). Other more complex configurations are also possible. For detailed descriptions of the components of these diagrams, see Section 3.4.1 iSCSI Architecture Model ๐งฉ
+-----------------------------------+
| Network Entity (iSCSI Client) |
| |
| +-------------+ |
| | iSCSI Node | |
| | (Initiator) | |
| +-------------+ |
| | | |
| +--------------+ +--------------+ |
| |Network Portal| |Network Portal| |
| | 10.1.30.4 | | 10.1.40.6 | |
+-+--------------+-+--------------+-+
| |
| IP Networks |
| |
+-+--------------+-+--------------+-+
| |Network Portal| |Network Portal| |
| | 10.1.30.21 | | 10.1.40.3 | |
| | TCP Port 3260| | TCP Port 3260| |
| +--------------+ +--------------+ |
| | | |
| ----------------- |
| | | |
| +-------------+ +--------------+ |
| | iSCSI Node | | iSCSI Node | |
| | (Target) | | (Target) | |
| +-------------+ +--------------+ |
| |
| Network Entity (iSCSI Server) |
+-----------------------------------+
3.4.1. iSCSI Architecture Model โจ
okay so this part is the bit of the iSCSI architecture model that matters most for how iSCSI lines up with the SCSI Architecture Model ๐ง ๐
a) Network Entity ๐ - this is a device or gateway you can reach from the IP network. A Network Entity must have one or more Network Portals (see item d), and each portal can be used by some of the iSCSI Nodes (see item b) inside that Network Entity to get onto the IP network.
b) iSCSI Node ๐ฆ - this is one single iSCSI initiator or iSCSI target. There are one or more iSCSI Nodes inside a Network Entity. The iSCSI Node can be reached through one or more Network Portals (see item d). Each iSCSI Node is identified by its iSCSI Name (see Section 3.2.6 iSCSI Names and Chapter 12). Keeping the iSCSI Name separate from the addresses the node uses is the whole trick, because it lets several iSCSI nodes share the same addresses and lets one iSCSI node use several addresses ๐โจ
c) An alias string can also be attached to an iSCSI Node ๐ท๏ธ It lets an organization pair a friendly, human-readable string with the iSCSI Name. BUT the alias is NOT a replacement for the iSCSI Name, so don't mix them up bestie ๐
d) Network Portal ๐ช - this is a piece of a Network Entity that has a TCP/IP network address. An iSCSI Node inside that Network Entity may use it for the connection(s) within one of its iSCSI sessions. On an initiator, it's identified by its IP address. On a target, it's identified by its IP address plus its listening TCP port ๐
e) Portal Groups ๐ง - iSCSI supports multiple connections inside the same session, and some implementations can combine connections in a session across several Network Portals. A Portal Group is a set of Network Portals inside an iSCSI Node that together can coordinate a session with connections spanning those portals. Not every Network Portal in a Portal Group has to take part in every session that goes through that Portal Group. One or more Portal Groups may provide access to an iSCSI Node. Every Network Portal, as used by a given iSCSI Node, belongs to exactly one portal group inside that node. Portal Groups are identified inside an iSCSI Node by a portal group tag, which is a simple unsigned integer between 0 and 65535 (see Section 12.3 SendTargets). All Network Portals sharing the same portal group tag within a given iSCSI Node are in the same Portal Group ๐
Both iSCSI Initiators and iSCSI Targets have portal groups, but only the iSCSI Target Portal Groups get used directly in the iSCSI protocol (for example, in SendTargets). For references to the initiator Portal Groups, see Section 9.1.1 Conservative Reuse of ISIDs ๐ธ
f) Portals inside a Portal Group should support similar session parameters, because they might end up taking part in a shared session ๐ซถ
Here's a diagram of one such setup on a target, and how a session that shares Network Portals within a Portal Group can get established ๐
----------------------------IP Network---------------------
| | |
+----|---------------|-----+ +----|---------+
| +---------+ +---------+ | | +---------+ |
| | Network | | Network | | | | Network | |
| | Portal | | Portal | | | | Portal | |
| +--|------+ +---------+ | | +---------+ |
| | | | | | |
| | Portal | | | | Portal |
| | Group 1 | | | | Group 2 |
+--------------------------+ +--------------+
| | |
+--------|---------------|--------------------|--------------------+
| | | | |
| +----------------------------+ +-----------------------------+ |
| | iSCSI Session (Target side)| | iSCSI Session (Target side) | |
| | | | | |
| | (TSIH = 56) | | (TSIH = 48) | |
| +----------------------------+ +-----------------------------+ |
| |
| iSCSI Target Node |
| (within Network Entity, not shown) |
+------------------------------------------------------------------+
3.4.2. SCSI Architecture Model ๐
okay this section explains how the SCSI Architecture Model [SAM2] lines up with the SCSI device, SCSI port and I_T nexus constructs, and with the iSCSI constructs from Section 3.4.1 iSCSI Architecture Model ๐
This relationship creates some implementation requirements so you can actually conform to the SAM2 model and the other SCSI operational functions. Those requirements get spelled out in Section 3.4.3 Consequences of the Model ๐ง
Here's the list of how SCSI architectural elements map onto iSCSI ๐
a) SCSI Device ๐ค - this is the SAM2 term for an entity that holds one or more SCSI ports connected to a service delivery subsystem and supports a SCSI application protocol. For example, a SCSI Initiator Device has one or more SCSI Initiator Ports and zero or more application clients. A SCSI Target Device has one or more SCSI Target Ports and one or more logical units. For iSCSI, the SCSI Device is the component inside an iSCSI Node that provides the SCSI functionality. So there can be ONE SCSI Device, at most, inside an iSCSI Node. Access to the SCSI Device can only be achieved in an iSCSI normal operational session (see Section 3.3 iSCSI Session Types). The SCSI Device Name is defined to be the iSCSI Name of the node, and it MUST be used in the iSCSI protocol ๐
b) SCSI Port ๐ - this is the SAM2 term for an entity inside a SCSI Device that provides the SCSI functionality needed to interface with a service delivery subsystem or transport. For iSCSI, the definitions of SCSI Initiator Port and SCSI Target Port are different ๐
SCSI Initiator Port: this maps to one endpoint of an iSCSI normal operational session (see Section 3.3 iSCSI Session Types). An iSCSI normal operational session gets negotiated through the login process between an iSCSI initiator node and an iSCSI target node. When that process finishes successfully, a SCSI Initiator Port gets created inside the SCSI Initiator Device. The SCSI Initiator Port Name and the SCSI Initiator Port Identifier are both defined to be the iSCSI Initiator Name together with (a) a label that marks it as an initiator port name/identifier and (b) the ISID portion of the session identifier ๐
SCSI Target Port: this maps to an iSCSI Target Portal Group. The SCSI Target Port Name and the SCSI Target Port Identifier are both defined to be the iSCSI Target Name together with (a) a label that marks it as a target port name/identifier and (b) the portal group tag ๐
The SCSI Port Name MUST be used in iSCSI. When it shows up in SCSI parameter data, the SCSI port name MUST be encoded like this ๐
- The iSCSI Name in UTF-8 format, followed by
- a comma separator (1 byte), followed by
- the ASCII character 'i' (for SCSI Initiator Port) or the ASCII character 't' (for SCSI Target Port) (1 byte), followed by
- a comma separator (1 byte), followed by
- a text encoding as a hex-constant (see Section 5.1 Text Format) of the ISID (for SCSI initiator port) or the portal group tag (for SCSI target port), including the initial 0X or 0x and the terminating null (15 bytes).
The ASCII character 'i' or 't' is the label that says whether this port is a SCSI Initiator Port or a SCSI Target Port ๐ฆ
c) I_T nexus ๐ - this is a relationship between a SCSI Initiator Port and a SCSI Target Port, according to [SAM2]. For iSCSI, that relationship is a session, defined as a relationship between an iSCSI Initiator's end of the session (the SCSI Initiator Port) and the iSCSI Target's Portal Group. The I_T nexus can be identified by combining the SCSI port names, or by the iSCSI session identifier SSID. iSCSI defines the I_T nexus identifier as the tuple (iSCSI Initiator Name + 'i' + ISID, iSCSI Target Name + 't' + Portal Group Tag) โจ
NOTE: the I_T nexus identifier is NOT equal to the session identifier (SSID). Don't mix those up bestie ๐
3.4.3. Consequences of the Model ๐
this section covers the implementation and behavioral requirements that fall out of mapping SCSI constructs onto the iSCSI constructs we just went through ๐ง Between a given SCSI initiator port and a given SCSI target port, only ONE I_T nexus (session) can exist. [SAM2] doesn't allow more than one nexus relationship (a parallel nexus). So at any given time, only one session can exist between a given iSCSI initiator node and an iSCSI target node with the same session identifier (SSID) ๐
These assumptions lead to the following conclusions and requirements ๐
ISID RULE: between a given iSCSI Initiator and iSCSI Target Portal Group (SCSI target port), there can only be one session with a given value for ISID that identifies the SCSI initiator port. See Section 10.12.5 ISID ๐
The structure of the ISID, which includes a naming authority component (see Section 10.12.5 ISID and [RFC3721]), gives you a mechanism to help comply with the ISID rule. (See Section 9.1.1 Conservative Reuse of ISIDs.) The iSCSI Initiator Node should manage the assignment of ISIDs before session initiation ๐ธ The "ISID RULE" does NOT preclude using the same ISID from the same iSCSI Initiator with different Target Portal Groups on the same iSCSI target, or on other iSCSI targets (see Section 9.1.1 Conservative Reuse of ISIDs). Allowing that would be like one SCSI Initiator Port having nexus relationships with several SCSI target ports on the same SCSI target device, or with SCSI target ports on other SCSI target devices ๐ฆ It's also possible to have several sessions with different ISIDs going to the same Target Portal Group. Each of those sessions counts as being with a different initiator, even when they all come from the same initiator device ๐ง The same ISID can be used by a different iSCSI initiator, because it's the iSCSI Name together with the ISID that identifies the SCSI Initiator Port ๐
NOTE: because of the ISID RULE and the spec for the I_T nexus identifier, two nexus with the same identifier should never exist at the same time ๐
TSIH RULE: the iSCSI Target selects a non-zero value for the TSIH at session creation (when an initiator presents a 0 value at Login). Once it's selected, the same TSIH value MUST be used whenever the initiator or target refers to the session and a TSIH is required ๐๐
3.4.3.1. I_T Nexus State โจ
okay so some nexus relationships carry explicit state, like initiator-specific mode pages ๐, and the device server [SAM2] needs to keep that state safe in a logical unit even when the iSCSI layer glitches (think session failures) ๐ญ. To get it back, the iSCSI initiator should re-login to the same Target Portal Group using the previous ISID ๐ซถ. That's session recovery, the thing Chapter 6 walks through ๐ . Why? The SCSI initiator port identifier and the SCSI target port identifier (or relative target port) together form the datum the SCSI logical unit device server uses to identify the I_T nexus. so it's literally the whole ID combo ๐
3.5. Request/Response Summary ๐
this section is the cheat sheet ๐ listing and briefly describing all the iSCSI PDU types (requests and responses).
every iSCSI PDU is built from one or more header segments (basic and auxiliary) and zero or one data segments ๐ง. the header group and the data segment may each be followed by a CRC (digest) ๐.
the basic header segment has a fixed length of 48 bytes ๐.
3.5.1. Request/Response Types Carrying SCSI Payload ๐ธ
3.5.1.1. SCSI-Command
this request carries the SCSI CDB plus all the other IN arguments for the SCSI execute command procedure call (see [SAM2]) ๐ฆ. that includes task attributes, the Expected Data Transfer Length for one or both directions (the latter for bidirectional commands), and the Task Tag (as part of the I_T_L_x nexus). the initiator and target derive the I_T_L nexus from the LUN field in the request, and the I_T nexus is implicit in the session identification ๐ซถ
the SCSI-Command PDU also carries the stuff iSCSI needs to run properly: the command sequence number (CmdSN) for the session and the expected status number (ExpStatSN) for the connection โจ
all or part of the SCSI output (write) data for the command can ride along inside the SCSI-Command PDU as a data segment ๐
3.5.1.2. SCSI-Response
the SCSI-Response carries all the OUT arguments of the SCSI execute-command procedure call (see [SAM2]) and the procedure call's return value ๐
it also holds the residual counts from the operation (if there are any), an indication of whether those counts are an overflow or an underflow, and either the SCSI status (when the status is valid) or a response code (a non-zero return value for the execute-command procedure call) when the status isn't valid ๐
for a valid status saying the command was processed but threw an exception (like a SCSI CHECK CONDITION) ๐, the data segment holds the matching sense data. Autosense ([SAM2]) is REQUIRED by iSCSI ๐ฅ
some data segment content may also go with a non-zero response code ๐
the SCSI-Response PDU also carries the iSCSI stuff that keeps things running smoothly:
- the number of Data-In PDUs that a target has sent (so the initiator can check that they all arrived) ๐
StatSN, the Status Sequence Number on this connectionExpCmdSN, the next Expected Command Sequence Number at the target ๐MaxCmdSN, the maximum CmdSN the target will accept from this initiator ๐
3.5.1.3 Task Management Function Request
the Task Management function request is how an initiator explicitly controls one or more SCSI Tasks or iSCSI functions ๐ฏ. the PDU carries a function identifier (which task management function to perform) plus enough info to unequivocally identify the task or task set to act on, even if that task hasn't arrived yet or got tossed because of an error ๐ซ
the referenced tag identifies an individual task whenever the function targets one individual task ๐ฆ
the I_T_L nexus is what identifies task sets. in iSCSI, the I_T_L nexus is identified by the LUN and the session identification (the session identifies an I_T nexus) ๐ง
for task sets, the CmdSN of the Task Management function request helps pick out the tasks to act on: all tasks associated with a LUN that have a CmdSN preceding the Task Management function request's CmdSN ๐ธ
for a Task Management function, the target handles coordinating the responses to the affected tasks and the Task Management function response โจ
3.5.1.4. Task Management Function Response
the Task Management function response tells you the function completed for a Task Management function request, including how it was completed (response and qualifier) and extra info for failure responses ๐
once the Task Management response says the function is complete, the initiator won't get any more responses from the affected tasks ๐
3.5.1.5. SCSI Data-Out and SCSI Data-In
SCSI Data-Out and SCSI Data-In are the main vehicles for moving SCSI data payload between initiator and target ๐. the payload gets tied to a specific SCSI command through the Initiator Task Tag ๐ท๏ธ. for the target's convenience, outgoing solicited data also carries a Target Transfer Tag (copied from R2T) and the LUN ๐. each PDU includes the payload length and the data offset relative to the buffer address in the SCSI execute command procedure call ๐
in each direction, the data transfer gets split into "sequences" ๐งฉ. an end-of-sequence is flagged with the F bit ๐
an outgoing sequence is either unsolicited (only the first sequence can be unsolicited) or made up of all the Data-Out PDUs sent in response to an R2T ๐
input sequences are built to allow direction switching for bidirectional commands ๐
for input, the target may ask for positive acknowledgement of the input data. this only works in sessions that support error recovery, and it's done with the A bit in the SCSI Data-In PDU header ๐โโ๏ธ
Data-In and Data-Out PDUs also carry the DataSN, so the initiator and target can spot missing PDUs (the ones discarded because of an error) ๐
Data-In PDUs also carry StatSN ๐
to get a SCSI command done with as few messages as possible, the last SCSI Data-In PDU for a command may also carry the status, as long as the status means termination with no exceptions (no sense or response involved) ๐
3.5.1.6. Ready To Transfer (R2T)
R2T is how the SCSI target "requests" output data from the initiator ๐. it tells the initiator the offset of the requested data relative to the buffer address from the execute command procedure call, plus the length of the solicited data ๐
so the target can match the resulting Data-Out with an R2T, the R2T carries a Target Transfer Tag. the initiator copies that tag into the solicited SCSI Data-Out PDUs ๐ช. there are no protocol-specific requirements for what these tag values are, but it's assumed that together with the LUN, they'll let the target associate data with an R2T ๐ซถ
R2T also carries the info iSCSI needs to run properly, such as:
R2TSN(so an initiator can detect a missing R2T) ๐ต๏ธโโ๏ธStatSNExpCmdSNMaxCmdSN
3.5.2. Requests/Responses carrying SCSI and iSCSI Payload ๐ฆ
3.5.2.1. Asynchronous Message
Asynchronous Messages carry SCSI asynchronous events (AEN) and iSCSI asynchronous messages ๐ฃ
when it's carrying an AEN, the event details come through as sense data in the data segment ๐
3.5.3. Requests/Responses Carrying iSCSI Only Payload ๐
3.5.3.1. Text Request and Text Response
text requests and responses are built for parameter negotiation and as a vehicle for future extensions ๐งฉ
in the data segment, Text Requests/Responses carry text info using a simple "key=value" syntax ๐
Text Request/Responses can form extended sequences using the same Initiator Task Tag. the initiator uses the F (Final) bit in the text request header to say it's ready to end a sequence. the target uses the F (Final) bit in the text response header to say it consents to ending it ๐ค
Text Requests and Responses also use the Target Transfer Tag to signal whether an operation is continuing or starting fresh ๐. a target that wants to continue an operation sets the Target Transfer Tag in a Text Response to a value other than the default 0xffffffff. an initiator willing to continue copies that value into the Target Transfer Tag of its next Text Request. if the initiator wants to restart the current target negotiation (start fresh), it sets the Target Transfer Tag to 0xffffffff ๐
a complete exchange is always started by the initiator, but specific parameter negotiations may be started by either the initiator or the target ๐
3.5.3.2. Login Request and Login Response
Login Requests and Responses are used only during the Login Phase of each connection, to set up the session and connection parameters ๐ช. (the Login Phase is a sequence of login requests and responses carrying the same Initiator Task Tag.)
a connection is identified by an arbitrarily selected connection-ID (CID) that's unique within a session ๐
like the Text Requests and Responses, Login Requests/Responses carry key=value text info with a simple syntax in the data segment ๐
the Login Phase goes through several stages (security negotiation, operational parameter negotiation). they're picked with two binary coded fields in the header: the "current stage" (CSG) and the "next stage" (NSG). the appearance of the latter gets signaled by the "transit" flag (T) ๐ค๏ธ
the first Login Phase of a session is the leading login, and it plays a special role ๐. it determines some header fields (like the version number, the maximum number of connections, and the session identification) ๐
the leading login also sets the initial value of the CmdSN ๐ข
StatSN for each connection is initiated by the connection login ๐ฑ
a login request can imply a logout (cleanup) of the connection being logged in, which is a connection restart. to do that, it uses the same Connection ID (CID) as an existing connection, plus the same session identifying elements of the session the old connection belonged to โป๏ธ
3.5.3.3. Logout Request and Response
Logout Requests and Responses are used for the orderly closing of connections for recovery or maintenance ๐งน. the logout request can be issued after a target prompts it (through an asynchronous message) or on the initiator's own initiative ๐โโ๏ธ. when it's issued on the connection being logged out, no other request may follow it ๐ซ
the Logout Response says the connection or session cleanup is complete and no other responses will arrive on that connection (if it's received on the logging-out connection) ๐. it also tells you two things in text keys: Time2Retain, how long the target will keep holding resources for recovery (like command execution that carries on over a new connection) ๐ฐ๏ธ, and Time2Wait, how long the initiator must wait before going ahead with recovery โณ
3.5.3.4. SNACK Request ๐จ
Okay so the SNACK Request is how the initiator asks the target to resend stuff it missed ๐ฅบ. It's basically "hey bestie, you dropped some messages, can you send them again?" ๐ One SNACK request covers a contiguous set of missing items, called a run ๐งต, all of one type. The type is indicated in a type field in the PDU header ๐ท๏ธ. The run is made up of an initial item (StatSN, DataSN, or R2TSN) plus the number of missed Status, Data, or R2T PDUs. Ngl that's giving super organized ๐.
For long Data-In sequences, the target may request (at predefined minimum intervals) a positive acknowledgement for the data it sent ๐โโ๏ธ. A SNACK request with a type field that indicates ACK and the number of Data-In PDUs acknowledged is how that positive acknowledgement gets conveyed. "Got it, thank you" energy ๐.
3.5.3.5. Reject ๐ซ
Reject is how the target reports an iSCSI error condition (e.g., protocol, unsupported option) ๐ฌ. It uses a Reason field in the PDU header, and it includes the complete header of the bad PDU in the Reject PDU data segment. So basically it's the receipts ๐งพ of the drama, and they're all there.
3.5.3.6. NOP-Out Request and NOP-In Response ๐
This request/response pair may be used by an initiator and target as a "ping" ๐ to verify that a connection/session is still active and all of its components are operational ๐. Such a ping can be triggered by the initiator or the target ๐. The triggering party says "I want a reply" by setting a value different from the default 0xffffffff in the corresponding Initiator/Target Transfer Tag ๐ฏ.
NOP-In/NOP-Out may also be used "unidirectional" ๐ธ to convey command, status or data counter values to the initiator/target when there's no other "carrier" ๐ฆ and there's a need to update the initiator/target. Main character energy for sure โจ.
4. SCSI Mode Parameters for iSCSI โ๏ธ
Plot twist: there are no iSCSI specific mode pages ๐.
5. Login and Full Feature Phase Negotiation ๐ค
Okay, so iSCSI parameters get negotiated at session or connection establishment by using Login Requests and Responses (see Section 3.2.3 iSCSI Login) ๐, and during the Full Feature Phase (Section 3.2.4 iSCSI Full Feature Phase) by using Text Requests and Responses ๐ฌ. In both cases the mechanism is an exchange of iSCSI-text-key=value pairs. For brevity, iSCSI-text-keys are called just keys in the rest of this document ๐ซถ.
Keys are either declarative or require negotiation, and the key description tells you which one it is ๐ฃ.
For the declarative keys, the declaring party sets a value for the key ๐. The key specification indicates if the key can be declared by the initiator, target or both ๐.
For the keys that require negotiation, one of the parties (the proposing party) proposes a value or set of values by including the key=value in the data part of a Login or Text Request or Response PDU ๐. The other party (the accepting party) makes a selection based on the value or list of values proposed, and includes the selected value in a key=value in the data part of one of the following Login or Text Response or Request PDUs ๐
. For most of the keys, both the initiator and target can be proposing parties ๐.
The login process proceeds in two stages: the security negotiation stage and the operational parameter negotiation stage ๐ฅ. Both stages are optional, but at least one of them has to be present to enable the setting of some mandatory parameters ๐ง.
If present, the security negotiation stage precedes the operational parameter negotiation stage ๐ธ.
Progression from stage to stage is controlled by the T (Transition) bit in the Login Request/Response PDU header. Through the T bit set to 1, the initiator indicates that it would like to transition. The target agrees to the transition (and selects the next stage) when it's ready ๐ฆ. A field in the Login PDU header indicates the current stage (CSG), and during transition another field indicates the next stage (NSG) proposed (initiator) and selected (target) โจ.
The text negotiation process is used to negotiate or declare operational parameters ๐. The negotiation process is controlled by the F (final) bit in the PDU header. During text negotiations, the F bit is used by the initiator to indicate that it's ready to finish the negotiation, and by the Target to acquiesce the end of negotiation ๐.
Since some key=value pairs may not fit entirely in a single PDU, the C (continuation) bit is used (both in Login and Text) to indicate that "more follows" ๐งต.
The text negotiation uses an additional mechanism by which a target may deliver larger amounts of data to an enquiring initiator ๐. The target sets a Target Task Tag to be used as a bookmark: when it's returned by the initiator, it means "go on" ๐. If reset to a "neutral value", it means "forget about the rest" ๐.
This chapter details the types of keys and values used, the syntax rules for parameter formation, and the negotiation schemes to be used with different types of parameters ๐๐.
5.1. Text Format
okay so the initiator and target both send little bundles of key=value pairs, and those are encoded in UTF-8 Unicode ๐โจ Every text key and text value in this doc is presented and interpreted exactly as it appears here, because they're case sensitive ๐ so no capitalizing it because vibes ๐
Here's the list of character symbols that are allowed in text items (the hex values are the Unicode code points) ๐ธ
(a-z, A-Z) - letters
(0-9) - digits
" " (0x20) - space
"." (0x2e) - dot
"-" (0x2d) - minus
"+" (0x2b) - plus
"@" (0x40) - commercial at
"_" (0x5f) - underscore
"=" (0x3d) - equal
":" (0x3a) - colon
"/" (0x2f) - solidus or slash
"[" (0x5b) - left bracket
"]" (0x5d) - right bracket
null (0x00) - null separator
"," (0x2c) - comma
"~" (0x7e) - tilde
okay now the fun part ๐ฆ key=value pairs can span PDU boundaries, so one PDU can end mid-pair. If an initiator or target sends partial key=value text in a PDU, it says "more text is coming" by setting the C bit in the Text or Login Request or Text or Login Response to 1. A series of PDUs with C set to 1 that ends with a PDU where C is 0, or a single PDU with C set to 0, has to be considered as forming a single logical-text-data-segment (LTDS) โจ it's giving puzzle pieces that all snap together ๐งฉ
Every key=value pair, including the last or only pair in a LTDS, MUST be followed by one null (0x00) delimiter. no exceptions bestie ๐
Some quick vocab so we're all on the same page ๐ A key-name is whatever comes before the first "=" in the key=value pair, and the doc just calls it key for short ๐ A value is whatever comes after the first "=" up to the end of the pair, but not including the null delimiter ๐
Next up are the definitions the rest of the doc uses ๐ these are kind of grammar-ish so I'm keeping them verbatim in a code block:
standard-label: A string of one or more characters that consist of
letters, digits, dot, minus, plus, commercial at, or underscore.
A standard-label MUST begin with a capital letter and must not
exceed 63 characters.
key-name: A standard-label.
text-value: A string of zero or more characters that consist of
letters, digits, dot, minus, plus, commercial at, underscore,
slash, left bracket, right bracket, or colon.
iSCSI-name-value: A string of one or more characters that consist
of minus, dot, colon, or any character allowed by the output of
the iSCSI string-prep template as specified in [RFC3722] (see
also Section 3.2.6.2 iSCSI Name Encoding).
iSCSI-local-name-value: A UTF-8 string; no null characters are
allowed in the string. This encoding is to be used for localized
(internationalized) aliases.
boolean-value: The string "Yes" or "No".
hex-constant: A hexadecimal constant encoded as a string that
starts with "0x" or "0X" followed by one or more digits or the
letters a, b, c, d, e, f, A, B, C, D, E, or F. Hex-constants are
used to encode numerical values or binary strings. When used to
encode numerical values, the excessive use of leading 0 digits is
discouraged. The string following 0X (or 0x) represents a base16
number that starts with the most significant base16 digit,
followed by all other digits in decreasing order of significance
and ending with the least-significant base16 digit. When used to
encode binary strings, hexadecimal constants have an implicit
byte-length that includes four bits for every hexadecimal digit
of the constant, including leading zeroes. For example, a
hex-constant of n hexadecimal digits has a byte-length of (the
integer part of) (n+1)/2.
decimal-constant: An unsigned decimal number with the digit 0 or a
string of one or more digits that start with a non-zero digit.
Decimal-constants are used to encode numerical values or binary
strings. Decimal constants can only be used to encode binary
strings if the string length is explicitly specified. There is
no implicit length for decimal strings. Decimal-constant MUST
NOT be used for parameter values if the values can be equal or
greater than 2**64 (numerical) or for binary strings that can be
longer than 64 bits.
base64-constant: base64 constant encoded as a string that starts
with "0b" or "0B" followed by 1 or more digits or letters or plus
or slash or equal. The encoding is done according to [RFC2045]
and each character, except equal, represents a base64 digit or a
6-bit binary string. Base64-constants are used to encode
numerical-values or binary strings. When used to encode
numerical values, the excessive use of leading 0 digits (encoded
as A) is discouraged. The string following 0B (or 0b) represents
a base64 number that starts with the most significant base64
digit, followed by all other digits in decreasing order of
significance and ending with the least-significant base64 digit;
the least significant base64 digit may be optionally followed by
pad digits (encoded as equal) that are not considered as part of
the number. When used to encode binary strings, base64-constants
have an implicit
byte-length that includes six bits for every character of the
constant, excluding trailing equals (i.e., a base64-constant of n
base64 characters excluding the trailing equals has a byte-length
of ((the integer part of) (n*3/4)). Correctly encoded base64
strings cannot have n values of 1, 5 ... k*4+1.
numerical-value: An unsigned integer always less than 2**64 encoded
as a decimal-constant or a hex-constant. Unsigned integer
arithmetic applies to numerical-values.
large-numerical-value: An unsigned integer that can be larger than
or equal to 2**64 encoded as a hex constant, or
base64-constant. Unsigned integer arithmetic applies to
large-numeric-values.
numeric-range: Two numerical-values separated by a tilde where the
value to the right of tilde must not be lower than the value to
the left.
regular-binary-value: A binary string not longer than 64 bits
encoded as a decimal constant, hex constant, or base64-constant.
The length of the string is either specified by the key
definition or is the implicit byte-length of the encoded string.
large-binary-value: A binary string longer than 64 bits encoded as
a hex-constant or base64-constant. The length of the string is
either specified by the key definition or is the implicit
byte-length of the encoded string.
binary-value: A regular-binary-value or a large-binary-value.
Operations on binary values are key specific.
simple-value: Text-value, iSCSI-name-value, boolean-value,
numeric-value, a numeric-range, or a binary-value.
list-of-values: A sequence of text-values separated by a comma.
๐ง default size rule: unless something else says otherwise, the maximum length of a simple-value (not its encoded form) is 255 bytes, not counting the delimiter (comma or zero byte) ๐
last but definitely not least ๐ญ any iSCSI target or initiator MUST support receiving at least 8192 bytes of key=value data in a negotiation sequence. And if they're proposing or accepting authentication methods that explicitly need support for very long authentication items, the initiator and target MUST support receiving at least 64 kilobytes of key=value data. that's the Simple Public-Key Mechanism (SPKM) in Appendix 11.1.2, which needs support for public key certificates ๐ฅ it's a whole main character moment for those big certs ๐
5.2. Text Mode Negotiation โจ
okay so during login (and honestly, whenever after that) some session or connection parameters get either declared or negotiated through a little text exchange ๐ฌ๐
the initiator starts the whole thing with a Text or Login Request, and it tells the target it's ready to wrap up by setting the F bit to 1 (and keeping it at 1 in a Text Request) or the T bit in the Login Request. negotiation text can span multiple PDUs, so a Text or Login Request or Text or Login Response PDU with the C bit set to 1 MUST NOT have the F/T bit set to 1 ๐
โโ๏ธ
and then the bounce-back rules are so clean ๐ซถ a target that gets a Text or Login Request with the C bit set to 1 MUST answer with a Text or Login Response that has no data segment (DataSegmentLength 0). and an initiator that gets a Text or Login Response with the C bit set to 1 MUST answer with a Text or Login Request that has no data segment (DataSegmentLength 0).
a target or initiator SHOULD NOT send a Text or Login Response or a Text or Login Request with no data segment (DataSegmentLength 0) unless a general or key-specific negotiation rule explicitly says it has to. no empty messages just for vibes ๐
here's what a declaration looks like ๐ธ
Declarer-> <key>=<valuex>
and the general shape of a negotiation is:
Proposer-> <key>=<valuex>
Acceptor-> <key>={<valuey>|NotUnderstood|Irrelevant|Reject}
so the main difference is that a declaration is a one-way textual exchange, while a negotiation is a two-way exchange ๐ฆ
the proposer or declarer can be the initiator or the target, and the acceptor will be the target or the initiator, respectively. and targets aren't stuck just replying to whatever key=value pairs the initiator throws at them ๐ง a target is allowed to propose key=value pairs of its own, main character energy โจ
all negotiations are explicit, which means the result MUST only be based on newly exchanged or declared values. there are no implicit proposals, so if nobody proposed something, nobody can expect a reply ๐ and conservative design also says you shouldn't lean on default values when using some other value would have serious consequences. safety first, bestie ๐ก๏ธ
the value that gets proposed or declared can be a numerical-value, a numerical-range (a lower and an upper integer, separated by a tilde), a binary value, a text-value, an iSCSI-name-value, an iSCSI-local-name-value, a boolean-value (Yes or No), or a list of comma separated text-values ๐ a range, a large-numerical-value, an iSCSI-name-value, and an iSCSI-local-name-value MAY ONLY be used if they're explicitly allowed. and an accepted value can be a numerical-value, a large-numerical-value, a text-value, or a boolean-value ๐
if a key just isn't relevant to the current negotiation, the acceptor can answer with the constant "Irrelevant" for any type of negotiation. the negotiation still doesn't count as failed when the answer is "Irrelevant" ๐ this is for when a proposer sends a bunch of keys, but picking one value for one key makes the other keys pointless. here's how that looks ๐
I->T OFMarker=Yes,OFMarkInt=2048~8192
T->I OFMarker=No,OFMarkInt=Irrelevant
I->T X#vkey1=(bla,alb,None),X#vkey2=(bla,alb)
T->I X#vkey1=None,X#vkey2=Irrelevant
any key the acceptor doesn't understand can be ignored without messing up the basic function ๐ but the answer for a key it doesn't understand MUST be key=NotUnderstood. no silent ghosting allowed ๐ป
the constants "None", "Reject", "Irrelevant", and "NotUnderstood" are reserved, and they MUST ONLY be used the way this document describes. breaking that rule is a protocol error, and that specifically includes using "Reject", "Irrelevant", and "NotUnderstood" as proposed values ๐ซ๐ญ
"Reject" or "Irrelevant" are legit negotiation options where they're allowed, but using them a ton is discouraged, so don't be that person ๐ a negotiation counts as complete once the acceptor has sent the key value pair, even if the value is "Reject", "Irrelevant", or "NotUnderstood". sending the same key again would be a re-negotiation, and that's forbidden for lots of keys ๐ โโ๏ธ
if the acceptor answers with "Reject", the negotiated key just stays at its current value (or its default, if no value was ever set) ๐ and if the current value isn't acceptable to the proposer on the connection or to the session it was sent on, the proposer MAY choose to terminate the connection or session. dramatic, but valid โจ
every key in this document, except for the X extension formats, MUST be supported by iSCSI initiators and targets when it's used the way it's specified here. and if it's used as specified, these keys MUST NOT be answered with NotUnderstood. no excuses, slay ๐
now, implementers can make up new keys by prefixing them with "X-", followed by their reversed domain name, or with new keys registered with IANA by prefixing them with X#. for example, the entity that owns the domain example.com can issue something like this ๐ฆ
X-com.example.bar.foo.do_something=3
or a registered key can be used like this ๐
X#SuperCalyPhraGilistic=Yes
implementers MAY also introduce new values, but ONLY for new keys or authentication methods (see Section 11 iSCSI Security Text Keys and Authentication Methods), or digests (see Section 12.1 HeaderDigest and DataDigest). so new values aren't a free-for-all, they're only for those specific things ๐
whenever a parameter's action or acceptance depends on other parameters, the dependency rules and the parameter sequence must be specified along with those parameters ๐งฉ
in the Login Phase (see Section 5.3 Login Phase), every stage is its own separate negotiation. in the FullFeaturePhase, a Text Request and Response sequence is a negotiation. negotiations MUST be handled as atomic operations ๐ that means all the negotiated values go into effect once the negotiation concludes in agreement, or they're all ignored if the negotiation fails. it's all or nothing, bestie ๐ซถ
some parameters come with integrity rules, like "parameter-x must not exceed parameter-y" or "parameter-u not 1 implies parameter-v be Yes" ๐ง whenever it's needed, the integrity rules get specified along with the keys. and checking compliance only happens once all the parameters are available, both the existing ones and the newly negotiated ones. an iSCSI target MUST perform integrity checking before the new parameters take effect, and an initiator MAY perform integrity checking too ๐
finally, an iSCSI initiator or target MAY end a negotiation that doesn't wrap up within a reasonable time or number of exchanges. no one's waiting around forever ๐ญโฐ
5.2.1. List negotiations
in list negotiation, the originator sends a list of values (which can include "None") ordered by its preference ๐
the responding party MUST answer with the same key and the first value it supports (and is allowed to use with that specific originator), picked from the originator's list ๐ฏ the constant "None" MUST always be used to indicate a missing function. however, "None" is only a valid selection if it was explicitly proposed ๐
if the acceptor doesn't understand a particular value in the list, it MUST ignore that value ๐ and if the acceptor doesn't support, doesn't understand, or isn't allowed to use any of the proposed options with that specific originator, it may answer with the constant "Reject" or terminate the negotiation ๐ selecting a value that was never proposed MUST be handled as a protocol error. no sneaky picks, periodt ๐
5.2.2. Simple-value Negotiations
for simple-value negotiations, the accepting party MUST answer with the same key, and the value it picks becomes the negotiation result ๐ธ
if someone proposes a value that isn't admissible (like one that's outside the specified bounds), that MAY be answered with the constant "Reject", or the acceptor MAY pick an admissible value instead ๐ฆ but if the acceptor selects a value that isn't admissible under the selection rules, that's a protocol error. the selection rules are key-specific, so check the key ๐
for a numerical range, the value selected must be an integer within the proposed range, or it's "Reject" (if the range is unacceptable) ๐
in Boolean negotiations (the ones that end up with keys taking the values Yes or No), the accepting party MUST answer with the same key and the result of the negotiation whenever the received value doesn't determine that result by itself. the last value transmitted becomes the negotiation result ๐ the rules for choosing what to answer with are written as Boolean functions of the value received, plus the value the accepting party would have picked if it had a choice. it's giving logic, honestly ๐ง
specifically, the two cases where answers are OPTIONAL are:
- The Boolean function is "AND" and the value "No" is received. The outcome of the negotiation is "No".
- The Boolean function is "OR" and the value "Yes" is received. The outcome of the negotiation is "Yes".
everything else is REQUIRED. responses are REQUIRED in all other cases, and whatever value the acceptor chooses and sends becomes the outcome of the negotiation ๐โจ
5.3. Login Phase โจ
okay so the Login Phase is the big glow-up moment ๐ where an initiator and a target connect, either spin up a brand new session or tack a connection onto one that already exists ๐ฆ. It's where they lock in the iSCSI protocol parameters and the security parameters, and where they authenticate each other, bestie ๐
The Login Phase only happens through Login Requests and Responses ๐. The whole thing counts as one single task with one single Initiator Task Tag, kinda like those linked SCSI commands ๐
The default MaxRecvDataSegmentLength is used during Login ๐ธ
The Login Phase goes in this order:
- Login initial request
- Login partial response (optional)
- More Login Requests and Responses (optional)
- Login Final-Response (mandatory)
Now the rules, and these are important, so read carefully ๐ The initial Login Request of any connection MUST include the InitiatorName key=value pair. The initial Login Request of the first connection of a session MAY also include the SessionType key=value pair. For any connection in a session whose type is not "Discovery", the first Login Request MUST also include the TargetName key=value pair.
The Login Final-Response is the one that accepts or rejects the Login Request. That's the verdict, periodt โ๏ธ
The Login Phase MAY include a SecurityNegotiation stage, a LoginOperationalNegotiation stage, or both, but it MUST include at least one of them. Whatever stage is included MAY be empty, apart from the mandatory names ๐ง
The Login Requests and Responses have a field (CSG) that says which negotiation stage you're in, either SecurityNegotiation or LoginOperationalNegotiation. If both stages get used, the SecurityNegotiation MUST come before the LoginOperationalNegotiation. No skipping the line here ๐
Some operational parameters can also be negotiated outside of login, through Text Requests and Responses ๐
Security MUST be completely negotiated within the Login Phase. The use of underlying IPsec security is specified in Chapter 8 and in [RFC3723]. iSCSI's own in-protocol security is only authentication in the Login Phase, so that's the whole vibe ๐
In some environments, a target or an initiator just isn't interested in authenticating its counterpart. That's fine, because it's possible to bypass authentication through the Login Request and Response ๐
The initiator and target MAY want to negotiate iSCSI authentication parameters. Once that negotiation is done, the channel is considered secure โจ
Most of the negotiation keys are only allowed in one specific stage. The SecurityNegotiation keys live in Chapter 11, and the LoginOperationalNegotiation keys live in Chapter 12. Only a limited set of keys (marked as Any-Stage in Chapter 12) may be used in either stage ๐ฆ
Every Login Request or Response belongs to a specific stage, and that stage decides which negotiation keys are allowed with it. Sending a key that isn't allowed in the current stage is a protocol error, so don't do it, not me ๐ โโ๏ธ
Stage transitions happen through a command exchange (request/response) that carries the T bit and the same CSG code. During that exchange, the target picks the next stage using the "next stage" code (NSG). The selected NSG MUST NOT exceed the value the initiator stated. The initiator can ask for a transition whenever it's ready, but the target can only respond with a transition after the initiator has proposed one ๐
Each pair of Login Request-Responses has its own T bit settings, and they have no bearing on the T bit settings of the next pair. So an initiator that set T to 1 in one pair and got a T bit of 0 back is totally allowed to send the next request with T set to 0 ๐
When the initiator requests a transition and the target acknowledges it, both sides switch to the selected stage. Clean and iconic ๐
Targets MUST NOT submit parameters that require an additional initiator Login Request in a Login Response with the T bit set to 1. Don't make the initiator do extra homework ๐
Stage transitions during login (including entering and exiting) are only possible as outlined in this table, so check it before you move ๐
+-----------------------------------------------------------+
|From To -> | Security | Operational | FullFeature |
| | | | | |
| V | | | |
+-----------------------------------------------------------+
| (start) | yes | yes | no |
+-----------------------------------------------------------+
| Security | no | yes | yes |
+-----------------------------------------------------------+
| Operational | no | no | yes |
+-----------------------------------------------------------+
The Login Final-Response that accepts a Login Request can only come as a response to a Login Request with the T bit set to 1. Both the request and the response MUST indicate FullFeaturePhase as the next phase via the NSG field. That's the grand finale โจ
Neither the initiator nor the target should try to declare or negotiate a parameter more than once during login. The exception is responses to specific keys that explicitly allow repeated declarations (for example, TargetAddress). Any attempt to renegotiate or redeclare parameters that aren't specifically allowed MUST be detected by the initiator and target ๐จ. If the target catches it, the target MUST respond with Login reject (initiator error). If the initiator catches it, the initiator MUST drop the connection. Yikes, no drama allowed ๐ญ
5.3.1. Login Phase Start ๐ฆ
The Login Phase starts with a Login Request from the initiator to the target. The initial Login Request includes:
- Protocol version supported by the initiator.
- iSCSI Initiator Name and iSCSI Target Name
- ISID, TSIH, and connection Ids
- Negotiation stage that the initiator is ready to enter.
A login can create a new session, or it can add a connection to an existing session. Between a given iSCSI Initiator Node (selected only by an InitiatorName) and a given iSCSI target defined by an iSCSI TargetName and a Target Portal Group Tag, the login results are defined by this table ๐ง
+------------------------------------------------------------------+
|ISID | TSIH | CID | Target action |
+------------------------------------------------------------------+
|new | non-zero | any | fail the login |
| | | | ("session does not exist") |
+------------------------------------------------------------------+
|new | zero | any | instantiate a new session |
+------------------------------------------------------------------+
|existing | zero | any | do session reinstatement |
| | | | (see section 5.3.5) |
+------------------------------------------------------------------+
|existing | non-zero | new | add a new connection to |
| | existing | | the session |
+------------------------------------------------------------------+
|existing | non-zero |existing| do connection reinstatement|
| | existing | | (see section 5.3.4) |
+------------------------------------------------------------------+
|existing | non-zero | any | fail the login |
| | new | | ("session does not exist") |
+------------------------------------------------------------------+
Whether something counts as "existing" or "new" is decided by the target ๐ต๏ธโโ๏ธ
The Login Request can optionally include any of the following:
- Security parameters OR
- iSCSI operational parameters AND/OR
- The next negotiation stage that the initiator is ready to enter.
The target can answer the login in these ways:
- Login Response with Login reject. This is an immediate rejection from the target. It makes the connection terminate, and it makes the session terminate too if this is the first (or only) connection of a new session. The T bit and the CSG and NSG fields are reserved. Ouch ๐
- Login Response with Login Accept as a final response (T bit set to 1, and the NSG in both request and response set to FullFeaturePhase). The response includes the protocol version supported by the target and the session ID, and it may include iSCSI operational or security parameters (depending on the current stage) ๐
- Login Response with Login Accept as a partial response (NSG not set to FullFeaturePhase in both request and response). This marks the start of a negotiation sequence. The response includes the protocol version supported by the target and either security or iSCSI parameters (when no security mechanism is chosen) supported by the target ๐ธ
If the initiator decides to forego the SecurityNegotiation stage, it issues the Login with the CSG set to LoginOperationalNegotiation. The target may reply with a Login Response saying it's unwilling to accept the connection without SecurityNegotiation (see Section 10.13 Login Response), and it will terminate the connection with a response of Authentication failure (see Section 10.13.5 Status-Class and Status-Detail). Not the vibe ๐ฌ
If the initiator is willing to negotiate iSCSI security, but doesn't want to make the initial parameter proposal and is okay accepting a connection without iSCSI security, it issues the Login with the T bit set to 1, the CSG set to SecurityNegotiation, and the NSG set to LoginOperationalNegotiation. If the target is also ready to skip security, the Login Response only contains the TargetPortalGroupTag key (see Section 12.9 TargetPortalGroupTag), with the T bit set to 1, the CSG set to SecurityNegotiation, and the NSG set to LoginOperationalNegotiation ๐ซถ
An initiator that wants to operate without iSCSI security, with all the operational parameters at their default values, issues the Login with the T bit set to 1, the CSG set to LoginOperationalNegotiation, and the NSG set to FullFeaturePhase. If the target is also ready to forego security and can finish its LoginOperationalNegotiation, the Login Response has the T bit set to 1, the CSG set to LoginOperationalNegotiation, and the NSG set to FullFeaturePhase in the next stage. Easy, breezy, beautiful ๐
During the Login Phase, the iSCSI target MUST return the TargetPortalGroupTag key with the first Login Response PDU that it's allowed to include it in (that is, the first Login Response issued after the first Login Request with the C bit set to 0). This applies for all session types when TargetName is given and the response is not a redirection. The TargetPortalGroupTag value tells you which iSCSI portal group is servicing the Login Request PDU. If portal group reconfiguration is a concern in a given environment, the iSCSI initiator should use this key to make sure it really started the Login Phase with the intended target portal group ๐โจ
5.3.2. iSCSI Security Negotiation ๐
okay bestie, the security exchange is where things get serious ๐โจ It sets the security mechanism and authenticates the initiator user and the target to each other ๐ซถ. It follows the authentication method picked during the negotiation phase, and it all runs through the key=value parameters inside the Login Requests and responses ๐
.
an initiator directed negotiation goes like this ๐:
- The initiator sends a Login Request with an ordered list of the options it supports (authentication algorithm). The options are listed in the initiator's order of preference. The initiator MAY also send private or public extension options. ๐ธ
- The target MUST reply with the first option in the list it supports and is allowed to use for the specific initiator unless it does not support any, in which case it MUST answer with "Reject" (see Section 5.2 Text Mode Negotiation). The parameters are encoded in
UTF8askey=value. For security parameters, see Chapter 11. ๐ฅ - When the initiator is ready to wrap up the SecurityNegotiation stage, it sets the
Tbit to 1 and theNSGto whatever stage it would like next. The target then sets theTbit to 1 and sets theNSGto the next stage in the Login Response once it finishes sending its security keys. The next stage will be the one the target selected. If the next stage isFullFeaturePhase, the target MUST respond with a Login Response with the TSIH value. โจ
if the security negotiation fails at the target, the target MUST send the appropriate Login Response PDU ๐. if it fails at the initiator, the initiator SHOULD close the connection ๐.
also, the negotiation might be directed by the target instead, if the initiator does support security but isn't ready to direct the negotiation (propose options) ๐ง.
5.3.3. Operational Parameter Negotiation During the Login Phase ๐
operational parameter negotiation during the login MAY be done ๐:
- Starting with the first Login Request if the initiator does not propose any security/integrity option.
- Starting immediately after the security negotiation if the initiator and target perform such a negotiation.
operational parameter negotiation MAY involve several Login Request-Response exchanges, all started and ended by the initiator ๐. The initiator MUST indicate its intent to end the negotiation by setting the T bit to 1, and the target sets the T bit to 1 on the last response ๐ซถ.
if the target answers a Login Request that has the T bit set to 1 with a Login Response that has the T bit set to 0, the initiator should keep sending the Login Request (even empty) with the T bit set to 1, for as long as it still wants to switch stage ๐ฆ. It keeps doing this until it gets a Login Response with the T bit set to 1, or it gets a key that requires it to set the T bit to 0 ๐
.
some session specific parameters can only be set during the Login Phase of the first connection of a session (i.e., begun by a Login Request that contains a zero-valued TSIH). That's the leading Login Phase, and an example is the maximum number of connections that can be used for this session ๐.
a session is operational once it has at least one connection in FullFeaturePhase. New or replacement connections can only be added after that point โจ.
for operational parameters, see Chapter 12 ๐ธ.
5.3.4. Connection Reinstatement ๐ฆ
connection reinstatement is when an initiator logs in with an ISID-TSIH-CID combination that might still be active from the target's point of view ๐ญ. That causes the implicit logout of the connection that matches the CID, and a fresh Full Feature Phase iSCSI connection takes its place (with the same CID) ๐.
so the TSIH in the Login PDU MUST be non-zero, and the CID doesn't change during a connection reinstatement ๐. The Login Request does the logout job for the old connection if an explicit logout didn't happen earlier. In sessions with a single connection, this might mean opening a second connection with the sole purpose of cleaning up the first ๐งน. Targets MUST support opening a second connection even when they don't support multiple connections in Full Feature Phase if ErrorRecoveryLevel is 2, and SHOULD support opening a second connection if ErrorRecoveryLevel is less than 2 ๐.
if the operational ErrorRecoveryLevel is 2, connection reinstatement enables future task reassignment ๐
. If the operational ErrorRecoveryLevel is less than 2, connection reinstatement just replaces the old CID and does not enable task reassignment. In that case, all the tasks that were active on the old CID must be immediately terminated without further notice to the initiator โ ๏ธ.
the initiator connection state MUST be CLEANUP_WAIT (section 7.1.3) when it attempts a connection reinstatement ๐.
in practical terms, on top of the implicit logout of the old connection, reinstatement works just like a new connection login ๐.
5.3.5. Session Reinstatement, Closure, and Timeout โณ
session reinstatement is when the initiator logs in with an ISID that might still be active from the target's point of view ๐. That implicitly logs out the session that matches the ISID, and a new iSCSI session takes its place (with the same ISID) ๐ซ. So the TSIH in the Login PDU MUST be zero to signal session reinstatement ๐ง. Session reinstatement causes all the tasks that were active on the old session to be immediately terminated by the target, without further notice to the initiator ๐.
the initiator session state MUST be FAILED (Section 7.3 Session State Diagrams) when it attempts a session reinstatement ๐.
session closure is an event that's one of the following:
- A successful "session close" logout.
- A successful "connection close" logout for the last Full Feature Phase connection, when no other connection in the session is waiting for cleanup (Section 7.2 Connection Cleanup State Diagram for Initiators and Targets) and no tasks in the session are waiting for reassignment.
session timeout is an event that happens when the last connection state timeout expires and no tasks are waiting for reassignment. It takes the session to the FREE state (N6 transition in the session state diagram) ๐ค.
5.3.5.1. Loss of Nexus Notification ๐ฃ
the iSCSI layer tells the SCSI layer about an "I_T nexus loss" when any one of these events happens:
- a) Successful completion of session reinstatement.
- b) Session closure event.
- c) Session timeout event.
certain SCSI object clearing actions may happen because of that notification in the SCSI end nodes, as documented in Appendix F. - Clearing Effects of Various Events on Targets - ๐งนโจ.
5.3.6. Session Continuation and Failure ๐
session continuation is when the state of an existing session keeps getting used, either through connection reinstatement (Section 5.3.4 Connection Reinstatement) or by adding a connection with a new CID. Either way, the new transport connection gets tied to the session state ๐ซถ.
session failure is an event where the last Full Feature Phase connection reaches the CLEANUP_WAIT state (Section 7.2 Connection Cleanup State Diagram for Initiators and Targets), or finishes a successful recovery logout. That causes all the active tasks that used to belong to the connection to start waiting for task reassignment ๐ญ๐.
5.4. Operational Parameter Negotiation Outside the Login Phase ๐ท
some operational parameters MAY be negotiated outside (after) the Login Phase ๐.
parameter negotiation in Full Feature Phase happens through Text requests and responses. Operational parameter negotiation MAY involve several Text request-response exchanges, which the initiator always starts and ends using the same Initiator Task Tag ๐. The initiator MUST indicate its intent to end the negotiation by setting the F bit to 1, and the target sets the F bit to 1 on the last response ๐
.
if the target answers a Text request with the F bit set to 1 and a Text response with the F bit set to 0, the initiator should keep sending the Text request (even empty) with the F bit set to 1, for as long as it still wants to finish the negotiation. It keeps going until it gets a Text response with the F bit set to 1 ๐ฆ. Answering a Text request with the F bit set to 1 with an empty response (no key=value pairs) that has the F bit set to 0 is discouraged ๐.
Targets MUST NOT put parameters that need another initiator Text request into a Text response with the F bit set to 1 ๐ซ.
in a negotiation sequence, the F bit settings in one pair of Text request-responses have no effect on the F bit settings in the next pair. An initiator that has the F bit set to 1 in a request and gets an F bit setting of 0 back may send its next request with the F bit set to 0 โจ.
whenever the target responds with the F bit set to 0, it MUST set the Target Transfer Tag to a value other than the default 0xffffffff ๐ฅ.
an initiator MAY reset an operational parameter negotiation by sending a Text request with the Target Transfer Tag set to 0xffffffff, after it gets a response with a Target Transfer Tag set to a value other than 0xffffffff ๐. A target may reset an operational parameter negotiation by answering a Text request with a Reject PDU ๐.
neither the initiator nor the target should try to declare or negotiate a parameter more than once during any negotiation sequence, unless there's an operational parameter negotiation reset in between. The exception is responses to specific keys that explicitly allow repeated key declarations (e.g., TargetAddress) ๐. If the target detects this, it MUST result in a Reject PDU with a reason of "protocol error" ๐. The initiator MUST reset the negotiation as outlined above ๐งน.
parameters negotiated by a text exchange only become effective after the negotiation sequence is completed โจ.
6. iSCSI Error Handling and Recovery ๐
6.1. Overview ๐ธ
6.1.1. Background ๐ญ
the following two things are why a lot of the error recovery stuff in iSCSI exists ๐:
- i) An iSCSI PDU may fail the digest check and be dropped, even though the TCP layer received it. The iSCSI layer must optionally be allowed to recover such dropped PDUs.
- ii) A TCP connection may fail at any time during the data transfer. All the active tasks must optionally be allowed to continue on a different TCP connection within the same session.
implementations have a lot of flexibility in deciding how much error recovery to support, when to use it, and which mechanisms to use to get the required behavior ๐. Only the externally visible actions of the error recovery mechanisms must be standardized, so things stay interoperable ๐ซถ.
this chapter describes a general model for recovery that supports interoperability. See Appendix E. - Algorithmic Presentation of Error Recovery Classes - for more detail on how the described model could be implemented ๐ง. Compliant implementations don't have to match the implementation details of this model as presented, but their external behavior must correspond to the externally observable characteristics of the presented model ๐ โจ.
6.1.2. Goals
okay so bestie, here are the major design goals for the iSCSI error recovery scheme ๐โจ
- a) Let iSCSI implementations meet different requirements by defining a collection of error recovery mechanisms they can pick from ๐
- b) Make sure any two implementations with different sets of error recovery capabilities can still interoperate ๐ซถ
- c) Define the error recovery mechanisms so command ordering survives even when errors happen, for initiators that need ordering ๐ฆ
- d) Don't add anything to the fast path, but moderate complexity in the error recovery path is totally fine ๐ง
- e) Stop the initiator and the target from both trying to recover the same set of PDUs at the same time ๐ญ there has to be a clear "error recovery functionality distribution" between them, no drama
6.1.3. Protocol Features and State Expectations
okay so the initiator mechanisms for error recovery are ๐ธ
- a) NOP-OUT to probe the sequence numbers of the target (section 10.18)
- b) Command retry (section 6.2.1)
- c) Recovery R2T support (section 6.7)
- d) Requesting retransmission of status/data/R2T using the SNACK facility (section 10.16)
- e) Acknowledging receipt of the data (section 10.16)
- f) Reassigning the connection allegiance of a task to a different TCP connection (section 6.2.2)
- g) Terminating the entire iSCSI session to start afresh (section 6.1.4.4)
and the target mechanisms are ๐
- a) NOP-IN to probe the sequence numbers of the initiator (section 10.19)
- b) Requesting retransmission of data using the recovery R2T feature (section 6.7)
- c) SNACK support (section 10.16)
- d) Requesting that parts of read data be acknowledged (section 10.7.2)
- e) Allegiance reassignment support (section 6.2.2)
- f) Terminating the entire iSCSI session to force the initiator to start over (section 6.1.4.4)
so for any outstanding SCSI command, it's assumed that iSCSI, working together with SCSI at the initiator, can keep enough info to rebuild the command PDU, and that the outgoing data is still sitting in host memory so it can be retransmitted while the command is outstanding ๐ง at the target, incoming data (read data) MAY be kept for recovery, or it can be reread from a device server. it's giving organized, no cap ๐
it's also assumed that a target will keep the "status & sense" for a command it has executed if it supports status retransmission. and a target that agrees to support data retransmission is expected to be ready to retransmit the outgoing data (i.e., Data-In) on request until either the status for the completed command is acknowledged, or the data in question has been separately acknowledged. main character energy from the target side ๐
6.1.4. Recovery Classes
okay so iSCSI gives you these classes of recovery, listed in order of increasing scope of affected iSCSI tasks ๐
- Within a command (i.e., without requiring command restart).
- Within a connection (i.e., without requiring the connection to be rebuilt, but perhaps requiring command restart).
- Connection recovery (i.e., perhaps requiring connections to be rebuilt and commands to be reissued).
- Session recovery.
the recovery scenarios in the rest of this section are representative, not exclusive, so they aren't a full list of everything that can happen ๐ in every case, they describe the lowest class of recovery that MAY be attempted. the implementer gets to decide when to escalate to the next recovery class and/or which recovery classes to implement. both the iSCSI target and initiator MAY escalate the error handling to an error recovery class, which affects a larger number of iSCSI tasks in any of the cases in the following discussion โจ
in all classes, the implementer can choose to defer errors to the SCSI initiator (with an appropriate response code). in that case the task, if there is one, has to be removed from the target, and all the side effects, such as ACA, must be considered ๐
Within-connection and within-command recovery classes MUST NOT be attempted before the connection is in Full Feature Phase. ๐ซ
in the detailed descriptions of the recovery classes, the mandating terms (MUST, SHOULD, MAY, etc.) mark normative actions that have to be executed if the recovery class is supported and used ๐
6.1.4.1. Recovery Within-command
okay so at the target, these cases are good candidates for within-command recovery ๐ฆ
- Lost data PDU, which shows up through one of these:
- a) Data digest error, handled as specified in Section 6.7 Digest Errors, using the option of a recovery R2T.
- b) Sequence reception timeout (no data or partial-data-and-no-F-bit), treated as an implicit sequence error and handled as specified in Section 6.8 Sequence Errors, using the option of a recovery R2T.
- c) Header digest error, which shows up as a sequence reception timeout or a sequence error, handled as specified in Section 6.8 Sequence Errors, using the option of a recovery R2T.
and at the initiator, these cases are good candidates for within-command recovery ๐ธ
- Lost data PDU or lost R2T, which shows up through one of these:
- a) Data digest error, handled as specified in Section 6.7 Digest Errors, using the option of a SNACK.
- b) Sequence reception timeout (no status) or response reception timeout, handled as specified in Section 6.8 Sequence Errors, using the option of a SNACK.
- c) Header digest error, which shows up as a sequence reception timeout or a sequence error, handled as specified in Section 6.8 Sequence Errors, using the option of a SNACK.
to avoid a race with the target, which might already have a recovery R2T or a termination response on its way, an initiator SHOULD NOT originate a SNACK for an R2T based on its internal timeouts (if it has any) ๐ โโ๏ธ recovery in this case is better left to the target, trust ๐ซถ
the timeout values used by the initiator and target are outside the scope of this document. sequence reception timeout is generally a large enough value to let the data sequence transfer finish, so it's not gonna cut things off too early ๐
6.1.4.2. Recovery Within-connection
okay so at the initiator, these cases are good candidates for within-connection recovery ๐ง
- Requests not acknowledged for a long time. requests get acknowledged explicitly through
ExpCmdSN, or implicitly by receiving data and/or status. the initiator MAY retry non-acknowledged commands as specified in Section 6.2 Retry and Reassign in Recovery ๐ฅ - Lost iSCSI numbered Response. you can spot it by either finding a data digest error on a Response PDU or a Data-In PDU carrying the status, or by receiving a Response PDU with a higher
StatSNthan expected. in the first case, digest error handling is done as specified in Section 6.7 Digest Errors, using the option of a SNACK. in the second case, sequence error handling is done as specified in Section 6.8 Sequence Errors, using the option of a SNACK ๐
and at the target, these cases are good candidates for within-connection recovery ๐
- Status/Response not acknowledged for a long time. the target MAY issue a NOP-IN (with a valid Target Transfer Tag or otherwise) that carries the next status sequence number it's going to use in the
StatSNfield. this helps the initiator detect any missingStatSNvalues and issue a SNACK for the status ๐ซถ
the timeout values used by the initiator and the target are outside the scope of this document ๐
6.1.4.3. Connection Recovery
okay so at an iSCSI initiator, these cases are good candidates for connection recovery ๐
- TCP connection failure: the initiator MUST close the connection. then it MUST either implicitly or explicitly log out the failed connection with the reason code
remove the connection for recovery, and reassign connection allegiance for all commands still in progress that were associated with the failed connection, on one or more connections (some or all of which MAY be newly established connections), using theTask reassigntask management function (see Section 10.5.1 Function). for an initiator, a command is in progress for as long as it hasn't received a response or a Data-In PDU including status ๐ฆ
Note: The logout function is mandatory. However, a new connection establishment is only mandatory if the failed connection was the last or only connection in the session. ๐
- Receiving an Asynchronous Message that indicates one or all connections in a session have been dropped. the initiator MUST handle it as a TCP connection failure for the connection(s) referred to in the Message ๐จ
and at an iSCSI target, these cases are good candidates for connection recovery ๐ธ
- TCP connection failure. the target MUST close the connection and, if more than one connection is available, the target SHOULD send an Asynchronous Message that indicates it has dropped the connection. then the target waits for the initiator to continue recovery ๐ง
6.1.4.4. Session Recovery
okay so session recovery should be performed when all the other recovery attempts have failed ๐ญ very simple initiators and targets MAY perform session recovery on all iSCSI errors and rely on recovery at the SCSI layer and above, which is honestly so relatable ๐
session recovery means closing all TCP connections, internally aborting all executing and queued tasks for the given initiator at the target, terminating all outstanding SCSI commands with an appropriate SCSI service response at the initiator, and restarting a session on a new set of connection(s) (TCP connection establishment and login on all new connections). it's a full reset, periodt ๐ฅ
for the possible clearing effects of session recovery on SCSI and iSCSI objects, check out Appendix F. - Clearing Effects of Various Events on Targets - ๐
6.1.5. Error Recovery Hierarchy ๐ช
okay so the error recovery classes we just went through? they're organized into a hierarchy bc it makes them way easier to understand AND keeps the implementation complexity from getting out of hand ๐ few, well-defined levels means interoperability is easier to achieve ๐ซถ the attributes of this hierarchy are as follows:
- a) Each level is a superset of the capabilities of the previous level. For example, Level 1 support implies supporting all capabilities of Level 0 and more.
- b) As a corollary, supporting a higher error recovery level means increased sophistication and possibly an increase in resource requirements.
- c) Supporting error recovery level "n" is advertised and negotiated by each iSCSI entity by exchanging the text key "ErrorRecoveryLevel=n". The lower of the two exchanged values is the operational ErrorRecoveryLevel for the session.
the following diagram represents the error recovery hierarchy ๐
+
/
/ 2 \ <-- Connection recovery
+-----+
/ 1 \ <-- Digest failure recovery
+---------+
/ 0 \ <-- Session failure recovery
+-------------+
the following table lists the error recovery capabilities expected from the implementations that support each error recovery level ๐
+-------------------+--------------------------------------------+
|ErrorRecoveryLevel | Associated Error recovery capabilities |
+-------------------+--------------------------------------------+
| 0 | Session recovery class |
| | (Section 6.1.4.4 Session Recovery) |
+-------------------+--------------------------------------------+
| 1 | Digest failure recovery (See Note below.) |
| | plus the capabilities of ER Level 0 |
+-------------------+--------------------------------------------+
| 2 | Connection recovery class |
| | (Section 6.1.4.3 Connection Recovery) |
| | plus the capabilities of ER Level 1 |
+-------------------+--------------------------------------------+
Note: Digest failure recovery is comprised of two recovery classes: Within-Connection recovery class (Section 6.1.4.2 Recovery Within-connection) and Within-Command recovery class (Section 6.1.4.1 Recovery Within-command).
when a defined value of ErrorRecoveryLevel is proposed by an originator in a text negotiation, the originator MUST support the functionality defined for the proposed value and additionally, the functionality corresponding to any defined value numerically less than the proposed. when a defined value of ErrorRecoveryLevel is returned by a responder in a text negotiation, the responder MUST support the functionality corresponding to the ErrorRecoveryLevel it is accepting.
when either party attempts to use error recovery functionality beyond what is negotiated, the recovery attempts MAY fail unless an a priori agreement outside the scope of this document exists between the two parties to provide such support.
Implementations MUST support error recovery level "0", while the rest are OPTIONAL to implement. in implementation terms, the above striation means that the following incremental sophistication with each level is required ๐ฅ
+-------------------+---------------------------------------------+
|Level transition | Incremental requirement |
+-------------------+---------------------------------------------+
| 0->1 | PDU retransmissions on the same connection |
+-------------------+---------------------------------------------+
| 1->2 | Retransmission across connections and |
| | allegiance reassignment |
+-------------------+---------------------------------------------+
6.2. Retry and Reassign in Recovery ๐
this section summarizes two important and somewhat related iSCSI protocol features used in error recovery ๐ง
6.2.1. Usage of Retry
by resending the same iSCSI command PDU ("retry") in the absence of a command acknowledgement (by way of an ExpCmdSN update) or a response, an initiator attempts to "plug" (what it thinks are) the discontinuities in CmdSN ordering on the target end. Discarded command PDUs, due to digest errors, may have created these discontinuities ๐
Retry MUST NOT be used for reasons other than plugging command sequence gaps, and in particular, cannot be used for requesting PDU retransmissions from a target. Any such PDU retransmission requests for a currently allegiant command in progress may be made using the SNACK mechanism described in section 10.16, although the usage of SNACK is OPTIONAL.
if initiators, as part of plugging command sequence gaps as described above, inadvertently issue retries for allegiant commands already in progress (i.e., targets did not see the discontinuities in CmdSN ordering), the duplicate commands are silently ignored by targets as specified in section 3.2.2.1 โจ
When an iSCSI command is retried, the command PDU MUST carry the original Initiator Task Tag and the original operational attributes (e.g., flags, function names, LUN, CDB etc.) as well as the original CmdSN. The command being retried MUST be sent on the same connection as the original command unless the original connection was already successfully logged out.
6.2.2. Allegiance Reassignment ๐
by issuing a "task reassign" task management request (Section 10.5.1 Function), the initiator signals its intent to continue an already active command (but with no current connection allegiance) as part of connection recovery. This means that a new connection allegiance is requested for the command, which seeks to associate it to the connection on which the task management request is being issued. Before the allegiance reassignment is attempted for a task, an implicit or explicit Logout with the reason code "remove the connection for recovery" ( see section 10.14) MUST be successfully completed for the previous connection to which the task was allegiant.
in reassigning connection allegiance for a command, the targets SHOULD continue the command from its current state. For example, when reassigning read commands, the target SHOULD take advantage of the ExpDataSN field provided by the Task Management function request (which must be set to zero if there was no data transfer) and bring the read command to completion by sending the remaining data and sending (or resending) the status. ExpDataSN acknowledges all data sent up to, but not including, the Data-In PDU and or R2T with DataSN (or R2TSN) equal to ExpDataSN. However, targets may choose to send/receive all unacknowledged data or all of the data on a reassignment of connection allegiance if unable to recover or maintain an accurate state. Initiators MUST not subsequently request data retransmission through Data SNACK for PDUs numbered less than ExpDataSN (i.e., prior to the acknowledged sequence number). For all types of commands, a reassignment request implies that the task is still considered in progress by the initiator and the target must conclude the task appropriately if the target returns the "Function Complete" response to the reassignment request. This might possibly involve retransmission of data/R2T/status PDUs as necessary, but MUST involve the (re)transmission of the status PDU.
It is OPTIONAL for targets to support the allegiance reassignment. This capability is negotiated via the ErrorRecoveryLevel text key during the login time. When a target does not support allegiance reassignment, it MUST respond with a Task Management response code of "Allegiance reassignment not supported". If allegiance reassignment is supported by the target, but the task is still allegiant to a different connection, or a successful recovery Logout of the previously allegiant connection was not performed, the target MUST respond with a Task Management response code of "Task still allegiant".
If allegiance reassignment is supported by the target, the Task Management response to the reassignment request MUST be issued before the reassignment becomes effective.
If a SCSI Command that involves data input is reassigned, any SNACK Tag it holds for a final response from the original connection is deleted and the default value of 0 MUST be used instead.
6.3. Usage Of Reject PDU in Recovery ๐ซ
Targets MUST NOT implicitly terminate an active task by sending a Reject PDU for any PDU exchanged during the life of the task. If the target decides to terminate the task, a Response PDU (SCSI, Text, Task, etc.) must be returned by the target to conclude the task. If the task had never been active before the Reject (i.e., the Reject is on the command PDU), targets should not send any further responses because the command itself is being discarded.
The above rule means that the initiator can eventually expect a response on receiving Rejects, if the received Reject is for a PDU other than the command PDU itself. The non-command Rejects only have diagnostic value in logging the errors, and they can be used for retransmission decisions by the initiators.
The CmdSN of the rejected command PDU (if it is a non-immediate command) MUST NOT be considered received by the target (i.e., a command sequence gap must be assumed for the CmdSN), even though the CmdSN of the rejected command PDU may be reliably ascertained. Upon receiving the Reject, the initiator MUST plug the CmdSN gap in order to continue to use the session. The gap may be plugged either by transmitting a command PDU with the same CmdSN, or by aborting the task (see section 6.9 on how an abort may plug a CmdSN gap) ๐งฉ
When a data PDU is rejected and its DataSN can be ascertained, a target MUST advance ExpDataSN for the current data burst if a recovery R2T is being generated. The target MAY advance its ExpDataSN if it does not attempt to recover the lost data PDU.
6.4. Connection Timeout Management โณ
iSCSI defines two session-global timeout values (in seconds) - Time2Wait and Time2Retain - that are applicable when an iSCSI Full Feature Phase connection is taken out of service either intentionally or by an exception. Time2Wait is the initial "respite time" before attempting an explicit/implicit Logout for the CID in question or task reassignment for the affected tasks (if any). Time2Retain is the maximum time after the initial respite interval that the task and/or connection state(s) is/are guaranteed to be maintained on the target to cater to a possible recovery attempt. Recovery attempts for the connection and/or task(s) SHOULD NOT be made before Time2Wait seconds, but MUST be completed within Time2Retain seconds after that initial Time2Wait waiting period. ๐ธ
6.4.1. Timeouts on Transport Exception Events
A transport connection shutdown or a transport reset without any preceding iSCSI protocol interactions informing the end-points of the fact causes a Full Feature Phase iSCSI connection to be abruptly terminated. The timeout values to be used in this case are the negotiated values of defaultTime2Wait (Section 12.15 DefaultTime2Wait) and DefaultTime2Retain (Section 12.16 DefaultTime2Retain) text keys for the session. ๐
6.4.2. Timeouts on Planned Decommissioning ๐ง
okay bestie, before any planned decommissioning of a Full Feature Phase iSCSI connection, there's always either a Logout Response PDU or an Async Message PDU ๐ซถ. The Time2Wait and Time2Retain field values (section 10.15) in a Logout Response PDU, and the Parameter2 and Parameter3 fields of an Async Message (AsyncEvent types "drop the connection" or "drop all the connections"; section 10.9.1), are what set the timeout values for each of those cases ๐
.
these timeout values only apply to the affected connection and the tasks active on it โจ. they don't touch any initiator timers (if there are any) that are already running on connections or tasks in that session ๐ it's giving very clear boundaries ๐
6.5. Implicit Termination of Tasks ๐ฅ
a target implicitly terminates its active tasks in these cases, because of how iSCSI protocol dynamics work ๐ฆ
- a) When a connection is implicitly or explicitly logged out with the reason code of "Close the connection" and there are active tasks allegiant to that connection.
- b) When a connection fails and the connection state eventually times out (state transition M1 in Section 7.2.2 State Transition Descriptions for Initiators and Targets) and there are active tasks allegiant to that connection.
- c) When a successful Logout with the reason code of "remove the connection for recovery" is performed while there are active tasks allegiant to that connection, and those tasks eventually time out after the Time2Wait and Time2Retain periods without allegiance reassignment.
- d) When a connection is implicitly or explicitly logged out with the reason code of "Close the session" and there are active tasks in that session.
if the tasks terminated in cases a), b, c) and d)are SCSI tasks, they must be internally terminated as if with CHECK CONDITION status ๐ง . this status only matters for handling the internal SCSI state and the SCSI side effects around ordering, because it's never sent back to the initiator as a terminating status ๐คซ. still, extra stuff may have to happen at the SCSI level depending on the SCSI context the SCSI standards define (e.g., queued commands and ACA, in cases a), b), and c), after the tasks are terminated, the target MUST report a Unit Attention condition on the next command processed on any connection for each affected I_T_L nexus with the status of CHECK CONDITION, and the ASC/ASCQ value of 47h/7Fh - "SOME COMMANDS CLEARED BY ISCSI PROTOCOL EVENT" , etc. - see [SAM2] and [SPC3]). main character energy for the SCSI layer ๐
6.6. Format Errors ๐
only two explicit violations of the PDU layout rules count as format errors ๐:
- a) Illegal contents of any PDU header field except the Opcode (legal values are specified in Section 10 iSCSI PDU Formats).
- b) Inconsistent field contents (consistent field contents are specified in Section 10 iSCSI PDU Formats).
format errors point to a major implementation flaw in one of the parties ๐ญ
when a target or an initiator gets an iSCSI PDU with a format error, it MUST immediately terminate all transport connections in the session, either with a connection close or with a connection reset, and escalate the format error to session recovery (see Section 6.1.4.4 Session Recovery) ๐จ
6.7. Digest Errors ๐
the legal choices for handling digest errors below leave out session recovery as an explicit option ๐ but either party that detects a digest error may choose to escalate it to session recovery ๐ง
when a target or an initiator receives any iSCSI PDU with a header digest error, it MUST either discard the header and all data up to the beginning of a later PDU or close the connection. because a header digest error means the length field may have been corrupted, the start of a later PDU has to be reliably found by other means, such as the operation of a sync and steering layer ๐
when a target receives any iSCSI PDU with a payload digest error, it MUST answer with a Reject PDU with a reason code of Data-Digest-Error and discard the PDU ๐ซ
- If the discarded PDU is a solicited or unsolicited iSCSI data PDU (for immediate data in a command PDU, non-data PDU rule below applies), the target MUST do one of the following:
- a) Request retransmission with a recovery R2T.
- b) Terminate the task with a response PDU with a CHECK CONDITION Status and an iSCSI Condition of "protocol service CRC error" (Section 10.4.7.2 Sense Data). If the target chooses to implement this option, it MUST wait to receive all the data (signaled by a Data PDU with the final bit set for all outstanding R2Ts) before sending the response PDU. A task management command (such as an abort task) from the initiator during this wait may also conclude the task.
- No further action is necessary for targets if the discarded PDU is a non-data PDU. In case of immediate data being present on a discarded command, the immediate data is implicitly recovered when the task is retried (see section 6.2.1), followed by the entire data transfer for the task. ๐
when an initiator receives any iSCSI PDU with a payload digest error, it MUST discard the PDU ๐๏ธ
- If the discarded PDU is an iSCSI data PDU, the initiator MUST do one of the following:
- a) Request the desired data PDU through SNACK. In response to the SNACK, the target MUST either resend the data PDU or reject the SNACK with a Reject PDU with a reason code of "SNACK reject", in which case:
- i) If the status has not already been sent for the command, the target MUST terminate the command with a CHECK CONDITION Status and an iSCSI Condition of "SNACK rejected" (Section 10.4.7.2 Sense Data).
- ii) If the status was already sent, no further action is necessary for the target. The initiator in this case MUST wait for the status to be received and then discard it, so as to internally signal the completion with CHECK CONDITION Status and an iSCSI Condition of "protocol service CRC error" (Section 10.4.7.2 Sense Data).
- b) Abort the task and terminate the command with an error.
- a) Request the desired data PDU through SNACK. In response to the SNACK, the target MUST either resend the data PDU or reject the SNACK with a Reject PDU with a reason code of "SNACK reject", in which case:
- If the discarded PDU is a response PDU, the initiator MUST do one of the following:
- a) Request PDU retransmission with a status SNACK.
- b) Logout the connection for recovery and continue the tasks on a different connection instance as described in Section 6.2 Retry and Reassign in Recovery.
- c) Logout to close the connection (abort all the commands associated with the connection).
- No further action is necessary for initiators if the discarded PDU is an unsolicited PDU (e.g., Async, Reject). Task timeouts (as in the initiator waiting for a command completion) or process timeouts (as in the target waiting for a Logout) will ensure that the correct operational behavior results in these cases despite the discarded PDU. โณ
6.8. Sequence Errors ๐งฉ
when an initiator receives an iSCSI R2T/data PDU with an out of order R2TSN/DataSN, or a SCSI response PDU with an ExpDataSN that implies missing data PDU(s), that means the initiator must have detected a header or payload digest error on one or more earlier R2T/data PDUs ๐ต๏ธโโ๏ธ. the initiator MUST address these implied digest errors as described in Section 6.7 Digest Errors. when a target receives a data PDU with an out of order DataSN, the target must have hit a header or payload digest error on at least one of the earlier data PDUs. the target MUST address these implied digest errors as described in Section 6.7 Digest Errors.
when an initiator receives an iSCSI status PDU with an out of order StatSN that implies missing responses, it MUST address the one or more missing status PDUs as described in Section 6.7 Digest Errors ๐. as a side effect of receiving the missing responses, the initiator may discover missing data PDUs. if the initiator wants to recover the missing data for a command, it MUST NOT acknowledge the received responses that start from the StatSN of the relevant command, until it has completed receiving all the data PDUs of the command ๐
when an initiator receives duplicate R2TSNs (due to proactive retransmission of R2Ts by the target) or duplicate DataSNs (due to proactive SNACKs by the initiator), it MUST discard the duplicates ๐งน
6.9. SCSI Timeouts โฐ
an iSCSI initiator MAY try to plug a command sequence gap on the target end before the ULP timeout ๐ช (when there's no acknowledgement of the command by way of ExpCmdSN) by retrying the unacknowledged command, as described in Section 6.2 Retry and Reassign in Recovery.
on a ULP timeout for a command (that carried a CmdSN of n), if the iSCSI initiator wants to keep the session going, it MUST abort the command. it can do that either with an appropriate Task Management function request for the specific command, or with a "close the connection" Logout ๐ . when using an ABORT TASK, if the ExpCmdSN is still less than (n+1), the target may see the abort request while missing the original command itself, for one of these reasons:
- Original command was dropped due to digest error.
- Connection on which the original command was sent was successfully logged out. Upon logout, the unacknowledged commands issued on the connection being logged out are discarded.
if the abort request is received and the original command is missing, targets MUST consider the original command with that RefCmdSN to be received and issue a Task Management response with the response code: Function Complete. this response concludes the task on both ends ๐. if the abort request is received and the target can determine (based on the Referenced Task Tag) that the command was received and executed, and also that the response was sent prior to the abort, then the target MUST respond with the response code of Task Does Not Exist ๐ซถ
6.10. Negotiation Failures ๐
okay so when you send text requests and responses to set or negotiate operational parameters, that back-and-forth IS the negotiation ๐ซถ and a negotiation failure is basically any of these (ngl they're all kinda messy):
- None of the choices, or the stated value, is acceptable to one of the sides in the negotiation.
- The text request timed out and possibly terminated.
- The text request was answered with a Reject PDU.
there are two rules for handling these, and they're lowkey different depending on where you are ๐ฆ
- During Login, any failure in negotiation MUST be considered a login process failure and the Login Phase must be terminated, and with it, the connection. If the target detects the failure, it must terminate the login with the appropriate Login Response code. no cap, login failures are a hard stop ๐
- A failure in negotiation, while in the Full Feature Phase, will terminate the entire negotiation sequence that may consist of a series of text requests that use the same Initiator Task Tag. The operational parameters of the session or the connection MUST continue to be the values agreed upon during an earlier successful negotiation (i.e., any partial results of this unsuccessful negotiation MUST NOT take effect and MUST be discarded). so the half-finished stuff just gets tossed, and your last successful settings stay put ๐งโจ
6.11. Protocol Errors ๐ธ
okay so mapping framed messages over a "stream" connection, like TCP, makes the proposed mechanisms kinda vulnerable to simple software framing errors ๐ญ BUT adding framing mechanisms to limit those effects might be onerous on performance for simple implementations, so it's a tradeoff babe. Command Sequence Numbers and the mechanisms for connection drop and reestablishment (from earlier!) help handle this type of mapping error ๐
all violations of iSCSI PDU exchange sequences specified in this document are also protocol errors. this category can ONLY be addressed by fixing the implementations, and iSCSI defines Reject and response codes to enable that ๐ so it's really on the devs to clean it up.
6.12. Connection Failures ๐ฆ
iSCSI can keep a session going as long as it can keep or establish at least one TCP connection between the initiator and the target in a timely fashion. targets and/or initiators may notice a failing connection through transport level means (TCP), a gap in the command sequence number, a response stream that isn't filled for a long time, or a failing iSCSI NOP (acting as a ping) ๐ the NOP one MAY be used periodically to boost the speed and likelihood of catching connection failures. and initiators and targets MAY also use the keep-alive option on the TCP connection to enable early link failure detection on otherwise idle links ๐
on connection failure, the initiator and target MUST do one of the following:
- Attempt connection recovery within the session (Section 6.1.4.3 Connection Recovery).
- Logout the connection with the reason code "closes the connection" (Section 10.14.5 Implicit termination of tasks), re-issue missing commands, and implicitly terminate all active commands. this option requires support for the within-connection recovery class (Section 6.1.4.2 Recovery Within-connection).
- Perform session recovery (Section 6.1.4.4 Session Recovery).
either side may choose to escalate to session recovery (via the initiator dropping all the connections, or via an Async Message that announces the similar intent from a target), and the other side MUST give it precedence ๐ no arguing, the escalation wins. and on a connection failure, a target MUST terminate and/or discard all of the active immediate commands regardless of which of the above options is used (i.e., immediate commands are not recoverable across connection failures). so immediate commands are a no-recovery zone, periodt ๐
6.13. Session Errors ๐ง
if all of the connections of a session fail and can't be reestablished in a short time, or if initiators detect protocol errors repeatedly, an initiator may choose to terminate a session and establish a new one. it's giving "start fresh" energy โจ
in this case, the initiator takes the following actions:
- Resets or closes all the transport connections.
- Terminates all outstanding requests with an appropriate response before initiating a new session. If the same I_T nexus is intended to be reestablished, the initiator MUST employ session reinstatement (see section 5.3.5).
when the session timeout (the connection state timeout for the last failed connection) happens on the target, it takes the following actions:
- Resets or closes the TCP connections (closes the session).
- Terminates all active tasks that were allegiant to the connection(s) that constituted the session.
and a target MUST also be prepared to handle a session reinstatement request from the initiator, which may be addressing session errors ๐
7. State Transitions ๐
okay this part is the state machine era โจ iSCSI connections and iSCSI sessions go through several well-defined states from the time they're created to the time they're cleared. so it's like a whole life cycle, lowkey iconic ๐
the connection state transitions are described in two separate but dependent state diagrams, for ease in understanding. the first one, the "standard connection state diagram", describes connection state transitions when the iSCSI connection is NOT waiting for, or undergoing, a cleanup by way of an explicit or implicit Logout. the second, the "connection cleanup state diagram", describes connection state transitions while performing the iSCSI connection cleanup ๐งน
the "session state diagram" describes the state transitions an iSCSI session goes through during its lifetime, and it depends on the states of possibly multiple iSCSI connections that participate in the session. ๐ซง
states and state transitions are described in the text, tables and diagrams. the diagrams are used for illustration. the text and the tables are the governing specification, so if the pictures and words ever disagree, the words win ๐ (don't @ me)
7.1. Standard Connection State Diagrams ๐
7.1.1. State Descriptions for Initiators and Targets ๐
state descriptions for the standard connection state diagram are as follows, bestie:
S1: FREE- initiator: State on instantiation, or after successful connection closure.
- target: State on instantiation, or after successful connection closure.
S2: XPT_WAIT- initiator: Waiting for a response to its transport connection establishment request.
- target: Illegal
S3: XPT_UP- initiator: Illegal
- target: Waiting for the Login process to commence.
S4: IN_LOGIN- initiator: Waiting for the Login process to conclude, possibly involving several PDU exchanges.
- target: Waiting for the Login process to conclude, possibly involving several PDU exchanges.
S5: LOGGED_IN- initiator: In Full Feature Phase, waiting for all internal, iSCSI, and transport events.
- target: In Full Feature Phase, waiting for all internal, iSCSI, and transport events.
S6: IN_LOGOUT- initiator: Waiting for a Logout response.
- target: Waiting for an internal event signaling completion of logout processing.
S7: LOGOUT_REQUESTED- initiator: Waiting for an internal event signaling readiness to proceed with Logout.
- target: Waiting for the Logout process to start after having requested a Logout via an Async Message.
S8: CLEANUP_WAIT- initiator: Waiting for the context and/or resources to initiate the cleanup processing for this CSM.
- target: Waiting for the cleanup process to start for this CSM.
7.1.2. State Transition Descriptions for Initiators and Targets
Okay bestie, transitions time ๐ฆ Each one is a little event that nudges a connection from one state to another, and it hits differently depending on whether you're the initiator or the target ๐
- T1 ๐ธ
- initiator: A transport connect request was made (e.g., TCP SYN sent).
- target: Illegal ๐
- T2 ๐
- initiator: The transport connection request timed out, a transport reset was received, or an internal event of receiving a Logout response (success) on another connection for a "close the session" Logout request was received.
- target: Illegal ๐
- T3 ๐ง
- initiator: Illegal ๐
- target: A valid transport connection request was received, and that establishes the transport connection.
- T4 โจ
- initiator: The transport connection got established, so the initiator is prompted to start the iSCSI Login.
- target: The initial iSCSI Login Request was received.
- T5 ๐
- initiator: The final iSCSI Login Response with a Status-Class of zero was received.
- target: The final iSCSI Login Request to conclude the Login Phase was received, so the target sends the final iSCSI Login Response with a Status-Class of zero.
- T6 ๐ญ
- initiator: Illegal ๐
- target: The target timed out waiting for an iSCSI Login, a transport disconnect indication was received, a transport reset was received, or an internal event indicating a transport timeout was received. In all of these cases, the connection is to be closed.
- T7 ๐ฅ
- initiator: One of the following events caused the transition:
- The final iSCSI Login Response was received with a non-zero Status-Class.
- Login timed out.
- A transport disconnect indication was received.
- A transport reset was received.
- An internal event was received indicating a transport timeout.
- An internal event of receiving a Logout response (success) on another connection for a "close the session" Logout request was received.
- initiator: One of the following events caused the transition:
In all of these cases, the transport connection is closed.
- target: One of the following events caused the transition:
- The final iSCSI Login Request to conclude the Login Phase was received, prompting the target to send the final iSCSI Login Response with a non-zero Status-Class.
- Login timed out.
- A transport disconnect indication was received.
- A transport reset was received.
- An internal event indicating a transport timeout was received.
- On another connection, a "close the session" Logout request was received.
In all of these cases, the connection is to be closed.
- T8 ๐
- initiator: An internal event of receiving a Logout response (success) on another connection for a "close the session" Logout request was received, which closes this connection and requires no further cleanup.
- target: An internal event of sending a Logout response (success) on another connection for a "close the session" Logout request was received, or an internal event of a successful connection/session reinstatement was received, so the target closes this connection cleanly.
- T9, T10 ๐ฅ
- initiator: An internal event that indicates readiness to start the Logout process was received, so the initiator sends an iSCSI Logout.
- target: An iSCSI Logout request was received.
- T11, T12 ๐
- initiator: An Async PDU with AsyncEvent "Request Logout" was received.
- target: An internal event that requires decommissioning of the connection was received, so an Async PDU with an AsyncEvent "Request Logout" gets sent.
- T13 ๐
- initiator: An iSCSI Logout response (success) was received, or an internal event of receiving a Logout response (success) on another connection for a "close the session" Logout request was received.
- target: An internal event that indicates successful processing of the Logout was received, which prompts an iSCSI Logout response (success) to be sent. Alternatively, an internal event of sending a Logout response (success) on another connection for a "close the session" Logout request was received, or an internal event of a successful connection/session reinstatement was received.
In all of these cases, the transport connection is closed.
- T14 ๐
- initiator: An Async PDU with AsyncEvent "Request Logout" was received again.
- target: Illegal ๐
- T15, T16 ๐
- initiator: One or more of the following events caused this transition:
- An internal event indicating a transport connection timeout was received, thus prompting a transport RESET or transport connection closure.
- A transport RESET.
- A transport disconnect indication.
- An Async PDU with AsyncEvent "Drop connection" (for this CID).
- An Async PDU with AsyncEvent "Drop all connections".
- target: One or more of the following events caused this transition:
- An internal event indicating a transport connection timeout was received, thus prompting a transport RESET or transport connection closure.
- An internal event of a failed connection/session reinstatement was received.
- A transport RESET.
- A transport disconnect indication.
- An internal emergency cleanup event was received, which prompts an Async PDU with AsyncEvent "Drop connection" (for this CID), or the event "Drop all connections".
- initiator: One or more of the following events caused this transition:
- T17 ๐ธ
- initiator: One or more of the following events caused this transition:
- A Logout response (failure, i.e., a non-zero status) was received, or Logout timed out.
- Any of the events specified for T15 and T16.
- target: One or more of the following events caused this transition:
- An internal event indicating a failure of the Logout processing was received, which prompts a Logout response (failure, i.e., a non-zero status) to be sent.
- Any of the events specified for T15 and T16.
- initiator: One or more of the following events caused this transition:
- T18 โญ
- initiator: An internal event of receiving a Logout response (success) on another connection for a "close the session" Logout request was received.
- target: An internal event of sending a Logout response (success) on another connection for a "close the session" Logout request was received, or an internal event of a successful connection/session reinstatement was received.
In both of these cases, the connection is closed.
The CLEANUP_WAIT state (S8) implies that there are possible iSCSI tasks that have not reached conclusion and are still considered busy. Main character energy, but make it a little messy ๐งน
7.1.3. Standard Connection State Diagram for an Initiator
Here are the symbolic names for the states, bestie ๐ซถ
S1: FREES2: XPT_WAITS4: IN_LOGINS5: LOGGED_INS6: IN_LOGOUTS7: LOGOUT_REQUESTEDS8: CLEANUP_WAIT
States S5, S6, and S7 make up the Full Feature Phase operation of the connection, so that's the main event ๐
Now the diagram. It's a lot, but it's giving art ๐จ
-------<-------------+
+--------->/ S1 \<----+ |
T13| +->\ /<-+ \ |
| / ---+--- \ \ |
| / | T2 \ | |
| T8 | |T1 | | |
| | | / |T7 |
| | | / | |
| | | / | |
| | V / / |
| | ------- / / |
| | / S2 \ / |
| | \ / / |
| | ---+--- / |
| | |T4 / |
| | V / | T18
| | ------- / |
| | / S4 \ |
| | \ / |
| | ---+--- | T15
| | |T5 +--------+---------+
| | | /T16+-----+------+ |
| | | / -+-----+--+ | |
| | | / / S7 \ |T12| |
| | | / +->\ /<-+ V V
| | | / / -+----- -------
| | | / /T11 |T10 / S8 \
| | V / / V +----+ \ /
| | ---+-+- ----+-- | -------
| | / S5 \T9 / S6 \<+ ^
| +-----\ /--->\ / T14 |
| ------- --+----+------+T17
+---------------------------+
Next up is the state transition table, which shows the same diagram in grid form. Read each row as the starting state, and whichever transition is in a cell takes you to the state in that column. For example, from S1 you take T1 to land in S2. A - means the transition is undefined ๐
+----+---+---+---+---+----+---+
|S1 |S2 |S4 |S5 |S6 |S7 |S8 |
---+----+---+---+---+---+----+---+
S1| - |T1 | - | - | - | - | - |
---+----+---+---+---+---+----+---+
S2|T2 |- |T4 | - | - | - | - |
---+----+---+---+---+---+----+---+
S4|T7 |- |- |T5 | - | - | - |
---+----+---+---+---+---+----+---+
S5|T8 |- |- | - |T9 |T11 |T15|
---+----+---+---+---+---+----+---+
S6|T13 |- |- | - |T14|- |T17|
---+----+---+---+---+---+----+---+
S7|T18 |- |- | - |T10|T12 |T16|
---+----+---+---+---+---+----+---+
S8| - |- |- | - | - | - | - |
---+----+---+---+---+---+----+---+
7.1.4. Standard Connection State Diagram for a Target โจ
okay so here are the target's connection states, bestie ๐ they're literally the same vibe as the initiator's, just with targets doing the driving ๐
Symbolic names for States:
S1: FREE
S3: XPT_UP
S4: IN_LOGIN
S5: LOGGED_IN
S6: IN_LOGOUT
S7: LOGOUT_REQUESTED
S8: CLEANUP_WAIT
States S5, S6, and S7 make up the Full Feature Phase of the connection ๐ธ that's where all the real action happens!
The state diagram looks like this ๐ฆ
-------<-------------+
+--------->/ S1 \<----+ |
T13| +->\ /<-+ \ |
| / ---+--- \ \ |
| / | T6 \ | |
| T8 | |T3 | | |
| | | / |T7 |
| | | / | |
| | | / | |
| | V / / |
| | ------- / / |
| | / S3 \ / |
| | \ / / | T18
| | ---+--- / |
| | |T4 / |
| | V / |
| | ------- / |
| | / S4 \ |
| | \ / |
| | ---+--- T15 |
| | |T5 +--------+---------+
| | | /T16+-----+------+ |
| | | / -+-----+---+ | |
| | | / / S7 \ |T12| |
| | | / +->\ /<-+ V V
| | | / / -+----- -------
| | | / /T11 |T10 / S8 \
| | V / / V \ /
| | ---+-+- ------- -------
| | / S5 \T9 / S6 \ ^
| +-----\ /--->\ / |
| ------- --+----+--------+T17
+---------------------------+
Here's the state transition table that matches the diagram. It follows the same conventions as the initiator diagram ๐
+----+---+---+---+---+----+---+
|S1 |S3 |S4 |S5 |S6 |S7 |S8 |
---+----+---+---+---+---+----+---+
S1| - |T3 | - | - | - | - | - |
---+----+---+---+---+---+----+---+
S3|T6 |- |T4 | - | - | - | - |
---+----+---+---+---+---+----+---+
S4|T7 |- |- |T5 | - | - | - |
---+----+---+---+---+---+----+---+
S5|T8 |- |- | - |T9 |T11 |T15|
---+----+---+---+---+---+----+---+
S6|T13 |- |- | - |- |- |T17|
---+----+---+---+---+---+----+---+
S7|T18 |- |- | - |T10|T12 |T16|
---+----+---+---+---+---+----+---+
S8| - |- |- | - | - | - | - |
---+----+---+---+---+---+----+---+
7.2. Connection Cleanup State Diagram for Initiators and Targets ๐งน
Symbolic names for states:
R1: CLEANUP_WAIT (same as S8)
R2: IN_CLEANUP
R3: FREE (same as S1)
okay this part is a little bit of a plot twist ๐ซฃ whenever a connection state machine (for example CSM-C) lands in the CLEANUP_WAIT state (S8), it must go through the transitions in the connection cleanup state diagram. It can do that in one of two ways:
- a) using a separate full-feature phase connection (let's call it CSM-E) that's in the LOGGED_IN state in the same session, or
- b) using a new transport connection (let's call it CSM-I) that's in the FREE state and gets added to the same session.
In the CSM-E case, an explicit logout for the CID that corresponds to CSM-C (either as a connection or session logout) needs to be performed to finish the cleanup. In the CSM-I case, an implicit logout for the CID that corresponds to CSM-C needs to be performed by way of connection reinstatement (section 5.3.4) for that CID. Either way, the protocol exchanges happening on CSM-E or CSM-I are what decide the state transitions for CSM-C. So this cleanup diagram only applies to the one connection that's being cleaned up (that's CSM-C) ๐ฏ
For the implicit logout, CSM-C reaches FREE (R3) at the moment CSM-I reaches LOGGED_IN. For the explicit logout, CSM-C reaches FREE (R3) when CSM-E gets a successful logout response while it's still sitting in the LOGGED_IN state.
An initiator must start an explicit or implicit connection logout for a connection in the CLEANUP_WAIT state, if the initiator plans on continuing to use the associated iSCSI session ๐
The following state diagram works for both initiators and targets โจ
-------
/ R1 \
+--\ /<-+
/ ---+---
/ | \ M3
M1 | |M2 |
| | /
| | /
| | /
| V /
| ------- /
| / R2 \
| \ /
| -------
| |
| |M4
| |
| |
| |
| V
| -------
| / R3 \
+---->\ /
-------
Here's the matching state transition table. It follows the same conventions as in the earlier sections ๐
+----+----+----+
|R1 |R2 |R3 |
-----+----+----+----+
R1 | - |M2 |M1 |
-----+----+----+----+
R2 |M3 | - |M4 |
-----+----+----+----+
R3 | - | - | - |
-----+----+----+----+
7.2.1. State Descriptions for Initiators and Targets ๐ง
- R1: CLEANUP_WAIT (Same as S8)
- initiator: Waiting for the internal event to start the cleanup processing for CSM-C.
- target: Waiting for the cleanup process to start for CSM-C.
- R2: IN_CLEANUP
- initiator: Waiting for the connection cleanup process to conclude for CSM-C.
- target: Waiting for the connection cleanup process to conclude for CSM-C.
- R3: FREE (Same as S1)
- initiator: End state for CSM-C.
- target: End state for CSM-C.
7.2.2. State Transition Descriptions for Initiators and Targets ๐ฆ
- M1: One or more of the following events was received:
- initiator:
- An internal event that indicates a connection state timeout.
- An internal event of receiving a successful Logout response on a different connection for a "close the session" Logout.
- target:
- An internal event that indicates a connection state timeout.
- An internal event of sending a Logout response (success) on a different connection for a "close the session" Logout request.
- initiator:
- M2: An implicit or explicit logout process was initiated by the initiator.
- In CSM-I usage:
- initiator: An internal event requesting the connection (or session) reinstatement was received, which prompted a connection (or session) reinstatement Login to be sent, moving CSM-I into state IN_LOGIN.
- target: A connection or session reinstatement Login was received while in state XPT_UP.
- In CSM-E usage:
- initiator: An internal event indicating that an explicit logout was sent for this CID in state LOGGED_IN.
- target: An explicit logout was received for this CID in state LOGGED_IN.
- In CSM-I usage:
- M3: Logout failure detected ๐ฌ
- In CSM-I usage:
- initiator: CSM-I failed to reach LOGGED_IN and arrived in FREE instead.
- target: CSM-I failed to reach LOGGED_IN and arrived in FREE instead.
- In CSM-E usage:
- initiator: CSM-E either moved out of LOGGED_IN, or the Logout timed out and/or was aborted, or a Logout response (failure) was received.
- target: CSM-E either moved out of LOGGED_IN, the Logout timed out and/or was aborted, or an internal event indicating that a failed Logout processing was received. A Logout response (failure) was sent in the last case.
- In CSM-I usage:
- M4: A successful implicit or explicit logout was performed. ๐
- In CSM-I usage:
- initiator: CSM-I reached state LOGGED_IN, or an internal event of receiving a Logout response (success) on another connection for a "close the session" Logout request was received.
- target: CSM-I reached state LOGGED_IN, or an internal event of sending a Logout response (success) on a different connection for a "close the session" Logout request was received.
- In CSM-E usage:
- initiator: CSM-E stayed in LOGGED_IN and received a Logout response (success), or an internal event of receiving a Logout response (success) on another connection for a "close the session" Logout request was received.
- target: CSM-E stayed in LOGGED_IN and an internal event indicating successful Logout processing was received, or an internal event of sending a Logout response (success) on a different connection for a "close the session" Logout request was received.
- In CSM-I usage:
7.3. Session State Diagrams ๐
7.3.1. Session State Diagram for an Initiator ๐
Symbolic Names for States:
Q1: FREE
Q3: LOGGED_IN
Q4: FAILED
State Q3 is the Full Feature Phase operation of the session โจ
The state diagram looks like this:
-------
/ Q1 \
+------>\ /<-+
/ ---+--- |
/ | |N3
N6 | |N1 |
| | |
| N4 | |
| +--------+ | /
| | | | /
| | | | /
| | V V /
-+--+-- -----+-
/ Q4 \ N5 / Q3 \
\ /<---\ /
------- -------
The state transition table is as follows:
+----+----+----+
|Q1 |Q3 |Q4 |
-----+----+----+----+
Q1 | - |N1 | - |
-----+----+----+----+
Q3 |N3 | - |N5 |
-----+----+----+----+
Q4 |N6 |N4 | - |
-----+----+----+----+
7.3.2. Session State Diagram for a Target ๐ฏ
Okay bestie, this one is the session state machine from the target's side ๐ Here are the symbolic names first:
Q1: FREEQ2: ACTIVEQ3: LOGGED_INQ4: FAILEDQ5: IN_CONTINUE
Q3 is the main-character era of the session ๐ It's where the Full Feature Phase operation lives.
Here's the diagram, no cap it's kind of a lot ๐ง
-------
+------------------>/ Q1 \
/ +-------------->\ /<-+
| | ---+--- |
| | ^ | |N3
N6 | |N11 N9| V N1 |
| | +------ |
| | / Q2 \ |
| | \ / |
| --+---- +--+--- |
| / Q5 \ | |
| \ / N10 | |
| +-+---+------------+ |N2 /
| ^ | | | /
|N7| |N8 | | /
| | | | V /
-+--+-V V----+-
/ Q4 \ N5 / Q3 \
\ /<-------------\ /
------- -------
And here's the transition table, all laid out ๐
+----+----+----+----+----+
|Q1 |Q2 |Q3 |Q4 |Q5 |
-----+----+----+----+----+----+
Q1 | - |N1 | - | - | - |
-----+----+----+----+----+----+
Q2 |N9 | - |N2 | - | - |
-----+----+----+----+----+----+
Q3 |N3 | - | - |N5 | - |
-----+----+----+----+----+----+
Q4 |N6 | - | - | - |N7 |
-----+----+----+----+----+----+
Q5 |N11 | - |N10 |N8 | - |
-----+----+----+----+----+----+
7.3.3. State Descriptions for Initiators and Targets ๐
Here's what each state means for each side ๐ฆ
Q1: FREE- initiator: This is where things start on instantiation, or after cleanup.
- target: Same vibe, the target starts here on instantiation or after cleanup.
Q2: ACTIVE- initiator: Illegal.
- target: The first iSCSI connection in the session has moved to
IN_LOGIN, and the target is waiting for that connection to finish logging in.
Q3: LOGGED_IN- initiator: Waiting for all session events.
- target: Waiting for all session events.
Q4: FAILED- initiator: Waiting for session recovery or session continuation.
- target: Waiting for session recovery or session continuation.
Q5: IN_CONTINUE- initiator: Illegal.
- target: Waiting for a session continuation attempt to reach a conclusion.
7.3.4. State Transition Descriptions for Initiators and Targets โจ
Now the plot twists ๐ Each N is an event that moves the session around.
N1- initiator: At least one transport connection has reached the LOGGED_IN state.
- target: The first iSCSI connection in the session had reached the
IN_LOGINstate.
N2- initiator: Illegal.
- target: At least one iSCSI connection has reached the LOGGED_IN state.
N3- initiator: The session is closed gracefully through session closure (Section 5.3.6 Session Continuation and Failure).
- target: The session is closed gracefully through session closure (Section 5.3.6 Session Continuation and Failure), or a successful session reinstatement cleanly closed the session.
N4- initiator: A session continuation attempt succeeded.
- target: Illegal.
N5- initiator: Session failure (Section 5.3.6 Session Continuation and Failure) occurred.
- target: Session failure (Section 5.3.6 Session Continuation and Failure) occurred.
N6- initiator: A session state timeout occurred, or a session reinstatement cleared this session instance. This frees all the associated resources, and the session state is discarded ๐ฅ
- target: A session state timeout occurred, or a session reinstatement cleared this session instance. This frees all the associated resources, and the session state is discarded ๐ฅ
N7- initiator: Illegal.
- target: A session continuation attempt is initiated.
N8- initiator: Illegal.
- target: The last session continuation attempt failed.
N9- initiator: Illegal.
- target: The login attempt on the leading connection failed.
N10- initiator: Illegal.
- target: A session continuation attempt succeeded.
N11- initiator: Illegal.
- target: A successful session reinstatement cleanly closed the session.
8. Security Considerations ๐
Okay so historically, native storage systems never really had to stress about security ๐ Their environments were pretty chill on risk, since the storage devices were either plugged straight into hosts or sitting on a SAN that was totally separate from the regular communications network. Once storage protocols like SCSI start running over IP networks, though, security suddenly has to be a whole priority ๐ญ
iSCSI implementations MUST provide protection against active attacks (for example, pretending to be another identity, inserting, deleting, modifying, and replaying messages) and passive attacks (for example, eavesdropping, or gaining an advantage by analyzing the data sent over the line). This is non-negotiable bestie ๐
iSCSI SHOULD NOT be configured without security. Technically it's possible, but iSCSI configured without security should be confined, in extreme cases, to closed environments that have no security risk at all. [RFC3723] specifies the mechanisms that must be used in order to fully mitigate the risks described in that document ๐จ
Here's the rundown on the security mechanisms an iSCSI implementation provides ๐ก๏ธ
8.1. iSCSI Security Mechanisms ๐ก๏ธ
The entities involved in iSCSI security are the initiator, the target, and the IP communication end points. We expect scenarios where several initiators or targets share a single communication end point, so iSCSI uses two separate security mechanisms to handle that ๐ซถ The first is in-band authentication between the initiator and the target at the iSCSI connection level, carried out by exchanging iSCSI Login PDUs. The second is packet protection (integrity, authentication, and confidentiality) by IPsec at the IP level. They complement each other perfectly โจ In-band authentication gives end-to-end trust between the iSCSI initiator and the target at login time, while IPsec gives a secure channel between the IP communication end points.
More details on typical iSCSI scenarios, and on how initiators, targets, and communication end points relate to each other, can be found in [RFC3723].
8.2. In-band Initiator-Target Authentication ๐
During login, the target MAY authenticate the initiator, and the initiator MAY authenticate the target. This happens on every new iSCSI connection through an exchange of iSCSI Login PDUs, using a negotiated authentication method.
The authentication method can't count on IPsec being underneath it, since IPsec is optional to use ๐ An attacker should gain as little advantage as possible from inspecting the authentication phase PDUs. So a method that uses clear text passwords (or something equivalent) is not acceptable. On the other hand, identity protection isn't strictly required.
The authentication mechanism protects against an unauthorized login to storage resources by using a false identity (spoofing). Once the authentication phase is done, if IPsec isn't being used, everything is sent and received in clear. The authentication mechanism on its own (without IPsec underneath) should only be used when there is no risk of eavesdropping, message insertion, deletion, modification, and replaying.
Section 11 iSCSI Security Text Keys and Authentication Methods defines several authentication methods and the exact steps that must be followed in each of them, including the iSCSI-text-keys and their allowed values in each step. Whenever an iSCSI initiator gets a response whose keys, or their values, don't match the step definition, it MUST abort the connection. Whenever an iSCSI target gets a response whose keys, or their values, don't match the step definition, it MUST answer with a Login reject carrying the "Initiator Error" or "Missing Parameter" status. Those statuses aren't meant for cryptographically incorrect values such as the CHAP response, for which the "Authentication Failure" status MUST be specified ๐ซ
This rule matters a lot, so here's why. In CHAP with target authentication (see Section 11.1.4 Challenge Handshake Authentication Protocol (CHAP)), the initiator could conduct a reflection attack by leaving out its response key (CHAP_R), reusing the same CHAP challenge as the target, and reflecting the target's response back at the target ๐ฑ CHAP stops this because the target has to answer a missing CHAP_R key with a Login reject carrying the "Missing Parameter" status.
For some of the authentication methods, a key specifies the identity of the iSCSI initiator or target for authentication purposes. The value tied to that key MAY be different from the iSCSI name, and SHOULD be configurable. (CHAP_N, see Section 11.1.4 Challenge Handshake Authentication Protocol (CHAP), and SRP_U, see Section 11.1.3 Secure Remote Password (SRP).) ๐
8.2.1. CHAP Considerations โจ
okay bestie, CHAP is up next and it's giving serious security drama ๐ Compliant iSCSI initiators and targets MUST implement the CHAP authentication method [RFC1994] (according to Section 11.1.4 Challenge Handshake Authentication Protocol (CHAP) including the target authentication option). ๐
ngl, when CHAP runs over a channel that isn't encrypted, it's vulnerable to an off-line dictionary attack ๐ญ so implementations MUST support use of up to 128 bit random CHAP secrets ๐, including the means to generate those secrets and to accept them from an external generation source. And the only secret generation (or expansion) means an implementation MUST NOT provide is anything other than random generation ๐ซถ
highkey, if an administrative entity is using CHAP with a secret that has less than 96 random bits, it MUST enforce IPsec encryption (according to the implementation requirements in Section 8.3.2 Confidentiality) to protect the connection ๐ก๏ธ Moreover, in this case IKE authentication with group pre-shared cryptographic keys SHOULD NOT be used unless it is not essential to protect group members against off-line dictionary attacks by other members. ๐
CHAP secrets MUST be an integral number of bytes (octets) ๐ A compliant implementation SHOULD NOT continue with the login step in which it should send a CHAP response (CHAP_R, Section 11.1.4 Challenge Handshake Authentication Protocol (CHAP)) unless it can verify that the CHAP secret is at least 96 bits, or that IPsec encryption is being used to protect the connection.
Now the main event ๐ Any CHAP secret used for initiator authentication MUST NOT be configured for authentication of any target, and any CHAP secret used for target authentication MUST NOT be configured for authentication of any initiator. If the CHAP response received by one end of an iSCSI connection is the same as the CHAP response that the receiving endpoint would have generated for the same CHAP challenge, the response MUST be treated as an authentication failure and cause the connection to close (this ensures that the same CHAP secret is not used for authentication in both directions). Also, if an iSCSI implementation can function as both initiator and target, different CHAP secrets and identities MUST be configured for these two roles. ๐ฆ
Here's the attack these rules are stopping, and it's sooo sneaky:
Rogue wants to impersonate Storage to Alice, and knows that a
single secret is used for both directions of Storage-Alice
authentication.
Rogue convinces Alice to open two connections to Rogue, and Rogue
identifies itself as Storage on both connections.
Rogue issues a CHAP challenge on connection 1, waits for Alice to
respond, and then reflects Alice's challenge as the initial
challenge to Alice on connection 2.
If Alice doesn't check for the reflection across connections,
Alice's response on connection 2 enables Rogue to impersonate
Storage on connection 1, even though Rogue does not know the
Alice-Storage CHAP secret.
Originators MUST NOT reuse the CHAP challenge sent by the Responder for the other direction of a bidirectional authentication. Responders MUST check for this condition and close the iSCSI TCP connection if it occurs. ๐ซ
The same CHAP secret SHOULD NOT be configured for authentication of multiple initiators or multiple targets, because that lets any of them impersonate any other one of them, and if one gets compromised, the attacker can impersonate any of them ๐ฌ It is recommended that iSCSI implementations check for use of identical CHAP secrets by different peers when this check is feasible, and take appropriate measures to warn users and/or administrators when this is detected. ๐
When an iSCSI initiator or target authenticates itself to counterparts in multiple administrative domains, it SHOULD use a different CHAP secret for each administrative domain to avoid propagating security compromises across domains. ๐
Within a single administrative domain, the rules are a bit more chill:
- A single CHAP secret MAY be used for authentication of an initiator to multiple targets.
- A single CHAP secret MAY be used for an authentication of a target to multiple initiators when the initiators use an external server (e.g., RADIUS) to verify the target's CHAP responses and do not know the target's CHAP secret.
If an external response verification server (e.g., RADIUS) is not used, employing a single CHAP secret for authentication of a target to multiple initiators requires that all such initiators know that target secret. Any of these initiators can impersonate the target to any other such initiator, and compromise of such an initiator enables an attacker to impersonate the target to all such initiators. Targets SHOULD use separate CHAP secrets for authentication to each initiator when such risks are of concern; in this situation it may be useful to configure a separate logical iSCSI target with its own iSCSI Node Name for each initiator or group of initiators among which such separation is desired. ๐ง
8.2.2. SRP Considerations ๐
The strength of the SRP authentication method (specified in [RFC2945]) depends on the characteristics of the group being used (i.e., the prime modulus N and generator g). As described in [RFC2945], N is required to be a Sophie-German prime (of the form N = 2q + 1, where q is also prime) and the generator g is a primitive root of GF(n). In iSCSI authentication, the prime modulus N MUST be at least 768 bits. ๐ข
The list of allowed SRP groups is provided in [RFC3723]. ๐
8.3. IPsec ๐ธ
iSCSI uses the IPsec mechanism for packet protection (cryptographic integrity, authentication, and confidentiality) at the IP level between the iSCSI communicating end points. The following sections describe the IPsec protocols that must be implemented for data integrity and authentication, confidentiality, and cryptographic key management. ๐
An iSCSI initiator or target may provide the required IPsec support fully integrated or in conjunction with an IPsec front-end device. In the latter case, the compliance requirements with regard to IPsec support apply to the "combined device". Only the "combined device" is to be considered an iSCSI device. ๐
Detailed considerations and recommendations for using IPsec for iSCSI are provided in [RFC3723]. ๐
8.3.1. Data Integrity and Authentication ๐ฆ
Data authentication and integrity is provided by a cryptographic keyed Message Authentication Code in every sent packet. This code protects against message insertion, deletion, and modification. Protection against message replay is realized by using a sequence counter. ๐
An iSCSI compliant initiator or target MUST provide data integrity and authentication by implementing IPsec [RFC2401] with ESP [RFC2406] in tunnel mode and MAY provide data integrity and authentication by implementing IPsec with ESP in transport mode. The IPsec implementation MUST fulfill the following iSCSI specific requirements:
- HMAC-SHA1 MUST be implemented [RFC2404].
- AES CBC MAC with XCBC extensions SHOULD be implemented [RFC3566].
The ESP anti-replay service MUST also be implemented. ๐ก๏ธ
At the high speeds iSCSI is expected to operate, a single IPsec SA could rapidly cycle through the 32-bit IPsec sequence number space ๐ณ In view of this, it may be desirable in the future for an iSCSI implementation that operates at speeds of 1 Gbps or greater to implement the IPsec sequence number extension [SEQ-EXT]. ๐
8.3.2. Confidentiality ๐คซ
Confidentiality is provided by encrypting the data in every packet. When confidentiality is used it MUST be accompanied by data integrity and authentication to provide comprehensive protection against eavesdropping, message insertion, deletion, modification, and replaying. ๐
An iSCSI compliant initiator or target MUST provide confidentiality by implementing IPsec [RFC2401] with ESP [RFC2406] in tunnel mode and MAY provide confidentiality by implementing IPsec with ESP in transport mode, with the following iSCSI specific requirements:
- 3DES in CBC mode MUST be implemented [RFC2451].
- AES in Counter mode SHOULD be implemented [RFC3686].
DES in CBC mode SHOULD NOT be used due to its inherent weakness. The NULL encryption algorithm MUST also be implemented. ๐
8.3.3. Policy, Security Associations, and Cryptographic Key Management ๐
A compliant iSCSI implementation MUST meet the cryptographic key management requirements of the IPsec protocol suite. Authentication, security association negotiation, and cryptographic key management MUST be provided by implementing IKE [RFC2409] using the IPsec DOI [RFC2407] with the following iSCSI specific requirements:
- Peer authentication using a pre-shared cryptographic key MUST be supported. Certificate-based peer authentication using digital signatures MAY be supported. Peer authentication using the public key encryption methods outlined in IKE sections 5.2 and 5.3[7] SHOULD NOT be used.
- When digital signatures are used to achieve authentication, an IKE negotiator SHOULD use IKE Certificate Request Payload(s) to specify the certificate authority. IKE negotiators SHOULD check the pertinent Certificate Revocation List (CRL) before accepting a PKI certificate for use in IKE authentication procedures.
- Conformant iSCSI implementations MUST support IKE Main Mode and SHOULD support Aggressive Mode. IKE main mode with pre-shared key authentication method SHOULD NOT be used when either the initiator or the target uses dynamically assigned IP addresses. While in many cases pre-shared keys offer good security, situations in which dynamically assigned addresses are used force the use of a group pre-shared key, which creates vulnerability to a man-in-the-middle attack. ๐ต๏ธ
- In the IKE Phase 2 Quick Mode, exchanges for creating the Phase 2 SA, the Identity Payload, fields MUST be present.
ID_IPV4_ADDR,ID_IPV6_ADDR(if the protocol stack supports IPv6) andID_FQDNIdentity payloads MUST be supported;ID_USER_FQDNSHOULD be supported. The IP Subnet, IP Address Range,ID_DER_ASN1_DN, andID_DER_ASN1_GNformats SHOULD NOT be used. TheID_KEY_IDIdentity Payload MUST NOT be used. ๐ชช
Manual cryptographic keying MUST NOT be used because it does not provide the necessary re-keying support. ๐
When IPsec is used, the receipt of an IKE Phase 2 delete message SHOULD NOT be interpreted as a reason for tearing down the iSCSI TCP connection. If additional traffic is sent on it, a new IKE Phase 2 SA will be created to protect it. ๐
The method used by the initiator to determine whether the target should be connected using IPsec is regarded as an issue of IPsec policy administration, and thus not defined in the iSCSI standard. ๐
If an iSCSI target is discovered via a SendTargets request in a discovery session not using IPsec, the initiator should assume that it does not need IPsec to establish a session to that target. If an iSCSI target is discovered using a discovery session that does use IPsec, the initiator SHOULD use IPsec when establishing a session to that target. โจ
9. Notes to Implementers โจ
okay bestie, this section is the "read this before you build" corner ๐. It covers performance and reliability stuff for iSCSI. The protocol was designed to be efficient in both silicon and software ๐ , and the iSCSI task tag mechanism exists so Direct Data Placement (DDP, which is a DMA form ๐ง) can happen at the iSCSI level or lower.
The big guiding assumption behind the whole design is that targets are resource constrained compared to initiators ๐ฅบ so keep that in mind, periodt.
Implementers are also advised to think about the implementation consequences of the iSCSI to SCSI mapping model in Section 3.4.3 Consequences of the Model. Go reread that one, it's giving foundation ๐ฆ
9.1. Multiple Network Adapters
iSCSI lets you have multiple connections, and they don't all have to go over the same network adapter ๐ธ. If you're using several network connections with hardware support, the command-data-status allegiance to one TCP connection means there's no need to copy info across network adapters or make them cooperate. No extra drama ๐
Hot take though: some task management commands may need some loose form of cooperation or replication, at least on the target ๐
9.1.1. Conservative Reuse of ISIDs
Okay, history lesson ๐. The SCSI model (and the implementations and apps built on it) has long assumed that SCSI ports are static, physical entities. Newer SCSI extensions take advantage of persistent worldwide unique names for those ports โจ. In iSCSI, though, the SCSI initiator ports are the endpoints of dynamically created sessions, so "static and physical" doesn't really apply ๐. Anyway, the model clauses (especially Section 3.4.2 SCSI Architecture Model) allow for persistent, reusable names for iSCSI-type SCSI initiator ports, even though there doesn't need to be any physical entity bound to those names ๐.
To keep legacy apps from getting disrupted and to make the SCSI features that rely on persistent port names work better, iSCSI implementations SHOULD attempt to provide a stable presentation of SCSI Initiator Ports (both to the upper OS layers and to the targets they connect to) ๐ซถ. An initiator can do this by conservatively reusing ISIDs. In other words, the same ISID should be used in the Login process to multiple target portal groups (of the same iSCSI Target or different iSCSI Targets) ๐.
The ISID RULE in Section 3.4.3 Consequences of the Model only prohibits reuse to the same target portal group. It does not "preclude" reuse to other target portal groups. The principle of conservative reuse "encourages" reuse to other target portal groups ๐. So when a SCSI target device sees the same (InitiatorName, ISID) pair in different sessions to different target portal groups, it can identify the underlying SCSI Initiator Port on each session as the same SCSI port. Basically, it can recognize multiple paths from the same source ๐งโจ.
9.1.2. iSCSI Name, ISID, and TPGT Use
The designers of iSCSI envisioned one iSCSI Initiator Node Name per operating system image on a machine ๐ป. This enables SAN resource configuration and authentication schemes based on a system's identity. It supports the idea that you should be able to assign access to storage resources based on "initiator device" identity ๐.
When there are multiple hardware or software components coordinated as a single iSCSI Node, there must be some (logical) entity that represents the iSCSI Node and makes the iSCSI Node Name available to all components involved in session creation and login ๐งฉ. Similarly, this entity that represents the iSCSI Node must be able to coordinate session identifier resources (ISID for initiators) to enforce both the ISID and TSIH RULES (see Section 3.4.3 Consequences of the Model) ๐.
For targets, the environment is closed, so implementing this entity should be straightforward ๐ท. However, vendors of iSCSI hardware (e.g., NICs or HBAs) intended for targets SHOULD provide mechanisms for configuring the iSCSI Node Name across the portal groups instantiated by multiple instances of these components within a target ๐ ๏ธ.
Complex targets that use multiple Target Portal Group Tags may reconfigure them to hit various quality goals ๐ฏ. Initiators have two mechanisms to discover and/or check reconfiguring targets: the discovery session type, and a key returned by the target during login to confirm the TPGT ๐ต๏ธโโ๏ธ. An initiator should attempt to "rediscover" the target configuration any time a session is terminated unexpectedly ๐.
For initiators, long term, operating system vendors are expected to take on the role of this entity and provide standard APIs that can tell components their iSCSI Node Name and can configure and/or coordinate ISID allocation, use, and reuse ๐ฅ๏ธโจ.
Those initiator APIs aren't available today, so other implementations of this role are possible ๐ . For example, a human may set up the (common) Node name during the installation of each iSCSI component involved in session creation and login ๐งโ๐ป. This can be done by pointing the component to a vendor-specific location for this datum or to a system-wide location.
The structure of the ISID namespace (see Section 10.12.5 ISID and [RFC3721]) makes ISID coordination easier, because each component vendor can independently coordinate allocation, use, and reuse of its own partition of the ISID namespace in a vendor-specific manner ๐ง. Partitioning the ISID namespace within initiator portal groups managed by that vendor lets each initiator portal group act independently of all the others when selecting an ISID for a login. That helps enforce the ISID RULE (see Section 3.4.3 Consequences of the Model) at the initiator ๐ฆ.
A vendor of iSCSI hardware (e.g., NICs or HBAs) intended for use in initiators MUST implement a mechanism for configuring the iSCSI Node Name ๐. Vendors and administrators must ensure that iSCSI Node Names are unique worldwide ๐. So it's important that if you reuse the iSCSI Node Name of a disabled unit, you don't re-assign that name to the original unit unless its worldwide uniqueness can be confirmed again ๐ โโ๏ธ.
Also, a vendor of iSCSI hardware must implement a mechanism to configure and/or coordinate ISIDs for all sessions managed by multiple instances of that hardware within a given iSCSI Node ๐. That configuration might be permanently pre-assigned at the factory (in a necessarily globally unique way), statically assigned (e.g., partitioned across all the NICs at initialization in a locally unique way), or dynamically assigned (e.g., by an on-line allocator, also in a locally unique way) ๐ญ. In the latter two cases, the configuration may happen via public APIs (perhaps driven by an independent vendor's software, such as the OS vendor) or via private APIs driven by the vendor's own software ๐.
9.2. Autosense and Auto Contingent Allegiance (ACA)
Autosense is the automatic return of sense data to the initiator when a command didn't complete successfully ๐จ. iSCSI initiators and targets MUST support and use autosense. No skipping this one, bestie ๐.
ACA helps preserve ordered command execution in the presence of errors ๐. Since iSCSI can have lots of commands in flight between initiator and target, iSCSI initiators and targets SHOULD support ACA ๐.
9.3. iSCSI Timeouts
iSCSI recovery actions often depend on iSCSI time-outs being recognized and acted on before SCSI time-outs โฐ. Figuring out the right time-outs for various iSCSI actions (command acknowledgements expected, status acknowledgements, etc.) really depends on the infrastructure (hardware, links, TCP/IP stack, iSCSI driver) ๐ง . As a guide, the implementer may use an average Nop-Out/Nop-In turnaround delay multiplied by a "safety factor" (e.g., 4) as a good estimate for the basic delay of the iSCSI stack for a given connection ๐. The safety factor should account for network load variability ๐. For connection teardown, the implementer may want to also consider the TCP common practice for the given infrastructure ๐งน.
Text negotiations MAY also be subject to time-limits or limits in the number of exchanges ๐. Those SHOULD be generous enough to avoid affecting interoperability (e.g., allowing each key to be negotiated on a separate exchange) ๐ซถ.
The relation between iSCSI timeouts and SCSI timeouts also matters ๐. SCSI timeouts should be longer than iSCSI timeouts plus the time required for iSCSI recovery whenever iSCSI recovery is planned ๐ฐ๏ธ. Alternatively, an implementer may choose to interlock iSCSI timeouts and recovery with SCSI timeouts, so SCSI recovery only becomes active where iSCSI isn't planned to recover, or failed to recover ๐.
The implementer may also want to think about how various iSCSI exception events (such as a digest failure) interact with later timeouts ๐ง. When iSCSI error recovery is active, a digest failure is likely to lead to discovering a missing command or data PDU ๐ต๏ธโโ๏ธ. In those cases, an implementer may want to lower the timeout values so recovery procedures start faster ๐โโ๏ธ๐จ.
9.4. Command Retry and Cleaning Old Command Instances
To keep old, retried command instances from showing up in a valid command window after a command sequence number wraps around, the protocol requires (see Section 3.2.2.1 Command Numbering and Acknowledging) that on every connection where a retry has been issued, a non-immediate command be issued and acknowledged within a 2**31-1 commands interval from the CmdSN of the retried command ๐. There are several ways an implementation can meet this requirement ๐งฉ.
The simplest technique is to send a (non-retry) non-immediate SCSI command (or a NOP if no SCSI command is available for a while) after every command retry on the connection where the retry was attempted ๐. Errors are deemed rare events, so this technique is probably the most effective, since it doesn't involve extra checks at the initiator when issuing commands ๐.
9.5. Synch and Steering Layer and Performance
A synch and steering layer is optional ๐. But an initiator or target that doesn't have it working against a target or initiator that demands synch and steering may see performance degradation caused by packet reordering and loss ๐. Providing a synch and steering mechanism is recommended for all high-speed implementations ๐โจ.
9.6. Considerations for State-dependent Devices and Long-lasting SCSI Operations ๐
Okay so, sequential access devices run on one main rule: where the device is depends on the last command it processed ๐ผ. That makes command processing order, plus knowing whether the previous command actually got processed, everything for data integrity ๐ญ. Blindly retrying SCSI commands when you don't know if the last one went through is a real data integrity risk, bestie.
Picture this: a SCSI SPACE command to backspace one filemark gets issued, then gets re-issued because no status came back. If the first SPACE was actually processed, the re-issued SPACE (if it's processed too) moves the position again. So a later write lands in the wrong spot and whatever was there gets overwritten ๐.
Now for medium changers ๐. An EXCHANGE MEDIUM command where the SOURCE ADDRESS and DESTINATION ADDRESS are the same (so it's a swap) gets issued, then re-issued due to no status. If the first one was processed, the re-issued one performs the swap again. The net result is that no swap happened at all, which leaves a data integrity exposure ๐.
All commands that change the state of the device (SPACE commands for sequential access devices, and EXCHANGE MEDIUM for medium changer devices) MUST be issued as non-immediate commands for deterministic and in order delivery to iSCSI targets ๐ซถ.
Many of those state-changing commands also assume they run exactly once โจ. Devices that implement READ POSITION and LOCATE give you a way to do SCSI-level command recovery, and new tape-class devices should support those commands. Without them, a retry at SCSI level is difficult, so error recovery at iSCSI level is advisable ๐.
Devices on long latency delivery subsystems that do long lasting SCSI operations may need mechanisms that enable connection replacement while commands are running (e.g., during an extended copy operation) ๐.
9.6.1. Determining the Proper ErrorRecoveryLevel ๐ง
The ErrorRecoveryLevel you use should be decided based on the deployment scenarios of a given iSCSI implementation. Generally, these factors must be considered before you pick the right level of recovery:
- a) Application resilience to I/O failures.
- b) Required level of availability in the face of transport connection failures.
- c) Probability of transport layer "checksum escape". This in turn decides the iSCSI digest failure frequency, and thus the criticality of iSCSI-level error recovery. The details of estimating this probability are outside the scope of this document.
So if you look at those factors for SCSI tape devices as an example, implementations SHOULD use ErrorRecoveryLevel=1 when transport connection failure is not a concern and SCSI level recovery is unavailable ๐ธ. They SHOULD use ErrorRecoveryLevel=2 when the connection failure is also highly likely during a backup or retrieval ๐.
For extended copy operations, implementations SHOULD use ErrorRecoveryLevel=2 whenever there is a relatively high likelihood of connection failure ๐ฅ.
10. iSCSI PDU Formats ๐
All multi-byte integers that are specified in formats defined in this document are to be represented in network byte order (i.e., big endian) ๐. Any field that appears in this document assumes that the most significant byte is the lowest numbered byte and the most significant bit (within byte or field) is the lowest numbered bit unless specified otherwise.
Any compliant sender MUST set all bits not defined and all reserved fields to zero unless specified otherwise ๐ง. Any compliant receiver MUST ignore any bit not defined and all reserved fields unless specified otherwise. Receipt of reserved code values in defined fields MUST be reported as a protocol error โญ.
Reserved fields are marked by the word "reserved", some abbreviation of "reserved", or by "." for individual bits when no other form of marking is technically feasible ๐ฆ.
10.1. iSCSI PDU Length and Padding
iSCSI PDUs are padded to the closest integer number of four byte words. The padding bytes SHOULD be sent as 0 ๐.
10.2. PDU Template, Header, and Opcodes
All iSCSI PDUs have one or more header segments and, optionally, a data segment. After the entire header segment group a header-digest MAY follow. The data segment MAY also be followed by a data-digest ๐ธ.
The Basic Header Segment (BHS) is the first segment in all of the iSCSI PDUs. The BHS is a fixed-length 48-byte header segment. It MAY be followed by Additional Header Segments (AHS), a Header-Digest, a Data Segment, and/or a Data-Digest โจ.
The overall structure of an iSCSI PDU is as follows ๐:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0/ Basic Header Segment (BHS) /
+/ /
+---------------+---------------+---------------+---------------+
48/ Additional Header Segment 1 (AHS) (optional) /
+/ /
+---------------+---------------+---------------+---------------+
/ Additional Header Segment 2 (AHS) (optional) /
+/ /
+---------------+---------------+---------------+---------------+
----
+---------------+---------------+---------------+---------------+
/ Additional Header Segment n (AHS) (optional) /
+/ /
+---------------+---------------+---------------+---------------+
----
+---------------+---------------+---------------+---------------+
k/ Header-Digest (optional) /
+/ /
+---------------+---------------+---------------+---------------+
l/ Data Segment(optional) /
+/ /
+---------------+---------------+---------------+---------------+
m/ Data-Digest (optional) /
+/ /
+---------------+---------------+---------------+---------------+
All PDU segments and digests are padded to the closest integer number of four byte words. For example, all PDU segments and digests start at a four byte word boundary and the padding ranges from 0 to 3 bytes. The padding bytes SHOULD be sent as 0 ๐ซง.
iSCSI response PDUs do not have AH Segments ๐ โโ๏ธ.
10.2.1. Basic Header Segment (BHS)
The BHS is 48 bytes long. The Opcode and DataSegmentLength fields appear in all iSCSI PDUs. In addition, when used, the Initiator Task Tag and Logical Unit Number always appear in the same location in the header ๐.
The format of the BHS is ๐ :
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|I| Opcode |F| Opcode-specific fields |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN or Opcode-specific fields |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20/ Opcode-specific fields /
+/ /
+---------------+---------------+---------------+---------------+
48
10.2.1.1. I
For request PDUs, the I bit set to 1 is an immediate delivery marker ๐.
10.2.1.2. Opcode
The Opcode indicates the type of iSCSI PDU the header encapsulates ๐ง.
The Opcodes are divided into two categories: initiator opcodes and target opcodes. Initiator opcodes are in PDUs sent by the initiator (request PDUs). Target opcodes are in PDUs sent by the target (response PDUs) ๐.
Initiators MUST NOT use target opcodes and targets MUST NOT use initiator opcodes. That's a hard no, bestie ๐ โโ๏ธ.
Initiator opcodes defined in this specification are ๐ท:
0x00 NOP-Out
0x01 SCSI Command (encapsulates a SCSI Command Descriptor Block)
0x02 SCSI Task Management function request
0x03 Login Request
0x04 Text Request
0x05 SCSI Data-Out (for WRITE operations)
0x06 Logout Request
0x10 SNACK Request
0x1c-0x1e Vendor specific codes
Target opcodes are ๐:
0x20 NOP-In
0x21 SCSI Response - contains SCSI status and possibly sense
information or other response information.
0x22 SCSI Task Management function response
0x23 Login Response
0x24 Text Response
0x25 SCSI Data-In - for READ operations.
0x26 Logout Response
0x31 Ready To Transfer (R2T) - sent by target when it is ready
to receive data.
0x32 Asynchronous Message - sent by target to indicate certain
special conditions.
0x3c-0x3e Vendor specific codes
0x3f Reject
All other opcodes are reserved ๐.
10.2.1.3. Final (F) bit
When set to 1, it indicates the final (or only) PDU of a sequence ๐.
10.2.1.4. Opcode-specific Fields
These fields have different meanings for different opcode types ๐ญ.
10.2.1.5. TotalAHSLength
Total length of all AHS header segments in units of four byte words including padding, if any ๐.
The TotalAHSLength is only used in PDUs that have an AHS and MUST be 0 in all other PDUs. No exceptions, periodt ๐ .
10.2.1.6. DataSegmentLength
This is the data segment payload length in bytes (excluding padding). The DataSegmentLength MUST be 0 whenever the PDU has no data segment ๐ซถ.
10.2.1.7. LUN
Some opcodes operate on a specific Logical Unit. The Logical Unit Number (LUN) field identifies which Logical Unit ๐ฏ. If the opcode does not relate to a Logical Unit, this field is either ignored or may be used in an opcode specific way ๐.
The LUN field is 64-bits and should be formatted in accordance with [SAM2]. For example, LUN[0] from [SAM2] is BHS byte 8 and so on up to LUN[7] from [SAM2], which is BHS byte 15 ๐ฆ.
10.2.1.8. Initiator Task Tag โจ
okay so the initiator hands out a Task Tag to every iSCSI task it sends ๐ While a task exists, this tag MUST uniquely identify that task across the whole session ๐ SCSI can also use the initiator task tag as part of its own SCSI task identifier, but only when the time an iSCSI tag has to stay unique is at least as long as the time a SCSI task tag has to stay unique ๐ง And even untagged SCSI commands need an iSCSI Initiator Task Tag that exists and is unique, no exceptions ๐ซถ
10.2.2. Additional Header Segment (AHS) ๐ฆ
the general shape of an AHS looks like this ๐
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| AHSLength | AHSType | AHS-Specific |
+---------------+---------------+---------------+---------------+
4/ AHS-Specific /
+/ /
+---------------+---------------+---------------+---------------+
x
10.2.2.1. AHSType ๐
the AHSType field is coded like this ๐
bit 0-1 - Reserved
bit 2-7 - AHS code
0 - Reserved
1 - Extended CDB
2 - Expected Bidirectional Read Data Length
3 - 63 Reserved
10.2.2.2. AHSLength ๐ธ
this field holds the effective length in bytes of the AHS, not counting AHSType, AHSLength, or any padding ๐ the AHS gets padded out to the smallest whole number of 4 byte words, so that's anywhere from 0 up to 3 padding bytes, bestie ๐
10.2.2.3. Extended CDB AHS ๐
the format of the Extended CDB AHS is ๐ฅ
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| AHSLength (CDBLength-15) | 0x01 | Reserved |
+---------------+---------------+---------------+---------------+
4/ ExtendedCDB...+padding /
+/ /
+---------------+---------------+---------------+---------------+
x
this type of AHS MUST NOT be used if the CDBLength is less than 17 ๐จ the length includes the reserved byte 3, so keep that in mind ๐ซ
10.2.2.4. Bidirectional Expected Read-Data Length AHS โจ
the format of the Bidirectional Read Expected Data Transfer Length AHS is ๐
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| AHSLength (0x0005) | 0x02 | Reserved |
+---------------+---------------+---------------+---------------+
4| Expected Read-Data Length |
+---------------+---------------+---------------+---------------+
8
10.2.3. Header Digest and Data Digest ๐ก๏ธ
okay so optional header and data digests protect the integrity of the header and the data, one each ๐ซถ the digests, if they're there, sit right after the header and the PDU-specific data, and they cover the header and the PDU data respectively, padding bytes included if there are any ๐ฆ
the existence and type of digests get negotiated during the Login Phase ๐ค
splitting the header and data digests is super useful in iSCSI routing, because only the header changes when a message gets forwarded ๐ท so in that case only the header digest should be recalculated ๐ง
digests are not counted in the data or header length fields ๐ โโ๏ธ
and a zero-length Data Segment also implies a zero-length data-digest ๐
10.2.4. Data Segment ๐
the (optional) Data Segment carries PDU associated data ๐ its payload effective length lives in the BHS field called DataSegmentLength ๐ฅ and the Data Segment gets padded to a whole number of 4 byte words too ๐
10.3. SCSI Command ๐
the format of the SCSI Command PDU is ๐
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|I| 0x01 |F|R|W|. .|ATTR | Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| Logical Unit Number (LUN) |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| Expected Data Transfer Length |
+---------------+---------------+---------------+---------------+
24| CmdSN |
+---------------+---------------+---------------+---------------+
28| ExpStatSN |
+---------------+---------------+---------------+---------------+
32/ SCSI Command Descriptor Block (CDB) /
+/ /
+---------------+---------------+---------------+---------------+
48/ AHS (Optional) /
+---------------+---------------+---------------+---------------+
x/ Header Digest (Optional) /
+---------------+---------------+---------------+---------------+
y/ (DataSegment, Command Data) (Optional) /
+/ /
+---------------+---------------+---------------+---------------+
z/ Data Digest (Optional) /
+---------------+---------------+---------------+---------------+
10.3.1. Flags and Task Attributes (byte 1) ๐ฉ
the flags for a SCSI Command are ๐
bit 0 (F) is set to 1 when no unsolicited SCSI Data-Out PDUs follow
this PDU. When F=1 for a write and if Expected Data
Transfer Length is larger than the DataSegmentLength, the
target may solicit additional data through R2T.
bit 1 (R) is set to 1 when the command is expected to input data.
bit 2 (W) is set to 1 when the command is expected to output data.
bit 3-4 Reserved.
bit 5-7 contains Task Attributes.
Task Attributes (ATTR) have one of these integer values (see [SAM2] for details) โจ
0 - Untagged
1 - Simple
2 - Ordered
3 - Head of Queue
4 - ACA
5-7 - Reserved
setting both the W and the F bit to 0 is an error, bestie ๐ โโ๏ธ either or both of R and W MAY be 1 when the Expected Data Transfer Length and/or Bidirectional Read Expected Data Transfer Length are 0 ๐ but they MUST NOT both be 0 when those lengths are not 0 ๐ซถ (so when some data transfer is expected, the transfer direction is shown by the R and/or W bit) ๐ฆ
10.3.2. CmdSN - Command Sequence Number ๐
this one enables ordered delivery across multiple connections in a single session ๐ง
10.3.3. ExpStatSN ๐ธ
command responses up to ExpStatSN-1 (mod 2**32) have been received on the connection, which is how it acknowledges status ๐
10.3.4. Expected Data Transfer Length ๐
for unidirectional operations, this field holds the number of bytes of data involved in the SCSI operation ๐ฅ for a unidirectional write (W flag set to 1 and R flag set to 0), the initiator uses this field to say how many bytes it expects to send for the operation ๐ for a unidirectional read (W flag set to 0 and R flag set to 1), the initiator uses it to say how many bytes it expects the target to send back ๐ it corresponds to the SAM2 byte count ๐
for bidirectional operations (both R and W flags set to 1), this field holds the number of data bytes in the write transfer ๐ซถ for bidirectional operations, an additional header segment MUST be present in the header sequence that indicates the Bidirectional Read Expected Data Transfer Length โจ the Expected Data Transfer Length field and the Bidirectional Read Expected Data Transfer Length field both correspond to the SAM2 byte count ๐
if the Expected Data Transfer Length for a write and the length of the immediate data part that follows the command (if there is any) are the same, then no more data PDUs are expected to follow ๐ in that case, the F bit MUST be set to 1 ๐จ
if the Expected Data Transfer Length is higher than the FirstBurstLength (the negotiated maximum amount of unsolicited data the target will accept), the initiator MUST send the maximum amount of unsolicited data OR ONLY the immediate data, if any ๐
when a data transfer finishes, the target tells the initiator (through residual counts) how many bytes it actually processed, meaning sent and/or received ๐ง
10.3.5. CDB - SCSI Command Descriptor Block ๐ท
the CDB field has 16 bytes, which is enough for the commonly used CDBs ๐ whenever the CDB is larger than 16 bytes, an Extended CDB AHS MUST be used to hold the CDB spillover ๐
10.3.6. Data Segment - Command Data ๐ฆ
some SCSI commands need extra parameter data along with the command ๐ that data can go past the iSCSI header boundary in a data segment ๐ธ or, alternatively, user data (like from a WRITE operation) can go in the data segment, and both cases are called immediate data ๐ these data follow the rules for solicited vs. unsolicited data outlined in Section 3.2.4.2 Data Transfer Overview ๐ฅ
10.4. SCSI Response ๐
Okay so the SCSI Response PDU is the message the target sends back to say "I'm done with your command, here's how it went" ๐ Bestie, the layout is giving very specific vibes, so here's the whole thing exactly as it goes:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x21 |1|. .|o|u|O|U|.| Response | Status |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| Reserved |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| SNACK Tag or Reserved |
+---------------+---------------+---------------+---------------+
24| StatSN |
+---------------+---------------+---------------+---------------+
28| ExpCmdSN |
+---------------+---------------+---------------+---------------+
32| MaxCmdSN |
+---------------+---------------+---------------+---------------+
36| ExpDataSN or Reserved |
+---------------+---------------+---------------+---------------+
40| Bidirectional Read Residual Count or Reserved |
+---------------+---------------+---------------+---------------+
44| Residual Count or Reserved |
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
/ Data Segment (Optional) /
+/ /
+---------------+---------------+---------------+---------------+
| Data-Digest (Optional) |
+---------------+---------------+---------------+---------------+
10.4.1. Flags (byte 1) ๐ฆ
Bestie, the flag bits are where the drama is โจ
bit 1-2 Reserved.
bit 3 is (o), and it gets set for Bidirectional Read Residual Overflow ๐ Then the Bidirectional Read Residual Count tells you how many bytes never made it back to the initiator, because the initiator's Expected Bidirectional Read Data Transfer Length wasn't big enough.
bit 4 is (u), for Bidirectional Read Residual Underflow ๐ Here the Bidirectional Read Residual Count tells you how many bytes didn't get transferred to the initiator, out of the number that were expected to be transferred.
bit 5 is (O), for Residual Overflow ๐ธ The Residual Count shows how many bytes weren't transferred because the initiator's Expected Data Transfer Length wasn't sufficient. For a bidirectional operation, the Residual Count holds the residual for the write operation.
bit 6 is (U), for Residual Underflow ๐ The Residual Count shows how many bytes weren't transferred out of the number that were expected to be transferred. For a bidirectional operation, the Residual Count holds the residual for the write operation.
bit 7 is (0), and it's Reserved ๐
Bits O and U, and bits o and u, are mutually exclusive, so having both o and u set, or both O and U set to 1, is a protocol error ๐จ Also, for a response other than "Command Completed at Target", bits 3-6 MUST be 0.
10.4.2. Status ๐
The Status field reports the SCSI status of the command (as specified in [SAM2]), and it's only valid if the Response Code is Command Completed at target ๐ง
Some of the status codes defined in [SAM2] are:
0x00 GOOD
0x02 CHECK CONDITION
0x08 BUSY
0x18 RESERVATION CONFLICT
0x28 TASK SET FULL
0x30 ACA ACTIVE
0x40 TASK ABORTED
See [SAM2] for the complete list and definitions ๐
Okay, this part is kinda intense ๐ญ If a SCSI device error gets detected while data from the initiator is still expected (the command PDU didn't contain all the data and the target hasn't received a Data PDU with the final bit Set), the target MUST wait until it receives a Data PDU with the F bit set in the last expected sequence before it sends the Response PDU. No skipping ahead, bestie ๐ โโ๏ธ
10.4.3. Response ๐
This field contains the iSCSI service response ๐
iSCSI service response codes defined in this specification are:
0x00 - Command Completed at Target
0x01 - Target Failure
0x80-0xff - Vendor specific
All other response codes are reserved ๐
The Response is used to report a Service Response. Mapping the response code into a SCSI service response code value, if needed, is outside the scope of this document. But symbolically, response value 0x00 maps to the SCSI service response (see [SAM2] and [SPC3]) of TASK COMPLETE or LINKED COMMAND COMPLETE. Every other Response value maps to the SCSI service response of SERVICE DELIVERY OR TARGET FAILURE ๐ซถ
If a PDU that includes SCSI status (a Response PDU or a Data-In PDU including status) doesn't arrive before the session is terminated, the SCSI service response is SERVICE DELIVERY OR TARGET FAILURE ๐ญ
A non-zero Response field indicates a failure to execute the command, and in that case the Status and Flag fields are undefined ๐
10.4.4. SNACK Tag ๐
This field contains a copy of the SNACK Tag of the last SNACK Tag accepted by the target on the same connection and for the command the response is issued for. Otherwise it's reserved and should be set to 0 โจ
After issuing a R-Data SNACK, the initiator must discard any SCSI status unless it's contained in an SCSI Response PDU carrying the same SNACK Tag as the last issued R-Data SNACK for the SCSI command on the current connection ๐ โโ๏ธ
For a detailed discussion on R-Data SNACK, see Section 10.16 SNACK Request ๐ฆ
10.4.5. Residual Count ๐
The Residual Count field MUST be valid in the case where either the U bit or the O bit is set. If neither bit is set, the Residual Count field is reserved. Targets may set the residual count, and initiators may use it when the response code is "completed at target" (even if the status returned isn't GOOD). If the O bit is set, the Residual Count indicates the number of bytes that weren't transferred because the initiator's Expected Data Transfer Length wasn't sufficient. If the U bit is set, the Residual Count indicates the number of bytes that weren't transferred out of the number of bytes expected to be transferred ๐ธ
10.4.6. Bidirectional Read Residual Count ๐
The Bidirectional Read Residual Count field MUST be valid in the case where either the u bit or the o bit is set. If neither bit is set, the Bidirectional Read Residual Count field is reserved. Targets may set the Bidirectional Read Residual Count, and initiators may use it when the response code is "completed at target". If the o bit is set, the Bidirectional Read Residual Count indicates the number of bytes that weren't transferred to the initiator because the initiator's Expected Bidirectional Read Transfer Length wasn't sufficient. If the u bit is set, the Bidirectional Read Residual Count indicates the number of bytes that weren't transferred to the initiator out of the number of bytes expected to be transferred ๐ฆ
10.4.7. Data Segment - Sense and Response Data Segment ๐ฅ
iSCSI targets MUST support and enable autosense. If Status is CHECK CONDITION (0x02), then the Data Segment MUST contain sense data for the failed command ๐จ
For some iSCSI responses, the response data segment MAY contain some response related information (e.g., for a target failure, it may contain a vendor specific detailed description of the failure) ๐ง
If the DataSegmentLength is not 0, the format of the Data Segment is as follows:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|SenseLength | Sense Data |
+---------------+---------------+---------------+---------------+
x/ Sense Data /
+---------------+---------------+---------------+---------------+
y/ Response Data /
/ /
+---------------+---------------+---------------+---------------+
z|
10.4.7.1. SenseLength ๐ท
Length of Sense Data ๐ท
10.4.7.2. Sense Data ๐
The Sense Data contains detailed information about a check condition, and [SPC3] specifies the format and content of the Sense Data ๐
Certain iSCSI conditions result in the command being terminated at the target (response Command Completed at Target) with a SCSI Check Condition Status, as outlined in the next table ๐
+--------------------------+----------+---------------------------+
| iSCSI Condition |Sense | Additional Sense Code & |
| |Key | Qualifier |
+--------------------------+----------+---------------------------+
| Unexpected unsolicited |Aborted | ASC = 0x0c ASCQ = 0x0c |
| data |Command-0B| Write Error |
+--------------------------+----------+---------------------------+
| Incorrect amount of data |Aborted | ASC = 0x0c ASCQ = 0x0d |
| |Command-0B| Write Error |
+--------------------------+----------+---------------------------+
| Protocol Service CRC |Aborted | ASC = 0x47 ASCQ = 0x05 |
| error |Command-0B| CRC Error Detected |
+--------------------------+----------+---------------------------+
| SNACK rejected |Aborted | ASC = 0x11 ASCQ = 0x13 |
| |Command-0B| Read Error |
+--------------------------+----------+---------------------------+
The target reports the "Incorrect amount of data" condition if, during data output, the total data length to output is greater than FirstBurstLength and the initiator sent unsolicited non-immediate data, but the total amount of unsolicited data is different than FirstBurstLength. The target reports the same error when the amount of data sent as a reply to an R2T doesn't match the amount requested ๐
10.4.8. ExpDataSN ๐ง
The number of R2T and Data-In (read) PDUs the target has sent for the command ๐ซถ
This field MUST be 0 if the response code is not Command Completed at Target, or the target sent no Data-In PDUs for the command ๐
10.4.9. StatSN - Status Sequence Number ๐
okay so StatSN is a Sequence Number that the target iSCSI layer generates per connection โจ, and its whole job is to let the initiator acknowledge that it got the status ๐ซถ. It goes up by 1 for every response/status sent on a connection, EXCEPT for responses sent because of a retry or SNACK, since those are kind of a special case ๐. And if a response is being resent because of a retransmission request, the StatSN MUST be the same as the first time that PDU was sent, unless the connection has since been restarted. no cap, that's the rule, bestie ๐
10.4.10. ExpCmdSN - Next Expected CmdSN from this Initiator ๐
ExpCmdSN is a Sequence Number that the target iSCSI sends back to the initiator to say "yup, got your commands" ๐ฆ. The initiator uses it to update a local variable with the same name. Also, if ExpCmdSN is equal to MaxCmdSN+1, that's the target basically saying "I can't take any new commands rn" ๐
10.4.11. MaxCmdSN - Maximum CmdSN from this Initiator ๐ธ
MaxCmdSN is another Sequence Number the target sends back, and this one tells the initiator the maximum CmdSN it's allowed to send ๐. Same deal as before, the initiator updates a local variable with the same name. If MaxCmdSN is equal to ExpCmdSN-1, that means the target can't receive any more commands, so it's a whole vibe check ๐. Now, when MaxCmdSN changes at the target while the target has no pending PDUs to pass this info along, the target MUST generate a NOP-IN to carry the new MaxCmdSN. that one is non-negotiable, periodt โจ
10.5. Task Management Function Request ๐
Here's the layout for this PDU, bestie ๐ง
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|I| 0x02 |1| Function | Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| Logical Unit Number (LUN) or Reserved |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| Referenced Task Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
24| CmdSN |
+---------------+---------------+---------------+---------------+
28| ExpStatSN |
+---------------+---------------+---------------+---------------+
32| RefCmdSN or Reserved |
+---------------+---------------+---------------+---------------+
36| ExpDataSN or Reserved |
+---------------+---------------+---------------+---------------+
40/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
10.5.1. Function ๐ฆ
Task Management is how an initiator gets to explicitly control one or more Tasks (SCSI and iSCSI tasks) โจ. These are the function codes, lowkey the menu of drama ๐ (for a deeper dive on SCSI task management, check out [SAM2]):
1- ABORT TASK - aborts the task identified by theReferenced Task Tagfield.2- ABORT TASK SET - aborts all Tasks issued via this session on the logical unit.3- CLEAR ACA - clears the Auto Contingent Allegiance condition.4- CLEAR TASK SET - aborts all Tasks in the appropriate task set as defined by the TST field in the Control mode page (see [SPC3]).5- LOGICAL UNIT RESET6- TARGET WARM RESET7- TARGET COLD RESET8- TASK REASSIGN - reassigns connection allegiance for the task identified by theReferenced Task Tagfield to this connection, thus resuming the iSCSI exchanges for the task.
For all of these, the Task Management function response MUST be returned as detailed in Section 10.6 Task Management Function Response ๐. All of these functions apply to the referenced tasks, whether they're proper SCSI tasks or tagged iSCSI operations, so no favourites ๐ซถ. Task management requests must act on all the commands from the same session that have a CmdSN lower than the task management CmdSN. LOGICAL UNIT RESET, TARGET WARM RESET and TARGET COLD RESET may affect commands from other sessions, or commands from the same session with CmdSN equal or exceeding CmdSN ๐.
If the task management request is marked for immediate delivery, it must be considered immediately for execution, but the operations involved (all or part of them) may be postponed so the target can receive all the relevant tasks โณ. According to [SAM2], for all the tasks covered by the Task Management response (so, the ones with CmdSN lower than the task management command CmdSN), except the Task Management response to a TASK REASSIGN, additional responses MUST NOT be delivered to the SCSI layer after the Task Management response ๐ซ. The iSCSI initiator MAY deliver to the SCSI layer all responses it received before the Task Management response. It's an implementation choice whether SCSI responses received before the Task Management response, but after the task management request was issued, get passed up to the SCSI layer by the iSCSI layer in the initiator ๐ง. The iSCSI target MUST ensure that no responses for the tasks covered by a task management function are delivered to the iSCSI initiator after the Task Management response, except for a task covered by a TASK REASSIGN ๐ฅ.
For ABORT TASK SET and CLEAR TASK SET, the issuing initiator MUST continue to respond to all valid target transfer tags (received via R2T, Text Response, NOP-In, or SCSI Data-In PDUs) related to the affected task set, even after issuing the task management request ๐ . The issuing initiator SHOULD however terminate these response sequences (by setting the F-bit to 1) as quickly as possible โก. The target on its part MUST wait for responses on all affected target transfer tags before acting on either of these two task management requests ๐ซถ. If all or part of the response sequence is not received for a valid TTT (because of digest errors), the target MAY treat it as a case of within-command error recovery class (see Section 6.1.4.1 Recovery Within-command) if it supports ErrorRecoveryLevel >= 1. Or it may drop the connection to complete the requested task set function ๐.
If an ABORT TASK is issued for a task created by an immediate command, then RefCmdSN MUST be that of the Task Management request itself (so CmdSN and RefCmdSN are equal). Otherwise, RefCmdSN MUST be set to the CmdSN of the task to be aborted, which is lower than CmdSN โจ.
If the connection is still active (it's not undergoing an implicit or explicit logout), ABORT TASK MUST be issued on the same connection that the task to be aborted is allegiant to at the time the Task Management Request is issued ๐. If the connection is implicitly or explicitly logged out (so no other request will be issued on the failing connection, and no other response will be received on it), then an ABORT TASK function request may be issued on another connection. This Task Management request will then establish a new allegiance for the command to be aborted AND abort it. So the task won't have to be retried or reassigned, and its status, if it was issued but not acknowledged, will be reissued followed by the Task Management response ๐ฆ.
At the target, an ABORT TASK function MUST NOT be executed on a Task Management request. Such a request MUST result in a Task Management response of "Function rejected" ๐ซ
For the LOGICAL UNIT RESET function, the target MUST behave as dictated by the Logical Unit Reset function in [SAM2] ๐.
The TARGET WARM RESET and TARGET COLD RESET functions are OPTIONAL to implement. When they are implemented, they should act as described below ๐. The TARGET WARM RESET is also subject to SCSI access controls on the requesting initiator, as defined in [SPC3]. When authorization fails at the target, the target MUST return the appropriate response described in Section 10.6 Task Management Function Response ๐. The TARGET COLD RESET function is not subject to SCSI access controls, but its execution privileges may be managed by iSCSI mechanisms such as login authentication ๐ง.
When executing the TARGET WARM RESET and TARGET COLD RESET functions, the target cancels all pending operations on all Logical Units known by the issuing initiator. Both functions are equivalent to the Target Reset function specified by [SAM2]. They can affect many other initiators logged in with the servicing SCSI target port ๐ธ.
The target MUST treat the TARGET COLD RESET function additionally as a power on event, which means it terminates all of its TCP connections to all initiators (all sessions are terminated) ๐. For this reason, the Service Response (defined by [SAM2]) for this SCSI task management function may not be reliably delivered to the issuing initiator port ๐ญ.
For the TASK REASSIGN function, the target should reassign the connection allegiance to this new connection, and thus resume iSCSI exchanges for the task ๐. TASK REASSIGN MUST ONLY be received by the target after the connection on which the command was previously executing has been successfully logged out. The Task Management response MUST be issued before the reassignment becomes effective. For more on how this works, see Section 6.2 Retry and Reassign in Recovery ๐.
At the target, a TASK REASSIGN function request MUST NOT be executed to reassign the connection allegiance of a Task Management function request, an active text negotiation task, or a Logout task. Such a request MUST result in a Task Management response of "Function rejected" ๐ โโ๏ธ
TASK REASSIGN MUST be issued as an immediate command โญ.
10.5.2. TotalAHSLength and DataSegmentLength ๐
For this PDU, TotalAHSLength and DataSegmentLength MUST be 0 ๐ซถ.
10.5.3. LUN ๐ธ
This field is required for functions that address a specific LU (ABORT TASK, CLEAR TASK SET, ABORT TASK SET, CLEAR ACA, LOGICAL UNIT RESET) and is reserved in all the others ๐.
10.5.4. Referenced Task Tag ๐ฆ
This is the Initiator Task Tag of the task to be aborted for the ABORT TASK function, or the one to be reassigned for the TASK REASSIGN function. For all the other functions, this field MUST be set to the reserved value 0xffffffff ๐.
10.5.5. RefCmdSN ๐ง
If an ABORT TASK is issued for a task created by an immediate command, then RefCmdSN MUST be that of the Task Management request itself (so CmdSN and RefCmdSN are equal) โจ.
For an ABORT TASK of a task created by a non-immediate command, RefCmdSN MUST be set to the CmdSN of the task identified by the Referenced Task Tag field. Targets must use this field as described in section 10.6.1 when the task identified by the Referenced Task Tag field is not with the target ๐.
Otherwise, this field is reserved ๐ .
10.5.6. ExpDataSN โจ
okay bestie, so the target and the initiator both keep track of a data acknowledgement reference number ๐. It's the first input DataSN the initiator hasn't acknowledged yet ๐ฆ. When a new command gets issued, this number is set to 0 ๐. If the function is TASK REASSIGN (the one that sets up a new connection allegiance for a Read or Bidirectional command that was already issued) ๐, then ExpDataSN holds either an updated data acknowledgement reference number or the value 0. Zero just means the reference number hasn't changed ๐ .
The initiator MUST discard any data PDUs from the previous execution that it didn't acknowledge, and the target MUST transmit all Data-In PDUs (if any) starting from the data acknowledgement reference number ๐ซถ. How many PDUs get resent might or might not match the original, depending on whether MaxRecvDataSegmentLength changed during the reassignment ๐คทโโ๏ธ. The target MAY also send no more Data-In PDUs if all the data has already been acknowledged โจ.
The value of ExpDataSN MUST be 0 or higher than the DataSN of the last acknowledged Data-In PDU, but not larger than DataSN+1 of the last Data-In PDU sent by the target. Any other value MUST be ignored by the target ๐. Main character energy for the target: it ignores anything sus ๐ .
For other functions this field is reserved ๐ธ.
10.6. Task Management Function Response ๐
Here's the layout, bestie ๐ง:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x22 |1| Reserved | Response | Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------------------------------------------------------+
8/ Reserved /
/ /
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| Reserved |
+---------------+---------------+---------------+---------------+
24| StatSN |
+---------------+---------------+---------------+---------------+
28| ExpCmdSN |
+---------------+---------------+---------------+---------------+
32| MaxCmdSN |
+---------------+---------------+---------------+---------------+
36/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
For the functions ABORT TASK, ABORT TASK SET, CLEAR ACA, CLEAR TASK SET, LOGICAL UNIT RESET, TARGET COLD RESET, TARGET WARM RESET and TASK REASSIGN, the target performs the requested Task Management function and sends a Task Management response back to the initiator. For TASK REASSIGN, the new connection allegiance MUST ONLY become effective at the target after the target issues the Task Management Response ๐ฆ.
10.6.1. Response ๐
The target provides a Response, which may take on the following values:
- a) 0 - Function complete.
- b) 1 - Task does not exist.
- c) 2 - LUN does not exist.
- d) 3 - Task still allegiant.
- e) 4 - Task allegiance reassignment not supported.
- f) 5 - Task management function not supported.
- g) 6 - Function authorization failed.
- h) 255 - Function rejected.
All other values are reserved ๐.
For a discussion on usage of response codes 3 and 4, see Section 6.2.2 Allegiance Reassignment ๐.
For the TARGET COLD RESET and TARGET WARM RESET functions, the target cancels all pending operations across all Logical Units known to the issuing initiator. For the TARGET COLD RESET function, the target MUST then close all of its TCP connections to all initiators (terminates all sessions) ๐.
The mapping of the response code into a SCSI service response code value, if needed, is outside the scope of this document. However, in symbolic terms, Response values 0 and 1 map to the SCSI service response of FUNCTION COMPLETE. All other Response values map to the SCSI service response of FUNCTION REJECTED. If a Task Management function response PDU does not arrive before the session is terminated, the SCSI service response is SERVICE DELIVERY OR TARGET FAILURE ๐ญ.
The response to ABORT TASK SET and CLEAR TASK SET MUST only be issued by the target after all of the commands affected have been received by the target, the corresponding task management functions have been executed by the SCSI target, and the delivery of all responses delivered until the task management function completion have been confirmed (acknowledged through ExpStatSN) by the initiator on all connections of this session. For the exact timeline of events, refer to Section 10.6.2 Task Management Actions on Task Sets ๐๏ธ.
For the ABORT TASK function:
- a) If the Referenced Task Tag identifies a valid task leading to a successful termination, then targets must return the "Function complete" response. โ
- b) If the Referenced Task Tag does not identify an existing task, but if the CmdSN indicated by the RefCmdSN field in the Task Management function request is within the valid CmdSN window and less than the CmdSN of the Task Management function request itself, then targets must consider the CmdSN received and return the "Function complete" response. ๐ซถ
- c) If the Referenced Task Tag does not identify an existing task and if the CmdSN indicated by the RefCmdSN field in the Task Management function request is outside the valid CmdSN window, then targets must return the "Task does not exist" response. ๐ โโ๏ธ
10.6.2. Task Management Actions on Task Sets ๐
The execution of ABORT TASK SET and CLEAR TASK SET Task Management function requests consists of the following sequence of events, in the specified order, on each of the entities. Think of it like a choreographed group routine ๐.
The initiator:
- a) Issues ABORT TASK SET/CLEAR TASK SET request.
- b) Continues to respond to each target transfer tag received for the affected task set.
- c) Receives any responses for the tasks in the affected task set (may process them as usual because they are guaranteed to be valid).
- d) Receives the task set management response, thus concluding all the tasks in the affected task set. ๐
The target:
- a) Receives the ABORT TASK SET/CLEAR TASK SET request.
- b) Waits for all target transfer tags to be responded to and for all affected tasks in the task set to be received.
- c) Propagates the command to, and receives the response from, the target SCSI layer.
- d) Takes note of last-sent StatSN on each of the connections in the iSCSI sessions (one or more) sharing the affected task set, and waits for acknowledgement of each StatSN (may solicit for acknowledgement by way of a NOP-In). If some tasks originate from non-iSCSI I_T_L nexi, then the means by which the target insures that all affected tasks have returned their status to the initiator are defined by the specific protocol. ๐ง
- e) Sends the task set management response to the issuing initiator. ๐
10.6.3. TotalAHSLength and DataSegmentLength ๐
For this PDU, TotalAHSLength and DataSegmentLength MUST be 0. Simple, but very important, so don't skip it ๐.
10.7. SCSI Data-Out & SCSI Data-In ๐
Okay so here's the shape of the SCSI Data-Out PDU, the one that carries WRITE data ๐ฆ
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x05 |F| Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN or Reserved |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| Target Transfer Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
24| Reserved |
+---------------+---------------+---------------+---------------+
28| ExpStatSN |
+---------------+---------------+---------------+---------------+
32| Reserved |
+---------------+---------------+---------------+---------------+
36| DataSN |
+---------------+---------------+---------------+---------------+
40| Buffer Offset |
+---------------+---------------+---------------+---------------+
44| Reserved |
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
/ DataSegment /
+/ /
+---------------+---------------+---------------+---------------+
| Data-Digest (Optional) |
+---------------+---------------+---------------+---------------+
And here's the Data-In PDU for READ operations, which is the one coming back the other way ๐
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x25 |F|A|0 0 0|O|U|S| Reserved |Status or Rsvd |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN or Reserved |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| Target Transfer Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
24| StatSN or Reserved |
+---------------+---------------+---------------+---------------+
28| ExpCmdSN |
+---------------+---------------+---------------+---------------+
32| MaxCmdSN |
+---------------+---------------+---------------+---------------+
36| DataSN |
+---------------+---------------+---------------+---------------+
40| Buffer Offset |
+---------------+---------------+---------------+---------------+
44| Residual Count |
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
/ DataSegment /
+/ /
+---------------+---------------+---------------+---------------+
| Data-Digest (Optional) |
+---------------+---------------+---------------+---------------+
Status can ride along on the last Data-In PDU, as long as the command didn't end with an exception. That means the status is "good status" (GOOD, CONDITION MET, or INTERMEDIATE CONDITION MET) ๐ธ The S flag bit is how you signal that status (plus a residual count) is in there. Targets MAY choose to send even non-exception status in separate responses, but initiators MUST support non-exception status in Data-In PDUs ๐
10.7.1. F (Final) Bit ๐ฆ
For outgoing data, F is 1 on the last PDU of unsolicited data, or on the last PDU of a sequence that answers an R2T ๐
Incoming (read) data works differently. F is 1 on the last input data PDU of each sequence. Input can be chopped into several sequences, and each one gets its own F bit. Splitting the stream like that doesn't change how DataSN is counted on Data-In PDUs ๐ข F MAY be used as a "change direction" flag for Bidirectional operations that need that kind of switch.
Size limits, bestie ๐ DataSegmentLength MUST not exceed MaxRecvDataSegmentLength for whichever direction it's going. The total DataSegmentLength across all PDUs in one sequence MUST not exceed MaxBurstLength (or FirstBurstLength for unsolicited data). BUT the number of PDUs can still go higher than the MaxBurstLength (or FirstBurstLength) to MaxRecvDataSegmentLength ratio, since the sender might only be able to make smaller PDUs ๐ Using DataSegmentLength of 0 can blow the PDU count past what's reasonable, so you should totally avoid it ๐
For Bidirectional ops, F is 1 at the end of both the input sequences and the output sequences ๐
10.7.2. A (Acknowledge) Bit ๐
For sessions with ErrorRecoveryLevel 1 or higher, the target sets A to 1 when it wants a positive acknowledgement from the initiator for the data it received ๐ The target should use A moderately. It MAY set A to 1 only once every MaxBurstLength bytes, or on the last Data-In PDU that wraps up the entire requested read transfer for the task (from the target's point of view). It MUST NOT do it more often than that ๐ For sessions with ErrorRecoveryLevel=0, the target MUST NOT set A to 1, and the initiator MUST ignore A set to 1 there โจ
On receiving a Data-In PDU with A set to 1 on a session with ErrorRecoveryLevel greater than 0, here's the deal ๐ If there are no holes in the read data up to that Data-In PDU, the initiator MUST issue a SNACK of type DataACK. The one exception is when it can acknowledge the status for the task right away through ExpStatSN on other outbound PDUs, as long as the status for the task has also arrived. In that latter case (acknowledgement through ExpStatSN), sending a SNACK of type DataACK in response to the A bit is OPTIONAL. But if you do send it, it must not be sent after the status acknowledgement through ExpStatSN ๐ซถ If the initiator has spotted holes in the read data before that Data-In PDU, it MUST postpone the SNACK of type DataACK until those holes are filled. An initiator also MUST NOT acknowledge the status for the task before the holes are filled ๐ญ A status acknowledgement for a task that generated the Data-In PDUs counts as an implicit acknowledgement of those Data-In PDUs from the target's side, if the target asked for one ๐
10.7.3. Flags (byte 1) ๐ฉ
The last SCSI Data packet a target sends to an initiator for a SCSI command that finished successfully (with a status of GOOD, CONDITION MET, INTERMEDIATE, or INTERMEDIATE CONDITION MET) can optionally carry the Status for the data transfer too โญ Sense Data can't ride along with the Command Status, though. So if the command ends in an error, the response and sense data MUST be sent in a SCSI Response PDU (i.e., MUST NOT be sent in a SCSI Data packet). If Status comes along with the data, then a SCSI Response PDU MUST NOT be sent, because that would break SCSI rules (a single status) ๐ For Bidirectional commands, the status MUST be sent in a SCSI Response PDU ๐ฅ
Here's the bit breakdown for byte 1:
bit 2-4 - Reserved.
bit 5-6 - used the same as in a SCSI Response. These bits are
only valid when S is set to 1. For details see Section
10.4.1 Flags (byte 1).
bit 7 S (status)- set to indicate that the Command Status field
contains status. If this bit is set to 1, the F bit
MUST also be set to 1.
The StatSN, Status, and Residual Count fields only mean something if the S bit is set to 1. Their values are defined in Section 10.4 SCSI Response ๐ง
10.7.4. Target Transfer Tag and LUN ๐ท
On outgoing data, the Target Transfer Tag gets handed to the target if the transfer is honoring an R2T. In that case, the Target Transfer Tag field is a replica of the Target Transfer Tag that came with the R2T ๐
On incoming data, the Target Transfer Tag and LUN MUST be provided by the target if A is set to 1. Otherwise, they're reserved ๐ธ The initiator copies the Target Transfer Tag and LUN into the SNACK of type DataACK it sends back after receiving a SCSI Data-In PDU with A set to 1 ๐ฌ
The Target Transfer Tag values aren't specified by this protocol, except that 0xffffffff is reserved and means the Target Transfer Tag isn't supplied ๐ If the Target Transfer Tag is provided, then the LUN field MUST hold a valid value and be consistent with whatever was specified with the command. Otherwise, the LUN field is reserved ๐
10.7.5. DataSN ๐ข
For input (read) or bidirectional Data-In PDUs, DataSN is the input PDU number within the data transfer for the command identified by the Initiator Task Tag ๐
R2T and Data-In PDUs share the same numbering sequence when we're talking about bidirectional commands (see Section 3.2.2.3 Data Sequencing) ๐ฆ
For output (write) data PDUs, DataSN is the Data-Out PDU number within the current output sequence. That output sequence is identified either by the Initiator Task Tag (for unsolicited data), or it's a data sequence generated for one R2T (for data solicited through R2T) ๐
10.7.6. Buffer Offset โจ
okay so the Buffer Offset field is basically the "where am I in the big picture" ๐บ๏ธ marker. It holds the offset of this PDU's payload data inside the complete data transfer. The sum of the buffer offset and length should not exceed the expected transfer length for the command, bestie, so no going past the end of the transfer ๐ โโ๏ธ
The order of data PDUs inside a sequence is decided by DataPDUInOrder. When it's set to Yes, the PDUs have to show up in increasing Buffer Offset order, and overlays are forbidden. No overlapping, no drama ๐
The ordering between sequences is decided by DataSequenceInOrder. When that's set to Yes, the sequences have to be in increasing Buffer Offset order, and overlays are forbidden here too ๐ธ
10.7.7. DataSegmentLength ๐
This is the data payload length of a SCSI Data-In or SCSI Data-Out PDU. Sending 0 length data segments should be avoided, but initiators and targets MUST be able to properly receive 0 length data segments. So you can avoid them, but you have to be able to handle them if they show up ๐ซถ
The Data Segments of Data-In and Data-Out PDUs SHOULD be filled to the integer number of 4 byte words (real payload) unless the F bit is set to 1. In other words, pad it out to 4 byte words, unless the F bit says otherwise ๐ฆ
10.8. Ready To Transfer (R2T) ๐ฅ
This is the R2T PDU, and it's giving "the target gets to pick the vibe" ๐ Here's the layout:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x31 |1| Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| Target Transfer Tag |
+---------------+---------------+---------------+---------------+
24| StatSN |
+---------------+---------------+---------------+---------------+
28| ExpCmdSN |
+---------------+---------------+---------------+---------------+
32| MaxCmdSN |
+---------------+---------------+---------------+---------------+
36| R2TSN |
+---------------+---------------+---------------+---------------+
40| Buffer Offset |
+---------------+---------------+---------------+---------------+
44| Desired Data Transfer Length |
+---------------------------------------------------------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
When an initiator has submitted a SCSI Command with data that passes from the initiator to the target (WRITE), the target may specify which blocks of data it is ready to receive. The target may request that the data blocks be delivered in whichever order is convenient for the target at that particular instant. This information is passed from the target to the initiator in the Ready To Transfer (R2T) PDU ๐
In order to allow write operations without an explicit initial R2T, the initiator and target MUST have negotiated the key InitialR2T to No during Login. So that's the setup step, and it's not optional ๐
An R2T MAY be answered with one or more SCSI Data-Out PDUs with a matching Target Transfer Tag. If an R2T is answered with a single Data-Out PDU, the Buffer Offset in the Data PDU MUST be the same as the one specified by the R2T, and the data length of the Data PDU MUST be the same as the Desired Data Transfer Length specified in the R2T. If the R2T is answered with a sequence of Data PDUs, the Buffer Offset and Length MUST be within the range of those specified by R2T, and the last PDU MUST have the F bit set to 1. If the last PDU (marked with the F bit) is received before the Desired Data Transfer Length is transferred, a target MAY choose to Reject that PDU with "Protocol error" reason code. ๐
DataPDUInOrder governs the Data-Out PDU ordering. If DataPDUInOrder is set to Yes, the Buffer Offsets and Lengths for consecutive PDUs MUST form a continuous non-overlapping range and the PDUs MUST be sent in increasing offset order. Lined up, no gaps, no overlaps ๐ง
The target may send several R2T PDUs. It, therefore, can have a number of pending data transfers. The number of outstanding R2T PDUs are limited by the value of the negotiated key MaxOutstandingR2T. Within a connection, outstanding R2Ts MUST be fulfilled by the initiator in the order in which they were received. First come, first served, literally ๐
R2T PDUs MAY also be used to recover Data Out PDUs. Such an R2T (Recovery-R2T) is generated by a target upon detecting the loss of one or more Data-Out PDUs due to:
- Digest error
- Sequence error
- Sequence reception timeout
A Recovery-R2T carries the next unused R2TSN, but requests part of or the entire data burst that an earlier R2T (with a lower R2TSN) had already requested. It's the comeback arc ๐
DataSequenceInOrder governs the buffer offset ordering in consecutive R2Ts. If DataSequenceInOrder is Yes, then consecutive R2Ts MUST refer to continuous non-overlapping ranges except for Recovery-R2Ts. โจ
10.8.1. TotalAHSLength and DataSegmentLength ๐
For this PDU TotalAHSLength and DataSegmentLength MUST be 0. Zeros all the way, bestie ๐ซถ
10.8.2. R2TSN ๐
R2TSN is the R2T PDU input PDU number within the command identified by the Initiator Task Tag. It's basically the R2T's numbered ticket for that command ๐๏ธ
For bidirectional commands R2T and Data-In PDUs share the input PDU numbering sequence (see Section 3.2.2.3 Data Sequencing). Same numbering line, shared between both ๐ฆ
10.8.3. StatSN ๐ธ
The StatSN field will contain the next StatSN. The StatSN for this connection is not advanced after this PDU is sent. So this one doesn't move the counter forward, it just carries the next number ๐
10.8.4. Desired Data Transfer Length and Buffer Offset ๐
The target specifies how many bytes it wants the initiator to send because of this R2T PDU. The target may request the data from the initiator in several chunks, not necessarily in the original order of the data. The target, therefore, also specifies a Buffer Offset that indicates the point at which the data transfer should begin, relative to the beginning of the total data transfer. The Desired Data Transfer Length MUST NOT be 0 and MUST not exceed MaxBurstLength. So it's the ask, the start point, and the size cap, all in one ๐
10.8.5. Target Transfer Tag ๐ง
The target assigns its own tag to each R2T request that it sends to the initiator. This tag can be used by the target to easily identify the data it receives. The Target Transfer Tag and LUN are copied in the outgoing data PDUs and are only used by the target. There is no protocol rule about the Target Transfer Tag except that the value 0xffffffff is reserved and MUST NOT be sent by a target in an R2T. That one reserved value is off-limits, babe ๐ซ
10.9. Asynchronous Message ๐ฃ
An Asynchronous Message may be sent from the target to the initiator without correspondence to a particular command. The target specifies the reason for the event and sense data. It's the target just tapping the initiator on the shoulder, unprompted ๐
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x32 |1| Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN or Reserved |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| 0xffffffff |
+---------------+---------------+---------------+---------------+
20| Reserved |
+---------------+---------------+---------------+---------------+
24| StatSN |
+---------------+---------------+---------------+---------------+
28| ExpCmdSN |
+---------------+---------------+---------------+---------------+
32| MaxCmdSN |
+---------------+---------------+---------------+---------------+
36| AsyncEvent | AsyncVCode | Parameter1 or Reserved |
+---------------+---------------+---------------+---------------+
40| Parameter2 or Reserved | Parameter3 or Reserved |
+---------------+---------------+---------------+---------------+
44| Reserved |
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
/ DataSegment - Sense Data and iSCSI Event Data /
+/ /
+---------------+---------------+---------------+---------------+
| Data-Digest (Optional) |
+---------------+---------------+---------------+---------------+
Some Asynchronous Messages are strictly related to iSCSI while others are related to SCSI [SAM2]. Some are iSCSI tea, some are SCSI tea โ
StatSN counts this PDU as an acknowledgeable event (StatSN is advanced), which allows for initiator and target state synchronization. So this one does move the StatSN forward, and that's how both sides stay in sync ๐ฅ
10.9.1. AsyncEvent โจ
okay so the codes for iSCSI Asynchronous Messages (events) are: ๐
0: a SCSI Asynchronous Event gets reported in the sense data ๐. The Sense Data that rides along in the data segment tells you what the condition is. Sending a SCSI Event (Asynchronous Event Reporting in SCSI terminology) depends on whether the target supports SCSI asynchronous event reporting (see [SAM2]), which shows up in the standard INQUIRY data (see [SPC3]). Its use may be enabled by parameters in the SCSI Control mode page (see [SPC3]).1: target requests Logout ๐ช this one is serious, bestie ๐ญ- This Async Message MUST be sent on the same connection as the one requesting to be logged out.
- The initiator MUST honor this request by issuing a Logout as early as possible, but no later than Parameter3 seconds.
- Initiator MUST send a Logout with a reason code of "Close the connection" OR "Close the session" to close all the connections.
- Once this message is received, the initiator SHOULD NOT issue new iSCSI commands on the connection to be logged out.
- The target MAY reject any new I/O requests that it receives after this Message with the reason code "Waiting for Logout".
- If the initiator does not Logout in Parameter3 seconds, the target should send an Async PDU with iSCSI event code "Dropped the connection" if possible, or simply terminate the transport connection.
- Parameter1 and Parameter2 are reserved.
2: target says it's going to drop the connection ๐- The Parameter1 field tells you the CID of the connection that is going to be dropped.
- The Parameter2 field (Time2Wait) tells you, in seconds, the minimum time to wait before attempting to reconnect or reassign.
- The Parameter3 field (Time2Retain) tells you the maximum time allowed to reassign commands after the initial wait (in Parameter2).
- If the initiator does not attempt to reconnect and/or reassign the outstanding commands within the time specified by Parameter3, or if Parameter3 is 0, the target will terminate all outstanding commands on this connection. In this case, no other responses should be expected from the target for the outstanding commands on this connection.
- A value of 0 for Parameter2 means reconnect can be attempted immediately ๐โโ๏ธ
3: target says it's going to drop ALL the connections of this session ๐- The Parameter1 field is reserved.
- The Parameter2 field (Time2Wait) tells you, in seconds, the minimum time to wait before attempting to reconnect. The Parameter3 field (Time2Retain) tells you the maximum time allowed to reassign commands after the initial wait (in Parameter2).
- If the initiator does not attempt to reconnect and/or reassign the outstanding commands within the time specified by Parameter3, or if Parameter3 is 0, the session is terminated.
- In this case, the target will terminate all outstanding commands in this session; no other responses should be expected from the target for the outstanding commands in this session. A value of 0 for Parameter2 means reconnect can be attempted immediately.
4: target requests parameter negotiation on this connection ๐ฃ๏ธ- The initiator MUST honor this request by issuing a Text Request (that can be empty) on the same connection as early as possible, but no later than Parameter3 seconds, unless a Text Request is already pending on the connection, or by issuing a Logout Request.
- If the initiator does not issue a Text Request, the target may reissue the Asynchronous Message requesting parameter negotiation.
255: vendor specific iSCSI Event ๐ the AsyncVCode spills the vendor code tea, and data MAY accompany the report.
All other event codes are reserved. ๐ โโ๏ธ
10.9.2. AsyncVCode ๐
AsyncVCode is a vendor specific detail code, and it's only valid if the AsyncEvent field says it's a vendor specific event. Otherwise, it is reserved. ๐
10.9.3. LUN ๐ง
The LUN field MUST be valid if AsyncEvent is 0. Otherwise, this field is reserved. ๐ซถ
10.9.4. Sense Data and iSCSI Event Data ๐
For a SCSI event, this data comes along with the report in the data segment and identifies the condition.
For an iSCSI event, additional vendor-unique data MAY accompany the Async event. Initiators MAY ignore the data when they don't understand it while processing the rest of the PDU ๐
If the DataSegmentLength is not 0, the format of the DataSegment looks like this:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|SenseLength | Sense Data |
+---------------+---------------+---------------+---------------+
x/ Sense Data /
+---------------+---------------+---------------+---------------+
y/ iSCSI Event Data /
/ /
+---------------+---------------+---------------+---------------+
z|
10.9.4.1. SenseLength ๐ธ
This is the length of Sense Data. When the Sense Data field is empty (e.g., the event is not a SCSI event), SenseLength is 0.
10.10. Text Request ๐
The Text Request is here to swap info and to leave room for future extensions ๐ฆ It lets the initiator tell a target about its capabilities or ask for some special operations.
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|I| 0x04 |F|C| Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN or Reserved |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| Target Transfer Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
24| CmdSN |
+---------------+---------------+---------------+---------------+
28| ExpStatSN |
+---------------+---------------+---------------+---------------+
32/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
/ DataSegment (Text) /
+/ /
+---------------+---------------+---------------+---------------+
| Data-Digest (Optional) |
+---------------+---------------+---------------+---------------+
An initiator MUST have at most one outstanding Text Request on a connection at any given time. ๐ฆ
On a connection failure, an initiator must either explicitly abort any active allegiant text negotiation task, or must cause such a task to be implicitly terminated by the target. ๐
10.10.1. F (Final) Bit ๐
When set to 1, this tells you it's the last or only text request in a sequence of Text Requests. Otherwise, it means more Text Requests will follow ๐ซถ
10.10.2. C (Continue) Bit โ๏ธ
When set to 1, this means the text (the set of key=value pairs) in this Text Request isn't complete yet, and it'll be continued in the subsequent Text Requests. Otherwise, it means this Text Request ends a set of key=value pairs. A Text Request with the C bit set to 1 MUST have the F bit set to 0. ๐ โโ๏ธ
10.10.3. Initiator Task Tag ๐ท๏ธ
This is the initiator assigned identifier for this Text Request. If the command is sent as part of a sequence of text requests and responses, the Initiator Task Tag MUST be the same for all the requests within the sequence (kind of like linked SCSI commands ๐). The I bit for all requests in a sequence also MUST be the same.
10.10.4. Target Transfer Tag ๐ฆ
When the Target Transfer Tag is set to the reserved value 0xffffffff, it tells the target that this is a brand new request, and the target resets any internal state tied to the Initiator Task Tag (aka it resets the current negotiation state) ๐งน
The target sets the Target Transfer Tag in a text response to a value other than the reserved value 0xffffffff whenever it says it has more data to send or more operations to perform that are tied to the specified Initiator Task Tag. It MUST do so whenever it sets the F bit to 0 in the response. By copying the Target Transfer Tag from the response into the next Text Request, the initiator tells the target to keep going with the operation for that specific Initiator Task Tag ๐ The initiator MUST ignore the Target Transfer Tag in the Text Response when the F bit is set to 1.
This mechanism lets the initiator and target pass a big pile of textual data over a sequence of text-command/text-response exchanges, or run extended negotiation sequences. It's giving teamwork ๐ค
If the Target Transfer Tag is not 0xffffffff, the LUN field MUST be sent by the target in the Text Response. ๐ง
A target MAY reset its internal negotiation state if an exchange is stalled by the initiator for a long time, or if it is running out of resources. ๐ฎโ๐จ
Long text responses go like this:
I->T Text SendTargets=All (F=1,TTT=0xffffffff)
T->I Text <part 1> (F=0,TTT=0x12345678)
I->T Text <empty> (F=1, TTT=0x12345678)
T->I Text <part 2> (F=0, TTT=0x12345678)
I->T Text <empty> (F=1, TTT=0x12345678)
...
T->I Text <part n> (F=1, TTT=0xffffffff)
10.10.5. Text โจ
Okay bestie, the data in a text request MUST NOT go over the target's MaxRecvDataSegmentLength. That's a per-connection, per-direction number that both sides negotiate, so nobody gets surprised ๐ . The text format is in Section 5.2 Text Mode Negotiation ๐.
Chapters 11 and 12 list some basic Text key=value pairs. Some of them work in Login Request/Response and some work in Text Request/Response ๐ธ.
A key=value pair can span Text request or response boundaries. It can START in one PDU and finish in the next one ๐ญ. So the end of a PDU doesn't automatically mean the key=value pair is over, iykyk.
The target responds by sending its response back to the initiator. The response text looks pretty similar to the request text โจ. The text response MAY refer to key=value pairs from an earlier text request, and the request text may refer back to earlier responses too ๐ฆ.
Chapter 5 has all the rules for Text Requests and Responses ๐.
Text operations are usually for parameter setting and negotiations, but they can also run some long-lasting operations ๐. If something takes a long time, it should go in its own Text request ๐.
10.11. Text Response ๐ง
The Text Response PDU carries the target's answers to the initiator's Text request. The Text field matches the format of the Text request ๐.
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x24 |F|C| Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN or Reserved |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| Target Transfer Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
24| StatSN |
+---------------+---------------+---------------+---------------+
28| ExpCmdSN |
+---------------+---------------+---------------+---------------+
32| MaxCmdSN |
+---------------+---------------+---------------+---------------+
36/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
/ DataSegment (Text) /
+/ /
+---------------+---------------+---------------+---------------+
| Data-Digest (Optional) |
+---------------+---------------+---------------+---------------+
10.11.1. F (Final) Bit ๐
When it's set to 1 in response to a Text Request that also has the Final bit set to 1, the F bit tells you the target is totally done with the whole operation ๐. If it's set to 0 in response to a Text Request with the Final Bit set to 1, the target has more work to do and is basically inviting a follow-on text request ๐ . A Text Response with the F bit set to 1 in response to a Text Request with the F bit set to 0 is a protocol error ๐.
A Text Response with the F bit set to 1 MUST NOT contain key=value pairs that may require additional answers from the initiator ๐.
A Text Response with the F bit set to 1 MUST have a Target Transfer Tag field set to the reserved value of 0xffffffff ๐.
A Text Response with the F bit set to 0 MUST have a Target Transfer Tag field set to a value other than the reserved 0xffffffff ๐ฆ.
10.11.2. C (Continue) Bit ๐ธ
When it's set to 1, the text (the set of key=value pairs) in this Text Response isn't finished yet, and it'll keep going in later Text Responses. If it's 0, this Text Response wraps up a set of key=value pairs ๐. A Text Response with the C bit set to 1 MUST have the F bit set to 0 โจ.
10.11.3. Initiator Task Tag ๐
The Initiator Task Tag matches the tag from the original Text Request ๐.
10.11.4. Target Transfer Tag ๐
Sometimes a target has more work to do. Maybe it can't send all the remaining text in one Text Response, or it has to keep negotiating. If it has enough resources to keep going, it MUST set the Target Transfer Tag to a value other than the reserved 0xffffffff. If not, the Target Transfer Tag MUST be set to 0xffffffff ๐ฅ.
When the Target Transfer Tag isn't 0xffffffff, the LUN field may be significant ๐ง.
The initiator MUST copy the Target Transfer Tag and LUN into its next request, which tells the target it wants the rest of the data ๐ซถ.
When the target gets a Text Request with the Target Transfer Tag set to the reserved 0xffffffff, it resets its internal information (its state) for that Initiator Task Tag, which restarts the negotiation ๐.
When a target can't finish the operation in a single Text Response and doesn't have enough resources to continue, it rejects the Text Request with the appropriate Reject code ๐ โโ๏ธ.
A target may reset its internal state for an Initiator Task Tag, meaning the current negotiation state that's expressed through the Target Transfer Tag, if the initiator stops continuing the exchange for a while ๐ด. After that, the target may reject later Text Requests whose Target Transfer Tag is set to the "stale" value ๐ฅ.
10.11.5. StatSN ๐
The target's StatSN variable goes up by one for every Text Response it sends โญ.
10.11.6. Text Response Data ๐
The data lengths of a text response MUST NOT exceed the iSCSI initiator MaxRecvDataSegmentLength. That's also a per-connection, per-direction negotiated parameter ๐ .
The text in the Text Response Data follows the same rules as the text in the Text Request Data (see Section 10.10.5 Text) ๐.
Even though the initiator is the one asking and controls how the request-response starts and ends, the target can offer its own key=value pairs as part of a sequence, not just in response to the initiator ๐.
10.12. Login Request ๐
After a TCP connection is set up between an initiator and a target, the initiator MUST start a Login Phase so it can get further access to the target's resources ๐๏ธ.
The Login Phase (see Chapter 5) is a sequence of Login Requests and Responses that all carry the same Initiator Task Tag ๐งฉ.
Login Requests are always considered immediate โก.
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|1| 0x03 |T|C|.|.|CSG|NSG| Version-max | Version-min |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| ISID |
+ +---------------+---------------+
12| | TSIH |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| CID | Reserved |
+---------------+---------------+---------------+---------------+
24| CmdSN |
+---------------+---------------+---------------+---------------+
28| ExpStatSN or Reserved |
+---------------+---------------+---------------+---------------+
32| Reserved |
+---------------+---------------+---------------+---------------+
36| Reserved |
+---------------+---------------+---------------+---------------+
40/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
48/ DataSegment - Login Parameters in Text request Format /
+/ /
+---------------+---------------+---------------+---------------+
10.12.1. T (Transit) Bit ๐
If it's set to 1, the initiator is ready to move on to the next stage ๐โโ๏ธ.
If the T bit is set to 1 and NSG is FullFeaturePhase, that also means the initiator is ready for the Final Login Response (see Chapter 5) ๐.
10.12.2. C (Continue) Bit ๐ท
When it's set to 1, the text (the set of key=value pairs) in this Login Request isn't complete yet, and it'll continue in later Login Requests. Otherwise, this Login Request ends a set of key=value pairs ๐. A Login Request with the C bit set to 1 MUST have the T bit set to 0 ๐ โโ๏ธ.
10.12.3. CSG and NSG ๐ญ
Through these fields, Current Stage (CSG) and Next Stage (NSG), the Login negotiation requests and responses get tied to a specific stage in the session (SecurityNegotiation, LoginOperationalNegotiation, FullFeaturePhase). They can also say which stage they want to move to next (see Chapter 5) ๐บ๏ธ. The next stage value only counts when the T bit is 1. Otherwise, it's reserved ๐ซง.
The stage codes are:
0 - SecurityNegotiation1 - LoginOperationalNegotiation3 - FullFeaturePhase
All other codes are reserved ๐.
10.12.4. Version ๐
The version number of the current draft is 0x00. Because of that, all devices MUST carry 0x00 for both Version-min and Version-max ๐.
10.12.4.1. Version-max ๐
This is the maximum Version number supported ๐.
All Login Requests within the Login Phase MUST carry the same Version-max ๐.
The target MUST use the value it got from the first Login Request ๐ฅ.
10.12.4.2. Version-min ๐ฆ
All Login Requests within the Login Phase MUST carry the same Version-min. The target MUST use the value it got from the first Login Request ๐ซถ.
10.12.5. ISID โจ
okay so ISID is the initiator-defined part of the session identifier, and it's giving very structured ๐ (see [RFC3721] and Section 9.1.1 Conservative Reuse of ISIDs for the deep dive, bestie):
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
8| T | A | B | C |
+---------------+---------------+---------------+---------------+
12| D |
+---------------+---------------+
the T field is the boss here ๐ because it tells you what format and usage A, B, C, and D have:
T
00b OUI-Format
A&B are a 22 bit OUI
(the I/G & U/L bits are omitted)
C&D 24 bit qualifier
01b EN - Format (IANA Enterprise Number)
A - Reserved
B&C EN (IANA Enterprise Number)
D - Qualifier
10b "Random"
A - Reserved
B&C Random
D - Qualifier
11b A,B,C&D Reserved
for T being 00b or 01b, a combo of A and B (for 00b) or B and C (for 01b) tells you which vendor or organization's component (software or hardware) made this ISID ๐ซถ and any vendor with one or more OUIs, or one or more Enterprise Numbers, MUST use at least one of those numbers and pick the right T value when its components generate ISIDs. the OUI or EN MUST be set in the matching fields in network byte order (byte big-endian), no cap ๐
if T is 10b, then B and C get set to a random 24-bit unsigned integer in network byte order (byte big-endian). lowkey this is where [RFC3721] comes in clutch for "conservative reuse" ๐ฆ
the Qualifier field is a 16 or 24-bit unsigned integer that gives you a range of ISID values inside the chosen namespace ๐ธ it may be set to any value that fits the rules in the iSCSI protocol (see Section 3.4.3 Consequences of the Model and Section 9.1.1 Conservative Reuse of ISIDs).
the T value of 11b is reserved, so don't even ๐
and now the big one: if the ISID comes from something a vendor assigned to a hardware adapter or interface as a preset default, it MUST be configurable to a value picked for the SCSI port behavior the system wants (see Section 9.1.1 Conservative Reuse of ISIDs and Section 9.1.2 iSCSI Name, ISID, and TPGT Use). the resulting ISID MUST also stay persistent over power cycles, reboot, card swap, etc. main character energy, but make it consistent ๐ง
10.12.6. TSIH ๐
TSIH must be set in the first Login Request, and the reserved value 0 MUST be used on the first connection for a new session. otherwise, the TSIH the target sent back at the end of a successful login on the first connection for this session MUST be used. basically the TSIH tells the target which existing session this new connection belongs to ๐
all Login Requests within a Login Phase MUST carry the same TSIH. periodt ๐
the target MUST check the value presented with the first Login Request and act as specified in Section 5.3.1 Login Phase Start โจ
10.12.7. Connection ID - CID ๐ฆ
this is a unique ID for this connection within the session. literally that's the whole vibe ๐
all Login Requests within the Login Phase MUST carry the same CID.
the target MUST use the value presented with the first Login Request.
โ ๏ธ okay this one is a whole plot twist: a Login Request with a non-zero TSIH and a CID that matches an existing connection implies a logout of that connection followed by a Login (see Section 5.3.4 Connection Reinstatement). for the details of that implicit Logout Request, check Section 10.14 Logout Request ๐
10.12.8. CmdSN ๐
CmdSN is either the initial command sequence number of a session (for the first Login Request of a session, aka the "leading" login), or the command sequence number in the command stream if the login is for a new connection in an existing session. ngl it's the number that keeps everything in order ๐
examples, because you know I love a good example ๐
- login on a leading connection: if the leading login carries the CmdSN 123, then every other Login Request in the same Login Phase carries the CmdSN 123, and the first non-immediate command in FullFeaturePhase also carries the CmdSN 123.
- login on a connection that isn't leading: if the current CmdSN is 500 when the first login on the connection gets issued, then that PDU carries CmdSN=500. later Login Requests needed to finish this Login Phase may carry a CmdSN higher than 500 if non-immediate requests issued on other connections in the same session moved CmdSN forward. the timeline is a little messy, but it's valid ๐ซถ
if the Login Request is a leading Login Request, the target MUST use the value presented in CmdSN as the target value for ExpCmdSN โจ
10.12.9. ExpStatSN ๐ธ
for the first Login Request on a connection, this is the ExpStatSN for the old connection, and this field is only valid if the Login Request restarts a connection (see Section 5.3.4 Connection Reinstatement).
for subsequent Login Requests, it's used to acknowledge the Login Responses with their increasing StatSN values ๐
10.12.10. Login Parameters ๐
the initiator MUST provide some basic parameters so the target can figure out whether the initiator is allowed to use its resources, plus the initial text parameters for the security exchange. it's the VIP pass ๐๏ธ
all the rules in Section 10.10.5 Text for text requests also hold for Login Requests. the keys and their explanations are in Chapter 11 (security negotiation keys) and Chapter 12 (operational parameter negotiation keys). all keys in Chapter 12, except for the X extension formats, MUST be supported by iSCSI initiators and targets. keys in Chapter 11 only need to be supported when the function they refer to is mandatory to implement ๐
10.13. Login Response ๐
the Login Response is how everybody knows the progress and/or end of the Login Phase ๐ง here's the layout:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x23 |T|C|.|.|CSG|NSG| Version-max | Version-active|
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| ISID |
+ +---------------+---------------+
12| | TSIH |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| Reserved |
+---------------+---------------+---------------+---------------+
24| StatSN |
+---------------+---------------+---------------+---------------+
28| ExpCmdSN |
+---------------+---------------+---------------+---------------+
32| MaxCmdSN |
+---------------+---------------+---------------+---------------+
36| Status-Class | Status-Detail | Reserved |
+---------------+---------------+---------------+---------------+
40/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
48/ DataSegment - Login Parameters in Text request Format /
+/ /
+---------------+---------------+---------------+---------------+
10.13.1. Version-max ๐ฆ
this is the highest version number the target supports ๐
all Login Responses within the Login Phase MUST carry the same Version-max.
the initiator MUST use the value presented as a response to the first Login Request.
10.13.2. Version-active ๐
this one shows the highest version that both the target and initiator support ๐ if the target doesn't support a version inside the range the initiator asked for, the target rejects the login, and this field shows the lowest version the target does support. so close, but no cigar ๐
all Login Responses within the Login Phase MUST carry the same Version-active.
the initiator MUST use the value presented as a response to the first Login Request.
10.13.3. TSIH โจ
the TSIH is the target assigned session identifying handle ๐ its internal format and content aren't defined by this protocol, except that the value 0 is reserved. except for the Login Final-Response in a new session, this field should be set to the TSIH the initiator gave in the Login Request. for a new session, the target MUST generate a non-zero TSIH and ONLY return it in the Login Final-Response (see Section 5.3 Login Phase) ๐
10.13.4. StatSN ๐ธ
for the first Login Response (the response to the first Login Request), this is the starting status Sequence Number for the connection. the next response of any kind, including the next Login Response (if there is one) in the same Login Phase, will carry this number + 1. this field is only valid if the Status-Class is 0 ๐ซถ bestie, it's all about keeping count โจ
10.13.5. Status-Class and Status-Detail โจ
okay so the Status in a Login Response tells you how the Login Phase went ๐ It has two parts:
Status-Class
Status-Detail
Status-Class 0 means success ๐ that's the vibe we want.
A non-zero Status-Class means something went sideways ๐ In that case, Status-Class is enough for a simple initiator to handle the exception, without even peeking at Status-Detail. Status-Detail is for the more sophisticated initiators who want finer-grained handling, plus better info for logging ๐ง
Here are the status classes:
- 0 - Success - indicates that the iSCSI target successfully received, understood, and accepted the request. The numbering fields (StatSN, ExpCmdSN, MaxCmdSN) are only valid if Status-Class is 0.
- 1 - Redirection - indicates that the initiator must take further action to complete the request. This is usually due to the target moving to a different address. All of the redirection status class responses MUST return one or more text key parameters of the type "TargetAddress", which indicates the target's new address. A redirection response MAY be issued by a target prior or after completing a security negotiation if a security negotiation is required. A redirection SHOULD be accepted by an initiator even without having the target complete a security negotiation if any security negotiation is required, and MUST be accepted by the initiator after the completion of the security negotiation if any security negotiation is required. ๐ฆ
- 2 - Initiator Error (not a format error) - indicates that the initiator most likely caused the error. This MAY be due to a request for a resource for which the initiator does not have permission. The request should not be tried again. ๐
- 3 - Target Error - indicates that the target sees no errors in the initiator's Login Request, but is currently incapable of fulfilling the request. The initiator may re-try the same Login Request later. ๐ธ
The table below shows all of the currently allocated status codes. The codes are in hexadecimal. The first byte is the status class and the second byte is the status detail ๐
-----------------------------------------------------------------
Status | Code | Description
|(hex) |
-----------------------------------------------------------------
Success | 0000 | Login is proceeding OK (*1).
-----------------------------------------------------------------
Target moved | 0101 | The requested iSCSI Target Name (ITN)
temporarily | | has temporarily moved
| | to the address provided.
-----------------------------------------------------------------
Target moved | 0102 | The requested ITN has permanently moved
permanently | | to the address provided.
-----------------------------------------------------------------
Initiator | 0200 | Miscellaneous iSCSI initiator
error | | errors.
----------------------------------------------------------------
Authentication| 0201 | The initiator could not be
failure | | successfully authenticated or target
| | authentication is not supported.
-----------------------------------------------------------------
Authorization | 0202 | The initiator is not allowed access
failure | | to the given target.
-----------------------------------------------------------------
Not found | 0203 | The requested ITN does not
| | exist at this address.
-----------------------------------------------------------------
Target removed| 0204 | The requested ITN has been removed and
| |no forwarding address is provided.
-----------------------------------------------------------------
Unsupported | 0205 | The requested iSCSI version range is
version | | not supported by the target.
-----------------------------------------------------------------
Too many | 0206 | Too many connections on this SSID.
connections | |
-----------------------------------------------------------------
Missing | 0207 | Missing parameters (e.g., iSCSI
parameter | | Initiator and/or Target Name).
-----------------------------------------------------------------
Can't include | 0208 | Target does not support session
in session | | spanning to this connection (address).
-----------------------------------------------------------------
Session type | 0209 | Target does not support this type of
not supported | | of session or not from this Initiator.
-----------------------------------------------------------------
Session does | 020a | Attempt to add a connection
not exist | | to a non-existent session.
-----------------------------------------------------------------
Invalid during| 020b | Invalid Request type during Login.
login | |
-----------------------------------------------------------------
Target error | 0300 | Target hardware or software error.
-----------------------------------------------------------------
Service | 0301 | The iSCSI service or target is not
unavailable | | currently operational.
-----------------------------------------------------------------
Out of | 0302 | The target has insufficient session,
resources | | connection, or other resources.
-----------------------------------------------------------------
(*1) If the response T bit is 1 in both the request and the matching response, and the NSG is FullFeaturePhase in both the request and the matching response, the Login Phase is finished and the initiator may proceed to issue SCSI commands. โญ
If the Status Class is not 0, the initiator and target MUST close the TCP connection. ๐ฅ
If the target wishes to reject the Login Request for more than one reason, it should return the primary reason for the rejection. ๐
10.13.6. T (Transit) bit ๐ฆ
The T bit is set to 1 as an indicator of the end of the stage. If the T bit is set to 1 and NSG is FullFeaturePhase, then this is also the Final Login Response (see Chapter 5). A T bit of 0 indicates a "partial" response, which means "more negotiation needed" ๐
A Login Response with a T bit set to 1 MUST NOT contain key=value pairs that may require additional answers from the initiator within the same stage. ๐ โโ๏ธ
If the status class is 0, the T bit MUST NOT be set to 1 if the T bit in the request was set to 0. ๐
10.13.7. C (Continue) Bit ๐
When set to 1, this indicates that the text (set of key=value pairs) in this Login Response is not complete. It will be continued on subsequent Login Responses. Otherwise, it indicates that this Login Response ends a set of key=value pairs. A Login Response with the C bit set to 1 MUST have the T bit set to 0. ๐ซถ
10.13.8. Login Parameters ๐
The target MUST provide some basic parameters so the initiator can figure out if it's connected to the correct port, plus the initial text parameters for the security exchange ๐ง
All the rules specified in Section 10.11.6 Text Response Data for text responses also hold for Login Responses. Keys and their explanations are listed in Chapter 11 (security negotiation keys) and Chapter 12 (operational parameter negotiation keys). All keys in Chapter 12, except for the X extension formats, MUST be supported by iSCSI initiators and targets. Keys in Chapter 11 only need to be supported when the function to which they refer is mandatory to implement. โจ
10.14. Logout Request โจ
okay bestie, so the Logout Request is how you do a controlled closing of a connection. think graceful exit, no dramatic door slam ๐ช๐
An initiator MAY use a Logout Request to remove a connection from a session or to close an entire session ๐ง
After sending the Logout Request PDU, an initiator MUST NOT send any new iSCSI requests on the closing connection. if the Logout Request is meant to close the session, new iSCSI requests MUST NOT be sent on any of the connections in that session ๐
when a target gets a Logout Request with the reason code "close the connection" or "close the session", the target MUST terminate all pending commands on that connection or session respectively, whether they were acknowledged via ExpCmdSN or not ๐
when a target gets a Logout Request with the reason code "remove connection for recovery", the target MUST discard all requests that haven't been acknowledged via ExpCmdSN and were issued on the specified connection. it also has to suspend all data/status/R2T transfers on behalf of pending commands on that connection ๐ฅ
then the target issues the Logout Response and half-closes the TCP connection (sends FIN). after the initiator gets the Logout Response and tries to catch the FIN (if it still can), the initiator MUST completely close the logging-out connection. for the terminated commands, no additional responses should be expected ๐ซถ
a Logout for a CID can happen on a different transport connection when the TCP connection for that CID has already been terminated. in that case, a Logout just implies a logical "closing" of the iSCSI connection for the CID ๐ฆ
all commands that weren't terminated or completed (with status) and acknowledged when the connection is fully closed can be reassigned to a new connection if the target supports connection recovery โจ
if an initiator wants to start recovery for a failing connection, it MUST use the Logout Request to "clean-up" the target end of the failing connection and let recovery start. it can also use the Login Request with a non-zero TSIH and the same CID on a new connection to get the same effect (see Section 10.14.3 CID). in sessions with a single connection, the connection can be closed and then a new one reopened. a connection reinstatement login can be used for recovery too (see Section 5.3.4 Connection Reinstatement) ๐ธ
ngl this is the part to re-read. the cleanup order is everything ๐
a successful Logout Request with the reason code "close the connection" or "remove the connection for recovery" makes the target discard unacknowledged commands that came in on the connection being logged out. these are commands that arrived on that connection but haven't been delivered to SCSI, because one or more commands with a smaller CmdSN haven't been received by iSCSI yet. see Section 3.2.2.1 Command Numbering and Acknowledging. the resulting holes in the command sequence numbers have to be handled by appropriate recovery (see Chapter 6), unless the session is also closed ๐งฉ
the whole logout discussion in this section also applies to an implicit Logout done through a connection reinstatement or session reinstatement. when a Login Request does an implicit Logout, that implicit Logout happens as if it had the reason codes below ๐
Reason code Type of implicit Logout
-------------------------------------------
0 session reinstatement
1 connection reinstatement when
the operational ErrorRecoveryLevel < 2
2 connection reinstatement when
the operational ErrorRecoveryLevel = 2
Here's the PDU layout, verbatim, because the bits matter ๐
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|I| 0x06 |1| Reason Code | Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------------------------------------------------------+
8/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| CID or Reserved | Reserved |
+---------------+---------------+---------------+---------------+
24| CmdSN |
+---------------+---------------+---------------+---------------+
28| ExpStatSN |
+---------------+---------------+---------------+---------------+
32/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
10.14.1. Reason Code
Reason Code tells you why the Logout is happening:
0- close the session. all commands associated with the session (if any) are terminated.1- close the connection. all commands associated with the connection (if any) are terminated.2- remove the connection for recovery. the connection is closed and all commands associated with it (if any) are to be prepared for a new allegiance.
All other values are reserved ๐ท
10.14.2. TotalAHSLength and DataSegmentLength
For this PDU, TotalAHSLength and DataSegmentLength MUST be 0. no extras, babe ๐ซง
10.14.3. CID
This is the connection ID of the connection to be closed (including closing the TCP stream). this field is only valid if the reason code is not "close the session" ๐ง
10.14.4. ExpStatSN
This is the last ExpStatSN value for the connection to be closed ๐
10.14.5. Implicit termination of tasks
a target implicitly terminates the active tasks, thanks to the iSCSI protocol, in these cases:
- a) When a connection is implicitly or explicitly logged out with the reason code of "Close the connection" and there are active tasks allegiant to that connection.
- b) When a connection fails and eventually the connection state times out (state transition M1 in Section 7.2.2 State Transition Descriptions for Initiators and Targets) and there are active tasks allegiant to that connection.
- c) When a successful recovery Logout is performed while there are active tasks allegiant to that connection, and those tasks eventually time out after the Time2Wait and Time2Retain periods without allegiance reassignment.
- d) When a connection is implicitly or explicitly logged out with the reason code of "Close the session" and there are active tasks in that session.
if the tasks terminated in any of the above cases are SCSI tasks, they must be internally terminated as if with CHECK CONDITION status. this status only matters for handling the internal SCSI state and SCSI side effects around ordering, because it's never sent back to the initiator as a terminating status. however, extra actions might be needed at the SCSI level depending on the SCSI context defined by the SCSI standards (e.g., queued commands and ACA). in cases a), b), and c), after the tasks are terminated, the target MUST report a Unit Attention condition on the next command processed on any connection for each affected I_T_L nexus, with the status of CHECK CONDITION and the ASC/ASCQ value of 47h/7Fh - "SOME COMMANDS CLEARED BY ISCSI PROTOCOL EVENT" - etc. - see [SAM2] and [SPC3]). ngl this is a LOT of SCSI lore, but it's giving thorough ๐คโจ
10.15. Logout Response
The Logout Response is how the target tells you whether the cleanup for the connection(s) has finished ๐
After Logout, the TCP connection referred to by the CID MUST be closed at both ends (or all connections must be closed if the logout reason was session close) ๐
Here's the layout again, verbatim ๐ฆ
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x26 |1| Reserved | Response | Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------------------------------------------------------+
8/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag |
+---------------+---------------+---------------+---------------+
20| Reserved |
+---------------+---------------+---------------+---------------+
24| StatSN |
+---------------+---------------+---------------+---------------+
28| ExpCmdSN |
+---------------+---------------+---------------+---------------+
32| MaxCmdSN |
+---------------+---------------+---------------+---------------+
36| Reserved |
+---------------------------------------------------------------+
40| Time2Wait | Time2Retain |
+---------------+---------------+---------------+---------------+
44| Reserved |
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
10.15.1. Response
Logout Response values:
0- connection or session closed successfully.1- CID not found.2- connection recovery is not supported. this is for when the Logout reason code was recovery and the target doesn't support it, as indicated by the ErrorRecoveryLevel.3- cleanup failed for various reasons.
10.15.2. TotalAHSLength and DataSegmentLength
For this PDU, TotalAHSLength and DataSegmentLength MUST be 0 ๐
10.15.3. Time2Wait
If the Logout Response code is 0 and the operational ErrorRecoveryLevel is 2, this is the minimum amount of time, in seconds, to wait before attempting task reassignment. if the Logout Response code is 0 and the operational ErrorRecoveryLevel is less than 2, this field is to be ignored โณ
this field is invalid if the Logout Response code is 1 ๐
if the Logout Response code is 2 or 3, this field specifies the minimum time to wait before attempting a new implicit or explicit logout โฐ
if Time2Wait is 0, the reassignment or a new Logout may be attempted immediately ๐
10.15.4. Time2Retain โจ
okay so if the Logout response code is 0 and the operational ErrorRecoveryLevel is 2, this is the max amount of time (in seconds) the target waits, after the initial wait (Time2Wait), for the allegiance reassignment of any active task. Once that's up, the task state is discarded ๐. If the Logout response code is 0 but the operational ErrorRecoveryLevel is less than 2, this field is to be ignored, bestie ๐ซถ.
This field is invalid if the Logout response code is 1. Not it ๐ โโ๏ธ.
If the Logout response code is 2 or 3, this field is the max time (in seconds) the target waits, after Time2Wait, for a new implicit or explicit logout ๐ฆ.
If it's the last connection of a session, the whole session state gets discarded after Time2Retain. main character energy, the session gets cleaned up last ๐
If Time2Retain is 0, the target has already discarded the connection (and possibly the session) state along with the task states. So no reassignment or Logout is needed in this case ๐ธ.
10.16. SNACK Request ๐
Here's the diagram, copied exactly so nobody gets confused ๐ง:
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x10 |1|.|.|.| Type | Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN or Reserved |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
20| Target Transfer Tag or SNACK Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
24| Reserved |
+---------------+---------------+---------------+---------------+
28| ExpStatSN |
+---------------+---------------+---------------+---------------+
32/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
40| BegRun |
+---------------------------------------------------------------+
44| RunLength |
+---------------------------------------------------------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
ok so if the implementation supports ErrorRecoveryLevel greater than zero, it MUST support all SNACK types. No skipping, periodt ๐.
The SNACK is how the initiator asks the target to resend numbered-responses, data, or R2T PDUs ๐. Each request describes "runs" ๐โโ๏ธ: the run starts at the first StatSN, DataSN, or R2TSN that needs resending, and the count says how many Status, Data, or R2T PDUs are wanted, the first one included. And 0 is special here ๐ (lowkey the most confusing part):
- When it's used in RunLength, it means all PDUs starting with the initial.
- When it's used in both BegRun and RunLength, it means all unacknowledged PDUs.
The numbered-response(s) or R2T(s) requested by a SNACK MUST be delivered as exact replicas of the ones the target sent originally, except for the fields ExpCmdSN, MaxCmdSN, and ExpDataSN, which MUST carry the current values. R2T(s) requested by SNACK MUST also carry the current value of StatSN ๐ซถ.
The numbered Data-In PDUs requested by a Data SNACK MUST be delivered as exact replicas of the originals, except for the fields ExpCmdSN and MaxCmdSN, which MUST carry the current values, and except for resegmentation (see Section 10.16.3 Resegmentation) โจ.
Any SNACK that requests a numbered-response, Data, or R2T that was not sent by the target, or was already acknowledged by the initiator, MUST be rejected with a reason code of "Protocol error". Do NOT be that person ๐ โโ๏ธ๐.
10.16.1. Type ๐
This field encodes the SNACK function like this:
0- Data/R2T SNACK: requesting retransmission of one or more Data-In or R2T PDUs.1- Status SNACK: requesting retransmission of one or more numbered responses.2- DataACK: positively acknowledges Data-In PDUs.3- R-Data SNACK: requesting retransmission of Data-In PDUs with possible resegmentation and status tagging.
All other values are reserved ๐.
A Data/R2T SNACK, Status SNACK, or R-Data SNACK for a command MUST precede status acknowledgement for the given command. The order matters, iykyk ๐.
10.16.2. Data Acknowledgement ๐
If an initiator operates at ErrorRecoveryLevel 1 or higher, it MUST issue a SNACK of type DataACK after receiving a Data-In PDU with the A bit set to 1. BUT, if the initiator has detected holes in the input sequence, it MUST postpone issuing the DataACK SNACK until those holes are filled ๐ณ๏ธ. An initiator MAY ignore the A bit if it decides the bit is being set aggressively by the target (for example, before the MaxBurstLength limit is reached) ๐.
The DataACK is used to free resources at the target. It is not used to request or imply data retransmission, so don't mix those up ๐ .
An initiator MUST NOT request retransmission for any data it had already acknowledged. Once it's acked, it's acked, no cap ๐ง.
10.16.3. Resegmentation ๐ญ
If the initiator's MaxRecvDataSegmentLength changed between the original transmission and the time the initiator requests retransmission, the initiator MUST issue an R-Data SNACK (see Section 10.16.1 Type). With an R-Data SNACK, the initiator is saying it discards all the unacknowledged data and expects the target to resend it ๐. It also expects resegmentation. In this case the retransmitted Data-In PDUs MAY be different from the ones originally sent, so they can reflect the changes in MaxRecvDataSegmentLength โจ. Their DataSN starts with the BegRun of the last DataACK the target received, if it received any. Otherwise it starts with 0 and goes up by 1 for each resent Data-In PDU ๐ข.
A target that has received an R-Data SNACK MUST return a SCSI Response that contains a copy of the SNACK Tag field from the R-Data SNACK, in the SCSI Response SNACK Tag field, as its last or only Response ๐ซถ. For example, if it already sent a response with a different value in the SNACK Tag field, or it had the status included in the last Data-In PDU, it must send a new SCSI Response PDU ๐. If a target sends more than one SCSI Response PDU because of this rule, all SCSI responses must carry the same StatSN (see Section 10.4.4 SNACK Tag). And if an initiator tries to recover a lost SCSI Response (with a Status SNACK, see Section 10.16.1 Type) when more than one response has been sent, the target will send the SCSI Response with the latest content it knows about, including the last SNACK Tag for the command ๐ง .
For considerations in allegiance reassignment of a task to a connection with a different MaxRecvDataSegmentLength, refer to Section 6.2.2 Allegiance Reassignment ๐ฆ.
10.16.4. Initiator Task Tag ๐
For Status SNACK and DataACK, the Initiator Task Tag MUST be set to the reserved value 0xffffffff. In all other cases, the Initiator Task Tag field MUST be set to the Initiator Task Tag of the referenced command ๐ฏ.
10.16.5. Target Transfer Tag or SNACK Tag ๐
For an R-Data SNACK, this field MUST contain a value that is different from 0 or 0xffffffff, and it must be unique for the task (identified by the Initiator Task Tag). This value MUST be copied by the iSCSI target into the last or only SCSI Response PDU it issues for the command ๐.
For DataACK, the Target Transfer Tag MUST contain a copy of the Target Transfer Tag and LUN provided with the SCSI Data-In PDU that has the A bit set to 1 ๐ซง.
In all other cases, the Target Transfer Tag field MUST be set to the reserved value of 0xffffffff ๐.
10.16.6. BegRun ๐
This is the DataSN, R2TSN, or StatSN of the first PDU whose retransmission is requested (Data/R2T and Status SNACK), or the next expected DataSN (DataACK SNACK) ๐.
BegRun 0, used together with RunLength 0, means resend all unacknowledged Data-In, R2T, or Response PDUs ๐ซ.
BegRun MUST be 0 for an R-Data SNACK ๐ โโ๏ธ.
10.16.7. RunLength ๐
This is the number of PDUs whose retransmission is requested ๐ข.
RunLength 0 signals that all Data-In, R2T, or Response PDUs carrying numbers equal to or greater than BegRun have to be resent ๐.
The RunLength MUST also be 0 for a DataACK SNACK, in addition to an R-Data SNACK ๐ง.
10.17. Reject โจ
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x3f |1| Reserved | Reason | Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
16| 0xffffffff |
+---------------+---------------+---------------+---------------+
20| Reserved |
+---------------+---------------+---------------+---------------+
24| StatSN |
+---------------+---------------+---------------+---------------+
28| ExpCmdSN |
+---------------+---------------+---------------+---------------+
32| MaxCmdSN |
+---------------+---------------+---------------+---------------+
36| DataSN/R2TSN or Reserved |
+---------------+---------------+---------------+---------------+
40| Reserved |
+---------------+---------------+---------------+---------------+
44| Reserved |
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
xx/ Complete Header of Bad PDU /
+/ /
+---------------+---------------+---------------+---------------+
yy/Vendor specific data (if any) /
/ /
+---------------+---------------+---------------+---------------+
zz| Data-Digest (Optional) |
+---------------+---------------+---------------+---------------+
Reject is how an iSCSI error gets flagged ๐จ. Think protocol mix-ups, unsupported options, that whole vibe. ๐
10.17.1. Reason ๐
The reject Reason is coded like this, and the table is honestly so organized ๐ญ:
+------+----------------------------------------+------------------+
| Code | Explanation | Can the original |
| (hex)| | PDU be re-sent? |
+------+----------------------------------------+------------------+
| 0x01 | Reserved | no |
| | | |
| 0x02 | Data (payload) Digest Error | yes (Note 1) |
| | | |
| 0x03 | SNACK Reject | yes |
| | | |
| 0x04 | Protocol Error (e.g., SNACK request for| no |
| | a status that was already acknowledged)| |
| | | |
| 0x05 | Command not supported | no |
| | | |
| 0x06 | Immediate Command Reject - too many | yes |
| | immediate commands | |
| | | |
| 0x07 | Task in progress | no |
| | | |
| 0x08 | Invalid Data ACK | no |
| | | |
| 0x09 | Invalid PDU field | no (Note 2) |
| | | |
| 0x0a | Long Operation Reject - Can't generate | yes |
| | Target Transfer Tag - out of resources | |
| | | |
| 0x0b | Negotiation Reset | no |
| | | |
| 0x0c | Waiting for Logout | no |
+------+----------------------------------------+------------------+
Note 1 (read this one, bestie ๐ซถ): for iSCSI, a Data-Out PDU only gets retransmitted if the target asks for it with a recovery R2T. BUT if it's a data digest error on immediate data, the initiator may choose to resend the whole PDU, immediate data included.
Note 2: a target should use this reason code for all invalid values of PDU fields that are meant to describe a task, a response, or a data transfer. Some examples are invalid TTT/ITT, buffer offset, LUN qualifying a TTT, and an invalid sequence number in a SNACK. ๐
All other values for Reason are reserved, so those are off-limits ๐ซ.
In every case where a pre-instantiated SCSI task gets terminated because of the reject, the target MUST issue a proper SCSI command response with CHECK CONDITION, as described in Section 10.4.3 Response. If a status for the SCSI task was already sent before the reject, no additional status is required. ๐ธ If the error is detected while data from the initiator is still expected (that is, the command PDU did not contain all the data, and the target has not received a Data-Out PDU with the Final bit set to 1 for the unsolicited data, if any, and all outstanding R2Ts, if any), the target MUST wait until it receives the last expected Data-Out PDUs with the F bit set to 1 before sending the Response PDU. Patience is a whole aesthetic ๐ง.
For additional usage semantics of Reject PDU, see Section 6.3 Usage Of Reject PDU in Recovery. ๐ฆ
10.17.2. DataSN/R2TSN ๐
This field is only valid if the rejected PDU is a Data/R2T SNACK and the Reject reason code is "Protocol error" (see Section 10.16 SNACK Request). The DataSN/R2TSN is the next Data/R2T sequence number that the target would send for the task, if any. โจ
10.17.3. StatSN, ExpCmdSN and MaxCmdSN ๐
These fields carry their usual values and are not related to the rejected command. StatSN is advanced after a Reject. ๐
10.17.4. Complete Header of Bad PDU ๐ฅ
The target returns the header (not including digest) of the PDU in error as the data of the response. It's basically showing its work ๐.
10.18. NOP-Out ๐
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|I| 0x00 |1| Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN or Reserved |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
20| Target Transfer Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
24| CmdSN |
+---------------+---------------+---------------+---------------+
28| ExpStatSN |
+---------------+---------------+---------------+---------------+
32/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
/ DataSegment - Ping Data (optional) /
+/ /
+---------------+---------------+---------------+---------------+
| Data-Digest (Optional) |
+---------------+---------------+---------------+---------------+
A NOP-Out is the initiator's ping ๐. It can be used to check that a connection/session is still active and all its components are operational, and the NOP-In response is the "ping echo" ๐.
The initiator also sends a NOP-Out in response to a NOP-In. ๐
A NOP-Out may also be used to confirm a changed ExpStatSN if another PDU will not be available for a long time. โณ
Upon receipt of a NOP-In with the Target Transfer Tag set to a valid value (not the reserved 0xffffffff), the initiator MUST respond with a NOP-Out. In this case, the NOP-Out Target Transfer Tag MUST contain a copy of the NOP-In Target Transfer Tag. ๐ซถ
10.18.1. Initiator Task Tag ๐ธ
The NOP-Out MUST have the Initiator Task Tag set to a valid value only if a response in the form of NOP-In is requested (i.e., the NOP-Out is used as a ping request). Otherwise, the Initiator Task Tag MUST be set to 0xffffffff. ๐
When a target receives the NOP-Out with a valid Initiator Task Tag, it MUST respond with a Nop-In Response (see Section 10.19 NOP-In). ๐
If the Initiator Task Tag contains 0xffffffff, the I bit MUST be set to 1, and the CmdSN is not advanced after this PDU is sent. ๐
10.18.2. Target Transfer Tag ๐ฆ
A target assigned identifier for the operation. ๐ง
The NOP-Out MUST only have the Target Transfer Tag set if it is issued in response to a NOP-In with a valid Target Transfer Tag. In this case, it copies the Target Transfer Tag from the NOP-In PDU. Otherwise, the Target Transfer Tag MUST be set to 0xffffffff. ๐
When the Target Transfer Tag is set to a value other than 0xffffffff, the LUN field MUST also be copied from the NOP-In. ๐
10.18.3. Ping Data ๐ฅ
Ping data are reflected in the NOP-In Response. The length of the reflected data is limited to MaxRecvDataSegmentLength. The length of ping data is indicated by the DataSegmentLength. 0 is a valid value for the DataSegmentLength and indicates the absence of ping data, so an empty ping is totally fine ๐โจ.
10.19. NOP-In ๐
okay so NOP-In is the target's multitasking queen move ๐ it's either a reply to a NOP-Out, a "ping" sent to the initiator ๐, or a way to sneak in an updated ExpCmdSN and/or MaxCmdSN when no other PDU is gonna show up for a long time (the target decides what "long" means ๐ฐ๏ธ)
Byte/ 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0|.|.| 0x20 |1| Reserved |
+---------------+---------------+---------------+---------------+
4|TotalAHSLength | DataSegmentLength |
+---------------+---------------+---------------+---------------+
8| LUN or Reserved |
+ +
12| |
+---------------+---------------+---------------+---------------+
16| Initiator Task Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
20| Target Transfer Tag or 0xffffffff |
+---------------+---------------+---------------+---------------+
24| StatSN |
+---------------+---------------+---------------+---------------+
28| ExpCmdSN |
+---------------+---------------+---------------+---------------+
32| MaxCmdSN |
+---------------+---------------+---------------+---------------+
36/ Reserved /
+/ /
+---------------+---------------+---------------+---------------+
48| Header-Digest (Optional) |
+---------------+---------------+---------------+---------------+
/ DataSegment - Return Ping Data /
+/ /
+---------------+---------------+---------------+---------------+
| Data-Digest (Optional) |
+---------------+---------------+---------------+---------------+
so when a target gets a NOP-Out with a valid Initiator Task Tag (aka not the reserved 0xffffffff), it MUST respond with a NOP-In carrying that same Initiator Task Tag from the NOP-Out request ๐ซถ it MUST also copy back up to the first MaxRecvDataSegmentLength bytes of the Ping Data the initiator sent, and for these responses the Target Transfer Tag MUST be 0xffffffff ๐
otherwise, when a target sends a NOP-In that is not a response to a Nop-Out from the initiator, the Initiator Task Tag MUST be set to 0xffffffff and the Data Segment MUST NOT contain any data (DataSegmentLength MUST be 0) ๐
10.19.1. Target Transfer Tag
- if the target is responding to a NOP-Out, this is set to the reserved value
0xffffffff๐ - if the target is sending a NOP-In as a Ping (intending to receive a corresponding NOP-Out), this field is set to a valid value (not the reserved
0xffffffff) ๐ - if the target is initiating a NOP-In without wanting to receive a corresponding NOP-Out, this field MUST hold the reserved value of
0xffffffff๐ง
10.19.2. StatSN
the StatSN field will always contain the next StatSN โจ the one exception: when the Initiator Task Tag is set to 0xffffffff, the StatSN for the connection is not advanced after this PDU is sent ๐
10.19.3. LUN
a LUN MUST be set to a correct value when the Target Transfer Tag is valid (not the reserved value 0xffffffff) ๐
11. iSCSI Security Text Keys and Authentication Methods ๐
okay the security vibes start here ๐ฅ only the following keys are used during the SecurityNegotiation stage of the Login Phase:
SessionType
InitiatorName
TargetName
TargetAddress
InitiatorAlias
TargetAlias
TargetPortalGroupTag
AuthMethod and the keys used by the authentication methods
specified under Section 11.1 AuthMethod along with all of
their associated keys as well as Vendor Specific
Authentication Methods.
other keys MUST NOT be used ๐ โโ๏ธ
SessionType, InitiatorName, TargetName, InitiatorAlias, TargetAlias, and TargetPortalGroupTag are described in Chapter 12 because they can also be used in the OperationalNegotiation stage ๐
all security keys have connection-wide applicability ๐ฆ
11.1. AuthMethod
Use: During Login - Security Negotiation Senders: Initiator and
Target Scope: connection
AuthMethod = <list-of-values>
the main item of security negotiation is the authentication method (AuthMethod) ๐
the authentication methods that can be used (the ones in the list-of-values) are either the ones in this table or vendor-unique methods:
+------------------------------------------------------------+
| Name | Description |
+------------------------------------------------------------+
| KRB5 | Kerberos V5 - defined in [RFC1510] |
+------------------------------------------------------------+
| SPKM1 | Simple Public-Key GSS-API Mechanism |
| | defined in [RFC2025] |
+------------------------------------------------------------+
| SPKM2 | Simple Public-Key GSS-API Mechanism |
| | defined in [RFC2025] |
+------------------------------------------------------------+
| SRP | Secure Remote Password |
| | defined in [RFC2945] |
+------------------------------------------------------------+
| CHAP | Challenge Handshake Authentication Protocol|
| | defined in [RFC1994] |
+------------------------------------------------------------+
| None | No authentication |
+------------------------------------------------------------+
the AuthMethod selection is followed by an "authentication exchange" specific to whichever method got picked ๐
the authentication method proposal can come from either the initiator or the target ๐ซถ but the initiator MUST make the first step specific to the selected authentication method as soon as it's selected. so if the target makes the proposal, the initiator sends the first key(s) of the exchange together with its authentication method selection ๐
the authentication exchange authenticates the initiator to the target, and optionally the target to the initiator โจ authentication is OPTIONAL to use, but it MUST be supported by the target and initiator ๐ฅ
the initiator and target MUST implement CHAP ๐ all other authentication methods are OPTIONAL ๐ธ
private or public extension algorithms MAY also be negotiated for authentication methods ๐ง whenever a private or public extension algorithm is part of the default offer (the offer made without any explicit administrative action), the implementer MUST ensure that CHAP is listed as an alternative in the default offer, and "None" is not part of the default offer ๐
extension authentication methods MUST be named using one of these two formats:
a) Z-reversed.vendor.dns_name.do_something=
b) Z<#><IANA-registered-string>=
methods named with the Z- format are private extensions ๐ methods named with the Z# format are public extensions that must be registered with IANA and MUST be described by an informational RFC ๐
for all of the public or private extension authentication methods, the method-specific keys MUST conform to the format specified in Section 5.1 Text Format for standard-label ๐
to identify the vendor for private extension authentication methods, we suggest using the reversed DNS-name as a prefix to the proper digest names ๐
the part of digest-name following Z- and Z# MUST conform to the format for standard-label specified in Section 5.1 Text Format ๐
support for public or private extension authentication methods is OPTIONAL ๐ฆ
the following subsections define the specific exchanges for each of the standardized authentication methods. like I said earlier, the first step is always done by the initiator ๐ซถ
11.1.1. Kerberos
for KRB5 (Kerberos V5) [RFC1510] and [RFC1964], the initiator MUST use:
KRB_AP_REQ=<KRB_AP_REQ>
where KRB_AP_REQ is the client message as defined in [RFC1510] ๐
the default principal name assumed by an iSCSI initiator or target (before any administrative configuration action) MUST be the iSCSI Initiator Name or iSCSI Target Name respectively, prefixed by the string "iscsi/" ๐
if the initiator authentication fails, the target MUST respond with a Login reject with "Authentication Failure" status. otherwise, if the initiator has selected the mutual authentication option (by setting MUTUAL-REQUIRED in the ap-options field of the KRB_AP_REQ), the target MUST reply with:
KRB_AP_REP=<KRB_AP_REP>
where KRB_AP_REP is the server's response message as defined in [RFC1510] โจ
if mutual authentication was selected and target authentication fails, the initiator MUST close the connection ๐
KRB_AP_REQ and KRB_AP_REP are binary-values, and their binary length (not the length of the character string that represents them in encoded form) MUST not exceed 65536 bytes ๐
11.1.2. Simple Public-Key Mechanism (SPKM)
for SPKM1 and SPKM2 [RFC2025], the initiator MUST use:
SPKM_REQ=<SPKM-REQ>
where SPKM-REQ is the first initiator token as defined in [RFC2025] ๐ง
[RFC2025] defines situations where each side may send an error token that may cause the peer to re-generate and resend its last token. this scheme is followed in iSCSI, and the error token syntax is:
SPKM_ERROR=<SPKM-ERROR>
however, the SPKM-DEL tokens that [RFC2025] defines for fatal errors will not be used by iSCSI ๐ โโ๏ธ if the target needs to send a SPKM-DEL token, it will instead send a Login "login reject" message with the "Authentication Failure" status and terminate the connection. if the initiator needs to send a SPKM-DEL token, it will close the connection ๐
in the following sections, we assume that no SPKM-ERROR tokens are required ๐ธ
if the initiator authentication fails, the target MUST return an error. otherwise, if the AuthMethod is SPKM1, or if the initiator has selected the mutual authentication option (by setting the mutual-state bit in the options field of the REQ-TOKEN in the SPKM-REQ), the target MUST reply with:
SPKM_REP_TI=<SPKM-REP-TI>
where SPKM-REP-TI is the target token as defined in [RFC2025] ๐ฆ
if mutual authentication was selected and target authentication fails, the initiator MUST close the connection. otherwise, if the AuthMethod is SPKM1, the initiator MUST continue with:
SPKM_REP_IT=<SPKM-REP-IT>
where SPKM-REP-IT is the second initiator token as defined in [RFC2025]. if the initiator authentication fails, the target MUST answer with a Login reject with "Authentication Failure" status ๐ญ
SPKM requires support for very long authentication items ๐
all the SPKM-* tokens are binary-values, and their binary length (not the length of the character string that represents them in encoded form) MUST not exceed 65536 bytes ๐
11.1.3. Secure Remote Password (SRP) ๐โจ
okay so SRP time bestie ๐ For SRP [RFC2945], the initiator MUST use:
SRP_U=<U> TargetAuth=Yes /* or TargetAuth=No */
The target MUST answer with a Login reject with the "Authorization Failure" status or reply with:
SRP_GROUP=<G1,G2...> SRP_s=<s>
Where G1,G2... are proposed groups, in order of preference.
The initiator MUST either close the connection or continue with:
SRP_A=<A> SRP_GROUP=<G>
Where G is one of G1,G2... that were proposed by the target.
The target MUST answer with a Login reject with the "Authentication Failure" status or reply with:
SRP_B=<B>
The initiator MUST close the connection or continue with:
SRP_M=<M>
If the initiator authentication fails, the target MUST answer with a Login reject with "Authentication Failure" status. Otherwise, if the initiator sent TargetAuth=Yes in the first message (requiring target authentication), the target MUST reply with:
SRP_HM=<H(A | M | K)>
If the target authentication fails, the initiator MUST close the connection.
Where U, s, A, B, M, and H(A | M | K) are defined in [RFC2945] (using the SHA1 hash function, such as SRP-SHA1) and G,Gn (Gn stands for G1,G2...) are identifiers of SRP groups specified in [RFC3723]. G, Gn, and U are text strings, s,A,B,M, and H(A | M | K) are binary-values. The length of s,A,B,M and H(A | M | K) in binary form (not the length of the character string that represents them in encoded form) MUST not exceed 1024 bytes.
For the SRP_GROUP, all the groups specified in [RFC3723] up to 1536 bits (i.e., SRP-768, SRP-1024, SRP-1280, SRP-1536) must be supported by initiators and targets. To guarantee interoperability, targets MUST always offer "SRP-1536" as one of the proposed groups. ๐ซถ
11.1.4. Challenge Handshake Authentication Protocol (CHAP) ๐งฉ
For CHAP [RFC1994], in the first step, the initiator MUST send:
CHAP_A=<A1,A2...>
Where A1,A2... are proposed algorithms, in order of preference.
In the second step, the target MUST answer with a Login reject with the "Authentication Failure" status or reply with:
CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
Where A is one of A1,A2... that were proposed by the initiator.
In the third step, the initiator MUST continue with:
CHAP_N=<N> CHAP_R=<R>
or, if it requires target authentication, with:
CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C>
If the initiator authentication fails, the target MUST answer with a Login reject with "Authentication Failure" status. Otherwise, if the initiator required target authentication, the target MUST either answer with a Login reject with "Authentication Failure" or reply with:
CHAP_N=<N> CHAP_R=<R>
If target authentication fails, the initiator MUST close the connection.
Where N, (A,A1,A2), I, C, and R are (correspondingly) the Name, Algorithm, Identifier, Challenge, and Response as defined in [RFC1994], N is a text string, A,A1,A2, and I are numbers, and C and R are large-binary-values and their binary length (not the length of the character string that represents them in encoded form) MUST not exceed 1024 bytes.
For the Algorithm, as stated in [RFC1994], one value is required to be implemented:
5 (CHAP with MD5)
To guarantee interoperability, initiators MUST always offer it as one of the proposed algorithms. ๐
12. Login/Text Operational Text Keys ๐
okay this part is about the operational keys, and some of them are super strict ๐ญ Some session specific parameters MUST only be carried on the leading connection and cannot be changed after the leading connection login (e.g., MaxConnections, the maximum number of connections). This holds for a single connection session with regard to connection restart. The keys that fall into this category have the use: LO (Leading Only).
Keys that can only be used during login have the use: IO (initialize only), while those that can be used in both the Login Phase and Full Feature Phase have the use: ALL.
Keys that can only be used during Full Feature Phase use FFPO (Full Feature Phase only).
Keys marked as Any-Stage may also appear in the SecurityNegotiation stage while all other keys described in this chapter are operational keys.
Keys that do not require an answer are marked as Declarative.
Key scope is indicated as session-wide (SW) or connection-only (CO).
Result function, wherever mentioned, states the function that can be applied to check the validity of the responder selection. Minimum means that the selected value cannot exceed the offered value. Maximum means that the selected value cannot be lower than the offered value. AND means that the selected value must be a possible result of a Boolean "and" function with an arbitrary Boolean value (e.g., if the offered value is No the selected value must be No). OR means that the selected value must be a possible result of a Boolean "or" function with an arbitrary Boolean value (e.g., if the offered value is Yes the selected value must be Yes).
12.1. HeaderDigest and DataDigest ๐งฎ
Use: IO
Senders: Initiator and Target
Scope: CO
HeaderDigest = <list-of-values>
DataDigest = <list-of-values>
Default is None for both HeaderDigest and DataDigest.
Digests enable the checking of end-to-end, non-cryptographic data integrity beyond the integrity checks provided by the link layers and the covering of the whole communication path including all elements that may change the network level PDUs such as routers, switches, and proxies.
The following table lists cyclic integrity checksums that can be negotiated for the digests and that MUST be implemented by every iSCSI initiator and target. These digest options only have error detection significance.
+---------------------------------------------+
| Name | Description | Generator |
+---------------------------------------------+
| CRC32C | 32 bit CRC |0x11edc6f41|
+---------------------------------------------+
| None | no digest |
+---------------------------------------------+
The generator polynomial for this digest is given in hex-notation (e.g., 0x3b stands for 0011 1011 and the polynomial is x5+X4+x**3+x+1).
When the Initiator and Target agree on a digest, this digest MUST be used for every PDU in Full Feature Phase.
Padding bytes, when present in a segment covered by a CRC, SHOULD be set to 0 and are included in the CRC.
The CRC MUST be calculated by a method that produces the same results as the following process:
- The PDU bits are considered as the coefficients of a polynomial M(x) of degree n-1; bit 7 of the lowest numbered byte is considered the most significant bit (x^n-1), followed by bit 6 of the lowest numbered byte through bit 0 of the highest numbered byte (x^0).
- The most significant 32 bits are complemented.
- The polynomial is multiplied by x^32 then divided by G(x). The generator polynomial produces a remainder R(x) of degree <= 31.
- The coefficients of R(x) are considered a 32 bit sequence.
- The bit sequence is complemented and the result is the CRC.
- The CRC bits are mapped into the digest word. The x^31 coefficient in bit 7 of the lowest numbered byte of the digest continuing through to the byte up to the x^24 coefficient in bit 0 of the lowest numbered byte, continuing with the x^23 coefficient in bit 7 of next byte through x^0 in bit 0 of the highest numbered byte.
- Computing the CRC over any segment (data or header) extended to include the CRC built using the generator 0x11edc6f41 will always get the value 0x1c2d19ed as its final remainder (R(x)). This value is given here in its polynomial form (i.e., not mapped as the digest word).
For a discussion about selection criteria for the CRC, see [RFC3385]. For a detailed analysis of the iSCSI polynomial, see [Castagnoli93].
Private or public extension algorithms MAY also be negotiated for digests. Whenever a private or public digest extension algorithm is part of the default offer (the offer made in absence of explicit administrative action) the implementer MUST ensure that CRC32C is listed as an alternative in the default offer and "None" is not part of the default offer.
Extension digest algorithms MUST be named using one of the following two formats:
a) Y-reversed.vendor.dns_name.do_something=
b) Y<#><IANA-registered-string>=
Digests named using the Y- format are used for private purposes (unregistered). Digests named using the Y# format (public extension) must be registered with IANA and MUST be described by an informational RFC.
For private extension digests, to identify the vendor, we suggest you use the reversed DNS-name as a prefix to the proper digest names.
The part of digest-name following Y- and Y# MUST conform to the format for standard-label specified in Section 5.1 Text Format.
Support for public or private extension digests is OPTIONAL.
12.2. MaxConnections ๐ข
Use: LO
Senders: Initiator and Target
Scope: SW
Irrelevant when: SessionType=Discovery
MaxConnections=<numerical-value-from-1-to-65535>
Default is 1.
Result function is Minimum.
Initiator and target negotiate the maximum number of connections requested/acceptable. ๐ฆ
12.3. SendTargets ๐ฌ
Use: FFPO
Senders: Initiator
Scope: SW
For a complete description, see Appendix D. - SendTargets Operation -.
12.4. TargetName ๐ฏ
Use: IO by initiator, FFPO by target - only as response to a
SendTargets, Declarative, Any-Stage
Senders: Initiator and Target
Scope: SW
TargetName=<iSCSI-name-value>
Examples:
TargetName=iqn.1993-11.com.disk-vendor:diskarrays.sn.45678
TargetName=eui.020000023B040506
The initiator of the TCP connection MUST provide this key to the remote endpoint in the first login request if the initiator is not establishing a discovery session. The iSCSI Target Name specifies the worldwide unique name of the target.
The TargetName key may also be returned by the "SendTargets" text request (which is its only use when issued by a target).
TargetName MUST not be redeclared within the login phase. ๐ซ
12.5. InitiatorName ๐ชช
Use: IO, Declarative, Any-Stage
Senders: Initiator
Scope: SW
InitiatorName=<iSCSI-name-value>
Examples:
InitiatorName=iqn.1992-04.com.os-vendor.plan9:cdrom.12345
InitiatorName=iqn.2001-02.com.ssp.users:customer235.host90
The initiator of the TCP connection MUST provide this key to the remote endpoint at the first Login of the Login Phase for every connection. The InitiatorName key enables the initiator to identify itself to the remote endpoint.
InitiatorName MUST not be redeclared within the login phase. ๐
12.6. TargetAlias ๐ธ
Use: ALL, Declarative, Any-Stage
Senders: Target
Scope: SW
TargetAlias=<iSCSI-local-name-value>
Examples:
TargetAlias=Bob-s Disk
TargetAlias=Database Server 1 Log Disk
TargetAlias=Web Server 3 Disk 20
If a target has been configured with a human-readable name or description, this name SHOULD be communicated to the initiator during a Login Response PDU if SessionType=Normal (see Section 12.21 SessionType). This string is not used as an identifier, nor is it meant to be used for authentication or authorization decisions. It can be displayed by the initiator's user interface in a list of targets to which it is connected. โจ
12.7. InitiatorAlias ๐
Use: ALL, Declarative, Any-Stage
Senders: Initiator
Scope: SW
InitiatorAlias=<iSCSI-local-name-value>
Examples:
InitiatorAlias=Web Server 4
InitiatorAlias=spyalley.nsa.gov
InitiatorAlias=Exchange Server
okay so if an initiator has a human-readable name or description, it SHOULD be shared with the target during a Login Request PDU ๐ซถ And if it doesn't have one? The host name can be used instead ๐
This string is not an identifier, and it's not for authentication or authorization decisions, so don't use it for that ๐ โโ๏ธ The target's user interface can display it in a list of the initiators that are connected to it โจ
12.8. TargetAddress ๐ฆ
Use: ALL, Declarative, Any-Stage
Senders: Target
Scope: SW
TargetAddress=domainname[:port][,portal-group-tag]
The domainname can be a DNS host name, a dotted-decimal IPv4 address, or a bracketed IPv6 address, as described in [RFC2732] ๐
If you don't specify the TCP port, it's assumed to be the IANA-assigned default port for iSCSI (see Section 13 IANA Considerations) ๐
If the TargetAddress comes back as the result of a redirect status in a login response, the comma and portal group tag MUST be omitted ๐
If the TargetAddress comes back inside a SendTargets response, the portal group tag MUST be included ๐ซถ
Examples:
TargetAddress=10.0.0.1:5003,1
TargetAddress=[1080:0:0:0:8:800:200C:417A],65
TargetAddress=[1080::8:800:200C:417A]:5003,1
TargetAddress=computingcenter.example.com,23
Use of the portal-group-tag is described in Appendix D ๐ง
- SendTargets Operation -. The formats for the port and portal-group-tag are the same as the one specified in Section 12.9 TargetPortalGroupTag ๐
12.9. TargetPortalGroupTag ๐ธ
Use: IO by target, Declarative, Any-Stage
Senders: Target
Scope: SW
TargetPortalGroupTag=<16-bit-binary-value>
Example:
TargetPortalGroupTag=1
okay so the target portal group tag is a 16-bit binary value that uniquely identifies a portal group within an iSCSI target node ๐ It carries the tag of the portal group that's servicing the Login request. The iSCSI target sends this key back to the initiator in the Login Response PDU to the first Login Request PDU that has the C bit set to 0, when the initiator gives a TargetName ๐ฅ
For the complete usage expectations of this key, see Section 5.3 Login Phase โจ
12.10. InitialR2T ๐
Use: LO
Senders: Initiator and Target
Scope: SW
Irrelevant when: SessionType=Discovery
InitialR2T=<boolean-value>
Examples:
I->InitialR2T=No
T->InitialR2T=No
Default is Yes. Result function is OR.
The InitialR2T key is how you turn off the default use of R2T for unidirectional commands and the output part of bidirectional commands ๐ง That lets an initiator start sending data right away, as if it had already received an initial R2T with Buffer Offset=Immediate Data Length and Desired Data Transfer Length=(min(FirstBurstLength, Expected Data Transfer Length) - Received Immediate Data Length). It's giving "I already got permission" energy ๐
By default, R2T is required, unless both the initiator and the target send this key-pair attribute with InitialR2T=No. Only the first outgoing data burst (immediate data and/or separate PDUs) can go out unsolicited, meaning without an explicit R2T ๐
12.11. ImmediateData ๐ฆ
Use: LO
Senders: Initiator and Target
Scope: SW
Irrelevant when: SessionType=Discovery
ImmediateData=<boolean-value>
Default is Yes. Result function is AND.
The initiator and target negotiate support for immediate data ๐ค To turn it off, the initiator or target has to say so. ImmediateData can only be turned on if both the initiator and the target have ImmediateData=Yes ๐
If ImmediateData is Yes and InitialR2T is Yes (the default), then only immediate data is accepted in the first burst ๐
If ImmediateData is No and InitialR2T is Yes, the initiator MUST NOT send unsolicited data, and the target MUST reject unsolicited data with the corresponding response code ๐ซ
If ImmediateData is No and InitialR2T is No, the initiator MUST NOT send unsolicited immediate data, but it MAY send one unsolicited burst of Data-Out PDUs ๐
If ImmediateData is Yes and InitialR2T is No, the initiator MAY send unsolicited immediate data and/or one unsolicited burst of Data-Out PDUs โจ
Here's a quick summary table of the unsolicited data options ๐
+----------+-------------+------------------+--------------+
|InitialR2T|ImmediateData| Unsolicited |Immediate Data|
| | | Data Out PDUs | |
+----------+-------------+------------------+--------------+
| No | No | Yes | No |
+----------+-------------+------------------+--------------+
| No | Yes | Yes | Yes |
+----------+-------------+------------------+--------------+
| Yes | No | No | No |
+----------+-------------+------------------+--------------+
| Yes | Yes | No | Yes |
+----------+-------------+------------------+--------------+
12.12. MaxRecvDataSegmentLength ๐ธ
Use: ALL, Declarative
Senders: Initiator and Target
Scope: CO
MaxRecvDataSegmentLength=<numerical-value-512-to-(2**24-1)>
Default is 8192 bytes.
Each initiator or target declares the maximum data segment length, in bytes, that it can receive in an iSCSI PDU ๐
The transmitter (initiator or target) is required to send PDUs whose data segment doesn't exceed the receiver's MaxRecvDataSegmentLength ๐
A target receiver is also limited by MaxBurstLength for solicited data and by FirstBurstLength for unsolicited data. An initiator MUST NOT send solicited PDUs that exceed MaxBurstLength, nor unsolicited PDUs that exceed FirstBurstLength (or FirstBurstLength-Immediate Data Length if immediate data was sent) ๐ซโจ
12.13. MaxBurstLength ๐ง
Use: LO
Senders: Initiator and Target
Scope: SW
Irrelevant when: SessionType=Discovery
MaxBurstLength=<numerical-value-512-to-(2**24-1)>
Default is 262144 (256 Kbytes).
Result function is Minimum.
The initiator and target negotiate the maximum SCSI data payload, in bytes, for a Data-In or solicited Data-Out iSCSI sequence ๐ฆ A sequence is one or more consecutive Data-In or Data-Out PDUs that ends with a Data-In or Data-Out PDU whose F bit is set to one ๐ฆ
12.14. FirstBurstLength ๐
Use: LO
Senders: Initiator and Target
Scope: SW
Irrelevant when: SessionType=Discovery
Irrelevant when: ( InitialR2T=Yes and ImmediateData=No )
FirstBurstLength=<numerical-value-512-to-(2**24-1)>
Default is 65536 (64 Kbytes).
Result function is Minimum.
The initiator and target negotiate the maximum amount of unsolicited data, in bytes, that an iSCSI initiator can send to the target while a single SCSI command is running ๐ That covers the immediate data (if any) and the sequence of unsolicited Data-Out PDUs (if any) that follow the command.
FirstBurstLength MUST NOT exceed MaxBurstLength ๐ โโ๏ธ
12.15. DefaultTime2Wait โณ
Use: LO
Senders: Initiator and Target
Scope: SW
DefaultTime2Wait=<numerical-value-0-to-3600>
Default is 2.
Result function is Maximum.
The initiator and target negotiate the minimum time, in seconds, to wait before trying an explicit or implicit logout, or an active task reassignment, after an unexpected connection termination or a connection reset ๐
A value of 0 means logout or active task reassignment can be tried immediately โก
12.16. DefaultTime2Retain ๐
Use: LO Senders: Initiator and Target Scope: SW
DefaultTime2Retain=<numerical-value-0-to-3600>
Default is 20. Result function is Minimum.
The initiator and target negotiate the maximum time, in seconds after the initial wait (Time2Wait), during which an active task reassignment is still possible after an unexpected connection termination or a connection reset ๐ฐ๏ธ
This value is also the session state timeout if the connection in question is the last LOGGED_IN connection in the session ๐ซถ
A value of 0 means the target discards the connection and task state immediately ๐
12.17. MaxOutstandingR2T ๐
Use: LO
Senders: Initiator and Target
Scope: SW
MaxOutstandingR2T=<numerical-value-from-1-to-65535>
Irrelevant when: SessionType=Discovery
Default is 1.
Result function is Minimum.
The initiator and target negotiate the maximum number of outstanding R2Ts per task, not counting any implied initial R2T that might be part of that task ๐ฅ An R2T stays outstanding until the last data PDU (with the F bit set to 1) is transferred, or until a sequence reception timeout (Section 6.1.4.1 Recovery Within-command) is hit for that data sequence โฑ๏ธ
12.18. DataPDUInOrder ๐
Use: LO
Senders: Initiator and Target
Scope: SW
Irrelevant when: SessionType=Discovery
DataPDUInOrder=<boolean-value>
Default is Yes.
Result function is OR.
No tells iSCSI that the data PDUs within a sequence can arrive in any order ๐ฒ Yes means the data PDUs within a sequence have to sit at continuously increasing addresses, and overlaps are forbidden ๐
12.19. DataSequenceInOrder ๐งฉ
Use: LO
Senders: Initiator and Target
Scope: SW
Irrelevant when: SessionType=Discovery
DataSequenceInOrder=<boolean-value>
Default is Yes. Result function is OR.
A Data Sequence is a sequence of Data-In or Data-Out PDUs that ends with a Data-In or Data-Out PDU whose F bit is set to one ๐ฆ A Data-Out sequence is sent either unsolicited or in response to an R2T. Sequences cover an offset range ๐
If DataSequenceInOrder is No, Data PDU sequences can be transferred in any order ๐
If DataSequenceInOrder is Yes, Data Sequences MUST be transferred using continuously non-decreasing sequence offsets (the R2T buffer offset for writes, or the smallest SCSI Data-In buffer offset within a read data sequence) ๐
If DataSequenceInOrder is Yes, a target may retry at most the last R2T, and an initiator may at most request retransmission for the last read data sequence. For this reason, if ErrorRecoveryLevel is not 0 and DataSequenceInOrder is Yes, then MaxOustandingR2T MUST be set to 1 ๐
Heads up bestie: when ErrorRecoveryLevel is not 0 and DataSequenceInOrder is Yes, MaxOustandingR2T has to be 1. No exceptions ๐
12.20. ErrorRecoveryLevel ๐
Use: LO
Senders: Initiator and Target
Scope: SW
ErrorRecoveryLevel=<numerical-value-0-to-2>
Default is 0.
Result function is Minimum.
The initiator and target negotiate the recovery level they both support ๐
Recovery levels are combinations of recovery capabilities. Each level includes all the capabilities of the lower levels and adds some new ones on top ๐ช
When the recovery mechanisms are described, certain recovery classes are specified. Section 6.1.5 Error Recovery Hierarchy explains how those classes map to the levels ๐บ๏ธ
12.21. SessionType โจ
Use: LO, Declarative, Any-Stage
Senders: Initiator
Scope: SW
SessionType= <Discovery|Normal>
Default is Normal ๐
The initiator picks what kind of session it wants to make ๐ and the target can either say yes or say no ๐ โโ๏ธ
A discovery session tells the Target that its ONLY job is discovery ๐ The only requests a target accepts in this kind of session are a text request with a SendTargets key and a logout request with reason "close the session" ๐ง
Also, a discovery session implies MaxConnections = 1 and overrides both the default and any explicit setting. Lowkey iconic that it wins over everything ๐
12.22. The Private or Public Extension Key Format
Use: ALL
Senders: Initiator and Target
Scope: specific key dependent
X-reversed.vendor.dns_name.do_something=
or
X<#><IANA-registered-string>=
Okay so these keys are for public or private extension stuff ๐ฆ They always start with X- if they're unregistered with IANA (private) or X# if they're registered with IANA (public) ๐
For unregistered keys, the vendor gets identified by putting the reversed DNS-name in front of the key-proper. We suggest it, so it's lowkey the move ๐
The part of the key-name that comes after X- and X# MUST conform to the format for key-name specified in Section 5.1 Text Format. No cap, that's the rule ๐
For IANA registered keys, the string after X# must be registered with IANA AND the use of the key MUST be described by an informational RFC ๐
Vendor specific keys MUST ONLY be used in normal sessions ๐ซ Not discovery, bestie!
Support for public or private extension keys is OPTIONAL ๐ธ
13. IANA Considerations โจ
This section conforms to [RFC2434] ๐
The well-known user TCP port number for iSCSI connections assigned by IANA is 3260, and this is the default iSCSI port ๐ Implementations that need a system TCP port number may use port 860, which is the port IANA assigned as the iSCSI system port. However, to use port 860 it MUST be explicitly specified. Implementations MUST NOT default to port 860, because 3260 is the only allowed default ๐
Extension keys, authentication methods, or digest types that a vendor (or a group of vendors) plans to make publicly available descriptions for MUST be described by an RFC and MUST be registered with IANA ๐
The IANA has set up the following three registries ๐๏ธ
- a) iSCSI extended key registry
- b) iSCSI authentication methods registry
- c) iSCSI digests registry
[RFC3723] also tells IANA to keep a registry for the values of the SRP_GROUP key. The format of these values must conform to the one specified for iSCSI extension item-label in Section 13.5.4 Standard iSCSI extension item-label format ๐ง
For the iSCSI authentication methods registry and the iSCSI digests registry, IANA MUST also assign a 16-bit unsigned integer number (the method number for the authentication method and the digest number for the digest) ๐ข
The following initial values for the registry for authentication methods are specified by the standards action of this document โจ
Authentication Method | Number |
+----------------------------------------+--------+
| CHAP | 1 |
+----------------------------------------+--------+
| SRP | 2 |
+----------------------------------------+--------+
| KRB5 | 3 |
+----------------------------------------+--------+
| SPKM1 | 4 |
+----------------------------------------+--------+
| SPKM2 | 5 |
+----------------------------------------+--------+
All other record numbers from 0 to 255 are reserved. IANA will register numbers above 255 ๐
Authentication methods with numbers above 255 MUST be unique within the registry and MUST be used with the prefix Z# ๐
The following initial values for the registry for digests are specified by the standards action of this document ๐ฆ
Digest | Number |
+----------------------------------------+--------+
| CRC32C | 1 |
+----------------------------------------+--------+
All other record numbers from 0 to 255 are reserved. IANA will register numbers above 255 โญ
Digests with numbers above 255 MUST be unique within the registry and MUST be used with the prefix Y# ๐
The RFC that describes the item to be registered MUST indicate in the IANA Considerations section the string and iSCSI registry it should be recorded in ๐
Extension Keys, Authentication Methods, and digests (iSCSI extension items) must conform to a number of requirements, as described below. It's giving checklist ๐
13.1. Naming Requirements
Each iSCSI extension item must have a unique name in its category. This name will be used as a standard-label for the key, access method, or digest, and it must conform to the syntax in Section 13.5.4 Standard iSCSI extension item-label format for iSCSI extension item-labels ๐ท๏ธ
13.2. Mechanism Specification Requirements
For iSCSI extension items, all of the protocols and procedures a given iSCSI extension item uses must be described. That can happen in the item's own specification or in some other publicly available specification ๐ The description has to be detailed enough for any competent implementor to build it ๐ ๏ธ Use of secret and/or proprietary methods in iSCSI extension items is expressly prohibited ๐ โโ๏ธ On top of that, the restrictions that [RFC1602] puts on standardizing patented algorithms must be respected โ๏ธ
13.3. Publication Requirements
All iSCSI extension items must be described by an RFC. The RFC may be informational rather than Standards-Track, although Standards Track review and approval are encouraged for all iSCSI extension items ๐
13.4. Security Requirements
Any known security issues that come from using the iSCSI extension item must be completely and fully described ๐จ It's not required that the iSCSI extension item be secure or free from risks. What matters is that the known risks get identified ๐ซถ Publishing a new iSCSI extension item does not require an exhaustive security review, and the security considerations section is subject to continuing evaluation ๐
Additional security considerations should be addressed by publishing revised versions of the iSCSI extension item specification ๐
For each of these registries, IANA must record the registered string, which MUST conform to the format rules in Section 13.5.4 Standard iSCSI extension item-label format for iSCSI extension item-labels, along with the RFC number that describes it. The key prefix (X#, Y# or Z#) is not part of the recorded string ๐
13.5. Registration Procedure
Registration of a new iSCSI extension item starts with building an Internet Draft to become an RFC โ๏ธ
13.5.1. Present the iSCSI extension item to the Community
Send a proposed access type specification to the IPS WG mailing list. If the IPS WG has been disbanded at registration time, send it to a mailing list the IETF Transport Area Director designates instead, for a review period of a month ๐ฃ The whole point of the public posting is to collect comments and feedback on the iSCSI extension item specification and to review any security considerations ๐
13.5.2. iSCSI extension item review and IESG approval
When the one-month period has passed, the IPS WG chair (or a person the IETF Transport Area Director nominates, the iSCSI extension item reviewer) forwards the Internet Draft to the IESG for publication as an informational RFC, or rejects it ๐ง If the specification is a standards track document, the usual IETF procedures for those get followed โจ
Decisions made by the iSCSI extension item reviewer must be published within two weeks after the month-long review period. Decisions made by the iSCSI extension item reviewer can be appealed through the IESG appeal process โ๏ธ
13.5.3. IANA Registration
As long as the iSCSI extension item has either passed review or been successfully appealed to the IESG, and the specification is published as an RFC, IANA will register the iSCSI extension item and make the registration available to the community ๐ฅณ
13.5.4. Standard iSCSI extension item-label format
The following character symbols are used in iSCSI extension item-labels. The hexadecimal values represent Unicode code points ๐ค
(a-z, A-Z) - letters
(0-9) - digits
"." (0x2e) - dot
"-" (0x2d) - minus
"+" (0x2b) - plus
"@" (0x40) - commercial at
"_" (0x5f) - underscore
An iSCSI extension item-label is a string of one or more characters made up of letters, digits, dot, minus, plus, commercial at, or underscore. An iSCSI extension item-label MUST begin with a capital letter and must not exceed 63 characters ๐
13.6. IANA Procedures for Registering iSCSI extension items
The identity of the iSCSI extension item reviewer is communicated to IANA by the IESG. After that, IANA only acts on iSCSI extension item definitions that the iSCSI extension item reviewer approves and forwards to IANA for registration. IANA also acts when the IESG tells it that an appeal has overturned the iSCSI extension item reviewer's ruling ๐
References
Normative References ๐
Okay bestie, these are the docs this spec literally can't function without, so here's the full list, exactly as it's written ๐ซถ
[CAM] ANSI X3.232-199X, Common Access Method-3.
[EUI] "Guidelines for 64-bit Global Identifier (EUI-64)",
http:
//standards.ieee.org/regauth/oui/tutorials/EUI64.html
[OUI] "IEEE OUI and Company_Id Assignments",
http://standards.ieee.org/regauth/oui
[RFC791] Postel, J., "Internet Protocol", STD 5, RFC 791,
September 1981.
[RFC793] Postel, J., "Transmission Control Protocol", STD 7,
RFC 793, September 1981.
[RFC1035] Mockapetris, P., "Domain Names - Implementation and
Specification", STD 13, RFC 1035, November 1987.
[RFC1122] Braden, R., Ed., "Requirements for Internet Hosts-
Communication Layer", STD 3, RFC 1122, October 1989.
[RFC1510] Kohl, J. and C. Neuman, "The Kerberos Network
Authentication Service (V5)", RFC 1510, September
1993.
[RFC1737] Sollins, K. and L. Masinter "Functional Requirements
for Uniform Resource Names"RFC 1737, December 1994.
[RFC1964] Linn, J., "The Kerberos Version 5 GSS-API Mechanism",
RFC 1964, June 1996.
[RFC1982] Elz, R. and R. Bush, "Serial Number Arithmetic", RFC
1982, August 1996.
[RFC1994] Simpson, W., "PPP Challenge Handshake Authentication
Protocol (CHAP)", RFC 1994, August 1996.
[RFC2025] Adams, C., "The Simple Public-Key GSS-API Mechanism
(SPKM)", RFC 2025, October 1996.
[RFC2045] Borenstein, N. and N. Freed, "MIME (Multipurpose
Internet Mail Extensions) Part One: Mechanisms for
Specifying and Describing the Format of Internet
Message Bodies", RFC 2045, November 1996.
[RFC2119] Bradner, S. "Key Words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC2279] Yergeau, F., "UTF-8, a Transformation Format of ISO
10646", RFC 2279 October 1996.
[RFC2373] Hinden, R. and S. Deering, "IP Version 6 Addressing
Architecture", RFC 2373, July 1998.
[RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter "Uniform
Resource Identifiers", RFC 2396, August 1998.
[RFC2401] Kent, S. and R. Atkinson, "Security Architecture for
the Internet Protocol", RFC 2401, November 1998.
[RFC2404] Madson, C. and R. Glenn, "The Use of HMAC-SHA-1-96
within ESP and AH", RFC 2404, November 1998.
[RFC2406] Kent, S. and R. Atkinson, "IP Encapsulating Security
Payload (ESP)", RFC 2406, November 1998.
[RFC2407] Piper, D., "The Internet IP Security Domain of
Interpretation of ISAKMP", RFC 2407, November 1998.
[RFC2409] Harkins, D. and D. Carrel, "The Internet Key Exchange
(IKE)", RFC2409, November 1998.
[RFC2434] Narten, T. and H. Alvestrand, "Guidelines for Writing
an IANA Considerations Section in RFCs.", BCP 26, RFC
2434, October 1998.
[RFC2451] Pereira, R. and R. Adams " The ESP CBC-Mode Cipher
Algorithms", RFC 2451, November 1998.
[RFC2732] Hinden, R., Carpenter, B. and L. Masinter, "Format for
Literal IPv6 Addresses in URL's", RFC 2451, December
1999.
[RFC2945] Wu, T., "The SRP Authentication and Key Exchange
System", RFC 2945, September 2000.
[RFC3066] Alvestrand, H., "Tags for the Identification of
Languages", STD 47, RFC 3066, January 2001.
[RFC3454] Hoffman, P. and M. Blanchet, "Preparation of
Internationalized Strings ("stringprep")", RFC 3454,
December 2002.
[RFC3566] Frankel, S. and H. Herbert, "The AES-XCBC-MAC-96
Algorithm and Its Use With IPsec", RFC 3566, September
2003.
[RFC3686] Housley, R., "Using Advanced Encryption Standard (AES)
Counter Mode with IPsec Encapsulating Security Payload
(ESP)", RFC 3686, January 2004.
[RFC3722] Bakke, M., "String Profile for Internet Small Computer
Systems Interface (iSCSI) Names", RFC 3722, March
2004.
[RFC3723] Aboba, B., Tseng, J., Walker, J., Rangan, V. and F.
Travostino, "Securing Block Storage Protocols over
IP", RFC 3723, March 2004.
[SAM2] T10/1157D, SCSI Architecture Model - 2 (SAM-2).
[SBC] NCITS.306-1998, SCSI-3 Block Commands (SBC).
[SPC3] T10/1416-D, SCSI Primary Commands-3.
[UNICODE] Unicode Standard Annex #15, "Unicode Normalization
Forms", http://www.unicode.org/unicode/reports/tr15
Informative References ๐ธ
Now the informative ones, which are good background reading but not required to implement ๐
[BOOT] P. Sarkar, et al., "Bootstrapping Clients using the
iSCSI Protocol", Work in Progress, July 2003.
[Castagnoli93] G. Castagnoli, S. Braeuer and M. Herrman "Optimization
of Cyclic Redundancy-Check Codes with 24 and 32 Parity
Bits", IEEE Transact. on Communications, Vol. 41, No.
6, June 1993.
[CORD] Chadalapaka, M. and R. Elliott, "SCSI Command
Ordering Considerations with iSCSI", Work in Progress.
[RFC3347] Krueger, M., Haagens, R., Sapuntzakis, C. and M.
Bakke, "Small Computer Systems Interface protocol over
the Internet (iSCSI) Requirements and Design
Considerations", RFC 3347, July 2002.
[RFC3385] Sheinwald, D., Staran, J., Thaler, P. and V. Cavanna,
"Internet Protocol Small Computer System Interface
(iSCSI) Cyclic Redundancy Check (CRC)/Checksum
Considerations", RFC 3385, September 2002.
[RFC3721] Bakke M., Hafner, J., Hufferd, J., Voruganti, K. and
M. Krueger, "Internet Small Computer Systems Interface
(iSCSI) Naming and Discovery, RFC 3721, March 2004.
[SEQ-EXT] Kent, S., "IP Encapsulating Security Payload (ESP)",
Work in Progress, July 2002.
Appendix A. Sync and Steering with Fixed Interval Markers โจ
Okay so this appendix is giving sync and steering ๐ง It's a simple scheme for synchronization, which is basically finding where each PDU starts. It uses markers carrying synchronization info, dropped at fixed intervals in the TCP stream.
A Marker is made up of the following:
Byte / 0 | 1 | 2 | 3 |
/ | | | |
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+---------------+---------------+---------------+---------------+
0| Next-iSCSI-PDU-start pointer - copy #1 |
+---------------+---------------+---------------+---------------+
4| Next-iSCSI-PDU-start pointer - copy #2 |
+---------------+---------------+---------------+---------------+
The Marker scheme counts bytes in the payload stream, and that count includes every byte iSCSI places in the TCP stream, except the markers themselves ๐ It also skips any bytes TCP counts that iSCSI didn't originate.
Markers MUST NOT be included in digest calculation. ๐
The Marker tells you the offset to the next iSCSI PDU header. It's eight bytes long and has two 32-bit offset fields, each saying how many bytes to skip in the TCP stream to find that next header. It keeps two copies of the pointer so that a marker split across a TCP packet boundary still leaves at least one valid copy in one of the packets. Iconic redundancy behavior ๐
The structure and meaning of an inserted marker don't depend on the marker interval at all.
The use of markers is negotiable. The initiator and target MAY indicate whether they're ready to receive and/or send markers during login, and they do this separately for each connection. The default is No.
A.1. Markers At Fixed Intervals ๐ฆ
A marker gets inserted at fixed intervals in the TCP byte stream. During login, each end of the iSCSI session says what interval it's willing to receive markers at, or it turns markers off completely. If a receiver asks for markers, the sender MAY agree during negotiation and provide markers at the requested interval. Heads up though: in certain environments, a sender that doesn't give markers to a receiver who wants them might take a pretty noticeable performance hit ๐ญ
The marker interval and the initial marker-less interval are both counted in terms of the bytes iSCSI places in the TCP stream data.
When it comes down to iSCSI terms, markers MUST indicate the offset to a 4-byte word boundary in the stream. The two least significant bits of each marker word are reserved and count as 0 for the offset computation. โจ
Padding iSCSI PDU payloads out to 4-byte word boundaries makes marker manipulation way simpler ๐
A.2. Initial Marker-less Interval ๐ง
So, to let the connection setup (including the Login Phase negotiation) go smoothly, marking (if any) only starts at the first marker interval after the Login Phase ends. But here's the twist: so the marker inclusion and exclusion mechanism can work without knowing how long the Login Phase was, the first marker gets placed in the TCP stream as if the Marker-less interval had included markers. Galaxy brain move ๐
That means all markers show up in the stream at locations matching this formula: [(MI + 8) * n - 8], where MI = Marker Interval and n = integer number.
For example, if the marker interval is 512 bytes and the login ended at byte 1003 (first iSCSI placed byte is 0), the first marker will be inserted after byte 1031 in the stream.
A.3. Negotiation ๐
The following operational key=value pairs are used to negotiate the fixed interval markers. The direction (output or input) is relative to the initiator.
A.3.1. OFMarker, IFMarker ๐
Use: IO
Senders: Initiator and Target
Scope: CO
OFMarker=<boolean-value>
IFMarker=<boolean-value>
Default is No. Result function is AND. ๐
OFMarker turns the initiator-to-target markers on or off on the connection. IFMarker turns the target-to-initiator markers on or off on the connection. Here's how it plays out:
Examples:
I->OFMarker=Yes,IFMarker=Yes
T->OFMarker=Yes,IFMarker=Yes
Results in the Marker being used in both directions while:
I->OFMarker=Yes,IFMarker=Yes
T->OFMarker=Yes,IFMarker=No
Results in Marker being used from the initiator to the target, but
not from the target to initiator.
A.3.2. OFMarkInt, IFMarkInt
Use: IO
Senders: Initiator and Target
Scope: CO
OFMarkInt is Irrelevant when: OFMarker=No
IFMarkInt is Irrelevant when: IFMarker=No
Offering:
OFMarkInt=<numeric-range-from-1-to-65535>
IFMarkInt=<numeric-range-from-1-to-65535>
Responding:
OFMarkInt=<numeric-value-from-1-to-65535>|Reject
IFMarkInt=<numeric-value-from-1-to-65535>|Reject
okay so OFMarkInt sets the marker interval for initiator-to-target markers on the connection, and IFMarkInt sets it for target-to-initiator markers ๐
when you're offering, the initiator or target says the minimum and maximum interval it wants (counted in 4-byte words) for one or both directions ๐ง if it only wants one exact value, it just sends that single value โจ the responder then picks something inside the min-to-max range you offered (or the single value you sent), or it says through the xFMarker key=value that it can't set and/or receive markers ๐ if the interval is unacceptable, the responder answers with "Reject" ๐ and Reject basically resets the marker function in that direction (Output or Input) back to No ๐ซถ
the interval gets measured from the end of one marker to the start of the next marker. so a value of 1024 means 1024 words, which is 4096 bytes of iSCSI payload between markers ๐ธ
the default is 2048 ๐
Appendix B. Examples ๐ฆ
B.1. Read Operation Example
+------------------+-----------------------+----------------------+
|Initiator Function| PDU Type | Target Function |
+------------------+-----------------------+----------------------+
| Command request |SCSI Command (READ)>>> | |
| (read) | | |
+------------------+-----------------------+----------------------+
| | |Prepare Data Transfer |
+------------------+-----------------------+----------------------+
| Receive Data | <<< SCSI Data-In | Send Data |
+------------------+-----------------------+----------------------+
| Receive Data | <<< SCSI Data-In | Send Data |
+------------------+-----------------------+----------------------+
| Receive Data | <<< SCSI Data-In | Send Data |
+------------------+-----------------------+----------------------+
| | <<< SCSI Response |Send Status and Sense |
+------------------+-----------------------+----------------------+
| Command Complete | | |
+------------------+-----------------------+----------------------+
B.2. Write Operation Example
+------------------+-----------------------+---------------------+
|Initiator Function| PDU Type | Target Function |
+------------------+-----------------------+---------------------+
| Command request |SCSI Command (WRITE)>>>| Receive command |
| (write) | | and queue it |
+------------------+-----------------------+---------------------+
| | | Process old commands|
+------------------+-----------------------+---------------------+
| | | Ready to process |
| | <<< R2T | WRITE command |
+------------------+-----------------------+---------------------+
| Send Data | SCSI Data-Out >>> | Receive Data |
+------------------+-----------------------+---------------------+
| | <<< R2T | Ready for data |
+------------------+-----------------------+---------------------+
| | <<< R2T | Ready for data |
+------------------+-----------------------+---------------------+
| Send Data | SCSI Data-Out >>> | Receive Data |
+------------------+-----------------------+---------------------+
| Send Data | SCSI Data-Out >>> | Receive Data |
+------------------+-----------------------+---------------------+
| | <<< SCSI Response |Send Status and Sense|
+------------------+-----------------------+---------------------+
| Command Complete | | |
+------------------+-----------------------+---------------------+
B.3. R2TSN/DataSN Use Examples
Output (write) data DataSN/R2TSN Example
+------------------+-----------------------+----------------------+
|Initiator Function| PDU Type & Content | Target Function |
+------------------+-----------------------+----------------------+
| Command request |SCSI Command (WRITE)>>>| Receive command |
| (write) | | and queue it |
+------------------+-----------------------+----------------------+
| | | Process old commands |
+------------------+-----------------------+----------------------+
| | <<< R2T | Ready for data |
| | R2TSN = 0 | |
+------------------+-----------------------+----------------------+
| | <<< R2T | Ready for more data |
| | R2TSN = 1 | |
+------------------+-----------------------+----------------------+
| Send Data | SCSI Data-Out >>> | Receive Data |
| for R2TSN 0 | DataSN = 0, F=0 | |
+------------------+-----------------------+----------------------+
| Send Data | SCSI Data-Out >>> | Receive Data |
| for R2TSN 0 | DataSN = 1, F=1 | |
+------------------+-----------------------+----------------------+
| Send Data | SCSI Data >>> | Receive Data |
| for R2TSN 1 | DataSN = 0, F=1 | |
+------------------+-----------------------+----------------------+
| | <<< SCSI Response |Send Status and Sense |
| | ExpDataSN = 0 | |
+------------------+-----------------------+----------------------+
| Command Complete | | |
+------------------+-----------------------+----------------------+
Input (read) data DataSN Example
+------------------+-----------------------+----------------------+
|Initiator Function| PDU Type | Target Function |
+------------------+-----------------------+----------------------+
| Command request |SCSI Command (READ)>>> | |
| (read) | | |
+------------------+-----------------------+----------------------+
| | | Prepare Data Transfer|
+------------------+-----------------------+----------------------+
| Receive Data | <<< SCSI Data-In | Send Data |
| | DataSN = 0, F=0 | |
+------------------+-----------------------+----------------------+
| Receive Data | <<< SCSI Data-In | Send Data |
| | DataSN = 1, F=0 | |
+------------------+-----------------------+----------------------+
| Receive Data | <<< SCSI Data-In | Send Data |
| | DataSN = 2, F=1 | |
+------------------+-----------------------+----------------------+
| | <<< SCSI Response |Send Status and Sense |
| | ExpDataSN = 3 | |
+------------------+-----------------------+----------------------+
| Command Complete | | |
+------------------+-----------------------+----------------------+
Bidirectional DataSN Example
+------------------+-----------------------+----------------------+
|Initiator Function| PDU Type | Target Function |
+------------------+-----------------------+----------------------+
| Command request |SCSI Command >>> | |
| (Read-Write) | Read-Write | |
+------------------+-----------------------+----------------------+
| | | Process old commands |
+------------------+-----------------------+----------------------+
| | <<< R2T | Ready to process |
| | R2TSN = 0 | WRITE command |
+------------------+-----------------------+----------------------+
| * Receive Data | <<< SCSI Data-In | Send Data |
| | DataSN = 1, F=0 | |
+------------------+-----------------------+----------------------+
| * Receive Data | <<< SCSI Data-In | Send Data |
| | DataSN = 2, F=1 | |
+------------------+-----------------------+----------------------+
| * Send Data | SCSI Data-Out >>> | Receive Data |
| for R2TSN 0 | DataSN = 0, F=1 | |
+------------------+-----------------------+----------------------+
| | <<< SCSI Response |Send Status and Sense |
| | ExpDataSN = 3 | |
+------------------+-----------------------+----------------------+
| Command Complete | | |
+------------------+-----------------------+----------------------+
*) okay so the Send Data and Receive Data can happen at the same time (that's the atomic Read-Old-Write-New vibe) ๐ฅ or they can go one after the other (the atomic Read-Update-Write way), and in that version the R2T can show up after the data you received โจ
Unsolicited and immediate output (write) data with DataSN Example
+------------------+-----------------------+----------------------+
|Initiator Function| PDU Type & Content | Target Function |
+------------------+-----------------------+----------------------+
| Command request |SCSI Command (WRITE)>>>| Receive command |
| (write) |F=0 | and data |
|+ Immediate data | | and queue it |
+------------------+-----------------------+----------------------+
| Send Unsolicited | SCSI Write Data >>> | Receive more Data |
| Data | DataSN = 0, F=1 | |
+------------------+-----------------------+----------------------+
| | | Process old commands |
+------------------+-----------------------+----------------------+
| | <<< R2T | Ready for more data |
| | R2TSN = 0 | |
+------------------+-----------------------+----------------------+
| Send Data | SCSI Write Data >>> | Receive Data |
| for R2TSN 0 | DataSN = 0, F=1 | |
+------------------+-----------------------+----------------------+
| | <<< SCSI Response |Send Status and Sense |
| | | |
+------------------+-----------------------+----------------------+
| Command Complete | | |
+------------------+-----------------------+----------------------+
B.4. CRC Examples โจ
okay bestie, time for the CRC examples ๐งฎ๐ N.B. all Values are Hexadecimal ๐ธ so every number below is base 16, obvi!
first up: 32 bytes of zeroes ๐ซถ
Byte: 0 1 2 3
0: 00 00 00 00
...
28: 00 00 00 00
CRC: aa 36 91 8a
next, 32 bytes of ones ๐ฅ
Byte: 0 1 2 3
0: ff ff ff ff
...
28: ff ff ff ff
CRC: 43 ab a8 62
now the 32 bytes of incrementing 00..1f ๐ it's giving counting up, and the CRC is different for each one ๐ญ
Byte: 0 1 2 3
0: 00 01 02 03
...
28: 1c 1d 1e 1f
CRC: 4e 79 dd 46
and the mirror version, 32 bytes of decrementing 1f..00 ๐ฆ counting down, same bytes, totally different CRC, iykyk
Byte: 0 1 2 3
0: 1f 1e 1d 1c
...
28: 03 02 01 00
CRC: 5c db 3f 11
last but not least, a real one: An iSCSI - SCSI Read (10) Command PDU ๐ this is the main character example, so pay attention ๐
Byte: 0 1 2 3
0: 01 c0 00 00
4: 00 00 00 00
8: 00 00 00 00
12: 00 00 00 00
16: 14 00 00 00
20: 00 00 04 00
24: 00 00 00 14
28: 00 00 00 18
32: 28 00 00 00
36: 00 00 00 00
40: 02 00 00 00
44: 00 00 00 00
CRC: 56 3a 96 d9
Appendix C. Login Phase Examples โจ
okay so this appendix is basically a showcase of every way two devices can log in to each other, and the whole thing is about who proves they are who they say they are ๐๐ we'll go one method at a time.
Kerberos, both ways ๐ The initiator and target authenticate each other via Kerberos. This one is super thorough, bestie.
I-> Login (CSG,NSG=0,1 T=1)
InitiatorName=iqn.1999-07.com.os:hostid.77
TargetName=iqn.1999-07.com.example:diskarray.sn.88
AuthMethod=KRB5,SRP,None
T-> Login (CSG,NSG=0,0 T=0)
AuthMethod=KRB5
I-> Login (CSG,NSG=0,1 T=1)
KRB_AP_REQ=<krb_ap_req>
(krb_ap_req contains the Kerberos V5 ticket and authenticator
with MUTUAL-REQUIRED set in the ap-options field)
If the authentication is successful, the target proceeds with:
T-> Login (CSG,NSG=0,1 T=1)
KRB_AP_REP=<krb_ap_rep>
(krb_ap_rep is the Kerberos V5 mutual authentication reply)
If the authentication is successful, the initiator may proceed with:
I-> Login (CSG,NSG=1,0 T=0) FirstBurstLength=8192
T-> Login (CSG,NSG=1,0 T=0) FirstBurstLength=4096
MaxBurstLength=8192
I-> Login (CSG,NSG=1,0 T=0) MaxBurstLength=8192
... more iSCSI Operational Parameters
T-> Login (CSG,NSG=1,0 T=0)
... more iSCSI Operational Parameters
And at the end:
I-> Login (CSG,NSG=1,3 T=1)
optional iSCSI parameters
T-> Login (CSG,NSG=1,3 T=1) "login accept"
If the initiator's authentication by the target is not successful, the target responds with:
T-> Login "login reject"
instead of the Login KRB_AP_REP message, and terminates the connection.
If the target's authentication by the initiator is not successful, the initiator terminates the connection (without responding to the Login KRB_AP_REP message).
Kerberos, one way ๐ฆ In this one, only the initiator is authenticated by the target via Kerberos. Less back-and-forth, same vibes.
I-> Login (CSG,NSG=0,1 T=1)
InitiatorName=iqn.1999-07.com.os:hostid.77
TargetName=iqn.1999-07.com.example:diskarray.sn.88
AuthMethod=SRP,KRB5,None
T-> Login-PR (CSG,NSG=0,0 T=0)
AuthMethod=KRB5
I-> Login (CSG,NSG=0,1 T=1)
KRB_AP_REQ=krb_ap_req
(MUTUAL-REQUIRED not set in the ap-options field of krb_ap_req)
If the authentication is successful, the target proceeds with:
T-> Login (CSG,NSG=0,1 T=1)
I-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
T-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
. . .
T-> Login (CSG,NSG=1,3 T=1)"login accept"
SPKM1 ๐ธ Here the initiator and target authenticate each other via SPKM1, and it's giving very structured token energy.
I-> Login (CSG,NSG=0,1 T=1)
InitiatorName=iqn.1999-07.com.os:hostid.77
TargetName=iqn.1999-07.com.example:diskarray.sn.88
AuthMethod=SPKM1,KRB5,None
T-> Login (CSG,NSG=0,0 T=0)
AuthMethod=SPKM1
I-> Login (CSG,NSG=0,0 T=0)
SPKM_REQ=<spkm-req>
(spkm-req is the SPKM-REQ token with the mutual-state bit in the
options field of the REQ-TOKEN set)
T-> Login (CSG,NSG=0,0 T=0)
SPKM_REP_TI=<spkm-rep-ti>
If the authentication is successful, the initiator proceeds:
I-> Login (CSG,NSG=0,1 T=1)
SPKM_REP_IT=<spkm-rep-it>
If the authentication is successful, the target proceeds with:
T-> Login (CSG,NSG=0,1 T=1)
The initiator may proceed:
I-> Login (CSG,NSG=1,0 T=0) ... iSCSI parameters
T-> Login (CSG,NSG=1,0 T=0) ... iSCSI parameters
And at the end:
I-> Login (CSG,NSG=1,3 T=1)
optional iSCSI parameters
T-> Login (CSG,NSG=1,3 T=1) "login accept"
If the target's authentication by the initiator is not successful, the initiator terminates the connection (without responding to the Login SPKM_REP_TI message).
If the initiator's authentication by the target is not successful, the target responds with:
T-> Login "login reject"
instead of the Login "proceed and change stage" message, and terminates the connection.
SPKM2 ๐ Next up, the initiator and target authenticate each other via SPKM2. Same squad, slightly different moves.
I-> Login (CSG,NSG=0,0 T=0)
InitiatorName=iqn.1999-07.com.os:hostid.77
TargetName=iqn.1999-07.com.example:diskarray.sn.88
AuthMethod=SPKM1,SPKM2
T-> Login-PR (CSG,NSG=0,0 T=0)
AuthMethod=SPKM2
I-> Login (CSG,NSG=0,1 T=1)
SPKM_REQ=<spkm-req>
(spkm-req is the SPKM-REQ token with the mutual-state bit in the
options field of the REQ-TOKEN not set)
If the authentication is successful, the target proceeds with:
T-> Login (CSG,NSG=0,1 T=1)
The initiator may proceed:
I-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
T-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
And at the end:
I-> Login (CSG,NSG=1,3 T=1)
optional iSCSI parameters
T-> Login (CSG,NSG=1,3 T=1) "login accept"
SRP, full mutual vibes ๐ฅ In this example the initiator and target authenticate each other via SRP. The target gets verified too, because TargetAuth=Yes is on the table.
I-> Login (CSG,NSG=0,1 T=1)
InitiatorName=iqn.1999-07.com.os:hostid.77
TargetName=iqn.1999-07.com.example:diskarray.sn.88
AuthMethod=KRB5,SRP,None
T-> Login-PR (CSG,NSG=0,0 T=0)
AuthMethod=SRP
I-> Login (CSG,NSG=0,0 T=0)
SRP_U=<user>
TargetAuth=Yes
T-> Login (CSG,NSG=0,0 T=0)
SRP_GROUP=SRP-1536,SRP-1024
SRP_s=<s>
I-> Login (CSG,NSG=0,0 T=0)
SRP_GROUP=SRP-1536
SRP_A=<A>
T-> Login (CSG,NSG=0,0 T=0)
SRP_B=<B>
I-> Login (CSG,NSG=0,1 T=1)
SRP_M=<M>
If the initiator authentication is successful, the target proceeds:
T-> Login (CSG,NSG=0,1 T=1)
SRP_HM=<H(A | M | K)>
Where N, g, s, A, B, M, and H(A | M | K) are defined in [RFC2945].
If the target authentication is not successful, the initiator terminates the connection; otherwise, it proceeds.
I-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
T-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
And at the end:
I-> Login (CSG,NSG=1,3 T=1)
optional iSCSI parameters
T-> Login (CSG,NSG=1,3 T=1) "login accept"
If the initiator authentication is not successful, the target responds with:
T-> Login "login reject"
Instead of the T-> Login SRP_HM=<H(A | M | K)> message, it terminates the connection.
SRP, target not checked ๐ Another SRP exchange, but this time TargetAuth=No, so the target skips the extra verification step.
I-> Login (CSG,NSG=0,1 T=1)
InitiatorName=iqn.1999-07.com.os:hostid.77
TargetName=iqn.1999-07.com.example:diskarray.sn.88
AuthMethod=KRB5,SRP,None
T-> Login-PR (CSG,NSG=0,0 T=0)
AuthMethod=SRP
I-> Login (CSG,NSG=0,0 T=0)
SRP_U=<user>
TargetAuth=No
T-> Login (CSG,NSG=0,0 T=0)
SRP_GROUP=SRP-1536
SRP_s=<s>
I-> Login (CSG,NSG=0,0 T=0)
SRP_GROUP=SRP-1536
SRP_A=<A>
T-> Login (CSG,NSG=0,0 T=0)
SRP_B=<B>
I-> Login (CSG,NSG=0,1 T=1)
SRP_M=<M>
If the initiator authentication is successful, the target proceeds:
T-> Login (CSG,NSG=0,1 T=1)
I-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
T-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
And at the end:
I-> Login (CSG,NSG=1,3 T=1)
optional iSCSI parameters
T-> Login (CSG,NSG=1,3 T=1) "login accept"
CHAP, mutual ๐ In the next example the initiator and target authenticate each other via CHAP. Lots of little challenge-and-response moments here.
I-> Login (CSG,NSG=0,0 T=0)
InitiatorName=iqn.1999-07.com.os:hostid.77
TargetName=iqn.1999-07.com.example:diskarray.sn.88
AuthMethod=KRB5,CHAP,None
T-> Login-PR (CSG,NSG=0,0 T=0)
AuthMethod=CHAP
I-> Login (CSG,NSG=0,0 T=0)
CHAP_A=<A1,A2>
T-> Login (CSG,NSG=0,0 T=0)
CHAP_A=<A1>
CHAP_I=<I>
CHAP_C=<C>
I-> Login (CSG,NSG=0,1 T=1)
CHAP_N=<N>
CHAP_R=<R>
CHAP_I=<I>
CHAP_C=<C>
If the initiator authentication is successful, the target proceeds:
T-> Login (CSG,NSG=0,1 T=1)
CHAP_N=<N>
CHAP_R=<R>
If the target authentication is not successful, the initiator aborts the connection; otherwise, it proceeds.
I-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
T-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
And at the end:
I-> Login (CSG,NSG=1,3 T=1)
optional iSCSI parameters
T-> Login (CSG,NSG=1,3 T=1) "login accept"
If the initiator authentication is not successful, the target responds with:
T-> Login "login reject"
Instead of the Login CHAP_R=<response> "proceed and change stage" message, it terminates the connection.
CHAP, one way ๐ฆ In the next example, only the initiator is authenticated by the target via CHAP.
I-> Login (CSG,NSG=0,1 T=0)
InitiatorName=iqn.1999-07.com.os:hostid.77
TargetName=iqn.1999-07.com.example:diskarray.sn.88
AuthMethod=KRB5,CHAP,None
T-> Login-PR (CSG,NSG=0,0 T=0)
AuthMethod=CHAP
I-> Login (CSG,NSG=0,0 T=0)
CHAP_A=<A1,A2>
T-> Login (CSG,NSG=0,0 T=0)
CHAP_A=<A1>
CHAP_I=<I>
CHAP_C=<C>
I-> Login (CSG,NSG=0,1 T=1)
CHAP_N=<N>
CHAP_R=<R>
If the initiator authentication is successful, the target proceeds:
T-> Login (CSG,NSG=0,1 T=1)
I-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
T-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
And at the end:
I-> Login (CSG,NSG=1,3 T=1)
optional iSCSI parameters
T-> Login (CSG,NSG=1,3 T=1) "login accept"
No security, straight to the good stuff ๐ In the next example, the initiator does not offer any security parameters. It therefore may offer iSCSI parameters on the Login PDU with the T bit set to 1, and the target may respond with a final Login Response PDU immediately.
I-> Login (CSG,NSG=1,3 T=1)
InitiatorName=iqn.1999-07.com.os:hostid.77
TargetName=iqn.1999-07.com.example:diskarray.sn.88
... iSCSI parameters
T-> Login (CSG,NSG=1,3 T=1) "login accept"
... ISCSI parameters
Security offered, but "None" chosen ๐ง In the last example, the initiator does offer security parameters on the Login PDU, but the target does not choose any (i.e., chooses the "None" values).
I-> Login (CSG,NSG=0,1 T=1)
InitiatorName=iqn.1999-07.com.os:hostid.77
TargetName=iqn.1999-07.com.example:diskarray.sn.88
AuthMethod=KRB5,SRP,None
T-> Login-PR (CSG,NSG=0,1 T=1)
AuthMethod=None
I-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
T-> Login (CSG,NSG=1,0 T=0)
... iSCSI parameters
And at the end:
I-> Login (CSG,NSG=1,3 T=1)
optional iSCSI parameters
T-> Login (CSG,NSG=1,3 T=1) "login accept"
Appendix D. SendTargets Operation ๐ง
Okay bestie, so to cut down on how much config an initiator has to do by hand, iSCSI gives us the SendTargets text request ๐ The initiator uses it to ask for a list of targets it might have access to, plus the addresses (IP address and TCP port) where those targets can be reached ๐ฆ
To use SendTargets, the initiator has to set up one of two session types first ๐ If it establishes the session with the key SessionType=Discovery, that's a discovery session and you don't have to name a target. Otherwise it's a normal, operational session. The SendTargets command MUST only be sent during the Full Feature Phase of a normal or discovery session ๐ฅ
A system that has targets MUST support discovery sessions on each of its iSCSI IP address-port pairs, and it MUST support the SendTargets command on the discovery session. In a discovery session, a target MUST return all path information (target name and IP address-port pairs and portal group tags) for the targets on the target network entity that the requesting initiator is authorized to access. Main character energy ๐
A target MUST support the SendTargets command on operational sessions. These only return path information about the target the session is connected to, and they don't need to return info about other target names that might be defined in the responding system ๐ธ
An initiator MAY make use of SendTargets as it sees fit โจ
A SendTargets command is a single Text request PDU. This PDU contains exactly one text key and value. The text key MUST be SendTargets. The expected response depends on the value, and also on whether the session is a discovery or operational one ๐ง
The value must be one of:
All: The initiator is asking for info on all relevant targets the implementation knows about. This value MUST be supported on a discovery session, and MUST NOT be supported on an operational session.<iSCSI-target-name>: If an iSCSI target name is specified, the session should respond with addresses for only the named target, if possible. This value MUST be supported on discovery sessions. A discovery session MUST be capable of returning addresses for those targets that would have been returned had value=All been designated.<nothing>: The session should only respond with addresses for the target it's logged in to. This MUST be supported on operational sessions, and MUST NOT return targets other than the one the session is logged in to.
The response is a text response with zero or more targets and, optionally, their addresses. Each target comes back as a target record. A target record starts with the TargetName text key, followed by a list of TargetAddress text keys, and it's bounded by the end of the text response or the next TargetName key, which starts a new record. No text keys other than TargetName and TargetAddress are permitted within a SendTargets response ๐
For the format of the TargetName, see Section 12.4 TargetName.
In a discovery session, a target MAY respond to a SendTargets request with its complete list of targets, or with a list of targets based on the name of the initiator logged in to the session ๐
A SendTargets response MUST NOT contain target names if there are no targets for the requesting initiator to access ๐
Each target record returned includes zero or more TargetAddress fields ๐
Each target record starts with one text key of the form:
TargetName=<target-name-goes-here>
Followed by zero or more address keys of the form:
TargetAddress=<hostname-or-ipaddress>[:<tcp-port>],
<portal-group-tag>
The hostname-or-ipaddress holds a domain name, IPv4 address, or IPv6 address, as specified for the TargetAddress key.
A hostname-or-ipaddress that shows up duplicated in TargetAddress responses for a given node (the port is absent or equal) would probably mean that multiple address families are in use at once (IPV6 and IPV4). Two families, one node, very efficient ๐ฆ
Each TargetAddress belongs to a portal group, identified by its numeric portal group tag (as in Section 12.9 TargetPortalGroupTag). The iSCSI target name, together with this tag, makes up the SCSI port identifier. The tag only needs to be unique within a given target's name list of addresses ๐
Multiple-connection sessions can span iSCSI addresses that belong to the same portal group.
Multiple-connection sessions cannot span iSCSI addresses that belong to different portal groups.
If a SendTargets response reports an iSCSI address for a target, it SHOULD also report all other addresses in its portal group in the same response ๐ซถ
A SendTargets text response can be longer than a single Text Response PDU, and it makes use of the long text responses as specified ๐
After getting a list of targets from the discovery target session, an iSCSI initiator may start new sessions to log in to the discovered targets for full operation. The initiator MAY keep the discovery session open, and MAY send subsequent SendTargets commands to discover new targets ๐
Examples:
This example is the SendTargets response from a single target that has no other interface ports.
Initiator sends a text request that contains:
SendTargets=All
Target sends a text response that contains:
TargetName=iqn.1993-11.com.example:diskarray.sn.8675309
All the target had to return in the simple case was the target name. The initiator assumes that the IP address and TCP port for this target are the same as the ones used on the current connection to the default iSCSI target ๐
The next example has two internal iSCSI targets, each accessible via two different ports with different IP addresses. The following is the text response:
TargetName=iqn.1993-11.com.example:diskarray.sn.8675309
TargetAddress=10.1.0.45:3000,1 TargetAddress=10.1.1.45:3000,2
TargetName=iqn.1993-11.com.example:diskarray.sn.1234567
TargetAddress=10.1.0.45:3000,1 TargetAddress=10.1.1.45:3000,2
Both targets share both addresses, and the multiple addresses are likely used to provide multi-path support. The initiator may connect to either target name on either address. Each of the addresses has its own portal group tag, and they do not support spanning multiple-connection sessions with each other. Keep in mind that the portal group tags for the two named targets are independent of one another. Portal group "1" on the first target is not necessarily the same as portal group "1" on the second target. Don't mix them up, bestie ๐
In the above example, a DNS host name or an IPv6 address could have been returned instead of an IPv4 address ๐ง
The next text response shows a target that supports spanning sessions across multiple addresses, and it further illustrates the use of portal group tags:
TargetName=iqn.1993-11.com.example:diskarray.sn.8675309
TargetAddress=10.1.0.45:3000,1 TargetAddress=10.1.1.46:3000,1
TargetAddress=10.1.0.47:3000,2 TargetAddress=10.1.1.48:3000,2
TargetAddress=10.1.1.49:3000,3
In this example, any of the target addresses can be used to reach the same target. A single-connection session can be established to any of these TCP addresses. A multiple-connection session could span addresses .45 and .46 or .47 and .48, but it cannot span any other combination. A TargetAddress with its own tag (.49) cannot be combined with any other address within the same session ๐ฆ
This SendTargets response does not indicate whether .49 supports multiple connections per session. That is communicated via the MaxConnections text key upon login to the target ๐ธ
Appendix E. Algorithmic Presentation of Error Recovery Classes โจ
This appendix illustrates the error recovery classes using a pseudo-programming-language. The procedure names are chosen to be obvious to most implementers. Each of the recovery classes described has initiator procedures as well as target procedures. These algorithms focus on outlining the mechanics of error recovery classes, and they don't exhaustively describe all other aspects or cases. Examples of this approach are:
- Handling for only certain Opcode types is shown.
- Only certain reason codes (e.g., Recovery in Logout command) are outlined.
- Resultant cases, such as recovery of Synchronization on a header digest error, are considered out-of-scope in these algorithms. In this particular example, a header digest error may lead to connection recovery if some type of sync and steering layer is not implemented.
These algorithms try to convey the iSCSI error recovery concepts in the simplest terms, and they are not designed to be optimal ๐
E.1. General Data Structure and Procedure Description
This section defines the procedures and data structures that are commonly used by all the error recovery algorithms. The structures may not be the exhaustive representations of what a typical implementation requires ๐
Data structure definitions:
struct TransferContext {
int TargetTransferTag;
int ExpectedDataSN;
};
struct TCB { /* task control block */
Boolean SoFarInOrder;
int ExpectedDataSN; /* used for both R2Ts, and Data */
int MissingDataSNList[MaxMissingDPDU];
Boolean FbitReceived;
Boolean StatusXferd;
Boolean CurrentlyAllegiant;
int ActiveR2Ts;
int Response;
char *Reason;
struct TransferContext
TransferContextList[MaxOutStandingR2T];
int InitiatorTaskTag;
int CmdSN;
int SNACK_Tag;
};
struct Connection {
struct Session SessionReference;
Boolean SoFarInOrder;
int CID;
int State;
int CurrentTimeout;
int ExpectedStatSN;
int MissingStatSNList[MaxMissingSPDU];
Boolean PerformConnectionCleanup;
};
struct Session {
int NumConnections;
int CmdSN;
int Maxconnections;
int ErrorRecoveryLevel;
struct iSCSIEndpoint OtherEndInfo;
struct Connection ConnectionList[MaxSupportedConns];
};
Procedure descriptions:
Receive-a-In-PDU(transport connection, inbound PDU);
check-basic-validity(inbound PDU);
Start-Timer(timeout handler, argument, timeout value);
Build-And-Send-Reject(transport connection, bad PDU, reason code);
E.2. Within-command Error Recovery Algorithms
E.2.1. Procedure Descriptions
Okay so this is the part where the target and initiator procedures get their names, and bestie, I'm obsessed ๐ง. Here's the full lineup of procedure descriptions, no cap:
Recover-Data-if-Possible(last required DataSN, task control
block);
Build-And-Send-DSnack(task control block);
Build-And-Send-RDSnack(task control block);
Build-And-Send-Abort(task control block);
SCSI-Task-Completion(task control block);
Build-And-Send-A-Data-Burst(transport connection, data-descriptor,
task control block);
Build-And-Send-R2T(transport connection, data-descriptor,
task control block);
Build-And-Send-Status(transport connection, task control block);
Transfer-Context-Timeout-Handler(transfer context);
Notes:
- One procedure used in this section: Handle-Status-SNACK-request is defined in Within-connection recovery algorithms. ๐
- The Response processing pseudo-code, shown in the target algorithms, applies to all solicited PDUs that carry StatSN - SCSI Response, Text Response etc. ๐
E.2.2. Initiator Algorithms โจ
Bestie, this is where the initiator figures out what's missing and asks for it back ๐ซถ.
Recover-Data-if-Possible(LastRequiredDataSN, TCB)
{
if (operational ErrorRecoveryLevel > 0) {
if (# of missing PDUs is trackable) {
Note the missing DataSNs in TCB.
if (the task spanned a change in
MaxRecvDataSegmentLength) {
if (TCB.StatusXferd is TRUE)
drop the status PDU;
Build-And-Send-RDSnack(TCB);
} else {
Build-And-Send-DSnack(TCB);
}
} else {
TCB.Reason = "Protocol service CRC error";
}
} else {
TCB.Reason = "Protocol service CRC error";
}
if (TCB.Reason == "Protocol service CRC error") {
Clear the missing PDU list in the TCB.
if (TCB.StatusXferd is not TRUE)
Build-And-Send-Abort(TCB);
}
}
Receive-a-In-PDU(Connection, CurrentPDU)
{
check-basic-validity(CurrentPDU);
if (Header-Digest-Bad) discard, return;
Retrieve TCB for CurrentPDU.InitiatorTaskTag.
if ((CurrentPDU.type == Data)
or (CurrentPDU.type = R2T)) {
if (Data-Digest-Bad for Data) {
send-data-SNACK = TRUE;
LastRequiredDataSN = CurrentPDU.DataSN;
} else {
if (TCB.SoFarInOrder = TRUE) {
if (current DataSN is expected) {
Increment TCB.ExpectedDataSN.
} else {
TCB.SoFarInOrder = FALSE;
send-data-SNACK = TRUE;
}
} else {
if (current DataSN was considered missing) {
remove current DataSN from missing PDU list.
} else if (current DataSN is higher than expected)
{
send-data-SNACK = TRUE;
} else {
discard, return;
}
Adjust TCB.ExpectedDataSN if appropriate.
}
LastRequiredDataSN = CurrentPDU.DataSN - 1;
}
if (send-data-SNACK is TRUE and
task is not already considered failed) {
Recover-Data-if-Possible(LastRequiredDataSN, TCB);
}
if (missing data PDU list is empty) {
TCB.SoFarInOrder = TRUE;
}
if (CurrentPDU.type == R2T) {
Increment ActiveR2Ts for this task.
Create a data-descriptor for the data burst.
Build-And-Send-A-Data-Burst(Connection, data-descriptor,
TCB);
}
} else if (CurrentPDU.type == Response) {
if (Data-Digest-Bad) {
send-status-SNACK = TRUE;
} else {
TCB.StatusXferd = TRUE;
Store the status information in TCB.
if (ExpDataSN does not match) {
TCB.SoFarInOrder = FALSE;
Recover-Data-if-Possible(current DataSN, TCB);
}
if (missing data PDU list is empty) {
TCB.SoFarInOrder = TRUE;
}
}
} else { /* REST UNRELATED TO WITHIN-COMMAND-RECOVERY, NOT
SHOWN */
}
if ((TCB.SoFarInOrder == TRUE) and
(TCB.StatusXferd == TRUE)) {
SCSI-Task-Completion(TCB);
}
}
E.2.3. Target Algorithms โจ
And now the target side, where it's all about spotting gaps in the data and sending R2Ts to fill them, periodt ๐ฆ.
Receive-a-In-PDU(Connection, CurrentPDU)
{
check-basic-validity(CurrentPDU);
if (Header-Digest-Bad) discard, return;
Retrieve TCB for CurrentPDU.InitiatorTaskTag.
if (CurrentPDU.type == Data) {
Retrieve TContext from CurrentPDU.TargetTransferTag;
if (Data-Digest-Bad) {
Build-And-Send-Reject(Connection, CurrentPDU,
Payload-Digest-Error);
Note the missing data PDUs in MissingDataRange[].
send-recovery-R2T = TRUE;
} else {
if (current DataSN is not expected) {
Note the missing data PDUs in MissingDataRange[].
send-recovery-R2T = TRUE;
}
if (CurrentPDU.Fbit == TRUE) {
if (current PDU is solicited) {
Decrement TCB.ActiveR2Ts.
}
if ((current PDU is unsolicited and
data received is less than I/O length and
data received is less than FirstBurstLength)
or (current PDU is solicited and the length of
this burst is less than expected)) {
send-recovery-R2T = TRUE;
Note the missing data in MissingDataRange[].
}
}
}
Increment TContext.ExpectedDataSN.
if (send-recovery-R2T is TRUE and
task is not already considered failed) {
if (operational ErrorRecoveryLevel > 0) {
Increment TCB.ActiveR2Ts.
Create a data-descriptor for the data burst
from MissingDataRange.
Build-And-Send-R2T(Connection, data-descriptor, TCB);
} else {
if (current PDU is the last unsolicited)
TCB.Reason = "Not enough unsolicited data";
else
TCB.Reason = "Protocol service CRC error";
}
}
if (TCB.ActiveR2Ts == 0) {
Build-And-Send-Status(Connection, TCB);
}
} else if (CurrentPDU.type == SNACK) {
snack-failure = FALSE;
if (operational ErrorRecoveryLevel > 0) {
if (CurrentPDU.type == Data/R2T) {
if (the request is satisfiable) {
if (request for Data) {
Create a data-descriptor for the data burst
from BegRun and RunLength.
Build-And-Send-A-Data-Burst(Connection,
data-descriptor, TCB);
} else { /* R2T */
Create a data-descriptor for the data burst
from BegRun and RunLength.
Build-And-Send-R2T(Connection, data-descriptor,
TCB);
}
} else {
snack-failure = TRUE;
}
} else if (CurrentPDU.type == status) {
Handle-Status-SNACK-request(Connection, CurrentPDU);
} else if (CurrentPDU.type == DataACK) {
Consider all data upto CurrentPDU.BegRun as
acknowledged.
Free up the retransmission resources for that data.
} else if (CurrentPDU.type == R-Data SNACK) {
Create a data descriptor for a data burst covering
all unacknowledged data.
Build-And-Send-A-Data-Burst(Connection,
data-descriptor, TCB);
TCB.SNACK_Tag = CurrentPDU.SNACK_Tag;
if (there's no more data to send) {
Build-And-Send-Status(Connection, TCB);
}
}
} else { /* operational ErrorRecoveryLevel = 0 */
snack-failure = TRUE;
}
if (snack-failure == TRUE) {
Build-And-Send-Reject(Connection, CurrentPDU,
SNACK-Reject);
if (TCB.StatusXferd != TRUE) {
TCB.Reason = "SNACK Rejected";
Build-And-Send-Status(Connection, TCB);
}
}
} else { /* REST UNRELATED TO WITHIN-COMMAND-RECOVERY, NOT SHOWN */
}
}
Transfer-Context-Timeout-Handler(TContext)
{
Retrieve TCB and Connection from TContext.
Decrement TCB.ActiveR2Ts.
if (operational ErrorRecoveryLevel > 0 and
task is not already considered failed) {
Note the missing data PDUs in MissingDataRange[].
Create a data-descriptor for the data burst
from MissingDataRange[].
Build-And-Send-R2T(Connection, data-descriptor, TCB);
} else {
TCB.Reason = "Protocol service CRC error";
if (TCB.ActiveR2Ts = 0) {
Build-And-Send-Status(Connection, TCB);
}
}
}
E.3. Within-connection Recovery Algorithms โจ
Okay, now we're zooming out to recovery within the whole connection, not just one command. Main character energy ๐.
E.3.1. Procedure Descriptions
Procedure descriptions:
Recover-Status-if-Possible(transport connection,
currently received PDU);
Evaluate-a-StatSN(transport connection, currently received PDU);
Retransmit-Command-if-Possible(transport connection, CmdSN);
Build-And-Send-SSnack(transport connection);
Build-And-Send-Command(transport connection, task control block);
Command-Acknowledge-Timeout-Handler(task control block);
Status-Expect-Timeout-Handler(transport connection);
Build-And-Send-Nop-Out(transport connection);
Handle-Status-SNACK-request(transport connection, status SNACK
PDU);
Retransmit-Status-Burst(status SNACK, task control block);
Is-Acknowledged(beginning StatSN, run length);
Implementation-specific tunables:
InitiatorProactiveSNACKEnabled
Notes:
- The initiator algorithms only deal with unsolicited Nop-In PDUs for generating status SNACKs. A solicited Nop-In PDU has an assigned StatSN, which, when out of order, could trigger the out of order StatSN handling in Within-command algorithms, again leading to Recover-Status-if-Possible. ๐ธ
- The pseudo-code shown may result in the retransmission of unacknowledged commands in more cases than necessary. This will not, however, affect the correctness of the operation because the target is required to discard the duplicate CmdSNs. ๐
- The procedure Build-And-Send-Async is defined in the Connection recovery algorithms. ๐
- The procedure Status-Expect-Timeout-Handler describes how initiators may proactively attempt to retrieve the Status if they so choose. This procedure is assumed to be triggered much before the standard ULP timeout. ๐ง
E.3.2. Initiator Algorithms
Bestie, the initiator is the one chasing down missing StatSNs here ๐.
Recover-Status-if-Possible(Connection, CurrentPDU)
{
if ((Connection.state == LOGGED_IN) and
connection is not already considered failed) {
if (operational ErrorRecoveryLevel > 0) {
if (# of missing PDUs is trackable) {
Note the missing StatSNs in Connection
that were not already requested with SNACK;
Build-And-Send-SSnack(Connection);
} else {
Connection.PerformConnectionCleanup = TRUE;
}
} else {
Connection.PerformConnectionCleanup = TRUE;
}
if (Connection.PerformConnectionCleanup == TRUE) {
Start-Timer(Connection-Cleanup-Handler, Connection, 0);
}
}
}
Retransmit-Command-if-Possible(Connection, CmdSN)
{
if (operational ErrorRecoveryLevel > 0) {
Retrieve the InitiatorTaskTag, and thus TCB for the CmdSN.
Build-And-Send-Command(Connection, TCB);
}
}
Evaluate-a-StatSN(Connection, CurrentPDU)
{
send-status-SNACK = FALSE;
if (Connection.SoFarInOrder == TRUE) {
if (current StatSN is the expected) {
Increment Connection.ExpectedStatSN.
} else {
Connection.SoFarInOrder = FALSE;
send-status-SNACK = TRUE;
}
} else {
if (current StatSN was considered missing) {
remove current StatSN from the missing list.
} else {
if (current StatSN is higher than expected){
send-status-SNACK = TRUE;
} else {
send-status-SNACK = FALSE;
discard the PDU;
}
}
Adjust Connection.ExpectedStatSN if appropriate.
if (missing StatSN list is empty) {
Connection.SoFarInOrder = TRUE;
}
}
return send-status-SNACK;
}
Receive-a-In-PDU(Connection, CurrentPDU)
{
check-basic-validity(CurrentPDU);
if (Header-Digest-Bad) discard, return;
Retrieve TCB for CurrentPDU.InitiatorTaskTag.
if (CurrentPDU.type == Nop-In) {
if (the PDU is unsolicited) {
if (current StatSN is not expected) {
Recover-Status-if-Possible(Connection,
CurrentPDU);
}
if (current ExpCmdSN is not Session.CmdSN) {
Retransmit-Command-if-Possible(Connection,
CurrentPDU.ExpCmdSN);
}
}
} else if (CurrentPDU.type == Reject) {
if (it is a data digest error on immediate data) {
Retransmit-Command-if-Possible(Connection,
CurrentPDU.BadPDUHeader.CmdSN);
}
} else if (CurrentPDU.type == Response) {
send-status-SNACK = Evaluate-a-StatSN(Connection,
CurrentPDU);
if (send-status-SNACK == TRUE)
Recover-Status-if-Possible(Connection, CurrentPDU);
} else { /* REST UNRELATED TO WITHIN-CONNECTION-RECOVERY,
* NOT SHOWN */
}
}
Command-Acknowledge-Timeout-Handler(TCB)
{
Retrieve the Connection for TCB.
Retransmit-Command-if-Possible(Connection, TCB.CmdSN);
}
Status-Expect-Timeout-Handler(Connection)
{
if (operational ErrorRecoveryLevel > 0) {
Build-And-Send-Nop-Out(Connection);
} else if (InitiatorProactiveSNACKEnabled){
if ((Connection.state == LOGGED_IN) and
connection is not already considered failed) {
Build-And-Send-SSnack(Connection);
}
}
}
E.3.3. Target Algorithms ๐ฏ
Okay, now we flip over to the target side, bestie ๐ This is where the SNACK requests get handled.
Handle-Status-SNACK-request(Connection, CurrentPDU)
{
if (operational ErrorRecoveryLevel > 0) {
if (request for an acknowledged run) {
Build-And-Send-Reject(Connection, CurrentPDU,
Protocol-Error);
} else if (request for an untransmitted run) {
discard, return;
} else {
Retransmit-Status-Burst(CurrentPDU, TCB);
} else {
Build-And-Send-Async(Connection, DroppedConnection,
DefaultTime2Wait,
DefaultTime2Retain);
}
}
E.4. Connection Recovery Algorithms ๐ธ
Now we're in the connection recovery zone, and it's giving main character energy โจ
E.4.1. Procedure Descriptions ๐
Here's the full lineup of procedures, so you can see all the pieces at once ๐ง
Build-And-Send-Async(transport connection, reason code,
minimum time, maximum time);
Pick-A-Logged-In-Connection(session);
Build-And-Send-Logout(transport connection, logout connection
identifier, reason code);
PerformImplicitLogout(transport connection, logout connection
identifier, target information);
PerformLogin(transport connection, target information);
CreateNewTransportConnection(target information);
Build-And-Send-Command(transport connection, task control block);
Connection-Cleanup-Handler(transport connection);
Connection-Resource-Timeout-Handler(transport connection);
Quiesce-And-Prepare-for-New-Allegiance(session, task control
block);
Build-And-Send-Logout-Response(transport connection,
CID of connection in recovery, reason
code);
Build-And-Send-TaskMgmt-Response(transport connection,
task mgmt command PDU, response code);
Establish-New-Allegiance(task control block, transport
connection);
Schedule-Command-To-Continue(task control block);
Notes:
- Okay so transport drama ๐ like an unexpected connection termination, a connection reset, or a hung connection while you're in the full-feature phase? Those are all assumed to get asynchronously signaled up to the iSCSI layer using the
Transport_Exception_Handlerprocedure ๐ซถ
E.4.2. Initiator Algorithms ๐ฅ
This is the initiator side of recovery, and honestly the logic is so iconic ๐
Receive-a-In-PDU(Connection, CurrentPDU) {
check-basic-validity(CurrentPDU);
if (Header-Digest-Bad) discard, return;
Retrieve TCB from CurrentPDU.InitiatorTaskTag.
if (CurrentPDU.type == Async) {
if (CurrentPDU.AsyncEvent == ConnectionDropped) {
Retrieve the AffectedConnection for
CurrentPDU.Parameter1.
AffectedConnection.CurrentTimeout =
CurrentPDU.Parameter3;
AffectedConnection.State = CLEANUP_WAIT;
Start-Timer(Connection-Cleanup-Handler,
AffectedConnection,
CurrentPDU.Parameter2);
} else if (CurrentPDU.AsyncEvent == LogoutRequest)) {
AffectedConnection = Connection;
AffectedConnection.State = LOGOUT_REQUESTED;
AffectedConnection.PerformConnectionCleanup = TRUE;
AffectedConnection.CurrentTimeout =
CurrentPDU.Parameter3;
Start-Timer(Connection-Cleanup-Handler,
AffectedConnection, 0);
} else if (CurrentPDU.AsyncEvent == SessionDropped)) {
for (each Connection) {
Connection.State = CLEANUP_WAIT;
Connection.CurrentTimeout = CurrentPDU.Parameter3;
Start-Timer(Connection-Cleanup-Handler,
Connection, CurrentPDU.Parameter2);
}
Session.state = FAILED;
}
} else if (CurrentPDU.type == LogoutResponse) {
Retrieve the CleanupConnection for CurrentPDU.CID.
if (CurrentPDU.Response = failure) {
CleanupConnection.State = CLEANUP_WAIT;
} else {
CleanupConnection.State = FREE;
}
} else if (CurrentPDU.type == LoginResponse) {
if (this is a response to an implicit Logout) {
Retrieve the CleanupConnection.
if (successful) {
CleanupConnection.State = FREE;
Connection.State = LOGGED_IN;
} else {
CleanupConnection.State = CLEANUP_WAIT;
DestroyTransportConnection(Connection);
}
}
} else { /* REST UNRELATED TO CONNECTION-RECOVERY,
* NOT SHOWN */
}
if (CleanupConnection.State == FREE) {
for (each command that was active on CleanupConnection) {
/* Establish new connection allegiance */
NewConnection = Pick-A-Logged-In-Connection(Session);
Build-And-Send-Command(NewConnection, TCB);
}
} }
Connection-Cleanup-Handler(Connection) {
Retrieve Session from Connection.
if (Connection can still exchange iSCSI PDUs) {
NewConnection = Connection;
} else {
Start-Timer(Connection-Resource-Timeout-Handler,
Connection, Connection.CurrentTimeout);
if (there are other logged-in connections) {
NewConnection = Pick-A-Logged-In-
Connection(Session);
} else {
NewConnection =
CreateTransportConnection(Session.OtherEndInfo);
Initiate an implicit Logout on NewConnection for
Connection.CID.
return;
}
}
Build-And-Send-Logout(NewConnection, Connection.CID,
RecoveryRemove); }
Transport_Exception_Handler(Connection) {
Connection.PerformConnectionCleanup = TRUE;
if (the event is an unexpected transport disconnect) {
Connection.State = CLEANUP_WAIT;
Connection.CurrentTimeout = DefaultTime2Retain;
Start-Timer(Connection-Cleanup-Handler, Connection,
DefaultTime2Wait);
} else {
Connection.State = FREE;
} }
E.4.3. Target Algorithms โจ
okay bestie, this is the target side of the connection-recovery story ๐ฆ when a Logout or Login shows up with recovery stuff, or a TaskReassign request comes in, the target has to sort out which TCB belongs to which connection. it's giving careful housekeeping, so read it slowly ๐
Receive-a-In-PDU(Connection, CurrentPDU)
{
check-basic-validity(CurrentPDU);
if (Header-Digest-Bad) discard, return;
else if (Data-Digest-Bad) {
Build-And-Send-Reject(Connection, CurrentPDU,
Payload-Digest-Error);
discard, return;
}
Retrieve TCB and Session.
if (CurrentPDU.type == Logout) {
if (CurrentPDU.ReasonCode = RecoveryRemove) {
Retrieve the CleanupConnection from CurrentPDU.CID).
for (each command active on CleanupConnection) {
Quiesce-And-Prepare-for-New-Allegiance(Session,
TCB);
TCB.CurrentlyAllegiant = FALSE;
}
Cleanup-Connection-State(CleanupConnection);
if ((quiescing successful) and (cleanup successful)) {
Build-And-Send-Logout-Response(Connection,
CleanupConnection.CID, Success);
} else {
Build-And-Send-Logout-Response(Connection,
CleanupConnection.CID, Failure);
}
}
} else if ((CurrentPDU.type == Login) and
operational ErrorRecoveryLevel == 2) {
Retrieve the CleanupConnection from CurrentPDU.CID).
for (each command active on CleanupConnection) {
Quiesce-And-Prepare-for-New-Allegiance(Session, TCB);
TCB.CurrentlyAllegiant = FALSE;
}
Cleanup-Connection-State(CleanupConnection);
if ((quiescing successful) and (cleanup successful)) {
Continue with the rest of the Login processing;
} else {
Build-And-Send-Login-Response(Connection,
CleanupConnection.CID, Target Error);
}
}
} else if (CurrentPDU.type == TaskManagement) {
if (CurrentPDU.function == "TaskReassign") {
if (Session.ErrorRecoveryLevel < 2) {
Build-And-Send-TaskMgmt-Response(Connection,
CurrentPDU, "Allegiance reassignment
not supported");
} else if (task is not found) {
Build-And-Send-TaskMgmt-Response(Connection,
CurrentPDU, "Task not in task set");
} else if (task is currently allegiant) {
Build-And-Send-TaskMgmt-Response(Connection,
CurrentPDU, "Task still allegiant");
} else {
Establish-New-Allegiance(TCB, Connection);
TCB.CurrentlyAllegiant = TRUE;
Schedule-Command-To-Continue(TCB);
}
}
} else { /* REST UNRELATED TO CONNECTION-RECOVERY,
* NOT SHOWN */
}
}
Transport_Exception_Handler(Connection)
{
Connection.PerformConnectionCleanup = TRUE;
if (the event is an unexpected transport disconnect) {
Connection.State = CLEANUP_WAIT;
Start-Timer(Connection-Resource-Timeout-Handler,
Connection,
(DefaultTime2Wait+DefaultTime2Retain));
if (this Session has full-feature phase connections
left)
{
DifferentConnection =
Pick-A-Logged-In-Connection(Session);
Build-And-Send-Async(DifferentConnection,
DroppedConnection, DefaultTime2Wait,
DefaultTime2Retain);
}
} else {
Connection.State = FREE;
}
}
Appendix F. Clearing Effects of Various Events on Targets ๐ธ
F.1. Clearing Effects on iSCSI Objects โจ
okay so these tables tell the target what to clear, discard, or reset when stuff happens ๐งน the second table extends the first one with more objects for the same events ๐ here's the legend:
- Y = Yes (cleared/discarded/reset on the event in that row). Unless otherwise noted, the clearing action only applies to the issuing initiator port ๐
- N = No (not affected by the event in that row, so it stays at its previous value) ๐ฆ
- NA = Not Applicable or Not Defined ๐
+-----+-----+-----+-----+-----+
|IT(1)|IC(2)|CT(5)|ST(6)|PP(7)|
+---------------------+-----+-----+-----+-----+-----+
|connection failure(8)|Y |Y |N |N |Y |
+---------------------+-----+-----+-----+-----+-----+
|connection state |NA |NA |Y |N |NA |
|timeout (9) | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|session timeout/ |Y |Y |Y |Y |Y(14)|
|closure/reinstatement| | | | | |
|(10) | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|session continuation |NA |NA |N(11)|N |NA |
|(12) | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|successful connection|Y |Y |Y |N |Y(13)|
|close logout | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|session failure (18) |Y |Y |N |N |Y |
+---------------------+-----+-----+-----+-----+-----+
|successful recovery |Y |Y |N |N |Y(13)|
|Logout | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|failed Logout |Y |Y |N |N |Y |
+---------------------+-----+-----+-----+-----+-----+
|connection Login |NA |NA |NA |Y(15)|NA |
|(leading) | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|connection Login |NA |NA |N(11)|N |Y |
|(non-leading) | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|target cold reset(16)|Y |Y |Y |Y |Y |
+---------------------+-----+-----+-----+-----+-----+
|target warm reset(16)|Y |Y |Y |Y |Y |
+---------------------+-----+-----+-----+-----+-----+
|LU reset(19) |Y |Y |Y |Y |Y |
+---------------------+-----+-----+-----+-----+-----+
|powercycle(16) |Y |Y |Y |Y |Y |
+---------------------+-----+-----+-----+-----+-----+
- Incomplete TTTs - Target Transfer Tags on which the target is still expecting PDUs to be received. Examples include TTTs received via R2T, NOP-IN, etc. ๐
- Immediate Commands - immediate commands, but waiting for execution on a target. For example, Abort Task Set. ๐ง
- Connection Tasks - tasks that are active on the iSCSI connection in question. ๐ธ
- Session Tasks - tasks that are active on the entire iSCSI session. A union of "connection tasks" on all participating connections. ๐
- Partial PDUs (if any) - PDUs that are partially sent and waiting for transport window credit to complete the transmission. ๐ซถ
- Connection failure is a connection exception condition. One of the transport connections shut down, got reset, or timed out, which abruptly terminated the iSCSI full-feature phase connection. A connection failure always takes the connection state machine to the CLEANUP_WAIT state. ๐ญ
- Connection state timeout happens if a connection spends more time than agreed upon during Login negotiation in the CLEANUP_WAIT state, and this takes the connection to the FREE state (M1 transition in connection cleanup state diagram). โฐ
- These are defined in Section 5.3.5 Session Reinstatement, Closure, and Timeout. ๐
- This clearing effect is "Y" only if it is a connection reinstatement and the operational ErrorRecoveryLevel is less than 2. ๐ฅ
- Session continuation is defined in Section 5.3.6 Session Continuation and Failure. ๐
- This clearing effect is only valid if the connection is being logged out on a different connection and when the connection being logged out on the target may have some partial PDUs pending to be sent. In all other cases, the effect is "NA". ๐
- This clearing effect is only valid for a "close the session" logout in a multi-connection session. In all other cases, the effect is "NA". ๐
- Only applicable if this leading connection login is a session reinstatement. If this is not the case, it is "NA". โจ
- This operation affects all logged-in initiators. ๐
- Session failure is defined in Section 5.3.6 Session Continuation and Failure. ๐
- This operation affects all logged-in initiators, and the clearing effects are only applicable to the LU being reset. ๐ฏ
Okay, now the second table, which is the extension I mentioned. Same legend, new columns ๐
+-----+-----+-----+-----+-----+
|DC(1)|DD(2)|SS(3)|CS(4)|DS(5)|
+---------------------+-----+-----+-----+-----+-----+
|connection failure |N |Y |N |N |N |
+---------------------+-----+-----+-----+-----+-----+
|connection state |Y |NA |Y |N |NA |
|timeout | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|session timeout/ |Y |Y |Y(7) |Y |NA |
|closure/reinstatement| | | | | |
+---------------------+-----+-----+-----+-----+-----+
|session continuation |N(11)|NA*12|NA |N |NA*13|
+---------------------+-----+-----+-----+-----+-----+
|successful connection|Y |Y |Y |N |NA |
|close Logout | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|session failure |N |Y |N |N |N |
+---------------------+-----+-----+-----+-----+-----+
|successful recovery |Y |Y |Y |N |N |
|Logout | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|failed Logout |N |Y(9) |N |N |N |
+---------------------+-----+-----+-----+-----+-----+
|connection Login |NA |NA |N(8) |N(8) |NA |
|(leading | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|connection Login |N(11)|NA*12|N(8) |N |NA*13|
|(non-leading) | | | | | |
+---------------------+-----+-----+-----+-----+-----+
|target cold reset |Y |Y |Y |Y(10)|NA |
+---------------------+-----+-----+-----+-----+-----+
|target warm reset |Y |Y |N |N |NA |
+---------------------+-----+-----+-----+-----+-----+
|LU reset |N |Y |N |N |N |
+---------------------+-----+-----+-----+-----+-----+
|powercycle |Y |Y |Y |Y(10)|NA |
+---------------------+-----+-----+-----+-----+-----+
- Discontiguous Commands - commands allegiant to the connection in question and waiting to be reordered in the iSCSI layer. All "Y"s in this column assume that the task causing the event (if indeed the event is the result of a task) is issued as an immediate command, because the discontiguities can be ahead of the task. ๐งฉ
- Discontiguous Data - data PDUs received for the task in question and waiting to be reordered due to prior discontiguities in DataSN. ๐ฆ
- StatSN ๐ข
- CmdSN ๐ข
- DataSN ๐ข
- It clears the StatSN on all the connections. ๐งน
- This sequence number is instantiated on this event. โจ
- A logout failure drives the connection state machine to the CLEANUP_WAIT state, similar to the connection failure event. Hence, it has a similar effect on this and several other protocol aspects. ๐ตโ๐ซ
- This is cleared by virtue of the fact that all sessions with all initiators are terminated. ๐ช
- This clearing effect is "Y" if it is a connection reinstatement. ๐
- This clearing effect is "Y" only if it is a connection reinstatement and the operational ErrorRecoveryLevel is 2. ๐
- This clearing effect is "N" only if it is a connection reinstatement and the operational ErrorRecoveryLevel is 2. ๐
F.2. Clearing Effects on SCSI Objects ๐
The only iSCSI protocol action that can cause clearing actions on SCSI objects is the "I_T nexus loss" notification (Section 4.3.5.1 Loss of Nexus notification). [SPC3] describes what this notification clears across a bunch of SCSI attributes. On top of that, SCSI standards docs (like [SAM2] and [SBC]) define extra clearing actions that can happen to several SCSI objects on SCSI events such as LU resets and power-on resets ๐
Since iSCSI treats a target cold reset as protocol-equivalent to a target power-cycle, the iSCSI target cold reset also has to count as the power-on reset event when you read the actions in the SCSI standards โก
When the iSCSI session gets rebuilt (between the same SCSI ports with the same nexus identifier), reestablishing the same I_T nexus, every SCSI object that is defined to not clear on the "I_T nexus loss" notification, like persistent reservations, is automatically associated with this new session ๐ซถ๐
Acknowledgements ๐ซถ
okay so this protocol was built by a design team! ๐ besides the authors, the team included Daniel Smith, Ofer Biran, Jim Hafner and John Hufferd (IBM), Mark Bakke (Cisco), Randy Haagens (HP), Matt Wakeley (Agilent, now Sierra Logic), Luciano Dalle Ore (Quantum), and Paul Von Stamwitz (Adaptec, now TrueSAN Networks). the whole team is iconic ๐
a huge crowd also helped by reviewing, commenting, and sharing insights, and the authors are so grateful ๐ฅน special shoutout to everyone who made time for the weekly phone calls and the in-person meetings in Almaden and Haifa, because those literally shaped this doc โจ: Prasenjit Sarkar, Meir Toledano, John Dowdy, Steve Legg, Alain Azagury (IBM), Dave Nagle (CMU), David Black (EMC), John Matze (Veritas - now Okapi Software), Steve DeGroote, Mark Schrandt (Cisco), Gabi Hecht (Gadzoox), Robert Snively and Brian Forbes (Brocade), Nelson Nachum (StorAge), and Uri Elzur (Broadcom). ๐ธ
lots of other people edited and improved the document inside the IPS working group, and we're especially thankful to David Robinson and Raghavendra Rao (Sun), Charles Monia, Joshua Tseng (Nishan), Somesh Gupta (Silverback), Michael Krause, Pierre Labat, Santosh Rao, Matthew Burbridge, Bob Barry, Robert Elliott, Nick Martin (HP), Stephen Bailey (Sandburst), Steve Senum, Ayman Ghanem, Dave Peterson (Cisco), Barry Reinhold (Trebia Networks), Bob Russell (UNH), Eddy Quicksall (iVivity, Inc.), Bill Lynn and Michael Fischer (Adaptec), Vince Cavanna, Pat Thaler (Agilent), Jonathan Stone (Stanford), Luben Tuikov (Splentec), Paul Koning (EqualLogic), Michael Krueger (Windriver), Martins Krikis (Intel), Doug Otis (Sanlight), John Marberg (IBM), Robert Griswold and Bill Moody (Crossroads), Bill Studenmund (Wasabi Systems), Elizabeth Rodriguez (Brocade) and Yaron Klein (Sanrad). ๐
the recovery chapter got a glow-up thanks to Stephen Bailey (Sandburst), Somesh Gupta (Silverback), and Venkat Rangan (Rhapsody Networks) ๐ฅ. Eddy Quicksall contributed some examples and kicked off the Definitions section, and Michael Fischer and Bob Barry started the Acronyms section. last but not least, Ralph Weber kept everyone in line with T10 (SCSI) standardization ๐ซก
we also want to thank Steve Hetzler for his unwavering support and for coming up with such a good name for the protocol ๐ง, plus Micky Rodeh, Jai Menon, Clod Barrera, and Andy Bechtolsheim for helping make this work happen ๐
if you want the full picture of the iSCSI spec, the authors recommend checking out these: "iSCSI Naming & Discovery"[RFC3721], "Bootstrapping Clients using the iSCSI Protocol" [BOOT], "Securing Block Storage Protocols over IP" [RFC3723] documents, "iSCSI Requirements and Design Considerations" [RFC3347] and "SCSI Command Ordering Considerations with iSCSI" [CORD] ๐
the "iSCSI Naming & Discovery" doc was written by:
- Mark Bakke (Cisco), Jim Hafner, John Hufferd, Kaladhar Voruganti (IBM), and Marjorie Krueger (HP).
the "Bootstrapping Clients using the iSCSI Protocol" doc was written by:
- Prasenjit Sarkar (IBM), Duncan Missimer (HP), and Costa Sapuntzakis (Cisco).
the "Securing Block Storage Protocols over IP" doc was written by:
- Bernard Aboba (Microsoft), Joshua Tseng (Nishan), Jesse Walker (Intel), Venkat Rangan (Rhapsody Networks), and Franco Travostino (Nortel Networks).
the "iSCSI Requirements and Design Considerations" doc was written by:
- Marjorie Krueger, Randy Haagens (HP), Costa Sapuntzakis, and Mark Bakke (Cisco).
the "SCSI Command Ordering Considerations with iSCSI" doc was written by:
- Mallikarjun Chadalapaka, Rob Elliot (HP)
the authors are so grateful to all of them for their amazing work and for helping them line this document up with the ones they produced ๐ฅฐ
Authors' Addresses ๐ฌ
Julian Satran
IBM Research Laboratory in Haifa
Haifa University Campus - Mount Carmel
Haifa 31905, Israel
Phone +972.4.829.6264
EMail: Julian_Satran@il.ibm.com
Kalman Meth
IBM Research Laboratory in Haifa
Haifa University Campus - Mount Carmel
Haifa 31905, Israel
Phone +972.4.829.6341
EMail: meth@il.ibm.com
Costa Sapuntzakis
Stanford University
353 Serra Mall Dr #407
Stanford, CA 94305
Phone: +1.650.723.2458
EMail: csapuntz@alum.mit.edu
Efri Zeidner
XIV Ltd.
1 Azrieli Center,
Tel-Aviv 67021, Israel
Phone: +972.3.607.4722
EMail: efri@xiv.co.il
Mallikarjun Chadalapaka
Hewlett-Packard Company
8000 Foothills Blvd.
Roseville, CA 95747-5668, USA
Phone: +1.916.785.5621
EMail: cbm@rose.hp.com
Full Copyright Statement ยฉ
Copyright (C) The Internet Society (2004). This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.
This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Intellectual Property ๐งพ
The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79.
Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.
The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.
Acknowledgement ๐ท
Funding for the RFC Editor function is currently provided by the Internet Society.
๐ฆ where this page comes from
- ietf: rfc3720 2004-04
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms