Merge with upstream

This commit is contained in:
Jon Grimm
2012-10-25 12:56:26 -05:00
22 changed files with 1000 additions and 105 deletions

View File

@@ -37,9 +37,10 @@ lib_libiscsi_la_LDFLAGS = \
# libiscsi utilities # libiscsi utilities
if PROGRAMS if PROGRAMS
bin_PROGRAMS += bin/iscsi-inq bin/iscsi-ls bin_PROGRAMS += bin/iscsi-inq bin/iscsi-ls bin/iscsi-readcapacity16
bin_iscsi_inq_SOURCES = src/iscsi-inq.c bin_iscsi_inq_SOURCES = src/iscsi-inq.c
bin_iscsi_ls_SOURCES = src/iscsi-ls.c bin_iscsi_ls_SOURCES = src/iscsi-ls.c
bin_iscsi_readcapacity16_SOURCES = src/iscsi-readcapacity16.c
# Other examples # Other examples
@@ -138,11 +139,13 @@ bin_iscsi_test_SOURCES = test-tool/iscsi-test.c \
test-tool/0421_reserve6_lun_reset.c \ test-tool/0421_reserve6_lun_reset.c \
test-tool/0422_reserve6_logout.c \ test-tool/0422_reserve6_logout.c \
test-tool/0423_reserve6_sessionloss.c \ test-tool/0423_reserve6_sessionloss.c \
test-tool/0424_reserve6_target_reset.c \
test-tool/0430_report_all_supported_ops.c \ test-tool/0430_report_all_supported_ops.c \
\ \
test-tool/1000_cmdsn_invalid.c \ test-tool/1000_cmdsn_invalid.c \
test-tool/1010_datasn_invalid.c \ test-tool/1010_datasn_invalid.c \
test-tool/1020_bufferoffset_invalid.c test-tool/1020_bufferoffset_invalid.c \
test-tool/1030_unsolicited_data_overflow.c
endif endif

View File

