RTPG support

Implementing support of the Report Target Port Groups command.

Tested on Ubuntu against Pure Storage Flash Array
using designated unit tests and new iscsi-rtpg utility

./iscsi-rtpg  -i iqn.2005-03.org.open-iscsi:6feb2db21ea iscsi://192.168.1.12/iqn.2010-06.com.purestorage:flasharray.4e8d52d82e4b2c0f/1
RTPG retrieved 2 groups
Group 0x0000: preferred 0, format 0x00, ALUA state ACTIVE-OPTIMIZED,flags 0x8f, status code 0x02, port count 65
Ports: [ 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf 0x10 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c
0x4d 0x4e 0x4f 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58 0x59 0x5a 0x5b 0x5c 0x5d 0x5e 0x5f 0x60 0x61 0x62 0x63 0x64 0x65 0x66 0x67
0x68 0x69 0x6a 0x6b 0x6c 0x6d 0x6e 0x6f 0x70 0x71]
Group 0x0001: preferred 0, format 0x00, ALUA state ACTIVE-OPTIMIZED,flags 0x8f, status code 0x02, port count 65
Ports: [ 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 0x20 0x72 0x73 0x74 0x75 0x76 0x77 0x78 0x79 0x7a
0x7b 0x7c 0x7d 0x7e 0x7f 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 0x90 0x91 0x92 0x93 0x94 0x95
0x96 0x97 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f 0xa0 0xa1 0xa2]
This commit is contained in:
Anatoliy Glagolev
2025-07-01 15:34:37 -06:00
parent e7c44b802f
commit 19d05ab7a7
12 changed files with 664 additions and 1 deletions

View File

@@ -210,6 +210,7 @@ iscsi_writeverify16_iov_sync
iscsi_writeverify16_iov_task
iscsi_writeverify16_sync
iscsi_writeverify16_task
scsi_alua_state_to_str
scsi_association_to_str
scsi_cdb_compareandwrite
scsi_cdb_extended_copy
@@ -237,6 +238,7 @@ scsi_cdb_readtoc
scsi_cdb_receive_copy_results
scsi_cdb_release6
scsi_cdb_report_supported_opcodes
scsi_cdb_report_target_port_groups
scsi_cdb_reserve6
scsi_cdb_sanitize
scsi_cdb_serviceactionin16

View File

@@ -1172,11 +1172,87 @@ scsi_maintenancein_datain_getfullsize(struct scsi_task *task)
task_get_uint16(task, 2);
}
return -1;
case SCSI_REPORT_TARGET_PORT_GROUPS:
return task_get_uint32(task, 0) + 4;
default:
return -1;
}
}
static struct scsi_report_target_port_groups *
scsi_report_target_port_groups_unmarshal(struct scsi_task *task)
{
int const group_descriptor_size = 8;
int const port_descriptor_size = 4;
struct scsi_report_target_port_groups *rtpg = NULL;
uint16_t *port = NULL;
int group_count, port_count, i, j, k;
if (task->datain.size < 4) {
return NULL;
}
port_count= 0;
group_count = 0;
for (j = 0; j < 2; ++j) {
/* 1st pass counts groups and ports, then allocates data structs to fit those;
* 2nd pass populates the allocated data structs.*/
for (i = 4; i< task->datain.size; ) {
uint8_t current_port_count;
if (task->datain.size - i < group_descriptor_size) {
break;
}
current_port_count = task_get_uint8(task, i + 7);
if (j == 1) {
rtpg->groups[group_count].port_count = current_port_count;
rtpg->groups[group_count].byte0 = task_get_uint8(task, i);
rtpg->groups[group_count].flags = task_get_uint8(task, i + 1);
rtpg->groups[group_count].port_group = task_get_uint16(task, i + 2);
rtpg->groups[group_count].status_code = task_get_uint8(task, i + 5);
rtpg->groups[group_count].ports = port;
}
i += group_descriptor_size;
for (k = 0; k < current_port_count &&
i + (k + 1) * port_descriptor_size <= task->datain.size; ++k) {
if (j == 1) {
rtpg->groups[group_count].ports[k] =
task_get_uint16(task, i + k * port_descriptor_size + 2);
}
}
if (j == 1) {
rtpg->groups[group_count].retrieved_port_count = k;
port += k;
}
++group_count;
port_count += k;
i += k * port_descriptor_size;
}
if (j == 0) {
rtpg = scsi_malloc(
task,
sizeof(struct scsi_report_target_port_groups) +
sizeof(struct scsi_target_port_group) * group_count +
sizeof(uint16_t) * port_count);
if (rtpg == NULL) {
return NULL;
}
port = (uint16_t *)((uint8_t *)rtpg +
sizeof(struct scsi_report_target_port_groups) +
sizeof(struct scsi_target_port_group) * group_count);
rtpg->num_groups = group_count;
group_count = 0;
port_count = 0;
}
}
return rtpg;
}
/*
* maintenance_in unmarshall
*/
@@ -1283,11 +1359,43 @@ scsi_maintenancein_datain_unmarshall(struct scsi_task *task)
}
return rsoc_one;
}
case SCSI_REPORT_TARGET_PORT_GROUPS:
return scsi_report_target_port_groups_unmarshal(task);
};
return NULL;
}
/*
* MAINTENANCE In / Report Target Port Groups
*/
struct scsi_task *
scsi_cdb_report_target_port_groups(uint32_t alloc_len)
{
struct scsi_task *task;
task = malloc(sizeof(struct scsi_task));
if (task == NULL) {
return NULL;
}
memset(task, 0, sizeof(struct scsi_task));
task->cdb[0] = SCSI_OPCODE_MAINTENANCE_IN;
task->cdb[1] = SCSI_REPORT_TARGET_PORT_GROUPS;
scsi_set_uint32(&task->cdb[6], alloc_len);
task->cdb_size = 12;
if (alloc_len != 0) {
task->xfer_dir = SCSI_XFER_READ;
} else {
task->xfer_dir = SCSI_XFER_NONE;
}
task->expxferlen = alloc_len;
return task;
}
/*
* MAINTENANCE In / Read Supported Op Codes
*/
@@ -4287,6 +4395,29 @@ scsi_designator_type_to_str(int type)
return "unknown";
}
const char *
scsi_alua_state_to_str(uint8_t state)
{
switch (state) {
case SCSI_ALUA_ACTIVE_OPTIMIZED:
return "ACTIVE-OPTIMIZED";
case SCSI_ALUA_ACTIVE_NONOPTIMIZED:
return "ACTIVE-NONOPTIMIZED";
case SCSI_ALUA_STANDBY:
return "STANDBY";
case SCSI_ALUA_UNAVAILABLE:
return "UNAVAILABLE";
case SCSI_ALUA_LOGICAL_BLOCK_DEPENDENT:
return "BLOCK-DEPENDENT";
case SCSI_ALUA_OFFLINE:
return "OFFLINE";
case SCSI_ALUA_TRANSITIONING:
return "TRANSITIONING";
}
return "unknown";
}
void
scsi_set_task_private_ptr(struct scsi_task *task, void *ptr)
{