diff --git a/include/iscsi-private.h b/include/iscsi-private.h index ca2ee36..4304168 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -229,11 +229,6 @@ struct iscsi_pdu { #define ISCSI_PDU_DROP_ON_RECONNECT 0x00000004 /* stop sending after this PDU has been sent */ #define ISCSI_PDU_CORK_WHEN_SENT 0x00000008 -/* put this immediate delivery PDU in front of outqueue. - * This is currently only used for immediate logout requests - * as answer to an async logout event. */ -#define ISCSI_PDU_URGENT_DELIVERY 0x00000010 - uint32_t flags; @@ -371,10 +366,6 @@ uint32_t iscsi_itt_post_increment(struct iscsi_context *iscsi); void iscsi_timeout_scan(struct iscsi_context *iscsi); -int -iscsi_logout_async_internal(struct iscsi_context *iscsi, iscsi_command_cb cb, - void *private_data, uint32_t flags); - #ifdef __cplusplus } #endif diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index 7877b0d..b7da624 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -115,9 +115,6 @@ iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu, /* ttt */ iscsi_pdu_set_ttt(pdu, ttt); - /* exp statsn */ - iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); - /* data sn */ iscsi_pdu_set_datasn(pdu, cmd_pdu->datasn++); @@ -305,13 +302,8 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, iscsi_pdu_set_expxferlen(pdu, task->expxferlen); /* cmdsn */ - iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); - pdu->cmdsn = iscsi->cmdsn; - iscsi->cmdsn++; + iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn++); - /* exp statsn */ - iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); - /* cdb */ iscsi_pdu_set_cdb(pdu, task); diff --git a/lib/login.c b/lib/login.c index 33d20a2..f0e8be4 100644 --- a/lib/login.c +++ b/lib/login.c @@ -790,6 +790,13 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb, return -1; } + /* randomize cmdsn and itt */ + if (!iscsi->current_phase && !iscsi->secneg_phase) { + iscsi->itt = (u_int32_t) rand(); + iscsi->cmdsn = (u_int32_t) rand(); + iscsi->expcmdsn = iscsi->maxcmdsn = iscsi->cmdsn; + } + pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_LOGIN_REQUEST, ISCSI_PDU_LOGIN_RESPONSE, @@ -804,6 +811,9 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb, /* login request */ iscsi_pdu_set_immediate(pdu); + /* cmdsn is not increased if Immediate delivery*/ + iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); + if (!iscsi->user[0]) { iscsi->current_phase = ISCSI_PDU_LOGIN_CSG_OPNEG; } @@ -1034,7 +1044,13 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, status = scsi_get_uint16(&in->hdr[36]); - iscsi_adjust_statsn(iscsi, in); + // Status-Class is 0 + if (!(status >> 8)) { + if (!iscsi->current_phase && !iscsi->secneg_phase) { + iscsi->statsn = scsi_get_uint32(&in->hdr[24]); + } + iscsi_adjust_statsn(iscsi, in); + } iscsi_adjust_maxexpcmdsn(iscsi, in); /* Using bidirectional CHAP? Then we must see a chap_n and chap_r @@ -1236,8 +1252,8 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, } int -iscsi_logout_async_internal(struct iscsi_context *iscsi, iscsi_command_cb cb, - void *private_data, uint32_t flags) +iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb, + void *private_data) { struct iscsi_pdu *pdu; @@ -1252,7 +1268,7 @@ iscsi_logout_async_internal(struct iscsi_context *iscsi, iscsi_command_cb cb, ISCSI_PDU_LOGOUT_REQUEST, ISCSI_PDU_LOGOUT_RESPONSE, iscsi_itt_post_increment(iscsi), - ISCSI_PDU_DROP_ON_RECONNECT|ISCSI_PDU_CORK_WHEN_SENT|flags); + ISCSI_PDU_DROP_ON_RECONNECT|ISCSI_PDU_CORK_WHEN_SENT); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate " "logout pdu."); @@ -1267,10 +1283,6 @@ iscsi_logout_async_internal(struct iscsi_context *iscsi, iscsi_command_cb cb, /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); - pdu->cmdsn = iscsi->cmdsn; - - /* exp statsn */ - iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); pdu->callback = cb; pdu->private_data = private_data; @@ -1285,13 +1297,6 @@ iscsi_logout_async_internal(struct iscsi_context *iscsi, iscsi_command_cb cb, return 0; } -int -iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb, - void *private_data) -{ - return iscsi_logout_async_internal(iscsi, cb, private_data, 0); -} - int iscsi_process_logout_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) diff --git a/lib/nop.c b/lib/nop.c index 993ed77..e010673 100644 --- a/lib/nop.c +++ b/lib/nop.c @@ -46,9 +46,6 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, return -1; } - /* immediate flag */ - iscsi_pdu_set_immediate(pdu); - /* flags */ iscsi_pdu_set_pduflags(pdu, 0x80); @@ -58,12 +55,8 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, /* lun */ iscsi_pdu_set_lun(pdu, 0); - /* cmdsn is not increased if Immediate delivery*/ - iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); - pdu->cmdsn = iscsi->cmdsn; - - /* exp statsn */ - iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); + /* cmdsn */ + iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn++); pdu->callback = cb; pdu->private_data = private_data; @@ -83,7 +76,9 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, } iscsi->nops_in_flight++; - ISCSI_LOG(iscsi, 6, "NOP Out Send (nops_in_flight: %d)", iscsi->nops_in_flight); + ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6, + "NOP Out Send (nops_in_flight: %d, pdu->cmdsn %08x, pdu->itt %08x, pdu->ttt %08x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x)", + iscsi->nops_in_flight, pdu->cmdsn, pdu->itt, 0xffffffff, iscsi->maxcmdsn, iscsi->expcmdsn); return 0; } @@ -117,10 +112,6 @@ iscsi_send_target_nop_out(struct iscsi_context *iscsi, uint32_t ttt) /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); - pdu->cmdsn = iscsi->cmdsn; - - /* exp statsn */ - iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1); if (iscsi_queue_pdu(iscsi, pdu) != 0) { iscsi_set_error(iscsi, "failed to queue iscsi nop-out pdu"); @@ -128,6 +119,10 @@ iscsi_send_target_nop_out(struct iscsi_context *iscsi, uint32_t ttt) return -1; } + ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6, + "NOP Out Send (nops_in_flight: %d, pdu->cmdsn %08x, pdu->itt %08x, pdu->ttt %08x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x)", + iscsi->nops_in_flight, pdu->cmdsn, 0xffffffff, ttt, iscsi->maxcmdsn, iscsi->expcmdsn); + return 0; } @@ -137,9 +132,14 @@ iscsi_process_nop_out_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, { struct iscsi_data data; - iscsi->nops_in_flight = 0; + iscsi_adjust_maxexpcmdsn(iscsi, in); + iscsi_adjust_statsn(iscsi, in); - ISCSI_LOG(iscsi, 6, "NOP Out Reply received"); + ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6, + "NOP-In received (pdu->itt %08x, pdu->ttt %08x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x, iscsi->statsn %08x)", + pdu->itt, 0xffffffff, iscsi->maxcmdsn, iscsi->expcmdsn, iscsi->statsn); + + iscsi->nops_in_flight = 0; if (pdu->callback == NULL) { return 0; diff --git a/lib/pdu.c b/lib/pdu.c index 3d0b5c4..d6b09ca 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -319,11 +319,15 @@ static const char *iscsi_reject_reason_str(enum iscsi_reject_reason reason) int iscsi_process_target_nop_in(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) { - uint32_t ttt; - - ttt = scsi_get_uint32(&in->hdr[20]); + uint32_t ttt = scsi_get_uint32(&in->hdr[20]); + uint32_t itt = scsi_get_uint32(&in->hdr[16]); iscsi_adjust_statsn(iscsi, in); + iscsi_adjust_maxexpcmdsn(iscsi, in); + + ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6, + "NOP-In received (pdu->itt %08x, pdu->ttt %08x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x, iscsi->statsn %08x)", + itt, ttt, iscsi->maxcmdsn, iscsi->expcmdsn, iscsi->statsn); /* if the server does not want a response */ if (ttt == 0xffffffff) { @@ -365,7 +369,7 @@ int iscsi_process_reject(struct iscsi_context *iscsi, if (reason == ISCSI_REJECT_WAITING_FOR_LOGOUT) { ISCSI_LOG(iscsi, 1, "target rejects request with reason: %s", iscsi_reject_reason_str(reason)); - iscsi_logout_async_internal(iscsi, iscsi_reconnect_after_logout, NULL, ISCSI_PDU_URGENT_DELIVERY); + iscsi_logout_async(iscsi, iscsi_reconnect_after_logout, NULL); return 0; } @@ -435,7 +439,7 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) ISCSI_LOG(iscsi, 2, "dropping connection to fix errors with broken DELL Equallogic firmware 7.x"); return -1; } - iscsi_logout_async_internal(iscsi, iscsi_reconnect_after_logout, NULL, ISCSI_PDU_URGENT_DELIVERY); + iscsi_logout_async(iscsi, iscsi_reconnect_after_logout, NULL); return 0; case 0x2: ISCSI_LOG(iscsi, 2, "target will drop this connection. Time2Wait is %u seconds", param2); @@ -447,7 +451,7 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) return 0; case 0x4: ISCSI_LOG(iscsi, 2, "target requests parameter renogitiation."); - iscsi_logout_async_internal(iscsi, iscsi_reconnect_after_logout, NULL, ISCSI_PDU_DROP_ON_RECONNECT); + iscsi_logout_async(iscsi, iscsi_reconnect_after_logout, NULL); return 0; default: ISCSI_LOG(iscsi, 1, "unhandled async event %u: param1 %u param2 %u param3 %u", event, param1, param2, param3); @@ -621,6 +625,7 @@ void iscsi_pdu_set_cmdsn(struct iscsi_pdu *pdu, uint32_t cmdsn) { scsi_set_uint32(&pdu->outdata.data[24], cmdsn); + pdu->cmdsn = cmdsn; } void diff --git a/lib/socket.c b/lib/socket.c index d73859c..dd2e4bb 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -92,10 +92,17 @@ iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) /* queue pdus in ascending order of CmdSN. * ensure that pakets with the same CmdSN are kept in FIFO order. + * immediate PDUs are queued in front of queue with the CmdSN + * of the first element in the outqueue. */ + + if (pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) { + iscsi_pdu_set_cmdsn(pdu, current->cmdsn); + } + do { if (iscsi_serial32_compare(pdu->cmdsn, current->cmdsn) < 0 || - pdu->flags & ISCSI_PDU_URGENT_DELIVERY) { + (pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE && !(current->outdata.data[0] & ISCSI_PDU_IMMEDIATE))) { /* insert PDU before the current */ if (last != NULL) { last->next=pdu; @@ -386,7 +393,10 @@ iscsi_which_events(struct iscsi_context *iscsi) if (iscsi->outqueue_current != NULL || (iscsi->outqueue != NULL && !iscsi->is_corked && - iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) <= 0)) { + (iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) <= 0 || + iscsi->outqueue->outdata.data[0] & ISCSI_PDU_IMMEDIATE) + ) + ) { events |= POLLOUT; } return events; @@ -639,13 +649,19 @@ iscsi_write_to_socket(struct iscsi_context *iscsi) iscsi->outqueue->cmdsn, iscsi->maxcmdsn); return 0; } + /* pop first element of the outqueue */ - if (iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->expcmdsn) < 0) { - iscsi_set_error(iscsi, "iscsi_write_to_scoket: outqueue[0]->cmdsn < expcmdsn (%08x < %08x)", - iscsi->outqueue->cmdsn, iscsi->expcmdsn); + if (iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->expcmdsn) < 0 && + (iscsi->outqueue->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) { + iscsi_set_error(iscsi, "iscsi_write_to_scoket: outqueue[0]->cmdsn < expcmdsn (%08x < %08x) opcode %02x", + iscsi->outqueue->cmdsn, iscsi->expcmdsn, iscsi->outqueue->outdata.data[0] & 0x3f); return -1; } iscsi->outqueue_current = iscsi->outqueue; + + /* set exp statsn */ + iscsi_pdu_set_expstatsn(iscsi->outqueue_current, iscsi->statsn + 1); + ISCSI_LIST_REMOVE(&iscsi->outqueue, iscsi->outqueue_current); if (!(iscsi->outqueue_current->flags & ISCSI_PDU_DELETE_WHEN_SENT)) { /* we have to add the pdu to the waitqueue already here diff --git a/lib/task_mgmt.c b/lib/task_mgmt.c index 0847103..237ccad 100644 --- a/lib/task_mgmt.c +++ b/lib/task_mgmt.c @@ -73,7 +73,6 @@ iscsi_task_mgmt_async(struct iscsi_context *iscsi, /* cmdsn is not increased if Immediate delivery*/ iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn); - pdu->cmdsn = iscsi->cmdsn; /* rcmdsn */ iscsi_pdu_set_rcmdsn(pdu, rcmdsn); diff --git a/utils/iscsi-perf.c b/utils/iscsi-perf.c index a9a84c3..30c5bb2 100644 --- a/utils/iscsi-perf.c +++ b/utils/iscsi-perf.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "iscsi.h" #include "scsi-lowlevel.h" @@ -33,7 +34,11 @@ #define VERSION "0.1" +#define NOP_INTERVAL 5 +#define MAX_NOP_FAILURES 3 + const char *initiator = "iqn.2010-11.libiscsi:iscsi-perf"; +int proc_alarm = 0; int max_in_flight = 32; int blocks_per_io = 8; uint64_t runtime = 0; @@ -43,6 +48,7 @@ struct client { int finished; int in_flight; int random; + int random_blocks; struct iscsi_context *iscsi; struct scsi_iovec perf_iov; @@ -55,6 +61,8 @@ struct client { uint64_t first_ns; uint64_t iops; uint64_t last_iops; + uint64_t bytes; + uint64_t last_bytes; int ignore_errors; int busy_cnt; @@ -92,40 +100,44 @@ void progress(struct client *client) { if (runtime) _runtime = runtime - _runtime; printf ("\r"); - uint64_t aiops = 1000000000UL * (client->iops) / (now - client->first_ns); + uint64_t aiops = 1000000000.0 * (client->iops) / (now - client->first_ns); + uint64_t ambps = 1000000000.0 * (client->bytes) / (now - client->first_ns); if (!_runtime) { finished = 1; printf ("iops average %" PRIu64 " (%" PRIu64 " MB/s) ", aiops, (aiops * blocks_per_io * client->blocksize) >> 20); } else { uint64_t iops = 1000000000UL * (client->iops - client->last_iops) / (now - client->last_ns); + uint64_t mbps = 1000000000UL * (client->bytes - client->last_bytes) / (now - client->last_ns); printf ("%02" PRIu64 ":%02" PRIu64 ":%02" PRIu64 " - ", _runtime / 3600, (_runtime % 3600) / 60, _runtime % 60); - printf ("lba %" PRIu64 ", iops current %" PRIu64 " (%" PRIu64 " MB/s), ", client->pos, iops, (iops * blocks_per_io * client->blocksize) >> 20); - printf ("iops average %" PRIu64 " (%" PRIu64 " MB/s), in_flight %d, busy %d ", aiops, (aiops * blocks_per_io * client->blocksize) >> 20, client->in_flight, client->busy_cnt); + printf ("lba %" PRIu64 ", iops current %" PRIu64 " (%" PRIu64 " MB/s), ", client->pos, iops, mbps >> 20); + printf ("iops average %" PRIu64 " (%" PRIu64 " MB/s), in_flight %d, busy %d ", aiops, ambps >> 20, client->in_flight, client->busy_cnt); } fflush(stdout); client->last_ns = now; client->last_iops = client->iops; + client->last_bytes = client->bytes; } void cb(struct iscsi_context *iscsi _U_, int status, void *command_data, void *private_data) { struct client *client = (struct client *)private_data; struct scsi_task *task = command_data, *task2 = NULL; + struct scsi_read16_cdb *read16_cdb = NULL; + + read16_cdb = scsi_cdb_unmarshall(task, SCSI_OPCODE_READ16); + if (read16_cdb == NULL) { + fprintf(stderr, "Failed to unmarshall READ16 CDB.\n"); + client->err_cnt++; + goto out; + } if (status == SCSI_STATUS_BUSY || (status == SCSI_STATUS_CHECK_CONDITION && task->sense.key == SCSI_SENSE_UNIT_ATTENTION)) { - struct scsi_read16_cdb *read16_cdb = NULL; if (client->retry_cnt++ > 4 * max_in_flight) { fprintf(stderr, "maxium number of command retries reached...\n"); client->err_cnt++; goto out; } - read16_cdb = scsi_cdb_unmarshall(task, SCSI_OPCODE_READ16); - if (read16_cdb == NULL) { - fprintf(stderr, "Failed to unmarshall READ16 CDB.\n"); - client->err_cnt++; - goto out; - } task2 = iscsi_read16_task(client->iscsi, client->lun, read16_cdb->lba, read16_cdb->transfer_length * client->blocksize, @@ -143,6 +155,7 @@ void cb(struct iscsi_context *iscsi _U_, int status, void *command_data, void *p client->err_cnt++; } else if (status == SCSI_STATUS_GOOD) { client->retry_cnt = 0; + client->bytes += read16_cdb->transfer_length * client->blocksize; } else { fprintf(stderr, "Read16 failed with %s\n", iscsi_get_error(iscsi)); if (!client->ignore_errors) { @@ -181,6 +194,10 @@ void fill_read_queue(struct client *client) if (num_blocks > blocks_per_io) { num_blocks = blocks_per_io; } + + if (client->random_blocks) { + num_blocks = rand() % num_blocks + 1; + } task = iscsi_read16_task(client->iscsi, client->lun, client->pos, @@ -202,8 +219,17 @@ void usage(void) { exit(1); } -void sig_handler (int signum _U_) { - finished = 1; +void sig_handler (int signum ) { + if (signum == SIGALRM) { + if (proc_alarm) { + fprintf(stderr, "\n\nABORT: Last alarm was not processed.\n"); + exit(10); + } + proc_alarm = 1; + alarm(NOP_INTERVAL); + } else { + finished = 1; + } } int main(int argc, char *argv[]) @@ -222,6 +248,7 @@ int main(int argc, char *argv[]) {"blocks", required_argument, NULL, 'b'}, {"runtime", required_argument, NULL, 't'}, {"random", no_argument, NULL, 'r'}, + {"random-blocks", no_argument, NULL, 'R'}, {"ignore-errors", no_argument, NULL, 'n'}, {0, 0, 0, 0} }; @@ -233,7 +260,7 @@ int main(int argc, char *argv[]) printf("iscsi-perf version %s - (c) 2014-2015 by Peter Lieven \n\n", VERSION); - while ((c = getopt_long(argc, argv, "i:m:b:t:nr", long_options, + while ((c = getopt_long(argc, argv, "i:m:b:t:nrR", long_options, &option_index)) != -1) { switch (c) { case 'i': @@ -254,6 +281,9 @@ int main(int argc, char *argv[]) case 'r': client.random = 1; break; + case 'R': + client.random_blocks = 1; + break; default: fprintf(stderr, "Unrecognized option '%c'\n\n", c); usage(); @@ -324,8 +354,13 @@ int main(int argc, char *argv[]) printf("capacity is %" PRIu64 " blocks or %" PRIu64 " byte (%" PRIu64 " MB)\n", client.num_blocks, client.num_blocks * client.blocksize, (client.num_blocks * client.blocksize) >> 20); - printf("performing %s READ with %d parallel requests\nfixed transfer size of %d blocks (%d byte)\n", - client.random ? "random" : "sequential", max_in_flight, blocks_per_io, blocks_per_io * client.blocksize); + printf("performing %s READ with %d parallel requests\n", client.random ? "RANDOM" : "SEQUENTIAL", max_in_flight); + + if (client.random_blocks) { + printf("RANDOM transfer size of 1 - %d blocks (%d - %d byte)\n", blocks_per_io, client.blocksize, blocks_per_io * client.blocksize); + } else { + printf("FIXED transfer size of %d blocks (%d byte)\n", blocks_per_io, blocks_per_io * client.blocksize); + } if (runtime) { printf("will run for %" PRIu64 " seconds.\n", runtime); @@ -340,6 +375,7 @@ int main(int argc, char *argv[]) sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); + sigaction(SIGALRM, &sa, NULL); printf("\n"); @@ -347,10 +383,21 @@ int main(int argc, char *argv[]) fill_read_queue(&client); + alarm(NOP_INTERVAL); + while (client.in_flight && !client.err_cnt) { pfd[0].fd = iscsi_get_fd(client.iscsi); pfd[0].events = iscsi_which_events(client.iscsi); + if (proc_alarm) { + if (iscsi_get_nops_in_flight(client.iscsi) > MAX_NOP_FAILURES) { + fprintf(stderr, "\n\nABORT: NOP timeout.\n"); + exit(10); + } + iscsi_nop_out_async(client.iscsi, NULL, NULL, 0, NULL); + proc_alarm = 0; + } + if (poll(&pfd[0], 1, -1) < 0) { continue; } @@ -359,6 +406,8 @@ int main(int argc, char *argv[]) break; } } + + alarm(0); progress(&client);