diff options
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/image.c | 2 | ||||
| -rw-r--r-- | src/server/iscsi.c | 1677 | ||||
| -rw-r--r-- | src/server/iscsi.h | 5822 | ||||
| -rw-r--r-- | src/server/net.c | 16 | ||||
| -rw-r--r-- | src/server/sendfile.c | 60 | ||||
| -rw-r--r-- | src/server/sendfile.h | 18 | ||||
| -rw-r--r-- | src/server/server.c | 7 |
7 files changed, 2287 insertions, 5315 deletions
diff --git a/src/server/image.c b/src/server/image.c index a2ff247..5d1f4a1 100644 --- a/src/server/image.c +++ b/src/server/image.c @@ -1361,7 +1361,7 @@ server_fail: ; image_release( image ); } // If everything worked out, this call should now actually return the image - image = image_get( name, acceptedRemoteRid, false ); + image = image_get( name, revision == 0 ? acceptedRemoteRid : revision, false ); if ( image != NULL && uplinkSock != -1 ) { // If so, init the uplink and pass it the socket if ( !uplink_init( image, uplinkSock, &uplinkServer, remoteProtocolVersion ) ) { diff --git a/src/server/iscsi.c b/src/server/iscsi.c index cc08e29..2b39955 100644 --- a/src/server/iscsi.c +++ b/src/server/iscsi.c @@ -72,11 +72,6 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task); static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task); - - - - - static void iscsi_scsi_task_create(iscsi_scsi_task *scsi_task); // Allocates and initializes a SCSI task static void iscsi_scsi_task_xfer_complete(iscsi_scsi_task *scsi_task, iscsi_pdu *pdu); // Callback function when an iSCSI SCSI task completed the data transfer @@ -89,15 +84,9 @@ static int iscsi_scsi_lun_get_from_iscsi(const uint64_t lun); // Converts an iSC static void iscsi_scsi_lun_task_run( iscsi_scsi_task *scsi_task, iscsi_pdu *pdu); // Runs an iSCSI SCSI task for a specified iSCSI SCSI LUN -static int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size); // Reads a number of blocks from a block offset of a DNBD3 image to a specified buffer - +static int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks); // Reads a number of blocks from a block offset of a DNBD3 image to a specified buffer - -static uint8_t *iscsi_vsprintf_append_realloc(char *buf, const char *format, va_list args); // Allocates and appends a buffer and sprintf's it -static uint8_t *iscsi_sprintf_append_realloc(char *buf, const char *format, ...); // Allocates and appends a buffer and sprintf's it -static uint8_t *iscsi_vsprintf_alloc(const char *format, va_list args); // Allocates a buffer and sprintf's it -static uint8_t *iscsi_sprintf_alloc(const char *format, ... ); // Allocates a buffer and sprintf's it static void iscsi_strcpy_pad(char *dst, const char *src, const size_t size, const int pad); // Copies a string with additional padding character to fill in a specified size @@ -107,129 +96,25 @@ static void iscsi_task_destroy(iscsi_task *task); // Deallocates resources acqui static void iscsi_task_response(iscsi_connection *conn, iscsi_task *task, iscsi_pdu *pdu); // Creates, initializes and sends an iSCSI task reponse PDU. static uint64_t iscsi_target_node_wwn_get(const uint8_t *name); // Calculates the WWN using 64-bit IEEE Extended NAA for a name -static dnbd3_image_t *iscsi_target_node_image_get(uint8_t *iqn); // Extracts the DNBD3 image out of an iSCSI IQN string and opens the DNBD3 image static iscsi_session *iscsi_session_create(iscsi_connection *conn, const int type); // Creates and initializes an iSCSI session static void iscsi_session_destroy(iscsi_session *session); // Deallocates all resources acquired by iscsi_session_create -static iscsi_connection *iscsi_connection_create(dnbd3_client_t *sock); // Creates data structure for an iSCSI connection from iSCSI portal and TCP/IP socket +static iscsi_connection *iscsi_connection_create(dnbd3_client_t *client); // Creates data structure for an iSCSI connection from iSCSI portal and TCP/IP socket static void iscsi_connection_destroy(iscsi_connection *conn); // Deallocates all resources acquired by iscsi_connection_create static int32_t iscsi_connection_read(const iscsi_connection *conn, uint8_t *buf, const uint32_t len); // Reads data for the specified iSCSI connection from its TCP socket -static int32_t iscsi_connection_write(const iscsi_connection *conn, uint8_t *buf, const uint32_t len); // Writes data for the specified iSCSI connection to its TCP socket static void iscsi_connection_login_response_reject(iscsi_pdu *login_response_pdu, const iscsi_pdu *pdu); // Initializes a rejecting login response packet -static iscsi_pdu *iscsi_connection_pdu_create(iscsi_connection *conn, const uint ahs_len, const int header_digest_size, const uint32_t ds_len, const int data_digest_size); +static iscsi_pdu *iscsi_connection_pdu_create(iscsi_connection *conn, const uint32_t ds_len); static void iscsi_connection_pdu_destroy(iscsi_pdu *pdu); // Destroys an iSCSI PDU structure used by connections -static iscsi_bhs_packet *iscsi_connection_pdu_append(iscsi_pdu *pdu, const uint ahs_len, const int header_digest_size, const uint32_t ds_len, const int data_digest_size); // Appends packet data to an iSCSI PDU structure used by connections - -static void iscsi_connection_pdu_digest_header_update(iscsi_header_digest *header_digest, const iscsi_bhs_packet *packet_data, const uint ahs_len); // Calculate and store iSCSI header digest (CRC32C) -static bool iscsi_connection_pdu_digest_header_verify(const iscsi_header_digest *header_digest, const iscsi_bhs_packet *packet_data, const uint ahs_len); // Validates a stored iSCSI header digest (CRC32C) with actual header data -static void iscsi_connection_pdu_digest_data_update(iscsi_data_digest *data_digest, const iscsi_scsi_ds_cmd_data *ds_cmd_data, const uint32_t ds_len); // Calculate iSCSI data digest (CRC32C) -static bool iscsi_connection_pdu_digest_data_verify(const iscsi_data_digest *data_digest, const iscsi_scsi_ds_cmd_data *ds_cmd_data, const uint32_t ds_len); // Validates a stored iSCSI data digest (CRC32C) with actual DataSegment +static iscsi_bhs_packet *iscsi_connection_pdu_resize(iscsi_pdu *pdu, const uint ahs_len, const uint32_t ds_len); // Appends packet data to an iSCSI PDU structure used by connections static bool iscsi_connection_pdu_write(iscsi_connection *conn, iscsi_pdu *pdu); - -/** - * @brief Allocates and appends a buffer and sprintf's it. - * - * Merges multiple strings using printf style formatting - * and allocates memory for holding the result. - * - * @param[in] buf Buffer to merge into. - * @param[in] format printf style format string. - * @param[in] args Values to fill in the format with. - * @return New buffer which holds the final result. - */ -static uint8_t *iscsi_vsprintf_append_realloc(char *buf, const char *format, va_list args) -{ - va_list args_copy; - uint orig_size = 0U; - - if ( buf != NULL ) - orig_size = (uint) strlen( (char *) buf ); - - va_copy( args_copy, args ); - uint new_size = vsnprintf( NULL, 0, format, args_copy ); - va_end( args_copy ); - - new_size += (uint) (orig_size + 1U); - - uint8_t *new_buf = realloc( buf, new_size ); - - if ( new_buf == NULL ) { - logadd( LOG_ERROR, "iscsi_vsprintf_append_realloc: Out of memory while allocating string buffer" ); - - return NULL; - } - - vsnprintf( (char *) (new_buf + orig_size), (new_size - orig_size), format, args ); - - return new_buf; -} - -/** - * @brief Allocates and appends a buffer and sprintf's it. - * - * Merges strings using printf style formatting and allocates - * memory for holding the result. - * - * @param[in] buf Buffer to merge into. - * @param[in] format printf style format string. - * @param[in] ... Values to fill in the format string with. - * @return New buffer which holds the final result. - */ -static uint8_t *iscsi_sprintf_append_realloc(char *buf, const char *format, ...) -{ - va_list args; - - va_start( args, format ); - uint8_t *ret_buf = iscsi_vsprintf_append_realloc( buf, format, args ); - va_end( args ); - - return ret_buf; -} - -/** - * @brief Allocates a buffer and sprintf's it. - * - * Merges strings using printf style formatting and allocates - * memory for holding the result. - * - * @param[in] format printf style format string. - * @param[in] args Values to fill in the format with. - * @return New buffer which holds the final result. - */ -static uint8_t *iscsi_vsprintf_alloc(const char *format, va_list args) -{ - return iscsi_vsprintf_append_realloc( NULL, format, args ); -} - -/** - * @brief Allocates a buffer and sprintf's it. - * - * Allocates a buffer large enough to hold printf style - * string concatenation and fills it using vspnrintf. - * - * @param[in] format Format string to allocate and fill. - * @param[in] ... Values to fill in the format string with. - * @return New buffer containing the formatted string. - */ -static uint8_t *iscsi_sprintf_alloc(const char *format, ... ) -{ - va_list args; - - va_start( args, format ); - uint8_t *buf = iscsi_vsprintf_alloc( format, args ); - va_end( args ); - - return buf; -} - /** * @brief Copies a string with additional padding character to fill in a specified size. * @@ -263,7 +148,7 @@ static void iscsi_copy_kvp_int(const char *name, int *dest, const char *src) const char *end = NULL; if ( *dest != -1 ) { - logadd( LOG_DEBUG1, "Received duplicate entry for key '%s', ignoring", name ); + logadd( LOG_DEBUG1, "Received duplicate entry for key '%s', ignoring (new: %s, old: %d)", name, src, *dest ); return; } @@ -271,7 +156,7 @@ static void iscsi_copy_kvp_int(const char *name, int *dest, const char *src) logadd( LOG_DEBUG1, "Empty value for numeric option '%s', ignoring", name ); return; } - res = strtoll( src, &end, 10 ); + res = strtoll( src, (char **)&end, 10 ); // WTF why is the second arg not const char ** if ( end == NULL ) { logadd( LOG_DEBUG1, "base 10 not valid! O.o" ); @@ -293,10 +178,10 @@ static void iscsi_copy_kvp_int(const char *name, int *dest, const char *src) static void iscsi_copy_kvp_str(const char *name, const char **dest, const char *src) { if ( *dest != NULL ) { - logadd( LOG_DEBUG1, "Received duplicate entry for key '%s', ignoring", name ); + logadd( LOG_DEBUG1, "Received duplicate entry for key '%s', ignoring (new: %s, old: %s)", name, src, *dest ); return; } - *dest = strdup( src ); + *dest = src; } /** @@ -315,12 +200,12 @@ static void iscsi_copy_kvp_str(const char *name, const char **dest, const char * * a negative value in case of an error. This can be used for * incrementing the offset to the next key / value pair. */ -static int iscsi_parse_text_key_value_pair(iscsi_login_kvp *key_value_pairs, const uint8_t *packet_data, const uint32_t len) +static int iscsi_parse_text_key_value_pair(iscsi_negotiation_kvp *key_value_pairs, const char *packet_data, const uint32_t len) { - uint key_val_len = (uint) strnlen( (char *) packet_data, len ); - const uint8_t *key_end = memchr( packet_data, '=', key_val_len ); + int key_val_len = (int) strnlen( packet_data, len ); + const char *key_end = memchr( packet_data, '=', key_val_len ); - if ( key_val_len == len ) { + if ( key_val_len == (int)len ) { logadd( LOG_DEBUG1, "iscsi_parse_text_key_value_pair: Final key/value pair not null-terminated, not spec compliant, aborting" ); return -1; } @@ -352,18 +237,26 @@ static int iscsi_parse_text_key_value_pair(iscsi_login_kvp *key_value_pairs, con } #define COPY_KVP(type, key) \ - else if ( strncmp( (const char *)packet_data, #key, key_len ) == 0 ) iscsi_copy_kvp_ ## type ( #key, &key_value_pairs->key, key_end + 1 ) + else if ( strncmp( packet_data, #key, key_len ) == 0 ) iscsi_copy_kvp_ ## type ( #key, &key_value_pairs->key, key_end + 1 ) if ( 0 ) {} COPY_KVP( int, MaxRecvDataSegmentLength ); COPY_KVP( int, MaxBurstLength ); COPY_KVP( int, FirstBurstLength ); + COPY_KVP( int, MaxConnections ); + COPY_KVP( int, ErrorRecoveryLevel ); + COPY_KVP( str, SessionType ); COPY_KVP( str, AuthMethod ); + COPY_KVP( str, SendTargets ); + COPY_KVP( str, HeaderDigest ); + COPY_KVP( str, DataDigest ); + COPY_KVP( str, InitiatorName ); + COPY_KVP( str, TargetName ); else { - logadd( LOG_DEBUG1, "iscsi_parse_text_key_value_pair: Unknown option: '%.*s'", (int)key_len, (const char*)packet_data ); + logadd( LOG_DEBUG1, "iscsi_parse_text_key_value_pair: Unknown option: '%.*s'", (int)key_len, packet_data ); } -#undef COPY_KVP_INT +#undef COPY_KVP return (int)key_val_len; } @@ -375,84 +268,35 @@ static int iscsi_parse_text_key_value_pair(iscsi_login_kvp *key_value_pairs, con * data amd puts the extracted data into a hash map to be used by * the iSCSI implementation. * - * @param[in] key_value_pairs Pointer to hash map that should contain all + * @param[in] pairs struct to write all key-value-pair options from packet to * extracted keys and pairs. May NOT be NULL, so take caution. * @param[in] packet_data Pointer to first key and value pair to * be parsed. NULL is an illegal value here, so be careful. * @param[in] len Length of the remaining packet data. - * @param[in] c_bit Non-zero value of C bit was set in previously. - * @param[in] partial_pairs Array of partial pair pointers in - * case C bit was set (multiple iSCSI packets for text data). * @retval -1 An error occured during parsing key. * @retval 0 Key and value pair was parsed successfully and was added to * hash map. */ -static int iscsi_parse_login_key_value_pairs(iscsi_login_kvp *key_value_pairs, const uint8_t *packet_data, uint len, int c_bit, uint8_t **partial_pairs) +static int iscsi_parse_login_key_value_pairs(iscsi_negotiation_kvp *pairs, const uint8_t *packet_data, uint len) { + memset( pairs, -1 , sizeof(*pairs) ); + pairs->SessionType = NULL; + pairs->AuthMethod = NULL; + pairs->SendTargets = NULL; + pairs->HeaderDigest = NULL; + pairs->DataDigest = NULL; + pairs->InitiatorName = NULL; + pairs->TargetName = NULL; + if ( len == 0U ) return 0; // iSCSI specs don't allow zero length - if ( (partial_pairs != NULL) && (*partial_pairs != NULL) ) { // Strip partial text parameters in case C bit was enabled previously - uint key_val_pair_len; - - for (key_val_pair_len = 0; (key_val_pair_len < len) && packet_data[key_val_pair_len] != '\0'; key_val_pair_len++) { - } - - uint8_t *tmp_partial_buf = iscsi_sprintf_alloc( "%s%s", *partial_pairs, (const char *) packet_data ); - - if ( tmp_partial_buf == NULL ) - return -1; - - const int rc = iscsi_parse_text_key_value_pair( key_value_pairs, tmp_partial_buf, (uint32_t) (key_val_pair_len + strlen( (char *) *partial_pairs )) ); - free( tmp_partial_buf ); - - if ( rc < 0 ) - return -1; - - free( *partial_pairs ); - *partial_pairs = NULL; - - packet_data += (key_val_pair_len + 1); - len -= (key_val_pair_len + 1); - } - - if ( c_bit ) { // Strip partial parameters in case C bit was enabled previousley - if ( partial_pairs == NULL ) { - logadd( LOG_ERROR, "iscsi_parse_key_value_pairs: C bit set but missing partial parameter" ); - - return -1; - } - - uint key_val_pair_len; - - for (key_val_pair_len = (len - 1U); (packet_data[key_val_pair_len] != '\0') && (key_val_pair_len > 0U); key_val_pair_len--) { - } - - if ( key_val_pair_len != 0U ) - key_val_pair_len++; // NUL char found, don't copy to target buffer' - - *partial_pairs = (uint8_t *) malloc( ((len - key_val_pair_len) + 1U) ); - - if ( *partial_pairs == NULL ) { - logadd( LOG_ERROR, "iscsi_parse_key_value_pairs: Out of memory allocating partial parameter" ); - - return -1; - } - - memcpy( *partial_pairs, &packet_data[key_val_pair_len], (len - key_val_pair_len) ); - - if ( key_val_pair_len != 0U ) - len = (key_val_pair_len - 1U); - else - return 0; - } - int offset = 0; while ( ((uint) offset < len) && (packet_data[offset] != '\0') ) { - const int rc = iscsi_parse_text_key_value_pair( key_value_pairs, (packet_data + offset), (len - offset) ); + const int rc = iscsi_parse_text_key_value_pair( pairs, (const char *)(packet_data + offset), (len - offset) ); - if ( rc < 0 ) + if ( rc <= 0 ) return -1; offset += rc; @@ -478,7 +322,7 @@ static int iscsi_parse_login_key_value_pairs(iscsi_login_kvp *key_value_pairs, c */ static iscsi_task *iscsi_task_create(iscsi_connection *conn) { - iscsi_task *task = (iscsi_task *) malloc( sizeof(struct iscsi_task) ); + iscsi_task *task = malloc( sizeof(struct iscsi_task) ); if ( task == NULL ) { logadd( LOG_ERROR, "iscsi_task_create: Out of memory while allocating iSCSI task" ); @@ -497,9 +341,6 @@ static iscsi_task *iscsi_task_create(iscsi_connection *conn) task->des_data_xfer_pos = 0UL; task->des_data_xfer_len = 0UL; task->data_sn = 0UL; - task->scsi_data_out_cnt = 0UL; - - conn->task_cnt++; iscsi_scsi_task_create( &task->scsi_task ); task->scsi_task.connection = conn; @@ -521,7 +362,6 @@ static void iscsi_task_destroy(iscsi_task *task) return; free( task->scsi_task.buf ); - task->conn->task_cnt--; free( task ); } @@ -548,7 +388,7 @@ static void iscsi_task_destroy(iscsi_task *task) */ static uint32_t iscsi_scsi_data_in_send(iscsi_connection *conn, iscsi_task *task, const uint32_t pos, const uint32_t len, const uint32_t res_cnt, const uint32_t data_sn, const int8_t flags, bool immediate) { - iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, 0U, conn->header_digest, len, conn->data_digest ); + iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, len ); if ( response_pdu == NULL ) { logadd( LOG_ERROR, "iscsi_scsi_data_in_send: Out of memory while allocating iSCSI SCSI Data In response PDU" ); @@ -706,7 +546,7 @@ static void iscsi_task_response(iscsi_connection *conn, iscsi_task *task, iscsi_ } const uint32_t ds_len = (task->scsi_task.sense_data_len != 0U) ? (task->scsi_task.sense_data_len + offsetof(struct iscsi_scsi_ds_cmd_data, sense_data)) : 0UL; - iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, 0U, conn->header_digest, ds_len, conn->data_digest ); + iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, ds_len ); if ( response_pdu == NULL ) { logadd( LOG_ERROR, "iscsi_task_response: Out of memory while allocating iSCSI SCSI response PDU" ); @@ -771,11 +611,7 @@ static void iscsi_task_response(iscsi_connection *conn, iscsi_task *task, iscsi_ } /** - * @brief Allocates and initializes a SCSI task. - * - * THis function assocates the callback - * functions to the SCSI task and sets - * the reference count to 1. + * @brief Initializes a SCSI task. * * @param[in] scsi_task Pointer to SCSI task. This * may NOT be NULL, so be careful. @@ -793,8 +629,6 @@ static void iscsi_scsi_task_create(iscsi_scsi_task *scsi_task) scsi_task->xfer_len = 0UL; scsi_task->sense_data_len = 0U; scsi_task->status = ISCSI_SCSI_STATUS_GOOD; - scsi_task->task_mgmt_func = ISCSI_TASK_MGMT_FUNC_REQ_FUNC_ABORT_TASK; - scsi_task->task_mgmt_response = ISCSI_TASK_MGMT_FUNC_RESPONSE_FUNC_COMPLETE; } /** @@ -892,44 +726,6 @@ static void iscsi_scsi_task_status_set(iscsi_scsi_task *scsi_task, const uint8_t } /** - * @brief Copies iSCSI SCSI task sense data and status code. - * - * This function allocates, if necessary, a - * SCSI sense data buffer and copies it over - * from source or deallocates the sense data - * buffer in case the source has no sense - * data. - * - * @param[in] dst_scsi_task Pointer to iSCSI SCSI task to copy to. - * May NOT be NULL, so be careful. - * @param[in] src_scsi_task Pointer to iSCSI SCSI task to copy from. - * NULL is NOT allowed here, take caution. - * @return 0 on successful copy operation, a negative - * error code otherwise. - */ -static int iscsi_scsi_task_status_copy(iscsi_scsi_task *dst_scsi_task, const iscsi_scsi_task *src_scsi_task) -{ - if ( dst_scsi_task->sense_data != NULL ) - free( dst_scsi_task->sense_data ); - - if ( src_scsi_task->sense_data != NULL ) { - dst_scsi_task->sense_data = malloc( src_scsi_task->sense_data_len ); - - if ( dst_scsi_task == NULL ) - return -1; - - memcpy( dst_scsi_task->sense_data, src_scsi_task->sense_data, src_scsi_task->sense_data_len ); - } else { - dst_scsi_task->sense_data = NULL; - } - - dst_scsi_task->sense_data_len = src_scsi_task->sense_data_len; - dst_scsi_task->status = src_scsi_task->status; - - return 0; -} - -/** * @brief Processes a iSCSI SCSI task with no LUN identifier. * * This function only generates a SCSI response @@ -1065,60 +861,6 @@ static void iscsi_scsi_lun_task_run( iscsi_scsi_task *scsi_task, iscsi_pdu *pdu) } /** - * @brief Checks whether an I/O feature is supported by a DNBD3 image. - * - * This function depends on DNBD3 image - * properties and queries only one I/O - * feature at once. - * - * @param[in] image Pointer to DNBD3 image to check I/O - * attributes for. May NOT be NULL, so be - * careful. - * @param[in] type I/O type to be checked for. - * @retval true The DNBD3 image supports the I/O feature. - * @retval false The I/O feature is NOT supported for the - * DNBD3 image. - */ -static inline bool iscsi_scsi_emu_io_type_is_supported(const dnbd3_image_t *image, const int type) -{ - switch ( type ) { - case ISCSI_SCSI_EMU_IO_TYPE_REMOVABLE : { - return true; - } - case ISCSI_SCSI_EMU_IO_TYPE_NO_ROTATION : { - return true; - } - case ISCSI_SCSI_EMU_IO_TYPE_PHYSICAL_READ_ONLY : { - return false; - } - case ISCSI_SCSI_EMU_IO_TYPE_WRITE_PROTECT : { - return true; - } - default : { - return false; - break; - } - } -} - -/** - * @brief Retrieves the bit shift of a physical block in bytes for a DNBD3 image. - * - * This function depends on DNBD3 image - * properties. - * - * @param[in] image Pointer to DNBD3 image to retrieve - * the physical bit shift size. May NOT - * be NULL, so be careful. - * @return The physical block size in bytes as a - * bit shift count. - */ -static inline uint32_t iscsi_scsi_emu_physical_block_get_size_shift(const dnbd3_image_t *image) -{ - return ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE_BITS; -} - -/** * @brief Retrieves the size of a physical block in bytes for a DNBD3 image. * * This function depends on DNBD3 image @@ -1147,77 +889,7 @@ static inline uint32_t iscsi_scsi_emu_physical_block_get_size(const dnbd3_image_ */ static inline uint64_t iscsi_scsi_emu_block_get_count(const dnbd3_image_t *image) { - return (image->virtualFilesize >> ISCSI_SCSI_EMU_BLOCK_SIZE_BITS); -} - -/** - * @brief Retrieves the bit shift of a logical block in bytes for a DNBD3 image. - * - * This function depends on DNBD3 image - * properties. - * - * @param[in] image Pointer to DNBD3 image to retrieve - * the logical block bit shift size. - * May NOT be NULL, so be careful. - * @return The logical block size in bytes as a - * bit shift count. - */ -static inline uint32_t iscsi_scsi_emu_block_get_size_shift(const dnbd3_image_t *image) -{ - return ISCSI_SCSI_EMU_BLOCK_SIZE_BITS; -} - -/** - * @brief Retrieves the size of a logical block in bytes for a DNBD3 image. - * - * This function depends on DNBD3 image - * properties. - * - * @param[in] image Pointer to DNBD3 image to retrieve - * the logical block size. May NOT be NULL, - * so be careful. - * @return The logical block size in bytes. - */ -static inline uint32_t iscsi_scsi_emu_block_get_size(const dnbd3_image_t *image) -{ - return ISCSI_SCSI_EMU_BLOCK_SIZE; -} - -/** - * @brief Retrieves the bit shift ratio between logical and physical block size for a DNBD3 image. - * - * This function depends on DNBD3 image - * properties. - * - * @param[in] image Pointer to DNBD3 image to retrieve - * the ratio between the logical and - * physical block size. May NOT be - * NULL, so be careful. - * @return The ratio between logical and physical - * block size as a logical bit shift - * count. - */ -static inline uint32_t iscsi_scsi_emu_block_get_ratio_shift(const dnbd3_image_t *image) -{ - return (iscsi_scsi_emu_physical_block_get_size_shift(image) - iscsi_scsi_emu_block_get_size_shift(image)); -} - -/** - * @brief Retrieves the ratio between logical and physical block size for a DNBD3 image. - * - * This function depends on DNBD3 image - * properties. - * - * @param[in] image Pointer to DNBD3 image to retrieve - * the ratio between the logical and - * physical block size. May NOT be - * NULL, so be careful. - * @return The ratio between logical logical and physical - * block size. - */ -static inline uint32_t iscsi_scsi_emu_block_get_ratio(const dnbd3_image_t *image) -{ - return (1UL << iscsi_scsi_emu_block_get_ratio_shift( image )); + return (image->virtualFilesize / ISCSI_SCSI_EMU_BLOCK_SIZE); } /** @@ -1239,21 +911,12 @@ static inline uint32_t iscsi_scsi_emu_block_get_ratio(const dnbd3_image_t *image * bytes is aligned to block size or a * positive value if unaligned. */ -static uint64_t iscsi_scsi_emu_bytes_to_blocks(uint64_t *offset_blocks, uint64_t *num_blocks, const uint64_t offset_bytes, const uint64_t num_bytes, const uint32_t block_size) +static uint64_t iscsi_scsi_emu_bytes_to_blocks(uint64_t *offset_blocks, uint64_t *num_blocks, const uint64_t offset_bytes, const uint64_t num_bytes) { - if ( iscsi_is_pow2( block_size ) ) { - const uint32_t shift = iscsi_get_log2_of_pow2( block_size ); - - *offset_blocks = (offset_bytes >> shift); - *num_blocks = (num_bytes >> shift); + *offset_blocks = (offset_bytes / ISCSI_SCSI_EMU_BLOCK_SIZE); + *num_blocks = (num_bytes / ISCSI_SCSI_EMU_BLOCK_SIZE); - return ((offset_bytes - (*offset_blocks << shift)) | (num_bytes - (*num_blocks << shift))); - } - - *offset_blocks = (offset_bytes / block_size); - *num_blocks = (num_bytes / block_size); - - return ((offset_bytes % block_size) | (num_bytes % block_size)); + return ((offset_bytes % ISCSI_SCSI_EMU_BLOCK_SIZE) | (num_bytes % ISCSI_SCSI_EMU_BLOCK_SIZE)); } /** @@ -1267,22 +930,13 @@ static uint64_t iscsi_scsi_emu_bytes_to_blocks(uint64_t *offset_blocks, uint64_t * careful. * @param[in] offset_blocks Offset in blocks. * @param[in] num_blocks Number of blocks. - * @param[in] block_size Block size in bytes. * @return Number of blocks in bytes. */ -static uint64_t iscsi_scsi_emu_blocks_to_bytes(uint64_t *offset_bytes, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size) +static uint64_t iscsi_scsi_emu_blocks_to_bytes(uint64_t *offset_bytes, const uint64_t offset_blocks, const uint64_t num_blocks) { - if ( iscsi_is_pow2( block_size ) ) { - const uint32_t shift = iscsi_get_log2_of_pow2( block_size ); - - *offset_bytes = (offset_blocks << shift); + *offset_bytes = (offset_blocks * ISCSI_SCSI_EMU_BLOCK_SIZE); - return (num_blocks << shift); - } - - *offset_bytes = (offset_blocks * block_size); - - return (num_blocks * block_size); + return (num_blocks * ISCSI_SCSI_EMU_BLOCK_SIZE); } /** @@ -1301,11 +955,11 @@ static uint64_t iscsi_scsi_emu_blocks_to_bytes(uint64_t *offset_bytes, const uin * uplink_request(). * @param[in] buffer Data for requested range. */ -static void iscsi_uplink_callback(void *data, uint64_t handle, uint64_t start UNUSED, uint32_t length, const char *buffer) +static void iscsi_uplink_callback(void *data, uint64_t handle UNUSED, uint64_t start UNUSED, uint32_t length, const char *buffer) { iscsi_scsi_task *scsi_task = (iscsi_scsi_task *) data; - memcpy( (uint8_t *) handle, buffer, length ); + memcpy( scsi_task->buf, buffer, length ); pthread_mutex_lock( &scsi_task->uplink_mutex ); pthread_cond_signal( &scsi_task->uplink_cond ); @@ -1323,9 +977,6 @@ static void iscsi_uplink_callback(void *data, uint64_t handle, uint64_t start UN * @param[in] scsi_task Pointer to iSCSI SCSI task which * executes the I/O read operation, may * NOT be NULL, so be careful. - * @param[in] buf Pointer to buffer where to store - * the read data. NULL is NOT allowed - * here, take caution. * @param[in] image Pointer to DNBD3 image to read * data from and may NOT be NULL, so * be careful. @@ -1335,10 +986,10 @@ static void iscsi_uplink_callback(void *data, uint64_t handle, uint64_t start UN * @return 0 on successful operation, a negative * error code otherwise. */ -static int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, uint8_t *buf, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks, const uint32_t block_size) +static int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, dnbd3_image_t *image, const uint64_t offset_blocks, const uint64_t num_blocks) { uint64_t offset_bytes; - const uint64_t num_bytes = iscsi_scsi_emu_blocks_to_bytes( &offset_bytes, offset_blocks, num_blocks, block_size ); + const uint64_t num_bytes = iscsi_scsi_emu_blocks_to_bytes( &offset_bytes, offset_blocks, num_blocks ); dnbd3_cache_map_t *cache = ref_get_cachemap( image ); bool readFromFile; @@ -1359,7 +1010,7 @@ static int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, uint8_t *bu pthread_cond_init( &scsi_task->uplink_cond, NULL ); pthread_mutex_lock( &scsi_task->uplink_mutex ); - if ( !uplink_request( image, scsi_task, iscsi_uplink_callback, (uint64_t) buf, offset_bytes, num_bytes ) ) { + if ( !uplink_request( image, scsi_task, iscsi_uplink_callback, 0, offset_bytes, num_bytes ) ) { pthread_mutex_unlock( &scsi_task->uplink_mutex ); logadd( LOG_DEBUG1, "Could not relay uncached request to upstream proxy for image %s:%d", @@ -1379,7 +1030,7 @@ static int iscsi_scsi_emu_io_blocks_read(iscsi_scsi_task *scsi_task, uint8_t *bu bool success; if ( readFromFile ) { - const int64_t len = pread( image->readFd, buf, (size_t) num_bytes, offset_bytes ); + const int64_t len = pread( image->readFd, scsi_task->buf, (size_t) num_bytes, offset_bytes ); success = ((uint64_t) len == num_bytes); } else { success = true; @@ -1420,15 +1071,21 @@ static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task { scsi_task->xfer_pos = 0UL; + if ( (flags & ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE) != 0 ) { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + + return ISCSI_SCSI_TASK_RUN_COMPLETE; + } + if ( (scsi_task->flags & (ISCSI_SCSI_TASK_FLAGS_XFER_READ | ISCSI_SCSI_TASK_FLAGS_XFER_WRITE)) == (ISCSI_SCSI_TASK_FLAGS_XFER_READ | ISCSI_SCSI_TASK_FLAGS_XFER_WRITE) ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return ISCSI_SCSI_TASK_RUN_COMPLETE; } - const uint64_t block_count = iscsi_scsi_emu_block_get_count( image ); + const uint64_t imgBlockCount = iscsi_scsi_emu_block_get_count( image ); - if ( (block_count <= lba) || ((block_count - lba) < xfer_len) ) { + if ( (imgBlockCount <= lba) || ((imgBlockCount - lba) < xfer_len) ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return ISCSI_SCSI_TASK_RUN_COMPLETE; @@ -1440,8 +1097,7 @@ static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task return ISCSI_SCSI_TASK_RUN_COMPLETE; } - const uint32_t block_size = iscsi_scsi_emu_block_get_size( image ); - const uint32_t max_xfer_len = ISCSI_MAX_DS_SIZE / block_size; + const uint32_t max_xfer_len = ISCSI_MAX_DS_SIZE / ISCSI_SCSI_EMU_BLOCK_SIZE; if ( xfer_len > max_xfer_len ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_INVALID_FIELD_IN_CDB, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); @@ -1449,16 +1105,10 @@ static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task return ISCSI_SCSI_TASK_RUN_COMPLETE; } - if ( (flags & ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE) != 0 ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - - return ISCSI_SCSI_TASK_RUN_COMPLETE; - } - uint64_t offset_blocks; uint64_t num_blocks; - if ( iscsi_scsi_emu_bytes_to_blocks( &offset_blocks, &num_blocks, scsi_task->pos, scsi_task->len, block_size ) != 0ULL ) { + if ( iscsi_scsi_emu_bytes_to_blocks( &offset_blocks, &num_blocks, scsi_task->pos, scsi_task->len ) != 0ULL ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); return ISCSI_SCSI_TASK_RUN_COMPLETE; @@ -1468,23 +1118,17 @@ static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task int rc; - if ( (flags & ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE) == 0 ) { - scsi_task->buf = (uint8_t *) malloc( scsi_task->len ); - - if ( scsi_task->buf == NULL ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_HARDWARE_ERR, - ISCSI_SCSI_ASC_INTERNAL_TARGET_FAIL, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE ); - - return ISCSI_SCSI_TASK_RUN_COMPLETE; - } + scsi_task->buf = (uint8_t *) malloc( scsi_task->len ); - rc = iscsi_scsi_emu_io_blocks_read( scsi_task, scsi_task->buf, image, offset_blocks, num_blocks, block_size ); - } else { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_DATA_PROTECT, ISCSI_SCSI_ASC_WRITE_PROTECTED, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); + if ( scsi_task->buf == NULL ) { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_HARDWARE_ERR, + ISCSI_SCSI_ASC_INTERNAL_TARGET_FAIL, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE ); return ISCSI_SCSI_TASK_RUN_COMPLETE; } + rc = iscsi_scsi_emu_io_blocks_read( scsi_task, image, offset_blocks, num_blocks ); + if ( rc < 0 ) { if ( rc == -ENOMEM ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_HARDWARE_ERR, @@ -1532,8 +1176,6 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) xfer_len = 256UL; return iscsi_scsi_emu_block_read_write( image, scsi_task, lba, xfer_len, 0 ); - - break; } case ISCSI_SCSI_OPCODE_READ10 : { const iscsi_scsi_cdb_read_write_10 *cdb_read_write_10 = (iscsi_scsi_cdb_read_write_10 *) scsi_task->cdb; @@ -1542,8 +1184,6 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) xfer_len = iscsi_get_be16(cdb_read_write_10->xfer_len); return iscsi_scsi_emu_block_read_write( image, scsi_task, lba, xfer_len, 0 ); - - break; } case ISCSI_SCSI_OPCODE_READ12 : { const iscsi_scsi_cdb_read_write_12 *cdb_read_write_12 = (iscsi_scsi_cdb_read_write_12 *) scsi_task->cdb; @@ -1552,8 +1192,6 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) xfer_len = iscsi_get_be32(cdb_read_write_12->xfer_len); return iscsi_scsi_emu_block_read_write( image, scsi_task, lba, xfer_len, 0 ); - - break; } case ISCSI_SCSI_OPCODE_READ16 : { const iscsi_scsi_cdb_read_write_16 *cdb_read_write_16 = (iscsi_scsi_cdb_read_write_16 *) scsi_task->cdb; @@ -1562,8 +1200,6 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) xfer_len = iscsi_get_be32(cdb_read_write_16->xfer_len); return iscsi_scsi_emu_block_read_write( image, scsi_task, lba, xfer_len, 0 ); - - break; } case ISCSI_SCSI_OPCODE_READCAPACITY10 : { iscsi_scsi_read_capacity_10_parameter_data_packet *buf = (iscsi_scsi_read_capacity_10_parameter_data_packet *) malloc( sizeof(struct iscsi_scsi_read_capacity_10_parameter_data_packet) ); @@ -1581,9 +1217,7 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) else iscsi_put_be32( (uint8_t *) &buf->lba, (uint32_t) lba ); - xfer_len = iscsi_scsi_emu_block_get_size( image ); - - iscsi_put_be32( (uint8_t *) &buf->block_len, xfer_len ); + iscsi_put_be32( (uint8_t *) &buf->block_len, ISCSI_SCSI_EMU_BLOCK_SIZE ); uint len = scsi_task->len; @@ -1599,53 +1233,41 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) case ISCSI_SCSI_OPCODE_SERVICE_ACTION_IN_16 : { const iscsi_scsi_cdb_service_action_in_16 *cdb_servce_in_action_16 = (iscsi_scsi_cdb_service_action_in_16 *) scsi_task->cdb; - switch ( ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_GET_ACTION(cdb_servce_in_action_16->action) ) { - case ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_READ_CAPACITY_16 : { - iscsi_scsi_service_action_in_16_parameter_data_packet *buf = (iscsi_scsi_service_action_in_16_parameter_data_packet *) malloc( sizeof(struct iscsi_scsi_service_action_in_16_parameter_data_packet) ); - - if ( buf == NULL ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_BECOMING_READY ); - - return ISCSI_SCSI_TASK_RUN_COMPLETE; - } - - lba = iscsi_scsi_emu_block_get_count( image ) - 1ULL; - xfer_len = iscsi_scsi_emu_block_get_size( image ); + if ( ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_GET_ACTION(cdb_servce_in_action_16->action) + != ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_READ_CAPACITY_16 ) { + return ISCSI_SCSI_TASK_RUN_UNKNOWN; + } + iscsi_scsi_service_action_in_16_parameter_data_packet *buf = (iscsi_scsi_service_action_in_16_parameter_data_packet *) malloc( sizeof(struct iscsi_scsi_service_action_in_16_parameter_data_packet) ); - iscsi_put_be64( (uint8_t *) &buf->lba, lba ); - iscsi_put_be32( (uint8_t *) &buf->block_len, xfer_len ); + if ( buf == NULL ) { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_BECOMING_READY ); - buf->flags = 0; + return ISCSI_SCSI_TASK_RUN_COMPLETE; + } - const uint8_t exponent = (uint8_t) iscsi_scsi_emu_block_get_ratio_shift( image ); + lba = iscsi_scsi_emu_block_get_count( image ) - 1ULL; - buf->exponents = ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_PUT_LBPPB_EXPONENT((exponent <= ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_MASK) ? exponent : 0U); + iscsi_put_be64( (uint8_t *) &buf->lba, lba ); + iscsi_put_be32( (uint8_t *) &buf->block_len, ISCSI_SCSI_EMU_BLOCK_SIZE ); - if ( iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_UNMAP ) ) - iscsi_put_be16( (uint8_t *) &buf->lbp_lalba, ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPME ); - else - buf->lbp_lalba = 0U; + buf->flags = 0; - buf->reserved[0] = 0ULL; - buf->reserved[1] = 0ULL; + const uint8_t exponent = ISCSI_SCSI_EMU_BLOCK_DIFF_SHIFT; - uint len = cdb_servce_in_action_16->alloc_len; + buf->exponents = ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_PUT_LBPPB_EXPONENT((exponent <= ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_MASK) ? exponent : 0U); - if ( len > sizeof(struct iscsi_scsi_service_action_in_16_parameter_data_packet) ) - len = sizeof(struct iscsi_scsi_service_action_in_16_parameter_data_packet); // TODO: Check whether scatter data is required + buf->lbp_lalba = 0U; + buf->reserved[0] = 0ULL; + buf->reserved[1] = 0ULL; - scsi_task->buf = (uint8_t *) buf; - scsi_task->xfer_pos = len; - scsi_task->status = ISCSI_SCSI_STATUS_GOOD; + uint len = cdb_servce_in_action_16->alloc_len; - break; - } - default : { - return ISCSI_SCSI_TASK_RUN_UNKNOWN; + if ( len > sizeof(struct iscsi_scsi_service_action_in_16_parameter_data_packet) ) + len = sizeof(struct iscsi_scsi_service_action_in_16_parameter_data_packet); // TODO: Check whether scatter data is required - break; - } - } + scsi_task->buf = (uint8_t *) buf; + scsi_task->xfer_pos = len; + scsi_task->status = ISCSI_SCSI_STATUS_GOOD; break; } @@ -1958,7 +1580,7 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task vpd_page_block_limits_inquiry_data_pkt->flags = 0; - uint32_t blocks = (ISCSI_MAX_DS_SIZE >> iscsi_scsi_emu_block_get_size_shift( image )); + uint32_t blocks = (ISCSI_MAX_DS_SIZE / ISCSI_SCSI_EMU_BLOCK_SIZE); vpd_page_block_limits_inquiry_data_pkt->max_cmp_write_len = (uint8_t) blocks; @@ -2027,7 +1649,7 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task const uint8_t pti = ISCSI_SCSI_BASIC_INQUIRY_DATA_PUT_PERIPHERAL_TYPE(ISCSI_SCSI_BASIC_INQUIRY_DATA_PERIPHERAL_TYPE_DIRECT) | ISCSI_SCSI_BASIC_INQUIRY_DATA_PUT_PERIPHERAL_ID(ISCSI_SCSI_BASIC_INQUIRY_DATA_PERIPHERAL_ID_POSSIBLE); std_inquiry_data_pkt->basic_inquiry.peripheral_type_id = pti; - std_inquiry_data_pkt->basic_inquiry.peripheral_type_mod_flags = (int8_t) (iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_REMOVABLE ) ? ISCSI_SCSI_BASIC_INQUIRY_DATA_PERIPHERAL_TYPE_MOD_FLAGS_REMOVABLE_MEDIA : 0); + std_inquiry_data_pkt->basic_inquiry.peripheral_type_mod_flags = 0; std_inquiry_data_pkt->basic_inquiry.version = ISCSI_SCSI_BASIC_INQUIRY_DATA_PUT_VERSION_ANSI(ISCSI_SCSI_BASIC_INQUIRY_DATA_VERSION_ANSI_SPC3); std_inquiry_data_pkt->basic_inquiry.response_data_fmt_flags = ISCSI_SCSI_BASIC_INQUIRY_DATA_PUT_RESPONSE_DATA_FMT_FLAGS(ISCSI_SCSI_BASIC_INQUIRY_DATA_RESPONSE_DATA_FMT_FLAGS_SCSI_2) | ISCSI_SCSI_BASIC_INQUIRY_DATA_RESPONSE_DATA_FMT_FLAGS_HISUP; @@ -2329,9 +1951,6 @@ static int iscsi_scsi_emu_primary_mode_sense_page(dnbd3_image_t *image, iscsi_sc iscsi_scsi_emu_primary_mode_sense_page_init( mode_sense_mode_page_pkt, page_len, page, sub_page ); - if ( (mode_sense_mode_page_pkt != NULL) && iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_WRITE_CACHE ) && (pc != ISCSI_SCSI_CDB_MODE_SENSE_6_PAGE_CONTROL_CHG_VALUES) ) - mode_sense_caching_mode_page_pkt->flags |= ISCSI_SCSI_MODE_SENSE_CACHING_MODE_PAGE_FLAGS_WCE; - if ( (mode_sense_mode_page_pkt != NULL) && (pc != ISCSI_SCSI_CDB_MODE_SENSE_6_PAGE_CONTROL_CHG_VALUES) ) mode_sense_caching_mode_page_pkt->flags |= ISCSI_SCSI_MODE_SENSE_CACHING_MODE_PAGE_FLAGS_RCD; @@ -2492,21 +2111,24 @@ static int iscsi_scsi_emu_primary_mode_sense(dnbd3_image_t *image, iscsi_scsi_ta if ( hdr_len == sizeof(struct iscsi_scsi_mode_sense_6_parameter_header_data_packet) ) { mode_sense_6_parameter_hdr_data_pkt->mode_data_len = (uint8_t) (alloc_len - sizeof(uint8_t)); mode_sense_6_parameter_hdr_data_pkt->medium_type = 0U; - mode_sense_6_parameter_hdr_data_pkt->flags = (int8_t) ((iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_PHYSICAL_READ_ONLY ) || iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_WRITE_PROTECT )) ? ISCSI_SCSI_MODE_SENSE_6_PARAM_HDR_DATA_FLAGS_WP : 0); + mode_sense_6_parameter_hdr_data_pkt->flags = ISCSI_SCSI_MODE_SENSE_6_PARAM_HDR_DATA_FLAGS_WP; mode_sense_6_parameter_hdr_data_pkt->block_desc_len = (uint8_t) block_desc_len; - } else { + } else if ( hdr_len == sizeof(struct iscsi_scsi_mode_sense_10_parameter_header_data_packet) ) { iscsi_scsi_mode_sense_10_parameter_header_data_packet *mode_sense_10_parameter_hdr_data_pkt = (iscsi_scsi_mode_sense_10_parameter_header_data_packet *) mode_sense_6_parameter_hdr_data_pkt; iscsi_put_be16( (uint8_t *) &mode_sense_10_parameter_hdr_data_pkt->mode_data_len, (uint16_t) (alloc_len - sizeof(uint16_t)) ); mode_sense_10_parameter_hdr_data_pkt->medium_type = 0U; - mode_sense_10_parameter_hdr_data_pkt->flags = (int8_t) ((iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_PHYSICAL_READ_ONLY ) || iscsi_scsi_emu_io_type_is_supported( image, ISCSI_SCSI_EMU_IO_TYPE_WRITE_PROTECT )) ? ISCSI_SCSI_MODE_SENSE_10_PARAM_HDR_DATA_FLAGS_WP : 0); + mode_sense_10_parameter_hdr_data_pkt->flags = ISCSI_SCSI_MODE_SENSE_10_PARAM_HDR_DATA_FLAGS_WP; mode_sense_10_parameter_hdr_data_pkt->long_lba = (uint8_t) long_lba; mode_sense_10_parameter_hdr_data_pkt->reserved = 0U; iscsi_put_be16( (uint8_t *) &mode_sense_10_parameter_hdr_data_pkt->block_desc_len, (uint16_t) block_desc_len ); + } else { + logadd( LOG_DEBUG1, "iscsi_scsi_emu_primary_mode_sense: invalid parameter header length %u", hdr_len ); + return -1; } const uint64_t num_blocks = iscsi_scsi_emu_block_get_count( image ); - const uint32_t block_size = iscsi_scsi_emu_block_get_size( image ); + const uint32_t block_size = ISCSI_SCSI_EMU_BLOCK_SIZE; if ( block_desc_len == sizeof(struct iscsi_scsi_mode_sense_lba_parameter_block_desc_data_packet) ) { iscsi_scsi_mode_sense_lba_parameter_block_desc_data_packet *lba_parameter_block_desc = (iscsi_scsi_mode_sense_lba_parameter_block_desc_data_packet *) (((uint8_t *) mode_sense_6_parameter_hdr_data_pkt) + hdr_len); @@ -2641,62 +2263,6 @@ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task) break; } - case ISCSI_SCSI_OPCODE_MODESELECT6 : { - const iscsi_scsi_cdb_mode_select_6 *cdb_mode_select_6 = (iscsi_scsi_cdb_mode_select_6 *) scsi_task->cdb; - - alloc_len = cdb_mode_select_6->param_list_len; - - if ( alloc_len == 0U ) - break; - - rc = iscsi_scsi_emu_check_len( scsi_task, alloc_len, sizeof(struct iscsi_scsi_mode_select_6_parameter_list_packet) ); - - if ( rc < 0 ) - break; - - len = scsi_task->len; - - if ( alloc_len < sizeof(struct iscsi_scsi_mode_select_6_parameter_list_packet) ) - alloc_len = sizeof(struct iscsi_scsi_mode_select_6_parameter_list_packet); - - rc = iscsi_scsi_emu_check_len( scsi_task, len, alloc_len ); - - if ( rc < 0 ) - break; - - scsi_task->xfer_pos = alloc_len; - scsi_task->status = ISCSI_SCSI_STATUS_GOOD; - - break; - } - case ISCSI_SCSI_OPCODE_MODESELECT10 : { - const iscsi_scsi_cdb_mode_select_10 *cdb_mode_select_10 = (iscsi_scsi_cdb_mode_select_10 *) scsi_task->cdb; - - alloc_len = iscsi_get_be16(cdb_mode_select_10->param_list_len); - - if ( alloc_len == 0U ) - break; - - rc = iscsi_scsi_emu_check_len( scsi_task, alloc_len, sizeof(struct iscsi_scsi_mode_select_10_parameter_list_packet) ); - - if ( rc < 0 ) - break; - - len = scsi_task->len; - - if ( alloc_len < sizeof(struct iscsi_scsi_mode_select_10_parameter_list_packet) ) - alloc_len = sizeof(struct iscsi_scsi_mode_select_10_parameter_list_packet); - - rc = iscsi_scsi_emu_check_len( scsi_task, len, alloc_len ); - - if ( rc < 0 ) - break; - - scsi_task->xfer_pos = alloc_len; - scsi_task->status = ISCSI_SCSI_STATUS_GOOD; - - break; - } case ISCSI_SCSI_OPCODE_MODESENSE6 : { const iscsi_scsi_cdb_mode_sense_6 *cdb_mode_sense_6 = (iscsi_scsi_cdb_mode_sense_6 *) scsi_task->cdb; @@ -2796,53 +2362,9 @@ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task) break; } - case ISCSI_SCSI_OPCODE_REQUESTSENSE : { - const iscsi_scsi_cdb_req_sense *cdb_req_sense = (iscsi_scsi_cdb_req_sense *) scsi_task->cdb; - - if ( (cdb_req_sense->flags & ISCSI_SCSI_CDB_REQ_SENSE_FLAGS_DESC) != 0 ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_INVALID_FIELD_IN_CDB, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - - break; - } - - alloc_len = cdb_req_sense->alloc_len; - - iscsi_scsi_task_sense_data_build( scsi_task, ISCSI_SCSI_SENSE_KEY_NO_SENSE, ISCSI_SCSI_ASC_NO_ADDITIONAL_SENSE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - - len = scsi_task->sense_data_len; - - if ( len > 0U ) { - iscsi_scsi_sense_data_check_cond_packet *sense_data = malloc( len ); - - if ( sense_data == NULL ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_BECOMING_READY ); - - break; - } - - memcpy( sense_data, scsi_task->sense_data, len ); - - if ( len > alloc_len ) - len = alloc_len; - - scsi_task->buf = (uint8_t *) sense_data; - } - - scsi_task->xfer_pos = len; - scsi_task->status = ISCSI_SCSI_STATUS_GOOD; - - break; - } - case ISCSI_SCSI_OPCODE_LOGSELECT : - case ISCSI_SCSI_OPCODE_LOGSENSE : { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_ILLEGAL_REQ, ISCSI_SCSI_ASC_INVALID_COMMAND_OPERATION_CODE, ISCSI_SCSI_ASCQ_CAUSE_NOT_REPORTABLE ); - - break; - } case ISCSI_SCSI_OPCODE_TESTUNITREADY : { scsi_task->xfer_pos = 0UL; scsi_task->status = ISCSI_SCSI_STATUS_GOOD; - logadd( LOG_WARNING, "UNIT READYYYYY" ); break; } @@ -2887,87 +2409,6 @@ static uint64_t iscsi_target_node_wwn_get(const uint8_t *name) } /** - * @brief Extracts the DNBD3 image out of an iSCSI IQN string and opens the DNBD3 image. - * - * This function uses the : separator as - * specified by the IQN standard.\n - * If no colons are in the IQN string, - * the complete string will be - * considered the image file name.\n - * The image file name is assumed - * before the last colon and is - * either directly opened or if - * that fails, a WWN name by - * IEEE Extended NAA is tried as - * well.\n - * The image revision is assumed - * after the last colon. - * @param[in] iqn Pointer to iSCSI IQN string. This - * is not allowed to be NULL, so be careful. - * @return Pointer to DNBD3 image if successful - * operation or NULL if failed. - */ -static dnbd3_image_t *iscsi_target_node_image_get(uint8_t *iqn) -{ - uint8_t *image_name = iqn; - uint8_t *image_rev = NULL; - uint8_t *tmp = (uint8_t *) strchr( (char *) iqn, ':' ); - - while ( tmp != NULL ) { - tmp++; - - image_name = image_rev; - image_rev = tmp; - tmp = (uint8_t *) strchr( (char *) tmp, ':' ); - } - - if ( image_rev == NULL ) - image_rev = image_name; - - const uint len = (uint) (image_rev - image_name); - - if ( len > 0U ) { - tmp = (uint8_t *) malloc( len ); - - if ( tmp == NULL ) { - logadd( LOG_ERROR, "iscsi_target_node_image_get: Out of memory while allocating DNBD3 image name for iSCSI target node" ); - - return NULL; - } - - memcpy( tmp, image_name, (len - 1) ); - tmp[len - 1] = '\0'; - } else { - tmp = image_name; - } - - const uint16_t rev = (uint16_t) ((len > 0U) ? atoi( (char *) image_rev ) : 0); - dnbd3_image_t *image = image_getOrLoad( (char *) image_name, rev ); - - if ( image == NULL ) { - image = image_getOrLoad( (char *) tmp, rev ); - - if ( image == NULL ) { - if ( strncasecmp( (char *) image_name, ISCSI_TARGET_NODE_WWN_NAME_PREFIX, ISCSI_STRLEN(ISCSI_TARGET_NODE_WWN_NAME_PREFIX) ) == 0 ) { - uint64_t wwn = strtoull( (char *) (image_name + ISCSI_STRLEN(ISCSI_TARGET_NODE_WWN_NAME_PREFIX)), NULL, 16 ); - - image = image_getByWwn( wwn, rev, true ); - - if ( image == NULL ) { - wwn = strtoull( (char *) (tmp + ISCSI_STRLEN(ISCSI_TARGET_NODE_WWN_NAME_PREFIX)), NULL, 16 ); - image = image_getByWwn( wwn, rev, true ); - } - } - } - } - - if ( len > 0U ) - free( tmp ); - - return image; -} - -/** * @brief Creates and initializes an iSCSI session. * * This function creates and initializes all relevant @@ -2991,8 +2432,6 @@ static iscsi_session *iscsi_session_create(iscsi_connection *conn, const int ty return NULL; } - session->flags = (ISCSI_SESSION_FLAGS_INIT_R2T | ISCSI_SESSION_FLAGS_DATA_PDU_IN_ORDER | ISCSI_SESSION_FLAGS_DATA_SEQ_IN_ORDER); - session->tsih = 0ULL; session->type = type; session->exp_cmd_sn = 0UL; @@ -3037,26 +2476,9 @@ static iscsi_connection *iscsi_connection_create(dnbd3_client_t *client) return NULL; } - conn->session = NULL; - - if ( conn->key_value_pairs == NULL ) { - logadd( LOG_ERROR, "iscsi_create_connection: Out of memory while allocating iSCSI login text key / value pair hash map" ); - - free( conn ); - - return NULL; - } - - conn->partial_pairs = NULL; - conn->text_partial_pairs = NULL; + conn->session = NULL; conn->pdu_processing = NULL; conn->login_response_pdu = NULL; - conn->target_send_total_size = 0U; - conn->scsi_data_in_cnt = 0U; - conn->scsi_data_out_cnt = 0U; - conn->task_cnt = 0U; - conn->header_digest = 0; - conn->data_digest = 0; conn->id = 0; conn->client = client; conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_READY; @@ -3070,7 +2492,6 @@ static iscsi_connection *iscsi_connection_create(dnbd3_client_t *client) conn->init_task_tag = 0UL; conn->target_xfer_tag = 0UL; conn->stat_sn = 0UL; - conn->exp_stat_sn = 0UL; return conn; } @@ -3092,13 +2513,7 @@ static void iscsi_connection_destroy(iscsi_connection *conn) { if ( conn != NULL ) { iscsi_session_destroy( conn->session ); - - free ( conn->text_partial_pairs ); - - if ( conn->partial_pairs != NULL ) { - free ( conn->partial_pairs ); - } - + iscsi_connection_pdu_destroy( conn->pdu_processing ); free( conn ); } } @@ -3120,31 +2535,14 @@ static int32_t iscsi_connection_read(const iscsi_connection *conn, uint8_t *buf, if ( len == 0UL ) return 0L; - const int32_t rc = (int32_t) recv( conn->client->sock, buf, (size_t) len, MSG_WAITALL ); - - return ((rc > 0L) ? rc : (int32_t) ISCSI_CONNECT_PDU_READ_ERR_FATAL); -} - -/** - * @brief Writes data for the specified iSCSI connection to its TCP socket. - * - * The TCP socket is marked as non-blocking, so this function may not read - * all data requested. - * - * Returns ISCSI_CONNECT_PDU_READ_ERR_FATAL if the operation - * indicates a fatal error with the TCP connection (including - * if the TCP connection was closed unexpectedly). - * - * Otherwise returns the number of bytes successfully written. - */ -static int32_t iscsi_connection_write(const iscsi_connection *conn, uint8_t *buf, const uint32_t len) -{ - if ( len == 0UL ) - return 0L; - - const int32_t rc = (int32_t) sock_sendAll( conn->client->sock, buf, (size_t) len, ISCSI_CONNECT_SOCKET_WRITE_RETRIES ); + int32_t rc; + do { + rc = (int32_t) recv( conn->client->sock, buf, (size_t) len, MSG_WAITALL ); + } while ( rc == -1 && errno == EINTR ); - return ((rc > 0L) ? rc : (int32_t) ISCSI_CONNECT_PDU_READ_ERR_FATAL); + if ( rc == 0 ) + return -1; // EOF + return rc; } /** @@ -3154,8 +2552,7 @@ static int32_t iscsi_connection_write(const iscsi_connection *conn, uint8_t *buf * and value pair to an output DataSegment * buffer and truncates if necessary. * - * @param[in] key_value_pair Pointer to key and value pair containing - * its attributes. + * @param[in] number true = int, false = char* * @param[in] key Pointer to key to be written to output * buffer. NULL is NOT allowed, take caution. * @param[in] value Pointer to value of the key that should @@ -3167,20 +2564,20 @@ static int32_t iscsi_connection_write(const iscsi_connection *conn, uint8_t *buf * @param[in] pos Position of buffer in bytes to start * writing to. * @param[in] buflen Total length of buffer in bytes. - * @return Bytes added to buffer, or negative - * error code. + * @return -1 if buffer is already full, otherwise the number + * of bytes that are written or would have been written to + * the buffer. */ -static int iscsi_append_key_value_pair_packet(const char *key, const char *value, uint8_t *buf, const uint32_t pos, const uint32_t buflen) +static int iscsi_append_key_value_pair_packet(const bool number, const char *key, const char *value, char *buf, const uint32_t pos, const uint32_t buflen) { if ( pos >= buflen ) return -1; const ssize_t maxlen = buflen - pos; - const ssize_t ret = snprintf( (char *) (buf + pos), maxlen, "%s=%s", key, value ) + 1; - - if ( ret > maxlen ) - return -1; - return (int)ret; + if ( number ) { + return (int)snprintf( (buf + pos), maxlen, "%s=%d", key, (const int)(const size_t)value ) + 1; + } + return (int)snprintf( (buf + pos), maxlen, "%s=%s", key, value ) + 1; } @@ -3203,28 +2600,11 @@ static int iscsi_append_key_value_pair_packet(const char *key, const char *value * @retval 0 All values have been updated successfully and * the socket is still alive. */ -static int iscsi_connection_update_key_value_pairs(iscsi_connection *conn, iscsi_login_kvp *pairs) +static void iscsi_connection_update_key_value_pairs(iscsi_connection *conn, iscsi_negotiation_kvp *pairs) { conn->session->opts.MaxBurstLength = CLAMP(pairs->MaxBurstLength, 512, ISCSI_MAX_DS_SIZE); conn->session->opts.FirstBurstLength = CLAMP(pairs->FirstBurstLength, 512, pairs->MaxBurstLength); conn->session->opts.MaxRecvDataSegmentLength = CLAMP(pairs->MaxRecvDataSegmentLength, 512, ISCSI_MAX_DS_SIZE); - - if ( conn->client->sock == -1 ) - return -1; - - int recv_buf_len = conn->session->opts.FirstBurstLength; - - if ( recv_buf_len < 4096 ) - recv_buf_len = 4096; - else if ( recv_buf_len > 8192 ) - recv_buf_len = 8192; - - recv_buf_len += (sizeof(struct iscsi_bhs_packet) + ISCSI_MAX_AHS_SIZE + conn->header_digest + conn->data_digest); // BHS + maximum AHS size + header and data digest overhead - recv_buf_len *= 16; // Receive up to 16 streams at once. - - setsockopt( conn->client->sock, SOL_SOCKET, SO_RCVBUF, &recv_buf_len, sizeof(recv_buf_len)); // Not being able to set the buffer is NOT fatal, so ignore error. - - return 0; } /** @@ -3236,42 +2616,35 @@ static int iscsi_connection_update_key_value_pairs(iscsi_connection *conn, iscsi * @param[in] conn Pointer to ISCSI connection to send the TCP/IP * packet with. May NOT be NULL, so be * careful. - * @param[in] login_response_pdu Pointer to login response PDU to + * @param[in] resp_pdu Pointer to login response PDU to * be sent via TCP/IP. NULL is NOT * allowed here, take caution. * @return 0 if the login response has been sent * successfully, a negative error code otherwise. */ -static int iscsi_connection_pdu_login_response(iscsi_connection *conn, iscsi_pdu *login_response_pdu) +static int iscsi_connection_pdu_login_response(iscsi_connection *conn, iscsi_pdu *resp_pdu) { - const uint32_t ds_len = login_response_pdu->ds_len; - - login_response_pdu->ds_len = login_response_pdu->len; - - iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) iscsi_connection_pdu_append( login_response_pdu, login_response_pdu->ahs_len, 0, ds_len, 0 ); + iscsi_login_response_packet *login_response_pkt = + (iscsi_login_response_packet *) iscsi_connection_pdu_resize( resp_pdu, resp_pdu->ahs_len, resp_pdu->ds_write_pos ); login_response_pkt->version_max = ISCSI_VERSION_MAX; login_response_pkt->version_active = ISCSI_VERSION_MAX; - iscsi_put_be32( (uint8_t *) &login_response_pkt->total_ahs_len, ds_len ); // TotalAHSLength is always 0 and DataSegmentLength is 24-bit, so write in one step. + iscsi_put_be32( (uint8_t *) &login_response_pkt->total_ahs_len, resp_pdu->ds_len ); // TotalAHSLength is always 0 and DataSegmentLength is 24-bit, so write in one step. iscsi_put_be32( (uint8_t *) &login_response_pkt->stat_sn, conn->stat_sn++ ); if ( conn->session != NULL ) { // TODO: Needed? MC/S? iscsi_put_be32( (uint8_t *) &login_response_pkt->exp_cmd_sn, conn->session->exp_cmd_sn ); iscsi_put_be32( (uint8_t *) &login_response_pkt->max_cmd_sn, conn->session->max_cmd_sn ); } else { - iscsi_put_be32( (uint8_t *) &login_response_pkt->exp_cmd_sn, login_response_pdu->cmd_sn ); - iscsi_put_be32( (uint8_t *) &login_response_pkt->max_cmd_sn, login_response_pdu->cmd_sn ); + iscsi_put_be32( (uint8_t *) &login_response_pkt->exp_cmd_sn, resp_pdu->cmd_sn ); + iscsi_put_be32( (uint8_t *) &login_response_pkt->max_cmd_sn, resp_pdu->cmd_sn ); } if ( login_response_pkt->status_class != ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SUCCESS ) login_response_pkt->flags &= (int8_t) ~(ISCSI_LOGIN_RESPONSE_FLAGS_TRANSIT | ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_MASK | ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_MASK ); - iscsi_connection_pdu_write( conn, login_response_pdu ); - - if ( conn->state < ISCSI_CONNECT_STATE_EXITING && (conn->flags & ISCSI_CONNECT_FLAGS_FULL_FEATURE) != 0 ) { - iscsi_connection_update_key_value_pairs( conn ); - } + iscsi_connection_pdu_write( conn, resp_pdu ); return ISCSI_CONNECT_PDU_READ_OK; } @@ -3295,8 +2668,6 @@ static int iscsi_connection_pdu_login_response_init(iscsi_pdu *login_response_pd iscsi_login_req_packet *login_req_pkt = (iscsi_login_req_packet *) pdu->bhs_pkt; iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - login_response_pdu->ds_len = 0UL; - login_response_pkt->opcode = ISCSI_OPCODE_SERVER_LOGIN_RES; login_response_pkt->flags = (int8_t) (login_req_pkt->flags & (ISCSI_LOGIN_REQ_FLAGS_TRANSIT | ISCSI_LOGIN_REQ_FLAGS_CONTINUE | ISCSI_LOGIN_REQ_FLAGS_CURRENT_STAGE_MASK)); @@ -3342,41 +2713,6 @@ static int iscsi_connection_pdu_login_response_init(iscsi_pdu *login_response_pd } /** - * @brief Saves incoming key / value pairs from the client of a login request PDU. - * - * The login response structure has status detail - * invalid login request type set in case of an error. - * - * @param[in] conn Pointer to iSCSI connection - * used for key and value pair extraction. - * @param[out] key_value_pairs Pointer to hash map which - * stores all the parsed key and value pairs. - * @param[in] login_response_pdu Pointer to iSCSI login response - * PDU, may NOT be NULL, so be careful. - * @param[in] pdu Pointer to iSCSI login request packet - * PDU, may NOT be NULL, so be careful. - * @retval -1 An error occured during parse of - * key and value pairs (memory exhaustion). - * @retval 0 All key and value pairs have been parsed successfully. - */ -static int iscsi_connection_save_incoming_key_value_pairs(iscsi_connection *conn, iscsi_login_kvp *key_value_pairs, iscsi_pdu *login_response_pdu, const iscsi_pdu *pdu) -{ - iscsi_login_req_packet *login_req_pkt = (iscsi_login_req_packet *) pdu->bhs_pkt; - iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - const int rc = iscsi_parse_login_key_value_pairs( key_value_pairs, (uint8_t *) pdu->ds_cmd_data, pdu->ds_len, - ((login_req_pkt->flags & ISCSI_LOGIN_REQ_FLAGS_CONTINUE) != 0), &conn->partial_pairs ); - - if ( rc < 0 ) { - login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; - login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISC; - - return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER; - } - - return ISCSI_CONNECT_PDU_READ_OK; -} - -/** * @brief Determines the session type of login. * * This function is used to retrieve the @@ -3393,13 +2729,17 @@ static int iscsi_connection_save_incoming_key_value_pairs(iscsi_connection *conn * otherwise. The output session 'type' is unchanged, if * an invalid session type value was retrieved. */ -static int iscsi_login_check_session_type(iscsi_pdu *login_response_pdu, const char *type_str ) +static int iscsi_login_parse_session_type(iscsi_pdu *login_response_pdu, const char *type_str, int *type) { iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - if ( type_str != NULL && strcasecmp( type_str, "Normal" ) == 0 ) + if ( type_str != NULL && strcasecmp( type_str, "Normal" ) == 0 ) { + *type = ISCSI_SESSION_TYPE_NORMAL; return ISCSI_CONNECT_PDU_READ_OK; + } + *type = ISCSI_SESSION_TYPE_INVALID; + logadd( LOG_DEBUG1, "Unsupported session type: %s", type_str ); login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISSING_PARAMETER; @@ -3426,11 +2766,60 @@ static int iscsi_login_check_session_type(iscsi_pdu *login_response_pdu, const c * @return 0 if the check was successful or a negative * error code otherwise. */ -static int iscsi_connection_login_check_target(iscsi_connection *conn, iscsi_pdu *login_response_pdu, uint8_t *target_name) +static int iscsi_image_from_target(iscsi_connection *conn, iscsi_pdu *login_response_pdu, const char *target_name) { iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - dnbd3_image_t *image = iscsi_target_node_image_get( target_name ); + char *image_rev = NULL; + char *tmpbuf = strdup( target_name ); + char *image_name = tmpbuf; + char *tmp = strchr( tmpbuf, ':' ); + + if ( tmpbuf == NULL ) { + logadd( LOG_ERROR, "iscsi_target_node_image_get: Out of memory while allocating DNBD3 image name for iSCSI target node" ); + login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR; + login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES; + + return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; + } + + while ( tmp != NULL ) { + *tmp++ = '\0'; + if ( image_rev != NULL ) { + image_name = image_rev; + } + image_rev = tmp; + tmp = strchr( tmp, ':' ); + } + + uint16_t rev = 0; + if ( image_rev != NULL ) { + char *end = NULL; + long rid = strtol( image_rev, &end, 10 ); + if ( end == NULL || *end != '\0' || rid < 0 || rid > 0xFFFF ) { + logadd( LOG_DEBUG1, "iscsi_image_from_target: Invalid revision number (%s) in iSCSI target node name: '%s'", image_rev, target_name ); + } else { + rev = (uint16_t)rid; + } + } + dnbd3_image_t *image = image_getOrLoad( image_name, rev ); + + if ( image == NULL && image_rev != NULL ) { + image = image_getOrLoad( image_rev, rev ); + } + + if ( image == NULL && strncasecmp( image_name, ISCSI_TARGET_NODE_WWN_NAME_PREFIX, ISCSI_STRLEN(ISCSI_TARGET_NODE_WWN_NAME_PREFIX) ) == 0 ) { + uint64_t wwn = strtoull( (image_name + ISCSI_STRLEN(ISCSI_TARGET_NODE_WWN_NAME_PREFIX)), NULL, 16 ); + + image = image_getByWwn( wwn, rev, true ); + + if ( image == NULL ) { + wwn = strtoull( (tmp + ISCSI_STRLEN(ISCSI_TARGET_NODE_WWN_NAME_PREFIX)), NULL, 16 ); + image = image_getByWwn( wwn, rev, true ); + } + } + + free( tmpbuf ); if ( image == NULL ) { login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; @@ -3485,57 +2874,51 @@ static void iscsi_connection_login_response_reject(iscsi_pdu *login_response_pdu * @param[in] conn Pointer to connection to link the PDU with. * If this is NULL the connection has to be * linked later. - * @param[in] ahs_len Length of AHS packet data to be appended. - * @param[in] header_digest_size Length of header digest. Currently, - * only 0, in which case the header digest will - * be removed, or 4 for CRC32C are allowed. * @param[in] ds_len Length of DataSegment packet data to be appended. * May not exceed 16MiB - 1 (16777215 bytes). - * @param[in] data_digest_size Length of optional data digest (0 or - * 4 for now) to add. * @return Pointer to allocated and zero filled PDU or NULL * in case of an error (usually memory exhaustion). */ -static iscsi_pdu *iscsi_connection_pdu_create(iscsi_connection *conn, const uint ahs_len, const int header_digest_size, const uint32_t ds_len, const int data_digest_size) +static iscsi_pdu *iscsi_connection_pdu_create(iscsi_connection *conn, const uint32_t ds_len) { - if ( (ahs_len > ISCSI_MAX_AHS_SIZE) || ((header_digest_size != 0) && (header_digest_size != ISCSI_DIGEST_SIZE)) || ((data_digest_size != 0) && data_digest_size != ISCSI_DIGEST_SIZE) || (ds_len > ISCSI_MAX_DS_SIZE) ) + if ( ds_len > ISCSI_MAX_DS_SIZE ) { + logadd( LOG_ERROR, "iscsi_pdu_create: Invalid DS length" ); return NULL; + } - const uint32_t pkt_ds_len = ISCSI_ALIGN(ds_len, ISCSI_ALIGN_SIZE); - const uint32_t len = (uint32_t) (sizeof(struct iscsi_bhs_packet) + (uint32_t) ahs_len + header_digest_size + pkt_ds_len + ((pkt_ds_len != 0UL) ? (uint32_t) data_digest_size : 0UL)); - - iscsi_pdu *pdu = malloc( sizeof(struct iscsi_pdu) + len ); + const uint32_t pkt_ds_len = ISCSI_ALIGN( ds_len, ISCSI_ALIGN_SIZE ); + const uint32_t len = (uint32_t) ( sizeof(struct iscsi_bhs_packet) + pkt_ds_len ); + iscsi_pdu *pdu = malloc( sizeof(struct iscsi_pdu) ); if ( pdu == NULL ) { logadd( LOG_ERROR, "iscsi_pdu_create: Out of memory while allocating iSCSI PDU" ); return NULL; } - iscsi_bhs_packet *bhs_pkt = (iscsi_bhs_packet *)(pdu + 1); + iscsi_bhs_packet *bhs_pkt = malloc( len ); + if ( bhs_pkt == NULL ) { + free( pdu ); + logadd( LOG_ERROR, "iscsi_pdu_create: Out of memory while allocating iSCSI BHS packet" ); + + return NULL; + } pdu->bhs_pkt = bhs_pkt; - pdu->ahs_pkt = (ahs_len != 0U) ? (iscsi_ahs_packet *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet) ) : NULL; - pdu->header_digest = (header_digest_size != 0) ? (iscsi_header_digest *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet) + ahs_len) : NULL; - pdu->ds_cmd_data = (pkt_ds_len != 0UL) ? (iscsi_scsi_ds_cmd_data *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet) + ahs_len + header_digest_size) : NULL; - pdu->data_digest = ((pkt_ds_len != 0uL) && (data_digest_size != 0)) ? (iscsi_data_digest *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet) + ahs_len + header_digest_size + ISCSI_ALIGN(pkt_ds_len, ISCSI_ALIGN_SIZE)) : NULL; + pdu->ahs_pkt = NULL; + pdu->ds_cmd_data = (pkt_ds_len != 0UL) ? (iscsi_scsi_ds_cmd_data *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet)) : NULL; pdu->task = NULL; pdu->flags = 0; pdu->bhs_pos = 0U; - pdu->ahs_pos = 0U; - pdu->ahs_len = ahs_len; - pdu->header_digest_pos = 0U; - pdu->header_digest_size = header_digest_size; - pdu->ds_len = pkt_ds_len; - pdu->pos = 0UL; - pdu->len = pkt_ds_len; - pdu->data_digest_pos = 0U; - pdu->data_digest_size = data_digest_size; - pdu->task_ref_cnt = 0U; + pdu->ahs_len = 0; + pdu->ds_len = ds_len; + pdu->ds_write_pos = 0; pdu->cmd_sn = 0UL; + pdu->recv_pos = 0; - if ( pkt_ds_len != 0UL ) + if ( pkt_ds_len != 0UL ) { memset( (((uint8_t *) pdu->ds_cmd_data) + ds_len), 0, (pkt_ds_len - ds_len) ); + } return pdu; } @@ -3552,6 +2935,9 @@ static iscsi_pdu *iscsi_connection_pdu_create(iscsi_connection *conn, const uint */ static void iscsi_connection_pdu_destroy(iscsi_pdu *pdu) { + if ( pdu == NULL ) + return; + free( pdu->bhs_pkt ); free( pdu ); } @@ -3566,32 +2952,29 @@ static void iscsi_connection_pdu_destroy(iscsi_pdu *pdu) * the packet data to. May NOT be NULL, so * be careful. * @param[in] ahs_len Length of AHS packet data to be appended. - * @param[in] header_digest_size Length of header digest. Currently, - * only 0, in which case the header digest will - * be removed, or 4 for CRC32C are allowed. * @param[in] ds_len Length of DataSegment packet data to be appended. * May not exceed 16MiB - 1 (16777215 bytes). - * @param[in] data_digest_size Length of optional data digest (0 or - * 4 for now) to add. * @return Pointer to allocated and zero filled PDU or NULL * in case of an error (usually memory exhaustion). */ -static iscsi_bhs_packet *iscsi_connection_pdu_append(iscsi_pdu *pdu, const uint ahs_len, const int header_digest_size, const uint32_t ds_len, const int data_digest_size) +static iscsi_bhs_packet *iscsi_connection_pdu_resize(iscsi_pdu *pdu, const uint ahs_len, const uint32_t ds_len) { - if ( (ahs_len > ISCSI_MAX_AHS_SIZE) || ((header_digest_size != 0) && (header_digest_size != ISCSI_DIGEST_SIZE)) || ((data_digest_size != 0) && data_digest_size != ISCSI_DIGEST_SIZE) || (ds_len > ISCSI_MAX_DS_SIZE) ) + if ( (ahs_len > ISCSI_MAX_AHS_SIZE) || (ds_len > ISCSI_MAX_DS_SIZE) || (ahs_len % 4 != 0) ) { + logadd( LOG_ERROR, "iscsi_connection_pdu_resize: Invalid AHS or DataSegment packet size" ); return NULL; + } - if ( (ahs_len != pdu->ahs_len) || (header_digest_size != pdu->header_digest_size) || (ds_len != pdu->ds_len) || (data_digest_size != pdu->data_digest_size) ) { + if ( (ahs_len != pdu->ahs_len) || (ds_len != pdu->ds_len) ) { iscsi_bhs_packet *bhs_pkt; const uint32_t pkt_ds_len = ISCSI_ALIGN(ds_len, ISCSI_ALIGN_SIZE); - const uint32_t old_len = (uint32_t) (sizeof(struct iscsi_bhs_packet) + (uint32_t) pdu->ahs_len + pdu->header_digest_size + pdu->ds_len + ((pdu->ds_len != 0UL) ? (uint32_t) pdu->data_digest_size : 0UL)); - const uint32_t new_len = (uint32_t) (sizeof(struct iscsi_bhs_packet) + (uint32_t) ahs_len + header_digest_size + pkt_ds_len + ((pkt_ds_len != 0UL) ? (uint32_t) data_digest_size : 0UL)); + const uint32_t old_len = (uint32_t) (sizeof(struct iscsi_bhs_packet) + (uint32_t) pdu->ahs_len + ISCSI_ALIGN(pdu->ds_len, ISCSI_ALIGN_SIZE)); + const uint32_t new_len = (uint32_t) (sizeof(struct iscsi_bhs_packet) + (uint32_t) ahs_len + pkt_ds_len); if ( new_len > old_len ) { bhs_pkt = realloc( pdu->bhs_pkt, new_len ); if ( bhs_pkt == NULL ) { - logadd( LOG_ERROR, "iscsi_connection_pdu_append: Out of memory while reallocating iSCSI PDU packet data" ); + logadd( LOG_ERROR, "iscsi_connection_pdu_resize: Out of memory while reallocating iSCSI PDU packet data" ); return NULL; } @@ -3601,182 +2984,19 @@ static iscsi_bhs_packet *iscsi_connection_pdu_append(iscsi_pdu *pdu, const uint bhs_pkt = pdu->bhs_pkt; } - pdu->ahs_pkt = (ahs_len != 0U) ? (iscsi_ahs_packet *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet) ) : NULL; - pdu->header_digest = (header_digest_size != 0) ? (iscsi_header_digest *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet) + ahs_len) : NULL; - pdu->ds_cmd_data = (pkt_ds_len != 0UL) ? (iscsi_scsi_ds_cmd_data *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet) + ahs_len + header_digest_size) : NULL; - pdu->data_digest = ((pkt_ds_len != 0UL) && (data_digest_size != 0)) ? (iscsi_data_digest *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet) + ahs_len + header_digest_size + pkt_ds_len) : NULL; + pdu->ahs_pkt = (ahs_len != 0U) ? (iscsi_ahs_packet *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet)) : NULL; + pdu->ds_cmd_data = (pkt_ds_len != 0UL) ? (iscsi_scsi_ds_cmd_data *) (((uint8_t *) bhs_pkt) + sizeof(struct iscsi_bhs_packet) + ahs_len) : NULL; pdu->ahs_len = ahs_len; - pdu->header_digest_size = header_digest_size; - pdu->ds_len = pkt_ds_len; - pdu->len = pkt_ds_len; - pdu->data_digest_size = data_digest_size; + pdu->ds_len = ds_len; - if ( pkt_ds_len != 0UL ) + if ( pkt_ds_len != 0UL ) { memset( (((uint8_t *) pdu->ds_cmd_data) + ds_len), 0, (pkt_ds_len - ds_len) ); + } } return pdu->bhs_pkt; } -/// CRC32C lookup table. Created with a polynomial reflect value of 0x82F63B78. -static const uint32_t crc32c_lut[] = { - 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, - 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, - 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, - 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, - 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, - 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, - 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, - 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, - 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, - 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, - 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, - 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, - 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, - 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, - 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, - 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, - 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, - 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, - 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, - 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, - 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, - 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, - 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, - 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, - 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, - 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, - 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, - 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, - 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, - 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, - 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, - 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351}; - -/** - * @brief Calculates digest (CRC32C). - * - * Calculates CRC32C with 0x82F63B78 polynomial - * reflect according to iSCSI specs.\n - * TODO: Implement optimized SSE4.2 and ARM versions - * - * @param[in] data Pointer to data to calculate CRC32C for. - * @param[in] len Length of data to be calculated. Must be - * divisable by 4 which is guaranteed by iSCSI standard. - * @param[in] crc32c Previous CRC32C in case of multiple passes. - * @return CRC32C value. THis function cannot fail. - */ -static inline uint32_t iscsi_crc32c_update(const uint8_t *data, const uint len, uint32_t crc32c) -{ - for ( uint i = 0; i < len - 3; i += 4 ) { - crc32c = (crc32c >> 8UL) ^ crc32c_lut[(crc32c ^ data[i]) & 0xFF]; - crc32c = (crc32c >> 8UL) ^ crc32c_lut[(crc32c ^ data[i + 1]) & 0xFF]; - crc32c = (crc32c >> 8UL) ^ crc32c_lut[(crc32c ^ data[i + 2]) & 0xFF]; - crc32c = (crc32c >> 8UL) ^ crc32c_lut[(crc32c ^ data[i + 3]) & 0xFF]; - } - - return crc32c; -} - -/** - * @brief Calculate and store iSCSI header digest (CRC32C). - * - * Calculates header digest (CRC32C) with - * 0x82F63B78 polynomial reflect according - * to iSCSI specs and stores the result in - * the iSCSI packet data. This function - * cannot fail. - * - * @param[out] header_digest Pointer to iSCSI header digest - * packet data to put CRC32C into. - * May NOT be NULL, so be careful. - * @param[in] packet_data Pointer to ISCSI BHS packet to - * calculate CRC32C for. NULL is NOT - * allowed here, take caution. - * @param[in] ahs_len AHS segment length in bytes. - */ -static void iscsi_connection_pdu_digest_header_update(iscsi_header_digest *header_digest, const iscsi_bhs_packet *packet_data, const uint ahs_len) -{ - const uint32_t crc32c = iscsi_crc32c_update( (uint8_t *) packet_data, (sizeof(struct iscsi_bhs_packet) + ahs_len), ISCSI_CRC32C_INITIAL ) ^ ISCSI_CRC32C_XOR; - - iscsi_put_le32( (uint8_t *) &header_digest->crc32c, crc32c ); -} - -/** - * @brief Validates a stored iSCSI header digest (CRC32C) with actual header data. - * - * Verifies header digest (CRC32C) with - * 0x82F63B78 polynomial reflect according - * to iSCSI specs. This function cannot - * fail. - * - * @param[in] header_digest Pointer to iSCSI header digest - * packet data to compare CRC32C with. - * May NOT be NULL, so be careful. - * @param[in] packet_data Pointer to ISCSI BHS packet to - * validate CRC32C for. May NOT be NULL, - * so be careful. - * @param[in] ahs_len AHS segment length in bytes. - * @retval true CRC32C matches the stored value. - * @retval false CRC32C does NOT match the stored value. - */ -static bool iscsi_connection_pdu_digest_header_verify(const iscsi_header_digest *header_digest, const iscsi_bhs_packet *packet_data, const uint ahs_len) -{ - const uint32_t crc32c = iscsi_crc32c_update( (uint8_t *) packet_data, (sizeof(struct iscsi_bhs_packet) + ahs_len), ISCSI_CRC32C_INITIAL ) ^ ISCSI_CRC32C_XOR; - - return (iscsi_get_le32(crc32c) == header_digest->crc32c); -} - -/** - * @brief Calculate iSCSI data digest (CRC32C). - * - * Calculates data digest (CRC32) with - * 0x82F63B78 polynomial reflect of a - * whole DataSegment (CRC32C) according - * to the iSCSI specs.\n - * The resulting CRC32C will be stored - * in the iSCSI packet. - * - * @param[out] data_digest Pointer to iSCSI data digest - * packet data to put CRC32C into. - * May NOT be NULL, so be careful. - * @param[in] ds_cmd_data Pointer to iSCSI DataSegment packet to - * calculate CRC32C for. NULL is NOT - * allowed here, take caution. - * @param[in] ds_len Data segment length in bytes. - */ -static void iscsi_connection_pdu_digest_data_update(iscsi_data_digest *data_digest, const iscsi_scsi_ds_cmd_data *ds_cmd_data, const uint32_t ds_len) -{ - const uint32_t crc32c = iscsi_crc32c_update( (uint8_t *) ds_cmd_data, ISCSI_ALIGN(ds_len, ISCSI_DIGEST_SIZE), ISCSI_CRC32C_INITIAL ) ^ ISCSI_CRC32C_XOR; - - iscsi_put_le32( (uint8_t *) &data_digest->crc32c, crc32c ); -} - -/** - * @brief Validates a stored iSCSI data digest (CRC32C) with actual DataSegment. - * - * Verifies data digest (CRC32C) with - * 0x82F63B78 polynomial reflect according - * to iSCSI specs. This function cannot - * fail. - * - * @param[out] data_digest Pointer to iSCSI data digest - * packet data to compare CRC32C with. - * May NOT be NULL, so be careful. - * @param[in] ds_cmd_data Pointer to iSCSI DataSegment - * packet to calculate CRC32C for. May NOT - * be NULL, so be careful. - * @param[in] ds_len Data segment length in bytes. - * @retval true CRC32C matches the stored value. - * @retval false CRC32C does NOT match the stored value. - */ -static bool iscsi_connection_pdu_digest_data_verify(const iscsi_data_digest *data_digest, const iscsi_scsi_ds_cmd_data *ds_cmd_data, const uint32_t ds_len) -{ - const uint32_t crc32c = iscsi_crc32c_update( (uint8_t *) ds_cmd_data, ISCSI_ALIGN(ds_len, ISCSI_DIGEST_SIZE), ISCSI_CRC32C_INITIAL ) ^ ISCSI_CRC32C_XOR; - - return (iscsi_get_le32(crc32c) == data_digest->crc32c); -} - /** * @brief Writes and sends a response PDU to the client. * @@ -3793,27 +3013,23 @@ static bool iscsi_connection_pdu_digest_data_verify(const iscsi_data_digest *dat */ static bool iscsi_connection_pdu_write(iscsi_connection *conn, iscsi_pdu *pdu) { - if ( ISCSI_GET_OPCODE(pdu->bhs_pkt->opcode) != ISCSI_OPCODE_CLIENT_LOGIN_REQ ) { - if ( pdu->header_digest != NULL ) - iscsi_connection_pdu_digest_header_update( pdu->header_digest, pdu->bhs_pkt, pdu->ahs_len ); - - if ( pdu->data_digest != NULL ) - iscsi_connection_pdu_digest_data_update( pdu->data_digest, pdu->ds_cmd_data, pdu->ds_len ); - } - if ( conn->state >= ISCSI_CONNECT_STATE_EXITING ) { iscsi_connection_pdu_destroy( pdu ); return false; } - const uint len = (uint) (sizeof(struct iscsi_bhs_packet) + pdu->ahs_len + conn->header_digest + ISCSI_ALIGN(pdu->ds_len, ISCSI_ALIGN_SIZE) + conn->data_digest); + // During allocation we already round up to ISCSI_ALIGN_SIZE, but store the requested size in the ds_len + // member, so it's safe to round up here before sending, the accessed memory will be valid and zeroed + const size_t len = (sizeof(struct iscsi_bhs_packet) + pdu->ahs_len + ISCSI_ALIGN(pdu->ds_len, ISCSI_ALIGN_SIZE)); + const ssize_t rc = sock_sendAll( conn->client->sock, pdu->bhs_pkt, len, ISCSI_CONNECT_SOCKET_WRITE_RETRIES ); - bool ok = iscsi_connection_write( conn, (uint8_t *) pdu->bhs_pkt, len ) > 0; iscsi_connection_pdu_destroy( pdu ); - if (!ok) { + + if ( rc != (ssize_t)len ) { conn->state = ISCSI_CONNECT_STATE_EXITING; + return false; } - return ok; + return true; } /** @@ -3874,7 +3090,7 @@ static int iscsi_connection_handle_reject(iscsi_connection *conn, iscsi_pdu *pdu pdu->flags |= ISCSI_PDU_FLAGS_REJECTED; const uint32_t ds_len = (uint32_t) sizeof(struct iscsi_bhs_packet) + ((uint32_t) pdu->bhs_pkt->total_ahs_len << 2UL); - iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, 0U, conn->header_digest, ds_len, conn->data_digest ); + iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, ds_len ); if ( response_pdu == NULL ) { logadd( LOG_ERROR, "iscsi_connection_handle_reject: Out of memory while allocating iSCSI reject response PDU" ); @@ -3990,7 +3206,7 @@ static int iscsi_connection_pdu_header_handle_login_req(iscsi_connection *conn, if ( pdu->ds_len > ISCSI_DEFAULT_RECV_DS_LEN ) return iscsi_connection_handle_reject( conn, pdu, ISCSI_REJECT_REASON_PROTOCOL_ERR ); - iscsi_pdu *login_response_pdu = iscsi_connection_pdu_create( conn, 0U, 0, ISCSI_DEFAULT_RECV_DS_LEN, 0 ); + iscsi_pdu *login_response_pdu = iscsi_connection_pdu_create( conn, 8192 ); if ( login_response_pdu == NULL ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; @@ -4097,11 +3313,10 @@ static int iscsi_connection_pdu_header_handle_scsi_cmd(iscsi_connection *conn, i task->scsi_task.flags |= ISCSI_SCSI_TASK_FLAGS_XFER_READ; if ( (scsi_cmd_pkt->flags_task & ISCSI_SCSI_CMD_FLAGS_TASK_WRITE) != 0 ) { - return iscsi_connection_handle_reject( conn, pdu, ISCSI_REJECT_REASON_PROTOCOL_ERR ); + return iscsi_connection_handle_reject( conn, pdu, ISCSI_REJECT_REASON_COMMAND_NOT_SUPPORTED ); } pdu->task = task; - pdu->task_ref_cnt++; return ISCSI_CONNECT_PDU_READ_OK; } @@ -4123,8 +3338,7 @@ static int iscsi_connection_pdu_header_handle_scsi_cmd(iscsi_connection *conn, i */ static int iscsi_connection_pdu_header_handle_text_req(iscsi_connection *conn, iscsi_pdu *pdu) { - if ( pdu->ds_len > (uint) (sizeof(struct iscsi_bhs_packet) + ISCSI_MAX_AHS_SIZE + conn->header_digest - + ISCSI_SESSION_DEFAULT_FIRST_BURST_LEN + conn->data_digest) ) + if ( pdu->ds_len > (uint) (sizeof(struct iscsi_bhs_packet) + ISCSI_DEFAULT_RECV_DS_LEN) ) return iscsi_connection_handle_reject( conn, pdu, ISCSI_REJECT_REASON_PROTOCOL_ERR ); iscsi_text_req_packet *text_req_pkt = (iscsi_text_req_packet *) pdu->bhs_pkt; @@ -4169,7 +3383,7 @@ static int iscsi_connection_pdu_header_handle_logout_req(iscsi_connection *conn, if ( (conn->session != NULL) && (conn->session->type == ISCSI_SESSION_TYPE_DISCOVERY) && (logout_req_pkt->reason_code != ISCSI_LOGOUT_REQ_REASON_CODE_CLOSE_SESSION) ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, 0U, conn->header_digest, 0UL, conn->data_digest ); + iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, 0UL ); if ( response_pdu == NULL ) { logadd( LOG_ERROR, "iscsi_connection_pdu_header_handle_logout_req: Out of memory while allocating iSCSI logout response PDU" ); @@ -4245,7 +3459,7 @@ static int iscsi_connection_pdu_header_handle(iscsi_connection *conn, iscsi_pdu return iscsi_connection_pdu_header_handle_login_req( conn, pdu ); if ( ((conn->flags & ISCSI_CONNECT_FLAGS_FULL_FEATURE) == 0) && (conn->state == ISCSI_CONNECT_STATE_RUNNING) ) { - iscsi_pdu *login_response_pdu = iscsi_connection_pdu_create( conn, 0U, 0, 0UL, 0 ); + iscsi_pdu *login_response_pdu = iscsi_connection_pdu_create( conn, 0UL ); if ( login_response_pdu == NULL ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; @@ -4326,7 +3540,7 @@ static int iscsi_connection_pdu_data_handle_nop_out(iscsi_connection *conn, iscs if ( init_task_tag == 0xFFFFFFFFUL ) return ISCSI_CONNECT_PDU_READ_OK; - iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, 0U, conn->header_digest, ds_len, conn->data_digest ); + iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, ds_len ); if ( response_pdu == NULL ) { logadd( LOG_ERROR, "iscsi_connection_pdu_data_handle_nop_out: Out of memory while allocating iSCSI NOP-In response PDU" ); @@ -4401,34 +3615,6 @@ static int iscsi_connection_pdu_data_handle_scsi_cmd(iscsi_connection *conn, isc return ISCSI_CONNECT_PDU_READ_OK; } -/** - * @brief Determines iSCSI session login steps for normal authentication. - * - * This function also does related validation checks. - * - * @param[in] conn Pointer to iSCSI connection, may NOT be - * NULL, so take caution. - * @param[in] login_response_pdu Pointer to login response PDU where - * NULL is not allowed, so be careful. - * @param[in] target_name Pointer to hash map containing the login - * request key and value pairs and may NOT be NULL, so - * take caution. - * @return 0 on successful operation, a negative error code - * otherwise. - */ -static int iscsi_connection_login_session_normal(iscsi_connection *conn, iscsi_pdu *login_response_pdu, const char *target_name) -{ - int rc = iscsi_connection_login_check_target( conn, login_response_pdu, target_name ); - - if ( rc != 0 ) - return rc; - - conn->flags &= ~(ISCSI_CONNECT_FLAGS_CHAP_REQUIRE | ISCSI_CONNECT_FLAGS_CHAP_MUTUAL); - conn->flags |= ISCSI_CONNECT_FLAGS_CHAP_DISABLE; - - return rc; -} - /* * This function is used to set the info in the connection data structure * return @@ -4470,23 +3656,23 @@ static int iscsi_connection_login_set_info(iscsi_connection *conn, iscsi_pdu *lo * may NOT be NULL, so be careful. * @param[in] login_response_pdu Pointer to login response PDU. * NULL is not allowed here, so take caution. - * @param[in] key_value_pairs Pointer to key and value pairs. + * @param[in] kvpairs Pointer to key and value pairs. * which may NOT be NULL, so take caution. * @param[in] cid Connection ID (CID). * @return 0 on success, a negative error code otherwise. */ -static int iscsi_connection_handle_login_phase_none(iscsi_connection *conn, iscsi_pdu *login_response_pdu, iscsi_login_kvp *key_value_pairs, uint cid) +static int iscsi_connection_handle_login_phase_none(iscsi_connection *conn, iscsi_pdu *login_response_pdu, iscsi_negotiation_kvp *kvpairs, uint cid) { int type, rc; iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - rc = iscsi_login_check_session_type( login_response_pdu, key_value_pairs->AuthMethod ); + rc = iscsi_login_parse_session_type( login_response_pdu, kvpairs->SessionType, &type ); if ( rc < 0 ) return rc; - if ( type == ISCSI_SESSION_TYPE_NORMAL ) { - rc = iscsi_connection_login_session_normal( conn, login_response_pdu, key_value_pairs ); + if ( kvpairs->TargetName != NULL && type == ISCSI_SESSION_TYPE_NORMAL ) { + rc = iscsi_image_from_target( conn, login_response_pdu, kvpairs->TargetName ); } else { login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISSING_PARAMETER; @@ -4500,120 +3686,105 @@ static int iscsi_connection_handle_login_phase_none(iscsi_connection *conn, iscs return iscsi_connection_login_set_info( conn, login_response_pdu, type, cid ); } +static int iscsi_write_login_options_to_pdu( iscsi_connection *conn, iscsi_negotiation_kvp *pairs, iscsi_pdu *response_pdu ) +{ + uint payload_len = response_pdu->ds_write_pos; + +# define ADD_KV_INTERNAL(num, key, value) do { \ +int rc = iscsi_append_key_value_pair_packet( num, key, value, (char *)response_pdu->ds_cmd_data, payload_len, response_pdu->ds_len ); \ +if ( rc < 0 ) return -1; \ +payload_len += rc; \ +} while (0) +# define ADD_KV_OPTION_INT(key) do { \ +if ( pairs->key != -1 ) ADD_KV_INTERNAL( true, #key, (const char *)(size_t)conn->session->opts.key ); \ +} while (0) +# define ADD_KV_OPTION_STR(key) do { \ +if ( pairs->key != NULL ) ADD_KV_INTERNAL( false, #key, conn->session->opts.key ); \ +} while (0) +# define ADD_KV_PLAIN_INT(key, value) do { \ +if ( pairs->key != -1 ) ADD_KV_INTERNAL( true, #key, (const char *)(size_t)(value) ); \ +} while (0) +# define ADD_KV_PLAIN_STR(key, value) do { \ +if ( pairs->key != NULL ) ADD_KV_INTERNAL( false, #key, value ); \ +} while (0) + ADD_KV_OPTION_INT( MaxRecvDataSegmentLength ); + ADD_KV_OPTION_INT( MaxBurstLength ); + ADD_KV_OPTION_INT( FirstBurstLength ); + ADD_KV_PLAIN_INT( MaxConnections, 1 ); + ADD_KV_PLAIN_INT( ErrorRecoveryLevel, 0 ); + ADD_KV_PLAIN_STR( HeaderDigest, "None" ); + ADD_KV_PLAIN_STR( DataDigest, "None" ); +# undef ADD_KV_PLAIN +# undef ADD_KV_OPTION_INT +# undef ADD_KV_OPTION_STR + + if ( payload_len <= response_pdu->ds_len ) { + response_pdu->ds_write_pos = payload_len; + } else { + response_pdu->ds_write_pos = response_pdu->ds_len; + } + return (int)payload_len; +} + /** - * @brief Handles the Current Stage (CSG) bit of login response. + * @brief Handles iSCSI connection login response. * - * This function determines the authentication method - * and processes the various authentication stages. + * This function negotiates the login parameters + * and determines the authentication method. * - * @param[in] conn Pointer to iSCSI connection, may NOT be - * NULL, so take caution. + * @param[in] conn Pointer to iSCSI connection, + * may NOT be NULL, so be careful. * @param[in] login_response_pdu Pointer to login response PDU. - * NULL is NOT an allowed value here, so be careful. - * @param[in] auth_method auth method requested, or NULL if not specified - * @return 0 if authentication has been handled successfully, - * a negative error code otherwise. + * NULL is not allowed here, so take caution. + * @return 0 on success, a negative error code otherwise. */ -static int iscsi_connecction_handle_login_response_csg_bit(iscsi_connection *conn, iscsi_pdu *login_response_pdu, char *auth_method) +static int iscsi_connecction_handle_login_response(iscsi_connection *conn, iscsi_pdu *login_response_pdu, iscsi_negotiation_kvp *pairs) { iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; + iscsi_connection_update_key_value_pairs( conn, pairs ); + int payload_len = iscsi_write_login_options_to_pdu( conn, pairs, login_response_pdu ); - switch ( ISCSI_LOGIN_RESPONSE_FLAGS_GET_CURRENT_STAGE(login_response_pkt->flags) ) { - case ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_SECURITY_NEGOTIATION : { - if ( auth_method != NULL && strcasecmp( auth_method, "None" ) == 0 ) { - conn->flags |= ISCSI_CONNECT_FLAGS_AUTH; - } else { - login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; - login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_AUTH_ERR; - - return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; - } - - break; - } - case ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_LOGIN_OPERATIONAL_NEGOTIATION : { - if ( conn->state == ISCSI_CONNECT_STATE_INVALID ) { - if ( conn->flags & ISCSI_CONNECT_FLAGS_CHAP_REQUIRE ) { - login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; - login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_AUTH_ERR; - - return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; - } else { - conn->flags |= ISCSI_CONNECT_FLAGS_AUTH; - } - } - - if ( (conn->flags & ISCSI_CONNECT_FLAGS_AUTH) == 0 ) { - login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; - login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_AUTH_ERR; + if ( payload_len < 0 || payload_len > login_response_pdu->ds_len ) { + login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_SERVER_ERR; + login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_SERVER_ERR_OUT_OF_RESOURCES; - return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; - } + return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; + } - break; - } - case ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_FULL_FEATURE_PHASE : - default : { + // Handle current stage (CSG bits) + switch ( ISCSI_LOGIN_RESPONSE_FLAGS_GET_CURRENT_STAGE(login_response_pkt->flags) ) { + case ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_SECURITY_NEGOTIATION : { + if ( pairs->AuthMethod != NULL && strcasecmp( pairs->AuthMethod, "None" ) == 0 ) { + conn->flags |= ISCSI_CONNECT_FLAGS_AUTH; + } else { + // Only "None" supported login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; - login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISC; + login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_AUTH_ERR; return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; - - break; } - } - return ISCSI_CONNECT_PDU_READ_OK; -} - -/** - * - * @brief Checks whether the session type is valid. - * - * This function also can be used to output - * debugging info about the session, which - * is currently not implemented. - * - * @param[in] conn Pointer to iSCSI connection to be checked for - * validity. May NOT be NULL, so be careful. - * @param[in] login_response_pdu Pointer to login response PDU to - * set status class and detail in case of an error. - * NULL is not an allowed value here, take caution. - * @return 0 if the session type is valid, a negative error code - * otherwise. - */ -static int iscsi_connection_login_session_info_notify(iscsi_connection *conn, iscsi_pdu *login_response_pdu) -{ - if ( (conn->session->type != ISCSI_SESSION_TYPE_NORMAL) && (conn->session->type != ISCSI_SESSION_TYPE_DISCOVERY) ) { - iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; + break; + } + case ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_LOGIN_OPERATIONAL_NEGOTIATION : { + if ( conn->state == ISCSI_CONNECT_STATE_INVALID ) { + conn->flags |= ISCSI_CONNECT_FLAGS_AUTH; + } + break; + } + case ISCSI_LOGIN_RESPONSE_FLAGS_CURRENT_STAGE_FULL_FEATURE_PHASE : + default : { login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISC; return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; } + } - return ISCSI_CONNECT_PDU_READ_OK; -} - -/** - * @brief Handles the Transit (T) bit of login response. - * - * This function handles the transitional stages - * of the authentication process. - * - * @param[in] conn Pointer to iSCSI connection, may NOT be - * NULL, so take caution. - * @param[in] login_response_pdu Pointer to login response PDU. - * NULL is NOT an allowed value here, so be careful. - * @return 0 if transition has been handled successfully, - * a negative error code otherwise. - */ -static int iscsi_connecction_handle_login_response_t_bit(iscsi_connection *conn, iscsi_pdu *login_response_pdu) -{ - iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - - switch ( ISCSI_LOGIN_RESPONSE_FLAGS_GET_NEXT_STAGE(login_response_pkt->flags) ) { + if ( (login_response_pkt->flags & ISCSI_LOGIN_RESPONSE_FLAGS_TRANSIT) != 0 ) { + // Client set the transition bit - requests to move on to next stage + switch ( ISCSI_LOGIN_RESPONSE_FLAGS_GET_NEXT_STAGE(login_response_pkt->flags) ) { case ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_SECURITY_NEGOTIATION : { conn->login_phase = ISCSI_LOGIN_RESPONSE_FLAGS_NEXT_STAGE_SECURITY_NEGOTIATION; @@ -4629,10 +3800,15 @@ static int iscsi_connecction_handle_login_response_t_bit(iscsi_connection *conn, iscsi_put_be16( (uint8_t *) &login_response_pkt->tsih, (uint16_t) conn->session->tsih ); - const int rc = iscsi_connection_login_session_info_notify( conn, login_response_pdu ); + if ( (conn->session->type != ISCSI_SESSION_TYPE_NORMAL) && (conn->session->type != ISCSI_SESSION_TYPE_DISCOVERY) ) { + logadd( LOG_DEBUG1, "Unsupported session type %d, rejecting", conn->session->type ); + iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - if ( rc < 0 ) - return rc; + login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; + login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISC; + + return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; + } conn->flags |= ISCSI_CONNECT_FLAGS_FULL_FEATURE; @@ -4643,8 +3819,7 @@ static int iscsi_connecction_handle_login_response_t_bit(iscsi_connection *conn, login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_MISC; return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; - - break; + } } } @@ -4652,48 +3827,6 @@ static int iscsi_connecction_handle_login_response_t_bit(iscsi_connection *conn, } /** - * @brief Handles iSCSI connection login response. - * - * This function negotiates the login parameters - * and determines the authentication method. - * - * @param[in] conn Pointer to iSCSI connection, - * may NOT be NULL, so be careful. - * @param[in] login_response_pdu Pointer to login response PDU. - * NULL is not allowed here, so take caution. - * @param[in] key_value_pairs Pointer to key and value pairs. - * which may NOT be NULL, so take caution. - * @return 0 on success, a negative error code otherwise. - */ -static int iscsi_connecction_handle_login_response(iscsi_connection *conn, iscsi_pdu *login_response_pdu, iscsi_login_kvp *key_value_pairs) -{ - iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; - - - // TODO: Handle KVPs - int ds_len = -1; - - if ( ds_len < 0L ) { - login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; - login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_AUTH_ERR; - - return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; - } - - login_response_pdu->ds_len = (uint32_t) ds_len; - - int rc = iscsi_connecction_handle_login_response_csg_bit( conn, login_response_pdu, key_value_pairs->AuthMethod ); - - if ( rc < 0 ) - return rc; - - if ( (login_response_pkt->flags & ISCSI_LOGIN_RESPONSE_FLAGS_TRANSIT) != 0 ) - rc = iscsi_connecction_handle_login_response_t_bit( conn, login_response_pdu ); - - return rc; -} - -/** * @brief Handles an incoming iSCSI payload data login request PDU. * * This function handles login request payload @@ -4710,6 +3843,7 @@ static int iscsi_connecction_handle_login_response(iscsi_connection *conn, iscsi */ static int iscsi_connection_pdu_data_handle_login_req(iscsi_connection *conn, iscsi_pdu *pdu) { + int rc; iscsi_pdu *login_response_pdu = (iscsi_pdu *) conn->login_response_pdu; if ( login_response_pdu == NULL ) @@ -4717,16 +3851,20 @@ static int iscsi_connection_pdu_data_handle_login_req(iscsi_connection *conn, is iscsi_login_req_packet *login_req_pkt = (iscsi_login_req_packet *) pdu->bhs_pkt; uint cid = iscsi_get_be16(login_req_pkt->cid); - int rc = iscsi_connection_save_incoming_key_value_pairs( conn, NULL, login_response_pdu, pdu ); - if ( rc < 0 ) { - iscsi_connection_pdu_login_response( conn, login_response_pdu ); + iscsi_negotiation_kvp pairs; + iscsi_login_response_packet *login_response_pkt = (iscsi_login_response_packet *) login_response_pdu->bhs_pkt; + rc = iscsi_parse_login_key_value_pairs( &pairs, (uint8_t *) pdu->ds_cmd_data, pdu->ds_len ); - return ISCSI_CONNECT_PDU_READ_OK; + if ( rc < 0 || rc > login_response_pdu->ds_len ) { + login_response_pkt->status_class = ISCSI_LOGIN_RESPONSE_STATUS_CLASS_CLIENT_ERR; + login_response_pkt->status_detail = ISCSI_LOGIN_RESPONSE_STATUS_DETAILS_CLIENT_ERR_AUTH_ERR; + + return ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE; } if ( conn->state == ISCSI_CONNECT_STATE_INVALID ) { - rc = iscsi_connection_handle_login_phase_none( conn, login_response_pdu, NULL, cid ); + rc = iscsi_connection_handle_login_phase_none( conn, login_response_pdu, &pairs, cid ); if ( (rc == ISCSI_CONNECT_PDU_READ_ERR_LOGIN_RESPONSE) || (rc == ISCSI_CONNECT_PDU_READ_ERR_LOGIN_PARAMETER) ) { iscsi_connection_pdu_login_response( conn, login_response_pdu ); @@ -4735,7 +3873,7 @@ static int iscsi_connection_pdu_data_handle_login_req(iscsi_connection *conn, is } } - rc = iscsi_connecction_handle_login_response( conn, login_response_pdu, NULL ); + rc = iscsi_connecction_handle_login_response( conn, login_response_pdu, &pairs ); if ( rc == ISCSI_CONNECT_PDU_READ_OK ) { conn->state = ISCSI_CONNECT_STATE_RUNNING; @@ -4764,14 +3902,14 @@ static int iscsi_connection_pdu_data_handle_login_req(iscsi_connection *conn, is static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, iscsi_pdu *pdu) { iscsi_text_req_packet *text_req_pkt = (iscsi_text_req_packet *) pdu->bhs_pkt; - int rc = iscsi_parse_login_key_value_pairs( NULL, (uint8_t *) pdu->ds_cmd_data, pdu->ds_len, ((text_req_pkt->flags & ISCSI_TEXT_REQ_FLAGS_CONTINUE) != 0), &conn->text_partial_pairs ); + iscsi_negotiation_kvp pairs; + int rc = iscsi_parse_login_key_value_pairs( &pairs, (uint8_t *) pdu->ds_cmd_data, pdu->ds_len ); if ( rc < 0 ) { return ISCSI_CONNECT_PDU_READ_ERR_FATAL; } - iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, 0U, conn->header_digest, - conn->session->opts.MaxRecvDataSegmentLength, conn->data_digest ); + iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn, 8192 ); if ( response_pdu == NULL ) { logadd( LOG_ERROR, "iscsi_connection_pdu_data_handle_text_req: Out of memory while allocating iSCSI text response PDU" ); @@ -4779,33 +3917,24 @@ static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, isc return ISCSI_CONNECT_PDU_READ_ERR_FATAL; } - response_pdu->ds_len = 0UL; + iscsi_connection_update_key_value_pairs( conn, &pairs ); - // TODO: Write stuff to reply packet - int ds_len = -1; + int payload_len = iscsi_write_login_options_to_pdu( conn, &pairs, response_pdu ); - if ( ds_len < 0L ) { + if ( payload_len < 0 || payload_len > response_pdu->ds_len ) { iscsi_connection_pdu_destroy( response_pdu ); return ISCSI_CONNECT_PDU_READ_ERR_FATAL; } - iscsi_text_response_packet *text_response_pkt = (iscsi_text_response_packet *) response_pdu->bhs_pkt; + iscsi_text_response_packet *text_response_pkt = (iscsi_text_response_packet *) iscsi_connection_pdu_resize( response_pdu, 0, response_pdu->ds_write_pos ); text_response_pkt->opcode = ISCSI_OPCODE_SERVER_TEXT_RES; - text_response_pkt->flags = 0; - - if ( (text_req_pkt->flags & ISCSI_TEXT_REQ_FLAGS_CONTINUE) != 0 ) - text_response_pkt->flags |= (int8_t) ISCSI_TEXT_RESPONSE_FLAGS_CONTINUE; - - if ( (text_req_pkt->flags & ISCSI_TEXT_REQ_FLAGS_FINAL) != 0 ) - text_response_pkt->flags |= (int8_t) ISCSI_TEXT_RESPONSE_FLAGS_FINAL; + text_response_pkt->flags = (int8_t) ISCSI_TEXT_RESPONSE_FLAGS_FINAL; - text_response_pkt->reserved = 0U; + text_response_pkt->reserved = 0; - text_response_pkt = (iscsi_text_response_packet *) iscsi_connection_pdu_append( response_pdu, response_pdu->ahs_len, conn->header_digest, ds_len, conn->data_digest ); - - iscsi_put_be32( (uint8_t *) &text_response_pkt->total_ahs_len, ds_len ); // TotalAHSLength is always 0 and DataSegmentLength is 24-bit, so write in one step. + iscsi_put_be32( (uint8_t *) &text_response_pkt->total_ahs_len, payload_len ); // TotalAHSLength is always 0 and DataSegmentLength is 24-bit, so write in one step. text_response_pkt->lun = text_req_pkt->lun; // Copying over doesn't change endianess. text_response_pkt->init_task_tag = text_req_pkt->init_task_tag; // Copying over doesn't change endianess. @@ -4828,7 +3957,6 @@ static int iscsi_connection_pdu_data_handle_text_req(iscsi_connection *conn, isc text_response_pkt->reserved2[1] = 0ULL; iscsi_connection_pdu_write( conn, response_pdu ); - iscsi_connection_update_key_value_pairs( conn ); return ISCSI_CONNECT_PDU_READ_OK; } @@ -4897,12 +4025,14 @@ static int iscsi_connection_pdu_data_handle(iscsi_connection *conn, iscsi_pdu *p * @brief Retrieves and merges splitted iSCSI PDU data read from TCP/IP socket. * * This function handles partial reads of data - * packet.\n - * Since iSCSI data can span multiple packets, not - * only by TCP/IP itself, but also by iSCSI protocol - * specifications, multiple calls are needed in order - * to be sure that all data packets have been - * received. + * packets.\n + * The function is guaranteed to read as many bytes as indicated by the + * PDU struct, unless the read timeout is reached, or the connection + * is closed/reset.\n + * Care is also taken for padding bytes that have to be read. It is + * assumed the according buffer will have enough space for the padding + * bytes, which is always guaranteed when using the create and resize + * helpers for allocating PDUs. * * @param[in] conn Pointer to iSCSI connection to read TCP/IP data from. * @param[in] pdu Pointer to iSCSI PDU to read TCP/IP data into. @@ -4912,36 +4042,19 @@ static int iscsi_connection_pdu_data_handle(iscsi_connection *conn, iscsi_pdu *p */ static int iscsi_connection_pdu_data_read(iscsi_connection *conn, iscsi_pdu *pdu) { - const uint32_t ds_len = pdu->ds_len; + const uint32_t ds_len = ISCSI_ALIGN( pdu->ds_len, ISCSI_ALIGN_SIZE ); - if ( pdu->pos < ds_len ) { - const int32_t len = iscsi_connection_read( conn, (((uint8_t *) pdu->ds_cmd_data) + pdu->pos), (ds_len - pdu->pos) ); + if ( pdu->recv_pos < ds_len ) { + const int32_t len = iscsi_connection_read( conn, (((uint8_t *) pdu->ds_cmd_data) + pdu->recv_pos), (ds_len - pdu->recv_pos) ); if ( len < 0L ) return len; - pdu->pos += len; + pdu->recv_pos += len; } - if ( pdu->pos < ds_len ) - return ISCSI_CONNECT_PDU_READ_PROCESSED; - - if ( pdu->data_digest != NULL ) { - if ( (int) pdu->data_digest_pos < pdu->data_digest_size ) { - const int32_t len = iscsi_connection_read( conn, (((uint8_t *) pdu->data_digest) + pdu->data_digest_pos), (pdu->data_digest_size - pdu->data_digest_pos) ); - - if ( len < 0L ) - return len; - - pdu->data_digest_pos += len; - - if ( (int) pdu->data_digest_pos < pdu->data_digest_size ) - return ISCSI_CONNECT_PDU_READ_OK; - } - - if ( !iscsi_connection_pdu_digest_data_verify( pdu->data_digest, pdu->ds_cmd_data, ds_len ) ) - return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - } + if ( pdu->recv_pos < ds_len ) + return ISCSI_CONNECT_PDU_READ_ERR_FATAL; return ISCSI_CONNECT_PDU_READ_OK; } @@ -4974,7 +4087,7 @@ static int iscsi_connection_pdu_read(iscsi_connection *conn) switch ( conn->pdu_recv_state ) { case ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_READY : { assert( conn->pdu_processing == NULL ); - conn->pdu_processing = iscsi_connection_pdu_create( conn, 0U, conn->header_digest, 0UL, conn->data_digest ); + conn->pdu_processing = iscsi_connection_pdu_create( conn, 0UL ); if ( conn->pdu_processing == NULL ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; @@ -4984,75 +4097,47 @@ static int iscsi_connection_pdu_read(iscsi_connection *conn) break; } case ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_HDR : { - if ( pdu->bhs_pos < sizeof(struct iscsi_bhs_packet) ) { + while ( pdu->bhs_pos < sizeof(struct iscsi_bhs_packet) ) { const int32_t len = iscsi_connection_read( conn, (((uint8_t *) pdu->bhs_pkt) + pdu->bhs_pos), (sizeof(struct iscsi_bhs_packet) - pdu->bhs_pos) ); if ( len < 0L ) { conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_ERR; - break; + return ISCSI_CONNECT_PDU_READ_ERR_FATAL; } pdu->bhs_pos += len; - - if ( pdu->bhs_pos < sizeof(struct iscsi_bhs_packet) ) - return ISCSI_CONNECT_PDU_READ_OK; } if ( (conn->flags & ISCSI_CONNECT_FLAGS_LOGGED_OUT) != 0 ) { conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_ERR; - break; + return ISCSI_CONNECT_PDU_READ_ERR_FATAL; } iscsi_bhs_packet *bhs_pkt = pdu->bhs_pkt; - const uint ahs_len = ((uint) bhs_pkt->total_ahs_len << 2U); + const uint ahs_len = ((uint) bhs_pkt->total_ahs_len * 4); const uint32_t ds_len = iscsi_get_be24(bhs_pkt->ds_len); - bhs_pkt = iscsi_connection_pdu_append( pdu, ahs_len, conn->header_digest, ds_len, conn->data_digest ); + bhs_pkt = iscsi_connection_pdu_resize( pdu, ahs_len, ds_len ); if ( bhs_pkt == NULL ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - if ( pdu->ahs_pos < ahs_len ) { - const int32_t len = iscsi_connection_read( conn, (((uint8_t *) pdu->ahs_pkt) + pdu->ahs_pos), (ahs_len - pdu->ahs_pos) ); + int pos = 0; + while ( pos < ahs_len ) { + const int32_t len = iscsi_connection_read( conn, (((uint8_t *) pdu->ahs_pkt) + pos), (ahs_len - pos) ); if ( len < 0L ) { conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_ERR; - break; - } - - pdu->ahs_pos += len; - - if ( pdu->ahs_pos < ahs_len ) - return ISCSI_CONNECT_PDU_READ_OK; - } - - if ( pdu->header_digest != NULL ) { - if ( (int) pdu->header_digest_pos < pdu->header_digest_size ) { - const int32_t len = iscsi_connection_read( conn, (((uint8_t *) pdu->header_digest) + pdu->header_digest_pos), (pdu->header_digest_size - pdu->header_digest_pos) ); - - if ( len < 0L ) { - conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_ERR; - - break; - } - - pdu->header_digest_pos += len; - - if ( (int) pdu->header_digest_pos < pdu->header_digest_size ) - return ISCSI_CONNECT_PDU_READ_OK; + return ISCSI_CONNECT_PDU_READ_ERR_FATAL; } - if ( !iscsi_connection_pdu_digest_header_verify( pdu->header_digest, bhs_pkt, ahs_len ) ) { - conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_ERR; - - break; - } + pos += len; } - if ((iscsi_connection_pdu_header_handle( conn, pdu ) < 0)) { + if ( iscsi_connection_pdu_header_handle( conn, pdu ) < 0 ) { conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_ERR; } else { conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_DATA; @@ -5067,7 +4152,7 @@ static int iscsi_connection_pdu_read(iscsi_connection *conn) if ( len < 0 ) { conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_ERR; - break; + return ISCSI_CONNECT_PDU_READ_ERR_FATAL; } else if ( len > 0 ) { return ISCSI_CONNECT_PDU_READ_OK; } @@ -5138,7 +4223,7 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ return; } - conn->pdu_processing = iscsi_connection_pdu_create( conn, 0U, 0, 0UL, 0 ); + conn->pdu_processing = iscsi_connection_pdu_create( conn, 0UL ); if ( conn->pdu_processing == NULL ) { iscsi_connection_destroy( conn ); diff --git a/src/server/iscsi.h b/src/server/iscsi.h index 7137991..0c279fe 100644 --- a/src/server/iscsi.h +++ b/src/server/iscsi.h @@ -32,10 +32,6 @@ #ifndef DNBD3_ISCSI_H_ #define DNBD3_ISCSI_H_ -#ifdef __cplusplus -extern "C" { -#endif - #include <limits.h> #include <stdbool.h> #include <stdint.h> @@ -48,23 +44,23 @@ extern "C" { #include "image.h" #if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) - // GCC-compatible compiler, targeting x86/x86-64 - #include <x86intrin.h> + // GCC-compatible compiler, targeting x86/x86-64 + #include <x86intrin.h> #elif defined(__GNUC__) && defined(__ARM_NEON__) - // GCC-compatible compiler, targeting ARM with NEON - #include <arm_neon.h> + // GCC-compatible compiler, targeting ARM with NEON + #include <arm_neon.h> #elif defined(__GNUC__) && defined(__IWMMXT__) - // GCC-compatible compiler, targeting ARM with WMMX - #include <mmintrin.h> + // GCC-compatible compiler, targeting ARM with WMMX + #include <mmintrin.h> #elif (defined(__GNUC__) || defined(__xlC__)) && (defined(__VEC__) || defined(__ALTIVEC__)) - // XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX - #include <altivec.h> + // XLC or GCC-compatible compiler, targeting PowerPC with VMX/VSX + #include <altivec.h> #elif defined(__GNUC__) && defined(__SPE__) - // GCC-compatible compiler, targeting PowerPC with SPE - #include <spe.h> + // GCC-compatible compiler, targeting PowerPC with SPE + #include <spe.h> #elif defined(_MSC_VER) - // Microsoft C/C++-compatible compiler - #include <intrin.h> + // Microsoft C/C++-compatible compiler + #include <intrin.h> #endif #if defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN) || (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) @@ -241,47 +237,6 @@ static inline bool iscsi_is_pow2(const uint32_t value) return ((value & (value - 1UL)) == 0UL); } -/** - * @brief Calculates the shift factor for a power of two value. - * - * This function is used to determine - * the shift factor to use instead of - * using very slow multiplication, - * division and modulo operations. - * - * @param[in] value Value to retrieve the - * the shift factor for. May NOT be - * zero in which case the result is - * undefined. - * @return The shift count to use as a - * replacement for multiplication - * and division. - */ -static inline uint32_t iscsi_get_log2_of_pow2(const uint32_t value) -{ -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) || defined(__INTEL_COMPILER) || defined(__ECC) -// GCC, CLang or Intel Compiler - return (((sizeof(uint32_t) * CHAR_BIT) - 1UL) - (uint32_t) __builtin_clz( value )); -#elif defined(_MSC_VER) -// MSVC - uint32_t shift; - - _BitScanReverse( &shift, value ); - - return (((sizeof(uint32_t) * CHAR_BIT) - 1UL) - shift); -#else -// Other compilers (use slow parallel calculation method with logical OR, bit shift, logcal AND) - uint32_t shift = ((value & 0xAAAAAAAAUL) != 0UL); - - shift |= ((value & 0xCCCCCCCCUL) != 0UL) << 1UL; - shift |= ((value & 0xF0F0F0F0UL) != 0UL) << 2UL; - shift |= ((value & 0xFF00FF00UL) != 0UL) << 3UL; - shift |= ((value & 0xFFFF0000UL) != 0UL) << 4UL; - - return shift; -#endif -} - /// Determines the next offset after member b of struct a. #define ISCSI_NEXT_OFFSET(a, b) (offsetof(struct a, b) + sizeof(((struct a *) 0)->b)) @@ -485,6 +440,7 @@ static inline uint32_t iscsi_get_log2_of_pow2(const uint32_t value) /// iSCSI opcode flags (I) Immediate bit: For Request PDUs, the I bit set to 1 is an immediate delivery marker. #define ISCSI_OPCODE_FLAGS_IMMEDIATE (1 << 6L) +#define ASSERT_IS_BHS(structname) _Static_assert( sizeof(structname) == ISCSI_BHS_SIZE, #structname " messed up" ) /** * @brief iSCSI Basic Header Segment packet data. @@ -495,32 +451,34 @@ static inline uint32_t iscsi_get_log2_of_pow2(const uint32_t value) * has been determined. */ typedef struct __attribute__((packed)) iscsi_bhs_packet { - /// Command opcode. - uint8_t opcode; + /// Command opcode. + uint8_t opcode; - /// Opcode-specific fields. - uint8_t opcode_fields[3]; + /// Opcode-specific fields. + uint8_t opcode_fields[3]; - /// Total length of AHS (Advanced Header Segment). - uint8_t total_ahs_len; + /// Total length of AHS (Advanced Header Segment). + uint8_t total_ahs_len; - /// Length of Data Segment. - uint8_t ds_len[3]; + /// Length of Data Segment. + uint8_t ds_len[3]; - union { - /// SCSI LUN bit mask. - uint64_t lun; + union { + /// SCSI LUN bit mask. + uint64_t lun; - /// Opcode-specific fields. - uint8_t opcode_spec[8]; - } lun_opcode; + /// Opcode-specific fields. + uint8_t opcode_spec[8]; + } lun_opcode; - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; - /// Opcode-specific fields. - uint8_t opcode_spec_fields[28]; + /// Opcode-specific fields. + uint8_t opcode_spec_fields[28]; } iscsi_bhs_packet; +ASSERT_IS_BHS( iscsi_bhs_packet ); + /// iSCSI AHS type: Extended Command Descriptor Block (CDB). @@ -539,61 +497,19 @@ typedef struct __attribute__((packed)) iscsi_bhs_packet { * has been determined. */ typedef struct __attribute__((packed)) iscsi_ahs_packet { - /// AHSLength. - uint16_t len; + /// AHSLength. + uint16_t len; - /// AHSType. - uint8_t type; + /// AHSType. + uint8_t type; - /// AHS-Specific. - uint8_t specific; + /// AHS-Specific. + uint8_t specific; - /// AHS-Specific data. - uint8_t data[0]; + /// AHS-Specific data. + uint8_t data[0]; } iscsi_ahs_packet; - -/** - * @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 { - /// 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 { - /// 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) - - /// 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; - - /** * @brief DataSegment Error: Unexpected unsolicited data. * @@ -635,84 +551,6 @@ typedef struct __attribute__((packed)) iscsi_bidi_read_exp_xfer_ahs_packet { */ #define ISCSI_DS_ERROR_INCORRECT_AMOUNT_OF_DATA_ASCQ 0x0D - -/** - * @brief DataSegment Error: Protocol Service CRC error. - * - * Certain iSCSI conditions result in the command being terminated at - * the target (response code of Command Completed at Target) with a SCSI - * CHECK CONDITION Status as outlined in the following definitions - * (Sense key: Aborted Command 0x0B). - */ -#define ISCSI_DS_ERROR_PROTOCOL_SERVICE_CRC_ERROR_ASC 0x47 - -/** - * @brief DataSegment Error: Protocol Service CRC error. - * - * Certain iSCSI conditions result in the command being terminated at - * the target (response code of Command Completed at Target) with a SCSI - * CHECK CONDITION Status as outlined in the following definitions - * (Sense key: Aborted Command 0x0B). - */ -#define ISCSI_DS_ERROR_PROTOCOL_SERVICE_CRC_ERROR_ASCQ 0x05 - - -/** - * @brief DataSegment Error: Selective Negative / Sequence Number Acknowledgment (SNACK) rejected. - * - * Certain iSCSI conditions result in the command being terminated at - * the target (response code of Command Completed at Target) with a SCSI - * CHECK CONDITION Status as outlined in the following definitions - * (Sense key: Aborted Command 0x0B). - */ -#define ISCSI_DS_ERROR_SNACK_REJECTED_ASC 0x11 - -/** - * @brief DataSegment Error: Selective Negative / Sequence Number Acknowledgment (SNACK) rejected. - * - * Certain iSCSI conditions result in the command being terminated at - * the target (response code of Command Completed at Target) with a SCSI - * CHECK CONDITION Status as outlined in the following definitions - * (Sense key: Aborted Command 0x0B). - */ -#define ISCSI_DS_ERROR_SNACK_REJECTED_ASCQ 0x13 - - -/** - * @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 { - /// 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 { - /// Data digest is a CRC32C for ensuring integrity. - uint32_t crc32c; -} iscsi_data_digest; - - /** * @brief iSCSI SCSI CDB packet data structure. * @@ -721,11 +559,11 @@ typedef struct __attribute__((packed)) iscsi_data_digest { * MUST be used to contain the CDB spillover. */ typedef struct __attribute__((packed)) iscsi_scsi_cdb { - /// SCSI opcode. - uint8_t opcode; + /// SCSI opcode. + uint8_t opcode; - /// Additional op-code specific data. - uint8_t data[0]; + /// Additional op-code specific data. + uint8_t data[0]; } iscsi_scsi_cdb; @@ -742,20 +580,20 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb { * There are 6 bytes in the CDB field for this command. */ typedef struct __attribute__((packed)) iscsi_scsi_cdb_inquiry { - /// SCSI opcode. - iscsi_scsi_cdb cdb; + /// SCSI opcode. + iscsi_scsi_cdb cdb; - /// Logical Unit Number (LUN), CMMDT and EVPD. - uint8_t lun_flags; + /// Logical Unit Number (LUN), CMMDT and EVPD. + uint8_t lun_flags; - /// Page code. - uint8_t page_code; + /// Page code. + uint8_t page_code; - /// Allocation length in bytes. - uint16_t alloc_len; + /// Allocation length in bytes. + uint16_t alloc_len; - /// Control. - uint8_t control; + /// Control. + uint8_t control; } iscsi_scsi_cdb_inquiry; @@ -765,17 +603,17 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_inquiry { * There are 6 bytes in the CDB field for this command. */ typedef struct __attribute__((packed)) iscsi_scsi_cdb_read_write_6 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; + /// SCSI opcode. + iscsi_scsi_cdb cdb; - /// Logical Block Address (LBA). - uint8_t lba[3]; + /// Logical Block Address (LBA). + uint8_t lba[3]; - /// Transfer length in bytes. - uint8_t xfer_len; + /// Transfer length in bytes. + uint8_t xfer_len; - /// Control. - uint8_t control; + /// Control. + uint8_t control; } iscsi_scsi_cdb_read_write_6; @@ -785,23 +623,23 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_read_write_6 { * There are 10 bytes in the CDB field for this command. */ typedef struct __attribute__((packed)) iscsi_scsi_cdb_read_write_10 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; + /// SCSI opcode. + iscsi_scsi_cdb cdb; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Logical Block Address (LBA). - uint32_t lba; + /// Logical Block Address (LBA). + uint32_t lba; - /// Group number. - int8_t group_num; + /// Group number. + int8_t group_num; - /// Transfer length in bytes. - uint16_t xfer_len; + /// Transfer length in bytes. + uint16_t xfer_len; - /// Control. - uint8_t control; + /// Control. + uint8_t control; } iscsi_scsi_cdb_read_write_10; @@ -811,23 +649,23 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_read_write_10 { * There are 12 bytes in the CDB field for this command. */ typedef struct __attribute__((packed)) iscsi_scsi_cdb_read_write_12 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; + /// SCSI opcode. + iscsi_scsi_cdb cdb; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Logical Block Address (LBA). - uint32_t lba; + /// Logical Block Address (LBA). + uint32_t lba; - /// Transfer length in bytes. - uint32_t xfer_len; + /// Transfer length in bytes. + uint32_t xfer_len; - /// Restricted for MMC-6 and group number. - int8_t restrict_group_num; + /// Restricted for MMC-6 and group number. + int8_t restrict_group_num; - /// Control. - uint8_t control; + /// Control. + uint8_t control; } iscsi_scsi_cdb_read_write_12; @@ -837,23 +675,23 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_read_write_12 { * There are 16 bytes in the CDB field for this command. */ typedef struct __attribute__((packed)) iscsi_scsi_cdb_read_write_16 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; + /// SCSI opcode. + iscsi_scsi_cdb cdb; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Logical Block Address (LBA). - uint64_t lba; + /// Logical Block Address (LBA). + uint64_t lba; - /// Transfer length in bytes. - uint32_t xfer_len; + /// Transfer length in bytes. + uint32_t xfer_len; - /// Restricted for MMC-6 and group number. - int8_t restrict_group_num; + /// Restricted for MMC-6 and group number. + int8_t restrict_group_num; - /// Control. - uint8_t control; + /// Control. + uint8_t control; } iscsi_scsi_cdb_read_write_16; @@ -873,86 +711,32 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_read_write_16 { * There are 12 bytes in the CDB field for this command. */ typedef struct __attribute__((packed)) iscsi_scsi_cdb_report_luns { - /// SCSI opcode. - iscsi_scsi_cdb cdb; + /// SCSI opcode. + iscsi_scsi_cdb cdb; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved; - /// Select report. - uint8_t select_report; + /// Select report. + uint8_t select_report; - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved2; + /// Reserved for future usage (always MUST be 0 for now). + uint16_t reserved2; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved3; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved3; - /// Allocation length in bytes. - uint32_t alloc_len; + /// Allocation length in bytes. + uint32_t alloc_len; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved4; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved4; - /// Control. - uint8_t control; + /// Control. + uint8_t control; } iscsi_scsi_cdb_report_luns; -/// iSCSI SCSI Command Descriptor Block (CDB) for COMPARE AND WRITE command flags: Force Unit Access (FUA). -#define ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_FUA (1 << 3L) - -/// iSCSI SCSI Command Descriptor Block (CDB) for COMPARE AND WRITE command flags: Disable Page Out (DPO). -#define ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_DPO (1 << 4L) - -/// iSCSI SCSI Command Descriptor Block (CDB) for COMPARE AND WRITE command write protect flags: First bit of the three bits. -#define ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_FIRST_BIT 5 - -/// iSCSI SCSI Command Descriptor Block (CDB) for COMPARE AND WRITE command write protect flags: Last bit of the three bits. -#define ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_LAST_BIT ((ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_FIRST_BIT) + 3 - 1) - -/// iSCSI SCSI Command Descriptor Block (CDB) for COMPARE AND WRITE command write protect flags: Bit mask. -#define ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_FIRST_BIT, ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_LAST_BIT)) - -/// iSCSI SCSI Command Descriptor Block (CDB) for COMPARE AND WRITE command write protect flags: Extracts the write protect bits. -#define ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_GET_WRPROTECT(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_FIRST_BIT, ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_LAST_BIT)) - -/// iSCSI SCSI Command Descriptor Block (CDB) for COMPARE AND WRITE command write protect flags: Stores into the write protect bits. -#define ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_PUT_WRPROTECT(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_FIRST_BIT, ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_LAST_BIT)) - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI COMPARE AND WRITE command. - * - * There are 16 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_cmp_write { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Flags. - int8_t flags; - - /// Logical Block Address (LBA). - uint64_t lba; - - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved; - - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved2; - - /// Number of blocks in bytes. - uint8_t num_blocks; - - /// Restricted for MMC-6 and group number. - int8_t restrict_group_num; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_cmp_write; - - /// iSCSI SCSI Command Descriptor Block (CDB) for SERVICE ACTION IN(16) command service action: READ CAPACITY(16). #define ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_READ_CAPACITY_16 0x10 @@ -981,196 +765,26 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_cmp_write { * There are 16 bytes in the CDB field for this command. */ typedef struct __attribute__((packed)) iscsi_scsi_cdb_service_action_in_16 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; + /// SCSI opcode. + iscsi_scsi_cdb cdb; - /// Service action. - uint8_t action; + /// Service action. + uint8_t action; - /// Logical Block Address (LBA), obselete by now. - uint64_t lba; + /// Logical Block Address (LBA), obselete by now. + uint64_t lba; - /// Allocation length in bytes. - uint32_t alloc_len; + /// Allocation length in bytes. + uint32_t alloc_len; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved; - /// Control. - uint8_t control; + /// Control. + uint8_t control; } iscsi_scsi_cdb_service_action_in_16; -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI SYNCHRONIZE CACHE(10) command. - * - * There are 10 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_sync_cache_10 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Flags. - int8_t flags; - - /// Logical Block Address (LBA). - uint32_t lba; - - /// Group number. - int8_t group_num; - - /// Transfer length in bytes. - uint16_t xfer_len; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_sync_cache_10; - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI SYNCHRONIZE CACHE(16) command. - * - * There are 16 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_sync_cache_16 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Flags. - int8_t flags; - - /// Logical Block Address (LBA). - uint64_t lba; - - /// Transfer length in bytes. - uint32_t xfer_len; - - /// Group number. - int8_t group_num; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_sync_cache_16; - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI WRITE SAME(10) command. - * - * There are 10 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_write_same_10 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Flags. - int8_t flags; - - /// Logical Block Address (LBA). - uint32_t lba; - - /// Group number. - int8_t group_num; - - /// Transfer length in bytes. - uint16_t xfer_len; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_write_same_10; - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI WRITE SAME(16) command. - * - * There are 16 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_write_same_16 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Flags. - int8_t flags; - - /// Logical Block Address (LBA). - uint64_t lba; - - /// Transfer length in bytes. - uint32_t xfer_len; - - /// Group number. - int8_t group_num; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_write_same_16; - - -/// iSCSI SCSI Command Descriptor Block (CDB) for MODE SELECT(6) command flags: Save Pages (SP). -#define ISCSI_SCSI_CDB_MODE_SELECT_6_FLAGS_SP (1 << 0) - -/// iSCSI SCSI Command Descriptor Block (CDB) for MODE SELECT(6) command flags: Revert To Defaults (RTD). -#define ISCSI_SCSI_CDB_MODE_SELECT_6_FLAGS_RTD (1 << 1) - -/// iSCSI SCSI Command Descriptor Block (CDB) for MODE SELECT(6) command flags: Page Format (PF). -#define ISCSI_SCSI_CDB_MODE_SELECT_6_FLAGS_PF (1 << 4) - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI MODE SELECT(6) command. - * - * There are 6 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_mode_select_6 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Flags. - int8_t flags; - - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved; - - /// Parameter list length in bytes. - uint8_t param_list_len; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_mode_select_6; - - -/// iSCSI SCSI Command Descriptor Block (CDB) for MODE SELECT(10) command flags: Save Pages (SP). -#define ISCSI_SCSI_CDB_MODE_SELECT_10_FLAGS_SP (1 << 0) - -/// iSCSI SCSI Command Descriptor Block (CDB) for MODE SELECT(10) command flags: Page Format (PF). -#define ISCSI_SCSI_CDB_MODE_SELECT_10_FLAGS_PF (1 << 4) - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI MODE SELECT(10) command. - * - * There are 10 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_mode_select_10 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Flags. - int8_t flags; - - /// Reserved for future usage (always MUST be 0 for now). - uint32_t reserved; - - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved2; - - /// Parameter list length in bytes. - uint16_t param_list_len; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_mode_select_10; - - /// iSCSI SCSI Command Descriptor Block (CDB) for MODE SENSE(6) command flags: Disable Block Descriptors (DBD). #define ISCSI_SCSI_CDB_MODE_SENSE_6_FLAGS_DBD (1 << 3) @@ -1224,23 +838,23 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_mode_select_10 { * There are 6 bytes in the CDB field for this command. */ typedef struct __attribute__((packed)) iscsi_scsi_cdb_mode_sense_6 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; + /// SCSI opcode. + iscsi_scsi_cdb cdb; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Page code and page control. - uint8_t page_code_control; + /// Page code and page control. + uint8_t page_code_control; - /// Sub page code. - uint8_t sub_page_code; + /// Sub page code. + uint8_t sub_page_code; - /// Allocation length in bytes. - uint8_t alloc_len; + /// Allocation length in bytes. + uint8_t alloc_len; - /// Control. - uint8_t control; + /// Control. + uint8_t control; } iscsi_scsi_cdb_mode_sense_6; @@ -1300,437 +914,32 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_mode_sense_6 { * There are 10 bytes in the CDB field for this command. */ typedef struct __attribute__((packed)) iscsi_scsi_cdb_mode_sense_10 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; + /// SCSI opcode. + iscsi_scsi_cdb cdb; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Page code and page control. - uint8_t page_code_control; + /// Page code and page control. + uint8_t page_code_control; - /// Sub page code. - uint8_t sub_page_code; + /// Sub page code. + uint8_t sub_page_code; - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint16_t reserved; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved2; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved2; - /// Allocation length in bytes. - uint16_t alloc_len; + /// Allocation length in bytes. + uint16_t alloc_len; - /// Control. - uint8_t control; + /// Control. + uint8_t control; } iscsi_scsi_cdb_mode_sense_10; -/// iSCSI SCSI Command Descriptor Block (CDB) for REQUEST SENSE command flags: Descriptor Format (DESC). -#define ISCSI_SCSI_CDB_REQ_SENSE_FLAGS_DESC (1 << 0) - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI REQUEST SENSE command. - * - * There are 6 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_req_sense { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Flags. - int8_t flags; - - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved; - - /// Allocation length in bytes. - uint8_t alloc_len; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_req_sense; - - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags: Reply immediately after CDB check (IMMED). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_EXEC_FLAGS_IMMED (1 << 0) - - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Process the START and LOEJ bits. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_PROC_START_LOEJ_BITS 0x0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the active power condition (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_ACTIVE 0x0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the idle_a power condition (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_IDLE_A 0x0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the idle_b power condition (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_IDLE_B 0x1 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the idle_c power condition (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_IDLE_C 0x2 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the standby_z power condition (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_STANDBY_Z 0x0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the standby_b power condition (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_STANDBY_Y 0x1 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Initialize and start all of the idle and standby condition timers that are enabled (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_LU_CONTROL 0x0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Force the idle_a condition timer to be set to zero (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FORCE_IDLE_A_0 0x0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Force the idle_b condition timer to be set to zero (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FORCE_IDLE_B_0 0x1 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Force the idle_c condition timer to be set to zero (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FORCE_IDLE_C_0 0x2 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Force the standby_z condition timer to be set to zero (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FORCE_STANDBY_Z_0 0x0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Force the standby_y condition timer to be set to zero (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FORCE_STANDBY_Y_0 0x1 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: First bit of the four bits. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FIRST_BIT 0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Last bit of the four bits. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_LAST_BIT ((ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FIRST_BIT) + 4 - 1) - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Bit mask. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_LAST_BIT)) - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Extracts the power condition modifier bits. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_GET_POWER_COND_MOD(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_LAST_BIT)) - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Stores into the power condition modifier bits. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_PUT_POWER_COND_MOD(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_LAST_BIT)) - - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags: START. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_START (1 << 0) - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags: LOad EJect (LOEJ). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_LOEJ (1 << 1) - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags: Do not flush caches until a power condition that prevents accessing the medium is entered (NO_FLUSH). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_NO_FLUSH (1 << 2) - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Process the START and LOEJ bits (START_VALID). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_START_VALID 0x0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Cause the logical unit to transition to the active power condition (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_ACTIVE 0x1 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Cause the logical unit to transition to the idle_a to idle_c power conditions (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_IDLE 0x2 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Cause the logical unit to transition to the standby_z and standby_y power conditions (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_STANDBY 0x3 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Obselete. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_OBSELETE 0x5 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Initialize and start all of the idle and standby condition timers that are enabled (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_LU_CONTROL 0x7 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Force the idle_a to idle_c condition timers to be set to zero (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FORCE_IDLE_0 0xA - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Force the standby_z and standby_y condition timers to be set to zero (see SPC5). -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FORCE_STANDBY_0 0xB - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: First bit of the four bits. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FIRST_BIT 4 - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Last bit of the four bits. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_LAST_BIT ((ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FIRST_BIT) + 8 - 1) - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Bit mask. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_LAST_BIT)) - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Extracts the power condition bits. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_GET_POWER_COND(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_LAST_BIT)) - -/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Stores into the power condition bits. -#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_PUT_POWER_COND(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_LAST_BIT)) - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI START STOP UNIT command. - * - * There are 6 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_start_stop_unit { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Execution flags. - int8_t exec_flags; - - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved; - - /// Power condition modifier. - uint8_t power_cond_mod; - - /// Flags. - int8_t flags; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_start_stop_unit; - - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Register - Register a reservation key without making a reservation. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_REGISTER 0x00 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Reserve - Create a persistent reservation of the specified scope and type. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_RESERVE 0x01 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Release - Releases the selected reservation for the requesting initiator. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_RELEASE 0x02 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Clear – Clears all reservations keys and all persistent reservations. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_CLEAR 0x03 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Preempt – Preempt reservations from another initiator. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_PREEMPT 0x04 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Preempt reservations from another initiator and abort all tasks for all initiators with the specified reservation key. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_PREEMPT_ABORT 0x05 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Register and Ignore Existing Key – Register a new reservation key and discard existing reservation key. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_REGISTER_IGNORE_EXIST_KEY 0x06 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Register and Move Registers - Registers a reservation key for another I_T nexus and moves the persistent reservation to that I-T nexus. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_REGISTER_MOVE_REGS 0x07 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: First bit of the five bits. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_FIRST_BIT 0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Last bit of the five bits. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_LAST_BIT ((ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_FIRST_BIT) + 5 - 1) - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Bit mask. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_FIRST_BIT, ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_LAST_BIT)) - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Extracts the service action bits. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_GET_ACTION(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_FIRST_BIT, ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_LAST_BIT)) - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Stores into the service action bits. -#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_PUT_ACTION(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_FIRST_BIT, ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_LAST_BIT)) - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI PERSISTENT RESERVE OUT command. - * - * There are 10 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_pr_reserve_out { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Service action. - uint8_t action; - - /// Scope and reservation type. - uint8_t scope_type; - - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved; - - /// Parameter list length in bytes. - uint32_t param_list_len; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_pr_reserve_out; - - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE IN command service action: Read keys - Reads all registered reservation keys (i.e. registrations) as described in SPC5. -#define ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_READ_KEYS 0x00 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE IN command service action: Read reservations - Reads the current persistent reservations as described in SPC5. -#define ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_READ_RESERVATIONS 0x01 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE IN command service action: Report capabilities - Returns capability information. -#define ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_READ_REPORT_CAPABILITIES 0x02 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE IN command service action: Read full status – Reads complete information about all registrations and the persistent reservations, if any. -#define ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_READ_FULL_STATUS 0x03 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE IN command service action: First bit of the five bits. -#define ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_FIRST_BIT 0 - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE IN command service action: Last bit of the five bits. -#define ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_LAST_BIT ((ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_FIRST_BIT) + 5 - 1) - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE IN command service action: Bit mask. -#define ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_FIRST_BIT, ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_LAST_BIT)) - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE IN command service action: Extracts the service action bits. -#define ISCSI_SCSI_CDB_PR_RESERVE_IN_GET_ACTION(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_FIRST_BIT, ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_LAST_BIT)) - -/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE IN command service action: Stores into the service action bits. -#define ISCSI_SCSI_CDB_PR_RESERVE_IN_PUT_ACTION(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_FIRST_BIT, ISCSI_SCSI_CDB_PR_RESERVE_IN_ACTION_LAST_BIT)) - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI PERSISTENT RESERVE IN command. - * - * There are 10 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_pr_reserve_in { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Service action. - uint8_t action; - - /// Reserved for future usage (always MUST be 0 for now). - uint32_t reserved; - - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved2; - - /// Parameter list length in bytes. - uint16_t param_list_len; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_pr_reserve_in; - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI RESERVE(6) command. - * - * There are 6 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_pr_reserve_6 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved_obselete; - - /// Obselete byte. - uint8_t obselete; - - /// Obselete word. - uint16_t obselete2; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_pr_reserve_6; - - -/// iSCSI SCSI Command Descriptor Block (CDB) for RESERVE(10) command flags: Long identifier larger than 255 (LONGID). -#define ISCSI_SCSI_CDB_RESERVE_10_FLAGS_LONGID (1 << 1) - -/// iSCSI SCSI Command Descriptor Block (CDB) for RESERVE(10) command flags: Third-party reservation (3RDPTY). -#define ISCSI_SCSI_CDB_RESERVE_10_FLAGS_3RDPTY (1 << 4) - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI RESERVE(10) command. - * - * There are 10 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_pr_reserve_10 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Flags. - int8_t flags; - - /// Obselete. - uint8_t obselete; - - /// Third-party device identifier. - uint8_t third_party_dev_id; - - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved; - - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved2; - - /// Parameter list length in bytes. - uint16_t param_list_len; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_pr_reserve_10; - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI RELEASE(6) command. - * - * There are 6 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_pr_release_6 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved_obselete; - - /// Obselete byte. - uint8_t obselete; - - /// Obselete word. - uint16_t obselete2; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_pr_release_6; - - -/// iSCSI SCSI Command Descriptor Block (CDB) for RELEASE(10) command flags: Long identifier larger than 255 (LONGID). -#define ISCSI_SCSI_CDB_RELEASE_10_FLAGS_LONGID (1 << 1) - -/// iSCSI SCSI Command Descriptor Block (CDB) for RELEASE(10) command flags: Third-party reservation (3RDPTY). -#define ISCSI_SCSI_CDB_RELEASE_10_FLAGS_3RDPTY (1 << 4) - - -/** - * @brief iSCSI SCSI CDB packet data structure for SCSI RELEASE(10) command. - * - * There are 10 bytes in the CDB field for this command. - */ -typedef struct __attribute__((packed)) iscsi_scsi_cdb_pr_release_10 { - /// SCSI opcode. - iscsi_scsi_cdb cdb; - - /// Flags. - int8_t flags; - - /// Obselete. - uint8_t obselete; - - /// Third-party device identifier. - uint8_t third_party_dev_id; - - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved; - - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved2; - - /// Parameter list length in bytes. - uint16_t param_list_len; - - /// Control. - uint8_t control; -} iscsi_scsi_cdb_pr_release_10; - - /** * @brief iSCSI SCSI DataSegment Command packet structure. * @@ -1743,14 +952,14 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_pr_release_10 { * contain a vendor-specific detailed description of the failure). */ typedef struct __attribute__((packed)) iscsi_scsi_ds_cmd_data { - /// SenseLength: This field indicates the length of Sense Data. - uint16_t len; + /// SenseLength: This field indicates the length of Sense Data. + uint16_t len; - /// 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]; + /// 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]; - /// Response Data. - uint8_t res_data[0]; + /// Response Data. + uint8_t res_data[0]; } iscsi_scsi_ds_cmd_data; @@ -1958,20 +1167,20 @@ typedef struct __attribute__((packed)) iscsi_scsi_ds_cmd_data { * cleared. */ typedef struct __attribute__((packed)) iscsi_scsi_basic_inquiry_data_packet { - /// Peripheral device type and qualifier. - uint8_t peripheral_type_id; + /// Peripheral device type and qualifier. + uint8_t peripheral_type_id; - /// Peripheral device type modifier and removable media bit. - int8_t peripheral_type_mod_flags; + /// Peripheral device type modifier and removable media bit. + int8_t peripheral_type_mod_flags; - /// ANSI-Approved, ECMA and ISO version. - uint8_t version; + /// ANSI-Approved, ECMA and ISO version. + uint8_t version; - /// Response data format, HISUP, NORMACA, AENC and TrmIOP flags. - int8_t response_data_fmt_flags; + /// Response data format, HISUP, NORMACA, AENC and TrmIOP flags. + int8_t response_data_fmt_flags; - /// Additional length in bytes. - uint8_t add_len; + /// Additional length in bytes. + uint8_t add_len; } iscsi_scsi_basic_inquiry_data_packet; @@ -2047,26 +1256,26 @@ typedef struct __attribute__((packed)) iscsi_scsi_basic_inquiry_data_packet { * cleared. */ typedef struct __attribute__((packed)) iscsi_scsi_std_inquiry_data_packet { - /// iSCSI SCSI basic inquiry data packet. - iscsi_scsi_basic_inquiry_data_packet basic_inquiry; + /// iSCSI SCSI basic inquiry data packet. + iscsi_scsi_basic_inquiry_data_packet basic_inquiry; - /// PROTECT, 3PC, TPGS, ACC and SCCS. - uint8_t tpgs_flags; + /// PROTECT, 3PC, TPGS, ACC and SCCS. + uint8_t tpgs_flags; - /// MULTIP, VS and ENCSERV. - int8_t services_flags; + /// MULTIP, VS and ENCSERV. + int8_t services_flags; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Vendor identification. - uint8_t vendor_id[8]; + /// Vendor identification. + uint8_t vendor_id[8]; - /// Product identification. - uint8_t product_id[16]; + /// Product identification. + uint8_t product_id[16]; - /// Product revision level. - uint8_t product_rev_level[4]; + /// Product revision level. + uint8_t product_rev_level[4]; } iscsi_scsi_std_inquiry_data_packet; @@ -2095,29 +1304,29 @@ typedef struct __attribute__((packed)) iscsi_scsi_std_inquiry_data_packet { * cleared. */ typedef struct __attribute__((packed)) iscsi_scsi_ext_inquiry_data_packet { - /// iSCSI SCSI standard inquiry data packet. - iscsi_scsi_std_inquiry_data_packet std_inquiry; + /// iSCSI SCSI standard inquiry data packet. + iscsi_scsi_std_inquiry_data_packet std_inquiry; - /// Vendor specific. - uint8_t vendor_spec[20]; + /// Vendor specific. + uint8_t vendor_spec[20]; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Reserved for future usage (always MUST be 0). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0). + uint8_t reserved; - /// Version descriptors. - uint16_t version_desc[8]; + /// Version descriptors. + uint16_t version_desc[8]; - /// Reserved for future usage (always MUST be 0). - uint64_t reserved2[2]; + /// Reserved for future usage (always MUST be 0). + uint64_t reserved2[2]; - /// Reserved for future usage (always MUST be 0). - uint32_t reserved3; + /// Reserved for future usage (always MUST be 0). + uint32_t reserved3; - /// Reserved for future usage (always MUST be 0). - uint16_t reserved4; + /// Reserved for future usage (always MUST be 0). + uint16_t reserved4; } iscsi_scsi_ext_inquiry_data_packet; @@ -2243,17 +1452,17 @@ typedef struct __attribute__((packed)) iscsi_scsi_ext_inquiry_data_packet { * set. */ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_inquiry_data_packet { - /// Peripheral device type and qualifier. - uint8_t peripheral_type_id; + /// Peripheral device type and qualifier. + uint8_t peripheral_type_id; - /// Page code. - uint8_t page_code; + /// Page code. + uint8_t page_code; - /// Allocation length in bytes. - uint16_t alloc_len; + /// Allocation length in bytes. + uint16_t alloc_len; - /// Parameters. - uint8_t params[0]; + /// Parameters. + uint8_t params[0]; } iscsi_scsi_vpd_page_inquiry_data_packet; @@ -2378,20 +1587,20 @@ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_inquiry_data_packet { * set. */ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_inquiry_data_packet { - /// Protocol identifier and code set. - uint8_t protocol_id_code_set; + /// Protocol identifier and code set. + uint8_t protocol_id_code_set; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Reserved for future usage (always MUST be 0). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0). + uint8_t reserved; - /// Length in bytes. - uint8_t len; + /// Length in bytes. + uint8_t len; - /// Designation descriptor. - uint8_t desc[0]; + /// Designation descriptor. + uint8_t desc[0]; } iscsi_scsi_vpd_page_design_desc_inquiry_data_packet; @@ -2403,8 +1612,8 @@ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_inquiry_d * set. */ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_ieee_naa_ext_inquiry_data_packet { - /// IEEE NAA Extended. - uint64_t ieee_naa_ext; + /// IEEE NAA Extended. + uint64_t ieee_naa_ext; } iscsi_scsi_vpd_page_design_desc_ieee_naa_ext_inquiry_data_packet; @@ -2416,14 +1625,14 @@ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_ieee_naa_ * set. */ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_t10_vendor_id_inquiry_data_packet { - /// Vendor identification. - uint8_t vendor_id[8]; + /// Vendor identification. + uint8_t vendor_id[8]; - /// Product identification. - uint8_t product_id[16]; + /// Product identification. + uint8_t product_id[16]; - /// Unit serial number. - uint8_t unit_serial_num[32]; + /// Unit serial number. + uint8_t unit_serial_num[32]; } iscsi_scsi_vpd_page_design_desc_t10_vendor_id_inquiry_data_packet; @@ -2435,11 +1644,11 @@ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_t10_vendo * set. */ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_rel_target_port_inquiry_data_packet { - /// Reserved for future usage (always MUST be 0). - uint16_t reserved; + /// Reserved for future usage (always MUST be 0). + uint16_t reserved; - /// Port index. - uint16_t index; + /// Port index. + uint16_t index; } iscsi_scsi_vpd_page_design_desc_rel_target_port_inquiry_data_packet; @@ -2451,11 +1660,11 @@ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_rel_targe * set. */ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_target_port_group_inquiry_data_packet { - /// Reserved for future usage (always MUST be 0). - uint16_t reserved; + /// Reserved for future usage (always MUST be 0). + uint16_t reserved; - /// Port group index. - uint16_t index; + /// Port group index. + uint16_t index; } iscsi_scsi_vpd_page_design_desc_target_port_group_inquiry_data_packet; @@ -2467,11 +1676,11 @@ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_target_po * set. */ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_logical_unit_group_inquiry_data_packet { - /// Reserved for future usage (always MUST be 0). - uint16_t reserved; + /// Reserved for future usage (always MUST be 0). + uint16_t reserved; - /// Logical unit identifier. - uint16_t id; + /// Logical unit identifier. + uint16_t id; } iscsi_scsi_vpd_page_design_desc_logical_unit_group_inquiry_data_packet; @@ -2619,296 +1828,47 @@ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_design_desc_logical_u * set. */ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_ext_inquiry_data_packet { - /// Peripheral device type and qualifier. - uint8_t peripheral_type_id; + /// Peripheral device type and qualifier. + uint8_t peripheral_type_id; - /// Page code. - uint8_t page_code; + /// Page code. + uint8_t page_code; - /// Reserved for future usage (always MUST be 0). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0). + uint8_t reserved; - /// Page length in bytes. - uint8_t page_len; + /// Page length in bytes. + uint8_t page_len; - /// Check flags. - int8_t check_flags; + /// Check flags. + int8_t check_flags; - /// Support flags. - int8_t support_flags; + /// Support flags. + int8_t support_flags; - /// More support flags. - int8_t support_flags_2; + /// More support flags. + int8_t support_flags_2; - /// LUICLR. - uint8_t luiclr; + /// LUICLR. + uint8_t luiclr; - /// CBCS. - uint8_t cbcs; + /// CBCS. + uint8_t cbcs; - /// Micro DL. - uint8_t micro_dl; + /// Micro DL. + uint8_t micro_dl; - /// Reserved for future usage (always MUST be 0). - uint64_t reserved2[6]; + /// Reserved for future usage (always MUST be 0). + uint64_t reserved2[6]; - /// Reserved for future usage (always MUST be 0). - uint32_t reserved3; + /// Reserved for future usage (always MUST be 0). + uint32_t reserved3; - /// Reserved for future usage (always MUST be 0). - uint16_t reserved4; + /// Reserved for future usage (always MUST be 0). + uint16_t reserved4; } iscsi_scsi_vpd_page_ext_inquiry_data_packet; -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data policy page code: First bit of the six bits. -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_POLICY_PAGE_CODE_FIRST_BIT 0 - -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data policy page code: Last bit of the six bits. -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_POLICY_PAGE_CODE_LAST_BIT ((ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_POLICY_PAGE_CODE_FIRST_BIT) + 6 - 1) - -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data policy page code: Bit mask. -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_POLICY_PAGE_CODE_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_POLICY_PAGE_CODE_FIRST_BIT, ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_POLICY_PAGE_CODE_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data policy page code: Extracts the policy page code bits. -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_GET_POLICY_PAGE_CODE(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_POLICY_PAGE_CODE_FIRST_BIT, ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_POLICY_PAGE_CODE_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data policy page code: Stores into the policy page code bits. -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_PUT_POLICY_PAGE_CODE(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_POLICY_PAGE_CODE_FIRST_BIT, ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_POLICY_PAGE_CODE_LAST_BIT)) - - -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data flags mode page policy: First bit of the two bits. -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MODE_PAGE_POLICY_FIRST_BIT 0 - -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data flags mode page policy: Last bit of the two bits. -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MODE_PAGE_POLICY_LAST_BIT ((ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MODE_PAGE_POLICY_FIRST_BIT) + 2 - 1) - -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data flags mode page policy: Bit mask. -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MODE_PAGE_POLICY_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MODE_PAGE_POLICY_FIRST_BIT, ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MODE_PAGE_POLICY_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data flags mode page policy: Extracts the mode page policy bits. -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_GET_MODE_PAGE_POLICY(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MODE_PAGE_POLICY_FIRST_BIT, ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MODE_PAGE_POLICY_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data flags mode page policy: Stores into the mode page policy bits. -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_PUT_MODE_PAGE_POLICY(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MODE_PAGE_POLICY_FIRST_BIT, ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MODE_PAGE_POLICY_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry Data flag: Multiple Logical Units Share (MLUS). -#define ISCSI_SCSI_VPD_MODE_PAGE_POLICY_DESC_INQUIRY_DATA_FLAGS_MLUS (1 << 7) - - -/** - * @brief iSCSI SCSI Vital Product Data (VPD) Mode Page Policy Descriptor Inquiry data packet. - * - * This structure is used by the SCSI INQUIRY command - * in order to fill in the result if the EVPD bit is - * set. - */ -typedef struct __attribute__((packed)) iscsi_scsi_vpd_mode_page_policy_desc_inquiry_data_packet { - /// Policy page code. - uint8_t page_code; - - /// Policy sub page code. - uint8_t sub_page_code; - - /// Policy flags. - int8_t flags; - - /// Reserved for future usage (always MUST be 0). - uint8_t reserved; -} iscsi_scsi_vpd_mode_page_policy_desc_inquiry_data_packet; - - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data protocol identifier: iSCSI. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_ISCSI 0x05 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data protocol identifier: First bit of the four bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_FIRST_BIT 0 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data protocol identifier: Last bit of the four bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_LAST_BIT ((ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_FIRST_BIT) + 4 - 1) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data protocol identifier: Bit mask. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data protocol identifier: Extracts the protocol identifier bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_GET_PROTOCOL_ID(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data protocol identifier: Stores into the protocol identifier bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PUT_PROTOCOL_ID(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PROTOCOL_ID_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data code set: Binary encoding. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_BINARY 0x01 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data code set: ASCII encoding. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_ASCII 0x02 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data code set: UTF-8 encoding. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_UTF8 0x03 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data code set: First bit of the four bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_FIRST_BIT 4 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data code set: Last bit of the four bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_LAST_BIT ((ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_FIRST_BIT) + 8 - 1) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data code set: Bit mask. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data code set: Extracts the protocol identifier bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_GET_CODE_SET(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data code set: Stores into the protocol identifier bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_PUT_CODE_SET(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_CODE_SET_LAST_BIT)) - - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: Vendor specific. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_VENDOR_SPEC 0x00 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: T10 vendor identifier. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_T10_VENDOR_ID 0x01 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: EUI64. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_EUI64 0x02 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: NAA. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_NAA 0x03 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: Relative target port. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_REL_TARGET_PORT 0x04 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: Target port group. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_TARGET_PORT_GROUP 0x05 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: Logical unit group. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_LOGICAL_UNIT_GROUP 0x06 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: MD5 logical unit. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_MD5_LOGICAL_UNIT 0x07 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: SCSI name. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_SCSI_NAME 0x08 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: First bit of the four bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_FIRST_BIT 0 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: Last bit of the four bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_LAST_BIT ((ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_FIRST_BIT) + 4 - 1) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: Bit mask. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: Extracts the type bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_GET_TYPE(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags type: Stores into the type bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_PUT_TYPE(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_TYPE_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags association: Logical unit. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_LOGICAL_UNIT 0x0 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags association: Target port. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_TARGET_PORT 0x1 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags association: Target device. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_TARGET_DEVICE 0x2 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags association: First bit of the two bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_FIRST_BIT 4 - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags association: Last bit of the two bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_LAST_BIT ((ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_FIRST_BIT) + 6 - 1) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags association: Bit mask. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags association: Extracts the association bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_GET_ASSOC(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags association: Stores into the association bits. -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_PUT_ASSOC(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_FIRST_BIT, ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_ASSOC_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data flags: Protocol Identifier Valid (PIV). -#define ISCSI_SCSI_VPD_SCSI_TARGET_PORT_DESIGN_DESC_INQUIRY_DATA_FLAGS_PIV (1 << 7) - - -/** - * @brief iSCSI SCSI Vital Product Data (VPD) SCSI Target Port Designation Descriptor Inquiry data packet. - * - * This structure is used by the SCSI INQUIRY command - * in order to fill in the result if the EVPD bit is - * set. - */ -typedef struct __attribute__((packed)) iscsi_scsi_vpd_scsi_target_port_design_dec_inquiry_data_packet { - /// Protocol identifier and code set. - uint8_t protocol_id_code_set; - - /// Flags. - int8_t flags; - - /// Reserved for future usage (always MUST be 0). - uint8_t reserved; - - /// Length in bytes. - uint8_t len; - - /// Designator. - uint8_t design[0]; -} iscsi_scsi_vpd_scsi_target_port_design_dec_inquiry_data_packet; - - -/** - * @brief iSCSI SCSI Vital Product Data (VPD) SCSI Port Designation Descriptor Inquiry data packet. - * - * This structure is used by the SCSI INQUIRY command - * in order to fill in the result if the EVPD bit is - * set. - */ -typedef struct __attribute__((packed)) iscsi_scsi_vpd_scsi_port_design_dec_inquiry_data_packet { - /// Reserved for future usage (always MUST be 0). - uint16_t reserved; - - /// Relative port identifier. - uint16_t rel_port_id; - - /// Reserved for future usage (always MUST be 0). - uint16_t reserved2; - - /// Initiator port length in bytes. - uint16_t init_port_len; - - /// Initiator port identifier. - uint16_t init_port_id[0]; - - /// Reserved for future usage (always MUST be 0). - uint16_t reserved3; - - /// SCSI Target Port Designation Descriptor length in bytes. - uint16_t target_desc_len; - - /// SCSI Target Port Designation Descriptor. - iscsi_scsi_vpd_scsi_target_port_design_dec_inquiry_data_packet target_desc[0]; -} iscsi_scsi_vpd_scsi_port_design_dec_inquiry_data_packet; - - -/** - * @brief iSCSI SCSI command INQUIRY Vital Product Data (VPD) SCSI Port Designation Descriptor entry fill. - * - * This structure is used by iterating through - * all iSCSI device ports in order to fill in - * the INQUIRY Vital Product Data (VPD) SCSI - * Port Designation Descriptor structure. - */ -typedef struct iscsi_scsi_emu_primary_inquiry_ports_fill { - /// Pointer to current Vital Product Data (VPD) SCSI Port Designation Descriptor entry packet data. - iscsi_scsi_vpd_scsi_port_design_dec_inquiry_data_packet *port_entry; - - /// Total length of Vital Product Data (VPD) SCSI Port Designation Descriptor entry packet data in bytes. - uint alloc_len; - - /// Total remaining allocation length for packet data in bytes. - uint len; -} iscsi_scsi_emu_primary_inquiry_ports_fill; - - /// iSCSI SCSI Vital Product Data (VPD) Page Block Limits Inquiry data UNMAP Granularity Alignment: First bit of the thirty one bits. #define ISCSI_SCSI_VPD_PAGE_BLOCK_LIMITS_INQUIRY_DATA_UNMAP_GRANULARITY_ALIGN_FIRST_BIT 0L @@ -2936,44 +1896,44 @@ typedef struct iscsi_scsi_emu_primary_inquiry_ports_fill { * set. */ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_block_limits_inquiry_data_packet { - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Maximum COMPARE AND WRITE length in logical blocks. - uint8_t max_cmp_write_len; + /// Maximum COMPARE AND WRITE length in logical blocks. + uint8_t max_cmp_write_len; - /// Optimal transfer length granularity in logical blocks. - uint16_t optimal_granularity_xfer_len; + /// Optimal transfer length granularity in logical blocks. + uint16_t optimal_granularity_xfer_len; - /// Maximum transfer length in logical blocks. - uint32_t max_xfer_len; + /// Maximum transfer length in logical blocks. + uint32_t max_xfer_len; - /// Optimal transfer length in logical blocks. - uint32_t optimal_xfer_len; + /// Optimal transfer length in logical blocks. + uint32_t optimal_xfer_len; - /// Maximum prefetch length in logical blocks. - uint32_t max_prefetch_len; + /// Maximum prefetch length in logical blocks. + uint32_t max_prefetch_len; - /// Maximum UNMAP LBA count in LBAs. - uint32_t max_unmap_lba_cnt; + /// Maximum UNMAP LBA count in LBAs. + uint32_t max_unmap_lba_cnt; - /// Maximum UNMAP block descriptor count in block descriptors. - uint32_t max_unmap_block_desc_cnt; + /// Maximum UNMAP block descriptor count in block descriptors. + uint32_t max_unmap_block_desc_cnt; - /// Optimal UNMAP granularity in logical blocks. - uint32_t optimal_unmap_granularity; + /// Optimal UNMAP granularity in logical blocks. + uint32_t optimal_unmap_granularity; - /// UNMAP granularity alignment (first LBA) and UGAVALID bit. - uint32_t unmap_granularity_align_ugavalid; + /// UNMAP granularity alignment (first LBA) and UGAVALID bit. + uint32_t unmap_granularity_align_ugavalid; - /// Maximum WRITE SAME length in logical blocks. - uint64_t max_write_same_len; + /// Maximum WRITE SAME length in logical blocks. + uint64_t max_write_same_len; - /// Reserved for future usage (always MUST be 0). - uint64_t reserved[2]; + /// Reserved for future usage (always MUST be 0). + uint64_t reserved[2]; - /// Reserved for future usage (always MUST be 0). - uint32_t reserved2; + /// Reserved for future usage (always MUST be 0). + uint32_t reserved2; } iscsi_scsi_vpd_page_block_limits_inquiry_data_packet; /// iSCSI SCSI Vital Product Data (VPD) Page Block Device Characteristics Inquiry data medium rotation rate: Medium rotation rate is not reported. @@ -3069,131 +2029,32 @@ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_block_limits_inquiry_ * set. */ typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_block_dev_chars_inquiry_data_packet { - /// Medium rotation rate. - uint16_t medium_rotation_rate; + /// Medium rotation rate. + uint16_t medium_rotation_rate; - /// Product type. - uint8_t product_type; + /// Product type. + uint8_t product_type; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Support flags. - uint8_t support_flags; + /// Support flags. + uint8_t support_flags; - /// Reserved for future usage (always MUST be 0). - uint64_t reserved[6]; + /// Reserved for future usage (always MUST be 0). + uint64_t reserved[6]; - /// Reserved for future usage (always MUST be 0). - uint32_t reserved2; + /// Reserved for future usage (always MUST be 0). + uint32_t reserved2; - /// Reserved for future usage (always MUST be 0). - uint16_t reserved3; + /// Reserved for future usage (always MUST be 0). + uint16_t reserved3; - /// Reserved for future usage (always MUST be 0). - uint8_t reserved4; + /// Reserved for future usage (always MUST be 0). + uint8_t reserved4; } iscsi_scsi_vpd_page_block_dev_chars_inquiry_data_packet; -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data flags: Descriptor Present (DP). -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_FLAGS_DP (1 << 0) - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data flags: Anchor Supported (ANC_SUP). -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_FLAGS_ANC_SUP (1 << 1) - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data flags: Logical Block Provisioning Read Zeros (LBPRZ). -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_FLAGS_LBPRZ (1 << 2) - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data flags: Logical Block Provisioning WRITE SAME(10) (LBPWS10). -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_FLAGS_LBPWS10 (1 << 5) - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data flags: Logical Block Provisioning WRITE SAME (LBPWS). -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_FLAGS_LBPWS (1 << 6) - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data flags: Logical Block Provisioning UNMAP (LBPU). -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_FLAGS_LBPU (1 << 7) - - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data provision type: The device server does NOT report a provisioning type. -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_PROVISIONING_NOT_REPORTED 0x0 - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data provision type: The logical unit is resource provisioned (see SBC3). -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_RESOURCE_PROVISIONING 0x1 - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data provision type: The logical unit is thin provisioned (see SBC3). -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_THIN_PROVISIONING 0x2 - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data provision type: First bit of the three bits. -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_FIRST_BIT 0 - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data provision type: Last bit of the three bits. -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_LAST_BIT ((ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_FIRST_BIT) + 3 - 1) - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data provision type: Bit mask. -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_FIRST_BIT, ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data provision type: Extracts the provision type bits. -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_GET_PROVISION_TYPE(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_FIRST_BIT, ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_LAST_BIT)) - -/// iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data provision type: Stores into the provision type bits. -#define ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PUT_PROVISION_TYPE(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_FIRST_BIT, ISCSI_SCSI_VPD_PAGE_THIN_PROVISION_INQUIRY_DATA_PROVISION_TYPE_LAST_BIT)) - - -/** - * @brief iSCSI SCSI Vital Product Data (VPD) Page Thin Provision Inquiry data packet. - * - * This structure is used by the SCSI INQUIRY command - * in order to fill in the result if the EVPD bit is - * set. - */ -typedef struct __attribute__((packed)) iscsi_scsi_vpd_page_thin_provision_inquiry_data_packet { - /// Threshold exponent. - uint8_t threshold_exponent; - - /// Flags. - int8_t flags; - - /// Provision type. - uint8_t provision_type; - - /// Reserved for future usage (always MUST be 0). - uint8_t reserved; - - /// Provision group descriptors. - uint8_t provision_group_desc[0]; -} iscsi_scsi_vpd_page_thin_provision_inquiry_data_packet; - - -/** - * @brief iSCSI SCSI 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_scsi_sense_event_data_packet { - /** - * @brief SenseLength. - * - * This is the length of Sense Data. When the Sense Data field is empty - * (e.g., the event is not a SCSI event), SenseLength is 0. - */ - uint16_t sense_len; - - /// Sense Data. - uint16_t sense_data[0]; - - /// iSCSI Event Data. - uint16_t event_data[0]; -} iscsi_scsi_sense_event_data_packet; - - /// iSCSI SCSI sense data response code: Current format. #define ISCSI_SCSI_SENSE_DATA_RESPONSE_CODE_CURRENT_FMT 0x70 @@ -3251,20 +2112,20 @@ typedef struct __attribute__((packed)) iscsi_scsi_sense_event_data_packet { * all SCSI sense data. */ typedef struct __attribute__((packed)) iscsi_scsi_sense_data_packet { - /// Response code. - int8_t response_code; + /// Response code. + int8_t response_code; - /// Reserved for future usage (always MUST be 0). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0). + uint8_t reserved; - /// Sense key and flags. - int8_t sense_key_flags; + /// Sense key and flags. + int8_t sense_key_flags; - /// Information. - uint32_t info; + /// Information. + uint32_t info; - /// Additional sense length in bytes. - uint8_t add_len; + /// Additional sense length in bytes. + uint8_t add_len; } iscsi_scsi_sense_data_packet; /// iSCSI SCSI maximum sense data length. @@ -3297,26 +2158,26 @@ typedef struct __attribute__((packed)) iscsi_scsi_sense_data_packet { * the check condition status code. */ typedef struct __attribute__((packed)) iscsi_scsi_sense_data_check_cond_packet { - /// Basic SCSI sense data packet. - iscsi_scsi_sense_data_packet sense_data; + /// Basic SCSI sense data packet. + iscsi_scsi_sense_data_packet sense_data; - /// Information. - uint32_t cmd_spec_info; + /// Information. + uint32_t cmd_spec_info; - /// Additional Sense Code (ASC). - uint8_t asc; + /// Additional Sense Code (ASC). + uint8_t asc; - /// Additional Sense Code Qualifier (ASCQ). - uint8_t ascq; + /// Additional Sense Code Qualifier (ASCQ). + uint8_t ascq; - /// Field replaceable unit code. - uint32_t field_rep_unit_code; + /// Field replaceable unit code. + uint32_t field_rep_unit_code; - /// Sense key specific. - uint8_t sense_key_spec_flags; + /// Sense key specific. + uint8_t sense_key_spec_flags; - /// Sense key specific. - uint16_t sense_key_spec; + /// Sense key specific. + uint16_t sense_key_spec; } iscsi_scsi_sense_data_check_cond_packet; @@ -3327,11 +2188,11 @@ typedef struct __attribute__((packed)) iscsi_scsi_sense_data_check_cond_packet { * and block length in bytes. */ typedef struct __attribute__((packed)) iscsi_scsi_read_capacity_10_parameter_data_packet { - /// Last valid Logical Block Address (LBA). - uint32_t lba; + /// Last valid Logical Block Address (LBA). + uint32_t lba; - /// Block length in bytes. - uint32_t block_len; + /// Block length in bytes. + uint32_t block_len; } iscsi_scsi_read_capacity_10_parameter_data_packet; @@ -3429,23 +2290,23 @@ typedef struct __attribute__((packed)) iscsi_scsi_read_capacity_10_parameter_dat * block length in bytes and LBP information. */ typedef struct __attribute__((packed)) iscsi_scsi_service_action_in_16_parameter_data_packet { - /// Last valid Logical Block Address (LBA). - uint64_t lba; + /// Last valid Logical Block Address (LBA). + uint64_t lba; - /// Block length in bytes. - uint32_t block_len; + /// Block length in bytes. + uint32_t block_len; - /// Flags: RC_BASIS, P_TYPE and PROT_EN. - int8_t flags; + /// Flags: RC_BASIS, P_TYPE and PROT_EN. + int8_t flags; - /// P_I_EXPONENT and logical blocks per physical block exponent. - uint8_t exponents; + /// P_I_EXPONENT and logical blocks per physical block exponent. + uint8_t exponents; - /// Logical Block Provisioning Management Enabled (LBPME), Logical Block Provisioning Read Zeros (LBPRZ) and Lowest Aligned Logical Block Address (LALBA). - uint16_t lbp_lalba; + /// Logical Block Provisioning Management Enabled (LBPME), Logical Block Provisioning Read Zeros (LBPRZ) and Lowest Aligned Logical Block Address (LALBA). + uint16_t lbp_lalba; - /// Reserved for future usage (always MUST be 0 for now). - uint64_t reserved[2]; + /// Reserved for future usage (always MUST be 0 for now). + uint64_t reserved[2]; } iscsi_scsi_service_action_in_16_parameter_data_packet; @@ -3456,11 +2317,11 @@ typedef struct __attribute__((packed)) iscsi_scsi_service_action_in_16_parameter * LUN list in bytes. */ typedef struct __attribute__((packed)) iscsi_scsi_report_luns_parameter_data_lun_list_packet { - /// Number of LUN's following this packet in bytes. - uint32_t lun_list_len; + /// Number of LUN's following this packet in bytes. + uint32_t lun_list_len; - /// Reserved for future usage (always MUST be 0 for now). - uint32_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint32_t reserved; } iscsi_scsi_report_luns_parameter_data_lun_list_packet; @@ -3471,44 +2332,19 @@ typedef struct __attribute__((packed)) iscsi_scsi_report_luns_parameter_data_lun * LUN list. */ typedef struct __attribute__((packed)) iscsi_scsi_report_luns_parameter_data_lun_entry_packet { - /// Logical Unit Number (LUN). - uint64_t lun; + /// Logical Unit Number (LUN). + uint64_t lun; } iscsi_scsi_report_luns_parameter_data_lun_entry_packet; /** - * @brief iSCSI SCSI command REPORT LUNS parameter data LUN entry fill. - * - * This structure is used by iterating through - * all iSCSI LUNs in order to fill in the - * REPORT LUNS parameter data structure. - */ -typedef struct iscsi_scsi_emu_primary_report_luns_fill { - /// Pointer to LUN list packet data. - iscsi_scsi_report_luns_parameter_data_lun_list_packet *lun_list; - - /// Pointer to current LUN entry packet data. - iscsi_scsi_report_luns_parameter_data_lun_entry_packet *lun_entry; - - /// Total length of LUN entry packet data in bytes. - uint32_t len; - - /// Total remaining allocation length for packet data in bytes. - uint alloc_len; - - /// Select report. - uint select_report; -} iscsi_scsi_emu_primary_report_luns_fill; - - -/** * @brief iSCSI SCSI command MODE SELECT(6) parameter list packet data. * * This returns 32-bit vendor specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_select_6_parameter_list_packet { - /// Vendor specific data. - uint32_t vendor_data; + /// Vendor specific data. + uint32_t vendor_data; } iscsi_scsi_mode_select_6_parameter_list_packet; @@ -3518,8 +2354,8 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_select_6_parameter_list_p * This returns 64-bit vendor specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_select_10_parameter_list_packet { - /// Vendor specific data. - uint64_t vendor_data; + /// Vendor specific data. + uint64_t vendor_data; } iscsi_scsi_mode_select_10_parameter_list_packet; @@ -3537,17 +2373,17 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_select_10_parameter_list_ * data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_6_parameter_header_data_packet { - /// Mode data length in bytes. - uint8_t mode_data_len; + /// Mode data length in bytes. + uint8_t mode_data_len; - /// Medium type. - uint8_t medium_type; + /// Medium type. + uint8_t medium_type; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Block descriptor length in bytes. - uint8_t block_desc_len; + /// Block descriptor length in bytes. + uint8_t block_desc_len; } iscsi_scsi_mode_sense_6_parameter_header_data_packet; @@ -3569,23 +2405,23 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_6_parameter_header_ * data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_10_parameter_header_data_packet { - /// Mode data length in bytes. - uint16_t mode_data_len; + /// Mode data length in bytes. + uint16_t mode_data_len; - /// Medium type. - uint8_t medium_type; + /// Medium type. + uint8_t medium_type; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Long Logical Block Address (LONGLBA). - uint8_t long_lba; + /// Long Logical Block Address (LONGLBA). + uint8_t long_lba; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved; - /// Block descriptor length in bytes. - uint16_t block_desc_len; + /// Block descriptor length in bytes. + uint16_t block_desc_len; } iscsi_scsi_mode_sense_10_parameter_header_data_packet; @@ -3597,14 +2433,14 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_10_parameter_header * descriptor data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_lba_parameter_block_desc_data_packet { - /// Number of blocks in logical blocks. - uint32_t num_blocks; + /// Number of blocks in logical blocks. + uint32_t num_blocks; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved; - /// Logical blcok length in bytes. - uint8_t block_len[3]; + /// Logical blcok length in bytes. + uint8_t block_len[3]; } iscsi_scsi_mode_sense_lba_parameter_block_desc_data_packet; @@ -3616,14 +2452,14 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_lba_parameter_block * descriptor data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_long_lba_parameter_block_desc_data_packet { - /// Number of blocks in logical blocks. - uint64_t num_blocks; + /// Number of blocks in logical blocks. + uint64_t num_blocks; - /// Reserved for future usage (always MUST be 0 for now). - uint32_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint32_t reserved; - /// Logical blcok length in bytes. - uint32_t block_len; + /// Logical blcok length in bytes. + uint32_t block_len; } iscsi_scsi_mode_sense_long_lba_parameter_block_desc_data_packet; @@ -3862,14 +2698,14 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_long_lba_parameter_ * This returns mode page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_mode_page_data_packet { - /// Page code and flags. - int8_t page_code_flags; + /// Page code and flags. + int8_t page_code_flags; - /// Page length in bytes. - uint8_t page_len; + /// Page length in bytes. + uint8_t page_len; - /// Mode parameters. - uint8_t params[0]; + /// Mode parameters. + uint8_t params[0]; } iscsi_scsi_mode_sense_mode_page_data_packet; @@ -3879,17 +2715,17 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_mode_page_data_pack * This returns mode sub page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_mode_sub_page_data_packet { - /// Page code and flags. - int8_t page_code_flags; + /// Page code and flags. + int8_t page_code_flags; - /// Sub page code. - uint8_t sub_page_code; + /// Sub page code. + uint8_t sub_page_code; - /// Page length in bytes. - uint16_t page_len; + /// Page length in bytes. + uint16_t page_len; - /// Mode parameters. - uint8_t params[0]; + /// Mode parameters. + uint8_t params[0]; } iscsi_scsi_mode_sense_mode_sub_page_data_packet; @@ -3899,29 +2735,29 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_mode_sub_page_data_ * This returns mode page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_read_write_err_recovery_mode_page_data_packet { - /// Mode page. - iscsi_scsi_mode_sense_mode_page_data_packet mode_page; + /// Mode page. + iscsi_scsi_mode_sense_mode_page_data_packet mode_page; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Read retry count. - uint8_t read_retry_cnt; + /// Read retry count. + uint8_t read_retry_cnt; - /// Obselete. - uint8_t obselete[3]; + /// Obselete. + uint8_t obselete[3]; - /// Restricted for MMC-6. - uint8_t restrict_mmc_6; + /// Restricted for MMC-6. + uint8_t restrict_mmc_6; - /// Write_retry count. - uint8_t write_retry_cnt; + /// Write_retry count. + uint8_t write_retry_cnt; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved; - /// Recovery time limit. - uint16_t recovery_time_limit; + /// Recovery time limit. + uint16_t recovery_time_limit; } iscsi_scsi_mode_sense_read_write_err_recovery_mode_page_data_packet; @@ -3931,32 +2767,32 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_read_write_err_reco * This returns mode page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_disconnect_reconnect_mode_page_data_packet { - /// Mode page. - iscsi_scsi_mode_sense_mode_page_data_packet mode_page; + /// Mode page. + iscsi_scsi_mode_sense_mode_page_data_packet mode_page; - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint16_t reserved; - /// Bus inactivity time limit. - uint16_t bus_inactivity_time_limit; + /// Bus inactivity time limit. + uint16_t bus_inactivity_time_limit; - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved2; + /// Reserved for future usage (always MUST be 0 for now). + uint16_t reserved2; - /// Maximum connect time limit. - uint16_t max_connect_time_limit; + /// Maximum connect time limit. + uint16_t max_connect_time_limit; - /// Maximum burst size. - uint16_t max_burst_size; + /// Maximum burst size. + uint16_t max_burst_size; - /// Restricted. - uint8_t restricted; + /// Restricted. + uint8_t restricted; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved3; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved3; - /// First burst size. - uint16_t first_burst_size; + /// First burst size. + uint16_t first_burst_size; } iscsi_scsi_mode_sense_disconnect_reconnect_mode_page_data_packet; @@ -3966,35 +2802,35 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_disconnect_reconnec * This returns mode page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_verify_err_recovery_mode_page_data_packet { - /// Mode page. - iscsi_scsi_mode_sense_mode_page_data_packet mode_page; + /// Mode page. + iscsi_scsi_mode_sense_mode_page_data_packet mode_page; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Verify retry count. - uint8_t verify_retry_cnt; + /// Verify retry count. + uint8_t verify_retry_cnt; - /// Obselete. - uint8_t obselete; + /// Obselete. + uint8_t obselete; - /// Head offset count. - uint8_t head_offset_cnt; + /// Head offset count. + uint8_t head_offset_cnt; - /// Data strobe offset count. - uint8_t data_strobe_offset_cnt; + /// Data strobe offset count. + uint8_t data_strobe_offset_cnt; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved; - /// Write retry count. - uint8_t write_retry_cnt; + /// Write retry count. + uint8_t write_retry_cnt; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved2; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved2; - /// Verify_recovery time limit. - uint16_t verify_recovery_time_limit; + /// Verify_recovery time limit. + uint16_t verify_recovery_time_limit; } iscsi_scsi_mode_sense_verify_err_recovery_mode_page_data_packet; @@ -4029,41 +2865,41 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_verify_err_recovery * This returns mode page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_caching_mode_page_data_packet { - /// Mode page. - iscsi_scsi_mode_sense_mode_page_data_packet mode_page; + /// Mode page. + iscsi_scsi_mode_sense_mode_page_data_packet mode_page; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Retention priority. - uint8_t retention_pri; + /// Retention priority. + uint8_t retention_pri; - /// Disable prefetch transfer length. - uint16_t disable_prefetch_xfer_len; + /// Disable prefetch transfer length. + uint16_t disable_prefetch_xfer_len; - /// Minimum prefetch. - uint16_t min_prefetch; + /// Minimum prefetch. + uint16_t min_prefetch; - /// Maximum prefetch. - uint16_t max_prefetch; + /// Maximum prefetch. + uint16_t max_prefetch; - /// Maximum prefetch ceiling. - uint16_t max_prefetch_ceil; + /// Maximum prefetch ceiling. + uint16_t max_prefetch_ceil; - /// Cache flags. - int8_t cache_flags; + /// Cache flags. + int8_t cache_flags; - /// Number of cache segments. - uint8_t num_cache_segs; + /// Number of cache segments. + uint8_t num_cache_segs; - /// Cache segment size. - uint16_t cache_seg_size; + /// Cache segment size. + uint16_t cache_seg_size; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved; - /// Obselete. - uint8_t obselete[3]; + /// Obselete. + uint8_t obselete[3]; } iscsi_scsi_mode_sense_caching_mode_page_data_packet; @@ -4073,29 +2909,29 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_caching_mode_page_d * This returns mode page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_control_mode_page_data_packet { - /// Mode page. - iscsi_scsi_mode_sense_mode_page_data_packet mode_page; + /// Mode page. + iscsi_scsi_mode_sense_mode_page_data_packet mode_page; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Queue flags. - int8_t queue_flags; + /// Queue flags. + int8_t queue_flags; - /// Control flags. - int8_t control_flags; + /// Control flags. + int8_t control_flags; - /// Application task flags. - int8_t app_task_flags; + /// Application task flags. + int8_t app_task_flags; - /// Ready AER holdoff period. - uint16_t ready_aer_holdoff_period; + /// Ready AER holdoff period. + uint16_t ready_aer_holdoff_period; - /// Busy timeout period. - uint16_t busy_timeout_period; + /// Busy timeout period. + uint16_t busy_timeout_period; - /// Extended self-test completition time. - uint16_t ext_self_test_complete_time; + /// Extended self-test completition time. + uint16_t ext_self_test_complete_time; } iscsi_scsi_mode_sense_control_mode_page_data_packet; @@ -4105,23 +2941,23 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_control_mode_page_d * This returns mode sub page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_control_ext_mode_page_data_packet { - /// Mode page. - iscsi_scsi_mode_sense_mode_sub_page_data_packet mode_sub_page; + /// Mode page. + iscsi_scsi_mode_sense_mode_sub_page_data_packet mode_sub_page; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Initial command priority. - uint8_t init_cmd_pri; + /// Initial command priority. + uint8_t init_cmd_pri; - /// Maximum sense data length in bytes. - uint8_t max_sense_data_len; + /// Maximum sense data length in bytes. + uint8_t max_sense_data_len; - /// Reserved for future usage (always MUST be 0 for now). - uint64_t reserved[3]; + /// Reserved for future usage (always MUST be 0 for now). + uint64_t reserved[3]; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved2; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved2; } iscsi_scsi_mode_sense_control_ext_mode_page_data_packet; @@ -4131,32 +2967,32 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_control_ext_mode_pa * This returns mode page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_xor_ext_mode_page_data_packet { - /// Mode page. - iscsi_scsi_mode_sense_mode_page_data_packet mode_page; + /// Mode page. + iscsi_scsi_mode_sense_mode_page_data_packet mode_page; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved; - /// Maximum XOR write size in logical blocks. - uint32_t max_xor_write_size; + /// Maximum XOR write size in logical blocks. + uint32_t max_xor_write_size; - /// Reserved for future usage (always MUST be 0 for now). - uint32_t reserved2; + /// Reserved for future usage (always MUST be 0 for now). + uint32_t reserved2; - /// Maximum regenerate size in logical blocks. - uint32_t max_regenerate_size; + /// Maximum regenerate size in logical blocks. + uint32_t max_regenerate_size; - /// Reserved for future usage (always MUST be 0 for now). - uint32_t reserved3; + /// Reserved for future usage (always MUST be 0 for now). + uint32_t reserved3; - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved4; + /// Reserved for future usage (always MUST be 0 for now). + uint16_t reserved4; - /// Rebuild delay. - uint16_t rebuild_delay; + /// Rebuild delay. + uint16_t rebuild_delay; } iscsi_scsi_mode_sense_xor_ext_mode_page_data_packet; @@ -4166,44 +3002,44 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_xor_ext_mode_page_d * This returns mode page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_power_cond_mode_page_data_packet { - /// Mode page. - iscsi_scsi_mode_sense_mode_page_data_packet mode_page; + /// Mode page. + iscsi_scsi_mode_sense_mode_page_data_packet mode_page; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Idle and standby flags. - int8_t idle_standby_flags; + /// Idle and standby flags. + int8_t idle_standby_flags; - /// idle_a condition timer. - uint32_t idle_a_cond_timer; + /// idle_a condition timer. + uint32_t idle_a_cond_timer; - /// standby_z condition timer. - uint32_t standby_z_cond_timer; + /// standby_z condition timer. + uint32_t standby_z_cond_timer; - /// idle_b condition timer. - uint32_t idle_b_cond_timer; + /// idle_b condition timer. + uint32_t idle_b_cond_timer; - /// idle_c condition timer. - uint32_t idle_c_cond_timer; + /// idle_c condition timer. + uint32_t idle_c_cond_timer; - /// standby_y condition timer. - uint32_t standby_y_cond_timer; + /// standby_y condition timer. + uint32_t standby_y_cond_timer; - /// Reserved for future usage (always MUST be 0 for now). - uint64_t reserved; + /// Reserved for future usage (always MUST be 0 for now). + uint64_t reserved; - /// Reserved for future usage (always MUST be 0 for now). - uint32_t reserved2; + /// Reserved for future usage (always MUST be 0 for now). + uint32_t reserved2; - /// Reserved for future usage (always MUST be 0 for now). - uint16_t reserved3; + /// Reserved for future usage (always MUST be 0 for now). + uint16_t reserved3; - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved4; + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved4; - /// Check Condition From (CCF) flags. - int8_t ccf_flags; + /// Check Condition From (CCF) flags. + int8_t ccf_flags; } iscsi_scsi_mode_sense_power_cond_mode_page_data_packet; @@ -4213,65 +3049,23 @@ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_power_cond_mode_pag * This returns mode page specific data. */ typedef struct __attribute__((packed)) iscsi_scsi_mode_sense_info_exceptions_control_mode_page_data_packet { - /// Mode page. - iscsi_scsi_mode_sense_mode_page_data_packet mode_page; + /// Mode page. + iscsi_scsi_mode_sense_mode_page_data_packet mode_page; - /// Flags. - int8_t flags; + /// Flags. + int8_t flags; - /// Method Of Reporting Informational Exceptions (MRIE) flags. - uint8_t mrie; + /// Method Of Reporting Informational Exceptions (MRIE) flags. + uint8_t mrie; - /// Interval timer. - uint32_t interval_timer; + /// Interval timer. + uint32_t interval_timer; - /// Report count. - uint32_t report_cnt; + /// Report count. + uint32_t report_cnt; } iscsi_scsi_mode_sense_info_exceptions_control_mode_page_data_packet; -/** - * @brief iSCSI SCSI command PERSISTENT RESERVE OUT parameter list packet data. - * - * This returns persistent storage specific data - * like the reservation and service action keys. - */ -typedef struct __attribute__((packed)) iscsi_scsi_pr_reserve_out_parameter_list_packet { - /// Reservation key. - uint64_t r_key; - - /// Service action reservation key. - uint64_t sa_key; - - /// Obselete. - uint32_t obselete; - - /// Flags. - int8_t flags; - - /// Reserved for future usage (always MUST be 0 for now). - uint8_t reserved; - - /// Obselete. - uint16_t obselete2; - -} iscsi_scsi_pr_reserve_out_parameter_list_packet; - - -/** - * @brief iSCSI SCSI command PERSISTENT RESERVE IN parameter data packet data. - * - * This returns persistent storage specific data - * like the reservation and service action keys. - */ -typedef struct __attribute__((packed)) iscsi_scsi_pr_reserve_in_parameter_data_packet { - /// Persistent Reservations (PR) Generation. - uint32_t pr_gen; - - /// Additional length in bytes. - uint32_t add_len; -} iscsi_scsi_pr_reserve_in_parameter_data_packet; - /// SCSI command opcode (embedded in iSCSI protocol): TEST UNIT READY. #define ISCSI_SCSI_OPCODE_TESTUNITREADY 0x00 @@ -4498,86 +3292,80 @@ typedef struct __attribute__((packed)) iscsi_scsi_pr_reserve_in_parameter_data_p * direction is indicated by the R and/or W bit). */ typedef struct __attribute__((packed)) iscsi_scsi_cmd_packet { - /// 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.\n - * 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.\n - * 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_scsi_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_scsi_ds_cmd_data ds_cmd_data; - - /// Optional data digest. - iscsi_data_digest 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.\n + * 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.\n + * 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_scsi_cdb scsi_cdb; + + /// Optional AHS packet data. + iscsi_ahs_packet ahs; + + /// Optional data segment, command data. + iscsi_scsi_ds_cmd_data ds_cmd_data; } iscsi_scsi_cmd_packet; @@ -4778,497 +3566,133 @@ typedef struct __attribute__((packed)) iscsi_scsi_cmd_packet { * terms, response value 0x00 maps to the SCSI service response (see */ typedef struct __attribute__((packed)) iscsi_scsi_response_packet { - /// 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 Selective Negative / Sequence Number Acknowledgment (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.\n - * 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.\n - * 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_scsi_ds_cmd_data ds_cmd_data; - - /// Optional data digest. - iscsi_data_digest 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 Selective Negative / Sequence Number Acknowledgment (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.\n + * 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.\n + * 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 data segment, command data. + iscsi_scsi_ds_cmd_data ds_cmd_data; } iscsi_scsi_response_packet; - -/// 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 - - -/** - * @brief iSCSI Task Management Function Request packet data. - * - * This structure is used to explicity control the execution of one - * or more tasks (iSCSI and SCSI). - */ -typedef struct __attribute__((packed)) iscsi_task_mgmt_func_req_packet { - /// 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).\n - * 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; - - -/// Task management function response: Function complete. -#define ISCSI_TASK_MGMT_FUNC_RESPONSE_FUNC_COMPLETE 0x00 - -/// Task management function response: Task does not exist. -#define ISCSI_TASK_MGMT_FUNC_RESPONSE_TASK_NO_EXIST 0x01 - -/// Task management function response: LUN does not exist. -#define ISCSI_TASK_MGMT_FUNC_RESPONSE_LUN_NO_EXIST 0x02 - -/// Task management function response: Task still allegiant. -#define ISCSI_TASK_MGMT_FUNC_RESPONSE_TASK_ALLEGIANT 0x03 - -/// Task management function response: Task allegiance reassignment not supported. -#define ISCSI_TASK_MGMT_FUNC_RESPONSE_TASK_UNSUPPORTED_ALLEGIANCE 0x04 - -/// Task management function response: Task management function not supported. -#define ISCSI_TASK_MGMT_FUNC_RESPONSE_TASK_UNSUPPORTED_MGMT 0x05 - -/// Task management function response: Function authorization failed. -#define ISCSI_TASK_MGMT_FUNC_RESPONSE_FUNC_AUTH_FAILED 0x06 - -/// Task management function response: Function rejected. -#define ISCSI_TASK_MGMT_FUNC_RESPONSE_FUNC_REJECTED 0xFF - - -/** - * @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 { - /// Always 0x22 according to specification. - uint8_t opcode; - - /// Reserved for future usage (must be always 0x80 for now). - int8_t flags; - - /** - * @brief Function response. - * - * For the TARGET COLD RESET and TARGET WARM RESET functions, the target - * cancels all pending operations across all LUs known to the issuing - * initiator. For the TARGET COLD RESET function, the target MUST then - * close all of its TCP connections to all initiators (terminates all - * sessions).\n - * The mapping of the response code into a SCSI service response code - * value, if needed, is outside the scope of this document. However, in - * symbolic terms, Response values 0 and 1 map to the SCSI service - * response of FUNCTION COMPLETE. Response value 2 maps to the SCSI - * service response of INCORRECT LOGICAL UNIT NUMBER. All other - * Response values map to the SCSI service response of FUNCTION - * REJECTED. If a Task Management Function Response PDU does not arrive - * before the session is terminated, the SCSI service response is - * SERVICE DELIVERY OR TARGET FAILURE.\n - * The response to ABORT TASK SET and CLEAR TASK SET MUST only be issued - * by the target after all of the commands affected have been received - * by the target, the corresponding task management functions have been - * executed by the SCSI target, and the delivery of all responses - * delivered until the task management function completion has been - * confirmed (acknowledged through the ExpStatSN) by the initiator on - * all connections of this session.\n - * For the ABORT TASK function,\n - * -# if the Referenced Task Tag identifies a valid task leading to a - * successful termination, then targets must return the "Function - * complete" response. - * -# if the Referenced Task Tag does not identify an existing task - * but the CmdSN indicated by the RefCmdSN field in the Task - * Management Function Request is within the valid CmdSN window - * and less than the CmdSN of the Task Management Function Request - * itself, then targets must consider the CmdSN as received and - * return the "Function complete" response. - * -# if the Referenced Task Tag does not identify an existing task - * and the CmdSN indicated by the RefCmdSN field in the Task - * Management Function Request is outside the valid CmdSN window, - * then targets must return the "Task does not exist" response - */ - uint8_t response; - - /// Reserved for future usage, always MUST be 0. - uint8_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]; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved2; - - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved3; - - /// StatSN. - uint32_t stat_sn; - - /// ExpCmdSN. - uint32_t exp_cmd_sn; - - /// MaxCmdSN. - uint32_t max_cmd_sn; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved4; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved5; - - /// Optional header digest. - iscsi_header_digest hdr_digest; -} iscsi_task_mgmt_func_response_packet; - /// SCSI data out / in flags: Immediately process transfer. #define ISCSI_SCSI_DATA_OUT_DATA_IN_FLAGS_IMMEDIATE (1 << 7) /** - * @brief iSCSI SCSI Data Out request packet data. - * - * THis structure is used by iSCSI for SCSI data output - * requests, i.e. write operations. - */ -typedef struct __attribute__((packed)) iscsi_scsi_data_out_req_packet { - /// Always 2 according to iSCSI specification. - uint8_t opcode; - - /// Flags. - int8_t flags; - - /// Reserved for future usage, always MUST be 0. - uint16_t reserved; - - /// TotalAHSLength. - uint8_t total_ahs_len; - - /** - * @brief DataSegmentLength. - * - * This is the data payload length of a SCSI Data-In or SCSI Data-Out - * PDU. The sending of 0-length data segments should be avoided, but - * initiators and targets MUST be able to properly receive 0-length data - * segments.\n - * The data segments of Data-In and Data-Out PDUs SHOULD be filled to - * the integer number of 4-byte words (real payload), unless the F bit - * is set to 1. - */ - uint8_t ds_len[3]; - - /** - * @brief Logical Unit Number (LUN) or Reserved. - * - * If the Target Transfer Tag is provided, then the LUN field MUST hold a - * valid value and be consistent with whatever was specified with the command; - * otherwise, the LUN field is reserved. - */ - uint64_t lun; - - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; - - /** - * @brief Target Transfer Tag or 0xFFFFFFFF. - * - * On outgoing data, the Target Transfer Tag is provided to the target - * if the transfer is honoring an R2T. In this case, the Target - * Transfer Tag field is a replica of the Target Transfer Tag provided - * with the R2T.\n - * The Target Transfer Tag values are not specified by this protocol, - * except that the value 0xFFFFFFFF is reserved and means that the - * Target Transfer Tag is not supplied. - */ - uint32_t target_xfer_tag; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved2; - - /// ExpStatSN. - uint32_t exp_stat_sn; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved3; - - /** - * @brief DataSN. - * - * For output (write) data PDUs, the DataSN is the Data-Out PDU number - * within the current output sequence. Either the current output - * sequence is identified by the Initiator Task Tag (for unsolicited - * data) or it is a data sequence generated for one R2T (for data - * solicited through R2T). - */ - uint32_t data_sn; - - /** - * @brief Buffer Offset. - * - * The Buffer Offset field contains the offset of this PDU payload data - * within the complete data transfer. The sum of the buffer offset and - * length should not exceed the expected transfer length for the - * command.\n - * The order of data PDUs within a sequence is determined by - * DataPDUInOrder. When set to Yes, it means that PDUs have to be in - * increasing buffer offset order and overlays are forbidden.\n - * The ordering between sequences is determined by DataSequenceInOrder. - * When set to Yes, it means that sequences have to be in increasing - * buffer offset order and overlays are forbidden. - */ - uint32_t buf_offset; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved4; - - /// Optional header digest. - iscsi_header_digest hdr_digest; - - /// Data segment. - iscsi_scsi_ds_cmd_data ds_cmd_data; - - /// Optional data digest. - iscsi_data_digest data_digest; -} iscsi_scsi_data_out_req_packet; - -/** * @brief SCSI Data In reponse flags: Status. * * (S) set to indicate that the Command Status field @@ -5366,437 +3790,115 @@ typedef struct __attribute__((packed)) iscsi_scsi_data_out_req_packet { * responses, i.e. read operations. */ typedef struct __attribute__((packed)) iscsi_scsi_data_in_response_packet { - /// Always 0x25 according to iSCSI specification. - uint8_t opcode; - - /// Incoming data flags. The fields StatSN, Status, and Residual Count only have meaningful content if the S bit is set to 1. - int8_t flags; - - /// Rserved for future usage, always MUST be 0. - uint8_t reserved; - - /** - * @brief Status or Reserved. - * - * Status can accompany the last Data-In PDU if the command did not end - * with an exception (i.e., the status is "good status" - GOOD, - * CONDITION MET, or INTERMEDIATE-CONDITION MET). The presence of - * status (and of a residual count) is signaled via the S flag bit. - * Although targets MAY choose to send even non-exception status in - * separate responses, initiators MUST support non-exception status in - * Data-In PDUs. - */ - uint8_t status; - - /// TotalAHSLength. - uint8_t total_ahs_len; - - /** - * @brief DataSegmentLength. - * - * This is the data payload length of a SCSI Data-In or SCSI Data-Out - * PDU. The sending of 0-length data segments should be avoided, but - * initiators and targets MUST be able to properly receive 0-length data - * segments.\n - * The data segments of Data-In and Data-Out PDUs SHOULD be filled to - * the integer number of 4-byte words (real payload), unless the F bit - * is set to 1. - */ - uint8_t ds_len[3]; - - /** - * @brief Logical Unit Number (LUN) or Reserved. - * - * If the Target Transfer Tag is provided, then the LUN field MUST hold a - * valid value and be consistent with whatever was specified with the command; - * otherwise, the LUN field is reserved. - */ - uint64_t lun; - - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; - - /** - * @brief Target Transfer Tag or 0xFFFFFFFF. - * - * On incoming data, the Target Transfer Tag and LUN MUST be provided by - * the target if the A bit is set to 1; otherwise, they are reserved. - * The Target Transfer Tag and LUN are copied by the initiator into the - * SNACK of type DataACK that it issues as a result of receiving a SCSI - * Data-In PDU with the A bit set to 1.\n - * The Target Transfer Tag values are not specified by this protocol, - * except that the value 0xFFFFFFFF is reserved and means that the - * Target Transfer Tag is not supplied. - */ - uint32_t target_xfer_tag; - - /// StatSN. - uint32_t stat_sn; - - /// ExpCmdSN. - - uint32_t exp_cmd_sn; - - /// MaxCmdSN. - uint32_t max_cmd_sn; - - /** - * @brief DataSN. - * - * For input (read) or bidirectional Data-In PDUs, the DataSN is the - * input PDU number within the data transfer for the command identified - * by the Initiator Task Tag.\n - * R2T and Data-In PDUs, in the context of bidirectional commands, share - * the numbering sequence. - */ - uint32_t data_sn; - - /** - * @brief Buffer Offset. - * - * The Buffer Offset field contains the offset of this PDU payload data - * within the complete data transfer. The sum of the buffer offset and - * length should not exceed the expected transfer length for the - * command.\n - * The order of data PDUs within a sequence is determined by - * DataPDUInOrder. When set to Yes, it means that PDUs have to be in - * increasing buffer offset order and overlays are forbidden.\n - * The ordering between sequences is determined by DataSequenceInOrder. - * When set to Yes, it means that sequences have to be in increasing - * buffer offset order and overlays are forbidden. - */ - uint32_t buf_offset; - - /// Residual Count or Reserved. - uint32_t res_cnt; - - /// Optional header digest. - iscsi_header_digest hdr_digest; - - /// Data segment. - iscsi_scsi_ds_cmd_data ds_cmd_data; - - /// Optional data digest. - iscsi_data_digest data_digest; + /// Always 0x25 according to iSCSI specification. + uint8_t opcode; + + /// Incoming data flags. The fields StatSN, Status, and Residual Count only have meaningful content if the S bit is set to 1. + int8_t flags; + + /// Rserved for future usage, always MUST be 0. + uint8_t reserved; + + /** + * @brief Status or Reserved. + * + * Status can accompany the last Data-In PDU if the command did not end + * with an exception (i.e., the status is "good status" - GOOD, + * CONDITION MET, or INTERMEDIATE-CONDITION MET). The presence of + * status (and of a residual count) is signaled via the S flag bit. + * Although targets MAY choose to send even non-exception status in + * separate responses, initiators MUST support non-exception status in + * Data-In PDUs. + */ + uint8_t status; + + /// TotalAHSLength. + uint8_t total_ahs_len; + + /** + * @brief DataSegmentLength. + * + * This is the data payload length of a SCSI Data-In or SCSI Data-Out + * PDU. The sending of 0-length data segments should be avoided, but + * initiators and targets MUST be able to properly receive 0-length data + * segments.\n + * The data segments of Data-In and Data-Out PDUs SHOULD be filled to + * the integer number of 4-byte words (real payload), unless the F bit + * is set to 1. + */ + uint8_t ds_len[3]; + + /** + * @brief Logical Unit Number (LUN) or Reserved. + * + * If the Target Transfer Tag is provided, then the LUN field MUST hold a + * valid value and be consistent with whatever was specified with the command; + * otherwise, the LUN field is reserved. + */ + uint64_t lun; + + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; + + /** + * @brief Target Transfer Tag or 0xFFFFFFFF. + * + * On incoming data, the Target Transfer Tag and LUN MUST be provided by + * the target if the A bit is set to 1; otherwise, they are reserved. + * The Target Transfer Tag and LUN are copied by the initiator into the + * SNACK of type DataACK that it issues as a result of receiving a SCSI + * Data-In PDU with the A bit set to 1.\n + * The Target Transfer Tag values are not specified by this protocol, + * except that the value 0xFFFFFFFF is reserved and means that the + * Target Transfer Tag is not supplied. + */ + uint32_t target_xfer_tag; + + /// StatSN. + uint32_t stat_sn; + + /// ExpCmdSN. + + uint32_t exp_cmd_sn; + + /// MaxCmdSN. + uint32_t max_cmd_sn; + + /** + * @brief DataSN. + * + * For input (read) or bidirectional Data-In PDUs, the DataSN is the + * input PDU number within the data transfer for the command identified + * by the Initiator Task Tag.\n + * R2T and Data-In PDUs, in the context of bidirectional commands, share + * the numbering sequence. + */ + uint32_t data_sn; + + /** + * @brief Buffer Offset. + * + * The Buffer Offset field contains the offset of this PDU payload data + * within the complete data transfer. The sum of the buffer offset and + * length should not exceed the expected transfer length for the + * command.\n + * The order of data PDUs within a sequence is determined by + * DataPDUInOrder. When set to Yes, it means that PDUs have to be in + * increasing buffer offset order and overlays are forbidden.\n + * The ordering between sequences is determined by DataSequenceInOrder. + * When set to Yes, it means that sequences have to be in increasing + * buffer offset order and overlays are forbidden. + */ + uint32_t buf_offset; + + /// Residual Count or Reserved. + uint32_t res_cnt; + + /// Data segment. + iscsi_scsi_ds_cmd_data ds_cmd_data; } iscsi_scsi_data_in_response_packet; /** - * @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 { - /// Always 0x31 according to iSCSI specification. - uint8_t opcode; - - /// Reserved for future usage (must be always 0x80 for now). - int8_t flags; - - /// Reserved for future usage, always MUST be 0 for now. - uint16_t reserved; - - /// TotalAHSLength, MUST be 0 for this PDU. - uint8_t total_ahs_len; - - /// DataSegmentLength, MUST be 0 0 for this PDU. - uint8_t ds_len[3]; - - /// Logical Unit Number (LUN) or Reserved. - uint64_t lun; - - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; - - /// Target Transfer Tag (TTT). - uint32_t target_xfer_tag; - - /// The StatSN field will contain the next StatSN. The StatSN for this connection is not advanced after this PDU is sent. - uint32_t stat_sn; - - /// ExpCmdSN. - uint32_t exp_cmd_sn; - - /// MaxCmdSN. - uint32_t max_cmd_sn; - - /// DataSN. - uint32_t data_sn; - - /// Ready To Transfer Sequence Number (R2TSN) is the R2T PDU input PDU number within the command identified by the Initiator Task Tag. For bidirectional commands, R2T and Data-In PDUs share the input PDU numbering sequence. - uint32_t r2t_sn; - - /** - * @brief Buffer Offset. - * - * The target therefore also specifies a buffer offset that indicates - * the point at which the data transfer should begin, relative to the - * beginning of the total data transfer. - */ - uint32_t buf_offset; - - /** - * @brief Desired Data Transfer Length. - * - * The target specifies how many bytes it wants the initiator to send - * because of this R2T PDU. The target may request the data from the - * initiator in several chunks, not necessarily in the original order of - * the data. The Desired Data Transfer Length MUST NOT be 0 and MUST NOT - * exceed MaxBurstLength. - */ - uint32_t des_data_xfer_len; - - /// Optional header digest. - iscsi_header_digest hdr_digest; -} iscsi_r2t_packet; - - -/** - * @brief SCSI Asynchronous Message Event: SCSI Async Event. - * - * A SCSI asynchronous event is reported in the sense data. - * Sense Data that accompanies the report, in the data - * segment, identifies the condition. The sending of a - * SCSI event ("asynchronous event reporting" in SCSI - * terminology) is dependent on the target support for SCSI - * asynchronous event reporting as indicated in the - * standard INQUIRY data. Its use may be enabled by - * parameters in the SCSI Control mode page. - */ -#define ISCSI_ASYNC_MSG_EVENT_SCSI_ASYNC_EVENT 0x00 - -/** - * @brief SCSI Asynchronous Message Event: Logout Request. - * - * The target requests Logout. This Async Message MUST - * be sent on the same connection as the one requesting - * to be logged out. The initiator MUST honor this request - * by issuing a Logout as early as possible but no later - * than Parameter3 seconds. The initiator MUST send a Logout - * with a reason code of "close the connection" OR "close the - * session" to close all the connections. Once this message is - * received, the initiator SHOULD NOT issue new iSCSI commands on - * the connection to be logged out. The target MAY reject any - * new I/O requests that it receives after this message with the - * reason code "Waiting for Logout". If the initiator does not - * log out in Parameter3 seconds, the target should send an Async - * PDU with iSCSI event code "Dropped the connection" if possible - * or simply terminate the transport connection. Parameter1 and - * Parameter2 are reserved. - */ -#define ISCSI_ASYNC_MSG_EVENT_LOGOUT_REQUEST 0x01 - -/** - * @brief SCSI Asynchronous Message Event: Connection Drop Notification. - * - * The target indicates that it will drop the connection. - * The Parameter1 field indicates the CID of the connection that - * is going to be dropped.\n - * The Parameter2 field (Time2Wait) indicates, in seconds, the - * minimum time to wait before attempting to reconnect or - * reassign.\n - * The Parameter3 field (Time2Retain) indicates the maximum time - * allowed to reassign commands after the initial wait (in - * Parameter2).\n - * If the initiator does not attempt to reconnect and/or reassign - * the outstanding commands within the time specified by - * Parameter3, or if Parameter3 is 0, the target will terminate - * all outstanding commands on this connection. In this case, no - * other responses should be expected from the target for the - * outstanding commands on this connection.\n - * A value of 0 for Parameter2 indicates that reconnect can be - * attempted immediately. - */ -#define ISCSI_ASYNC_MSG_EVENT_CONNECT_DROP_NOTIFY 0x02 - -/** - * @brief SCSI Asynchronous Message Event: Session Drop Notification. - * - * The target indicates that it will drop all the connections - * of this session.\n - * The Parameter1 field is reserved.\n - * The Parameter2 field (Time2Wait) indicates, in seconds, the - * minimum time to wait before attempting to reconnect.\n - * The Parameter3 field (Time2Retain) indicates the maximum time - * allowed to reassign commands after the initial wait (in - * Parameter2).\n - * If the initiator does not attempt to reconnect and/or reassign - * the outstanding commands within the time specified by - * Parameter3, or if Parameter3 is 0, the session is terminated.\n - * In this case, the target will terminate all outstanding - * commands in this session; no other responses should be - * expected from the target for the outstanding commands in this - * session. A value of 0 for Parameter2 indicates that reconnect - * can be attempted immediately. - */ -#define ISCSI_ASYNC_MSG_EVENT_SESSION_DROP_NOTIFY 0x03 - -/** - * @brief SCSI Asynchronous Message Event: Negotiation Request. - * - * The target requests parameter negotiation on this connection. - * The initiator MUST honor this request by issuing a Text - * Request (that can be empty) on the same connection as early - * as possible, but no later than Parameter3 seconds, unless a - * Text Request is already pending on the connection, or by - * issuing a Logout Request. If the initiator does not issue a - * Text Request, the target may reissue the Asynchronous Message - * requesting parameter negotiation. - */ -#define ISCSI_ASYNC_MSG_EVENT_NEGOTIATION_REQUEST 0x04 - -/** - * @brief SCSI Asynchronous Message Event: Task Termination. - * - * All active tasks for a LU with a matching LUN field in the - * Async Message PDU are being terminated. The receiving - * initiator iSCSI layer MUST respond to this message by - * taking the following steps, in order: - * - Stop Data-Out transfers on that connection for all active - * TTTs for the affected LUN quoted in the Async Message PDU. - * - Acknowledge the StatSN of the Async Message PDU via a - * NOP-Out PDU with ITT=0xFFFFFFFF (i.e., non-ping flavor), - * while copying the LUN field from the Async Message to - * NOP-Out. - * This value of AsyncEvent, however, MUST NOT be used on an - * iSCSI session unless the new TaskReporting text key was - * negotiated to FastAbort on the session. - */ -#define ISCSI_ASYNC_MSG_EVENT_TASK_TERMINATION 0x05 - -/// SCSI Asynchronous Message Event: First vendor-specific iSCSI event. The AsyncVCode details the vendor code, and data MAY accompany the report. -#define ISCSI_ASYNC_MSG_EVENT_VENDOR_FIRST 0xF8 - -/// SCSI Asynchronous Message Event: Last vendor-specific iSCSI event. The AsyncVCode details the vendor code, and data MAY accompany the report. -#define ISCSI_ASYNC_MSG_EVENT_VENDOR_LAST 0xFF - -/** - * @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.\n - * Some Asynchronous Messages are strictly related to iSCSI, while - * others are related to SCSI - */ -typedef struct __attribute__((packed)) iscsi_async_msg_packet { - /// Always 0x32 according to iSCSI specification. - uint8_t opcode; - - /// Reserved for future usage (must be always 0x80 for now). - int8_t flags; - - /// Reserved for 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 0 for this PDU. - uint8_t ds_len[3]; - - /// The LUN field MUST be valid if AsyncEvent is 0. Otherwise, this field is reserved. - uint64_t lun; - - /// Tag (always 0xFFFFFFFF for now). - uint32_t tag; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved2; - - /** - * @brief StatSN. - * - * The StatSN counts this PDU as an acknowledgeable event (the StatSN is - * advanced), which allows for initiator and target state synchronization. - */ - uint32_t stat_sn; - - /// ExpCmdSN. - uint32_t exp_cmd_sn; - - /// MaxCmdSN. - uint32_t max_cmd_sn; - - /// AsyncEvent. - uint8_t async_event; - - /// AsyncVCode is a vendor-specific detail code that is only valid if the AsyncEvent field indicates a vendor-specific event. Otherwise, it is reserved. - uint8_t async_vcode; - - /// Parameter1 or Reserved. - uint16_t param_1; - - /// Parameter2 or Reserved. - uint16_t param_2; - - /// Parameter3 or Reserved. - uint16_t param_3; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved3; - - /// Optional header digest. - iscsi_header_digest hdr_digest; - - /// Data segment. - iscsi_scsi_ds_cmd_data ds_cmd_data; - - /// Optional data digest. - iscsi_data_digest data_digest; -} iscsi_async_msg_packet; - - -/** * @brief Text Request flags: Continue. * * (C) When set to 1, this bit indicates that the text (set of key=value @@ -5831,106 +3933,100 @@ typedef struct __attribute__((packed)) iscsi_async_msg_packet { * implicitly terminated by the target. */ typedef struct __attribute__((packed)) iscsi_text_req_packet { - /// Always 0x04 according to iSCSI specification. - uint8_t opcode; - - /// Text request flags. - int8_t flags; - - /// Reserved for future usage, always MUST be 0. - uint16_t reserved; - - /// TotalAHSLength. - uint8_t total_ahs_len; - - /// DataSegmentLength. - uint8_t ds_len[3]; - - /// Logical Unit Number (LUN) or Reserved. - uint64_t lun; - - /** - * @brief Initiator Task Tag (ITT). - * - * This is the initiator-assigned identifier for this Text Request. If - * the command is sent as part of a sequence of Text Requests and - * responses, the Initiator Task Tag MUST be the same for all the - * requests within the sequence (similar to linked SCSI commands). The - * I bit for all requests in a sequence also MUST be the same. - */ - uint32_t init_task_tag; - - /** - * @brief Target Transfer Tag (TTT). - * - * When the Target Transfer Tag is set to the reserved value 0xFFFFFFFF, - * it tells the target that this is a new request, and the target resets - * any internal state associated with the Initiator Task Tag (resets the - * current negotiation state).\n - * The target sets the Target Transfer Tag in a Text Response to a value - * other than the reserved value 0xFFFFFFFF whenever it indicates that - * it has more data to send or more operations to perform that are - * associated with the specified Initiator Task Tag. It MUST do so - * whenever it sets the F bit to 0 in the response. By copying the - * Target Transfer Tag from the response to the next Text Request, the - * initiator tells the target to continue the operation for the specific - * Initiator Task Tag. The initiator MUST ignore the Target Transfer - * Tag in the Text Response when the F bit is set to 1.\n - * This mechanism allows the initiator and target to transfer a large - * amount of textual data over a sequence of text-command/text-response - * exchanges or to perform extended negotiation sequences.\n - * If the Target Transfer Tag is not 0xFFFFFFFF, the LUN field MUST be - * sent by the target in the Text Response.\n - * A target MAY reset its internal negotiation state if an exchange is - * stalled by the initiator for a long time or if it is running out of - * resources.\n - * Long Text Responses are handled as shown in the following example:\n - * @verbatim - * I->T Text SendTargets=All (F = 1, TTT = 0xFFFFFFFF) - * T->I Text <part 1> (F = 0, TTT = 0x12345678) - * I->T Text <empty> (F = 1, TTT = 0x12345678) - * T->I Text <part 2> (F = 0, TTT = 0x12345678) - * I->T Text <empty> (F = 1, TTT = 0x12345678) - * ... - * T->I Text <part n> (F = 1, TTT = 0xFFFFFFFF) - * @endverbatim - */ - uint32_t target_xfer_tag; - - /// CmdSN. - uint32_t cmd_sn; - - /// ExpStatSN. - uint32_t exp_stat_sn; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved2[2]; - - /// Optional header digest. - iscsi_header_digest hdr_digest; - - /** - * @brief Data segment. - * - * The data lengths of a Text Request MUST NOT exceed the iSCSI target - * MaxRecvDataSegmentLength (a parameter that is negotiated per - * connection and per direction).\n - * A key=value pair can span Text Request or Text Response boundaries. - * A key=value pair can start in one PDU and continue on the next. In - * other words, the end of a PDU does not necessarily signal the end of - * a key=value pair.\n - * The target responds by sending its response back to the initiator. - * The response text format is similar to the request text format. The - * Text Response MAY refer to key=value pairs presented in an earlier - * Text Request, and the text in the request may refer to earlier - * responses.\n - * Text operations are usually meant for parameter setting/negotiations - * but can also be used to perform some long-lasting operations. - */ - iscsi_scsi_ds_cmd_data ds_cmd_data; - - /// Optional data digest. - iscsi_data_digest data_digest; + /// Always 0x04 according to iSCSI specification. + uint8_t opcode; + + /// Text request flags. + int8_t flags; + + /// Reserved for future usage, always MUST be 0. + uint16_t reserved; + + /// TotalAHSLength. + uint8_t total_ahs_len; + + /// DataSegmentLength. + uint8_t ds_len[3]; + + /// Logical Unit Number (LUN) or Reserved. + uint64_t lun; + + /** + * @brief Initiator Task Tag (ITT). + * + * This is the initiator-assigned identifier for this Text Request. If + * the command is sent as part of a sequence of Text Requests and + * responses, the Initiator Task Tag MUST be the same for all the + * requests within the sequence (similar to linked SCSI commands). The + * I bit for all requests in a sequence also MUST be the same. + */ + uint32_t init_task_tag; + + /** + * @brief Target Transfer Tag (TTT). + * + * When the Target Transfer Tag is set to the reserved value 0xFFFFFFFF, + * it tells the target that this is a new request, and the target resets + * any internal state associated with the Initiator Task Tag (resets the + * current negotiation state).\n + * The target sets the Target Transfer Tag in a Text Response to a value + * other than the reserved value 0xFFFFFFFF whenever it indicates that + * it has more data to send or more operations to perform that are + * associated with the specified Initiator Task Tag. It MUST do so + * whenever it sets the F bit to 0 in the response. By copying the + * Target Transfer Tag from the response to the next Text Request, the + * initiator tells the target to continue the operation for the specific + * Initiator Task Tag. The initiator MUST ignore the Target Transfer + * Tag in the Text Response when the F bit is set to 1.\n + * This mechanism allows the initiator and target to transfer a large + * amount of textual data over a sequence of text-command/text-response + * exchanges or to perform extended negotiation sequences.\n + * If the Target Transfer Tag is not 0xFFFFFFFF, the LUN field MUST be + * sent by the target in the Text Response.\n + * A target MAY reset its internal negotiation state if an exchange is + * stalled by the initiator for a long time or if it is running out of + * resources.\n + * Long Text Responses are handled as shown in the following example:\n + * @verbatim + * I->T Text SendTargets=All (F = 1, TTT = 0xFFFFFFFF) + * T->I Text <part 1> (F = 0, TTT = 0x12345678) + * I->T Text <empty> (F = 1, TTT = 0x12345678) + * T->I Text <part 2> (F = 0, TTT = 0x12345678) + * I->T Text <empty> (F = 1, TTT = 0x12345678) + * ... + * T->I Text <part n> (F = 1, TTT = 0xFFFFFFFF) + * @endverbatim + */ + uint32_t target_xfer_tag; + + /// CmdSN. + uint32_t cmd_sn; + + /// ExpStatSN. + uint32_t exp_stat_sn; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved2[2]; + + /** + * @brief Data segment. + * + * The data lengths of a Text Request MUST NOT exceed the iSCSI target + * MaxRecvDataSegmentLength (a parameter that is negotiated per + * connection and per direction).\n + * A key=value pair can span Text Request or Text Response boundaries. + * A key=value pair can start in one PDU and continue on the next. In + * other words, the end of a PDU does not necessarily signal the end of + * a key=value pair.\n + * The target responds by sending its response back to the initiator. + * The response text format is similar to the request text format. The + * Text Response MAY refer to key=value pairs presented in an earlier + * Text Request, and the text in the request may refer to earlier + * responses.\n + * Text operations are usually meant for parameter setting/negotiations + * but can also be used to perform some long-lasting operations. + */ + iscsi_scsi_ds_cmd_data ds_cmd_data; } iscsi_text_req_packet; @@ -5972,87 +4068,81 @@ typedef struct __attribute__((packed)) iscsi_text_req_packet { * of the Text Request. */ typedef struct __attribute__((packed)) iscsi_text_response_packet { - /// Always 0x24 according to iSCSI specification. - uint8_t opcode; - - /// Text response flags. - int8_t flags; - - /// Reserved for future usage, always MUST be 0. - uint16_t reserved; - - /// TotalAHSLength. - uint8_t total_ahs_len; - - /// DataSegmentLength. - uint8_t ds_len[3]; - - /// Logical Unit Number (LUN) or Reserved. - uint64_t lun; - - /// The Initiator Task Tag matches the tag used in the initial Text Request. - uint32_t init_task_tag; - - /** - * @brief Target Transfer Tag (TTT). - * - * When a target has more work to do (e.g., cannot transfer all the - * remaining text data in a single Text Response or has to continue the - * negotiation) and has enough resources to proceed, it MUST set the - * Target Transfer Tag to a value other than the reserved value - * 0xFFFFFFFF. Otherwise, the Target Transfer Tag MUST be set to - * 0xFFFFFFFF.\n - * When the Target Transfer Tag is not 0xFFFFFFFF, the LUN field may be - * significant.\n - * The initiator MUST copy the Target Transfer Tag and LUN in its next - * request to indicate that it wants the rest of the data.\n - * When the target receives a Text Request with the Target Transfer Tag - * set to the reserved value 0xFFFFFFFF, it resets its internal - * information (resets state) associated with the given Initiator Task - * Tag (restarts the negotiation).\n - * When a target cannot finish the operation in a single Text Response - * and does not have enough resources to continue, it rejects the Text - * Request with the appropriate Reject code.\n - * A target may reset its internal state associated with an Initiator - * Task Tag (the current negotiation state) as expressed through the - * Target Transfer Tag if the initiator fails to continue the exchange - * for some time. The target may reject subsequent Text Requests with - * the Target Transfer Tag set to the "stale" value. - */ - uint32_t target_xfer_tag; - - /// StatSN. The target StatSN variable is advanced by each Text Response sent. - uint32_t stat_sn; - - /// ExpCmdSN. - uint32_t exp_cmd_sn; - - /// MaxCmdSN. - uint32_t max_cmd_sn; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved2[2]; - - /// Optional header digest. - iscsi_header_digest hdr_digest; - - /** - * @brief Data segment. - * - * The data lengths of a Text Response MUST NOT exceed the iSCSI - * initiator MaxRecvDataSegmentLength (a parameter that is negotiated - * per connection and per direction).\n - * The text in the Text Response Data is governed by the same rules as - * the text in the Text Request Data.\n - * Although the initiator is the requesting party and controls the - * request-response initiation and termination, the target can offer - * key=value pairs of its own as part of a sequence and not only in - * response to the initiator. - */ - iscsi_scsi_ds_cmd_data ds_cmd_data; - - /// Optional data digest. - iscsi_data_digest data_digest; + /// Always 0x24 according to iSCSI specification. + uint8_t opcode; + + /// Text response flags. + int8_t flags; + + /// Reserved for future usage, always MUST be 0. + uint16_t reserved; + + /// TotalAHSLength. + uint8_t total_ahs_len; + + /// DataSegmentLength. + uint8_t ds_len[3]; + + /// Logical Unit Number (LUN) or Reserved. + uint64_t lun; + + /// The Initiator Task Tag matches the tag used in the initial Text Request. + uint32_t init_task_tag; + + /** + * @brief Target Transfer Tag (TTT). + * + * When a target has more work to do (e.g., cannot transfer all the + * remaining text data in a single Text Response or has to continue the + * negotiation) and has enough resources to proceed, it MUST set the + * Target Transfer Tag to a value other than the reserved value + * 0xFFFFFFFF. Otherwise, the Target Transfer Tag MUST be set to + * 0xFFFFFFFF.\n + * When the Target Transfer Tag is not 0xFFFFFFFF, the LUN field may be + * significant.\n + * The initiator MUST copy the Target Transfer Tag and LUN in its next + * request to indicate that it wants the rest of the data.\n + * When the target receives a Text Request with the Target Transfer Tag + * set to the reserved value 0xFFFFFFFF, it resets its internal + * information (resets state) associated with the given Initiator Task + * Tag (restarts the negotiation).\n + * When a target cannot finish the operation in a single Text Response + * and does not have enough resources to continue, it rejects the Text + * Request with the appropriate Reject code.\n + * A target may reset its internal state associated with an Initiator + * Task Tag (the current negotiation state) as expressed through the + * Target Transfer Tag if the initiator fails to continue the exchange + * for some time. The target may reject subsequent Text Requests with + * the Target Transfer Tag set to the "stale" value. + */ + uint32_t target_xfer_tag; + + /// StatSN. The target StatSN variable is advanced by each Text Response sent. + uint32_t stat_sn; + + /// ExpCmdSN. + uint32_t exp_cmd_sn; + + /// MaxCmdSN. + uint32_t max_cmd_sn; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved2[2]; + + /** + * @brief Data segment. + * + * The data lengths of a Text Response MUST NOT exceed the iSCSI + * initiator MaxRecvDataSegmentLength (a parameter that is negotiated + * per connection and per direction).\n + * The text in the Text Response Data is governed by the same rules as + * the text in the Text Request Data.\n + * Although the initiator is the requesting party and controls the + * request-response initiation and termination, the target can offer + * key=value pairs of its own as part of a sequence and not only in + * response to the initiator. + */ + iscsi_scsi_ds_cmd_data ds_cmd_data; } iscsi_text_response_packet; @@ -6129,17 +4219,17 @@ typedef struct __attribute__((packed)) iscsi_text_response_packet { * MUST also be persistent over power cycles, reboot, card swap, etc. */ typedef struct __attribute__((packed)) iscsi_isid { - /// Meaning depends on T bit, either 22-bit OUI or reserved. - uint8_t a; + /// Meaning depends on T bit, either 22-bit OUI or reserved. + uint8_t a; - /// Meaning depends on T bit, either 22-bit OUI, EN (IANA Enterprise Number) or random. - uint16_t b; + /// Meaning depends on T bit, either 22-bit OUI, EN (IANA Enterprise Number) or random. + uint16_t b; - /// Meaning depends on T bit, either 24-bit Qualifier, EN (IANA Enterprise Number) or random. - uint8_t c; + /// Meaning depends on T bit, either 24-bit Qualifier, EN (IANA Enterprise Number) or random. + uint8_t c; - /// Meaning depends on T bit, either 24-bit Qualifier or Qualifier. - uint16_t d; + /// Meaning depends on T bit, either 24-bit Qualifier or Qualifier. + uint16_t d; } iscsi_isid; @@ -6265,119 +4355,119 @@ typedef struct __attribute__((packed)) iscsi_isid { * Login Requests are always considered as immediate. */ typedef struct __attribute__((packed)) iscsi_login_req_packet { - /// Always 0x03 according to iSCSI specification. - uint8_t opcode; - - /// Login request flags. - int8_t flags; - - /** - * @brief Version-max indicates the maximum version number supported. - * - * All Login Requests within the Login Phase MUST carry the same - * Version-max. Currently, this is always 0.\n - * The target MUST use the value presented with the first Login Request. - */ - uint8_t version_max; - - /** - * @brief Version-min indicates the minimum version number supported. - * - * All Login Requests within the Login Phase MUST carry the same - * Version-min. The target MUST use the value presented with the first - * Login Request. Always 0 for now. - */ - uint8_t version_min; - - /// TotalAHSLength. - uint8_t total_ahs_len; - - /// DataSegmentLength. - uint8_t ds_len[3]; - - /// Initiator Session ID (ISID). - iscsi_isid isid; - - /** - * @brief Target Session Identifying Handle (TSIH). - * - * The TSIH must be set in the first Login Request. The reserved value - * 0 MUST be used on the first connection for a new session. Otherwise, - * the TSIH sent by the target at the conclusion of the successful login - * of the first connection for this session MUST be used. The TSIH - * identifies to the target the associated existing session for this new - * connection.\n - * All Login Requests within a Login Phase MUST carry the same TSIH. - * The target MUST check the value presented with the first Login - * Request. - */ - uint16_t tsih; - - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; - - /** - * @brief Connection ID (CID). - * - * The CID provides a unique ID for this connection within the session.\n - * All Login Requests within the Login Phase MUST carry the same CID. - * The target MUST use the value presented with the first Login Request.\n - * A Login Request with a non-zero TSIH and a CID equal to that of an - * existing connection implies a logout of the connection followed by a - * login. - */ - uint16_t cid; - - /// Reserved for future usage, always MUST be 0. - uint16_t reserved; - - /** - * @brief CmdSN. - * - * The CmdSN is either the initial command sequence number of a session - * (for the first Login Request of a session - the "leading" login) or - * the command sequence number in the command stream if the login is for - * a new connection in an existing session.\n - * Examples: - * - Login on a leading connection: If the leading login carries the - * CmdSN 123, all other Login Requests in the same Login Phase carry - * the CmdSN 123, and the first non-immediate command in the Full - * Feature Phase also carries the CmdSN 123. - * - Login on other than a leading connection: If the current CmdSN at - * the time the first login on the connection is issued is 500, then - * that PDU carries CmdSN=500. Subsequent Login Requests that are - * needed to complete this Login Phase may carry a CmdSN higher than - * 500 if non-immediate requests that were issued on other connections - * in the same session advance the CmdSN. - * - * If the Login Request is a leading Login Request, the target MUST use - * the value presented in the CmdSN as the target value for the - * ExpCmdSN. - */ - uint32_t cmd_sn; - - /** - * @brief ExpStatSN. - * - * For the first Login Request on a connection, this is the ExpStatSN - * for the old connection, and this field is only valid if the Login - * Request restarts a connection.\n - * For subsequent Login Requests, it is used to acknowledge the Login - * Responses with their increasing StatSN values. - */ - uint32_t exp_stat_sn; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved2[2]; - - /** - * @brief Data segment - Login Parameters in Text Request Format. - * - * The initiator MUST provide some basic parameters in order - * to enable the target to determine if the initiator may use - * the target's resources and the initial text parameters for the security exchange - */ - iscsi_scsi_ds_cmd_data ds_cmd_data; + /// Always 0x03 according to iSCSI specification. + uint8_t opcode; + + /// Login request flags. + int8_t flags; + + /** + * @brief Version-max indicates the maximum version number supported. + * + * All Login Requests within the Login Phase MUST carry the same + * Version-max. Currently, this is always 0.\n + * The target MUST use the value presented with the first Login Request. + */ + uint8_t version_max; + + /** + * @brief Version-min indicates the minimum version number supported. + * + * All Login Requests within the Login Phase MUST carry the same + * Version-min. The target MUST use the value presented with the first + * Login Request. Always 0 for now. + */ + uint8_t version_min; + + /// TotalAHSLength. + uint8_t total_ahs_len; + + /// DataSegmentLength. + uint8_t ds_len[3]; + + /// Initiator Session ID (ISID). + iscsi_isid isid; + + /** + * @brief Target Session Identifying Handle (TSIH). + * + * The TSIH must be set in the first Login Request. The reserved value + * 0 MUST be used on the first connection for a new session. Otherwise, + * the TSIH sent by the target at the conclusion of the successful login + * of the first connection for this session MUST be used. The TSIH + * identifies to the target the associated existing session for this new + * connection.\n + * All Login Requests within a Login Phase MUST carry the same TSIH. + * The target MUST check the value presented with the first Login + * Request. + */ + uint16_t tsih; + + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; + + /** + * @brief Connection ID (CID). + * + * The CID provides a unique ID for this connection within the session.\n + * All Login Requests within the Login Phase MUST carry the same CID. + * The target MUST use the value presented with the first Login Request.\n + * A Login Request with a non-zero TSIH and a CID equal to that of an + * existing connection implies a logout of the connection followed by a + * login. + */ + uint16_t cid; + + /// Reserved for future usage, always MUST be 0. + uint16_t reserved; + + /** + * @brief CmdSN. + * + * The CmdSN is either the initial command sequence number of a session + * (for the first Login Request of a session - the "leading" login) or + * the command sequence number in the command stream if the login is for + * a new connection in an existing session.\n + * Examples: + * - Login on a leading connection: If the leading login carries the + * CmdSN 123, all other Login Requests in the same Login Phase carry + * the CmdSN 123, and the first non-immediate command in the Full + * Feature Phase also carries the CmdSN 123. + * - Login on other than a leading connection: If the current CmdSN at + * the time the first login on the connection is issued is 500, then + * that PDU carries CmdSN=500. Subsequent Login Requests that are + * needed to complete this Login Phase may carry a CmdSN higher than + * 500 if non-immediate requests that were issued on other connections + * in the same session advance the CmdSN. + * + * If the Login Request is a leading Login Request, the target MUST use + * the value presented in the CmdSN as the target value for the + * ExpCmdSN. + */ + uint32_t cmd_sn; + + /** + * @brief ExpStatSN. + * + * For the first Login Request on a connection, this is the ExpStatSN + * for the old connection, and this field is only valid if the Login + * Request restarts a connection.\n + * For subsequent Login Requests, it is used to acknowledge the Login + * Responses with their increasing StatSN values. + */ + uint32_t exp_stat_sn; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved2[2]; + + /** + * @brief Data segment - Login Parameters in Text Request Format. + * + * The initiator MUST provide some basic parameters in order + * to enable the target to determine if the initiator may use + * the target's resources and the initial text parameters for the security exchange + */ + iscsi_scsi_ds_cmd_data ds_cmd_data; } iscsi_login_req_packet; @@ -6624,107 +4714,107 @@ typedef struct __attribute__((packed)) iscsi_login_req_packet { * Phase. */ typedef struct __attribute__((packed)) iscsi_login_response_packet { - /// Always 0x23 according to iSCSI specification. - uint8_t opcode; - - /// Login response flags. - int8_t flags; - - /** - * @brief This is the highest version number supported by the target. - * - * All Login Responses within the Login Phase MUST carry the same - * Version-max. - */ - uint8_t version_max; - - /** - * @brief Version-active indicates the highest version supported by the target and initiator. - * - * If the target does not support a version within the - * range specified by the initiator, the target rejects the login and - * this field indicates the lowest version supported by the target. - * All Login Responses within the Login Phase MUST carry the same - * Version-active.\n - * The initiator MUST use the value presented as a response to the first - * Login Request. - */ - uint8_t version_active; - - /// TotalAHSLength. - uint8_t total_ahs_len; - - /// DataSegmentLength. - uint8_t ds_len[3]; - - /// Initiator Session ID (ISID). - iscsi_isid isid; - - /** - * @brief Target Session Identifying Handle (TSIH). - * - * The TSIH is the target-assigned session-identifying handle. Its - * internal format and content are not defined by this protocol, except - * for the value 0, which is reserved. With the exception of the Login - * Final-Response in a new session, this field should be set to the TSIH - * provided by the initiator in the Login Request. For a new session, - * the target MUST generate a non-zero TSIH and ONLY return it in the - * Login Final-Response. - */ - uint16_t tsih; - - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved; - - /** - * @brief StatSN. - * - * For the first Login Response (the response to the first Login - * Request), this is the starting status sequence number for the - * connection. The next response of any kind - including the next - * Login Response, if any, in the same Login Phase - will carry this - * number + 1. This field is only valid if the Status-Class is 0. - */ - uint32_t stat_sn; - - /// ExpCmdSN. - uint32_t exp_cmd_sn; - - /// MaxCmdSN. - uint32_t max_cmd_sn; - - /** - * @brief Status-class. - * - * Status-class (see above for details). If the Status-Class is - * not 0, the initiator and target MUST close the TCP connection - * If the target wishes to reject the Login Request for more than one - * reason, it should return the primary reason for the rejection. - */ - uint8_t status_class; - - /// Status-detail. - uint8_t status_detail; - - /// Reserved for future usage, always MUST be 0. - uint16_t reserved2; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved3; - - /** - * @brief Data segment - Login Parameters in Text Request Format. - * - * The target MUST provide some basic parameters in order to enable the - * initiator to determine if it is connected to the correct port and the - * initial text parameters for the security exchange.\n - * All the rules specified for Text Responses also hold for Login - * Responses. - */ - iscsi_scsi_ds_cmd_data ds_cmd_data; + /// Always 0x23 according to iSCSI specification. + uint8_t opcode; + + /// Login response flags. + int8_t flags; + + /** + * @brief This is the highest version number supported by the target. + * + * All Login Responses within the Login Phase MUST carry the same + * Version-max. + */ + uint8_t version_max; + + /** + * @brief Version-active indicates the highest version supported by the target and initiator. + * + * If the target does not support a version within the + * range specified by the initiator, the target rejects the login and + * this field indicates the lowest version supported by the target. + * All Login Responses within the Login Phase MUST carry the same + * Version-active.\n + * The initiator MUST use the value presented as a response to the first + * Login Request. + */ + uint8_t version_active; + + /// TotalAHSLength. + uint8_t total_ahs_len; + + /// DataSegmentLength. + uint8_t ds_len[3]; + + /// Initiator Session ID (ISID). + iscsi_isid isid; + + /** + * @brief Target Session Identifying Handle (TSIH). + * + * The TSIH is the target-assigned session-identifying handle. Its + * internal format and content are not defined by this protocol, except + * for the value 0, which is reserved. With the exception of the Login + * Final-Response in a new session, this field should be set to the TSIH + * provided by the initiator in the Login Request. For a new session, + * the target MUST generate a non-zero TSIH and ONLY return it in the + * Login Final-Response. + */ + uint16_t tsih; + + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; + + /// Reserved for future usage, always MUST be 0. + uint32_t reserved; + + /** + * @brief StatSN. + * + * For the first Login Response (the response to the first Login + * Request), this is the starting status sequence number for the + * connection. The next response of any kind - including the next + * Login Response, if any, in the same Login Phase - will carry this + * number + 1. This field is only valid if the Status-Class is 0. + */ + uint32_t stat_sn; + + /// ExpCmdSN. + uint32_t exp_cmd_sn; + + /// MaxCmdSN. + uint32_t max_cmd_sn; + + /** + * @brief Status-class. + * + * Status-class (see above for details). If the Status-Class is + * not 0, the initiator and target MUST close the TCP connection + * If the target wishes to reject the Login Request for more than one + * reason, it should return the primary reason for the rejection. + */ + uint8_t status_class; + + /// Status-detail. + uint8_t status_detail; + + /// Reserved for future usage, always MUST be 0. + uint16_t reserved2; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved3; + + /** + * @brief Data segment - Login Parameters in Text Request Format. + * + * The target MUST provide some basic parameters in order to enable the + * initiator to determine if it is connected to the correct port and the + * initial text parameters for the security exchange.\n + * All the rules specified for Text Responses also hold for Login + * Responses. + */ + iscsi_scsi_ds_cmd_data ds_cmd_data; } iscsi_login_response_packet; @@ -6832,82 +4922,79 @@ typedef struct __attribute__((packed)) iscsi_login_response_packet { * recovery, unless the session is also closed. */ typedef struct __attribute__((packed)) iscsi_logout_req_packet { - /// Always 6 according to iSCSI specification. - uint8_t opcode; - - /** - * @brief Reason code. - * - * A target implicitly terminates the active tasks due to the iSCSI - * protocol in the following cases: - * -# When a connection is implicitly or explicitly logged out with - * the reason code "close the connection" and there are active - * tasks allegiant to that connection. - * -# When a connection fails and eventually the connection state - * times out and there are active tasks allegiant to that - * connection - * -# When a successful recovery Logout is performed while there are - * active tasks allegiant to that connection and those tasks - * eventually time out after the Time2Wait and Time2Retain periods - * without allegiance reassignment - * -# When a connection is implicitly or explicitly logged out with - * the reason code "close the session" and there are active tasks - * in that session - * - * If the tasks terminated in any of the above cases are SCSI tasks, - * they must be internally terminated as if with CHECK CONDITION status. - * This status is only meaningful for appropriately handling the - * internal SCSI state and SCSI side effects with respect to ordering, - * because this status is never communicated back as a terminating - * status to the initiator. However, additional actions may have to be - * taken at the SCSI level, depending on the SCSI context as defined by - * the SCSI standards (e.g., queued commands and ACA; UA for the next - * command on the I_T nexus in cases a), b), and c) above). After the - * tasks are terminated, the target MUST report a Unit Attention condition - * on the next command processed on any connection for each affected - * I_T_L nexus with the status of CHECK CONDITION, the ASC/ASCQ value - * of 0x47 / 0x7F ("SOME COMMANDS CLEARED BY ISCSI PROTOCOL EVENT"), etc. - */ - int8_t reason_code; - - /// Reserved for 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]; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved2; - - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; - - /** - * @brief Connection ID (CID). - * - * This is the connection ID of the connection to be closed (including - * closing the TCP stream). This field is only valid if the reason code - * is not "close the session". - */ - uint16_t cid; - - /// Reserved for future usage, always MUST be 0. - uint16_t reserved3; - - /// CmdSN. - uint32_t cmd_sn; - - /// This is the last ExpStatSN value for the connection to be closed. - uint32_t exp_stat_sn; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved4[2]; - - /// Optional header digest. - iscsi_header_digest hdr_digest; + /// Always 6 according to iSCSI specification. + uint8_t opcode; + + /** + * @brief Reason code. + * + * A target implicitly terminates the active tasks due to the iSCSI + * protocol in the following cases: + * -# When a connection is implicitly or explicitly logged out with + * the reason code "close the connection" and there are active + * tasks allegiant to that connection. + * -# When a connection fails and eventually the connection state + * times out and there are active tasks allegiant to that + * connection + * -# When a successful recovery Logout is performed while there are + * active tasks allegiant to that connection and those tasks + * eventually time out after the Time2Wait and Time2Retain periods + * without allegiance reassignment + * -# When a connection is implicitly or explicitly logged out with + * the reason code "close the session" and there are active tasks + * in that session + * + * If the tasks terminated in any of the above cases are SCSI tasks, + * they must be internally terminated as if with CHECK CONDITION status. + * This status is only meaningful for appropriately handling the + * internal SCSI state and SCSI side effects with respect to ordering, + * because this status is never communicated back as a terminating + * status to the initiator. However, additional actions may have to be + * taken at the SCSI level, depending on the SCSI context as defined by + * the SCSI standards (e.g., queued commands and ACA; UA for the next + * command on the I_T nexus in cases a), b), and c) above). After the + * tasks are terminated, the target MUST report a Unit Attention condition + * on the next command processed on any connection for each affected + * I_T_L nexus with the status of CHECK CONDITION, the ASC/ASCQ value + * of 0x47 / 0x7F ("SOME COMMANDS CLEARED BY ISCSI PROTOCOL EVENT"), etc. + */ + int8_t reason_code; + + /// Reserved for 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]; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved2; + + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; + + /** + * @brief Connection ID (CID). + * + * This is the connection ID of the connection to be closed (including + * closing the TCP stream). This field is only valid if the reason code + * is not "close the session". + */ + uint16_t cid; + + /// Reserved for future usage, always MUST be 0. + uint16_t reserved3; + + /// CmdSN. + uint32_t cmd_sn; + + /// This is the last ExpStatSN value for the connection to be closed. + uint32_t exp_stat_sn; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved4[2]; } iscsi_logout_req_packet; @@ -6934,272 +5021,90 @@ typedef struct __attribute__((packed)) iscsi_logout_req_packet { * was session close). */ typedef struct __attribute__((packed)) iscsi_logout_response_packet { - /// Always 0x26 according to iSCSI specification. - uint8_t opcode; - - /// Reserved for future usage (must be always 0x80 for now). - int8_t flags; - - /// Response. - uint8_t response; - - /// Reserved for future usage, always MUST be 0. - uint8_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]; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved2; - - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved3; - - /// StatSN. - uint32_t stat_sn; - - /// ExpCmdSN. - uint32_t exp_cmd_sn; - - /// MaxCmdSN. - uint32_t max_cmd_sn; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved4; - - /** - * @brief Time2Wait. - * - * If the Logout response code is 0 and the operational - * ErrorRecoveryLevel is 2, this is the minimum amount of time, in - * seconds, to wait before attempting task reassignment. If the Logout - * response code is 0 and the operational ErrorRecoveryLevel is less - * than 2, this field is to be ignored.\n - * This field is invalid if the Logout response code is 1.\n - * If the Logout response code is 2 or 3, this field specifies the - * minimum time to wait before attempting a new implicit or explicit - * logout.\n - * If Time2Wait is 0, the reassignment or a new Logout may be attempted - * immediately. - */ - uint16_t time_wait; - - /** - * @brief Time2Retain. - * - * If the Logout response code is 0 and the operational - * ErrorRecoveryLevel is 2, this is the maximum amount of time, in - * seconds, after the initial wait (Time2Wait) that the target waits for - * the allegiance reassignment for any active task, after which the task - * state is discarded. If the Logout response code is 0 and the - * operational ErrorRecoveryLevel is less than 2, this field is to be - * ignored.\n - * This field is invalid if the Logout response code is 1.\n - * If the Logout response code is 2 or 3, this field specifies the - * maximum amount of time, in seconds, after the initial wait - * (Time2Wait) that the target waits for a new implicit or explicit - * logout.\n - * If it is the last connection of a session, the whole session state is - * discarded after Time2Retain.\n - * If Time2Retain is 0, the target has already discarded the connection - * (and possibly the session) state along with the task states. No - * reassignment or Logout is required in this case. - */ - uint16_t time_retain; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved5; - - /// Optional header digest. - iscsi_header_digest hdr_digest; + /// Always 0x26 according to iSCSI specification. + uint8_t opcode; + + /// Reserved for future usage (must be always 0x80 for now). + int8_t flags; + + /// Response. + uint8_t response; + + /// Reserved for future usage, always MUST be 0. + uint8_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]; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved2; + + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; + + /// Reserved for future usage, always MUST be 0. + uint32_t reserved3; + + /// StatSN. + uint32_t stat_sn; + + /// ExpCmdSN. + uint32_t exp_cmd_sn; + + /// MaxCmdSN. + uint32_t max_cmd_sn; + + /// Reserved for future usage, always MUST be 0. + uint32_t reserved4; + + /** + * @brief Time2Wait. + * + * If the Logout response code is 0 and the operational + * ErrorRecoveryLevel is 2, this is the minimum amount of time, in + * seconds, to wait before attempting task reassignment. If the Logout + * response code is 0 and the operational ErrorRecoveryLevel is less + * than 2, this field is to be ignored.\n + * This field is invalid if the Logout response code is 1.\n + * If the Logout response code is 2 or 3, this field specifies the + * minimum time to wait before attempting a new implicit or explicit + * logout.\n + * If Time2Wait is 0, the reassignment or a new Logout may be attempted + * immediately. + */ + uint16_t time_wait; + + /** + * @brief Time2Retain. + * + * If the Logout response code is 0 and the operational + * ErrorRecoveryLevel is 2, this is the maximum amount of time, in + * seconds, after the initial wait (Time2Wait) that the target waits for + * the allegiance reassignment for any active task, after which the task + * state is discarded. If the Logout response code is 0 and the + * operational ErrorRecoveryLevel is less than 2, this field is to be + * ignored.\n + * This field is invalid if the Logout response code is 1.\n + * If the Logout response code is 2 or 3, this field specifies the + * maximum amount of time, in seconds, after the initial wait + * (Time2Wait) that the target waits for a new implicit or explicit + * logout.\n + * If it is the last connection of a session, the whole session state is + * discarded after Time2Retain.\n + * If Time2Retain is 0, the target has already discarded the connection + * (and possibly the session) state along with the task states. No + * reassignment or Logout is required in this case. + */ + uint16_t time_retain; + + /// Reserved for future usage, always MUST be 0. + uint32_t reserved5; } iscsi_logout_response_packet; -/// Selective Negative / Sequence Number Acknowledgment (SNACK) request: Data/R2T SNACK: requesting retransmission of one or more Data-In or R2T PDUs. -#define ISCSI_SNACK_REQ_TYPE_DATA_R2T_SNACK 0x00 - -/// Selective Negative / Sequence Number Acknowledgment (SNACK) request: -#define ISCSI_SNACK_REQ_TYPE_STATUS_SNACK 0x01 // Status SNACK: requesting retransmission of one or more - // numbered responses - -/** - * @brief Selective Negative / Sequence Number Acknowledgment (SNACK) request: DataACK: positively acknowledges Data-In PDUs. - * - * If an initiator operates at ErrorRecoveryLevel 1 or higher, it MUST - * issue a SNACK of type DataACK after receiving a Data-In PDU with the - * A bit set to 1. However, if the initiator has detected holes in the - * input sequence, it MUST postpone issuing the SNACK of type DataACK - * until the holes are filled. An initiator MAY ignore the A bit if it - * deems that the bit is being set aggressively by the target (i.e., - * before the MaxBurstLength limit is reached).\n - * The DataACK is used to free resources at the target and not to - * request or imply data retransmission.\n - * An initiator MUST NOT request retransmission for any data it had - * already acknowledged - */ -#define ISCSI_SNACK_REQ_TYPE_DATA_ACK 0x02 - -/** - * @brief Selective Negative / Sequence Number Acknowledgment (SNACK) request: R-Data SNACK: requesting retransmission of Data-In PDUs with possible resegmentation and status tagging. - * - * If the initiator MaxRecvDataSegmentLength changed between the - * original transmission and the time the initiator requests - * retransmission, the initiator MUST issue a R-Data SNACK.\n - * With R-Data SNACK, the initiator indicates that it discards all the - * unacknowledged data and expects the target to resend it. It also - * expects resegmentation. In this case, the retransmitted Data-In PDUs - * MAY be different from the ones originally sent in order to reflect - * changes in MaxRecvDataSegmentLength. Their DataSN starts with the - * BegRun of the last DataACK received by the target if any was received; - * otherwise, it starts with 0 and is increased by 1 for each resent - * Data-In PDU.\n - * A target that has received a R-Data SNACK MUST return a SCSI Response - * that contains a copy of the SNACK Tag field from the R-Data SNACK in - * the SCSI Response SNACK Tag field as its last or only Response. For - * example, if it has already sent a response containing another value - * in the SNACK Tag field or had the status included in the last Data-In - * PDU, it must send a new SCSI Response PDU. If a target sends more - * than one SCSI Response PDU due to this rule, all SCSI Response PDUs - * must carry the same StatSN. If an initiator attempts to recover a lost - * SCSI Response when more than one response has been sent, the - * target will send the SCSI Response with the latest content known to - * the target, including the last SNACK Tag for the command.\n - * For considerations in allegiance reassignment of a task to a - * connection with a different MaxRecvDataSegmentLength. - */ -#define ISCSI_SNACK_REQ_TYPE_R_DATA_SNACK 0x03 - - -/** - * @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 { - /// Always 0x10 according to iSCSI specification. - uint8_t opcode; - - /** - * @brief Type. - * - * Data/R2T SNACK, Status SNACK, or R-Data SNACK for a command MUST - * precede status acknowledgment for the given command. - */ - int8_t type; - - /// Reserved for future usage, always MUST be 0. - uint16_t reserved; - - /// TotalAHSLength. - uint8_t total_ahs_len; - - /// DataSegmentLength. - uint8_t ds_len[3]; - - /// LUN or Reserved. - uint64_t lun; - - /** - * @brief Initiator Task Tag (ITT). - * - * For a Status SNACK and DataACK, the Initiator Task Tag MUST be set to - * the reserved value 0xFFFFFFFF. In all other cases, the Initiator - * Task Tag field MUST be set to the Initiator Task Tag of the - * referenced command. - */ - uint32_t init_task_tag; - - /** - * @brief Target Transfer Tag (TTT). - * - * For a R-Data SNACK, this field MUST contain a value that is different - * from 0 or 0xFFFFFFFF and is unique for the task (identified by the - * Initiator Task Tag). This value MUST be copied by the iSCSI target - * in the last or only SCSI Response PDU it issues for the command.\n - * For DataACK, the Target Transfer Tag MUST contain a copy of the - * Target Transfer Tag and LUN provided with the SCSI Data-In PDU with - * the A bit set to 1.\n - * In all other cases, the Target Transfer Tag field MUST be set to the - * reserved value 0xFFFFFFFF. - */ - uint32_t target_xfer_snack_tag; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved2; - - /// ExpStatSN. - uint32_t exp_stat_sn; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved3; - - /** - * @brief BegRun. - * - * This field indicates the DataSN, R2TSN, or StatSN of the first PDU - * whose retransmission is requested (Data/R2T and Status SNACK), or the - * next expected DataSN (DataACK SNACK).\n - * A BegRun of 0, when used in conjunction with a RunLength of 0, means - * "resend all unacknowledged Data-In, R2T or Response PDUs". - * BegRun MUST be 0 for a R-Data SNACK. - */ - uint32_t beg_run; - - /** - * @brief RunLength. - * - * This field indicates the number of PDUs whose retransmission is - * requested.\n - * A RunLength of 0 signals that all Data-In, R2T, or Response PDUs - * carrying the numbers equal to or greater than BegRun have to be - * resent.\n - * The RunLength MUST also be 0 for a DataACK SNACK in addition to a - * R-Data SNACK. - */ - uint32_t run_len; - - /// Optional header digest. - iscsi_header_digest hdr_digest; -} iscsi_snack_req_packet; - - /// iSCSI Reject packet data: Reserved, original PDU can't be resent. #define ISCSI_REJECT_REASON_RESERVED 0x01 @@ -7266,100 +5171,91 @@ typedef struct __attribute__((packed)) iscsi_snack_req_packet { * packet was rejected or has been rejected for some reason. */ typedef struct __attribute__((packed)) iscsi_reject_packet { - /// Always 0x3F according to iSCSI specification. - uint8_t opcode; - - /// Reserved for future usage (must be always 0x80 for now). - int8_t flags; - - /** - * @brief Reject reason. - * - * In all the cases in which a pre-instantiated SCSI task is terminated - * because of the reject, the target MUST issue a proper SCSI command - * response with CHECK CONDITION. In these cases in which a status for - * the SCSI task was already sent before the reject, no additional - * status is required. If the error is detected while data from the - * initiator is still expected (i.e., the command PDU did not contain - * all the data and the target has not received a Data-Out PDU with the - * Final bit set to 1 for the unsolicited data, if any, and all - * outstanding R2Ts, if any), the target MUST wait until it receives - * the last expected Data-Out PDUs with the F bit set to 1 before - * sending the Response PDU. - */ - uint8_t reason; - - /// Reserved for future usage, always MUST be 0. - uint8_t reserved; - - /// TotalAHSLength. - uint8_t total_ahs_len; - - /// DataSegmentLength. - uint8_t ds_len[3]; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved2; - - /// Always 0xFFFFFFFF for now. - uint32_t tag; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved3; - - /** - * @brief StatSN. - * - * This field carries its usual value and is not related to the - * rejected command. The StatSN is advanced after a Reject. - */ - uint32_t stat_sn; - - /** - * @brief ExpCmdSN. - * - * This field carries its usual value and is not related to the - * rejected command. - */ - uint32_t exp_cmd_sn; - - /** - * @brief MaxCmdSN. - * - * This field carries its usual value and is not related to the - * rejected command. - */ - uint32_t max_cmd_sn; - - /** - * @brief DataSN / Ready To Transfer Sequence Number (R2TSN) or Reserved. - * - * This field is only valid if the rejected PDU is a Data/R2T SNACK and - * the Reject reason code is "Protocol Error". The DataSN/R2TSN is the - * next Data/R2T sequence number that the target would send for the - * task, if any. - */ - uint32_t data_r2t_sn; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved4; - - /// Optional header digest. - iscsi_header_digest hdr_digest; - - /** - * @brief Complete Header of Bad PDU. - * - * The target returns the header (not including the digest) of the - * PDU in error as the data of the response. - */ - iscsi_bhs_packet bad_pdu_hdr; - - /// Vendor-specific data (if any). - uint8_t vendor_data[0]; - - /// Optional data digest. - iscsi_data_digest data_digest; + /// Always 0x3F according to iSCSI specification. + uint8_t opcode; + + /// Reserved for future usage (must be always 0x80 for now). + int8_t flags; + + /** + * @brief Reject reason. + * + * In all the cases in which a pre-instantiated SCSI task is terminated + * because of the reject, the target MUST issue a proper SCSI command + * response with CHECK CONDITION. In these cases in which a status for + * the SCSI task was already sent before the reject, no additional + * status is required. If the error is detected while data from the + * initiator is still expected (i.e., the command PDU did not contain + * all the data and the target has not received a Data-Out PDU with the + * Final bit set to 1 for the unsolicited data, if any, and all + * outstanding R2Ts, if any), the target MUST wait until it receives + * the last expected Data-Out PDUs with the F bit set to 1 before + * sending the Response PDU. + */ + uint8_t reason; + + /// Reserved for future usage, always MUST be 0. + uint8_t reserved; + + /// TotalAHSLength. + uint8_t total_ahs_len; + + /// DataSegmentLength. + uint8_t ds_len[3]; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved2; + + /// Always 0xFFFFFFFF for now. + uint32_t tag; + + /// Reserved for future usage, always MUST be 0. + uint32_t reserved3; + + /** + * @brief StatSN. + * + * This field carries its usual value and is not related to the + * rejected command. The StatSN is advanced after a Reject. + */ + uint32_t stat_sn; + + /** + * @brief ExpCmdSN. + * + * This field carries its usual value and is not related to the + * rejected command. + */ + uint32_t exp_cmd_sn; + + /** + * @brief MaxCmdSN. + * + * This field carries its usual value and is not related to the + * rejected command. + */ + uint32_t max_cmd_sn; + + /** + * @brief DataSN / Ready To Transfer Sequence Number (R2TSN) or Reserved. + * + * This field is only valid if the rejected PDU is a Data/R2T SNACK and + * the Reject reason code is "Protocol Error". The DataSN/R2TSN is the + * next Data/R2T sequence number that the target would send for the + * task, if any. + */ + uint32_t data_r2t_sn; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved4; + + /** + * @brief Complete Header of Bad PDU. + * + * The target returns the header (not including the digest) of the + * PDU in error as the data of the response. + */ + iscsi_bhs_packet bad_pdu_hdr; } iscsi_reject_packet; /** @@ -7384,76 +5280,76 @@ typedef struct __attribute__((packed)) iscsi_reject_packet { * in response to each other. */ typedef struct __attribute__((packed)) iscsi_nop_out_packet { - /// Always 0x00 according to iSCSI specification. - uint8_t opcode; - - /// Reserved for future usage (must be always 0x80 for now). - int8_t flags; - - /// Reserved for future usage, always MUST be 0. - uint16_t reserved; - - /// TotalAHSLength. - uint8_t total_ahs_len; - - /// DataSegmentLength. - uint8_t ds_len[3]; - - /// LUN or Reserved. - uint64_t lun; - - /** - * @brief Initiator Task Tag (ITT). - * - * The NOP-Out MUST have the Initiator Task Tag set to a valid value - * only if a response in the form of a NOP-In is requested (i.e., the - * NOP-Out is used as a ping request). Otherwise, the Initiator Task - * Tag MUST be set to 0xFFFFFFFF.\n - * When a target receives the NOP-Out with a valid Initiator Task Tag, - * it MUST respond with a NOP-In Response.\n - * If the Initiator Task Tag contains 0xFFFFFFFF, the I bit MUST be set - * to 1, and the CmdSN is not advanced after this PDU is sent. - */ - uint32_t init_task_tag; - - /** - * @brief Target Transfer Tag (TTT). - * - * The Target Transfer Tag is a target-assigned identifier for the - * operation.\n - * The NOP-Out MUST only have the Target Transfer Tag set if it is - * issued in response to a NOP-In with a valid Target Transfer Tag. In - * this case, it copies the Target Transfer Tag from the NOP-In PDU.\n - * Otherwise, the Target Transfer Tag MUST be set to 0xFFFFFFFF.\n - * When the Target Transfer Tag is set to a value other than 0xFFFFFFFF, - * the LUN field MUST also be copied from the NOP-In. - */ - uint32_t target_xfer_tag; - - /// CmdSN. - uint32_t cmd_sn; - - /// ExpStatSN. - uint32_t exp_stat_sn; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved2[2]; - - /// Optional header digest. - iscsi_header_digest hdr_digest; - - /** - * @brief DataSegment - Ping Data (optional). - * - * Ping data is reflected in the NOP-In Response. The length of the - * reflected data is limited to MaxRecvDataSegmentLength. The length of - * ping data is indicated by the DataSegmentLength. 0 is a valid value - * for the DataSegmentLength and indicates the absence of ping data. - */ - iscsi_scsi_ds_cmd_data ds_ping_data; - - /// Optional data digest. - iscsi_data_digest data_digest; + /// Always 0x00 according to iSCSI specification. + uint8_t opcode; + + /// Reserved for future usage (must be always 0x80 for now). + int8_t flags; + + /// Reserved for future usage, always MUST be 0. + uint16_t reserved; + + /// TotalAHSLength. + uint8_t total_ahs_len; + + /// DataSegmentLength. + uint8_t ds_len[3]; + + /// LUN or Reserved. + uint64_t lun; + + /** + * @brief Initiator Task Tag (ITT). + * + * The NOP-Out MUST have the Initiator Task Tag set to a valid value + * only if a response in the form of a NOP-In is requested (i.e., the + * NOP-Out is used as a ping request). Otherwise, the Initiator Task + * Tag MUST be set to 0xFFFFFFFF.\n + * When a target receives the NOP-Out with a valid Initiator Task Tag, + * it MUST respond with a NOP-In Response.\n + * If the Initiator Task Tag contains 0xFFFFFFFF, the I bit MUST be set + * to 1, and the CmdSN is not advanced after this PDU is sent. + */ + uint32_t init_task_tag; + + /** + * @brief Target Transfer Tag (TTT). + * + * The Target Transfer Tag is a target-assigned identifier for the + * operation.\n + * The NOP-Out MUST only have the Target Transfer Tag set if it is + * issued in response to a NOP-In with a valid Target Transfer Tag. In + * this case, it copies the Target Transfer Tag from the NOP-In PDU.\n + * Otherwise, the Target Transfer Tag MUST be set to 0xFFFFFFFF.\n + * When the Target Transfer Tag is set to a value other than 0xFFFFFFFF, + * the LUN field MUST also be copied from the NOP-In. + */ + uint32_t target_xfer_tag; + + /// CmdSN. + uint32_t cmd_sn; + + /// ExpStatSN. + uint32_t exp_stat_sn; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved2[2]; + + /// Optional header digest. + uint32_t hdr_digest; + + /** + * @brief DataSegment - Ping Data (optional). + * + * Ping data is reflected in the NOP-In Response. The length of the + * reflected data is limited to MaxRecvDataSegmentLength. The length of + * ping data is indicated by the DataSegmentLength. 0 is a valid value + * for the DataSegmentLength and indicates the absence of ping data. + */ + iscsi_scsi_ds_cmd_data ds_ping_data; + + /// Optional data digest. + uint32_t data_digest; } iscsi_nop_out_packet; @@ -7482,70 +5378,70 @@ typedef struct __attribute__((packed)) iscsi_nop_out_packet { * (DataSegmentLength MUST be 0). */ typedef struct __attribute__((packed)) iscsi_nop_in_packet { - /// Always 0x20 according to iSCSI specification. - uint8_t opcode; - - /// Reserved for future usage (must be always 0x80 for now). - int8_t flags; - - /// Reserved for future usage, always MUST be 0. - uint16_t reserved; - - /// TotalAHSLength - uint8_t total_ahs_len; - - /// DataSegmentLength. - uint8_t ds_len[3]; - - /// A LUN MUST be set to a correct value when the Target Transfer Tag is valid (not the reserved value 0xFFFFFFFF). - uint64_t lun; - - /// Initiator Task Tag (ITT) or 0xFFFFFFFF. - uint32_t init_task_tag; - - /** - * @brief Target Transfer Tag (TTT). - * - * If the target is responding to a NOP-Out, this field is set to the - * reserved value 0xFFFFFFFF.\n - * If the target is sending a NOP-In as a ping (intending to receive a - * corresponding NOP-Out), this field is set to a valid value (not the - * reserved value 0xFFFFFFFF).\n - * If the target is initiating a NOP-In without wanting to receive a - * corresponding NOP-Out, this field MUST hold the reserved value - * 0xFFFFFFFF. - */ - uint32_t target_xfer_tag; - - /** - * @brief StatSN. - * - * The StatSN field will always contain the next StatSN. However, when - * the Initiator Task Tag is set to 0xFFFFFFFF, the StatSN for the - * connection is not advanced after this PDU is sent. - */ - uint32_t stat_sn; - - /// ExpCmdSN. - uint32_t exp_cmd_sn; // ExpCmdSN - - /// MaxCmdSN. - uint32_t max_cmd_sn; - - /// Reserved for future usage, always MUST be 0. - uint32_t reserved2; - - /// Reserved for future usage, always MUST be 0. - uint64_t reserved3; - - /// Optional header digest. - iscsi_header_digest hdr_digest; - - /// DataSegment - Return Ping Data. - iscsi_scsi_ds_cmd_data ds_ping_data; - - /// Optional data digest. - iscsi_data_digest data_digest; + /// Always 0x20 according to iSCSI specification. + uint8_t opcode; + + /// Reserved for future usage (must be always 0x80 for now). + int8_t flags; + + /// Reserved for future usage, always MUST be 0. + uint16_t reserved; + + /// TotalAHSLength + uint8_t total_ahs_len; + + /// DataSegmentLength. + uint8_t ds_len[3]; + + /// A LUN MUST be set to a correct value when the Target Transfer Tag is valid (not the reserved value 0xFFFFFFFF). + uint64_t lun; + + /// Initiator Task Tag (ITT) or 0xFFFFFFFF. + uint32_t init_task_tag; + + /** + * @brief Target Transfer Tag (TTT). + * + * If the target is responding to a NOP-Out, this field is set to the + * reserved value 0xFFFFFFFF.\n + * If the target is sending a NOP-In as a ping (intending to receive a + * corresponding NOP-Out), this field is set to a valid value (not the + * reserved value 0xFFFFFFFF).\n + * If the target is initiating a NOP-In without wanting to receive a + * corresponding NOP-Out, this field MUST hold the reserved value + * 0xFFFFFFFF. + */ + uint32_t target_xfer_tag; + + /** + * @brief StatSN. + * + * The StatSN field will always contain the next StatSN. However, when + * the Initiator Task Tag is set to 0xFFFFFFFF, the StatSN for the + * connection is not advanced after this PDU is sent. + */ + uint32_t stat_sn; + + /// ExpCmdSN. + uint32_t exp_cmd_sn; // ExpCmdSN + + /// MaxCmdSN. + uint32_t max_cmd_sn; + + /// Reserved for future usage, always MUST be 0. + uint32_t reserved2; + + /// Reserved for future usage, always MUST be 0. + uint64_t reserved3; + + /// Optional header digest. + uint32_t hdr_digest; + + /// DataSegment - Return Ping Data. + iscsi_scsi_ds_cmd_data ds_ping_data; + + /// Optional data digest. + uint32_t data_digest; } iscsi_nop_in_packet; @@ -7593,17 +5489,17 @@ typedef struct __attribute__((packed)) iscsi_nop_in_packet { * identifier data. */ typedef struct __attribute__((packed)) iscsi_transport_id { - /// First 4 bits are protocol ID and last 2 bits are format. - uint8_t id; + /// First 4 bits are protocol ID and last 2 bits are format. + uint8_t id; - /// Reserved for future usage (always MUST be 0). - uint8_t reserved; + /// Reserved for future usage (always MUST be 0). + uint8_t reserved; - /// Additional length of name. - uint16_t add_len; + /// Additional length of name. + uint16_t add_len; - /// Name. - uint8_t name[0]; + /// Name. + uint8_t name[0]; } iscsi_transport_id; @@ -7683,20 +5579,20 @@ typedef struct __attribute__((packed)) iscsi_transport_id { * and the iSCSI connection lookup table. */ typedef struct iscsi_key_value_pair_lut_entry { - /// Name of key. - const uint8_t *key; + /// Name of key. + const uint8_t *key; - /// Default value of the key, always in string representation. - uint8_t *value; + /// Default value of the key, always in string representation. + uint8_t *value; - /// NUL separated list of allowed string values. If key type is numeric: NUL separated minimum and maximum integer range. End is marked with another NUL. - uint8_t *list_range; + /// NUL separated list of allowed string values. If key type is numeric: NUL separated minimum and maximum integer range. End is marked with another NUL. + uint8_t *list_range; - /// Type of key and value pair. - const int type; + /// Type of key and value pair. + const int type; - /// Flags indicating special key attributes. - const int flags; + /// Flags indicating special key attributes. + const int flags; } iscsi_key_value_pair_lut_entry; @@ -7708,19 +5604,19 @@ typedef struct iscsi_key_value_pair_lut_entry { * Text or Login packet data. */ typedef struct iscsi_key_value_pair { - /// Value of the key which is stored in the hash map. + /// Value of the key which is stored in the hash map. uint8_t *value; - /// NUL separated list of allowed string values. If key type is numeric: NUL separated minimum and maximum integer range. End is marked with another NUL. - uint8_t *list_range; + /// NUL separated list of allowed string values. If key type is numeric: NUL separated minimum and maximum integer range. End is marked with another NUL. + uint8_t *list_range; - /// Type of key and value pair. - int type; + /// Type of key and value pair. + int type; - /// Flags indicating special key attributes. - int flags; + /// Flags indicating special key attributes. + int flags; - /// State bit mask. + /// State bit mask. uint state_mask; } iscsi_key_value_pair; @@ -7733,20 +5629,20 @@ typedef struct iscsi_connection iscsi_connection; * pairs for sending as DataSegment packet data to the client. */ typedef struct iscsi_key_value_pair_packet { - /// Associated iSCSI connection. - iscsi_connection *conn; + /// Associated iSCSI connection. + iscsi_connection *conn; - /// Current text buffer containing multiple key=value + NUL terminator pairs. - uint8_t *buf; + /// Current text buffer containing multiple key=value + NUL terminator pairs. + uint8_t *buf; - /// Position of output buffer for next write. - uint32_t pos; + /// Position of output buffer for next write. + uint32_t pos; - /// Current length of buffer including final NUL terminator without iSCSI zero padding. - uint32_t len; + /// Current length of buffer including final NUL terminator without iSCSI zero padding. + uint32_t len; - /// Discovery mode. - int discovery; + /// Discovery mode. + int discovery; } iscsi_key_value_pair_packet; /// iSCSI main global data flags: Allow duplicate ISIDs. @@ -7989,47 +5885,41 @@ typedef struct iscsi_scsi_lun iscsi_scsi_lun; * layer task management. */ typedef struct iscsi_scsi_task { - /// Connection associated with this task. - iscsi_connection *connection; - - /// SCSI Command Descriptor Block (CDB). - iscsi_scsi_cdb *cdb; + /// Connection associated with this task. + iscsi_connection *connection; - /// SCSI sense data. - iscsi_scsi_sense_data_packet *sense_data; + /// SCSI Command Descriptor Block (CDB). + iscsi_scsi_cdb *cdb; - /// Output buffer. - uint8_t *buf; + /// SCSI sense data. + iscsi_scsi_sense_data_packet *sense_data; - /// Position of buffer in bytes. - uint32_t pos; + /// Output buffer. + uint8_t *buf; - /// Length of buffer in bytes. - uint32_t len; + /// Position of buffer in bytes. + uint32_t pos; - /// Unique identifier for this task. - uint64_t id; + /// Length of buffer in bytes. + uint32_t len; - /// Flags. - int flags; + /// Unique identifier for this task. + uint64_t id; - /// Transfer position in bytes. - uint32_t xfer_pos; + /// Flags. + int flags; - /// Transfer length in bytes. - uint32_t xfer_len; + /// Transfer position in bytes. + uint32_t xfer_pos; - /// Sense data length. - uint8_t sense_data_len; + /// Transfer length in bytes. + uint32_t xfer_len; - /// iSCSI SCSI status code. - uint8_t status; + /// Sense data length. + uint8_t sense_data_len; - /// Task management function. - uint8_t task_mgmt_func; - - /// Task management response code. - uint8_t task_mgmt_response; + /// iSCSI SCSI status code. + uint8_t status; /// Uplink read mutex for sync pthread_mutex_t uplink_mutex; @@ -8039,18 +5929,14 @@ typedef struct iscsi_scsi_task { } iscsi_scsi_task; -/// iSCSI SCSI emulation physical block size in bits. -#define ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE_BITS 12UL - /// iSCSI SCSI emulation physical block size in bytes. -#define ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE (1UL << ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE_BITS) - - -/// iSCSI SCSI emulation logical block size in bits. -#define ISCSI_SCSI_EMU_BLOCK_SIZE_BITS 9UL +#define ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE DNBD3_BLOCK_SIZE /// iSCSI SCSI emulation logical block size in bytes. -#define ISCSI_SCSI_EMU_BLOCK_SIZE (1UL << ISCSI_SCSI_EMU_BLOCK_SIZE_BITS) +#define ISCSI_SCSI_EMU_BLOCK_SIZE (512) + +/// Block shift difference between dnbd3 (4k) and iSCSI (512b) +#define ISCSI_SCSI_EMU_BLOCK_DIFF_SHIFT (3) /// iSCSI SCSI emulation I/O type: Removable. #define ISCSI_SCSI_EMU_IO_TYPE_REMOVABLE (1 << 0) @@ -8067,9 +5953,6 @@ typedef struct iscsi_scsi_task { /// iSCSI SCSI emulation I/O type: Device is (temporarily) write protected. #define ISCSI_SCSI_EMU_IO_TYPE_WRITE_PROTECT (1 << 4) -/// iSCSI SCSI emulation I/O type: Write cache available. -#define ISCSI_SCSI_EMU_IO_TYPE_WRITE_CACHE (1 << 5) - /// iSCSI SCSI emulation block flags: Write operation. #define ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE (1 << 0) @@ -8086,51 +5969,6 @@ typedef struct iscsi_scsi_task { #define ISCSI_TARGET_NODE_MAX_NAME_LEN 223U -/// iSCSI target node flags: CHAP authentication disabled. -#define ISCSI_TARGET_NODE_FLAGS_CHAP_DISABLE (1 << 0) - -/// iSCSI target node flags: CHAP authentication required. -#define ISCSI_TARGET_NODE_FLAGS_CHAP_REQUIRE (1 << 1) - -/// iSCSI target node flags: CHAP authentication mutual. -#define ISCSI_TARGET_NODE_FLAGS_CHAP_MUTUAL (1 << 2) - -/// iSCSI target node flags: Destroyed. -#define ISCSI_TARGET_NODE_FLAGS_DESTROYED (1 << 3) - - -/// iSCSI session flags: Initial ready to transfer. -#define ISCSI_SESSION_FLAGS_INIT_R2T (1 << 0) - -/// iSCSI session flags: Data PDU in order. -#define ISCSI_SESSION_FLAGS_DATA_PDU_IN_ORDER (1 << 2) - -/// iSCSI session flags: Data sequence in order. -#define ISCSI_SESSION_FLAGS_DATA_SEQ_IN_ORDER (1 << 3) - - -/// iSCSI session: Default maximum number of connections. -#define ISCSI_SESSION_DEFAULT_MAX_CONNECTIONS 2UL - -/// iSCSI session: Default maximum number of outstanding ready to transfers. -#define ISCSI_SESSION_DEFAULT_MAX_OUTSTANDING_R2T 1UL - -/// iSCSI session: Default time to wait in seconds. -#define ISCSI_SESSION_DEFAULT_TIME_TO_WAIT 2UL - -/// iSCSI session: Default time to retain in seconds. -#define ISCSI_SESSION_DEFAULT_TIME_TO_RETAIN 20UL - -/// iSCSI session: First burst length in bytes. -#define ISCSI_SESSION_DEFAULT_FIRST_BURST_LEN ISCSI_DEFAULT_RECV_DS_LEN - -/// iSCSI session: Maximum burst length in bytes. -#define ISCSI_SESSION_DEFAULT_MAX_BURST_LEN (ISCSI_DEFAULT_MAX_RECV_DS_LEN * ISCSI_DEFAULT_MAX_DATA_OUT_PER_CONNECTION) - -/// iSCSI session: Default error recovery level. -#define ISCSI_SESSION_DEFAULT_ERR_RECOVERY_LEVEL 0UL - - /// iSCSI session type: Invalid. #define ISCSI_SESSION_TYPE_INVALID 0 @@ -8155,9 +5993,31 @@ typedef struct iscsi_login_kvp // Maximum unsolicited burst length client can receive. int FirstBurstLength; - /// Desired auth method + /// Maximum number of connections. + int MaxConnections; + + /// Error recovery level. + int ErrorRecoveryLevel; + + /// The session type (Discovery, Normal). + const char *SessionType; + + /// Desired auth method. const char *AuthMethod; -} iscsi_login_kvp; + + /// SendTargets command. + const char *SendTargets; + + /// HeaderDigest requested by client. + const char *HeaderDigest; + + /// DataDigest requested by client. + const char *DataDigest; + + const char *InitiatorName; + + const char *TargetName; +} iscsi_negotiation_kvp; /** * Options/limits the client told us that @@ -8183,29 +6043,29 @@ typedef struct iscsi_session_options * login phase. */ typedef struct iscsi_session { - /// Initiator Session ID (ISID). - uint64_t isid; + /// Initiator Session ID (ISID). + uint64_t isid; - /// Target Session Identifying Handle (TSIH). - uint64_t tsih; + /// Target Session Identifying Handle (TSIH). + uint64_t tsih; - /// Flags (extracted from key and value pairs). - int flags; + /// Flags (extracted from key and value pairs). + int flags; - /// iSCSI session type. - int type; + /// iSCSI session type. + int type; - /// ExpCmdSN. - uint32_t exp_cmd_sn; + /// ExpCmdSN. + uint32_t exp_cmd_sn; - /// MaxCmdSN. - uint32_t max_cmd_sn; + /// MaxCmdSN. + uint32_t max_cmd_sn; - /// Current text Initiator Task Tag (ITT). - uint32_t current_text_init_task_tag; + /// Current text Initiator Task Tag (ITT). + uint32_t current_text_init_task_tag; - /// Session options client sent in login request. - iscsi_session_options opts; + /// Session options client sent in login request. + iscsi_session_options opts; } iscsi_session; @@ -8298,83 +6158,56 @@ typedef struct iscsi_pdu iscsi_pdu; * and iSCSI portals. */ typedef struct iscsi_connection { - /// iSCSI session associated with this connection. - iscsi_session *session; - - /// Temporarily storage for partially received login parameter. - uint8_t *partial_pairs; - - /// Temporarily storage for partially received text parameter. - uint8_t *text_partial_pairs; + /// iSCSI session associated with this connection. + iscsi_session *session; /// Associated dnbd3 client dnbd3_client_t *client; - /// Current PDU being processed. - iscsi_pdu *pdu_processing; - - /// Login response PDU. - iscsi_pdu *login_response_pdu; + /// Current PDU being processed. + iscsi_pdu *pdu_processing; - /// iSCSI SendTargets total number of bytes completed. - uint target_send_total_size; + /// Login response PDU. + iscsi_pdu *login_response_pdu; - /// iSCSI SCSI Data In count. - uint scsi_data_in_cnt; + /// Internal connection identifier + int id; - /// iSCSI SCSI Data Out count. - uint scsi_data_out_cnt; + /// iSCSI connection receiving state. + int pdu_recv_state; - /// iSCSI tasks pending count. - uint task_cnt; + /// iSCSI connection flags. + int flags; - /// iSCSI connection contains a header digest (CRC32), always MUST be 0 or 4 for now. - int header_digest; + /// iSCSI connection state. + int state; - /// iSCSI connection contains a data digest (CRC32), always MUST be 0 or 4 for now. - int data_digest; + /// iSCSI connection login phase. + int login_phase; - /// Internal connection identifier (key of iSCSI global vector hash map). - int id; + /// Initiator Session ID (ISID). + iscsi_isid isid; - /// iSCSI connection receiving state. - int pdu_recv_state; + /// Target Session Identifying Handle (TSIH). + uint16_t tsih; - /// iSCSI connection flags. - int flags; + /// Connection ID (CID). + uint16_t cid; - /// iSCSI connection state. - int state; + /// Bit mask for connection state key negotiation. + uint16_t state_negotiated; - /// iSCSI connection login phase. - int login_phase; + /// Bit mask for session state key negotiation. + uint32_t session_state_negotiated; - /// Initiator Session ID (ISID). - iscsi_isid isid; + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; - /// Target Session Identifying Handle (TSIH). - uint16_t tsih; + /// Targer Transfer Tag (TTT). + uint32_t target_xfer_tag; - /// Connection ID (CID). - uint16_t cid; - - /// Bit mask for connection state key negotiation. - uint16_t state_negotiated; - - /// Bit mask for session state key negotiation. - uint32_t session_state_negotiated; - - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; - - /// Targer Transfer Tag (TTT). - uint32_t target_xfer_tag; - - /// StatSN. - uint32_t stat_sn; - - /// ExpStatSN. - uint32_t exp_stat_sn; + /// StatSN. + uint32_t stat_sn; } iscsi_connection; @@ -8393,62 +6226,38 @@ typedef struct iscsi_task iscsi_task; * and filling the BHS, AHS and DS properly. */ typedef struct iscsi_pdu { - /// iSCSI Basic Header Segment (BHS) packet data. - iscsi_bhs_packet *bhs_pkt; - - /// iSCSI Advanced Header Segment (AHS) packet data for fast access and is straight after BHS packet in memory. - iscsi_ahs_packet *ahs_pkt; - - /// Header digest (CRC32C) packet data for fast access and is straight after BHS and AHS packet in memory. - iscsi_header_digest *header_digest; - - /// iSCSI DataSegment (DS) packet data for fast access and is straight after BHS, AHS and header digest packet in memory. - iscsi_scsi_ds_cmd_data *ds_cmd_data; + /// iSCSI Basic Header Segment (BHS) packet data. + iscsi_bhs_packet *bhs_pkt; - /// Data digest (CRC32C) packet data for fast access and is straight after BHS, AHS, header digest and DataSegment packet in memory. - iscsi_data_digest *data_digest; + /// iSCSI Advanced Header Segment (AHS) packet data for fast access and is straight after BHS packet in memory. + iscsi_ahs_packet *ahs_pkt; - /// iSCSI task handling this PDU. - iscsi_task *task; + /// iSCSI DataSegment (DS) packet data for fast access and is straight after BHS, AHS and header digest packet in memory. + iscsi_scsi_ds_cmd_data *ds_cmd_data; - /// Flags. - int flags; + /// iSCSI task handling this PDU. + iscsi_task *task; - /// Bytes of Basic Header Segment (BHS) already read. - uint bhs_pos; + /// Flags. + int flags; - /// Bytes of Advanced Header Segment (AHS) already read. - uint ahs_pos; + /// Bytes of Basic Header Segment (BHS) already read. + uint bhs_pos; - /// AHSLength. - uint ahs_len; + /// AHSLength. + uint ahs_len; - /// Bytes of header digest (CRC32C) already read. - uint header_digest_pos; + /// DataSegmentLength. + uint32_t ds_len; - /// Header digest size (always 0 or 4 for now). - int header_digest_size; + /// DS Buffer write pos when filling buffer for sending. + uint32_t ds_write_pos; - /// DataSegmentLength. - uint32_t ds_len; + /// Read position in AHS + DS buffer (recv). + uint32_t recv_pos; - /// Position of DataSegment buffer for next operation. - uint32_t pos; - - /// Allocated DataSegment buffer length. - uint32_t len; - - /// Bytes of data digest (CRC32C) already read. - uint data_digest_pos; - - /// Data digest size (always 0 or 4 for now). - int data_digest_size; - - /// Tasks referenced by this PDU counter. - uint task_ref_cnt; - - /// CmdSN. - uint32_t cmd_sn; + /// CmdSN. + uint32_t cmd_sn; } iscsi_pdu; @@ -8466,52 +6275,43 @@ typedef struct iscsi_pdu { * including the underlying SCSI layer. */ typedef struct iscsi_task { - /// Underlying SCSI task structure. - iscsi_scsi_task scsi_task; + /// Underlying SCSI task structure. + iscsi_scsi_task scsi_task; - /// Associated iSCSI connection. - iscsi_connection *conn; + /// Associated iSCSI connection. + iscsi_connection *conn; - /// Buffer position in bytes. - uint32_t pos; + /// Buffer position in bytes. + uint32_t pos; - /// Buffer length in bytes. - uint32_t len; + /// Buffer length in bytes. + uint32_t len; - /// Unique identifier for this task. - uint64_t id; + /// Unique identifier for this task. + uint64_t id; - /// Flags. - int flags; + /// Flags. + int flags; - /// LUN identifier associated with this task (always MUST be between 0 and 7), used for hot removal tracking. - int lun_id; + /// LUN identifier associated with this task (always MUST be between 0 and 7), used for hot removal tracking. + int lun_id; - /// Initiator Task Tag (ITT). - uint32_t init_task_tag; + /// Initiator Task Tag (ITT). + uint32_t init_task_tag; - /// Target Transfer Tag (TTT). - uint32_t target_xfer_tag; + /// Target Transfer Tag (TTT). + uint32_t target_xfer_tag; - /// Desired number of bytes completed. - uint32_t des_data_xfer_pos; + /// Desired number of bytes completed. + uint32_t des_data_xfer_pos; - /// Desired data transfer length. - uint32_t des_data_xfer_len; + /// Desired data transfer length. + uint32_t des_data_xfer_len; - /// SCSI Data In Data Sequence Number (DataSN). - uint32_t data_sn; - - /// SCSI Data Out count. - uint32_t scsi_data_out_cnt; + /// SCSI Data In Data Sequence Number (DataSN). + uint32_t data_sn; } iscsi_task; -int iscsi_create(void); // Allocates and initializes the iSCSI global vector structure -void iscsi_destroy(void); // Deallocates all resources acquired by iscsi_create void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *request, const int len); // Handles an iSCSI connection until connection is closed -#ifdef __cplusplus -} -#endif - #endif /* DNBD3_ISCSI_H_ */ diff --git a/src/server/net.c b/src/server/net.c index 41caa96..fcbe9fb 100644 --- a/src/server/net.c +++ b/src/server/net.c @@ -33,6 +33,7 @@ #include <dnbd3/shared/serialize.h> #include <assert.h> +#include <netinet/tcp.h> #ifdef __linux__ #include <sys/sendfile.h> @@ -174,6 +175,21 @@ void* net_handleNewConnection(void *clientPtr) // Await data from client. Since this is a fresh connection, we expect data right away sock_setTimeout( client->sock, _clientTimeout ); + // NODELAY makes sense since we're sending a lot of data + int e2 = 1; + socklen_t optlen = sizeof(e2); + setsockopt( client->sock, IPPROTO_TCP, TCP_NODELAY, (void *)&e2, optlen ); + // Also increase send buffer + if ( getsockopt( client->sock, SOL_SOCKET, SO_SNDBUF, (void *)&e2, &optlen ) == 0 ) { +#ifdef __linux__ + // Linux doubles the value to account for overhead, get "real" value + e2 /= 2; +#endif + if ( e2 < SERVER_TCP_BUFFER_MIN_SIZE_PAYLOAD ) { + e2 = SERVER_TCP_BUFFER_MIN_SIZE_PAYLOAD; + setsockopt( client->sock, SOL_SOCKET, SO_SNDBUF, &e2, sizeof(e2) ); + } + } do { #ifdef DNBD3_SERVER_AFL const int ret = (int)recv( 0, &request, sizeof(request), MSG_WAITALL ); diff --git a/src/server/sendfile.c b/src/server/sendfile.c new file mode 100644 index 0000000..9e27238 --- /dev/null +++ b/src/server/sendfile.c @@ -0,0 +1,60 @@ +#include "sendfile.h" + +#if defined(__linux__) +#include <sys/sendfile.h> +#elif defined(__FreeBSD__) +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#else +#error "What platform is this?" +#endif + +#include <errno.h> + +bool sendfile_all(const int fd, const int sock, off_t foffset, const size_t bytes) +{ + if ( bytes == 0 ) + return true; +#ifdef DNBD3_SERVER_AFL + errno = 0; + return true; +#elif defined(__linux__) + size_t done = 0; + int againCount = 0; + + while ( done < bytes ) { + const ssize_t sent = sendfile( sock, fd, &foffset, bytes - done ); + if ( sent == 0 ) // Probably EOF, like with send(), but manpage is not clear :-/ + return false; + if ( sent < 0 ) { + if ( errno == EAGAIN || errno == EINTR ) { + // Retry once, but give up otherwise - EAGAIN might just be the send timeout + if ( ++againCount > 1 ) + return false; + continue; + } + return false; + } + done += sent; + } +#elif defined(__FreeBSD__) + off_t sent; + size_t done = 0; + int againCount = 0; + + while ( done < bytes ) { + const int ret = sendfile( fd, sock, foffset + done, bytes - done, NULL, &sent, 0 ); + if ( ret == 0 || errno == EAGAIN || errno == EINTR ) { + // Retry once, but give up otherwise - EAGAIN might just be the send timeout + if ( sent == 0 && ++againCount > 1 ) + return false; + done += sent; + continue; + } + // Something else went wrong + return false; + } +#endif + return true; +}
\ No newline at end of file diff --git a/src/server/sendfile.h b/src/server/sendfile.h new file mode 100644 index 0000000..e4cc5b7 --- /dev/null +++ b/src/server/sendfile.h @@ -0,0 +1,18 @@ +#ifndef SENDFILE_H_ +#define SENDFILE_H_ + +#include <stdbool.h> +#include <stddef.h> +#include <sys/types.h> + +/** + * Platform-agnostic wrapper around sendfile, with retry logic. + * @param fd file to read from + * @param sock socket to write to + * @param foffset offset in file to start reading from + * @param bytes number of bytes to read/send + * @return true on success + */ +bool sendfile_all(int fd, int sock, off_t foffset, size_t bytes); + +#endif
\ No newline at end of file diff --git a/src/server/server.c b/src/server/server.c index bfda12d..b91e4ce 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -27,7 +27,6 @@ #include "net.h" #include "altservers.h" #include "integrity.h" -#include "iscsi.h" #include "threadpool.h" #include "rpc.h" #include "fuse.h" @@ -177,9 +176,6 @@ _Noreturn static void dnbd3_cleanup() threadpool_waitEmpty(); - // Destroy iSCSI global vector - iscsi_destroy(); - // Clean up images retries = 5; while ( !image_tryFreeAll() && --retries > 0 ) { @@ -370,9 +366,6 @@ int main(int argc, char *argv[]) integrity_init(); net_init(); - if ( iscsi_create() < 0 ) - return EXIT_FAILURE; - uplink_globalsInit(); rpc_init(); if ( mountDir != NULL && !dfuse_init( "-oallow_other", mountDir ) ) { |
