/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see .
*/
#include
#include
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-support.h"
#include "iscsi-test-cu.h"
#include
void
test_rtpg_alloc_length(void)
{
int ret, full_size, size, group;
struct scsi_inquiry_standard *std_inq;
struct scsi_report_target_port_groups *report;
logging(LOG_VERBOSE, LOG_BLANK_LINE);
logging(LOG_VERBOSE, "Test of the RTPG command with insufficient buffers");
logging(LOG_VERBOSE, "Checking if the target supports RTPG");
ret = inquiry(sd, &task, 0, 0, 260, EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
std_inq = scsi_datain_unmarshall(task);
CU_ASSERT_NOT_EQUAL(std_inq, NULL);
if (std_inq->tpgs == 0) {
logging(LOG_VERBOSE, "The target does not support RTPG. Skipping RTPG tests.");
scsi_free_scsi_task(task);
task = NULL;
return;
}
scsi_free_scsi_task(task);
task = NULL;
logging(LOG_VERBOSE, "Retrieving 4 bytes of RTPG data");
ret = rtpg(sd, &task, 4, EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
full_size = scsi_datain_getfullsize(task);
scsi_free_scsi_task(task);
task = NULL;
logging(LOG_VERBOSE, "Retrieving all RTPG data (%d bytes)", full_size);
ret = rtpg(sd, &task, full_size, EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
report = scsi_datain_unmarshall(task);
CU_ASSERT_NOT_EQUAL(report, NULL);
/* data size stays the same */
CU_ASSERT_EQUAL(full_size, scsi_datain_getfullsize(task));
/* The test assumes that groups are reported in the same order for any buffer size. */
size = 4; /* offset of the 1st target port group descriptor */
for (group = 0; group < report->num_groups; ++group) {
const int group_descriptor_size = 8;
const int port_descriptor_size = 4;
struct scsi_report_target_port_groups *report_partial = NULL;
struct scsi_task *task_partial = NULL;
int i;
logging(LOG_VERBOSE, "Buffer boundary cuts descriptor of group %d in half", group);
size += group_descriptor_size / 2;
ret = rtpg(sd, &task_partial, size, EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
report_partial = scsi_datain_unmarshall(task_partial);
CU_ASSERT_NOT_EQUAL(report_partial, NULL);
/* cut group not unmarshalled */
CU_ASSERT_EQUAL(group, report_partial->num_groups);
/* previous groups unmarshalled along with their ports */
for (i = 0; i < group; ++i) {
CU_ASSERT_EQUAL(report_partial->groups[i].retrieved_port_count,
report_partial->groups[i].port_count);
CU_ASSERT_EQUAL(report_partial->groups[i].retrieved_port_count,
report->groups[i].retrieved_port_count);
}
scsi_free_scsi_task(task_partial);
task_partial = NULL;
logging(LOG_VERBOSE, "Buffer boundary at the end of descriptor of group %d", group);
size += group_descriptor_size / 2;
ret = rtpg(sd, &task_partial, size, EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
report_partial = scsi_datain_unmarshall(task_partial);
CU_ASSERT_NOT_EQUAL(report_partial, NULL);
/* group unmarshalled */
CU_ASSERT_EQUAL(group + 1, report_partial->num_groups);
/* previous groups unmarshalled along with their ports */
for (i = 0; i < group; ++i) {
CU_ASSERT_EQUAL(report_partial->groups[i].retrieved_port_count,
report_partial->groups[i].port_count);
CU_ASSERT_EQUAL(report_partial->groups[i].retrieved_port_count,
report->groups[i].retrieved_port_count);
}
/* no retrieved ports for the current group */
CU_ASSERT_EQUAL(report_partial->groups[group].retrieved_port_count, 0);
CU_ASSERT_EQUAL(report_partial->groups[group].port_count,
report->groups[group].port_count);
scsi_free_scsi_task(task_partial);
task_partial = NULL;
if (report->groups[group].port_count == 0) {
continue;
}
size += port_descriptor_size;
if (report->groups[group].port_count > 1) {
logging(LOG_VERBOSE, "Just one port of group %d fits the buffer", group);
ret = rtpg(sd, &task_partial, size, EXPECT_STATUS_GOOD);
CU_ASSERT_EQUAL(ret, 0);
report_partial = scsi_datain_unmarshall(task_partial);
CU_ASSERT_NOT_EQUAL(report_partial, NULL);
/* group unmarshalled */
CU_ASSERT_EQUAL(group + 1, report_partial->num_groups);
/* previous groups unmarshalled along with their ports */
for (i = 0; i < group; ++i) {
CU_ASSERT_EQUAL(report_partial->groups[i].retrieved_port_count,
report_partial->groups[i].port_count);
CU_ASSERT_EQUAL(report_partial->groups[i].retrieved_port_count,
report->groups[i].retrieved_port_count);
}
/* 1 retrieved port for the current group */
CU_ASSERT_EQUAL(report_partial->groups[group].retrieved_port_count, 1);
CU_ASSERT_EQUAL(report_partial->groups[group].port_count,
report->groups[group].port_count);
scsi_free_scsi_task(task_partial);
task_partial = NULL;
size += port_descriptor_size * (report->groups[group].port_count - 1);
}
}
scsi_free_scsi_task(task);
task = NULL;
};