Files
libiscsi/test-tool/1040_saturate_maxcmdsn.c
Ronnie Sahlberg efc556e2e9 TESTS: Create a test that tries to overflow the maxcmdsn counter
so that i/o from the initiator stops flowing and are just queued locally
until teh cmdsn window opens up again.

Send a lot of writes that block until we have processed the R2T
back from the target and verify we can still make process when we
have saturated the cmdsn window and are also blocked waiting for R2Ts.
2012-11-27 19:51:22 -08:00

136 lines
3.6 KiB
C

/*
Copyright (C) 2012 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <arpa/inet.h>
#include "iscsi.h"
#include "iscsi-private.h"
#include "scsi-lowlevel.h"
#include "iscsi-test.h"
static int num_cmds_in_flight;
static void test_cb(struct iscsi_context *iscsi _U_, int status _U_,
void *command_data _U_, void *private_data)
{
struct iscsi_async_state *state = private_data;
if (--num_cmds_in_flight == 0) {
state->finished = 1;
}
}
int T1040_saturate_maxcmdsn(const char *initiator, const char *url, int data_loss, int show_info)
{
struct iscsi_context *iscsi;
struct scsi_task *task;
struct scsi_readcapacity16 *rc16;
int i, ret, lun;
uint32_t block_size;
unsigned char data[4096 * 2];
struct iscsi_async_state test_state;
printf("1040_saturate_maxcmdsn:\n");
printf("=======================\n");
if (show_info) {
printf("Test sending so many commands we saturate maxcmdsn we do recover eventually\n");
printf("1, Send 1024 commands in one go and make sure we eventually finish the queue of commands in flight\n");
printf("\n");
return 0;
}
iscsi = iscsi_context_login(initiator, url, &lun);
if (iscsi == NULL) {
printf("Failed to login to target\n");
return -1;
}
/* find the size of the LUN */
task = iscsi_readcapacity16_sync(iscsi, lun);
if (task == NULL) {
printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi));
ret = -1;
goto finished;
}
if (task->status != SCSI_STATUS_GOOD) {
printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto finished;
}
rc16 = scsi_datain_unmarshall(task);
if (rc16 == NULL) {
printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto finished;
}
block_size = rc16->block_length;
scsi_free_scsi_task(task);
if (!data_loss) {
printf("--dataloss flag is not set. Skipping test\n");
ret = -2;
goto finished;
}
ret = 0;
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO;
iscsi->target_max_recv_data_segment_length = block_size;
printf("Send 1024 Writes each needing a R2T so that we saturate the maxcmdsn queue ... ");
/* we dont want autoreconnect since some targets will drop the
* on this condition.
*/
iscsi_set_noautoreconnect(iscsi, 1);
for (i = 0; i < 1024; i++) {
num_cmds_in_flight++;
task = iscsi_write10_task(iscsi, lun, 0, data, 2 * block_size, block_size,
0, 0, 0, 0, 0,
test_cb, &test_state);
if (task == NULL) {
printf("[FAILED]\n");
printf("Failed to send WRITE10 command: %s\n", iscsi_get_error(iscsi));
ret++;
goto test2;
}
}
test_state.task = task;
test_state.finished = 0;
test_state.status = 0;
wait_until_test_finished(iscsi, &test_state);
if (num_cmds_in_flight != 0) {
printf("[FAILED]\n");
printf("Did not complete all I/O before deadline.\n");
ret++;
goto test2;
}
printf("[OK]\n");
test2:
finished:
iscsi_destroy_context(iscsi);
return ret;
}