@@ -65,6 +65,7 @@ struct iscsi_context {
const char *initiator_name; const char *initiator_name;
const char *target_name; const char *target_name;
const char *target_address; /* If a redirect */ const char *target_address; /* If a redirect */
const char *connected_portal;
const char *alias; const char *alias;
const char *user; const char *user;
@@ -84,6 +85,12 @@ struct iscsi_context {
int fd; int fd;
int is_connected; int is_connected;
int tcp_user_timeout;
int tcp_keepcnt;
int tcp_keepintvl;
int tcp_keepidle;
int tcp_syncnt;
int current_phase; int current_phase;
int next_phase; int next_phase;
#define ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP 0 #define ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP 0
@@ -120,6 +127,7 @@ struct iscsi_context {
const char *portal; const char *portal;
int no_auto_reconnect; int no_auto_reconnect;
int reconnect_deferred; int reconnect_deferred;
int debug;
}; };
#define ISCSI_PDU_IMMEDIATE 0x40 #define ISCSI_PDU_IMMEDIATE 0x40
@@ -274,7 +282,6 @@ unsigned long crc32c(char *buf, int len);
struct scsi_task *iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu); struct scsi_task *iscsi_scsi_get_task_from_pdu(struct iscsi_pdu *pdu);
int iscsi_reconnect(struct iscsi_context *iscsi);
void iscsi_set_noautoreconnect(struct iscsi_context *iscsi, int state); void iscsi_set_noautoreconnect(struct iscsi_context *iscsi, int state);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -231,6 +231,7 @@ enum scsi_status {
SCSI_STATUS_GOOD = 0, SCSI_STATUS_GOOD = 0,
SCSI_STATUS_CHECK_CONDITION = 2, SCSI_STATUS_CHECK_CONDITION = 2,
SCSI_STATUS_RESERVATION_CONFLICT = 0x18, SCSI_STATUS_RESERVATION_CONFLICT = 0x18,
SCSI_STATUS_REDIRECT = 0x101,
SCSI_STATUS_CANCELLED = 0x0f000000, SCSI_STATUS_CANCELLED = 0x0f000000,
SCSI_STATUS_ERROR = 0x0f000001 SCSI_STATUS_ERROR = 0x0f000001
}; };
@@ -332,6 +333,15 @@ EXTERN int iscsi_full_connect_sync(struct iscsi_context *iscsi, const char *port
*/ */
EXTERN int iscsi_disconnect(struct iscsi_context *iscsi); EXTERN int iscsi_disconnect(struct iscsi_context *iscsi);
/*
* Disconnect a connection to a target and try to reconnect.
*
* Returns:
* 0 reconnect was successful
* <0 error
*/
EXTERN int iscsi_reconnect(struct iscsi_context *iscsi);
/* /*
* Asynchronous call to perform an ISCSI login. * Asynchronous call to perform an ISCSI login.
* *
@@ -956,6 +966,53 @@ iscsi_scsi_task_cancel(struct iscsi_context *iscsi,
EXTERN void EXTERN void
iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi); iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi);
#define DPRINTF(iscsi,level,fmt,args...) \
do { \
if ((iscsi)->debug >= level) { \
fprintf(stderr,"libiscsi: "); \
fprintf(stderr, (fmt), ##args); \
if (iscsi->target_name) { \
fprintf(stderr," [%s]",iscsi->target_name); \
} \
fprintf(stderr,"\n"); \
} \
} while (0);
/*
* This function is to set the debugging level (0=disabled).
*/
EXTERN void
iscsi_set_debug(struct iscsi_context *iscsi, int level);
/*
* This function is to set the TCP_USER_TIMEOUT option. It has to be called after iscsi
* context creation. The value given in ms is then applied each time a new socket is created.
*/
EXTERN void
iscsi_set_tcp_user_timeout(struct iscsi_context *iscsi, int timeout_ms);
/*
* This function is to set the TCP_KEEPIDLE option. It has to be called after iscsi
* context creation.
*/
EXTERN void
iscsi_set_tcp_keepidle(struct iscsi_context *iscsi, int value);
/*
* This function is to set the TCP_KEEPCNT option. It has to be called after iscsi
* context creation.
*/
EXTERN void
iscsi_set_tcp_keepcnt(struct iscsi_context *iscsi, int value);
/*
* This function is to set the TCP_KEEPINTVL option. It has to be called after iscsi
* context creation.
*/
EXTERN void
iscsi_set_tcp_keepintvl(struct iscsi_context *iscsi, int value);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -24,6 +24,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <time.h>
#include "slist.h" #include "slist.h"
#include "iscsi.h" #include "iscsi.h"
#include "iscsi-private.h" #include "iscsi-private.h"
@@ -35,6 +36,10 @@ struct connect_task {
int lun; int lun;
}; };
static void
iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data _U_,
void *private_data);
static void static void
iscsi_testunitready_cb(struct iscsi_context *iscsi, int status, iscsi_testunitready_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *private_data) void *command_data, void *private_data)
@@ -82,6 +87,14 @@ iscsi_login_cb(struct iscsi_context *iscsi, int status, void *command_data _U_,
{ {
struct connect_task *ct = private_data; struct connect_task *ct = private_data;
if (status == SCSI_STATUS_REDIRECT && iscsi->target_address) {
iscsi_disconnect(iscsi);
if (iscsi_connect_async(iscsi, iscsi->target_address, iscsi_connect_cb, iscsi->connect_data) != 0) {
return;
}
return;
}
if (status != 0) { if (status != 0) {
ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data); ct->cb(iscsi, SCSI_STATUS_ERROR, NULL, ct->private_data);
return; return;
@@ -158,6 +171,8 @@ int iscsi_reconnect(struct iscsi_context *old_iscsi)
{ {
struct iscsi_context *iscsi = old_iscsi; struct iscsi_context *iscsi = old_iscsi;
DPRINTF(iscsi,2,"reconnect initiated");
/* This is mainly for tests, where we do not want to automatically /* This is mainly for tests, where we do not want to automatically
reconnect but rather want the commands to fail with an error reconnect but rather want the commands to fail with an error
if the target drops the session. if the target drops the session.
@@ -195,6 +210,9 @@ int iscsi_reconnect(struct iscsi_context *old_iscsi)
return 0; return 0;
} }
int retry = 0;
srand (time(NULL)^getpid());
try_again: try_again:
iscsi = iscsi_create_context(old_iscsi->initiator_name); iscsi = iscsi_create_context(old_iscsi->initiator_name);
@@ -214,9 +232,27 @@ try_again:
iscsi->portal = strdup(old_iscsi->portal); iscsi->portal = strdup(old_iscsi->portal);
iscsi->debug = old_iscsi->debug;
iscsi->tcp_user_timeout = old_iscsi->tcp_user_timeout;
iscsi->tcp_keepidle = old_iscsi->tcp_keepidle;
iscsi->tcp_keepcnt = old_iscsi->tcp_keepcnt;
iscsi->tcp_keepintvl = old_iscsi->tcp_keepintvl;
iscsi->tcp_syncnt = old_iscsi->tcp_syncnt;
if (iscsi_full_connect_sync(iscsi, iscsi->portal, iscsi->lun) != 0) { if (iscsi_full_connect_sync(iscsi, iscsi->portal, iscsi->lun) != 0) {
int backoff=retry;
if (backoff > 10) {
backoff+=rand()%10;
backoff-=5;
}
if (backoff > 30) {
backoff=30;
}
DPRINTF(iscsi,1,"reconnect try %d failed, waiting %d seconds",retry,backoff);
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
sleep(1); sleep(backoff);
retry++;
goto try_again; goto try_again;
} }
@@ -249,6 +285,15 @@ try_again:
continue; continue;
} }
if (pdu->flags & ISCSI_PDU_DELETE_WHEN_SENT) {
/* We dont want to requeue things like DATA-OUT since these guys
* will be reissued automatically anyway once the corresponding
* write command is replayed.
*/
iscsi_free_pdu(old_iscsi, pdu);
continue;
}
pdu->itt = iscsi->itt++; pdu->itt = iscsi->itt++;
iscsi_pdu_set_itt(pdu, pdu->itt); iscsi_pdu_set_itt(pdu, pdu->itt);

View File

@@ -71,6 +71,34 @@ iscsi_create_context(const char *initiator_name)
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES; iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES;
iscsi->want_header_digest = ISCSI_HEADER_DIGEST_NONE_CRC32C; iscsi->want_header_digest = ISCSI_HEADER_DIGEST_NONE_CRC32C;
iscsi->tcp_keepcnt=3;
iscsi->tcp_keepintvl=30;
iscsi->tcp_keepidle=30;
if (getenv("LIBISCSI_DEBUG") != NULL) {
iscsi_set_debug(iscsi,atoi(getenv("LIBISCSI_DEBUG")));
}
if (getenv("LIBISCSI_TCP_USER_TIMEOUT") != NULL) {
iscsi_set_tcp_user_timeout(iscsi,atoi(getenv("LIBISCSI_TCP_USER_TIMEOUT")));
}
if (getenv("LIBISCSI_TCP_KEEPCNT") != NULL) {
iscsi_set_tcp_keepcnt(iscsi,atoi(getenv("LIBISCSI_TCP_KEEPCNT")));
}
if (getenv("LIBISCSI_TCP_KEEPINTVL") != NULL) {
iscsi_set_tcp_keepintvl(iscsi,atoi(getenv("LIBISCSI_TCP_KEEPINTVL")));
}
if (getenv("LIBISCSI_TCP_KEEPIDLE") != NULL) {
iscsi_set_tcp_keepidle(iscsi,atoi(getenv("LIBISCSI_TCP_KEEPIDLE")));
}
if (getenv("LIBISCSI_TCP_SYNCNT") != NULL) {
iscsi_set_tcp_syncnt(iscsi,atoi(getenv("LIBISCSI_TCP_SYNCNT")));
}
return iscsi; return iscsi;
} }
@@ -244,6 +272,11 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
free(discard_const(iscsi->chap_c)); free(discard_const(iscsi->chap_c));
iscsi->chap_c = NULL; iscsi->chap_c = NULL;
if (iscsi->connected_portal != NULL) {
free(discard_const(iscsi->connected_portal));
iscsi->connected_portal = NULL;
}
iscsi->connect_data = NULL; iscsi->connect_data = NULL;
free(iscsi); free(iscsi);
@@ -251,8 +284,6 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
return 0; return 0;
} }
void void
iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...) iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...)
{ {
@@ -270,9 +301,18 @@ iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...)
free(iscsi->error_string); free(iscsi->error_string);
iscsi->error_string = str; iscsi->error_string = str;
va_end(ap); va_end(ap);
DPRINTF(iscsi,1,"%s",str);
} }
void
iscsi_set_debug(struct iscsi_context *iscsi, int level)
{
iscsi->debug = level;
DPRINTF(iscsi,2,"set debug level to %d",level);
}
const char * const char *
iscsi_get_error(struct iscsi_context *iscsi) iscsi_get_error(struct iscsi_context *iscsi)
@@ -547,8 +587,7 @@ iscsi_destroy_url(struct iscsi_url *iscsi_url)
int int
iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi, iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi,
const char *user, const char *user, const char *passwd)
const char *passwd)
{ {
free(discard_const(iscsi->user)); free(discard_const(iscsi->user));
iscsi->user = strdup(user); iscsi->user = strdup(user);

View File

@@ -64,6 +64,7 @@ iscsi_scsi_command_sync
iscsi_scsi_task_cancel iscsi_scsi_task_cancel
iscsi_service iscsi_service
iscsi_set_alias iscsi_set_alias
iscsi_set_debug
iscsi_set_header_digest iscsi_set_header_digest
iscsi_set_initiator_username_pwd iscsi_set_initiator_username_pwd
iscsi_set_isid_en iscsi_set_isid_en
@@ -73,6 +74,11 @@ iscsi_set_isid_reserved
iscsi_set_session_type iscsi_set_session_type
iscsi_set_targetname iscsi_set_targetname
iscsi_set_tcp_keepalive iscsi_set_tcp_keepalive
iscsi_set_tcp_user_timeout
iscsi_set_tcp_keepidle
iscsi_set_tcp_keepcnt
iscsi_set_tcp_keepintvl
iscsi_set_tcp_syncnt
iscsi_startstopunit_sync iscsi_startstopunit_sync
iscsi_startstopunit_task iscsi_startstopunit_task
iscsi_synchronizecache10_sync iscsi_synchronizecache10_sync

View File

@@ -62,6 +62,7 @@ iscsi_scsi_command_sync
iscsi_scsi_task_cancel iscsi_scsi_task_cancel
iscsi_service iscsi_service
iscsi_set_alias iscsi_set_alias
iscsi_set_debug
iscsi_set_header_digest iscsi_set_header_digest
iscsi_set_initiator_username_pwd iscsi_set_initiator_username_pwd
iscsi_set_isid_en iscsi_set_isid_en
@@ -71,6 +72,11 @@ iscsi_set_isid_reserved
iscsi_set_session_type iscsi_set_session_type
iscsi_set_targetname iscsi_set_targetname
iscsi_set_tcp_keepalive iscsi_set_tcp_keepalive
iscsi_set_tcp_user_timeout
iscsi_set_tcp_keepidle
iscsi_set_tcp_keepcnt
iscsi_set_tcp_keepintvl
iscsi_set_tcp_syncnt
iscsi_startstopunit_sync iscsi_startstopunit_sync
iscsi_startstopunit_task iscsi_startstopunit_task
iscsi_synchronizecache10_sync iscsi_synchronizecache10_sync

View File

@@ -1088,6 +1088,13 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
size -= len + 1; size -= len + 1;
} }
if (status == SCSI_STATUS_REDIRECT && iscsi->target_address) {
DPRINTF(iscsi,2,"target requests redirect to %s",iscsi->target_address);
pdu->callback(iscsi, SCSI_STATUS_REDIRECT, NULL,
pdu->private_data);
return 0;
}
if (status != 0) { if (status != 0) {
iscsi_set_error(iscsi, "Failed to log in to target. Status: %s(%d)", iscsi_set_error(iscsi, "Failed to log in to target. Status: %s(%d)",
login_error_str(status), status); login_error_str(status), status);

View File

@@ -242,8 +242,8 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
if (iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_YES) { if (iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_YES) {
uint32_t len = data.size; uint32_t len = data.size;
if (len > iscsi->target_max_recv_data_segment_length) { if (len > iscsi->first_burst_length) {
len = iscsi->target_max_recv_data_segment_length; len = iscsi->first_burst_length;
} }
if (iscsi_pdu_add_data(iscsi, pdu, data.data, len) if (iscsi_pdu_add_data(iscsi, pdu, data.data, len)
@@ -302,7 +302,7 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
} }
/* Can we send some unsolicited data ? */ /* Can we send some unsolicited data ? */
if (pdu->nidata.size != 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO) { if (pdu->nidata.size != 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO && iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_NO) {
uint32_t len = pdu->nidata.size - offset; uint32_t len = pdu->nidata.size - offset;
if (len > iscsi->first_burst_length) { if (len > iscsi->first_burst_length) {

View File

@@ -76,8 +76,8 @@ scsi_malloc(struct scsi_task *task, size_t size)
} }
struct value_string { struct value_string {
int value; int value;
const char *string; const char *string;
}; };
static const char * static const char *
@@ -1399,7 +1399,7 @@ scsi_cdb_compareandwrite(uint64_t lba, uint32_t xferlen, int blocksize, int wrpr
task->xfer_dir = SCSI_XFER_WRITE; task->xfer_dir = SCSI_XFER_WRITE;
} else { } else {
task->xfer_dir = SCSI_XFER_NONE; task->xfer_dir = SCSI_XFER_NONE;
} }
task->expxferlen = xferlen; task->expxferlen = xferlen;
task->params.compareandwrite.lba = lba; task->params.compareandwrite.lba = lba;
@@ -2508,9 +2508,9 @@ scsi_get_task_private_ptr(struct scsi_task *task)
struct scsi_data_buffer { struct scsi_data_buffer {
struct scsi_data_buffer *next; struct scsi_data_buffer *next;
uint32_t len; uint32_t len;
unsigned char *data; unsigned char *data;
}; };
int int

View File

@@ -58,6 +58,52 @@ static void set_nonblocking(int fd)
#endif #endif
} }
int set_tcp_sockopt(int sockfd, int optname, int value)
{
int level;
#if defined(__FreeBSD__) || defined(__sun)
struct protoent *buf;
if ((buf = getprotobyname("tcp")) != NULL)
level = buf->p_proto;
else
return -1;
#else
level = SOL_TCP;
#endif
return setsockopt(sockfd, level, optname, &value, sizeof(value));
}
#ifndef TCP_USER_TIMEOUT
#define TCP_USER_TIMEOUT 18
#endif
int set_tcp_user_timeout(struct iscsi_context *iscsi)
{
if (set_tcp_sockopt(iscsi->fd, TCP_USER_TIMEOUT, iscsi->tcp_user_timeout) != 0) {
iscsi_set_error(iscsi, "TCP: Failed to set tcp user timeout. Error %s(%d)", strerror(errno), errno);
return -1;
}
DPRINTF(iscsi,3,"TCP_USER_TIMEOUT set to %d",iscsi->tcp_user_timeout);
return 0;
}
#ifndef TCP_SYNCNT
#define TCP_SYNCNT 7
#endif
int set_tcp_syncnt(struct iscsi_context *iscsi)
{
if (set_tcp_sockopt(iscsi->fd, TCP_SYNCNT, iscsi->tcp_syncnt) != 0) {
iscsi_set_error(iscsi, "TCP: Failed to set tcp syn retries. Error %s(%d)", strerror(errno), errno);
return -1;
}
DPRINTF(iscsi,3,"TCP_SYNCNT set to %d",iscsi->tcp_syncnt);
return 0;
}
int int
iscsi_connect_async(struct iscsi_context *iscsi, const char *portal, iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
iscsi_command_cb cb, void *private_data) iscsi_command_cb cb, void *private_data)
@@ -68,6 +114,8 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
struct addrinfo *ai = NULL; struct addrinfo *ai = NULL;
int socksize; int socksize;
DPRINTF(iscsi,2,"connecting to portal %s",portal);
if (iscsi->fd != -1) { if (iscsi->fd != -1) {
iscsi_set_error(iscsi, iscsi_set_error(iscsi,
"Trying to connect but already connected."); "Trying to connect but already connected.");
@@ -158,6 +206,16 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
set_nonblocking(iscsi->fd); set_nonblocking(iscsi->fd);
iscsi_set_tcp_keepalive(iscsi, iscsi->tcp_keepidle, iscsi->tcp_keepcnt, iscsi->tcp_keepintvl);
if (iscsi->tcp_user_timeout > 0) {
set_tcp_user_timeout(iscsi);
}
if (iscsi->tcp_syncnt > 0) {
set_tcp_syncnt(iscsi);
}
if (connect(iscsi->fd, ai->ai_addr, socksize) != 0 if (connect(iscsi->fd, ai->ai_addr, socksize) != 0
&& errno != EINPROGRESS) { && errno != EINPROGRESS) {
iscsi_set_error(iscsi, "Connect failed with errno : " iscsi_set_error(iscsi, "Connect failed with errno : "
@@ -169,6 +227,10 @@ iscsi_connect_async(struct iscsi_context *iscsi, const char *portal,
} }
freeaddrinfo(ai); freeaddrinfo(ai);
if (iscsi->connected_portal) free(discard_const(iscsi->connected_portal));
iscsi->connected_portal=strdup(portal);
return 0; return 0;
} }
@@ -183,6 +245,9 @@ iscsi_disconnect(struct iscsi_context *iscsi)
close(iscsi->fd); close(iscsi->fd);
if (iscsi->connected_portal)
DPRINTF(iscsi,2,"disconnected from portal %s",iscsi->connected_portal);
iscsi->fd = -1; iscsi->fd = -1;
iscsi->is_connected = 0; iscsi->is_connected = 0;
@@ -374,6 +439,17 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
return 0; return 0;
} }
int inline
iscsi_service_reconnect_if_loggedin(struct iscsi_context *iscsi)
{
if (iscsi->is_loggedin) {
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
}
int int
iscsi_service(struct iscsi_context *iscsi, int revents) iscsi_service(struct iscsi_context *iscsi, int revents)
{ {
@@ -395,30 +471,19 @@ iscsi_service(struct iscsi_context *iscsi, int revents)
} }
iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL, iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL,
iscsi->connect_data); iscsi->connect_data);
if (iscsi->is_loggedin) { return iscsi_service_reconnect_if_loggedin(iscsi);
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
} }
if (revents & POLLHUP) { if (revents & POLLHUP) {
iscsi_set_error(iscsi, "iscsi_service: POLLHUP, " iscsi_set_error(iscsi, "iscsi_service: POLLHUP, "
"socket error."); "socket error.");
iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL, iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, NULL,
iscsi->connect_data); iscsi->connect_data);
if (iscsi->is_loggedin) { return iscsi_service_reconnect_if_loggedin(iscsi);
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
} }
if (iscsi->is_connected == 0 && iscsi->fd != -1 && revents&POLLOUT) { if (iscsi->is_connected == 0 && iscsi->fd != -1 && revents&POLLOUT) {
int err = 0; int err = 0;
socklen_t err_size = sizeof(err); socklen_t err_size = sizeof(err);
if (getsockopt(iscsi->fd, SOL_SOCKET, SO_ERROR, if (getsockopt(iscsi->fd, SOL_SOCKET, SO_ERROR,
&err, &err_size) != 0 || err != 0) { &err, &err_size) != 0 || err != 0) {
if (err == 0) { if (err == 0) {
@@ -429,15 +494,11 @@ iscsi_service(struct iscsi_context *iscsi, int revents)
strerror(err), err); strerror(err), err);
iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR, iscsi->socket_status_cb(iscsi, SCSI_STATUS_ERROR,
NULL, iscsi->connect_data); NULL, iscsi->connect_data);
if (iscsi->is_loggedin) { return iscsi_service_reconnect_if_loggedin(iscsi);
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
} }
iscsi_set_tcp_keepalive(iscsi, 30, 3, 30); DPRINTF(iscsi,2,"connection to %s established",iscsi->connected_portal);
iscsi->is_connected = 1; iscsi->is_connected = 1;
iscsi->socket_status_cb(iscsi, SCSI_STATUS_GOOD, NULL, iscsi->socket_status_cb(iscsi, SCSI_STATUS_GOOD, NULL,
iscsi->connect_data); iscsi->connect_data);
@@ -446,22 +507,12 @@ iscsi_service(struct iscsi_context *iscsi, int revents)
if (revents & POLLOUT && iscsi->outqueue != NULL) { if (revents & POLLOUT && iscsi->outqueue != NULL) {
if (iscsi_write_to_socket(iscsi) != 0) { if (iscsi_write_to_socket(iscsi) != 0) {
if (iscsi->is_loggedin) { return iscsi_service_reconnect_if_loggedin(iscsi);
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
} }
} }
if (revents & POLLIN) { if (revents & POLLIN) {
if (iscsi_read_from_socket(iscsi) != 0) { if (iscsi_read_from_socket(iscsi) != 0) {
if (iscsi->is_loggedin) { return iscsi_service_reconnect_if_loggedin(iscsi);
if (iscsi_reconnect(iscsi) == 0) {
return 0;
}
}
return -1;
} }
} }
@@ -515,47 +566,66 @@ iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue)
} }
} }
void iscsi_set_tcp_syncnt(struct iscsi_context *iscsi, int value)
{
iscsi->tcp_syncnt=value;
DPRINTF(iscsi,2,"TCP_SYNCNT will be set to %d on next socket creation",value);
}
void iscsi_set_tcp_user_timeout(struct iscsi_context *iscsi, int value)
{
iscsi->tcp_user_timeout=value;
DPRINTF(iscsi,2,"TCP_USER_TIMEOUT will be set to %dms on next socket creation",value);
}
void iscsi_set_tcp_keepidle(struct iscsi_context *iscsi, int value)
{
iscsi->tcp_keepidle=value;
DPRINTF(iscsi,2,"TCP_KEEPIDLE will be set to %d on next socket creation",value);
}
void iscsi_set_tcp_keepcnt(struct iscsi_context *iscsi, int value)
{
iscsi->tcp_keepcnt=value;
DPRINTF(iscsi,2,"TCP_KEEPCNT will be set to %d on next socket creation",value);
}
void iscsi_set_tcp_keepintvl(struct iscsi_context *iscsi, int value)
{
iscsi->tcp_keepintvl=value;
DPRINTF(iscsi,2,"TCP_KEEPINTVL will be set to %d on next socket creation",value);
}
int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, int interval) int iscsi_set_tcp_keepalive(struct iscsi_context *iscsi, int idle, int count, int interval)
{ {
int level, value;
#if defined(__FreeBSD__) || defined(__sun)
struct protoent *buf;
if ((buf = getprotobyname("tcp")) != NULL)
level = buf->p_proto;
else
return -1;
#else
level = SOL_TCP;
#endif
#ifdef SO_KEEPALIVE #ifdef SO_KEEPALIVE
value =1; int value = 1;
if (setsockopt(iscsi->fd, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value)) != 0) { if (setsockopt(iscsi->fd, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(value)) != 0) {
iscsi_set_error(iscsi, "TCP: Failed to set socket option SO_KEEPALIVE. Error %s(%d)", strerror(errno), errno); iscsi_set_error(iscsi, "TCP: Failed to set socket option SO_KEEPALIVE. Error %s(%d)", strerror(errno), errno);
return -1; return -1;
} }
#endif DPRINTF(iscsi,3,"SO_KEEPALIVE set to %d",value);
#ifdef TCP_KEEPCNT #ifdef TCP_KEEPCNT
value = count; if (set_tcp_sockopt(iscsi->fd, TCP_KEEPCNT, count) != 0) {
if (setsockopt(iscsi->fd, level, TCP_KEEPCNT, &value, sizeof(value)) != 0) {
iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive count. Error %s(%d)", strerror(errno), errno); iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive count. Error %s(%d)", strerror(errno), errno);
return -1; return -1;
} }
DPRINTF(iscsi,3,"TCP_KEEPCNT set to %d",count);
#endif #endif
#ifdef TCP_KEEPINTVL #ifdef TCP_KEEPINTVL
value = interval; if (set_tcp_sockopt(iscsi->fd, TCP_KEEPINTVL, interval) != 0) {
if (setsockopt(iscsi->fd, level, TCP_KEEPINTVL, &value, sizeof(value)) != 0) {
iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive interval. Error %s(%d)", strerror(errno), errno); iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive interval. Error %s(%d)", strerror(errno), errno);
return -1; return -1;
} }
DPRINTF(iscsi,3,"TCP_KEEPINTVL set to %d",interval);
#endif #endif
#ifdef TCP_KEEPIDLE #ifdef TCP_KEEPIDLE
value = idle; if (set_tcp_sockopt(iscsi->fd, TCP_KEEPIDLE, idle) != 0) {
if (setsockopt(iscsi->fd, level, TCP_KEEPIDLE, &value, sizeof(value)) != 0) {
iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive idle. Error %s(%d)", strerror(errno), errno); iscsi_set_error(iscsi, "TCP: Failed to set tcp keepalive idle. Error %s(%d)", strerror(errno), errno);
return -1; return -1;
} }
DPRINTF(iscsi,3,"TCP_KEEPIDLE set to %d",idle);
#endif
#endif #endif
return 0; return 0;

