diff options
| author | Sebastian Vater | 2025-09-05 15:01:47 +0200 |
|---|---|---|
| committer | Sebastian Vater | 2025-09-05 15:01:47 +0200 |
| commit | 13aa3dbfe2e6e8aaf4e8597f15555473d19dd6a3 (patch) | |
| tree | 24dd06c1856dabd77727f460608a304629648278 | |
| parent | Implemented basic iSCSI SCSI Persistent Reservation (PR) handling and checkin... (diff) | |
| download | dnbd3-13aa3dbfe2e6e8aaf4e8597f15555473d19dd6a3.tar.gz dnbd3-13aa3dbfe2e6e8aaf4e8597f15555473d19dd6a3.tar.xz dnbd3-13aa3dbfe2e6e8aaf4e8597f15555473d19dd6a3.zip | |
iSCSI SCSI emulation for DNBD3 started and most block based operations finished, also some bug fixes. Finally, some code refactoring again.
| -rw-r--r-- | src/server/iscsi.c | 681 | ||||
| -rw-r--r-- | src/server/iscsi.h | 498 |
2 files changed, 1052 insertions, 127 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c index 49a99e3..cc1c7a5 100644 --- a/src/server/iscsi.c +++ b/src/server/iscsi.c @@ -113,36 +113,26 @@ static const iscsi_key_value_pair_lut_entry iscsi_session_key_value_pair_lut[] = static int iscsi_global_key_value_pair_init(iscsi_hashmap *key_value_pairs, const iscsi_key_value_pair_lut_entry *lut) { for ( uint i = 0; lut[i].key != NULL; i++ ) { - const uint key_len = (uint) strlen( (char *) lut[i].key ) + 1UL; - uint8_t *hash_key = iscsi_hashmap_key_create( lut[i].key, key_len ); - - if ( hash_key == NULL ) { - logadd( LOG_ERROR, "iscsi_global_key_value_pair_init: Out of memory allocating key" ); - - return -1L; - } - iscsi_key_value_pair *key_value_pair = (iscsi_key_value_pair *) malloc( sizeof(struct iscsi_key_value_pair) ); if ( key_value_pair == NULL ) { logadd( LOG_ERROR, "iscsi_global_key_value_pair_init: Out of memory allocating key value pair" ); - iscsi_hashmap_key_destroy( hash_key ); - return -1L; } + const uint key_len = (uint) strlen( (char *) lut[i].key ) + 1UL; + key_value_pair->value = lut[i].value; key_value_pair->list_range = lut[i].list_range; key_value_pair->type = lut[i].type; key_value_pair->flags = lut[i].flags; key_value_pair->state_mask = (1UL << i); - const int rc = iscsi_hashmap_put( key_value_pairs, hash_key, key_len, (uint8_t *) key_value_pair ); + const int rc = iscsi_hashmap_put( key_value_pairs, (uint8_t *) lut[i].key, key_len, (uint8_t *) key_value_pair ); if ( rc < 0 ) { free( key_value_pair ); - iscsi_hashmap_key_destroy( hash_key ); return rc; } @@ -240,7 +230,7 @@ int iscsi_create() if ( globvec->connection_key_value_pairs == NULL ) { logadd( LOG_ERROR, "iscsi_create: Out of memory while initializing iSCSI global vector session key and value pairs hash map" ); - iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->session_key_value_pairs ); iscsi_hashmap_destroy( globvec->sessions ); iscsi_hashmap_destroy( globvec->target_nodes ); @@ -256,7 +246,7 @@ int iscsi_create() if ( globvec->connections == NULL ) { logadd( LOG_ERROR, "iscsi_create: Out of memory while allocating iSCSI global vector connections hash map" ); - iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->session_key_value_pairs ); iscsi_hashmap_destroy( globvec->sessions ); iscsi_hashmap_destroy( globvec->target_nodes ); @@ -273,7 +263,7 @@ int iscsi_create() logadd( LOG_ERROR, "iscsi_create: Out of memory while allocating iSCSI global vector connection key and value pairs hash map" ); iscsi_hashmap_destroy( globvec->connections ); - iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->session_key_value_pairs ); iscsi_hashmap_destroy( globvec->sessions ); iscsi_hashmap_destroy( globvec->target_nodes ); @@ -289,10 +279,10 @@ int iscsi_create() if ( rc < 0 ) { logadd( LOG_ERROR, "iscsi_create: Out of memory while initializing iSCSI global vector connection key and value pairs hash map" ); - iscsi_hashmap_iterate( globvec->connection_key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_iterate( globvec->connection_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->connection_key_value_pairs ); iscsi_hashmap_destroy( globvec->connections ); - iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->session_key_value_pairs ); iscsi_hashmap_destroy( globvec->sessions ); iscsi_hashmap_destroy( globvec->target_nodes ); @@ -331,14 +321,14 @@ void iscsi_destroy() if ( globvec != NULL ) { iscsi_globvec = NULL; - iscsi_hashmap_iterate( globvec->connection_key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_iterate( globvec->connection_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->connection_key_value_pairs ); globvec->connection_key_value_pairs = NULL; iscsi_hashmap_destroy( globvec->connections ); globvec->connections = NULL; - iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_key_destroy_value_callback, NULL ); + iscsi_hashmap_iterate( globvec->session_key_value_pairs, iscsi_hashmap_destroy_value_callback, NULL ); iscsi_hashmap_destroy( globvec->session_key_value_pairs ); globvec->session_key_value_pairs = NULL; @@ -729,14 +719,13 @@ uint8_t *iscsi_hashmap_key_create(const uint8_t *data, const size_t len) * * @param[in] map Pointer to hash map to construct the key * for and may NOT be NULL, so be careful. - * @return Pointer to generated usable key or NULL in - * case of an error (usually memory exhaustion). + * @param[out] key Pointer to key to store the + * unique key in. NULL is NOT allowed here, be + * careful. */ -uint8_t *iscsi_hashmap_key_create_id(const iscsi_hashmap *map) +void iscsi_hashmap_key_create_id(const iscsi_hashmap *map, uint64_t *key) { - const uint64_t key = ((uint64_t) map->capacity + (uint64_t) map->count + 1ULL); - - return iscsi_hashmap_key_create( (uint8_t *) &key, sizeof(key) ); + *key = ((uint64_t) map->capacity + (uint64_t) map->count + 1ULL); } /** @@ -776,6 +765,30 @@ int iscsi_hashmap_key_destroy_callback(uint8_t *key, const size_t key_size, uint } /** + * @brief Deallocates a value in a hash map. + * + * Default callback function for deallocation of + * hash map resources by simply deallocating + * the value. + * + * @param[in] key Pointer to zero padded key. NULL is + * an invalid pointer here, so be careful. + * @param[in] key_size Number of bytes for the key. + * @param[in] value Value of the key, NULL is allowed. + * @param[in,out] user_data This argument is not used by + * this function and should be always NULL for now, as + * there is a possibility for future usage. + * @return Always returns 0 as this function cannot fail. + */ +int iscsi_hashmap_destroy_value_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data) +{ + if ( value != NULL ) + free( value ); + + return 0L; +} + +/** * @brief Deallocates a key / value pair in a hash map by calling free (default destructor). * * Default callback function for deallocation of @@ -2575,6 +2588,7 @@ iscsi_task *iscsi_task_create(iscsi_connection *conn, iscsi_task *parent, iscsi_ task->buf = NULL; task->pos = 0UL; task->len = 0UL; + task->id = 0ULL; task->flags = 0L; task->lun_id = 0L; task->init_task_tag = 0UL; @@ -2774,12 +2788,8 @@ int iscsi_task_xfer_complete_process_read_insert_before_callback(uint8_t *key, c if ( insert_before_task->task->scsi_task.pos >= task->scsi_task.pos ) return 0L; - uint8_t *hash_key = iscsi_hashmap_key_create_id( insert_before_task->sub_tasks ); - - if ( hash_key == NULL ) - return -1L; - - iscsi_hashmap_insert_before( insert_before_task->sub_tasks, hash_key, sizeof(uint64_t), (uint8_t *) task, key, key_size ); + iscsi_hashmap_key_create_id( insert_before_task->sub_tasks, &task->id ); + iscsi_hashmap_insert_before( insert_before_task->sub_tasks, (uint8_t *) &task->id, sizeof(task->id), (uint8_t *) task, key, key_size ); return -1L; } @@ -2897,19 +2907,12 @@ void iscsi_task_xfer_complete_process_read(iscsi_connection *conn, iscsi_task *t iscsi_hashmap_iterate( primary_task->sub_tasks, iscsi_task_xfer_complete_process_read_insert_before_callback, (uint8_t *) &insert_before_task ); - uint8_t *hash_key = iscsi_hashmap_key_create_id( primary_task->sub_tasks ); - - if ( hash_key == NULL ) - return; - - iscsi_hashmap_put( primary_task->sub_tasks, hash_key, sizeof(uint64_t), (uint8_t *) task ); + iscsi_hashmap_key_create_id( primary_task->sub_tasks, &task->id ); + iscsi_hashmap_put( primary_task->sub_tasks, (uint8_t *) &task->id, sizeof(task->id), (uint8_t *) task ); } else { - uint8_t *hash_key = iscsi_hashmap_key_create_id( primary_task->sub_tasks ); - - if ( hash_key == NULL ) - return; + iscsi_hashmap_key_create_id( primary_task->sub_tasks, &task->id ); + iscsi_hashmap_push( primary_task->sub_tasks, (uint8_t *) &task->id, sizeof(task->id), (uint8_t *) task ); - iscsi_hashmap_push( primary_task->sub_tasks, hash_key, sizeof(uint64_t), (uint8_t *) task ); iscsi_task_xfer_complete_process_read_sub_tasks( conn, primary_task ); } } @@ -2940,18 +2943,11 @@ static int iscsi_task_xfer_add(iscsi_connection *conn, iscsi_task *task) task->scsi_data_out_cnt = data_out_req; if ( conn->r2t_pending >= ISCSI_DEFAULT_MAX_R2T_PER_CONNECTION ) { - uint8_t *hash_key = iscsi_hashmap_key_create_id( conn->r2t_tasks_queue ); - - if ( hash_key == NULL ) - return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - - const int rc = iscsi_hashmap_put( conn->r2t_tasks_queue, hash_key, sizeof(uint64_t), (uint8_t *) task ); - - if ( rc < 0 ) { - iscsi_hashmap_key_destroy( hash_key ); + iscsi_hashmap_key_create_id( conn->r2t_tasks_queue, &task->id ); + const int rc = iscsi_hashmap_put( conn->r2t_tasks_queue, (uint8_t *) &task->id, sizeof(task->id), (uint8_t *) task ); + if ( rc < 0 ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - } return ISCSI_CONNECT_PDU_READ_OK; } @@ -2989,18 +2985,11 @@ static int iscsi_task_xfer_add(iscsi_connection *conn, iscsi_task *task) break; } - uint8_t *hash_key = iscsi_hashmap_key_create_id( conn->r2t_tasks_active ); - - if ( hash_key == NULL ) - return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - - const int rc = iscsi_hashmap_put( conn->r2t_tasks_active, hash_key, sizeof(uint64_t), (uint8_t *) task ); - - if ( rc < 0 ) { - iscsi_hashmap_key_destroy( hash_key ); + iscsi_hashmap_key_create_id( conn->r2t_tasks_active, &task->id ); + const int rc = iscsi_hashmap_put( conn->r2t_tasks_active, (uint8_t *) &task->id, sizeof(task->id), (uint8_t *) task ); + if ( rc < 0 ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - } task->flags |= ISCSI_TASK_FLAGS_R2T_ACTIVE; @@ -3747,9 +3736,9 @@ void iscsi_scsi_task_create(iscsi_scsi_task *scsi_task, iscsi_scsi_task_xfer_com scsi_task->destroy_callback = destroy_callback; scsi_task->sense_data = NULL; scsi_task->buf = NULL; - scsi_task->id = 0ULL; scsi_task->pos = 0UL; scsi_task->len = 0UL; + scsi_task->id = 0ULL; scsi_task->flags = 0L; scsi_task->ref = 1UL; scsi_task->xfer_len = 0UL; @@ -4193,14 +4182,9 @@ int iscsi_scsi_lun_get_from_iscsi(const uint64_t lun) */ int iscsi_scsi_lun_task_append(iscsi_scsi_lun *lun, iscsi_scsi_task *scsi_task) { - uint8_t *hash_key = iscsi_hashmap_key_create_id( lun->tasks_pending ); - - if ( hash_key == NULL ) - return -1L; + iscsi_hashmap_key_create_id( lun->tasks_pending, &scsi_task->id ); - scsi_task->id = *(uint64_t *) hash_key; - - return iscsi_hashmap_put( lun->tasks_pending, hash_key, sizeof(uint64_t), (uint8_t *) scsi_task ); + return iscsi_hashmap_put( lun->tasks_pending, (uint8_t *) &scsi_task->id, sizeof(scsi_task->id), (uint8_t *) scsi_task ); } /** @@ -4294,23 +4278,12 @@ static bool iscsi_scsi_lun_handle_unit_attention(iscsi_scsi_task *scsi_task) */ void iscsi_scsi_lun_task_run(iscsi_scsi_lun *lun, iscsi_scsi_task *scsi_task) { - uint8_t *hash_key = iscsi_hashmap_key_create_id( lun->tasks ); - - if ( hash_key == NULL ) { - iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_HARDWARE_ERR, ISCSI_SCSI_ASC_WARNING, ISCSI_SCSI_ASCQ_POWER_LOSS_EXPECTED ); - - return; - } - - scsi_task->id = *(uint64_t *) hash_key; - - int rc = iscsi_hashmap_put( lun->tasks, hash_key, sizeof(uint64_t), (uint8_t *) scsi_task ); + iscsi_hashmap_key_create_id( lun->tasks, &scsi_task->id ); + int rc = iscsi_hashmap_put( lun->tasks, (uint8_t *) &scsi_task->id, sizeof(scsi_task->id), (uint8_t *) scsi_task ); if ( rc < 0 ) { iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_HARDWARE_ERR, ISCSI_SCSI_ASC_WARNING, ISCSI_SCSI_ASCQ_POWER_LOSS_EXPECTED ); - iscsi_hashmap_key_destroy( hash_key ); - return; } @@ -4724,6 +4697,488 @@ int iscsi_scsi_pr_check(iscsi_scsi_task *scsi_task) } /** + * @brief Checks whether an I/O feature is supported by a DNBD3 image. + * + * This function depends on DNBB3 image + * properties. + * + * @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, int type) +{ + // TODO: Actually implement this function. + + return (type != ISCSI_SCSI_EMU_IO_TYPE_UNMAP); +} + +/** + * @brief Retrieves the number of total physical blocks for a DNBB3 image. + * + * This function depends on DNBB3 image + * properties. + * + * @param[in] image Pointer to DNBD3 image to retrieve + * the physical size from. May NOT be NULL, + * so be careful. + * @return The number of total physical blocks. + */ +static inline uint64_t iscsi_scsi_emu_physical_block_get_count(const dnbd3_image_t *image) +{ + return (image->virtualFilesize >> ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE_BITS); +} + +/** + * @brief Retrieves the size of a physical block in bytes for a DNBB3 image. + * + * This function depends on DNBB3 image + * properties. + * + * @param[in] image Pointer to DNBD3 image to retrieve + * the physical block size. May NOT be NULL, + * so be careful. + * @return The physical block size in bytes. + */ +static inline uint32_t iscsi_scsi_emu_physical_block_get_size(const dnbd3_image_t *image) +{ + return ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE; +} + +/** + * @brief Retrieves the number of total logical blocks for a DNBB3 image. + * + * This function depends on DNBB3 image + * properties. + * + * @param[in] image Pointer to DNBD3 image to retrieve + * the logical size from. May NOT be NULL, + * so be careful. + * @return The number of total logical blocks. + */ +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 size of a logical block in bytes for a DNBB3 image. + * + * This function depends on DNBB3 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 DNBB3 image. + * + * This function depends on DNBB3 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_SIZE_BITS - ISCSI_SCSI_EMU_BLOCK_SIZE_BITS); +} + +/** + * @brief Retrieves the ratio between logical and physical block size for a DNBB3 image. + * + * This function depends on DNBB3 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 )); +} + +/** + * @brief Executes a read or write operation on a DNBD3 image. + * + * This function also sets the SCSI + * status result code accordingly. + * + * @param[in] image Pointer to DNBD3 image to read from + * or to write to. May NOT be NULL, so + * be careful. + * @param[in] scsi_task Pointer to iSCSI SCSI task + * responsible for this read or write + * task. NULL is NOT allowed here, take + * caution. + * @param[in] lba Logical Block Address (LBA) to start + * reading from or writing to. + * @param[in] xfer_len Transfer length in logical blocks. + * @param[in] flags Flags indicating if a read or write + * operation is in progress. For a + * write operation an optional verify + * can be requested. + * @return 0 on successful operation, a negative + * error code otherwise. + */ +static int iscsi_scsi_emu_block_read_write(dnbd3_image_t *image, iscsi_scsi_task *scsi_task, const uint64_t lba, const uint32_t xfer_len, const int flags) +{ + // TODO: Implement SCSI emulation for DNBD3 image. + + return 0L; +} + +/** + * @brief Executes a cache synchronization operation on a DNBD3 image. + * + * This function also sets the SCSI + * status result code accordingly. + * + * @param[in] image Pointer to DNBD3 image to + * synchronize the cache of. May NOT + * be NULL, so be careful. + * @param[in] scsi_task Pointer to iSCSI SCSI task + * responsible for this cache + * synchronization. NULL is NOT + * allowed here, take caution. + * @param[in] lba Logical Block Address (LBA) to start + * cache synchronization with. + * @param[in] xfer_len Synchronization length in logical blocks. + * @return 0 on successful operation, a negative + * error code otherwise. + */ +static int iscsi_scsi_emu_block_sync(dnbd3_image_t *image, iscsi_scsi_task *scsi_task, const uint64_t lba, const uint32_t xfer_len) +{ + // TODO: Implement SCSI emulation for DNBD3 image. + + return 0L; +} + +/** + * @brief Executes a unmap operation on a DNBD3 image. + * + * This function also sets the SCSI + * status result code accordingly. + * + * @param[in] image Pointer to DNBD3 image to + * unmap. May NOT be NULL, so be + * careful. + * @param[in] scsi_task Pointer to iSCSI SCSI task + * responsible for this unmap + * operation. NULL is NOT allowed + * here, take caution. + * @return 0 on successful operation, a negative + * error code otherwise. + */ +static int iscsi_scsi_emu_block_unmap(dnbd3_image_t *image, iscsi_scsi_task *scsi_task) +{ + // TODO: Implement SCSI emulation for DNBD3 image. + + return 0L; +} + +/** + * @brief Executes a write same operation on a DNBD3 image. + * + * This function also sets the SCSI + * status result code accordingly. + * + * @param[in] image Pointer to DNBD3 image to write + * to. May NOT be NULL, so be + * careful. + * @param[in] scsi_task Pointer to iSCSI SCSI task + * responsible for this write task. + * NULL is NOT allowed here, take + * caution. + * @param[in] lba Logical Block Address (LBA) to start + * writing to. + * @param[in] xfer_len Transfer length in logical blocks. + * @param[in] flags SCSI (Command Descriptor Block) CDB flags. + * @return 0 on successful operation, a negative + * error code otherwise. + */ +static int iscsi_scsi_emu_block_write_same(dnbd3_image_t *image, iscsi_scsi_task *scsi_task, const uint64_t lba, const uint32_t xfer_len, const int flags) +{ + // TODO: Implement SCSI emulation for DNBD3 image. + + return 0L; +} + +/** + * @brief Executes SCSI block emulation on a DNBD3 image. + * + * This function determines the block + * based SCSI opcode and executes it. + * + * @param[in] scsi_task Pointer to iSCSI SCSI task + * to process the SCSI block operation + * for and may NOT be NULL, be careful. + * @return 0 on successful operation, a negative + * error code otherwise. + */ +static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task) +{ + iscsi_scsi_lun *lun = scsi_task->lun; + uint64_t lba; + uint32_t xfer_len; + + switch ( scsi_task->cdb->opcode ) { + case ISCSI_SCSI_OPCODE_READ6 : + case ISCSI_SCSI_OPCODE_WRITE6 : { + const iscsi_scsi_cdb_read_write_6 *cdb_read_write_6 = (iscsi_scsi_cdb_read_write_6 *) scsi_task->cdb; + + lba = iscsi_get_be24(cdb_read_write_6->lba); + xfer_len = cdb_read_write_6->xfer_len; + + if ( xfer_len == 0 ) + xfer_len = 256UL; + + return iscsi_scsi_emu_block_read_write( lun->image, scsi_task, lba, xfer_len, ((scsi_task->cdb->opcode == ISCSI_SCSI_OPCODE_WRITE6) ? ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE : 0L) ); + + break; + } + case ISCSI_SCSI_OPCODE_READ10 : + case ISCSI_SCSI_OPCODE_WRITE10 : { + const iscsi_scsi_cdb_read_write_10 *cdb_read_write_10 = (iscsi_scsi_cdb_read_write_10 *) scsi_task->cdb; + + lba = iscsi_get_be32(cdb_read_write_10->lba); + xfer_len = iscsi_get_be16(cdb_read_write_10->xfer_len); + + return iscsi_scsi_emu_block_read_write( lun->image, scsi_task, lba, xfer_len, ((scsi_task->cdb->opcode == ISCSI_SCSI_OPCODE_WRITE10) ? ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE : 0L) ); + + break; + } + case ISCSI_SCSI_OPCODE_READ12 : + case ISCSI_SCSI_OPCODE_WRITE12 : { + const iscsi_scsi_cdb_read_write_12 *cdb_read_write_12 = (iscsi_scsi_cdb_read_write_12 *) scsi_task->cdb; + + lba = iscsi_get_be32(cdb_read_write_12->lba); + xfer_len = iscsi_get_be32(cdb_read_write_12->xfer_len); + + return iscsi_scsi_emu_block_read_write( lun->image, scsi_task, lba, xfer_len, ((scsi_task->cdb->opcode == ISCSI_SCSI_OPCODE_WRITE12) ? ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE : 0L) ); + + break; + } + case ISCSI_SCSI_OPCODE_READ16 : + case ISCSI_SCSI_OPCODE_WRITE16 : { + const iscsi_scsi_cdb_read_write_16 *cdb_read_write_16 = (iscsi_scsi_cdb_read_write_16 *) scsi_task->cdb; + + lba = iscsi_get_be64(cdb_read_write_16->lba); + xfer_len = iscsi_get_be32(cdb_read_write_16->xfer_len); + + return iscsi_scsi_emu_block_read_write( lun->image, scsi_task, lba, xfer_len, ((scsi_task->cdb->opcode == ISCSI_SCSI_OPCODE_WRITE16) ? ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE : 0L) ); + + break; + } + case ISCSI_SCSI_OPCODE_COMPARE_AND_WRITE : { + const iscsi_scsi_cdb_cmp_write *cdb_cmp_write = (iscsi_scsi_cdb_cmp_write *) scsi_task->cdb; + + lba = iscsi_get_be64(cdb_cmp_write->lba); + xfer_len = cdb_cmp_write->num_blocks; + + if ( ((cdb_cmp_write->flags & ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_FUA) != 0) || ((cdb_cmp_write->flags & ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_DPO) != 0) || ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_GET_WRPROTECT(cdb_cmp_write->flags) ) { + 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 ); + + return ISCSI_SCSI_TASK_RUN_COMPLETE; + } + + if ( xfer_len != 1 ) { + 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 ); + + return ISCSI_SCSI_TASK_RUN_COMPLETE; + } + + return iscsi_scsi_emu_block_read_write( lun->image, scsi_task, lba, xfer_len, (ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE | ISCSI_SCSI_EMU_BLOCK_FLAGS_VERIFY) ); + + 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) ); + + if ( buf == NULL ) { + iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_HARDWARE_ERR, ISCSI_SCSI_ASC_WARNING, ISCSI_SCSI_ASCQ_POWER_LOSS_EXPECTED ); + + return ISCSI_SCSI_TASK_RUN_COMPLETE; + } + + lba = iscsi_scsi_emu_block_get_count( lun->image ) - 1ULL; + + if ( lba > 0xFFFFFFFFULL ) + buf->lba = 0xFFFFFFFFUL; // Minus one does not require endianess conversion + else + iscsi_put_be32( (uint8_t *) &buf->lba, (uint32_t) lba ); + + xfer_len = iscsi_scsi_emu_block_get_size( lun->image ); + + iscsi_put_be32( (uint8_t *) &buf->block_len, xfer_len ); + + uint len = scsi_task->len; + + if ( len > sizeof(struct iscsi_scsi_read_capacity_10_parameter_data_packet) ) + len = sizeof(struct iscsi_scsi_read_capacity_10_parameter_data_packet); // TODO: Check whether scatter data is required + + scsi_task->buf = (uint8_t *) buf; + scsi_task->pos = len; + scsi_task->status = ISCSI_SCSI_STATUS_GOOD; + + break; + } + 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_HARDWARE_ERR, ISCSI_SCSI_ASC_WARNING, ISCSI_SCSI_ASCQ_POWER_LOSS_EXPECTED ); + + return ISCSI_SCSI_TASK_RUN_COMPLETE; + } + + lba = iscsi_scsi_emu_block_get_count( lun->image ) - 1ULL; + xfer_len = iscsi_scsi_emu_block_get_size( lun->image ); + + iscsi_put_be64( (uint8_t *) &buf->lba, lba ); + iscsi_put_be32( (uint8_t *) &buf->block_len, xfer_len ); + + buf->flags = 0; + + const uint8_t exponent = (uint8_t) iscsi_scsi_emu_block_get_ratio_shift( lun->image ); + + buf->expontents = ((exponent <= ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_MASK) ? exponent : 0U); + + if ( iscsi_scsi_emu_io_type_is_supported( lun->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->reserved[0] = 0ULL; + buf->reserved[1] = 0ULL; + + uint len = cdb_servce_in_action_16->alloc_len; + + 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 + + scsi_task->buf = (uint8_t *) buf; + scsi_task->pos = len; + scsi_task->status = ISCSI_SCSI_STATUS_GOOD; + + break; + } + default : { + return ISCSI_SCSI_TASK_RUN_UNKNOWN; + + break; + } + } + + break; + } + case ISCSI_SCSI_OPCODE_SYNCHRONIZECACHE10 : { + const iscsi_scsi_cdb_sync_cache_10 *cdb_sync_cache_10 = (iscsi_scsi_cdb_sync_cache_10 *) scsi_task->cdb; + + lba = iscsi_get_be32(cdb_sync_cache_10->lba); + xfer_len = iscsi_get_be16(cdb_sync_cache_10->xfer_len); + + if ( xfer_len == 0 ) + xfer_len = (uint32_t) (iscsi_scsi_emu_block_get_count( lun->image ) - lba); + + return iscsi_scsi_emu_block_sync( lun->image, scsi_task, lba, xfer_len ); + + break; + } + case ISCSI_SCSI_OPCODE_SYNCHRONIZECACHE16 : { + const iscsi_scsi_cdb_sync_cache_16 *cdb_sync_cache_16 = (iscsi_scsi_cdb_sync_cache_16 *) scsi_task->cdb; + + lba = iscsi_get_be64(cdb_sync_cache_16->lba); + xfer_len = iscsi_get_be32(cdb_sync_cache_16->xfer_len); + + if ( xfer_len == 0 ) + xfer_len = (uint32_t) (iscsi_scsi_emu_block_get_count( lun->image ) - lba); + + return iscsi_scsi_emu_block_sync( lun->image, scsi_task, lba, xfer_len ); + + break; + } + case ISCSI_SCSI_OPCODE_UNMAP : { + return iscsi_scsi_emu_block_unmap( lun->image, scsi_task ); + + break; + } + case ISCSI_SCSI_OPCODE_WRITE_SAME10 : { + const iscsi_scsi_cdb_write_same_10 *cdb_write_same_10 = (iscsi_scsi_cdb_write_same_10 *) scsi_task->cdb; + + lba = iscsi_get_be32(cdb_write_same_10->lba); + xfer_len = iscsi_get_be16(cdb_write_same_10->xfer_len); + + return iscsi_scsi_emu_block_write_same( lun->image, scsi_task, lba, xfer_len, cdb_write_same_10->flags ); + + break; + } + case ISCSI_SCSI_OPCODE_WRITE_SAME16 : { + const iscsi_scsi_cdb_write_same_16 *cdb_write_same_16 = (iscsi_scsi_cdb_write_same_16 *) scsi_task->cdb; + + lba = iscsi_get_be64(cdb_write_same_16->lba); + xfer_len = iscsi_get_be32(cdb_write_same_16->xfer_len); + + return iscsi_scsi_emu_block_write_same( lun->image, scsi_task, lba, xfer_len, cdb_write_same_16->flags ); + + break; + } + default : { + return ISCSI_SCSI_TASK_RUN_UNKNOWN; + + break; + } + } + + return ISCSI_SCSI_TASK_RUN_COMPLETE; +} + +/** + * @brief Executes SCSI non-block emulation on a DNBD3 image. + * + * This function determines the + * non-block based SCSI opcode and + * executes it. + * + * @param[in] scsi_task Pointer to iSCSI SCSI task + * to process the SCSI non-block + * operation for and may NOT be NULL, + * be careful. + * @return 0 on successful operation, a negative + * error code otherwise. + */ +static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task) +{ + // TODO: Implement SCSI emulation for DNBD3 image. + + return 0L; +} + +/** * @brief Executes the iSCSI SCSI emulation for an iSCSI SCSI task. * * This function also handles all SCSI emulation @@ -4737,9 +5192,19 @@ int iscsi_scsi_pr_check(iscsi_scsi_task *scsi_task) */ int iscsi_scsi_emu_exec(iscsi_scsi_task *scsi_task) { - // TODO: Implement SCSI emulation. + int rc = iscsi_scsi_emu_block_process( scsi_task ); - return 0L; + if ( rc == ISCSI_SCSI_TASK_RUN_UNKNOWN ) { + rc = iscsi_scsi_emu_primary_process( scsi_task ); + + if ( rc == ISCSI_SCSI_TASK_RUN_UNKNOWN ) { + 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 ); + + return ISCSI_SCSI_TASK_RUN_COMPLETE; + } + } + + return rc; } /** @@ -8527,21 +8992,11 @@ static int iscsi_connection_pdu_data_handle_scsi_cmd_read(iscsi_connection *conn task->pos = 0UL; - uint8_t *hash_key = iscsi_hashmap_key_create_id( task->sub_tasks ); - - if ( hash_key == NULL ) { - logadd( LOG_ERROR, "iscsi_connection_pdu_data_handle_scsi_cmd_read: Out of memory while allocating iSCSI task sub task hash map" ); + iscsi_hashmap_key_create_id( task->sub_tasks, &task->id ); + const int rc = iscsi_hashmap_put( task->sub_tasks, (uint8_t *) &task->id, sizeof(task->id), (uint8_t *) task ); + if ( rc < 0 ) return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - } - - const int rc = iscsi_hashmap_put( task->sub_tasks, hash_key, sizeof(uint64_t), (uint8_t *) task ); - - if ( rc < 0 ) { - iscsi_hashmap_key_destroy( hash_key ); - - return ISCSI_CONNECT_PDU_READ_ERR_FATAL; - } return iscsi_connection_handle_scsi_data_in_queued_tasks( conn ); } @@ -9906,7 +10361,7 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ return; } - uint8_t *hash_key = iscsi_hashmap_key_create_id( iscsi_globvec->portal_groups ); + uint64_t *hash_key = (uint64_t *) malloc( sizeof(uint64_t) ); if ( hash_key == NULL ) { logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI portal group" ); @@ -9915,10 +10370,12 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ } portal_group->tag = (int) (*(uint64_t *) hash_key); - int rc = iscsi_hashmap_put( iscsi_globvec->portal_groups, hash_key, sizeof(uint64_t), (uint8_t *) portal_group ); + + iscsi_hashmap_key_create_id( iscsi_globvec->portal_groups, hash_key ); + int rc = iscsi_hashmap_put( iscsi_globvec->portal_groups, (uint8_t *) hash_key, sizeof(uint64_t), (uint8_t *) portal_group ); if ( rc < 0 ) { - iscsi_hashmap_key_destroy( hash_key ); + iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); iscsi_portal_group_destroy( portal_group ); return; @@ -9944,7 +10401,7 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ return; } - hash_key = iscsi_hashmap_key_create_id( iscsi_globvec->target_nodes ); + hash_key = (uint64_t *) malloc( sizeof(uint64_t) ); if ( hash_key == NULL ) { logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI target node" ); @@ -9954,10 +10411,11 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ return; } - rc = iscsi_hashmap_put( iscsi_globvec->target_nodes, hash_key, sizeof(uint64_t), (uint8_t *) target ); + iscsi_hashmap_key_create_id( iscsi_globvec->target_nodes, hash_key ); + rc = iscsi_hashmap_put( iscsi_globvec->target_nodes, (uint8_t *) hash_key, sizeof(uint64_t), (uint8_t *) target ); if ( rc < 0 ) { - iscsi_hashmap_key_destroy( hash_key ); + iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); iscsi_target_node_destroy( target ); return; @@ -9973,7 +10431,7 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ return; } - hash_key = iscsi_hashmap_key_create_id( iscsi_globvec->connections ); + hash_key = (uint64_t *) malloc( sizeof(uint64_t) ); if ( hash_key == NULL ) { logadd( LOG_ERROR, "iscsi_connection_handle: Out of memory while allocating iSCSI connection" ); @@ -9984,12 +10442,10 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ return; } - conn->id = (int) (*(uint64_t *) hash_key); - conn->pdu_processing = iscsi_connection_pdu_create( conn ); if ( conn->pdu_processing == NULL ) { - iscsi_hashmap_key_destroy( hash_key ); + iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); iscsi_connection_destroy( conn ); iscsi_portal_destroy( portal ); @@ -10001,11 +10457,14 @@ void iscsi_connection_handle(dnbd3_client_t *client, const dnbd3_request_t *requ conn->pdu_processing->bhs_pos = len; conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_HDR; - rc = iscsi_hashmap_put( iscsi_globvec->connections, hash_key, sizeof(uint64_t), (uint8_t *) conn ); + conn->id = (int) (*(uint64_t *) hash_key); + + iscsi_hashmap_key_create_id( iscsi_globvec->connections, hash_key ); + rc = iscsi_hashmap_put( iscsi_globvec->connections, (uint8_t *) hash_key, sizeof(uint64_t), (uint8_t *) conn ); if ( rc < 0 ) { iscsi_connection_pdu_destroy( conn->pdu_processing ); - iscsi_hashmap_key_destroy( hash_key ); + iscsi_hashmap_key_destroy( (uint8_t *) hash_key ); iscsi_connection_destroy( conn ); iscsi_portal_destroy( portal ); diff --git a/src/server/iscsi.h b/src/server/iscsi.h index 5c9cb7b..15b925c 100644 --- a/src/server/iscsi.h +++ b/src/server/iscsi.h @@ -271,9 +271,10 @@ void iscsi_hashmap_destroy(iscsi_hashmap *map); // Deallocates the hash map obje // Use iscsi_hashmap_iterate to deallocate the elements themselves uint8_t *iscsi_hashmap_key_create(const uint8_t *data, const size_t len); // Creates a key suitable for hashmap usage (ensures 8-byte boundary and zero padding) -uint8_t *iscsi_hashmap_key_create_id(const iscsi_hashmap *map); // Creates an unique key identifier suitable for hashmap usage (ensures 8-byte boundary and zero padding) +void iscsi_hashmap_key_create_id(const iscsi_hashmap *map, uint64_t *key); // Creates an unique key identifier suitable for hashmap usage (ensures 8-byte boundary and zero padding) void iscsi_hashmap_key_destroy(uint8_t *key); // Deallocates all resources acquired by iscsi_hashmap_create_key int iscsi_hashmap_key_destroy_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Deallocates a key in a hash map +int iscsi_hashmap_destroy_value_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Deallocates a value in a hash map int iscsi_hashmap_key_destroy_value_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Deallocates a key / value pair in a hash map by calling free (default destructor) int iscsi_hashmap_put(iscsi_hashmap *map, uint8_t *key, const size_t key_size, uint8_t *value); // Assigns key / value pair to hash map at the tail of linked list without making copies @@ -534,10 +535,10 @@ typedef struct __attribute__((packed)) iscsi_ext_cdb_ahs_packet { * expected data transfer length. */ typedef struct __attribute__((packed)) iscsi_bidi_read_exp_xfer_ahs_packet { - /// AHSLength: Always 5 according to ISCSI specifications for now. + /// AHSLength: Always 5 according to iSCSI specifications for now. uint16_t len; - /// AHSType: Always 2 according to ISCSI specifications for now. + /// 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. @@ -689,6 +690,7 @@ 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; /// Logical Unit Number (LUN) and EVPD. @@ -705,6 +707,316 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_inquiry { } iscsi_scsi_cdb_inquiry; +/** + * @brief iSCSI SCSI CDB packet data structure for SCSI READ(6) and WRITE(6) commands. + * + * 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; + + /// Logical Block Address (LBA). + uint8_t lba[3]; + + /// Transfer length in bytes. + uint8_t xfer_len; + + /// Control. + uint8_t control; +} iscsi_scsi_cdb_read_write_6; + + +/** + * @brief iSCSI SCSI CDB packet data structure for SCSI READ(10) and WRITE(10) commands. + * + * 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; + + /// 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_read_write_10; + + +/** + * @brief iSCSI SCSI CDB packet data structure for SCSI READ(12) and WRITE(12) commands. + * + * 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; + + /// Flags. + int8_t flags; + + /// Logical Block Address (LBA). + uint32_t lba; + + /// Transfer length in bytes. + uint32_t xfer_len; + + /// Restricted for MMC-6 and group number. + int8_t restrict_group_num; + + /// Control. + uint8_t control; +} iscsi_scsi_cdb_read_write_12; + + +/** + * @brief iSCSI SCSI CDB packet data structure for SCSI READ(16) and WRITE(16) commands. + * + * 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; + + /// Flags. + int8_t flags; + + /// Logical Block Address (LBA). + uint64_t lba; + + /// Transfer length in bytes. + uint32_t xfer_len; + + /// Restricted for MMC-6 and group number. + int8_t restrict_group_num; + + /// Control. + uint8_t control; +} iscsi_scsi_cdb_read_write_16; + + +/// 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: Second bit of the three bits. +#define ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_SECOND_BIT ((ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_FIRST_BIT) + 1) + +/// iSCSI SCSI Command Descriptor Block (CDB) for COMPARE AND WRITE command write protect flags: Third bit of the three bits. +#define ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_THIRD_BIT ((ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_SECOND_BIT) + 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 ((1 << (ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_FIRST_BIT)) | (1 << (ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_SECOND_BIT)) | (1 << (ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_THIRD_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) (((x) & ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_MASK) >> ISCSI_SCSI_CDB_CMP_WRITE_FLAGS_WRPROTECT_FIRST_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 + +/// iSCSI SCSI Command Descriptor Block (CDB) for SERVICE ACTION IN(16) command service action: READ LONG(16). +#define ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_READ_LONG_16 0x11 + +/// iSCSI SCSI Command Descriptor Block (CDB) for SERVICE ACTION IN(16) command service action: First bit of the five bits. +#define ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_FIRST_BIT 0 + +/// iSCSI SCSI Command Descriptor Block (CDB) for SERVICE ACTION IN(16) command service action: Second bit of the five bits. +#define ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_SECOND_BIT ((ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_FIRST_BIT) + 1) + +/// iSCSI SCSI Command Descriptor Block (CDB) for SERVICE ACTION IN(16) command service action: Third bit of the five bits. +#define ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_THIRD_BIT ((ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_SECOND_BIT) + 1) + +/// iSCSI SCSI Command Descriptor Block (CDB) for SERVICE ACTION IN(16) command service action: Fourth bit of the five bits. +#define ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_FOURTH_BIT ((ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_THIRD_BIT) + 1) + +/// iSCSI SCSI Command Descriptor Block (CDB) for SERVICE ACTION IN(16) command service action: Fifth bit of the five bits. +#define ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_FIFTH_BIT ((ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_FOURTH_BIT) + 1) + +/// iSCSI SCSI Command Descriptor Block (CDB) for SERVICE ACTION IN(16) command service action: Bit mask. +#define ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_MASK ((1 << (ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_FIRST_BIT)) | (1 << (ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_SECOND_BIT)) | (1 << (ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_THIRD_BIT)) | (1 << (ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_FOURTH_BIT)) | (1 << (ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_FIFTH_BIT))) + +/// iSCSI SCSI Command Descriptor Block (CDB) for SERVICE ACTION IN(16) command service action: Extracts the service action bits. +#define ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_GET_ACTION(x) (((x) & ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_MASK) >> ISCSI_SCSI_CDB_SERVICE_ACTION_IN_16_ACTION_FIRST_BIT) + + +/** + * @brief iSCSI SCSI CDB packet data structure for SCSI SERVICE IN ACTION(16) command. + * + * 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; + + /// Service action. + uint8_t action; + + /// Logical Block Address (LBA), obselete by now. + uint64_t lba; + + /// Allocation length in bytes. + uint32_t alloc_len; + + /// Reserved for future usage (always MUST be 0 for now). + uint8_t reserved; + + /// 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 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 @@ -748,7 +1060,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_inquiry { #define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_MASK ((1 << (ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_FIRST_BIT)) | (1 << (ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_SECOND_BIT)) | (1 << (ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_THIRD_BIT)) | (1 << (ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_FOURTH_BIT)) | (1 << (ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_FIFTH_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) (((x) & ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_MASK) >> ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_FIRST_BIT) +#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_GET_ACTION(x) (((x) & ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_MASK) >> ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_FIRST_BIT) /** @@ -757,6 +1069,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_inquiry { * 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; /// Logical Unit Number (LUN) and service action. @@ -851,7 +1164,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_ds_cmd_data { #define ISCSI_SCSI_DATA_PERIPHERAL_TYPE_MASK ((1 << (ISCSI_SCSI_DATA_PERIPHERAL_TYPE_FIRST_BIT)) | (1 << (ISCSI_SCSI_DATA_PERIPHERAL_TYPE_SECOND_BIT)) | (1 << (ISCSI_SCSI_DATA_PERIPHERAL_TYPE_THIRD_BIT)) | (1 << (ISCSI_SCSI_DATA_PERIPHERAL_TYPE_FOURTH_BIT)) | (1 << (ISCSI_SCSI_DATA_PERIPHERAL_TYPE_FIFTH_BIT))) /// iSCSI SCSI Data peripheral type: Extracts the Peripheral device type bits. -#define ISCSI_SCSI_DATA_GET_PERIPHERAL_TYPE(x) (((x) & ISCSI_SCSI_DATA_PERIPHERAL_TYPE_MASK) >> ISCSI_SCSI_DATA_PERIPHERAL_TYPE_FIRST_BIT) +#define ISCSI_SCSI_DATA_GET_PERIPHERAL_TYPE(x) (((x) & ISCSI_SCSI_DATA_PERIPHERAL_TYPE_MASK) >> ISCSI_SCSI_DATA_PERIPHERAL_TYPE_FIRST_BIT) /// iSCSI SCSI Data peripheral identifier: The specified peripheral device type is currently connected to this logical unit, or connection state could not be determined. #define ISCSI_SCSI_DATA_PERIPHERAL_ID_POSSIBLE 0x0 @@ -878,7 +1191,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_ds_cmd_data { #define ISCSI_SCSI_DATA_PERIPHERAL_ID_MASK ((1 << (ISCSI_SCSI_DATA_PERIPHERAL_ID_FIRST_BIT)) | (1 << (ISCSI_SCSI_DATA_PERIPHERAL_ID_SECOND_BIT)) | (1 << (ISCSI_SCSI_DATA_PERIPHERAL_ID_THIRD_BIT))) /// iSCSI SCSI Data peripheral identifier: Extracts the Peripheral device identifier bits. -#define ISCSI_SCSI_DATA_GET_PERIPHERAL_ID(x) (((x) & ISCSI_SCSI_DATA_PERIPHERAL_ID_MASK) >> ISCSI_SCSI_DATA_PERIPHERAL_ID_FIRST_BIT) +#define ISCSI_SCSI_DATA_GET_PERIPHERAL_ID(x) (((x) & ISCSI_SCSI_DATA_PERIPHERAL_ID_MASK) >> ISCSI_SCSI_DATA_PERIPHERAL_ID_FIRST_BIT) /// iSCSI SCSI Data peripheral type modifier: Bit mask. @@ -901,7 +1214,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_ds_cmd_data { #define ISCSI_SCSI_DATA_VERSION_ANSI_MASK ((1 << (ISCSI_SCSI_DATA_VERSION_ANSI_FIRST_BIT)) | (1 << (ISCSI_SCSI_DATA_VERSION_ANSI_SECOND_BIT)) | (1 << (ISCSI_SCSI_DATA_VERSION_ANSI_THIRD_BIT))) /// iSCSI SCSI Data ANSI version: Extracts the Peripheral device identifier bits. -#define ISCSI_SCSI_DATA_GET_VERSION_ANSI(x) (((x) & ISCSI_SCSI_DATA_VERSION_ANSI_MASK) >> ISCSI_SCSI_DATA_VERSION_ANSI_FIRST_BIT) +#define ISCSI_SCSI_DATA_GET_VERSION_ANSI(x) (((x) & ISCSI_SCSI_DATA_VERSION_ANSI_MASK) >> ISCSI_SCSI_DATA_VERSION_ANSI_FIRST_BIT) /// iSCSI SCSI Data ECMA version: First bit of the three bits. #define ISCSI_SCSI_DATA_VERSION_ECMA_FIRST_BIT 3 @@ -916,7 +1229,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_ds_cmd_data { #define ISCSI_SCSI_DATA_VERSION_ECMA_MASK ((1 << (ISCSI_SCSI_DATA_VERSION_ECMA_FIRST_BIT)) | (1 << (ISCSI_SCSI_DATA_VERSION_ECMA_SECOND_BIT)) | (1 << (ISCSI_SCSI_DATA_VERSION_ECMA_THIRD_BIT))) /// iSCSI SCSI Data ECMA version: Extracts the Peripheral device identifier bits. -#define ISCSI_SCSI_DATA_GET_VERSION_ECMA(x) (((x) & ISCSI_SCSI_DATA_VERSION_ECMA_MASK) >> ISCSI_SCSI_DATA_VERSION_ECMA_FIRST_BIT) +#define ISCSI_SCSI_DATA_GET_VERSION_ECMA(x) (((x) & ISCSI_SCSI_DATA_VERSION_ECMA_MASK) >> ISCSI_SCSI_DATA_VERSION_ECMA_FIRST_BIT) /// iSCSI SCSI Data ISO version: First bit of the two bits. #define ISCSI_SCSI_DATA_VERSION_ISO_FIRST_BIT 6 @@ -928,7 +1241,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_ds_cmd_data { #define ISCSI_SCSI_DATA_VERSION_ISO_MASK ((1 << (ISCSI_SCSI_DATA_VERSION_ISO_FIRST_BIT)) | (1 << (ISCSI_SCSI_DATA_VERSION_ISO_SECOND_BIT))) /// iSCSI SCSI Data ISO version: Extracts the Peripheral device identifier bits. -#define ISCSI_SCSI_DATA_GET_VERSION_ISO(x) (((x) & ISCSI_SCSI_DATA_VERSION_ISO_MASK) >> ISCSI_SCSI_DATA_VERSION_ISO_FIRST_BIT) +#define ISCSI_SCSI_DATA_GET_VERSION_ISO(x) (((x) & ISCSI_SCSI_DATA_VERSION_ISO_MASK) >> ISCSI_SCSI_DATA_VERSION_ISO_FIRST_BIT) /// iSCSI SCSI Data response data format flags: This structure complies with SCSI-1 specifications. @@ -956,7 +1269,7 @@ typedef struct __attribute__((packed)) iscsi_scsi_ds_cmd_data { #define ISCSI_SCSI_DATA_RESPONSE_DATA_FMT_FLAGS_MASK ((1 << (ISCSI_SCSI_DATA_RESPONSE_DATA_FMT_FLAGS_FIRST_BIT)) | (1 << (ISCSI_SCSI_DATA_RESPONSE_DATA_FMT_FLAGS_SECOND_BIT)) | (1 << (ISCSI_SCSI_DATA_RESPONSE_DATA_FMT_FLAGS_THIRD_BIT)) | (1 << (ISCSI_SCSI_DATA_RESPONSE_DATA_FMT_FLAGS_FOURTH_BIT))) /// iSCSI SCSI Data response data format flags: Extracts the Peripheral device type bits. -#define ISCSI_SCSI_DATA_GET_RESPONSE_DATA_FMT_FLAGS(x) (((x) & ISCSI_SCSI_DATA_RESPONSE_DATA_FMT_FLAGS_MASK) >> ISCSI_SCSI_DATA_RESPONSE_DATA_FMT_FLAGS_FIRST_BIT) +#define ISCSI_SCSI_DATA_GET_RESPONSE_DATA_FMT_FLAGS(x) (((x) & ISCSI_SCSI_DATA_RESPONSE_DATA_FMT_FLAGS_MASK) >> ISCSI_SCSI_DATA_RESPONSE_DATA_FMT_FLAGS_FIRST_BIT) /// iSCSI SCSI Data response data format flags: TERMINATE I/O PROCESS message device support. #define ISCSI_SCSI_DATA_RESPONSE_DATA_FMT_FLAGS_TERMINATE_IO_PROC_MSG (1 << 6L) @@ -1175,6 +1488,129 @@ typedef struct __attribute__((packed)) iscsi_scsi_sense_data_check_cond_packet { } iscsi_scsi_sense_data_check_cond_packet; +/** + * @brief iSCSI SCSI command READ CAPACITY(10) parameter data packet data. + * + * This returns the Logical Block Address (LBA) + * 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; + + /// Block length in bytes. + uint32_t block_len; +} iscsi_scsi_read_capacity_10_parameter_data_packet; + + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data flags: Protection enabled (PROT_EN). +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROT_EN (1 << 0L) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection type flags: First bit of the three bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_FIRST_BIT 1 + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection type flags: Second bit of the three bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_SECOND_BIT ((ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_FIRST_BIT) + 1) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection type flags: Third bit of the three bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_THIRD_BIT ((ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_SECOND_BIT) + 1) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection type flags: Bit mask. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_MASK ((1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_FIRST_BIT)) | (1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_SECOND_BIT)) | (1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_THIRD_BIT))) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection type flags: Extracts the protection type bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_GET_PROTECT_TYPE(x) (((x) & ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_MASK) >> ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_PROTECT_TYPE_FIRST_BIT) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data RC basis flags: First bit of the two bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_RC_BASIS_FIRST_BIT 4 + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data RC basis flags: Second bit of the two bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_RC_BASIS_SECOND_BIT ((ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_RC_BASIS_FIRST_BIT) + 1) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data RC basis flags: Bit mask. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_RC_BASIS_MASK ((1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_RC_BASIS_FIRST_BIT)) | (1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_RC_BASIS_SECOND_BIT))) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data RC basis flags: Extracts the RC basis bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_GET_RC_BASIS(x) (((x) & ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_RC_BASIS_MASK) >> ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_FLAGS_RC_BASIS_FIRST_BIT) + + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data logical blocks per physical block exponent: First bit of the four bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_FIRST_BIT 0 + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data logical blocks per physical block exponent: Second bit of the four bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_SECOND_BIT ((ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_FIRST_BIT) + 1) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data logical blocks per physical block exponent: Third bit of the four bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_THIRD_BIT ((ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_SECOND_BIT) + 1) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data logical blocks per physical block exponent: Fourth bit of the four bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_FOURTH_BIT ((ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_THIRD_BIT) + 1) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data logical blocks per physical block exponent: Bit mask. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_MASK ((1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_FIRST_BIT)) | (1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_SECOND_BIT)) | (1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_THIRD_BIT)) | (1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_FOURTH_BIT))) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data logical blocks per physical block exponent: Extracts the logical blocks per physical block bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_GET_LBPPB_EXPONENT(x) (((x) & ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_MASK) >> ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPPB_EXPONENT_FIRST_BIT) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection information intervals exponent: First bit of the four bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_FIRST_BIT 4 + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection information intervals exponent: Second bit of the four bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_SECOND_BIT ((ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_FIRST_BIT) + 1) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection information intervals exponent: Third bit of the four bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_THIRD_BIT ((ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_SECOND_BIT) + 1) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection information intervals exponent: Fourth bit of the four bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_FOURTH_BIT ((ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_THIRD_BIT) + 1) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection information intervals exponent: Bit mask. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_MASK ((1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_FIRST_BIT)) | (1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_SECOND_BIT)) | (1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_THIRD_BIT)) | (1 << (ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_FOURTH_BIT))) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter data protection information intervals exponent: Extracts the Peripheral device type bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_GET_P_I_EXPONENT(x) (((x) & ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_MASK) >> ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_P_I_EXPONENT_FIRST_BIT) + + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter logical block provisioning: Lowest Aligned Logical Block Address mask (LALBA). +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LALBA_MASK 0x3FFF + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter logical block provisioning: Extracts the Lowest Aligned Logical Block Address (LALBA) bits. +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_GET_LABLA ((x) & ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LALBA_MASK) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter logical block provisioning: Logical Block Provisioning Read Zeros (LBPRZ). +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPRZ (1 << 14L) + +/// iSCSI SCSI command SERVICE ACTION IN(16) parameter logical block provisioning: Logical Block Provisioning Management Enabled (LBPME). +#define ISCSI_SCSI_SERVICE_ACTION_IN_16_PARAM_DATA_LBPME (1 << 15L) + + +/** + * @brief iSCSI SCSI command SERVICE ACTION IN(16) parameter data packet data. + * + * This returns the Logical Block Address (LBA), + * 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; + + /// Block length in bytes. + uint32_t block_len; + + /// Flags: RC_BASIS, P_TYPE and PROT_EN. + int8_t flags; + + /// P_I_EXPONENT and logical blocks per physical block exponent. + uint8_t expontents; + + /// 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]; +} iscsi_scsi_service_action_in_16_parameter_data_packet; + + /// SCSI command opcode (embedded in iSCSI protocol): TEST UNIT READY. #define ISCSI_SCSI_OPCODE_TESTUNITREADY 0x00 @@ -6807,15 +7243,15 @@ typedef struct iscsi_scsi_task { /// Output buffer. uint8_t *buf; - /// Unique identifier for this task. - uint64_t id; - /// Position of buffer in bytes. uint pos; /// Length of buffer in bytes. uint len; + /// Unique identifier for this task. + uint64_t id; + /// Flags. int flags; @@ -6838,8 +7274,30 @@ typedef struct iscsi_scsi_task { uint8_t task_mgmt_response; } iscsi_scsi_task; -/// ISCSI port flags: In use. -#define ISCSI_PORT_FLAGS_IN_USE (1 << 0L) + +/// iSCSI SCSI emulation physical block size in bits. +#define ISCSI_SCSI_EMU_PHYSICAL_BLOCK_SIZE_BITS 9UL + +/// 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 block size in bits. +#define ISCSI_SCSI_EMU_BLOCK_SIZE_BITS 12UL + +/// iSCSI SCSI emulation block size in bytes. +#define ISCSI_SCSI_EMU_BLOCK_SIZE (1UL << ISCSI_SCSI_EMU_BLOCK_SIZE_BITS) + + +/// iSCSI SCSI emulation I/O type: Unmap. +#define ISCSI_SCSI_EMU_IO_TYPE_UNMAP (1 << 0L) + + +/// iSCSI SCSI emulation block flags: Write operation. +#define ISCSI_SCSI_EMU_BLOCK_FLAGS_WRITE (1 << 0L) + +/// iSCSI SCSI emulation block flags: Verify operation. +#define ISCSI_SCSI_EMU_BLOCK_FLAGS_VERIFY (1 << 1L) void iscsi_scsi_task_create(iscsi_scsi_task *scsi_task, iscsi_scsi_task_xfer_complete_callback xfer_complete_callback, iscsi_scsi_task_destroy_callback destroy_callback); // Allocates and initializes a SCSI task @@ -6871,6 +7329,11 @@ int iscsi_scsi_pr_check(iscsi_scsi_task *scsi_task); // Checks the iSCSI SCSI Pe int iscsi_scsi_emu_exec(iscsi_scsi_task *scsi_task); // Executes the iSCSI SCSI emulation for an iSCSI SCSI task + +/// iSCSI port flags: In use. +#define ISCSI_PORT_FLAGS_IN_USE (1 << 0L) + + /** * @brief iSCSI port. * @@ -7579,7 +8042,7 @@ typedef struct iscsi_pdu { /** * @brief This structure is used for iSCSI task management. * - * This structure maintains the ISCSI task handling + * This structure maintains the iSCSI task handling * including the underlying SCSI layer. */ typedef struct iscsi_task { @@ -7607,6 +8070,9 @@ typedef struct iscsi_task { /// Buffer length in bytes. uint len; + /// Unique identifier for this task. + uint64_t id; + /// Flags. int flags; |
