diff options
| -rw-r--r-- | Doxyfile | 5 | ||||
| -rw-r--r-- | src/server/iscsi.c | 12 | ||||
| -rw-r--r-- | src/server/iscsi.h | 2075 |
3 files changed, 1391 insertions, 701 deletions
@@ -28,8 +28,9 @@ STRIP_CODE_COMMENTS = NO # Preprocessor ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES -EXPAND_ONLY_PREDEF = NO -SKIP_FUNCTION_MACROS = YES +EXPAND_ONLY_PREDEF = YES +SKIP_FUNCTION_MACROS = NO +PREDEFINED = __attribute__(x)= # Warnings WARN_IF_UNDOCUMENTED = YES diff --git a/src/server/iscsi.c b/src/server/iscsi.c index d59d6df..b6057c8 100644 --- a/src/server/iscsi.c +++ b/src/server/iscsi.c @@ -413,7 +413,7 @@ void iscsi_hashmap_key_destroy(uint8_t *key) { * be a multiple of 8 bytes which is NOT checked, so * be careful. * @param[in] value Value of the key, NULL is allowed. - * @param[in] user_data This argument is not used by + * @param[in,out] user_data This argument is not used by * this function and should be always NULL for now, as * there is a possibility for future usage. * @return Always returns 0 as this function cannot fail. @@ -570,7 +570,7 @@ int iscsi_hashmap_get_put(iscsi_hashmap *map, const uint8_t *key, const size_t k * overwritten key and value pair. The function is * invoked just before overwriting the old values. * This may NOT be NULL, so take caution. - * @param[in] user_data Pointer to user specific data + * @param[in,out] user_data Pointer to user specific data * passed to the callback function in case more * information is needed. * @return -1 in case adding key / value pair would @@ -721,7 +721,7 @@ void iscsi_hashmap_remove(iscsi_hashmap *map, const uint8_t *key, const size_t k * key and value pair to be removed. The function is * invoked just before marking the key / value pair * as removed. This may NOT be NULL, so take caution. - * @param[in] user_data Pointer to user specific data + * @param[in,out] user_data Pointer to user specific data * passed to the callback function in case more * information is needed. */ @@ -770,7 +770,7 @@ int iscsi_hashmap_size(iscsi_hashmap *map) * invoked for each element not marked for removal * in the hash map. If the return value of the callback * function is below zero, the iteration will stop. - * @param[in] user_data Pointer to user specific data + * @param[in,out] user_data Pointer to user specific data * passed to the callback function in case more * information is needed. * @return The return code from the last invoked @@ -1708,7 +1708,7 @@ int iscsi_parse_key_value_pairs(iscsi_hashmap *pairs, const uint8_t *packet_data * be careful. * @param[in] value Value of the key, NULL creates an * empty key assignment. - * @param[in] user_data Pointer to a data structure + * @param[in,out] user_data Pointer to a data structure * containing the memory buffer and length for the * iSCSI packet data (iscsi_key_value_pair_packet * structure), may NOT be NULL, so be careful. @@ -1896,7 +1896,7 @@ void iscsi_connection_destroy(iscsi_connection *conn) * be a multiple of 8 bytes which is NOT checked, so * be careful. * @param[in] value Value of the key, NULL is allowed. - * @param[in] user_data This argument is not used by + * @param[in,out] user_data This argument is not used by * this function and should be always NULL for now, as * there is a possibility for future usage. * @return Always returns 0 as this function cannot fail. diff --git a/src/server/iscsi.h b/src/server/iscsi.h index 7fa1558..ff2920c 100644 --- a/src/server/iscsi.h +++ b/src/server/iscsi.h @@ -123,34 +123,84 @@ uint8_t *iscsi_sprintf_append_realloc(char *buf, const char *format, ...); // Al uint8_t *iscsi_vsprintf_alloc(const char *format, va_list args); // Allocates a buffer and sprintf's it uint8_t *iscsi_sprintf_alloc(const char *format, ... ); // Allocates a buffer and sprintf's it -#define ISCSI_HASHMAP_DEFAULT_CAPACITY_SHIFT 5UL // Shift factor for default capacity -#define ISCSI_HASHMAP_DEFAULT_CAPACITY (1UL << (ISCSI_HASHMAP_DEFAULT_CAPACITY_SHIFT)) // Default capacity is 32 buckets -#define ISCSI_HASHMAP_RESIZE_SHIFT 1UL // Number of bits to shift left when resizing -#define ISCSI_HASHMAP_KEY_ALIGN_SHIFT 3UL // Key data shift value for alignment enforcement -#define ISCSI_HASHMAP_KEY_ALIGN (1UL << (ISCSI_HASHMAP_KEY_ALIGN_SHIFT)) // Key data size must be multiple of 8 bytes by now -#define ISCSI_HASHMAP_HASH_INITIAL 0x811C9DC5UL // Initial hash code -#define ISCSI_HASHMAP_HASH_MUL 0xBF58476D1CE4E5B9ULL // Value to multiply hash code with +/// Shift factor for default capacity. +#define ISCSI_HASHMAP_DEFAULT_CAPACITY_SHIFT 5UL +/// Default capacity is 32 buckets. +#define ISCSI_HASHMAP_DEFAULT_CAPACITY (1UL << (ISCSI_HASHMAP_DEFAULT_CAPACITY_SHIFT)) + +/// Number of bits to shift left when resizing. +#define ISCSI_HASHMAP_RESIZE_SHIFT 1UL + +/// Key data shift value for alignment enforcement. +#define ISCSI_HASHMAP_KEY_ALIGN_SHIFT 3UL + +/// Key data size must be multiple of 8 bytes by now. +#define ISCSI_HASHMAP_KEY_ALIGN (1UL << (ISCSI_HASHMAP_KEY_ALIGN_SHIFT)) + +/// Initial hash code. +#define ISCSI_HASHMAP_HASH_INITIAL 0x811C9DC5UL + +/// Value to multiply hash code with. +#define ISCSI_HASHMAP_HASH_MUL 0xBF58476D1CE4E5B9ULL + +/** + * @brief Hash map bucket containing key, value and hash code. + * + * This structure is used by the iSCSI hash map implementation + * in order to maintain the elements. + */ typedef struct iscsi_hashmap_bucket { - struct iscsi_hashmap_bucket *next; // Must be first element + /// Next bucket, must be first element. + struct iscsi_hashmap_bucket *next; + + /// Data used as key, must be aligned to 8 bytes and zero padded. + uint8_t *key; - uint8_t *key; // Data used as key, zero padding - size_t key_size; // Size of key, must be a multiple of 8 bytes - uint32_t hash; // Hash code - uint8_t *value; // Value + /// Size of key, must be a multiple of 8 bytes. + size_t key_size; + + /// Hash code for the key. + uint32_t hash; + + /// Associate4d value to the key, NULL is allowed. + uint8_t *value; } iscsi_hashmap_bucket; +/** + * @brief Hash map containing an expandable list of buckets + * + * This structure is used by the ultra performant hash map + * implementation. It uses a linked list allowing fast + * insertions. Elements can be removed and are marked for + * deletion until a resize operation is necessary. + */ typedef struct iscsi_hashmap { - iscsi_hashmap_bucket *buckets; // Hashmap buckets - uint capacity; // Current capacity in elements + /// Linked list containing the hash map buckets. + iscsi_hashmap_bucket *buckets; + + /// Current bucket capacity, MUST be a power of two. + uint capacity; + + /// Current capacity threshold triggering resize operation. uint cap_load; // Capacity load threshold before next resize - uint count; // Number of buckets - uint removed_count; // Number of removed buckets - iscsi_hashmap_bucket *first; // First bucket of linked list - iscsi_hashmap_bucket *last; // Last bucket, allows faster traversion + + /// Current count of buckets including ones marked for removal. + uint count; + + /// Number of buckets marked for removal. + uint removed_count; + + /// First linked list bucket for fast insertion. + iscsi_hashmap_bucket *first; + + /// Last linked list bucket for faster traversion. + iscsi_hashmap_bucket *last; } iscsi_hashmap; /** + * @brief A Callback for iterating over map, freeing and removing entries. user_data is free for personal use. + * * Callback function. This is a pointer to a * function for various purposes like iterating * through a hash map. It is also used for replacing @@ -162,6 +212,11 @@ typedef struct iscsi_hashmap { * be a multiple of 8 bytes which is NOT checked, so * be careful. * @param[in] value Value of the key, NULL is allowed. + * @param[in,out] user_data User data to be used by the + * callback function. User data can be modified if + * desired and may also be NULL if the callback + * function handles this case. See the documentation + * of the callback implementation for details. * @return A negative result indicates as fatal error, * 0 means successful operation and a positive value * indicates a non-fatal error or a warning. @@ -190,100 +245,237 @@ int iscsi_hashmap_iterate(iscsi_hashmap *map, iscsi_hashmap_callback callback, u /* iSCSI protocol stuff (all WORD/DWORD/QWORD values are big endian by default unless specified otherwise). */ -#define ISCSI_BHS_SIZE 48UL // iSCSI Basic Header Segment size -#define ISCSI_DIGEST_SIZE 4UL // iSCSI header and data digest size (CRC32C) -#define ISCSI_ALIGN_SIZE 4UL // iSCSI packet data alignment (BHS, AHS and DS) +/// iSCSI Basic Header Segment size. +#define ISCSI_BHS_SIZE 48UL + +/// iSCSI header and data digest size (CRC32C). +#define ISCSI_DIGEST_SIZE 4UL + +/// iSCSI packet data alignment (BHS, AHS and DataSegment). +#define ISCSI_ALIGN_SIZE 4UL + +/// Current minimum iSCSI protocol version supported by this implementation. +#define ISCSI_VERSION_MIN 0 + +/// Current maximum iSCSI protocol version supported by this implementation. +#define ISCSI_VERSION_MAX 0 -#define ISCSI_VERSION_MIN 0 // Current minimum iSCSI protocol version supported by this implementation -#define ISCSI_VERSION_MAX 0 // Current maximum iSCSI protocol version supported by this implementation -// CRC32C constants for header and data digest +/// CRC32C initial constant for header and data digest. #define ISCSI_CRC32C_INITIAL 0xFFFFFFFFUL + +/// CRC32C initial constant for header and data digest. #define ISCSI_CRC32C_XOR 0xFFFFFFFFUL -// iSCSI initiator (client) command opcodes -#define ISCSI_CLIENT_NOP_OUT 0x00 // NOP-Out -#define ISCSI_CLIENT_SCSI_CMD 0x01 // SCSI Command (encapsulates a SCSI Command Descriptor Block) -#define ISCSI_CLIENT_TASK_FUNC_REQ 0x02 // SCSI Task Management Function Request -#define ISCSI_CLIENT_LOGIN_REQ 0x03 // Login Request -#define ISCSI_CLIENT_TEXT_REQ 0x04 // Text Request -#define ISCSI_CLIENT_SCSI_DATA_OUT 0x05 // SCSI Data-Out (for write operations) -#define ISCSI_CLIENT_LOGOUT_REQ 0x06 // Logout Request -#define ISCSI_CLIENT_SNACK_REQ 0x10 // SNACK Request -#define ISCSI_CLIENT_VENDOR_CODE1 0x1C // Vendor-specific code #1 -#define ISCSI_CLIENT_VENDOR_CODE2 0x1D // Vendor-specific code #2 -#define ISCSI_CLIENT_VENDOR_CODE3 0x1E // Vendor-specific code #3 - -#define ISCSI_CLIENT_FIRST_OPCODE 0x00 // First client opcode value -#define ISCSI_CLIENT_LAST_OPCODE 0x1F // Last client opcode value - -// iSCSI target (server) command opcodes -#define ISCSI_SERVER_NOP_IN 0x20 // NOP-In -#define ISCSI_SERVER_SCSI_RESPONSE 0x21 // SCSI Response - contains SCSI status and possibly sense information or other response information -#define ISCSI_SERVER_TASK_FUNC_RES 0x22 // SCSI Task Management Function Response -#define ISCSI_SERVER_LOGIN_RES 0x23 // Login Response -#define ISCSI_SERVER_TEXT_RES 0x24 // Text Response -#define ISCSI_SERVER_SCSI_DATA_IN 0x25 // SCSI Data-In (for read operations) -#define ISCSI_SERVER_LOGOUT_RES 0x26 // Logout Response -#define ISCSI_SERVER_READY_XFER 0x31 // Ready To Transfer (R2T) - sent by target when it is ready to receive data -#define ISCSI_SERVER_ASYNC_MSG 0x32 // Asynchronous Message - sent by target to indicate certain special conditions -#define ISCSI_SERVER_VENDOR_CODE1 0x3C // Vendor-specific code #1 -#define ISCSI_SERVER_VENDOR_CODE2 0x3D // Vendor-specific code #2 -#define ISCSI_SERVER_VENDOR_CODE3 0x3E // Vendor-specific code #3 -#define ISCSI_SERVER_REJECT 0x3F // Reject - -#define ISCSI_SERVER_FIRST_OPCODE 0x20 // First client opcode value -#define ISCSI_SERVER_LAST_OPCODE 0x3F // Last client opcode value - -#define ISCSI_OPCODE_MASK 0x3F // ISCSI opcode bit mask (bits 0-5 used) -#define ISCSI_GET_OPCODE(x) ((x) & ISCSI_OPCODE_MASK) // Funky macro to get iSCSI packet opcode +/// iSCSI initiator (client) command opcode: NOP-Out. +#define ISCSI_CLIENT_NOP_OUT 0x00 + +/// iSCSI initiator (client) command opcode: SCSI Command (encapsulates a SCSI Command Descriptor Block). +#define ISCSI_CLIENT_SCSI_CMD 0x01 + +/// iSCSI initiator (client) command opcode: SCSI Task Management Function Request. +#define ISCSI_CLIENT_TASK_FUNC_REQ 0x02 + +/// iSCSI initiator (client) command opcode: Login Request. +#define ISCSI_CLIENT_LOGIN_REQ 0x03 + +/// iSCSI initiator (client) command opcode: Text Request. +#define ISCSI_CLIENT_TEXT_REQ 0x04 + +/// iSCSI initiator (client) command opcode: SCSI Data-Out (for write operations). +#define ISCSI_CLIENT_SCSI_DATA_OUT 0x05 + +/// iSCSI initiator (client) command opcode: Logout Request. +#define ISCSI_CLIENT_LOGOUT_REQ 0x06 + +/// iSCSI initiator (client) command opcode: SNACK Request. +#define ISCSI_CLIENT_SNACK_REQ 0x10 + +/// iSCSI initiator (client) command opcode: Vendor-specific code #1. +#define ISCSI_CLIENT_VENDOR_CODE1 0x1C + +/// iSCSI initiator (client) command opcode: Vendor-specific code #2. +#define ISCSI_CLIENT_VENDOR_CODE2 0x1D + +/// iSCSI initiator (client) command opcode: Vendor-specific code #3. +#define ISCSI_CLIENT_VENDOR_CODE3 0x1E + +/// First iSCSI initiator (client) command opcode. +#define ISCSI_CLIENT_FIRST_OPCODE 0x00 + +/// Last iSCSI initiator (client) command opcode. +#define ISCSI_CLIENT_LAST_OPCODE 0x1F + + +/// iSCSI target (server) command opcode: NOP-In. +#define ISCSI_SERVER_NOP_IN 0x20 + +/// iSCSI target (server) command opcode: SCSI Response - contains SCSI status and possibly sense information or other response information. +#define ISCSI_SERVER_SCSI_RESPONSE 0x21 + +/// iSCSI target (server) command opcode: SCSI Task Management Function Response. +#define ISCSI_SERVER_TASK_FUNC_RES 0x22 + +/// iSCSI target (server) command opcode: Login Response. +#define ISCSI_SERVER_LOGIN_RES 0x23 + +/// iSCSI target (server) command opcode: Text Response. +#define ISCSI_SERVER_TEXT_RES 0x24 + +/// iSCSI target (server) command opcode: SCSI Data-In (for read operations). +#define ISCSI_SERVER_SCSI_DATA_IN 0x25 + +/// iSCSI target (server) command opcode: Logout Response. +#define ISCSI_SERVER_LOGOUT_RES 0x26 + +/// iSCSI target (server) command opcode: Ready To Transfer (R2T) - sent by target when it is ready to receive data. +#define ISCSI_SERVER_READY_XFER 0x31 + +/// iSCSI target (server) command opcode: Asynchronous Message - sent by target to indicate certain special conditions. +#define ISCSI_SERVER_ASYNC_MSG 0x32 + +/// iSCSI target (server) command opcode: Vendor-specific code #1. +#define ISCSI_SERVER_VENDOR_CODE1 0x3C + +/// iSCSI target (server) command opcode: Vendor-specific code #2. +#define ISCSI_SERVER_VENDOR_CODE2 0x3D + +/// iSCSI target (server) command opcode: Vendor-specific code #3. +#define ISCSI_SERVER_VENDOR_CODE3 0x3E + +/// iSCSI target (server) command opcode: Reject. +#define ISCSI_SERVER_REJECT 0x3F + + +/// First iSCSI target (server) command opcode. +#define ISCSI_SERVER_FIRST_OPCODE 0x20 + +/// Last iSCSI target (server) command opcode. +#define ISCSI_SERVER_LAST_OPCODE 0x3F + + +/// iSCSI opcode bit mask (bits 0-5 used). +#define ISCSI_OPCODE_MASK 0x3F + +/// Macro which extracts iSCSI packet data opcode out of opcode byte +#define ISCSI_GET_OPCODE(x) ((x) & ISCSI_OPCODE_MASK) + +/** + * @brief iSCSI Basic Header Segment packet data. + * + * This structure contains the basic iSCSI packet + * data and is shared among all opcodes. This has + * to be used before the opcode of the packet data + * has been determined. + */ typedef struct __attribute__((packed)) iscsi_bhs_packet { - uint8_t opcode; // Command opcode (see above) - uint8_t opcode_fields[3]; // Opcode-specific fields - uint8_t total_ahs_len; // Total AHS length - uint8_t ds_len[3]; // Data segment length + /// Command opcode. + uint8_t opcode; + + /// Opcode-specific fields. + uint8_t opcode_fields[3]; + + /// Total length of AHS (Advanced Header Segment). + uint8_t total_ahs_len; + + /// Length of Data Segment. + uint8_t ds_len[3]; + union { - uint64_t lun; // LUN bitmask - uint8_t opcode_spec[8]; // Opcode-specific fields + /// SCSI LUN bit mask. + uint64_t lun; + + /// Opcode-specific fields. + uint8_t opcode_spec[8]; } lun_opcode; - uint32_t init_task_tag; // Initiator task tag + + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; + + /// Opcode-specific fields. uint8_t opcode_spec_fields[28]; } iscsi_bhs_packet; -#define ISCSI_AHS_TYPE_EXT_CDB_PACKET 0x01 // Command Descriptor Block (CDB) + +/// iSCSI AHS type: Extended Command Descriptor Block (CDB). +#define ISCSI_AHS_TYPE_EXT_CDB_PACKET 0x01 + +/// iSCSI AHS type: Bidirectional Read Expected Data Transfer Length. #define ISCSI_AHS_TYPE_BIDI_READ_EXP_XFER_AHS_PACKET 0x02 + +/** + * @brief iSCSI Advanced Header Segment packet data. + * + * This structure contains the advanced iSCSI packet + * data and is shared among all opcodes. This has + * to be used before the opcode of the packet data + * has been determined. + */ typedef struct __attribute__((packed)) iscsi_ahs_packet { - uint16_t len; // AHSLength - uint8_t type; // AHSType - uint8_t specific; // AHS-Specific - uint8_t data[0]; // AHS-Specific data + /// AHSLength. + uint16_t len; + + /// AHSType. + uint8_t type; + + /// AHS-Specific. + uint8_t specific; + + /// AHS-Specific data. + uint8_t data[0]; } iscsi_ahs_packet; -/* There are 16 bytes in the CDB field to accommodate the commonly used - CDBs. Whenever the CDB is larger than 16 bytes, an Extended CDB AHS - MUST be used to contain the CDB spillover. -*/ +/** + * @brief iSCSI CDB packet data structure. + * + * There are 16 bytes in the CDB field to accommodate the commonly used + * CDBs. Whenever the CDB is larger than 16 bytes, an Extended CDB AHS + * MUST be used to contain the CDB spillover. + */ typedef struct __attribute__((packed)) iscsi_cdb { uint8_t data[16]; } iscsi_cdb; -/* This type of AHS MUST NOT be used if the CDBLength is less than 17. - The length includes the reserved byte 3. -*/ +/** + * @brief iSCSI Extended CDB AHS packet data structure. + * + * This type of AHS MUST NOT be used if the CDBLength is less than 17. + * The length includes the reserved byte 3. + */ typedef struct __attribute__((packed)) iscsi_ext_cdb_ahs_packet { - uint16_t len; // AHSLength - (CDBLength - 15) - uint8_t type; // Identifier (always 0x01 according to specs) - uint8_t reserved; // Reserved for future usage - uint8_t data[0]; // ExtendedCDB + /// AHSLength: AHSLength - (CDBLength - 15). + uint16_t len; + + // AHSType: Identifier (always 1 according to iSCSI specifications). + uint8_t type; + + /// Reserved for future usage, always MUST be 0. + uint8_t reserved; + + /// ExtendedCDB. + uint8_t data[0]; } iscsi_ext_cdb_ahs_packet; +/** + * @brief iSCSI Bidirectional Read Expected Data Transfer Length AHS packet data structure. + * + * This structure is used to determine the bidirectional read + * expected data transfer length. + */ typedef struct __attribute__((packed)) iscsi_bidi_read_exp_xfer_ahs_packet { - uint16_t len; // Always 0x0005 according to specs + /// AHSLength: Always 5 according to ISCSI specifications for now. + uint16_t len; + + /// AHSType: Always 2 according to ISCSI specifications for now. uint8_t type; // Identifier (always 0x02 according to specs) - uint8_t reserved; // Reserved for future usage - uint32_t bidi_read_exp_xfer_len; // Bidirectional Read Expected Data Transfer Length + + /// Reserved for future usage, always MUST be 0. + uint8_t reserved; + + /// Bidirectional Read Expected Data Transfer Length. + uint32_t bidi_read_exp_xfer_len; } iscsi_bidi_read_exp_xfer_ahs_packet; /* Certain iSCSI conditions result in the command being terminated at @@ -303,368 +495,795 @@ typedef struct __attribute__((packed)) iscsi_bidi_read_exp_xfer_ahs_packet { #define ISCSI_DS_ERROR_SNACK_REJECTED_ASC 0x11 // SNACK rejected #define ISCSI_DS_ERROR_SNACK_REJECTED_ASCQ 0x13 -/* Optional header and data digests protect the integrity of the header - and data, respectively. The digests, if present, are located, - respectively, after the header and PDU-specific data and cover, - respectively, the header and the PDU data, each including the padding - bytes, if any. - The existence and type of digests are negotiated during the Login - Phase. -*/ +/** + * @brief iSCSI header digest in case CRC32C has been negotiated. + * + * Optional header and data digests protect the integrity of the header + * and data, respectively. The digests, if present, are located, + * respectively, after the header and PDU-specific data and cover, + * respectively, the header and the PDU data, each including the padding + * bytes, if any. + * + * The existence and type of digests are negotiated during the Login + * Phase. + */ typedef struct __attribute__((packed)) iscsi_header_digest { - uint32_t crc32c; // Header digest is a CRC32C for ensuring integrity + /// Header digest is a CRC32C for ensuring integrity. + uint32_t crc32c; } iscsi_header_digest; +/** + * @brief iSCSI data digest in case CRC32C has been negotiated. + * + * Optional header and data digests protect the integrity of the header + * and data, respectively. The digests, if present, are located, + * respectively, after the header and PDU-specific data and cover, + * respectively, the header and the PDU data, each including the padding + * bytes, if any. + * + * The existence and type of digests are negotiated during the Login + * Phase. + */ typedef struct __attribute__((packed)) iscsi_data_digest { - uint32_t crc32c; // Data digest is a CRC32C for ensuring integrity + /// Data digest is a CRC32C for ensuring integrity. + uint32_t crc32c; } iscsi_data_digest; -/* 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. +/** + * @brief iSCSI DataSegment Command packet structure. + * + * 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). + */ +typedef struct __attribute__((packed)) iscsi_ds_cmd_data { + /// SenseLength: This field indicates the length of Sense Data. + uint16_t len; - 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). -*/ + /// The Sense Data contains detailed information about a CHECK CONDITION. SPC3 specifies the format and content of the Sense Data. + uint8_t sense_data[0]; -typedef struct __attribute__((packed)) iscsi_ds_cmd_data { - uint16_t len; // SenseLength - This field indicates the length of Sense Data. - uint8_t sense_data[0]; // The Sense Data contains detailed information about a CHECK CONDITION. - // SPC3 specifies the format and content of the Sense Data. - uint8_t res_data[0]; // Response Data + /// Response Data. + uint8_t res_data[0]; } iscsi_ds_cmd_data; -// SCSI command opcodes (embedded in iSCSI protocol) -#define SCSI_OPCODE_TESTUNITREADY 0x00 // TEST UNIT READY -#define SCSI_OPCODE_READ6 0x08 // READ(6) -#define SCSI_OPCODE_INQUIRY 0x12 // INQUIRY -#define SCSI_OPCODE_MODESELECT6 0x15 // MODE SELECT(6) -#define SCSI_OPCODE_RESERVE6 0x16 // RESERVE(6) -#define SCSI_OPCODE_RELEASE6 0x17 // RELEASE(6) -#define SCSI_OPCODE_MODESENSE6 0x1A // MODE SENSE(6) -#define SCSI_OPCODE_STARTSTOPUNIT 0x1B // START STOP UNIT -#define SCSI_OPCODE_PREVENTALLOW 0x1E // PREVENT ALLOW MEDIUM REMOVAL -#define SCSI_OPCODE_READCAPACITY10 0x25 // READ CAPACITY(10) -#define SCSI_OPCODE_READ10 0x28 // READ(10) -#define SCSI_OPCODE_WRITE10 0x2A // WRITE(10) -#define SCSI_OPCODE_WRITE_VERIFY10 0x2E // WRITE AND VERIFY(10) -#define SCSI_OPCODE_VERIFY10 0x2F // VERIFY(10) -#define SCSI_OPCODE_PREFETCH10 0x34 // PRE-FETCH(10) -#define SCSI_OPCODE_SYNCHRONIZECACHE10 0x35 // SYNCHRONIZE CACHE(10) -#define SCSI_OPCODE_READ_DEFECT_DATA10 0x37 // READ DEFECT DATA(10) -#define SCSI_OPCODE_WRITE_SAME10 0x41 // WRITE SAME(10) -#define SCSI_OPCODE_UNMAP 0x42 // UNMAP -#define SCSI_OPCODE_READTOC 0x43 // READ TOC/PMA/ATIP -#define SCSI_OPCODE_SANITIZE 0x48 // SANITIZE -#define SCSI_OPCODE_MODESELECT10 0x55 // MODE SELECT(10) -#define SCSI_OPCODE_MODESENSE10 0x5A // MODE SENSE(10) -#define SCSI_OPCODE_PERSISTENT_RESERVE_IN 0x5E // PERSISTENT RESERVE IN -#define SCSI_OPCODE_PERSISTENT_RESERVE_OUT 0x5F // PERSISTENT RESERVE OUT -#define SCSI_OPCODE_EXTENDED_COPY 0x83 // Third-party Copy OUT -#define SCSI_OPCODE_RECEIVE_COPY_RESULTS 0x84 // Third-party Copy IN -#define SCSI_OPCODE_READ16 0x88 // READ(16) -#define SCSI_OPCODE_COMPARE_AND_WRITE 0x89 // COMPARE AND WRITE -#define SCSI_OPCODE_WRITE16 0x8A // WRITE(16) -#define SCSI_OPCODE_ORWRITE 0x8B // ORWRITE -#define SCSI_OPCODE_WRITE_VERIFY16 0x8E // WRITE AND VERIFY(16) -#define SCSI_OPCODE_VERIFY16 0x8F // VERIFY(16) -#define SCSI_OPCODE_PREFETCH16 0x90 // PRE-FETCH(16) -#define SCSI_OPCODE_SYNCHRONIZECACHE16 0x91 // SYNCHRONIZE CACHE(16) -#define SCSI_OPCODE_WRITE_SAME16 0x93 // WRITE SAME(16) -#define SCSI_OPCODE_WRITE_ATOMIC16 0x9C // WRITE ATOMIC(16) -#define SCSI_OPCODE_SERVICE_ACTION_IN 0x9E // SERVICE ACTION IN(16) -#define SCSI_OPCODE_REPORTLUNS 0xA0 // REPORT LUNS -#define SCSI_OPCODE_MAINTENANCE_IN 0xA3 // MAINTENANCE IN -#define SCSI_OPCODE_READ12 0xA8 // READ(12) -#define SCSI_OPCODE_WRITE12 0xAA // WRITE(12) -#define SCSI_OPCODE_WRITE_VERIFY12 0xAE // WRITE AND VERIFY(12) -#define SCSI_OPCODE_VERIFY12 0xAF // VERIFY(12) -#define SCSI_OPCODE_READ_DEFECT_DATA12 0xB7 // READ DEFECT DATA(12) - -#define ISCSI_SCSI_CMD_FLAGS_TASK_NO_UNSOLICITED_DATA (1 << 7) // (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. -#define ISCSI_SCSI_CMD_FLAGS_TASK_READ (1 << 6) // (R) is set to 1 when the command is expected to input data -#define ISCSI_SCSI_CMD_FLAGS_TASK_WRITE (1 << 5) // (W) is set to 1 when the command is expected to output data - -#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_UNTAGGED 0x0 // Untagged task attribute -#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_SIMPLE 0x1 // Simple task attribute -#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_ORDERED 0x2 // Ordered task attribute -#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_HEAD_QUEUE 0x3 // Head of queue task attribute -#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_ACA 0x4 // ACA task attribute -#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_RESERVED_1 0x5 // ACA task attribute -#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_RESERVED_2 0x6 // ACA task attribute -#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_RESERVED_3 0x7 // ACA task attribute - -/* Flags and Task Attributes: - At least one of the W and F bits MUST be set to 1. - Either or both of R and W MAY be 1 when the Expected Data Transfer - Length and/or the Bidirectional Read Expected Data Transfer Length - are 0, but they MUST NOT both be 0 when the Expected Data Transfer - Length and/or Bidirectional Read Expected Data Transfer Length are - not 0 (i.e., when some data transfer is expected, the transfer - direction is indicated by the R and/or W bit). -*/ +/// SCSI command opcode (embedded in iSCSI protocol): TEST UNIT READY. +#define ISCSI_SCSI_OPCODE_TESTUNITREADY 0x00 + +/// SCSI command opcode (embedded in iSCSI protocol): READ(6). +#define ISCSI_SCSI_OPCODE_READ6 0x08 + +/// SCSI command opcode (embedded in iSCSI protocol): INQUIRY. +#define ISCSI_SCSI_OPCODE_INQUIRY 0x12 + +/// SCSI command opcode (embedded in iSCSI protocol): MODE SELECT(6). +#define ISCSI_SCSI_OPCODE_MODESELECT6 0x15 + +/// SCSI command opcode (embedded in iSCSI protocol): RESERVE(6). +#define ISCSI_SCSI_OPCODE_RESERVE6 0x16 + +/// SCSI command opcode (embedded in iSCSI protocol): RELEASE(6). +#define ISCSI_SCSI_OPCODE_RELEASE6 0x17 + +/// SCSI command opcode (embedded in iSCSI protocol): MODE SENSE(6). +#define ISCSI_SCSI_OPCODE_MODESENSE6 0x1A + +/// SCSI command opcode (embedded in iSCSI protocol): START STOP UNIT. +#define ISCSI_SCSI_OPCODE_STARTSTOPUNIT 0x1B + +/// SCSI command opcode (embedded in iSCSI protocol): PREVENT ALLOW MEDIUM REMOVAL. +#define ISCSI_SCSI_OPCODE_PREVENTALLOW 0x1E + +/// SCSI command opcode (embedded in iSCSI protocol): READ CAPACITY(10). +#define ISCSI_SCSI_OPCODE_READCAPACITY10 0x25 + +/// SCSI command opcode (embedded in iSCSI protocol): READ(10). +#define ISCSI_SCSI_OPCODE_READ10 0x28 + +/// SCSI command opcode (embedded in iSCSI protocol): WRITE(10). +#define ISCSI_SCSI_OPCODE_WRITE10 0x2A + +/// SCSI command opcode (embedded in iSCSI protocol): WRITE AND VERIFY(10). +#define ISCSI_SCSI_OPCODE_WRITE_VERIFY10 0x2E + +/// SCSI command opcode (embedded in iSCSI protocol): VERIFY(10). +#define ISCSI_SCSI_OPCODE_VERIFY10 0x2F + +/// SCSI command opcode (embedded in iSCSI protocol): PRE-FETCH(10). +#define ISCSI_SCSI_OPCODE_PREFETCH10 0x34 + +/// SCSI command opcode (embedded in iSCSI protocol): SYNCHRONIZE CACHE(10). +#define ISCSI_SCSI_OPCODE_SYNCHRONIZECACHE10 0x35 + +/// SCSI command opcode (embedded in iSCSI protocol): READ DEFECT DATA(10). +#define ISCSI_SCSI_OPCODE_READ_DEFECT_DATA10 0x37 + +/// SCSI command opcode (embedded in iSCSI protocol): WRITE SAME(10). +#define ISCSI_SCSI_OPCODE_WRITE_SAME10 0x41 + +/// SCSI command opcode (embedded in iSCSI protocol): UNMAP. +#define ISCSI_SCSI_OPCODE_UNMAP 0x42 + +/// SCSI command opcode (embedded in iSCSI protocol): READ TOC/PMA/ATIP. +#define ISCSI_SCSI_OPCODE_READTOC 0x43 + +/// SCSI command opcode (embedded in iSCSI protocol): SANITIZE. +#define ISCSI_SCSI_OPCODE_SANITIZE 0x48 + +/// SCSI command opcode (embedded in iSCSI protocol): MODE SELECT(10). +#define ISCSI_SCSI_OPCODE_MODESELECT10 0x55 + +/// SCSI command opcode (embedded in iSCSI protocol): MODE SENSE(10). +#define ISCSI_SCSI_OPCODE_MODESENSE10 0x5A + +/// SCSI command opcode (embedded in iSCSI protocol): PERSISTENT RESERVE IN. +#define ISCSI_SCSI_OPCODE_PERSISTENT_RESERVE_IN 0x5E + +/// SCSI command opcode (embedded in iSCSI protocol): PERSISTENT RESERVE OUT. +#define ISCSI_SCSI_OPCODE_PERSISTENT_RESERVE_OUT 0x5F + +/// SCSI command opcode (embedded in iSCSI protocol): Third-party Copy OUT. +#define ISCSI_SCSI_OPCODE_EXTENDED_COPY 0x83 + +/// SCSI command opcode (embedded in iSCSI protocol): Third-party Copy IN. +#define ISCSI_SCSI_OPCODE_RECEIVE_COPY_RESULTS 0x84 + +/// SCSI command opcode (embedded in iSCSI protocol): READ(16). +#define ISCSI_SCSI_OPCODE_READ16 0x88 + +/// SCSI command opcode (embedded in iSCSI protocol): COMPARE AND WRITE. +#define ISCSI_SCSI_OPCODE_COMPARE_AND_WRITE 0x89 + +/// SCSI command opcode (embedded in iSCSI protocol): WRITE(16). +#define ISCSI_SCSI_OPCODE_WRITE16 0x8A + +/// SCSI command opcode (embedded in iSCSI protocol): ORWRITE. +#define ISCSI_SCSI_OPCODE_ORWRITE 0x8B + +/// SCSI command opcode (embedded in iSCSI protocol): WRITE AND VERIFY(16). +#define ISCSI_SCSI_OPCODE_WRITE_VERIFY16 0x8E + +/// SCSI command opcode (embedded in iSCSI protocol): VERIFY(16). +#define ISCSI_SCSI_OPCODE_VERIFY16 0x8F + +/// SCSI command opcode (embedded in iSCSI protocol): PRE-FETCH(16). +#define ISCSI_SCSI_OPCODE_PREFETCH16 0x90 + +/// SCSI command opcode (embedded in iSCSI protocol): SYNCHRONIZE CACHE(16). +#define ISCSI_SCSI_OPCODE_SYNCHRONIZECACHE16 0x91 + +/// SCSI command opcode (embedded in iSCSI protocol): WRITE SAME(16). +#define ISCSI_SCSI_OPCODE_WRITE_SAME16 0x93 -#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_MASK 0x7 // Task Attributes (ATTR) are encoded in the first three LSBs' +/// SCSI command opcode (embedded in iSCSI protocol): WRITE ATOMIC(16). +#define ISCSI_SCSI_OPCODE_WRITE_ATOMIC16 0x9C +/// SCSI command opcode (embedded in iSCSI protocol): SERVICE ACTION IN(16). +#define ISCSI_SCSI_OPCODE_SERVICE_ACTION_IN 0x9E + +/// SCSI command opcode (embedded in iSCSI protocol): REPORT LUNS. +#define ISCSI_SCSI_OPCODE_REPORTLUNS 0xA0 + +/// SCSI command opcode (embedded in iSCSI protocol): MAINTENANCE IN. +#define ISCSI_SCSI_OPCODE_MAINTENANCE_IN 0xA3 + +/// SCSI command opcode (embedded in iSCSI protocol): READ(12). +#define ISCSI_SCSI_OPCODE_READ12 0xA8 + +/// SCSI command opcode (embedded in iSCSI protocol): WRITE(12). +#define ISCSI_SCSI_OPCODE_WRITE12 0xAA + +/// SCSI command opcode (embedded in iSCSI protocol): WRITE AND VERIFY(12). +#define ISCSI_SCSI_OPCODE_WRITE_VERIFY12 0xAE + +/// SCSI command opcode (embedded in iSCSI protocol): VERIFY(12). +#define ISCSI_SCSI_OPCODE_VERIFY12 0xAF + +/// SCSI command opcode (embedded in iSCSI protocol): READ DEFECT DATA(12). +#define ISCSI_SCSI_OPCODE_READ_DEFECT_DATA12 0xB7 + + +/** + * @brief iSCSI SCSI command flags: No unsolicited data. + * + * (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. + */ +#define ISCSI_SCSI_CMD_FLAGS_TASK_NO_UNSOLICITED_DATA (1 << 7) + +/** + * @brief iSCSI SCSI command flags: Expected input data. + * + * (R) is set to 1 when the command is expected to input data. + */ +#define ISCSI_SCSI_CMD_FLAGS_TASK_READ (1 << 6) + +/** + * @brief iSCSI SCSI command flags: Expected output data. + * + * (W) is set to 1 when the command is expected to output data. + */ +#define ISCSI_SCSI_CMD_FLAGS_TASK_WRITE (1 << 5) + + +/// SCSI command flags task attribute: Untagged. +#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_UNTAGGED 0x0 + +/// SCSI command flags task attribute: Simple. +#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_SIMPLE 0x1 + +/// SCSI command flags task attribute: Ordered. +#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_ORDERED 0x2 + +/// SCSI command flags task attribute: Head of queue. +#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_HEAD_QUEUE 0x3 + +/// SCSI command flags task attribute: ACA. +#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_ACA 0x4 + +/// SCSI command flags task attribute: Reserved. +#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_RESERVED_1 0x5 + +/// SCSI command flags task attribute: Reserved. +#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_RESERVED_2 0x6 + +/// SCSI command flags task attribute: Reserved. +#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_RESERVED_3 0x7 + +/// SCSI command flags Task Attributes (ATTR) are encoded in the first three LSBs. +#define ISCSI_SCSI_CMD_FLAGS_TASK_ATTR_MASK 0x7 + + +/** + * @brief iSCSI Flag and Task Attributes for SCSI command packet data. + * + * Flags and Task Attributes: + * At least one of the W and F bits MUST be set to 1. + * Either or both of R and W MAY be 1 when the Expected Data Transfer + * Length and/or the Bidirectional Read Expected Data Transfer Length + * are 0, but they MUST NOT both be 0 when the Expected Data Transfer + * Length and/or Bidirectional Read Expected Data Transfer Length are + * not 0 (i.e., when some data transfer is expected, the transfer + * direction is indicated by the R and/or W bit). + */ typedef struct __attribute__((packed)) iscsi_scsi_cmd_packet { - uint8_t opcode; // Always 0x01 according to specification (see above) - int8_t flags_task; // Flags and Task Attributes - uint16_t reserved; // Reserved for future usage - uint8_t total_ahs_len; // Total AHS length - uint8_t ds_len[3]; // Data segment length - uint64_t lun; // LUN bitmask - uint32_t init_task_tag; // Initiator task tag - uint32_t exp_xfer_len; // Expected Data Transfer Length - // For unidirectional operations, the Expected Data Transfer Length - // field contains the number of bytes of data involved in this SCSI - // operation. For a unidirectional write operation (W flag set to 1 and - // R flag set to 0), the initiator uses this field to specify the number - // of bytes of data it expects to transfer for this operation. For a - // unidirectional read operation (W flag set to 0 and R flag set to 1), - // the initiator uses this field to specify the number of bytes of data - // it expects the target to transfer to the initiator. It corresponds - // to the SAM-2 byte count. - // For bidirectional operations (both R and W flags are set to 1), this - // field contains the number of data bytes involved 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 correspond to the SAM-2 byte count. - // If the Expected Data Transfer Length for a write and the length of - // the immediate data part that follows the command (if any) are the - // same, then no more data PDUs are expected to follow. In this 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. - // Upon completion of a data transfer, the target informs the initiator - // (through residual counts) of how many bytes were actually processed - // (sent and/or received) by the target. - uint32_t cmd_sn; // The CmdSN enables ordered delivery across multiple connections in a single session - uint32_t exp_stat_sn; // Command responses up to ExpStatSN - 1 (modulo 2**32) have been - // received (acknowledges status) on the connection. - struct iscsi_cdb scsi_cdb; // SCSI Command Descriptor Block (CDB) - // There are 16 bytes in the CDB field to accommodate the commonly used - // CDBs. Whenever the CDB is larger than 16 bytes, an Extended CDB AHS - // MUST be used to contain the CDB spillover. - struct iscsi_ahs_packet ahs; // Optional AHS packet data - struct iscsi_header_digest hdr_digest; // Optional header digest - struct iscsi_ds_cmd_data ds_cmd_data; // Optional data segment, command data - struct iscsi_data_digest data_digest; // Optional data digest + /// Always 1 according to the iSCSI specification. + uint8_t opcode; + + /// Flags and Task Attributes. + int8_t flags_task; + + /// Reserved for future usage, MUST always be 0. + uint16_t reserved; + + /// Total length of AHS. + uint8_t total_ahs_len; + + /// Length of DataSegment. + uint8_t ds_len[3]; + + /// SCSI LUN bit mask. + uint64_t lun; + + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; + + /** + * @brief Expected Data Transfer Length. + * + * For unidirectional operations, the Expected Data Transfer Length + * field contains the number of bytes of data involved in this SCSI + * operation. For a unidirectional write operation (W flag set to 1 and + * R flag set to 0), the initiator uses this field to specify the number + * of bytes of data it expects to transfer for this operation. For a + * unidirectional read operation (W flag set to 0 and R flag set to 1), + * the initiator uses this field to specify the number of bytes of data + * it expects the target to transfer to the initiator. It corresponds + * to the SAM-2 byte count. + * For bidirectional operations (both R and W flags are set to 1), this + * field contains the number of data bytes involved 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 correspond to the SAM-2 byte count. + * If the Expected Data Transfer Length for a write and the length of + * the immediate data part that follows the command (if any) are the + * same, then no more data PDUs are expected to follow. In this 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. + * Upon completion of a data transfer, the target informs the initiator + * (through residual counts) of how many bytes were actually processed + * (sent and/or received) by the target. + */ + uint32_t exp_xfer_len; + + /// The CmdSN enables ordered delivery across multiple connections in a single session. + uint32_t cmd_sn; + + /// Command responses up to ExpStatSN - 1 (modulo 2**32) have been received (acknowledges status) on the connection. + uint32_t exp_stat_sn; + + /** + * @brief SCSI Command Descriptor Block (CDB). + * + * There are 16 bytes in the CDB field to accommodate the commonly used + * CDBs. Whenever the CDB is larger than 16 bytes, an Extended CDB AHS + * MUST be used to contain the CDB spillover. + */ + iscsi_cdb scsi_cdb; + + /// Optional AHS packet data. + iscsi_ahs_packet ahs; + + /// Optional header digest. + iscsi_header_digest hdr_digest; + + /// Optional data segment, command data. + iscsi_ds_cmd_data ds_cmd_data; + + /// Optional data digest. + iscsi_data_digest data_digest; } iscsi_scsi_cmd_packet; -#define ISCSI_SCSI_RESPONSE_FLAGS_RES_UNDERFLOW (1 << 1) // (U) set for Residual Underflow. In this case, the Residual - // Count indicates the number of bytes that were not - // transferred out of the number of bytes that were expected - // to be transferred. For a bidirectional operation, the - // Residual Count contains the residual for the write - // operation. - -#define ISCSI_SCSI_RESPONSE_FLAGS_RES_OVERFLOW (1 << 2) // (O) set for Residual Overflow. In this case, the Residual - // Count indicates the number of bytes that were not - // transferred because the initiator's Expected Data - // Transfer Length was not sufficient. For a bidirectional - // operation, the Residual Count contains the residual for - // the write operation. - -#define ISCSI_SCSI_RESPONSE_FLAGS_BIDI_READ_RES_UNDERFLOW (1 << 3) // (u) set for Bidirectional Read Residual Underflow. In this - // case, the Bidirectional Read Residual Count indicates the - // number of bytes that were not transferred to the - // initiator out of the number of bytes expected to be - // transferred. - -#define ISCSI_SCSI_RESPONSE_FLAGS_BIDI_READ_RES_OVERFLOW (1 << 4) // (o) set for Bidirectional Read Residual Overflow. In this - // case, the Bidirectional Read Residual Count indicates the - // number of bytes that were not transferred to the - // initiator because the initiator's Bidirectional Read - // Expected Data Transfer Length was not sufficient. - -/* Bits O and U and bits o and u are mutually exclusive (i.e., having - both o and u or O and U set to 1 is a protocol error). - - For a response other than "Command Completed at Target", bits 3-6 - MUST be 0. -*/ -#define ISCSI_SCSI_RESPONSE_STATUS_GOOD 0x00 -#define ISCSI_SCSI_RESPONSE_STATUS_CHECK_COND 0x02 -#define ISCSI_SCSI_RESPONSE_STATUS_BUSY 0x08 -#define ISCSI_SCSI_RESPONSE_STATUS_RES_CONFLICT 0x18 -#define ISCSI_SCSI_RESPONSE_STATUS_TASK_SET_FULL 0x28 -#define ISCSI_SCSI_RESPONSE_STATUS_ACA_ACTIVE 0x30 -#define ISCSI_SCSI_RESPONSE_STATUS_TASK_ABORTED 0x40 - -/* The Status field is used to report the SCSI status of the command (as - specified in SAM2) and is only valid if the response code is - Command Completed at Target. - - If a SCSI device error is detected while data from the initiator is - still expected (the command PDU did not contain all the data and the - target has not 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 sending the Response PDU. -*/ +/** + * @brief SCSI response flags: Residual Underflow. + * + * (U) set for Residual Underflow. In this case, the Residual + * Count indicates the number of bytes that were not + * transferred out of the number of bytes that were expected + * to be transferred. For a bidirectional operation, the + * Residual Count contains the residual for the write + * operation. + * + * Bits O and U and bits o and u are mutually exclusive (i.e., having + * both o and u or O and U set to 1 is a protocol error). + * + * For a response other than "Command Completed at Target", bits 3-6 + * MUST be 0. + */ +#define ISCSI_SCSI_RESPONSE_FLAGS_RES_UNDERFLOW (1 << 1) + +/** + * @brief SCSI response flags: Residual Overflow. + * + * (O) set for Residual Overflow. In this case, the Residual + * Count indicates the number of bytes that were not + * transferred because the initiator's Expected Data + * Transfer Length was not sufficient. For a bidirectional + * operation, the Residual Count contains the residual for + * the write operation. + * + * Bits O and U and bits o and u are mutually exclusive (i.e., having + * both o and u or O and U set to 1 is a protocol error). + * + * For a response other than "Command Completed at Target", bits 3-6 + * MUST be 0. + */ +#define ISCSI_SCSI_RESPONSE_FLAGS_RES_OVERFLOW (1 << 2) -#define ISCSI_SCSI_RESPONSE_CODE_OK 0x00 // Command Completed at Target -#define ISCSI_SCSI_RESPONSE_CODE_FAIL 0x01 // Target Failure -#define ISCSI_SCSI_RESPONSE_CODE_VENDOR_FIRST 0x80 // First vendor specific response code -#define ISCSI_SCSI_RESPONSE_CODE_VENDOR_LAST 0xFF // Last vendor specific response code +/** + * @brief SCSI response flags: Bidirectional Read Residual Underflow. + * + * (u) set for Bidirectional Read Residual Underflow. In this + * case, the Bidirectional Read Residual Count indicates the + * number of bytes that were not transferred to the + * initiator out of the number of bytes expected to be + * transferred. + * + * Bits O and U and bits o and u are mutually exclusive (i.e., having + * both o and u or O and U set to 1 is a protocol error). + * + * For a response other than "Command Completed at Target", bits 3-6 + * MUST be 0. + */ +#define ISCSI_SCSI_RESPONSE_FLAGS_BIDI_READ_RES_UNDERFLOW (1 << 3) -/* The Response field is used to report a service response. 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 value 0x00 maps to the SCSI service response (see -*/ +/** + * @brief SCSI response flags: Bidirectional Read Residual Overflow. + * + + (o) set for Bidirectional Read Residual Overflow. In this + * case, the Bidirectional Read Residual Count indicates the + * number of bytes that were not transferred to the + * initiator because the initiator's Bidirectional Read + * Expected Data Transfer Length was not sufficient. + * + * Bits O and U and bits o and u are mutually exclusive (i.e., having + * both o and u or O and U set to 1 is a protocol error). + * + * For a response other than "Command Completed at Target", bits 3-6 + * MUST be 0. + */ +#define ISCSI_SCSI_RESPONSE_FLAGS_BIDI_READ_RES_OVERFLOW (1 << 4) + +/** + * @brief SCSI status response code: Good. + * + * The Status field is used to report the SCSI status of the command (as + * specified in SAM2) and is only valid if the response code is + * Command Completed at Target. + * + * If a SCSI device error is detected while data from the initiator is + * still expected (the command PDU did not contain all the data and the + * target has not 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 sending the Response PDU. + */ +#define ISCSI_SCSI_RESPONSE_STATUS_GOOD 0x00 + +/** + * @brief SCSI status response code: Check condition. + * + * The Status field is used to report the SCSI status of the command (as + * specified in SAM2) and is only valid if the response code is + * Command Completed at Target. + * + * If a SCSI device error is detected while data from the initiator is + * still expected (the command PDU did not contain all the data and the + * target has not 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 sending the Response PDU. + */ +#define ISCSI_SCSI_RESPONSE_STATUS_CHECK_COND 0x02 + +/** + * @brief SCSI status response code: Busy. + * + * The Status field is used to report the SCSI status of the command (as + * specified in SAM2) and is only valid if the response code is + * Command Completed at Target. + * + * If a SCSI device error is detected while data from the initiator is + * still expected (the command PDU did not contain all the data and the + * target has not 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 sending the Response PDU. + */ +#define ISCSI_SCSI_RESPONSE_STATUS_BUSY 0x08 + +/** + * @brief SCSI status response code: Residual conflict. + * + * The Status field is used to report the SCSI status of the command (as + * specified in SAM2) and is only valid if the response code is + * Command Completed at Target. + * + * If a SCSI device error is detected while data from the initiator is + * still expected (the command PDU did not contain all the data and the + * target has not 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 sending the Response PDU. + */ +#define ISCSI_SCSI_RESPONSE_STATUS_RES_CONFLICT 0x18 + +/** + * @brief SCSI status response code: Task set full. + * + * The Status field is used to report the SCSI status of the command (as + * specified in SAM2) and is only valid if the response code is + * Command Completed at Target. + * + * If a SCSI device error is detected while data from the initiator is + * still expected (the command PDU did not contain all the data and the + * target has not 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 sending the Response PDU. + */ +#define ISCSI_SCSI_RESPONSE_STATUS_TASK_SET_FULL 0x28 + +/** + * @brief SCSI status response code: ACA active. + * + * The Status field is used to report the SCSI status of the command (as + * specified in SAM2) and is only valid if the response code is + * Command Completed at Target. + * + * If a SCSI device error is detected while data from the initiator is + * still expected (the command PDU did not contain all the data and the + * target has not 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 sending the Response PDU. + */ +#define ISCSI_SCSI_RESPONSE_STATUS_ACA_ACTIVE 0x30 + +/** + * @brief SCSI status response code: Task aborted. + * + * The Status field is used to report the SCSI status of the command (as + * specified in SAM2) and is only valid if the response code is + * Command Completed at Target. + * + * If a SCSI device error is detected while data from the initiator is + * still expected (the command PDU did not contain all the data and the + * target has not 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 sending the Response PDU. + */ +#define ISCSI_SCSI_RESPONSE_STATUS_TASK_ABORTED 0x40 + +/// SCSI response code: Command Completed at Target. +#define ISCSI_SCSI_RESPONSE_CODE_OK 0x00 + +/// SCSI response code: Target Failure. +#define ISCSI_SCSI_RESPONSE_CODE_FAIL 0x01 + +/// SCSI response code: First vendor specific response code. +#define ISCSI_SCSI_RESPONSE_CODE_VENDOR_FIRST 0x80 + +/// SCSI response code: Last vendor specific response code. +#define ISCSI_SCSI_RESPONSE_CODE_VENDOR_LAST 0xFF + +/** + * @brief iSCSI SCSI command response packet data. + * + * The Response field is used to report a service response. 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 value 0x00 maps to the SCSI service response (see + */ typedef struct __attribute__((packed)) iscsi_scsi_response_packet { - uint8_t opcode; // Always 0x21 according to specification (see above) - int8_t flags; // Flags (see above) - uint8_t response; // This field contains the iSCSI service response. - uint8_t status; // The Status field is used to report the SCSI status of the command (as - // specified in SAM2) and is only valid if the response code is - // Command Completed at Target. See above for codes. - uint8_t total_ahs_len; // Total AHS length - uint8_t ds_len[3]; // Data segment length - uint64_t reserved; // Reserved for future usage - uint32_t init_task_tag; // Initiator task tag - uint32_t 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 for - // which the response is issued. Otherwise, it is reserved and should - // be set to 0. - // After issuing a R-Data SNACK, the initiator must discard any SCSI - // status unless contained in a SCSI Response PDU carrying the same - // SNACK Tag as the last issued R-Data SNACK for the SCSI command on the - // current connection. - uint32_t stat_sn; // StatSN - Status Sequence Number - // The StatSN is a sequence number that the target iSCSI layer generates - // per connection and that in turn enables the initiator to acknowledge - // status reception. The StatSN is incremented by 1 for every - // response/status sent on a connection, except for responses sent as a - // result of a retry or SNACK. In the case of responses sent due to a - // retransmission request, the StatSN MUST be the same as the first time - // the PDU was sent, unless the connection has since been restarted. - uint32_t exp_cmd_sn; // ExpCmdSN - Next Expected CmdSN from This Initiator - // The ExpCmdSN is a sequence number that the target iSCSI returns to - // the initiator to acknowledge command reception. It is used to update - // a local variable with the same name. An ExpCmdSN equal to - // MaxCmdSN + 1 indicates that the target cannot accept new commands. - uint32_t max_cmd_sn; // MaxCmdSN - Maximum CmdSN from This Initiator - // The MaxCmdSN is a sequence number that the target iSCSI returns to - // the initiator to indicate the maximum CmdSN the initiator can send. - // It is used to update a local variable with the same name. If the - // MaxCmdSN is equal to ExpCmdSN - 1, this indicates to the initiator - // that the target cannot receive any additional commands. When the - // MaxCmdSN changes at the target while the target has no pending PDUs - // to convey this information to the initiator, it MUST generate a - // NOP-In to carry the new MaxCmdSN. - uint32_t exp_data_sn; // ExpDataSN or Reserved - // This field indicates the number of 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. - uint32_t bidi_read_res_cnt; // Bidirectional Read Residual Count or Reserved - // 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 Command Completed at Target. If the o bit - // is set, the Bidirectional Read Residual Count indicates the number of - // bytes that were not transferred to the initiator because the - // initiator's Bidirectional Read Expected Data Transfer Length was not - // sufficient. If the u bit is set, the Bidirectional Read Residual - // Count indicates the number of bytes that were not transferred to the - // initiator out of the number of bytes expected to be transferred. - uint32_t res_cnt; // Residual Count or Reserved - // 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 MUST be ignored on reception and SHOULD be set to 0 when - // sending. Targets may set the residual count, and initiators may use - // it when the response code is Command Completed at Target (even if the - // status returned is not GOOD). If the O bit is set, the Residual - // Count indicates the number of bytes that were not transferred because - // the initiator's Expected Data Transfer Length was not sufficient. If - // the U bit is set, the Residual Count indicates the number of bytes - // that were not transferred out of the number of bytes expected to be - // transferred. - struct iscsi_header_digest hdr_digest; // Optional header digest - struct iscsi_ds_cmd_data ds_cmd_data; // Optional data segment, command data - struct iscsi_data_digest data_digest; // Optional data digest + /// Always 0x21 according to specification. + uint8_t opcode; + + /// Flags. + int8_t flags; + + /// This field contains the iSCSI service response. + uint8_t response; + + /// The Status field is used to report the SCSI status of the command (as specified in SAM2) and is only valid if the response code is Command Completed at Target. + uint8_t status; + + /// Total AHS length. + uint8_t total_ahs_len; + + /// Data segment length. + uint8_t ds_len[3]; + + /// Reserved for future usage. Always MUST be 0. + uint64_t reserved; + + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; + + /** + * @brief Copy of the last accepted 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 for + * which the response is issued. Otherwise, it is reserved and should + * be set to 0. + * After issuing a R-Data SNACK, the initiator must discard any SCSI + * status unless contained in a SCSI Response PDU carrying the same + * SNACK Tag as the last issued R-Data SNACK for the SCSI command on the + * current connection. + */ + uint32_t snack_tag; + + /** + * @brief StatSN - Status Sequence Number. + * + * The StatSN is a sequence number that the target iSCSI layer generates + * per connection and that in turn enables the initiator to acknowledge + * status reception. The StatSN is incremented by 1 for every + * response/status sent on a connection, except for responses sent as a + * result of a retry or SNACK. In the case of responses sent due to a + * retransmission request, the StatSN MUST be the same as the first time + * the PDU was sent, unless the connection has since been restarted. + */ + uint32_t stat_sn; + + /** + * @brief ExpCmdSN - Next Expected CmdSN from This Initiator. + * + * The ExpCmdSN is a sequence number that the target iSCSI returns to + * the initiator to acknowledge command reception. It is used to update + * a local variable with the same name. An ExpCmdSN equal to + * MaxCmdSN + 1 indicates that the target cannot accept new commands. + */ + uint32_t exp_cmd_sn; + + /** + * @brief MaxCmdSN - Maximum CmdSN from This Initiator. + * + * The MaxCmdSN is a sequence number that the target iSCSI returns to + * the initiator to indicate the maximum CmdSN the initiator can send. + * It is used to update a local variable with the same name. If the + * MaxCmdSN is equal to ExpCmdSN - 1, this indicates to the initiator + * that the target cannot receive any additional commands. When the + * MaxCmdSN changes at the target while the target has no pending PDUs + * to convey this information to the initiator, it MUST generate a + * NOP-In to carry the new MaxCmdSN. + */ + uint32_t max_cmd_sn; + + /** + * @brief ExpDataSN or Reserved. + * + * This field indicates the number of 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. + */ + uint32_t exp_data_sn; + + /** + * @brief Bidirectional Read Residual Count or Reserved. + * + * 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 Command Completed at Target. If the o bit + * is set, the Bidirectional Read Residual Count indicates the number of + * bytes that were not transferred to the initiator because the + * initiator's Bidirectional Read Expected Data Transfer Length was not + * sufficient. If the u bit is set, the Bidirectional Read Residual + * Count indicates the number of bytes that were not transferred to the + * initiator out of the number of bytes expected to be transferred. + */ + uint32_t bidi_read_res_cnt; + + /** + * @brief Residual Count or Reserved. + * + * 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 MUST be ignored on reception and SHOULD be set to 0 when + * sending. Targets may set the residual count, and initiators may use + * it when the response code is Command Completed at Target (even if the + * status returned is not GOOD). If the O bit is set, the Residual + * Count indicates the number of bytes that were not transferred because + * the initiator's Expected Data Transfer Length was not sufficient. If + * the U bit is set, the Residual Count indicates the number of bytes + * that were not transferred out of the number of bytes expected to be + * transferred. + */ + uint32_t res_cnt; + + /// Optional header digest. + iscsi_header_digest hdr_digest; + + /// Optional data segment, command data. + iscsi_ds_cmd_data ds_cmd_data; + + /// Optional data digest. + iscsi_data_digest data_digest; } iscsi_scsi_response_packet; -#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_ABORT_TASK 0x01 // ABORT TASK - aborts the task identified by the Referenced Task Tag field -#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_ABORT_TASK_SET 0x02 // ABORT TASK SET - aborts all tasks issued via this session on the LU -#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_CLEAR_ACA 0x03 // CLEAR ACA - clears the Auto Contingent Allegiance condition -#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_CLEAR_TASK_SET 0x04 // CLEAR TASK SET - aborts all tasks in the appropriate task set - // as defined by the TST field in the Control mode page - // (see SPC3) -#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_LOGICAL_UNIT_RESET 0x05 // LOGICAL UNIT RESET -#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_TARGET_WARM_RESET 0x06 // TARGET WARM RESET -#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_TARGET_COLD_RESET 0x07 // TARGET COLD RESET -#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_TASK_REASSIGN 0x08 // TASK REASSIGN - reassigns connection allegiance for the task - // identified by the Initiator Task Tag field to this connection, - // thus resuming the iSCSI exchanges for the task + +/// Task management request function: ABORT TASK: aborts the task identified by the Referenced Task Tag field. +#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_ABORT_TASK 0x01 + +/// Task management request function: ABORT TASK SET: aborts all tasks issued via this session on the LU. +#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_ABORT_TASK_SET 0x02 + +/// Task management request function: CLEAR ACA - clears the Auto Contingent Allegiance condition. +#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_CLEAR_ACA 0x03 + +/// Task management request function: CLEAR TASK SET - aborts all tasks in the appropriate task set as defined by the TST field in the Control mode page (see SPC3). +#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_CLEAR_TASK_SET 0x04 + +/// Task management request function: LOGICAL UNIT RESET. +#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_LOGICAL_UNIT_RESET 0x05 + +/// Task management request function: TARGET WARM RESET. +#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_TARGET_WARM_RESET 0x06 + +/// Task management request function: TARGET COLD RESET. +#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_TARGET_COLD_RESET 0x07 + +/// Task management request function: TASK REASSIGN - reassigns connection allegiance for the task identified by the Initiator Task Tag field to this connection, thus resuming the iSCSI exchanges for the task. +#define ISCSI_TASK_MGMT_FUNC_REQ_FUNC_TASK_REASSIGN 0x08 typedef struct __attribute__((packed)) iscsi_task_mgmt_func_req_packet { - uint8_t opcode; // Always 0x02 according to specification (see above) - int8_t func; // Function. - // The task management functions provide an initiator with a way to - // explicitly control the execution of one or more tasks (SCSI and iSCSI - // tasks). The task management function codes are listed below. For a - // more detailed description of SCSI task management, see SAM2. - uint16_t reserved; // Reserved for future usage - uint8_t total_ahs_len; // TotalAHSLength (MUST be 0 for this PDU) - uint8_t ds_len[3]; // DataSegmentLength (MUST be 0 for this PDU) - uint64_t lun; // Logical Unit Number (LUN) or Reserved - // 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 others - uint32_t init_task_tag; // Initiator task tag - // This is the Initiator Task Tag of the task to be aborted for the - // ABORT TASK function or reassigned for the TASK REASSIGN function. - // For all the other functions, this field MUST be set to the reserved - // value 0xFFFFFFFF - uint32_t ref_task_tag; // Referenced task tag or 0xFFFFFFFF - uint32_t cmd_sn; // CmdSN - uint32_t exp_stat_sn; // ExpStatSN - uint32_t ref_cmd_sn; // RefCmdSN or Reserved - // If an ABORT TASK is issued for a task created by an immediate - // command, then the RefCmdSN MUST be that of the task management - // request itself (i.e., the CmdSN and RefCmdSN are equal). - // For an ABORT TASK of a task created by a non-immediate command, the - // RefCmdSN MUST be set to the CmdSN of the task identified by the - // Referenced Task Tag field. Targets must use this field when the task - // identified by the Referenced Task Tag field is not with the target. - // Otherwise, this field is reserved - uint32_t exp_data_sn; // ExpDataSN or Reserved - // For recovery purposes, the iSCSI target and initiator maintain a data - // acknowledgment reference number - the first input DataSN number - // unacknowledged by the initiator. When issuing a new command, this - // number is set to 0. If the function is TASK REASSIGN, which - // establishes a new connection allegiance for a previously issued read - // or bidirectional command, the ExpDataSN will contain an updated data - // acknowledgment reference number or the value 0; the latter indicates - // that the data acknowledgment reference number is unchanged. The - // initiator MUST discard any data PDUs from the previous execution that - // it did not acknowledge, and the target MUST transmit all Data-In PDUs - // (if any) starting with the data acknowledgment reference number. The - // number of retransmitted PDUs may or may not be the same as the - // original transmission, depending on if there was a change in - // MaxRecvDataSegmentLength in the reassignment. The target MAY also - // send no more Data-In PDUs if all data has 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. - // For other functions, this field is reserved - uint64_t reserved2; // Reserved for future usage - struct iscsi_header_digest hdr_digest; // Optional header digest + /// Always 2 according to iSCSI specification. + uint8_t opcode; + + /** + * @brief Function. + * + * The task management functions provide an initiator with a way to + * explicitly control the execution of one or more tasks (SCSI and iSCSI + * tasks). The task management function codes are listed below. For a + * more detailed description of SCSI task management, see SAM2. + */ + int8_t func; + + /// Reserved fot future usage, always MUST be 0. + uint16_t reserved; + + /// TotalAHSLength (MUST be 0 for this PDU). + uint8_t total_ahs_len; + + /// DataSegmentLength (MUST be 0 for this PDU). + uint8_t ds_len[3]; + + /** + * @brief Logical Unit Number (LUN) or Reserved. + * + * 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 others + */ + uint64_t lun; + + /** + * @brief Initiator Task Tag (ITT). + * + * This is the Initiator Task Tag of the task to be aborted for the + * ABORT TASK function or reassigned for the TASK REASSIGN function. + * For all the other functions, this field MUST be set to the reserved + * value 0xFFFFFFFF. + */ + uint32_t init_task_tag; + + /// Referenced task tag or 0xFFFFFFFF. + uint32_t ref_task_tag; + + /// CmdSN. + uint32_t cmd_sn; + + /// ExpStatSN + uint32_t exp_stat_sn; + + /** + * @brief RefCmdSN or Reserved. + * + * If an ABORT TASK is issued for a task created by an immediate + * command, then the RefCmdSN MUST be that of the task management + * request itself (i.e., the CmdSN and RefCmdSN are equal). + * For an ABORT TASK of a task created by a non-immediate command, the + * RefCmdSN MUST be set to the CmdSN of the task identified by the + * Referenced Task Tag field. Targets must use this field when the task + * identified by the Referenced Task Tag field is not with the target. + * Otherwise, this field is reserved. + */ + uint32_t ref_cmd_sn; + + /** + * @brief ExpDataSN or Reserved. + * + * For recovery purposes, the iSCSI target and initiator maintain a data + * acknowledgment reference number - the first input DataSN number + * unacknowledged by the initiator. When issuing a new command, this + * number is set to 0. If the function is TASK REASSIGN, which + * establishes a new connection allegiance for a previously issued read + * or bidirectional command, the ExpDataSN will contain an updated data + * acknowledgment reference number or the value 0; the latter indicates + * that the data acknowledgment reference number is unchanged. The + * initiator MUST discard any data PDUs from the previous execution that + * it did not acknowledge, and the target MUST transmit all Data-In PDUs + * (if any) starting with the data acknowledgment reference number. The + * number of retransmitted PDUs may or may not be the same as the + * original transmission, depending on if there was a change in + * MaxRecvDataSegmentLength in the reassignment. The target MAY also + * send no more Data-In PDUs if all data has 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. + * For other functions, this field is reserved + */ + uint32_t exp_data_sn; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved2; + + /// Optional header digest. + iscsi_header_digest hdr_digest; } iscsi_task_mgmt_func_req_packet; #define ISCSI_TASK_MGMT_FUNC_RESPONSE_FUNC_COMPLETE 0x00 // Function complete @@ -676,14 +1295,17 @@ typedef struct __attribute__((packed)) iscsi_task_mgmt_func_req_packet { #define ISCSI_TASK_MGMT_FUNC_RESPONSE_FUNC_AUTH_FAILED 0x06 // Function authorization failed #define ISCSI_TASK_MGMT_FUNC_RESPONSE_FUNC_REJECTED 0xFF // Function rejected -/* 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. -*/ +/** + * @brief iSCSI Task Management Function response packet data. + * + * 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. + */ typedef struct __attribute__((packed)) iscsi_task_mgmt_func_response_packet { uint8_t opcode; // Always 0x22 according to specification (see above) int8_t flags; // Reserved for future usage (must be always 0x80 for now) @@ -895,58 +1517,61 @@ typedef struct __attribute__((packed)) iscsi_scsi_data_in_response_packet { struct iscsi_data_digest data_digest; // Optional data digest } iscsi_scsi_data_in_response_packet; -/* 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. - - 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 the - 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 - the "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. - - The target may send several R2T PDUs. It therefore can have a number - of pending data transfers. The number of outstanding R2T PDUs is - limited by the value of the negotiated key MaxOutstandingR2T. Within - a task, outstanding R2Ts MUST be fulfilled by the initiator in the - order in which they were received. - - 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. - - 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. -*/ +/** + * @brief iSCSI Ready To Transfer packet data. + * + * 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. + * + * 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 the + * 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 + * the "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. + * + * The target may send several R2T PDUs. It therefore can have a number + * of pending data transfers. The number of outstanding R2T PDUs is + * limited by the value of the negotiated key MaxOutstandingR2T. Within + * a task, outstanding R2Ts MUST be fulfilled by the initiator in the + * order in which they were received. + * + * 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. + * + * 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. + */ typedef struct __attribute__((packed)) iscsi_r2t_packet { uint8_t opcode; // Always 0x31 according to specification (see above) int8_t flags; // Reserved for future usage (must be always 0x80 for now) @@ -1062,12 +1687,15 @@ typedef struct __attribute__((packed)) iscsi_r2t_packet { #define ISCSI_ASYNC_MSG_EVENT_VENDOR_LAST 0xFF // Last vendor-specific iSCSI event. The AsyncVCode details the // vendor code, and data MAY accompany the report -/* An Asynchronous Message may be sent from the target to the initiator - without corresponding to a particular command. The target specifies - the reason for the event and sense data. - Some Asynchronous Messages are strictly related to iSCSI, while - others are related to SCSI -*/ +/** + * @brief iSCSI Asynchronous Message packet data. + * + * An Asynchronous Message may be sent from the target to the initiator + * without corresponding to a particular command. The target specifies + * the reason for the event and sense data. + * Some Asynchronous Messages are strictly related to iSCSI, while + * others are related to SCSI + */ typedef struct __attribute__((packed)) iscsi_async_msg_packet { uint8_t opcode; // Always 0x32 according to specification (see above int8_t flags; // Reserved for future usage (must be always 0x80 for now) @@ -1096,16 +1724,19 @@ typedef struct __attribute__((packed)) iscsi_async_msg_packet { struct iscsi_data_digest data_digest; // Optional data digest } iscsi_async_msg_packet; -/* For a SCSI event, this data accompanies 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 not understood, - while processing the rest of the PDU. - - If the DataSegmentLength is not 0, the format of the DataSegment is - as follows: -*/ +/** + * @brief iSCSI Sense Event data packet. + * + * For a SCSI event, this data accompanies 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 not understood, + * while processing the rest of the PDU. + * + * If the DataSegmentLength is not 0, the format of the DataSegment is + * as follows: + */ typedef struct __attribute__((packed)) iscsi_sense_event_data_packet { uint16_t sense_len; // SenseLength // This is the length of Sense Data. When the Sense Data field is empty @@ -1123,17 +1754,20 @@ typedef struct __attribute__((packed)) iscsi_sense_event_data_packet { // Request in a sequence of Text Requests; otherwise, it indicates that // more Text Requests will follow. -/* The Text Request is provided to allow for the exchange of information - and for future extensions. It permits the initiator to inform a - target of its capabilities or request some special operations. - - An initiator MUST NOT have more than 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 cause such a task to be - implicitly terminated by the target. -*/ +/** + * @brief iSCSI Text Request packet data. + * + * The Text Request is provided to allow for the exchange of information + * and for future extensions. It permits the initiator to inform a + * target of its capabilities or request some special operations. + * + * An initiator MUST NOT have more than 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 cause such a task to be + * implicitly terminated by the target. + */ typedef struct __attribute__((packed)) iscsi_text_req_packet { uint8_t opcode; // Always 0x04 according to specification (see above) int8_t flags; // Text request flags (see above) @@ -1216,10 +1850,13 @@ typedef struct __attribute__((packed)) iscsi_text_req_packet { // 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 value 0xFFFFFFFF -/* The Text Response PDU contains the target's responses to the - initiator's Text Request. The format of the Text field matches that - of the Text Request. -*/ +/** + * @brief iSCSI Text Response packet data. + * + * The Text Response PDU contains the target's responses to the + * initiator's Text Request. The format of the Text field matches that + * of the Text Request. + */ typedef struct __attribute__((packed)) iscsi_text_response_packet { uint8_t opcode; // Always 0x24 according to specification (see above) int8_t flags; // Text response flags (see above) @@ -2102,32 +2739,35 @@ typedef struct __attribute__((packed)) iscsi_text_response_packet { // implementation MUST NOT respond with a "NotUnderstood" value for // either of these keys -/* This is an initiator-defined component of the session identifier and - is structured as follows: - - For the T field values 00b and 01b, a combination of A and B (for - 00b) or B and C (for 01b) identifies the vendor or organization whose - component (software or hardware) generates this ISID. A vendor or - organization with one or more OUIs, or one or more Enterprise - Numbers, MUST use at least one of these numbers and select the - appropriate value for the T field when its components generate ISIDs. - An OUI or EN MUST be set in the corresponding fields in network byte - order (byte big-endian). - - If the T field is 10b, B and C are set to a random 24-bit unsigned - integer value in network byte order (byte big-endian). - - The Qualifier field is a 16-bit or 24-bit unsigned integer value that - provides a range of possible values for the ISID within the selected - namespace. It may be set to any value within the constraints - specified in the iSCSI protocol. - - If the ISID is derived from something assigned to a hardware adapter - or interface by a vendor as a preset default value, it MUST be - configurable to a value assigned according to the SCSI port behavior - desired by the system in which it is installed. The resultant ISID - MUST also be persistent over power cycles, reboot, card swap, etc. -*/ +/** + * @brief iSCSI ISID packet data. + * + * This is an initiator-defined component of the session identifier and + * is structured as follows: + * + * For the T field values 00b and 01b, a combination of A and B (for + * 00b) or B and C (for 01b) identifies the vendor or organization whose + * component (software or hardware) generates this ISID. A vendor or + * organization with one or more OUIs, or one or more Enterprise + * Numbers, MUST use at least one of these numbers and select the + * appropriate value for the T field when its components generate ISIDs. + * An OUI or EN MUST be set in the corresponding fields in network byte + * order (byte big-endian). + * + * If the T field is 10b, B and C are set to a random 24-bit unsigned + * integer value in network byte order (byte big-endian). + * + * The Qualifier field is a 16-bit or 24-bit unsigned integer value that + * provides a range of possible values for the ISID within the selected + * namespace. It may be set to any value within the constraints + * specified in the iSCSI protocol. + * + * If the ISID is derived from something assigned to a hardware adapter + * or interface by a vendor as a preset default value, it MUST be + * configurable to a value assigned according to the SCSI port behavior + * desired by the system in which it is installed. The resultant ISID + * MUST also be persistent over power cycles, reboot, card swap, etc. + */ typedef struct __attribute__((packed)) iscsi_isid { uint8_t a; // Meaning depends on T bit (see above) uint16_t b; // Meaning depends on T bit (see above) @@ -2165,15 +2805,18 @@ typedef struct __attribute__((packed)) iscsi_isid { // this also indicates that the initiator is ready for the Login // Final-Response. -/* After establishing a TCP connection between an initiator and a - target, the initiator MUST start a Login Phase to gain further access - to the target's resources. - - The Login Phase consists of a sequence of Login Requests and Login - Responses that carry the same Initiator Task Tag. - - Login Requests are always considered as immediate. -*/ +/** + * @brief iSCSI Login Request packet data. + * + * After establishing a TCP connection between an initiator and a + * target, the initiator MUST start a Login Phase to gain further access + * to the target's resources. + * + * The Login Phase consists of a sequence of Login Requests and Login + * Responses that carry the same Initiator Task Tag. + * + * Login Requests are always considered as immediate. + */ typedef struct __attribute__((packed)) iscsi_login_req_packet { uint8_t opcode; // Always 0x03 according to specification (see above) int8_t flags; // Login request flags (see above) @@ -2332,9 +2975,12 @@ typedef struct __attribute__((packed)) iscsi_login_req_packet { #define ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES 0x02 // The target has insufficient session, // connection, or other resources -/* The Login Response indicates the progress and/or end of the Login - Phase. -*/ +/** + * @brief iSCSI Login Response packet data. + * + * The Login Response indicates the progress and/or end of the Login + * Phase. + */ typedef struct __attribute__((packed)) iscsi_login_response_packet { uint8_t opcode; // Always 0x23 according to specification (see above) int8_t flags; // Login response flags (see above) @@ -2403,62 +3049,65 @@ typedef struct __attribute__((packed)) iscsi_login_response_packet { #define ISCSI_LOGOUT_REQ_REASON_CODE_IMPLICIT_CONNECTION_REINSTATEMENT_2 0x02 // connection reinstatement when the operational // ErrorRecoveryLevel = 2 -/* The Logout Request is used to perform a controlled closing of a - connection. - - 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 intended to close the session, new iSCSI requests MUST NOT be sent - on any of the connections participating in the session. - - When receiving a Logout Request with the reason code "close the - connection" or "close the session", the target MUST terminate all - pending commands, whether acknowledged via the ExpCmdSN or not, on - that connection or session, respectively. - - When receiving a Logout Request with the reason code "remove the - connection for recovery", the target MUST discard all requests not - yet acknowledged via the ExpCmdSN that were issued on the specified - connection and suspend all data/status/R2T transfers on behalf of - pending commands on the specified connection. - - The target then issues the Logout Response and half-closes the TCP - connection (sends FIN). After receiving the Logout Response and - attempting to receive the FIN (if still possible), the initiator MUST - completely close the logging-out connection. For the terminated - commands, no additional responses should be expected. - - A Logout for a CID may be performed on a different transport - connection when the TCP connection for the CID has already been - terminated. In such a case, only a logical "closing" of the iSCSI - connection for the CID is implied with a Logout. - - All commands that were not terminated or not completed (with status) - and acknowledged when the connection is closed completely can be - reassigned to a new connection if the target supports connection - recovery. - - If an initiator intends to start recovery for a failing connection, - it MUST use the Logout Request to "clean up" the target end of a - failing connection and enable recovery to start, or use the Login - Request with a non-zero TSIH and the same CID on a new connection for - the same effect. In sessions with a single connection, the - connection can be closed and then a new connection reopened. A - connection reinstatement login can be used for recovery. - - A successful completion of a Logout Request with the reason code - "close the connection" or "remove the connection for recovery" - results at the target in the discarding of unacknowledged commands - received on the connection being logged out. These are commands that - have arrived on the connection being logged out but that have not - been delivered to SCSI because one or more commands with a smaller - CmdSN have not been received by iSCSI. The resulting holes in the - command sequence numbers will have to be handled by appropriate - recovery, unless the session is also closed. -*/ +/** + * @brief iSCSI Logout Request packet data. + * + * The Logout Request is used to perform a controlled closing of a + * connection. + * + * 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 intended to close the session, new iSCSI requests MUST NOT be sent + * on any of the connections participating in the session. + * + * When receiving a Logout Request with the reason code "close the + * connection" or "close the session", the target MUST terminate all + * pending commands, whether acknowledged via the ExpCmdSN or not, on + * that connection or session, respectively. + * + * When receiving a Logout Request with the reason code "remove the + * connection for recovery", the target MUST discard all requests not + * yet acknowledged via the ExpCmdSN that were issued on the specified + * connection and suspend all data/status/R2T transfers on behalf of + * pending commands on the specified connection. + * + * The target then issues the Logout Response and half-closes the TCP + * connection (sends FIN). After receiving the Logout Response and + * attempting to receive the FIN (if still possible), the initiator MUST + * completely close the logging-out connection. For the terminated + * commands, no additional responses should be expected. + * + * A Logout for a CID may be performed on a different transport + * connection when the TCP connection for the CID has already been + * terminated. In such a case, only a logical "closing" of the iSCSI + * connection for the CID is implied with a Logout. + * + * All commands that were not terminated or not completed (with status) + * and acknowledged when the connection is closed completely can be + * reassigned to a new connection if the target supports connection + * recovery. + * + * If an initiator intends to start recovery for a failing connection, + * it MUST use the Logout Request to "clean up" the target end of a + * failing connection and enable recovery to start, or use the Login + * Request with a non-zero TSIH and the same CID on a new connection for + * the same effect. In sessions with a single connection, the + * connection can be closed and then a new connection reopened. A + * connection reinstatement login can be used for recovery. + * + * A successful completion of a Logout Request with the reason code + * "close the connection" or "remove the connection for recovery" + * results at the target in the discarding of unacknowledged commands + * received on the connection being logged out. These are commands that + * have arrived on the connection being logged out but that have not + * been delivered to SCSI because one or more commands with a smaller + * CmdSN have not been received by iSCSI. The resulting holes in the + * command sequence numbers will have to be handled by appropriate + * recovery, unless the session is also closed. + */ typedef struct __attribute__((packed)) iscsi_logout_req_packet { uint8_t opcode; // Always 0x06 according to specification (see above) int8_t reason_code; // Reason Code @@ -2513,13 +3162,16 @@ typedef struct __attribute__((packed)) iscsi_logout_req_packet { // ErrorRecoveryLevel) #define ISCSI_LOGOUT_RESPONSE_CLEANUP_FAILED 0x03 // Cleanup failed for various reasons -/* The Logout Response is used by the target to indicate if the cleanup - operation for the connection(s) has completed. - - After Logout, the TCP connection referred by the CID MUST be closed - at both ends (or all connections must be closed if the logout reason - was session close). -*/ +/** + * @brief iSCSI Logout Response packet data. + * + * The Logout Response is used by the target to indicate if the cleanup + * operation for the connection(s) has completed. + * + * After Logout, the TCP connection referred by the CID MUST be closed + * at both ends (or all connections must be closed if the logout reason + * was session close). + */ typedef struct __attribute__((packed)) iscsi_logout_response_packet { uint8_t opcode; // Always 0x26 according to specification (see above) int8_t flags; // Reserved for future usage (must be always 0x80 for now) @@ -2611,39 +3263,42 @@ typedef struct __attribute__((packed)) iscsi_logout_response_packet { // For considerations in allegiance reassignment of a task to a // connection with a different MaxRecvDataSegmentLength. -/* If the implementation supports ErrorRecoveryLevel greater than zero, - it MUST support all SNACK types. - - The SNACK is used by the initiator to request the retransmission of - numbered responses, data, or R2T PDUs from the target. The SNACK - Request indicates the numbered responses or data "runs" whose - retransmission is requested, where the run starts with the first - StatSN, DataSN, or R2TSN whose retransmission is requested and - indicates the number of Status, Data, or R2T PDUs requested, - including the first. 0 has special meaning when used as a starting - number and length: - - - When used in RunLength, it means all PDUs starting with the - initial. - - - When 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 that the target transmitted - 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 the StatSN. - - The numbered Data-In PDUs requested by a Data SNACK MUST be delivered - as exact replicas of the ones that the target transmitted originally, - except for the fields ExpCmdSN and MaxCmdSN, which MUST carry the - current values; and except for 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". -*/ +/** + * @brief iSCSI SNACK Request packet data. + * + * If the implementation supports ErrorRecoveryLevel greater than zero, + * it MUST support all SNACK types. + * + * The SNACK is used by the initiator to request the retransmission of + * numbered responses, data, or R2T PDUs from the target. The SNACK + * Request indicates the numbered responses or data "runs" whose + * retransmission is requested, where the run starts with the first + * StatSN, DataSN, or R2TSN whose retransmission is requested and + * indicates the number of Status, Data, or R2T PDUs requested, + * including the first. 0 has special meaning when used as a starting + * number and length: + * + * - When used in RunLength, it means all PDUs starting with the + * initial. + * + * - When 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 that the target transmitted + * 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 the StatSN. + * + * The numbered Data-In PDUs requested by a Data SNACK MUST be delivered + * as exact replicas of the ones that the target transmitted originally, + * except for the fields ExpCmdSN and MaxCmdSN, which MUST carry the + * current values; and except for 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". + */ typedef struct __attribute__((packed)) iscsi_snack_req_packet { uint8_t opcode; // Always 0x10 according to specification (see above) int8_t type; // Type @@ -2758,24 +3413,27 @@ typedef struct __attribute__((packed)) iscsi_reject_packet { struct iscsi_data_digest data_digest; // Optional data digest } iscsi_reject_packet; -/* NOP-Out may be used by an initiator as a "ping request" to verify - that a connection/session is still active and all its components are - operational. The NOP-In response is the "ping echo". - - A NOP-Out is also sent by an initiator 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 value 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. The initiator - - SHOULD NOT send a NOP-Out in response to any other received NOP-In, - in order to avoid lengthy sequences of NOP-In and NOP-Out PDUs sent - in response to each other. -*/ +/** + * @brief iSCSI NOP-Out packet data. + * + * NOP-Out may be used by an initiator as a "ping request" to verify + * that a connection/session is still active and all its components are + * operational. The NOP-In response is the "ping echo". + * + * A NOP-Out is also sent by an initiator 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 value 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. The initiator + * + * SHOULD NOT send a NOP-Out in response to any other received NOP-In, + * in order to avoid lengthy sequences of NOP-In and NOP-Out PDUs sent + * in response to each other. + */ typedef struct __attribute__((packed)) iscsi_nop_out_packet { uint8_t opcode; // Always 0x00 according to specification (see above) int8_t flags; // Reserved for future usage (must be always 0x80 for now) @@ -2811,28 +3469,30 @@ typedef struct __attribute__((packed)) iscsi_nop_out_packet { struct iscsi_data_digest data_digest; // Optional data digest } iscsi_nop_out_packet; -/* NOP-In is sent by a target as either a response to a NOP-Out, a - "ping" to an initiator, or a means to carry a changed ExpCmdSN and/or - MaxCmdSN if another PDU will not be available for a long time (as - determined by the target). - - When a target receives the NOP-Out with a valid Initiator Task Tag - (not the reserved value 0xFFFFFFFF), it MUST respond with a NOP-In - with the same Initiator Task Tag that was provided in the NOP-Out - request. It MUST also duplicate up to the first - MaxRecvDataSegmentLength bytes of the initiator-provided Ping Data. - For such a response, the Target Transfer Tag MUST be 0xFFFFFFFF. The - - target SHOULD NOT send a NOP-In in response to any other received - NOP-Out in order to avoid lengthy sequences of NOP-In and NOP-Out - PDUs sent in response to each other. - - Otherwise, when a target sends a NOP-In that is not a response to a - NOP-Out received 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). -*/ - +/** + * @brief iSCSI NOP-In packet data. + * + * NOP-In is sent by a target as either a response to a NOP-Out, a + * "ping" to an initiator, or a means to carry a changed ExpCmdSN and/or + * MaxCmdSN if another PDU will not be available for a long time (as + * determined by the target). + * + * When a target receives the NOP-Out with a valid Initiator Task Tag + * (not the reserved value 0xFFFFFFFF), it MUST respond with a NOP-In + * with the same Initiator Task Tag that was provided in the NOP-Out + * request. It MUST also duplicate up to the first + * MaxRecvDataSegmentLength bytes of the initiator-provided Ping Data. + * For such a response, the Target Transfer Tag MUST be 0xFFFFFFFF. The + * + * target SHOULD NOT send a NOP-In in response to any other received + * NOP-Out in order to avoid lengthy sequences of NOP-In and NOP-Out + * PDUs sent in response to each other. + * + * Otherwise, when a target sends a NOP-In that is not a response to a + * NOP-Out received 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). + */ typedef struct __attribute__((packed)) iscsi_nop_in_packet { uint8_t opcode; // Always 0x20 according to specification (see above) int8_t flags; // Reserved for future usage (must be always 0x80 for now) @@ -2900,15 +3560,36 @@ int iscsi_validate_packet(const struct iscsi_bhs_packet *packet_data, const uint #define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_BOOL_OR 6L // Boolean OR #define ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_BOOL_AND 7L // Boolean AND +/** + * @brief iSCSI Text / Login extracted key=value pair. + * + * This structure is used for accessing key and value + * pairs which have been extracted from either the + * Text or Login packet data. + */ typedef struct iscsi_key_value_pair { - int type; // Type of pair (see above) + /// Type of key and value pair. + int type; + + /// State index. int state_index; - uint8_t *value; // Value of key + + /// Value of the key which is stored in the hash map. + uint8_t *value; } iscsi_key_value_pair; +/** + * @brief iSCSI Text / Login key=value packet data construction helper. + * + * This structure is used to store the key=value plus NUL terminator + * pairs for sending as DataSegment packet data to the client. + */ typedef struct iscsi_key_value_pair_packet { - uint8_t *buf; // Current text buffer containing multiple zeroes - uint len; // Current length of buffer including final zero terminator + /// Current text buffer containing multiple key=value + NUL terminator pairs. + uint8_t *buf; + + /// Current length of buffer including final NUL terminator without iSCSI zero padding. + uint len; } iscsi_key_value_pair_packet; static int iscsi_parse_text_key_value_pair(iscsi_hashmap *pairs, const uint8_t *packet_data, const uint32_t len); // Extracts a single text key / value pairs out of an iSCSI packet into a hash map @@ -2916,6 +3597,14 @@ int iscsi_parse_key_value_pairs(iscsi_hashmap *pairs, const uint8_t *packet_data int iscsi_create_key_value_pair_packet_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Creates a single partial iSCSI packet stream out of a single text key and value pair iscsi_key_value_pair_packet *iscsi_create_key_value_pairs_packet(const iscsi_hashmap *pairs); // Creates a properly aligned iSCSI packet DataSegment out of a hash map containing text key and value pairs +/** + * @brief iSCSI incoming connection. + * + * This structure is used for maintaining incoming iSCSI + * connections. Negiotiated text key=value pairs are + * stored here, status of the connection, session + * and iSCSI portals. + */ typedef struct iscsi_connection { iscsi_hashmap *key_value_pairs; // Hash map containing text key / value pairs associated to this connection int header_digest; // iSCSI connection contains a header digest (CRC32), must be 0 or 4 for now |