View File

@@ -30,9 +30,9 @@
#include "scsi-lowlevel.h" #include "scsi-lowlevel.h"
struct iscsi_sync_state { struct iscsi_sync_state {
int finished; int finished;
int status; int status;
struct scsi_task *task; struct scsi_task *task;
}; };
static void static void

View File

@@ -196,6 +196,7 @@ void print_help(void)
fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n");
fprintf(stderr, " -e, --evpd=integer evpd\n"); fprintf(stderr, " -e, --evpd=integer evpd\n");
fprintf(stderr, " -c, --pagecode=integer page code\n"); fprintf(stderr, " -c, --pagecode=integer page code\n");
fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "Help options:\n"); fprintf(stderr, "Help options:\n");
fprintf(stderr, " -?, --help Show this help message\n"); fprintf(stderr, " -?, --help Show this help message\n");
@@ -218,7 +219,7 @@ int main(int argc, const char *argv[])
const char *url = NULL; const char *url = NULL;
struct iscsi_url *iscsi_url = NULL; struct iscsi_url *iscsi_url = NULL;
int evpd = 0, pagecode = 0; int evpd = 0, pagecode = 0;
int show_help = 0, show_usage = 0; int show_help = 0, show_usage = 0, debug = 0;
int res; int res;
struct poptOption popt_options[] = { struct poptOption popt_options[] = {
@@ -227,6 +228,7 @@ int main(int argc, const char *argv[])
{ "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" },
{ "evpd", 'e', POPT_ARG_INT, &evpd, 0, "evpd", "integer" }, { "evpd", 'e', POPT_ARG_INT, &evpd, 0, "evpd", "integer" },
{ "pagecode", 'c', POPT_ARG_INT, &pagecode, 0, "page code", "integer" }, { "pagecode", 'c', POPT_ARG_INT, &pagecode, 0, "page code", "integer" },
{ "debug", 'd', POPT_ARG_INT, &debug, 0, "Debugging level", "integer" },
POPT_TABLEEND POPT_TABLEEND
}; };
@@ -263,6 +265,10 @@ int main(int argc, const char *argv[])
exit(10); exit(10);
} }
if (debug > 0) {
iscsi_set_debug(iscsi, debug);
}
if (url == NULL) { if (url == NULL) {
fprintf(stderr, "You must specify the URL\n"); fprintf(stderr, "You must specify the URL\n");
print_usage(); print_usage();

View File

@@ -291,6 +291,7 @@ void print_help(void)
fprintf(stderr, "Usage: iscsi-ls [OPTION...] <iscsi-url>\n"); fprintf(stderr, "Usage: iscsi-ls [OPTION...] <iscsi-url>\n");
fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n");
fprintf(stderr, " -s, --show-luns Show the luns for each target\n"); fprintf(stderr, " -s, --show-luns Show the luns for each target\n");
fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n");
fprintf(stderr, "\n"); fprintf(stderr, "\n");
fprintf(stderr, "Help options:\n"); fprintf(stderr, "Help options:\n");
fprintf(stderr, " -?, --help Show this help message\n"); fprintf(stderr, " -?, --help Show this help message\n");
@@ -314,13 +315,14 @@ int main(int argc, const char *argv[])
const char *url = NULL; const char *url = NULL;
poptContext pc; poptContext pc;
int res; int res;
int show_help = 0, show_usage = 0; int show_help = 0, show_usage = 0, debug = 0;
struct poptOption popt_options[] = { struct poptOption popt_options[] = {
{ "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL }, { "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL },
{ "usage", 0, POPT_ARG_NONE, &show_usage, 0, "Display brief usage message", NULL }, { "usage", 0, POPT_ARG_NONE, &show_usage, 0, "Display brief usage message", NULL },
{ "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" },
{ "show-luns", 's', POPT_ARG_NONE, &showluns, 0, "Show the luns for each target", NULL }, { "show-luns", 's', POPT_ARG_NONE, &showluns, 0, "Show the luns for each target", NULL },
{ "debug", 'd', POPT_ARG_INT, &debug, 0, "Debugging level", "integer" },
POPT_TABLEEND POPT_TABLEEND
}; };
@@ -353,7 +355,6 @@ int main(int argc, const char *argv[])
poptFreeContext(pc); poptFreeContext(pc);
if (url == NULL) { if (url == NULL) {
fprintf(stderr, "You must specify iscsi target portal.\n"); fprintf(stderr, "You must specify iscsi target portal.\n");
print_usage(); print_usage();
@@ -366,6 +367,10 @@ int main(int argc, const char *argv[])
exit(10); exit(10);
} }
if (debug > 0) {
iscsi_set_debug(iscsi, debug);
}
iscsi_url = iscsi_parse_portal_url(iscsi, url); iscsi_url = iscsi_parse_portal_url(iscsi, url);
if (iscsi_url == NULL) { if (iscsi_url == NULL) {
fprintf(stderr, "Failed to parse URL: %s\n", fprintf(stderr, "Failed to parse URL: %s\n",

167
src/iscsi-readcapacity16.c Normal file
View File

@@ -0,0 +1,167 @@
/*
Copyright (C) 2012 by Peter Lieven <pl@kamp.de>
Copyright (C) 2010 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 <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <poll.h>
#include <popt.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
const char *initiator = "iqn.2007-10.com.github:sahlberg:libiscsi:iscsi-readcapacity16";
void print_usage(void)
{
fprintf(stderr, "Usage: iscsi-readcapacity16 [-?] [-?|--help] [--usage] [-i|--initiator-name=iqn-name] <iscsi-url>\n");
}
void print_help(void)
{
fprintf(stderr, "Usage: iscsi_readcapacity16 [OPTION...] <iscsi-url>\n");
fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n");
fprintf(stderr, " -d, --debug=integer debug level (0=disabled)\n");
fprintf(stderr, "\n");
fprintf(stderr, "Help options:\n");
fprintf(stderr, " -?, --help Show this help message\n");
fprintf(stderr, " --usage Display brief usage message\n");
fprintf(stderr, "\n");
fprintf(stderr, "iSCSI URL format : %s\n", ISCSI_URL_SYNTAX);
fprintf(stderr, "\n");
fprintf(stderr, "<host> is either of:\n");
fprintf(stderr, " \"hostname\" iscsi.example\n");
fprintf(stderr, " \"ipv4-address\" 10.1.1.27\n");
fprintf(stderr, " \"ipv6-address\" [fce0::1]\n");
}
int main(int argc, const char *argv[])
{
poptContext pc;
struct iscsi_context *iscsi;
const char **extra_argv;
int extra_argc = 0;
const char *url = NULL;
struct iscsi_url *iscsi_url = NULL;
int show_help = 0, show_usage = 0, debug = 0;
int res;
struct poptOption popt_options[] = {
{ "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL },
{ "usage", 0, POPT_ARG_NONE, &show_usage, 0, "Display brief usage message", NULL },
{ "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" },
{ "debug", 'd', POPT_ARG_INT, &debug, 0, "Debugging level", "integer" },
POPT_TABLEEND
};
pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_POSIXMEHARDER);
if ((res = poptGetNextOpt(pc)) < -1) {
fprintf(stderr, "Failed to parse option : %s %s\n",
poptBadOption(pc, 0), poptStrerror(res));
exit(10);
}
extra_argv = poptGetArgs(pc);
if (extra_argv) {
url = *extra_argv;
extra_argv++;
while (extra_argv[extra_argc]) {
extra_argc++;
}
}
if (show_help != 0) {
print_help();
exit(0);
}
if (show_usage != 0) {
print_usage();
exit(0);
}
poptFreeContext(pc);
iscsi = iscsi_create_context(initiator);
if (iscsi == NULL) {
fprintf(stderr, "Failed to create context\n");
exit(10);
}
if (debug > 0) {
iscsi_set_debug(iscsi, debug);
}
if (url == NULL) {
fprintf(stderr, "You must specify the URL\n");
print_usage();
exit(10);
}
iscsi_url = iscsi_parse_full_url(iscsi, url);
if (iscsi_url == NULL) {
fprintf(stderr, "Failed to parse URL: %s\n",
iscsi_get_error(iscsi));
exit(10);
}
iscsi_set_targetname(iscsi, iscsi_url->target);
iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL);
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
if (iscsi_url->user != NULL) {
if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) {
fprintf(stderr, "Failed to set initiator username and password\n");
exit(10);
}
}
if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
fprintf(stderr, "Login Failed. %s\n", iscsi_get_error(iscsi));
iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi);
exit(10);
}
struct scsi_task *task;
struct scsi_readcapacity16 *rc16;
task = iscsi_readcapacity16_sync(iscsi, iscsi_url->lun);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
fprintf(stderr,"failed to send readcapacity command\n");
iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi);
exit(10);
}
rc16 = scsi_datain_unmarshall(task);
if (rc16 == NULL) {
fprintf(stderr,"failed to unmarshall readcapacity16 data\n");
scsi_free_scsi_task(task);
iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi);
exit(10);
}
fprintf(stdout,"%lu",rc16->block_length*(rc16->returned_lba + 1));
iscsi_destroy_url(iscsi_url);
iscsi_logout_sync(iscsi);
iscsi_destroy_context(iscsi);
return 0;
}

View File

@@ -37,6 +37,10 @@ static const char *initiator = "iqn.2007-10.com.github:sahlberg:libiscsi:ld-iscs
#define ISCSI_MAX_FD 255 #define ISCSI_MAX_FD 255
static int debug = 0;
#define LD_ISCSI_DPRINTF(level,fmt,args...) do { if ((debug) >= level) {fprintf(stderr,"ld_iscsi: ");fprintf(stderr, (fmt), ##args); fprintf(stderr,"\n");} } while (0);
struct iscsi_fd_list { struct iscsi_fd_list {
int is_iscsi; int is_iscsi;
int dup2fd; int dup2fd;
@@ -46,6 +50,10 @@ struct iscsi_fd_list {
uint32_t block_size; uint32_t block_size;
uint64_t num_blocks; uint64_t num_blocks;
off_t offset; off_t offset;
mode_t mode;
int get_lba_status;
struct scsi_lba_status_descriptor lbasd_cached;
int lbasd_cache_valid;
}; };
static struct iscsi_fd_list iscsi_fd_list[ISCSI_MAX_FD]; static struct iscsi_fd_list iscsi_fd_list[ISCSI_MAX_FD];
@@ -60,19 +68,24 @@ int open(const char *path, int flags, mode_t mode)
struct iscsi_context *iscsi; struct iscsi_context *iscsi;
struct iscsi_url *iscsi_url; struct iscsi_url *iscsi_url;
struct scsi_task *task; struct scsi_task *task;
struct scsi_readcapacity10 *rc10; struct scsi_readcapacity16 *rc16;
if (mode & O_NONBLOCK) {
LD_ISCSI_DPRINTF(0,"Non-blocking I/O is currently not supported");
errno = EINVAL;
return -1;
}
iscsi = iscsi_create_context(initiator); iscsi = iscsi_create_context(initiator);
if (iscsi == NULL) { if (iscsi == NULL) {
fprintf(stderr, "ld-iscsi: Failed to create context\n"); LD_ISCSI_DPRINTF(0,"Failed to create context");
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
iscsi_url = iscsi_parse_full_url(iscsi, path); iscsi_url = iscsi_parse_full_url(iscsi, path);
if (iscsi_url == NULL) { if (iscsi_url == NULL) {
fprintf(stderr, "ld-iscsi: Failed to parse URL: %s\n", LD_ISCSI_DPRINTF(0,"Failed to parse URL: %s\n", iscsi_get_error(iscsi));
iscsi_get_error(iscsi));
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
errno = EINVAL; errno = EINVAL;
return -1; return -1;
@@ -84,7 +97,7 @@ int open(const char *path, int flags, mode_t mode)
if (iscsi_url->user != NULL) { if (iscsi_url->user != NULL) {
if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) { if (iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd) != 0) {
fprintf(stderr, "Failed to set initiator username and password\n"); LD_ISCSI_DPRINTF(0,"Failed to set initiator username and password");
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
@@ -92,25 +105,25 @@ int open(const char *path, int flags, mode_t mode)
} }
if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) { if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
fprintf(stderr, "ld-iscsi: Login Failed. %s\n", iscsi_get_error(iscsi)); LD_ISCSI_DPRINTF(0,"Login Failed. %s\n", iscsi_get_error(iscsi));
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
errno = EIO; errno = EIO;
return -1; return -1;
} }
task = iscsi_readcapacity10_sync(iscsi, iscsi_url->lun, 0, 0); task = iscsi_readcapacity16_sync(iscsi, iscsi_url->lun);
if (task == NULL || task->status != SCSI_STATUS_GOOD) { if (task == NULL || task->status != SCSI_STATUS_GOOD) {
fprintf(stderr, "ld-iscsi: failed to send readcapacity command\n"); LD_ISCSI_DPRINTF(0,"failed to send readcapacity command");
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
errno = EIO; errno = EIO;
return -1; return -1;
} }
rc10 = scsi_datain_unmarshall(task); rc16 = scsi_datain_unmarshall(task);
if (rc10 == NULL) { if (rc16 == NULL) {
fprintf(stderr, "ld-iscsi: failed to unmarshall readcapacity10 data\n"); LD_ISCSI_DPRINTF(0,"failed to unmarshall readcapacity10 data");
scsi_free_scsi_task(task); scsi_free_scsi_task(task);
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
@@ -118,9 +131,11 @@ int open(const char *path, int flags, mode_t mode)
return -1; return -1;
} }
LD_ISCSI_DPRINTF(4,"readcapacity16_sync: block_size: %d, num_blocks: %lu",rc16->block_length,rc16->returned_lba + 1);
fd = iscsi_get_fd(iscsi); fd = iscsi_get_fd(iscsi);
if (fd >= ISCSI_MAX_FD) { if (fd >= ISCSI_MAX_FD) {
fprintf(stderr, "ld-iscsi: Too many files open\n"); LD_ISCSI_DPRINTF(0,"Too many files open");
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
iscsi_destroy_context(iscsi); iscsi_destroy_context(iscsi);
errno = ENFILE; errno = ENFILE;
@@ -130,10 +145,19 @@ int open(const char *path, int flags, mode_t mode)
iscsi_fd_list[fd].is_iscsi = 1; iscsi_fd_list[fd].is_iscsi = 1;
iscsi_fd_list[fd].dup2fd = -1; iscsi_fd_list[fd].dup2fd = -1;
iscsi_fd_list[fd].iscsi = iscsi; iscsi_fd_list[fd].iscsi = iscsi;
iscsi_fd_list[fd].block_size = rc10->block_size; iscsi_fd_list[fd].block_size = rc16->block_length;
iscsi_fd_list[fd].num_blocks = rc10->lba + 1; iscsi_fd_list[fd].num_blocks = rc16->returned_lba + 1;
iscsi_fd_list[fd].offset = 0; iscsi_fd_list[fd].offset = 0;
iscsi_fd_list[fd].lun = iscsi_url->lun; iscsi_fd_list[fd].lun = iscsi_url->lun;
iscsi_fd_list[fd].mode = mode;
if (getenv("LD_ISCSI_GET_LBA_STATUS") != NULL) {
iscsi_fd_list[fd].get_lba_status = atoi(getenv("LD_ISCSI_GET_LBA_STATUS"));
if (rc16->lbpme == 0){
LD_ISCSI_DPRINTF(1,"Logical unit is fully provisioned. Will skip get_lba_status tasks");
iscsi_fd_list[fd].get_lba_status = 0;
}
}
scsi_free_scsi_task(task); scsi_free_scsi_task(task);
iscsi_destroy_url(iscsi_url); iscsi_destroy_url(iscsi_url);
@@ -141,7 +165,7 @@ int open(const char *path, int flags, mode_t mode)
return fd; return fd;
} }
return real_open(path, flags, mode); return real_open(path, flags, mode);
} }
int open64(const char *path, int flags, mode_t mode) int open64(const char *path, int flags, mode_t mode)
@@ -257,8 +281,9 @@ ssize_t read(int fd, void *buf, size_t count)
{ {
if ((iscsi_fd_list[fd].is_iscsi == 1) && (iscsi_fd_list[fd].in_flight == 0)) { if ((iscsi_fd_list[fd].is_iscsi == 1) && (iscsi_fd_list[fd].in_flight == 0)) {
uint64_t offset; uint64_t offset;
uint32_t num_blocks, lba; uint64_t num_blocks, lba;
struct scsi_task *task; struct scsi_task *task;
struct scsi_get_lba_status *lbas;
if (iscsi_fd_list[fd].dup2fd >= 0) { if (iscsi_fd_list[fd].dup2fd >= 0) {
return read(iscsi_fd_list[fd].dup2fd, buf, count); return read(iscsi_fd_list[fd].dup2fd, buf, count);
@@ -278,10 +303,70 @@ ssize_t read(int fd, void *buf, size_t count)
} }
iscsi_fd_list[fd].in_flight = 1; iscsi_fd_list[fd].in_flight = 1;
task = iscsi_read10_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, lba, num_blocks * iscsi_fd_list[fd].block_size, iscsi_fd_list[fd].block_size, 0, 0, 0, 0, 0); if (iscsi_fd_list[fd].get_lba_status != 0) {
if (iscsi_fd_list[fd].lbasd_cache_valid==1) {
LD_ISCSI_DPRINTF(5,"cached get_lba_status_descriptor is lba %lu, num_blocks %d, provisioning %d",iscsi_fd_list[fd].lbasd_cached.lba,iscsi_fd_list[fd].lbasd_cached.num_blocks,iscsi_fd_list[fd].lbasd_cached.provisioning);
if (iscsi_fd_list[fd].lbasd_cached.provisioning != 0x00 && lba >= iscsi_fd_list[fd].lbasd_cached.lba && lba+num_blocks < iscsi_fd_list[fd].lbasd_cached.lba+iscsi_fd_list[fd].lbasd_cached.num_blocks)
{
LD_ISCSI_DPRINTF(4,"skipped read16_sync for non-allocated blocks: lun %d, lba %lu, num_blocks: %lu, block_size: %d, offset: %lu count: %lu",iscsi_fd_list[fd].lun,lba,num_blocks,iscsi_fd_list[fd].block_size,offset,count);
memset(buf, 0x00, count);
iscsi_fd_list[fd].offset += count;
iscsi_fd_list[fd].in_flight = 0;
return count;
}
}
LD_ISCSI_DPRINTF(4,"get_lba_status_sync: lun %d, lba %lu, num_blocks: %lu",iscsi_fd_list[fd].lun,lba,num_blocks);
task = iscsi_get_lba_status_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, lba, 8+16);
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
LD_ISCSI_DPRINTF(0,"failed to send get_lba_status command");
iscsi_fd_list[fd].in_flight = 0;
errno = EIO;
return -1;
}
lbas = scsi_datain_unmarshall(task);
if (lbas == NULL) {
LD_ISCSI_DPRINTF(0,"failed to unmarshall get_lba_status data");
scsi_free_scsi_task(task);
iscsi_fd_list[fd].in_flight = 0;
errno = EIO;
return -1;
}
u_int32_t i;
LD_ISCSI_DPRINTF(5,"get_lba_status: num_descriptors: %d",lbas->num_descriptors);
u_int32_t _num_allocated=0;
u_int32_t _num_blocks=0;
for (i=0;i<lbas->num_descriptors;i++) {
struct scsi_lba_status_descriptor *lbasd = &lbas->descriptors[i];
LD_ISCSI_DPRINTF(5,"get_lba_status_descriptor %d, lba %lu, num_blocks %d, provisioning %d",i,lbasd->lba,lbasd->num_blocks,lbasd->provisioning);
if (lbasd->lba != _num_blocks+lba) {
LD_ISCSI_DPRINTF(0,"get_lba_status response is non-continuous");
scsi_free_scsi_task(task);
iscsi_fd_list[fd].in_flight = 0;
errno = EIO;
return -1;
}
_num_allocated+=(lbasd->provisioning==0x00)?lbasd->num_blocks:0;
_num_blocks+=lbasd->num_blocks;
iscsi_fd_list[fd].lbasd_cached=lbas->descriptors[i];
iscsi_fd_list[fd].lbasd_cache_valid=1;
}
scsi_free_scsi_task(task);
if (_num_allocated == 0 && _num_blocks >= num_blocks) {
LD_ISCSI_DPRINTF(4,"skipped read16_sync for non-allocated blocks: lun %d, lba %lu, num_blocks: %lu, block_size: %d, offset: %lu count: %lu",iscsi_fd_list[fd].lun,lba,num_blocks,iscsi_fd_list[fd].block_size,offset,count);
memset(buf, 0x00, count);
iscsi_fd_list[fd].offset += count;
iscsi_fd_list[fd].in_flight = 0;
return count;
}
}
LD_ISCSI_DPRINTF(4,"read16_sync: lun %d, lba %lu, num_blocks: %lu, block_size: %d, offset: %lu count: %lu",iscsi_fd_list[fd].lun,lba,num_blocks,iscsi_fd_list[fd].block_size,offset,count);
task = iscsi_read16_sync(iscsi_fd_list[fd].iscsi, iscsi_fd_list[fd].lun, lba, num_blocks * iscsi_fd_list[fd].block_size, iscsi_fd_list[fd].block_size, 0, 0, 0, 0, 0);
iscsi_fd_list[fd].in_flight = 0; iscsi_fd_list[fd].in_flight = 0;
if (task == NULL || task->status != SCSI_STATUS_GOOD) { if (task == NULL || task->status != SCSI_STATUS_GOOD) {
fprintf(stderr, "ld-iscsi: failed to send read10 command\n"); LD_ISCSI_DPRINTF(0,"failed to send read16 command");
errno = EIO; errno = EIO;
return -1; return -1;
} }
@@ -381,59 +466,63 @@ static void __attribute__((constructor)) _init(void)
iscsi_fd_list[i].dup2fd = -1; iscsi_fd_list[i].dup2fd = -1;
} }
if (getenv("LD_ISCSI_DEBUG") != NULL) {
debug = atoi(getenv("LD_ISCSI_DEBUG"));
}
real_open = dlsym(RTLD_NEXT, "open"); real_open = dlsym(RTLD_NEXT, "open");
if (real_open == NULL) { if (real_open == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(open)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(open)");
exit(10); exit(10);
} }
real_close = dlsym(RTLD_NEXT, "close"); real_close = dlsym(RTLD_NEXT, "close");
if (real_close == NULL) { if (real_close == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(close)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(close)");
exit(10); exit(10);
} }
real_fxstat = dlsym(RTLD_NEXT, "__fxstat"); real_fxstat = dlsym(RTLD_NEXT, "__fxstat");
if (real_fxstat == NULL) { if (real_fxstat == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(__fxstat)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(__fxstat)");
exit(10); exit(10);
} }
real_lxstat = dlsym(RTLD_NEXT, "__lxstat"); real_lxstat = dlsym(RTLD_NEXT, "__lxstat");
if (real_lxstat == NULL) { if (real_lxstat == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(__lxstat)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(__lxstat)");
exit(10); exit(10);
} }
real_xstat = dlsym(RTLD_NEXT, "__xstat"); real_xstat = dlsym(RTLD_NEXT, "__xstat");
if (real_xstat == NULL) { if (real_xstat == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(__xstat)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(__xstat)");
exit(10); exit(10);
} }
real_read = dlsym(RTLD_NEXT, "read"); real_read = dlsym(RTLD_NEXT, "read");
if (real_read == NULL) { if (real_read == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(read)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(read)");
exit(10); exit(10);
} }
real_dup2 = dlsym(RTLD_NEXT, "dup2"); real_dup2 = dlsym(RTLD_NEXT, "dup2");
if (real_dup2 == NULL) { if (real_dup2 == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(dup2)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(dup2)");
exit(10); exit(10);
} }
real_fxstat64 = dlsym(RTLD_NEXT, "__fxstat64"); real_fxstat64 = dlsym(RTLD_NEXT, "__fxstat64");
if (real_fxstat64 == NULL) { if (real_fxstat64 == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(__fxstat64)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(__fxstat64)");
} }
real_lxstat64 = dlsym(RTLD_NEXT, "__lxstat64"); real_lxstat64 = dlsym(RTLD_NEXT, "__lxstat64");
if (real_lxstat64 == NULL) { if (real_lxstat64 == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(_lxstat64)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(_lxstat64)");
} }
real_xstat64 = dlsym(RTLD_NEXT, "__xstat64"); real_xstat64 = dlsym(RTLD_NEXT, "__xstat64");
if (real_xstat64 == NULL) { if (real_xstat64 == NULL) {
fprintf(stderr, "ld_iscsi: Failed to dlsym(__xstat64)\n"); LD_ISCSI_DPRINTF(0,"Failed to dlsym(__xstat64)");
} }
} }

View File

@@ -41,6 +41,7 @@ int T0000_testunitready_simple(const char *initiator, const char *url, int data_
return -1; return -1;
} }
ret=0;
printf("Test TESTUNITREADY ... "); printf("Test TESTUNITREADY ... ");
task = iscsi_testunitready_sync(iscsi, lun); task = iscsi_testunitready_sync(iscsi, lun);

View File

@@ -0,0 +1,212 @@
/*
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 <string.h>
#include <ctype.h>
#include <poll.h>
#include "iscsi.h"
#include "scsi-lowlevel.h"
#include "iscsi-test.h"
struct mgmt_task {
uint32_t status;
uint32_t finished;
};
static void mgmt_cb(struct iscsi_context *iscsi _U_, int status _U_,
void *command_data, void *private_data)
{
struct mgmt_task *mgmt_task = (struct mgmt_task *)private_data;
mgmt_task->status = *(uint32_t *)command_data;
mgmt_task->finished = 1;
}
int T0424_reserve6_target_reset(const char *initiator, const char *url, int data_loss, int show_info)
{
struct iscsi_context *iscsi, *iscsi2;
struct scsi_task *task;
int ret, lun;
struct mgmt_task mgmt_task = {0, 0};
struct pollfd pfd;
printf("0424_reserve6_target_reset:\n");
printf("========================\n");
if (show_info) {
printf("Test that a RESERVE6 is dropped by a Target-reset\n");
printf(" If device does not support RESERVE6, just skip the test.\n");
printf("1, Reserve the device from the first initiator.\n");
printf("2, Verify we can access the LUN from the first initiator\n");
printf("3, Verify we can NOT access the LUN from the second initiator\n");
printf("4, Send a Target-reset\n");
printf("5, Verify we can access the LUN from the second initiator\n");
printf("\n");
return 0;
}
iscsi = iscsi_context_login(initiator, url, &lun);
if (iscsi == NULL) {
printf("Failed to login to target\n");
return -1;
}
iscsi2 = iscsi_context_login(initiator2, url, &lun);
if (iscsi2 == NULL) {
printf("Failed to login to target\n");
return -1;
}
ret = 0;
printf("Send RESERVE6 from the first initiator ... ");
task = iscsi_reserve6_sync(iscsi, lun);
if (task == NULL) {
printf("[FAILED]\n");
printf("Failed to send RESERVE6 command : %s\n",
iscsi_get_error(iscsi));
ret = -1;
goto finished;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_ILLEGAL_REQUEST
&& task->sense.ascq == SCSI_SENSE_ASCQ_INVALID_OPERATION_CODE) {
printf("[SKIPPED]\n");
printf("RESERVE6 Not Supported\n");
ret = -2;
scsi_free_scsi_task(task);
goto finished;
}
if (task->status != SCSI_STATUS_GOOD) {
printf("[FAILED]\n");
printf("RESERVE6 failed with sense:%s\n",
iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto test2;
}
scsi_free_scsi_task(task);
printf("[OK]\n");
test2:
printf("Verify we can access the LUN from the first initiator ... ");
task = iscsi_testunitready_sync(iscsi, lun);
if (task == NULL) {
printf("[FAILED]\n");
printf("Failed to send TEST UNIT READY command: %s\n",
iscsi_get_error(iscsi));
ret = -1;
goto finished;
}
if (task->status != SCSI_STATUS_GOOD) {
printf("[FAILED]\n");
printf("TEST UNIT READY command: failed with sense %s\n",
iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto test3;
}
scsi_free_scsi_task(task);
printf("[OK]\n");
test3:
printf("Verify we can NOT access the LUN from the second initiator ... ");
task = iscsi_testunitready_sync(iscsi2, lun);
if (task == NULL) {
printf("[FAILED]\n");
printf("Failed to send TEST UNIT READY command: %s\n",
iscsi_get_error(iscsi2));
ret = -1;
goto finished;
}
if (task->status != SCSI_STATUS_RESERVATION_CONFLICT) {
printf("[FAILED]\n");
printf("Expected RESERVATION CONFLICT\n");
ret = -1;
scsi_free_scsi_task(task);
goto finished;
}
scsi_free_scsi_task(task);
printf("[OK]\n");
test4:
printf("Send a Target Cold-Reset ... ");
iscsi_task_mgmt_target_cold_reset_async(iscsi, mgmt_cb, &mgmt_task);
while (mgmt_task.finished == 0) {
pfd.fd = iscsi_get_fd(iscsi);
pfd.events = iscsi_which_events(iscsi);
if (poll(&pfd, 1, -1) < 0) {
printf("Poll failed");
goto finished;
}
if (iscsi_service(iscsi, pfd.revents) < 0) {
printf("iscsi_service failed with : %s\n", iscsi_get_error(iscsi));
break;
}
}
if (mgmt_task.status != 0) {
printf("[FAILED]\n");
printf("Failed to reset the LUN\n");
goto finished;
}
printf("[OK]\n");
test5:
/* We might be getting UNIT_ATTENTION/BUS_RESET after the lun-reset above.
If so just loop and try the TESTUNITREADY again until it clears
*/
printf("Verify we can access the LUN from the second initiator ... ");
task = iscsi_testunitready_sync(iscsi2, lun);
if (task == NULL) {
printf("[FAILED]\n");
printf("Failed to send TEST UNIT READY command: %s\n",
iscsi_get_error(iscsi2));
ret = -1;
goto finished;
}
if (task->status == SCSI_STATUS_CHECK_CONDITION
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION
&& task->sense.ascq == SCSI_SENSE_ASCQ_BUS_RESET) {
printf("Got BUS RESET. Retry accessing the LUN\n");
goto test5;
}
if (task->status != SCSI_STATUS_GOOD) {
printf("[FAILED]\n");
printf("TEST UNIT READY command: failed with sense %s\n",
iscsi_get_error(iscsi2));
ret = -1;
scsi_free_scsi_task(task);
goto test3;
}
scsi_free_scsi_task(task);
printf("[OK]\n");
finished:
iscsi_logout_sync(iscsi);
iscsi_destroy_context(iscsi);
iscsi_logout_sync(iscsi2);
iscsi_destroy_context(iscsi2);
return ret;
}

View File

@@ -65,7 +65,7 @@ int T1020_bufferoffset_invalid(const char *initiator, const char *url, int data_
struct scsi_task *task; struct scsi_task *task;
struct scsi_readcapacity16 *rc16; struct scsi_readcapacity16 *rc16;
int ret, lun; int ret, lun;
unsigned char data[block_size * 256]; unsigned char data[4096 * 256];
struct iscsi_async_state test_state; struct iscsi_async_state test_state;
printf("1020_bufferoffset_invalid:\n"); printf("1020_bufferoffset_invalid:\n");

View File

@@ -0,0 +1,150 @@
/*
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 <stdlib.h>
#include <arpa/inet.h>
#include "iscsi.h"
#include "iscsi-private.h"
#include "scsi-lowlevel.h"
#include "iscsi-test.h"
uint32_t block_size;
static void test_cb(struct iscsi_context *iscsi _U_, int status,
void *command_data _U_, void *private_data)
{
struct scsi_task *task = command_data;
struct iscsi_async_state *state = private_data;
state->finished = 1;
state->status = status;
if (status) {
task->status = status;
}
}
int T1030_unsolicited_data_overflow(const char *initiator, const char *url, int data_loss, int show_info)
{
struct iscsi_context *iscsi, *iscsi2;
struct scsi_task *task;
struct scsi_readcapacity16 *rc16;
int ret, lun;
unsigned char *buf = NULL;
struct iscsi_async_state test_state;
uint32_t old_first_burst_len;
printf("1030_unsolicited_data_overflow:\n");
printf("===============================\n");
if (show_info) {
printf("Test sending command with way more unsolicited data than the target supports\n");
printf("1, Send HUGE unsolicited data to the target.\n");
printf("2, Verify the target is still alive\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_YES;
old_first_burst_len = iscsi->first_burst_length;
/* make first burst REAL big */
iscsi->first_burst_length *= 16;
buf = malloc(iscsi->first_burst_length);
printf("Write too much unsolicited data ... ");
/* we dont want autoreconnect since some targets will drop the session
* on this condition.
*/
iscsi_set_noautoreconnect(iscsi, 1);
// 102400 -- 1024000
task = iscsi_write16_task(iscsi, lun, 0, buf,
iscsi->first_burst_length, block_size,
0, 0, 0, 0, 0,
test_cb, &test_state);
if (task == NULL) {
printf("[FAILED]\n");
printf("Failed to send WRITE16 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);
printf("[OK]\n");
test2:
printf("Verify the target is still alive ... ");
iscsi2 = iscsi_context_login(initiator, url, &lun);
if (iscsi2 == NULL) {
printf("[FAILED]\n");
printf("Target is dead?\n");
ret = -1;
goto finished;
}
printf("[OK]\n");
finished:
if (buf) {
free(buf);
}
iscsi_destroy_context(iscsi);
iscsi_destroy_context(iscsi2);
return ret;
}

View File

@@ -221,6 +221,7 @@ struct scsi_test tests[] = {
{ "T0421_reserve6_lun_reset", T0421_reserve6_lun_reset }, { "T0421_reserve6_lun_reset", T0421_reserve6_lun_reset },
{ "T0422_reserve6_logout", T0422_reserve6_logout }, { "T0422_reserve6_logout", T0422_reserve6_logout },
{ "T0423_reserve6_sessionloss", T0423_reserve6_sessionloss }, { "T0423_reserve6_sessionloss", T0423_reserve6_sessionloss },
{ "T0424_reserve6_target_reset", T0424_reserve6_target_reset },
/* Maintenance In - Report Supported Operations */ /* Maintenance In - Report Supported Operations */
{ "T0430_report_all_supported_ops", T0430_report_all_supported_ops }, { "T0430_report_all_supported_ops", T0430_report_all_supported_ops },
@@ -236,12 +237,15 @@ struct scsi_test tests[] = {
/* invalid bufferoffset from initiator */ /* invalid bufferoffset from initiator */
{ "T1020_bufferoffset_invalid", T1020_bufferoffset_invalid }, { "T1020_bufferoffset_invalid", T1020_bufferoffset_invalid },
/* sending too much unsolicited data */
{ "T1030_unsolicited_data_overflow", T1030_unsolicited_data_overflow },
{ NULL, NULL } { NULL, NULL }
}; };
void print_usage(void) void print_usage(void)
{ {
fprintf(stderr, "Usage: iscsi-test [-?] [-?|--help] [--usage] [-t|--test=<test>]\n" fprintf(stderr, "Usage: iscsi-test [-?] [-?|--help] [--usage] [-t|--test=<test>] [-s|--skip=<test>]\n"
"\t\t[-l|--list] [--info] [-i|--initiator-name=<iqn-name>]\n" "\t\t[-l|--list] [--info] [-i|--initiator-name=<iqn-name>]\n"
"\t\t<iscsi-url>\n"); "\t\t<iscsi-url>\n");
} }
@@ -252,6 +256,7 @@ void print_help(void)
fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n"); fprintf(stderr, " -i, --initiator-name=iqn-name Initiatorname to use\n");
fprintf(stderr, " -I, --initiator-name-2=iqn-name Second initiatorname to use\n"); fprintf(stderr, " -I, --initiator-name-2=iqn-name Second initiatorname to use\n");
fprintf(stderr, " -t, --test=test-name Which test to run. Default is to run all tests.\n"); fprintf(stderr, " -t, --test=test-name Which test to run. Default is to run all tests.\n");
fprintf(stderr, " -s, --skip=test-name Which test to skip. Default is to run all tests.\n");
fprintf(stderr, " -l, --list List all tests.\n"); fprintf(stderr, " -l, --list List all tests.\n");
fprintf(stderr, " --info, Print extra info about a test.\n"); fprintf(stderr, " --info, Print extra info about a test.\n");
fprintf(stderr, " --dataloss Allow destructive tests.\n"); fprintf(stderr, " --dataloss Allow destructive tests.\n");
@@ -375,6 +380,7 @@ int main(int argc, const char *argv[])
int res, num_failed, num_skipped; int res, num_failed, num_skipped;
struct scsi_test *test; struct scsi_test *test;
char *testname = NULL; char *testname = NULL;
char *skipname = NULL;
struct poptOption popt_options[] = { struct poptOption popt_options[] = {
{ "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL }, { "help", '?', POPT_ARG_NONE, &show_help, 0, "Show this help message", NULL },
@@ -383,6 +389,7 @@ int main(int argc, const char *argv[])
{ "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" }, { "initiator-name", 'i', POPT_ARG_STRING, &initiator, 0, "Initiatorname to use", "iqn-name" },
{ "initiator-name-2", 'I', POPT_ARG_STRING, &initiator, 0, "Second initiatorname to use for tests using more two sessions", "iqn-name" }, { "initiator-name-2", 'I', POPT_ARG_STRING, &initiator, 0, "Second initiatorname to use for tests using more two sessions", "iqn-name" },
{ "test", 't', POPT_ARG_STRING, &testname, 0, "Which test to run", "testname" }, { "test", 't', POPT_ARG_STRING, &testname, 0, "Which test to run", "testname" },
{ "skip", 's', POPT_ARG_STRING, &skipname, 0, "Which test to skip", "skipname" },
{ "info", 0, POPT_ARG_NONE, &show_info, 0, "Show information about the test", "testname" }, { "info", 0, POPT_ARG_NONE, &show_info, 0, "Show information about the test", "testname" },
{ "dataloss", 0, POPT_ARG_NONE, &data_loss, 0, "Allow destructuve tests", NULL }, { "dataloss", 0, POPT_ARG_NONE, &data_loss, 0, "Allow destructuve tests", NULL },
POPT_TABLEEND POPT_TABLEEND
@@ -438,6 +445,21 @@ int main(int argc, const char *argv[])
continue; continue;
} }
if (skipname != NULL) {
char * pchr = skipname;
char * pchr2 = NULL;
int skip = 0;
do {
pchr2 = strchr(pchr,',');
if (pchr2) pchr2[0]=0x00;
if (!fnmatch(pchr, test->name, 0)) {
skip = 1;
}
if (pchr2) {pchr2[0]=',';pchr=pchr2+1;}
} while (pchr2);
if (skip) continue;
}
res = test->test(initiator, url, data_loss, show_info); res = test->test(initiator, url, data_loss, show_info);
if (res == 0) { if (res == 0) {
printf("TEST %s [OK]\n", test->name); printf("TEST %s [OK]\n", test->name);

View File

@@ -173,9 +173,12 @@ int T0420_reserve6_simple(const char *initiator, const char *url, int data_loss,
int T0421_reserve6_lun_reset(const char *initiator, const char *url, int data_loss, int show_info); int T0421_reserve6_lun_reset(const char *initiator, const char *url, int data_loss, int show_info);
int T0422_reserve6_logout(const char *initiator, const char *url, int data_loss, int show_info); int T0422_reserve6_logout(const char *initiator, const char *url, int data_loss, int show_info);
int T0423_reserve6_sessionloss(const char *initiator, const char *url, int data_loss, int show_info); int T0423_reserve6_sessionloss(const char *initiator, const char *url, int data_loss, int show_info);
int T0424_reserve6_target_reset(const char *initiator, const char *url, int data_loss, int show_info);
int T0430_report_all_supported_ops(const char *initiator, const char *url, int data_loss, int show_info); int T0430_report_all_supported_ops(const char *initiator, const char *url, int data_loss, int show_info);
int T1000_cmdsn_invalid(const char *initiator, const char *url, int data_loss, int show_info); int T1000_cmdsn_invalid(const char *initiator, const char *url, int data_loss, int show_info);
int T1010_datasn_invalid(const char *initiator, const char *url, int data_loss, int show_info); int T1010_datasn_invalid(const char *initiator, const char *url, int data_loss, int show_info);
int T1020_bufferoffset_invalid(const char *initiator, const char *url, int data_loss, int show_info); int T1020_bufferoffset_invalid(const char *initiator, const char *url, int data_loss, int show_info);
int T1030_unsolicited_data_overflow(const char *initiator, const char *url, int data_loss, int show_info);