summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
authorSebastian Vater2025-09-05 15:01:47 +0200
committerSebastian Vater2025-09-05 15:01:47 +0200
commit13aa3dbfe2e6e8aaf4e8597f15555473d19dd6a3 (patch)
tree24dd06c1856dabd77727f460608a304629648278 /src/server
parentImplemented basic iSCSI SCSI Persistent Reservation (PR) handling and checkin... (diff)
downloaddnbd3-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.
Diffstat (limited to 'src/server')
-rw-r--r--src/server/iscsi.c681
-rw-r--r--src/server/iscsi.h498
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;