summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Vater2025-09-12 15:13:48 +0200
committerSebastian Vater2025-09-12 15:13:48 +0200
commit40a64a37fe9e61189bf69c815e3d8535604e28ed (patch)
tree1c6dd2f5c80c7bdefac7a7327420038894ca0756
parentImplemented remaining INQUIRY iSCSI SCSI emulation related stuff. Also fixed ... (diff)
downloaddnbd3-40a64a37fe9e61189bf69c815e3d8535604e28ed.tar.gz
dnbd3-40a64a37fe9e61189bf69c815e3d8535604e28ed.tar.xz
dnbd3-40a64a37fe9e61189bf69c815e3d8535604e28ed.zip
Fixed iSCSI SCSI emulation and implemented adding target port to iSCSI device, QEMU now tries to boot from PXE: Important milestone. Finally, some code refactoring was done again.
-rw-r--r--src/server/iscsi.c235
-rw-r--r--src/server/iscsi.h154
2 files changed, 355 insertions, 34 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c
index 9c44f04..0ab6f1e 100644
--- a/src/server/iscsi.c
+++ b/src/server/iscsi.c
@@ -18,6 +18,7 @@
*
*/
+#include "image.h"
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -2636,7 +2637,6 @@ iscsi_task *iscsi_task_create(iscsi_connection *conn, iscsi_task *parent, iscsi_
task->sub_tasks = NULL;
task->conn = conn;
task->pdu = NULL;
- task->buf = NULL;
task->pos = 0U;
task->len = 0U;
task->id = 0ULL;
@@ -3289,7 +3289,7 @@ static uint32_t iscsi_scsi_data_in_send(iscsi_connection *conn, iscsi_task *task
response_pdu->data_digest_size = conn->data_digest;
}
- memcpy( response_pdu->ds_cmd_data, task->buf, len );
+ memcpy( response_pdu->ds_cmd_data, task->scsi_task.buf, len );
response_pdu->task = task;
task->scsi_task.ref++;
@@ -4025,7 +4025,7 @@ iscsi_scsi_lun *iscsi_scsi_lun_create(const uint id)
iscsi_scsi_lun *lun = (iscsi_scsi_lun *) malloc( sizeof(struct iscsi_scsi_lun) );
if ( lun == NULL ) {
- logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN" );
+ logadd( LOG_ERROR, "iscsi_scsi_lun_create: Out of memory allocating iSCSI device LUN" );
return NULL;
}
@@ -4033,7 +4033,7 @@ iscsi_scsi_lun *iscsi_scsi_lun_create(const uint id)
lun->tasks = iscsi_hashmap_create( 0U );
if ( lun->tasks == NULL ) {
- logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN tasks hash map" );
+ logadd( LOG_ERROR, "iscsi_scsi_lun_create: Out of memory allocating iSCSI device LUN tasks hash map" );
free( lun );
@@ -4043,7 +4043,7 @@ iscsi_scsi_lun *iscsi_scsi_lun_create(const uint id)
lun->tasks_pending = iscsi_hashmap_create( 0U );
if ( lun->tasks_pending == NULL ) {
- logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN pending tasks hash map" );
+ logadd( LOG_ERROR, "iscsi_scsi_lun_create: Out of memory allocating iSCSI device LUN pending tasks hash map" );
iscsi_hashmap_destroy( lun->tasks );
free( lun );
@@ -4054,7 +4054,7 @@ iscsi_scsi_lun *iscsi_scsi_lun_create(const uint id)
lun->tasks_mgmt = iscsi_hashmap_create( 0U );
if ( lun->tasks_mgmt == NULL ) {
- logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN management tasks hash map" );
+ logadd( LOG_ERROR, "iscsi_scsi_lun_create: Out of memory allocating iSCSI device LUN management tasks hash map" );
iscsi_hashmap_destroy( lun->tasks_pending );
iscsi_hashmap_destroy( lun->tasks );
@@ -4066,7 +4066,7 @@ iscsi_scsi_lun *iscsi_scsi_lun_create(const uint id)
lun->tasks_mgmt_pending = iscsi_hashmap_create( 0U );
if ( lun->tasks_mgmt_pending == NULL ) {
- logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN pending management tasks hash map" );
+ logadd( LOG_ERROR, "iscsi_scsi_lun_create: Out of memory allocating iSCSI device LUN pending management tasks hash map" );
iscsi_hashmap_destroy( lun->tasks_mgmt );
iscsi_hashmap_destroy( lun->tasks_pending );
@@ -4079,7 +4079,7 @@ iscsi_scsi_lun *iscsi_scsi_lun_create(const uint id)
lun->pr_regs = iscsi_hashmap_create( 0U );
if ( lun->pr_regs == NULL ) {
- logadd( LOG_ERROR, "iscsi_device_create: Out of memory allocating iSCSI device LUN Persistent Reservation (PR) registrant for I_T nexus hash map" );
+ logadd( LOG_ERROR, "iscsi_scsi_lun_create: Out of memory allocating iSCSI device LUN Persistent Reservation (PR) registrant for I_T nexus hash map" );
iscsi_hashmap_destroy( lun->tasks_mgmt_pending );
iscsi_hashmap_destroy( lun->tasks_mgmt );
@@ -4383,7 +4383,7 @@ void iscsi_scsi_lun_task_run(iscsi_scsi_lun *lun, iscsi_scsi_task *scsi_task)
void iscsi_scsi_lun_task_complete(iscsi_scsi_lun *lun, iscsi_scsi_task *scsi_task)
{
if ( lun != NULL )
- iscsi_hashmap_remove( lun->tasks, (uint8_t *) &scsi_task->id, sizeof(uint64_t) );
+ iscsi_hashmap_remove( lun->tasks, (uint8_t *) &scsi_task->id, sizeof(scsi_task->id) );
scsi_task->xfer_complete_callback( scsi_task );
}
@@ -5112,6 +5112,50 @@ static int iscsi_scsi_emu_block_write_same(dnbd3_image_t *image, iscsi_scsi_task
}
/**
+ * @brief Initializes a DNBD3 image for an iSCSI SCSI LUN retrieved from its iSCSI SCSI task and optionally check for read access.
+ *
+ * This function also sets the SCSI
+ * status result code accordingly.
+ *
+ * @param[in] scsi_task Pointer to iSCSI SCSI task
+ * to retrieve the iSCSI SCSI LUN
+ * from in order to initialize the
+ * DNBD3 image and also set the SCSI
+ * error code. May NOT be NULL, so
+ * be careful.
+ * @param[in] access Check if read access for DNBD3
+ * image is working.
+ * @retval true The DNBD3 image has been initialized
+ * successfully and is readable.
+ * @retval false The DNBD3 image has NOT been
+ * successfully and is read is not possible.
+ */
+static bool iscsi_scsi_emu_image_init(iscsi_scsi_task *scsi_task, const bool access)
+{
+ // TODO: Handle server and proxy stuff.
+
+ iscsi_scsi_lun *lun = scsi_task->lun;
+
+ if ( lun->image == NULL ) {
+ lun->image = image_getOrLoad( lun->device->name, (uint16_t) lun->id );
+
+ if ( lun->image == NULL ) {
+ iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_MANUAL_INTERVENTION_REQUIRED );
+
+ return false;
+ }
+ }
+
+ if ( access && (!image_ensureOpen( lun->image ) || lun->image->problem.read || (lun->image->virtualFilesize == 0ULL)) ) {
+ iscsi_scsi_task_status_set( scsi_task, ISCSI_SCSI_STATUS_CHECK_COND, ISCSI_SCSI_SENSE_KEY_NOT_READY, ISCSI_SCSI_ASC_LOGICAL_UNIT_NOT_READY, ISCSI_SCSI_ASCQ_MANUAL_INTERVENTION_REQUIRED );
+
+ return false;
+ }
+
+ return true;
+}
+
+/**
* @brief Executes SCSI block emulation on a DNBD3 image.
*
* This function determines the block
@@ -5134,6 +5178,9 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
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;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
lba = iscsi_get_be24(cdb_read_write_6->lba);
xfer_len = cdb_read_write_6->xfer_len;
@@ -5148,6 +5195,9 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
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;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
lba = iscsi_get_be32(cdb_read_write_10->lba);
xfer_len = iscsi_get_be16(cdb_read_write_10->xfer_len);
@@ -5159,6 +5209,9 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
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;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
lba = iscsi_get_be32(cdb_read_write_12->lba);
xfer_len = iscsi_get_be32(cdb_read_write_12->xfer_len);
@@ -5170,6 +5223,9 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
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;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
lba = iscsi_get_be64(cdb_read_write_16->lba);
xfer_len = iscsi_get_be32(cdb_read_write_16->xfer_len);
@@ -5195,11 +5251,17 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
return ISCSI_SCSI_TASK_RUN_COMPLETE;
}
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
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 : {
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
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 ) {
@@ -5235,6 +5297,9 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
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 : {
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
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 ) {
@@ -5286,6 +5351,9 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
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;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
lba = iscsi_get_be32(cdb_sync_cache_10->lba);
xfer_len = iscsi_get_be16(cdb_sync_cache_10->xfer_len);
@@ -5299,6 +5367,9 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
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;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
lba = iscsi_get_be64(cdb_sync_cache_16->lba);
xfer_len = iscsi_get_be32(cdb_sync_cache_16->xfer_len);
@@ -5310,6 +5381,9 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
break;
}
case ISCSI_SCSI_OPCODE_UNMAP : {
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
return iscsi_scsi_emu_block_unmap( lun->image, scsi_task );
break;
@@ -5317,6 +5391,9 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
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;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
lba = iscsi_get_be32(cdb_write_same_10->lba);
xfer_len = iscsi_get_be16(cdb_write_same_10->xfer_len);
@@ -5327,6 +5404,9 @@ static int iscsi_scsi_emu_block_process(iscsi_scsi_task *scsi_task)
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;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
lba = iscsi_get_be64(cdb_write_same_16->lba);
xfer_len = iscsi_get_be32(cdb_write_same_16->xfer_len);
@@ -5596,7 +5676,7 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task
alloc_len += (sizeof(struct iscsi_scsi_vpd_page_design_desc_inquiry_data_packet) + sizeof(struct iscsi_scsi_vpd_page_design_desc_target_port_group_inquiry_data_packet)); // Target Port Group
alloc_len += (sizeof(struct iscsi_scsi_vpd_page_design_desc_inquiry_data_packet) + sizeof(struct iscsi_scsi_vpd_page_design_desc_logical_unit_group_inquiry_data_packet)); // Logical Unit Group
- if ( (alloc_len + sizeof(struct iscsi_scsi_vpd_page_inquiry_data_packet)) > len ) {
+ if ( len < (alloc_len + sizeof(struct iscsi_scsi_vpd_page_inquiry_data_packet)) ) {
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 -1;
@@ -5691,7 +5771,7 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task
alloc_len = (sizeof(iscsi_scsi_vpd_page_ext_inquiry_data_packet) - sizeof(iscsi_scsi_vpd_page_inquiry_data_packet));
- if ( (alloc_len + sizeof(struct iscsi_scsi_vpd_page_inquiry_data_packet)) > len ) {
+ if ( len < (alloc_len + sizeof(struct iscsi_scsi_vpd_page_inquiry_data_packet)) ) {
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 -1;
@@ -5758,7 +5838,7 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task
case ISCSI_SCSI_VPD_PAGE_INQUIRY_DATA_PAGE_CODE_BLOCK_LIMITS : {
iscsi_scsi_vpd_page_block_limits_inquiry_data_packet *vpd_page_block_limits_inquiry_data_pkt = (iscsi_scsi_vpd_page_block_limits_inquiry_data_packet *) vpd_page_inquiry_data_pkt->params;
- if ( (sizeof(struct iscsi_scsi_vpd_page_inquiry_data_packet) + sizeof(struct iscsi_scsi_vpd_page_block_limits_inquiry_data_packet)) > len ) {
+ if ( len < (sizeof(struct iscsi_scsi_vpd_page_inquiry_data_packet) + sizeof(struct iscsi_scsi_vpd_page_block_limits_inquiry_data_packet)) ) {
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 -1;
@@ -5805,7 +5885,7 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task
case ISCSI_SCSI_VPD_PAGE_INQUIRY_DATA_PAGE_CODE_BLOCK_DEV_CHARS : {
iscsi_scsi_vpd_page_block_dev_chars_inquiry_data_packet *vpd_page_block_dev_chars_inquiry_data_pkt = (iscsi_scsi_vpd_page_block_dev_chars_inquiry_data_packet *) vpd_page_inquiry_data_pkt->params;
- if ( (sizeof(struct iscsi_scsi_vpd_page_inquiry_data_packet) + sizeof(struct iscsi_scsi_vpd_page_block_dev_chars_inquiry_data_packet)) > len ) {
+ if ( len < (sizeof(struct iscsi_scsi_vpd_page_inquiry_data_packet) + sizeof(struct iscsi_scsi_vpd_page_block_dev_chars_inquiry_data_packet)) ) {
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 -1;
@@ -5882,7 +5962,7 @@ static int iscsi_scsi_emu_primary_inquiry(dnbd3_image_t *image, iscsi_scsi_task
char image_rev[sizeof(std_inquiry_data_pkt->product_rev_level) + 1];
- sprintf( "%04X", image_rev, image->rid );
+ sprintf( image_rev, "%04X", image->rid );
iscsi_strcpy_pad( image_rev, (char *) std_inquiry_data_pkt->product_rev_level, sizeof(std_inquiry_data_pkt->product_rev_level), ' ' );
uint add_len = (sizeof(struct iscsi_scsi_std_inquiry_data_packet) - sizeof(struct iscsi_scsi_basic_inquiry_data_packet));
@@ -6111,11 +6191,14 @@ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task)
case ISCSI_SCSI_OPCODE_INQUIRY : {
const iscsi_scsi_cdb_inquiry *cdb_inquiry = (iscsi_scsi_cdb_inquiry *) scsi_task->cdb;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
alloc_len = iscsi_get_be16(cdb_inquiry->alloc_len);
len = alloc_len;
- if ( len > 4096U )
- len = 4096U;
+ if ( len < ISCSI_DEFAULT_RECV_DS_LEN )
+ len = ISCSI_DEFAULT_RECV_DS_LEN;
iscsi_scsi_std_inquiry_data_packet *std_inquiry_data_pkt = NULL;
@@ -6157,8 +6240,8 @@ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task)
len = alloc_len;
- if ( len > 4096U )
- len = 4096U;
+ if ( len < ISCSI_DEFAULT_RECV_DS_LEN )
+ len = ISCSI_DEFAULT_RECV_DS_LEN;
iscsi_scsi_report_luns_parameter_data_lun_list_packet *report_luns_parameter_data_pkt = NULL;
@@ -6254,6 +6337,9 @@ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task)
case ISCSI_SCSI_OPCODE_MODESENSE6 : {
const iscsi_scsi_cdb_mode_sense_6 *cdb_mode_sense_6 = (iscsi_scsi_cdb_mode_sense_6 *) scsi_task->cdb;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
alloc_len = cdb_mode_sense_6->alloc_len;
const int dbd = (cdb_mode_sense_6->flags & ISCSI_SCSI_CDB_MODE_SENSE_6_FLAGS_DBD);
@@ -6303,6 +6389,9 @@ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task)
case ISCSI_SCSI_OPCODE_MODESENSE10 : {
const iscsi_scsi_cdb_mode_sense_10 *cdb_mode_sense_10 = (iscsi_scsi_cdb_mode_sense_10 *) scsi_task->cdb;
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
alloc_len = iscsi_get_be16(cdb_mode_sense_10->alloc_len);
const int dbd10 = (cdb_mode_sense_10->flags & ISCSI_SCSI_CDB_MODE_SENSE_10_FLAGS_DBD);
@@ -6393,8 +6482,21 @@ static int iscsi_scsi_emu_primary_process(iscsi_scsi_task *scsi_task)
break;
}
- case ISCSI_SCSI_OPCODE_TESTUNITREADY :
+ case ISCSI_SCSI_OPCODE_TESTUNITREADY : {
+ if ( !iscsi_scsi_emu_image_init( scsi_task, false ) )
+ break;
+
+ scsi_task->pos = 0U;
+ scsi_task->status = ISCSI_SCSI_STATUS_GOOD;
+
+ break;
+ }
case ISCSI_SCSI_OPCODE_STARTSTOPUNIT : {
+ // TODO: Handle eject image and power saving (suspend and standby) modes.
+
+ if ( !iscsi_scsi_emu_image_init( scsi_task, true ) )
+ break;
+
scsi_task->pos = 0U;
scsi_task->status = ISCSI_SCSI_STATUS_GOOD;
@@ -6795,7 +6897,6 @@ iscsi_device *iscsi_device_create(const uint8_t *name, const uint luns, const ui
device->id = 0;
device->flags = 0;
- device->num_ports = 0U;
device->protocol_id = protocol_id;
return device;
@@ -6867,7 +6968,7 @@ iscsi_port *iscsi_device_find_port_by_portal_group_tag(const iscsi_device *devic
* @brief Finds an iSCSI LUN by LUN identifier.
*
* Callback function for each element while iterating
- * through the iSCSI device.\n
+ * through the iSCSI device hash map.\n
* LUNs about to be removed are not returned by this
* callback.
*
@@ -6906,7 +7007,8 @@ int iscsi_device_find_lun_callback(uint8_t *key, const size_t key_size, uint8_t
* hash map.
*
* @param[in] device Pointer to iSCSI device to
- * search in the LUN hash map.
+ * search in the LUN hash map. May NOT be
+ * NULL, so be careful.
* @param[in] lun_id LUN identifier to be searched
* for.
* @return Pointer to found iSCSI LUN or NULL in
@@ -6923,6 +7025,45 @@ iscsi_scsi_lun *iscsi_device_find_lun(iscsi_device *device, const int lun_id)
}
/**
+ * @brief Creates, initializes and adds an iSCSI target port to an iSCSI device.
+ *
+ * This function checks whether the iSCSI
+ * target port already exists for the
+ * device.
+ *
+ * @param[in] device Pointer to iSCSI device to
+ * add the port for. May NOT be NULL, so
+ * be careful.
+ * @param[in] name Pointer to string containing
+ * the name for the iSCSI target port.
+ * NULL is NOT allowed here, take caution.
+ * @param[in] id Unique iSCSI target port
+ * identifier to be used.
+ * @return 0 on successful operation, a
+ * negative error code otherwise.
+ */
+int iscsi_device_port_add(iscsi_device *device, const uint8_t *name, const uint64_t id)
+{
+ if ( iscsi_hashmap_contains( device->ports, (uint8_t *) &id, sizeof(id) ) )
+ return -1;
+
+ iscsi_port *port = iscsi_port_create( name, id, (uint16_t) iscsi_hashmap_size( device->ports ) );
+
+ if ( port == NULL )
+ return -1;
+
+ const int rc = iscsi_hashmap_put( device->ports, (uint8_t *) &port->id, sizeof(port->id), (uint8_t *) port );
+
+ if ( rc < 0 ) {
+ iscsi_port_destroy( port );
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
* @brief Enqueues an iSCSI SCSI task to the first LUN of an iSCSI device.
*
* This function adds an iSCSI SCSI task
@@ -7002,6 +7143,38 @@ static int iscsi_target_node_check_flags(const int flags, const int32_t chap_gro
}
/**
+ * @brief Creates, initializes and adds a portal group to an iSCSI target node.
+ *
+ * Callback function for each element while iterating
+ * through the iSCSI global vector portal group
+ * hash map.
+ *
+ * @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 creates an
+ * empty key assignment.
+ * @param[in,out] user_data Pointer to the iSCSI target
+ * node to be added and may NOT be NULL, so be
+ * careful.
+ * @retval -1 An error occured during adding the
+ * iSCSI portal group to the iSCSI target node.
+ * @retval 0 The iSCSI portal group has been
+ * added successfully.
+ */
+int iscsi_target_node_create_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data)
+{
+ iscsi_target_node *target = (iscsi_target_node *) user_data;
+ iscsi_portal_group *portal_group = (iscsi_portal_group *) value;
+ uint8_t *port_name = iscsi_sprintf_alloc( "%s,t,0x%4.4x", target->device->name, portal_group->tag );
+
+ if ( port_name == NULL )
+ return -1;
+
+ return iscsi_device_port_add( target->device, port_name, (uint64_t) portal_group->tag );
+}
+
+/**
* @brief Creates and initializes an iSCSI target node.
*
* This function also allocates the underlying SCSI
@@ -7078,6 +7251,20 @@ iscsi_target_node *iscsi_target_node_create(const uint8_t *name, const uint8_t *
return NULL;
}
+ const int rc = iscsi_hashmap_iterate( iscsi_globvec->portal_groups, iscsi_target_node_create_callback, (uint8_t *) target );
+
+ if ( rc < 0 ) {
+ iscsi_device_destroy( target->device );
+
+ if ( target->alias != NULL )
+ free( target->alias );
+
+ free( target->name );
+ free( target );
+
+ return NULL;
+ }
+
target->num = index;
target->queue_depth = queue_depth;
target->flags = flags;
@@ -10005,8 +10192,8 @@ static int iscsi_connection_pdu_header_handle_scsi_data_out(iscsi_connection *co
return iscsi_connection_handle_reject( conn, pdu, ISCSI_REJECT_REASON_PROTOCOL_ERR );
// TODO: Implement dif ctx stuff.
- if ( task->buf != NULL ) {
- pdu->ds_cmd_data = (iscsi_scsi_ds_cmd_data *) (task->buf + task->len);
+ if ( task->scsi_task.buf != NULL ) {
+ pdu->ds_cmd_data = (iscsi_scsi_ds_cmd_data *) (task->scsi_task.buf + task->len);
pdu->ds_len = ISCSI_DEFAULT_MAX_RECV_DS_LEN;
} else {
// TODO: Implement dif ctx stuff.
diff --git a/src/server/iscsi.h b/src/server/iscsi.h
index 91cb447..bd6e0b7 100644
--- a/src/server/iscsi.h
+++ b/src/server/iscsi.h
@@ -1334,6 +1334,140 @@ typedef struct __attribute__((packed)) iscsi_scsi_cdb_req_sense {
} iscsi_scsi_cdb_req_sense;
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags: Reply immediately after CDB check (IMMED).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_EXEC_FLAGS_IMMED (1 << 0)
+
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Process the START and LOEJ bits.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_PROC_START_LOEJ_BITS 0x0
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the active power condition (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_ACTIVE 0x0
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the idle_a power condition (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_IDLE_A 0x0
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the idle_b power condition (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_IDLE_B 0x1
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the idle_c power condition (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_IDLE_C 0x2
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the standby_z power condition (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_STANDBY_Z 0x0
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Cause the logical unit to transition to the standby_b power condition (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_STANDBY_Y 0x1
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Initialize and start all of the idle and standby condition timers that are enabled (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_LU_CONTROL 0x0
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Force the idle_a condition timer to be set to zero (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FORCE_IDLE_A_0 0x0
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Force the idle_b condition timer to be set to zero (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FORCE_IDLE_B_0 0x1
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Force the idle_c condition timer to be set to zero (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FORCE_IDLE_C_0 0x2
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Force the standby_z condition timer to be set to zero (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FORCE_STANDBY_Z_0 0x0
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Force the standby_y condition timer to be set to zero (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FORCE_STANDBY_Y_0 0x1
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: First bit of the four bits.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FIRST_BIT 0
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Last bit of the four bits.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_LAST_BIT ((ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FIRST_BIT) + 4 - 1)
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Bit mask.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_LAST_BIT))
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Extracts the power condition modifier bits.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_GET_POWER_COND_MOD(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_LAST_BIT))
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution power condition modifier: Stores into the power condition modifier bits.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_PUT_POWER_COND_MOD(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_POWER_COND_MOD_LAST_BIT))
+
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags: START.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_START (1 << 0)
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags: LOad EJect (LOEJ).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_LOEJ (1 << 1)
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags: Do not flush caches until a power condition that prevents accessing the medium is entered (NO_FLUSH).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_NO_FLUSH (1 << 2)
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Process the START and LOEJ bits (START_VALID).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_START_VALID 0x0
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Cause the logical unit to transition to the active power condition (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_ACTIVE 0x1
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Cause the logical unit to transition to the idle_a to idle_c power conditions (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_IDLE 0x2
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Cause the logical unit to transition to the standby_z and standby_y power conditions (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_STANDBY 0x3
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Obselete.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_OBSELETE 0x5
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Initialize and start all of the idle and standby condition timers that are enabled (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_LU_CONTROL 0x7
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Force the idle_a to idle_c condition timers to be set to zero (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FORCE_IDLE_0 0xA
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Force the standby_z and standby_y condition timers to be set to zero (see SPC5).
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FORCE_STANDBY_0 0xB
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: First bit of the four bits.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FIRST_BIT 4
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Last bit of the four bits.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_LAST_BIT ((ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FIRST_BIT) + 8 - 1)
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Bit mask.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_MASK (ISCSI_BITS_GET_MASK(ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_LAST_BIT))
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Extracts the power condition bits.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_GET_POWER_COND(x) (ISCSI_BITS_GET((x), ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_LAST_BIT))
+
+/// iSCSI SCSI Command Descriptor Block (CDB) for START STOP UNIT command execution flags power condition: Stores into the power condition bits.
+#define ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_PUT_POWER_COND(x) (ISCSI_BITS_PUT((x), ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_FIRST_BIT, ISCSI_SCSI_CDB_START_STOP_UNIT_FLAGS_POWER_COND_LAST_BIT))
+
+
+/**
+ * @brief iSCSI SCSI CDB packet data structure for SCSI START STOP UNIT command.
+ *
+ * There are 6 bytes in the CDB field for this command.
+ */
+typedef struct __attribute__((packed)) iscsi_scsi_cdb_start_stop_unit {
+ /// SCSI opcode.
+ iscsi_scsi_cdb cdb;
+
+ /// Execution flags.
+ int8_t exec_flags;
+
+ /// Reserved for future usage (always MUST be 0 for now).
+ uint8_t reserved;
+
+ /// Power condition modifier.
+ uint8_t power_cond_mod;
+
+ /// Flags.
+ int8_t flags;
+
+ /// Control.
+ uint8_t control;
+} iscsi_scsi_cdb_start_stop_unit;
+
+
/// iSCSI SCSI Command Descriptor Block (CDB) for PERSISTENT RESERVE OUT command service action: Register - Register a reservation key without making a reservation.
#define ISCSI_SCSI_CDB_PR_RESERVE_OUT_ACTION_REGISTER 0x00
@@ -8746,11 +8880,11 @@ typedef struct iscsi_portal_group {
/// Hash map containing all portals associated with this iSCSI group.
iscsi_hashmap *portals;
- /// Reference count.
- int ref_count;
-
/// Tag value for this portal group.
- int tag;
+ uint64_t tag;
+
+ /// Reference count.
+ int ref_count;
/// Portal group flags.
int flags;
@@ -8942,6 +9076,9 @@ void iscsi_portal_destroy(iscsi_portal *portal);
/// iSCSI SCSI Additional Sense Code Qualifier (ASCQ): No access rights.
#define ISCSI_SCSI_ASCQ_NO_ACCESS_RIGHTS 0x02
+/// iSCSI SCSI Additional Sense Code Qualifier (ASCQ): Manual intervention required.
+#define ISCSI_SCSI_ASCQ_MANUAL_INTERVENTION_REQUIRED 0x03
+
/// iSCSI SCSI Additional Sense Code Qualifier (ASCQ): Block reference tag check failed.
#define ISCSI_SCSI_ASCQ_LOGICAL_BLOCK_REF_TAG_CHECK_FAIL 0x03
@@ -9393,9 +9530,6 @@ typedef struct iscsi_device {
/// Flags.
int flags;
- /// Number of ports.
- uint num_ports;
-
/// Protocol identifier.
uint8_t protocol_id;
} iscsi_device;
@@ -9962,9 +10096,6 @@ typedef struct iscsi_task {
/// Associated iSCSI PDU.
iscsi_pdu *pdu;
- /// Buffer to send to initiator.
- uint8_t *buf;
-
/// Buffer position in bytes.
uint pos;
@@ -10106,8 +10237,11 @@ iscsi_port *iscsi_device_find_port_by_portal_group_tag(const iscsi_device *devic
int iscsi_device_find_lun_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Finds an iSCSI LUN by LUN identifier
iscsi_scsi_lun *iscsi_device_find_lun(iscsi_device *device, const int lun_id); // Searches an iSCSI LUN by LUN identifier
+int iscsi_device_port_add(iscsi_device *device, const uint8_t *name, const uint64_t id); // Creates, initializes and adds an iSCSI target port to an iSCSI device
+
void iscsi_device_scsi_task_queue(iscsi_device *device, iscsi_scsi_task *scsi_task); // Enqueues an iSCSI SCSI task to the first LUN of an iSCSI device
+int iscsi_target_node_create_callback(uint8_t *key, const size_t key_size, uint8_t *value, uint8_t *user_data); // Creates, initializes and adds a portal group to an iSCSI target node
iscsi_target_node *iscsi_target_node_create(const uint8_t *name, const uint8_t *alias, const int index, const uint luns, const uint queue_depth, const int flags, const int32_t chap_group, const int header_digest, const int data_digest); // Creates and initializes an iSCSI target node
void iscsi_target_node_destroy(iscsi_target_node *target); // Deallocates all resources acquired by iscsi_target_node_create