diff --git a/include/iscsi-private.h b/include/iscsi-private.h index b55f25d..8a4e438 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -243,6 +243,7 @@ int iscsi_process_r2t(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in); int iscsi_process_reject(struct iscsi_context *iscsi, struct iscsi_in_pdu *in); +int iscsi_send_target_nop_out(struct iscsi_context *iscsi, uint32_t ttt); void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...); diff --git a/lib/nop.c b/lib/nop.c index 5fe6910..33c6502 100644 --- a/lib/nop.c +++ b/lib/nop.c @@ -47,12 +47,15 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, iscsi_pdu_set_ttt(pdu, 0xffffffff); /* lun */ - iscsi_pdu_set_lun(pdu, 2); + 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); + pdu->callback = cb; pdu->private_data = private_data; @@ -71,6 +74,46 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb, return 0; } +int +iscsi_send_target_nop_out(struct iscsi_context *iscsi, uint32_t ttt) +{ + struct iscsi_pdu *pdu; + + pdu = iscsi_allocate_pdu_with_itt_flags(iscsi, ISCSI_PDU_NOP_OUT, ISCSI_PDU_NO_PDU, + 0xffffffff,ISCSI_PDU_DELETE_WHEN_SENT|ISCSI_PDU_NO_CALLBACK); + if (pdu == NULL) { + iscsi_set_error(iscsi, "Failed to allocate nop-out pdu"); + return -1; + } + + /* immediate flag */ + iscsi_pdu_set_immediate(pdu); + + /* flags */ + iscsi_pdu_set_pduflags(pdu, 0x80); + + /* ttt */ + iscsi_pdu_set_ttt(pdu, ttt); + + /* 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); + + if (iscsi_queue_pdu(iscsi, pdu) != 0) { + iscsi_set_error(iscsi, "failed to queue iscsi nop-out pdu"); + iscsi_free_pdu(iscsi, pdu); + return -1; + } + + return 0; +} + int iscsi_process_nop_out_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) diff --git a/lib/pdu.c b/lib/pdu.c index dea174a..bcaf570 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -178,7 +178,7 @@ iscsi_get_pdu_data_size(const unsigned char *hdr) return size; } -static enum iscsi_reject_reason { +enum iscsi_reject_reason { ISCSI_REJECT_RESERVED = 0x01, ISCSI_REJECT_DATA_DIGEST_ERROR = 0x02, ISCSI_REJECT_SNACK_REJECT = 0x03, @@ -225,6 +225,32 @@ static const char *iscsi_reject_reason_str(enum iscsi_reject_reason reason) return "Unknown"; } +int iscsi_process_target_nop_in(struct iscsi_context *iscsi, + struct iscsi_in_pdu *in) +{ + uint32_t itt, ttt; + uint32_t statsn; + + itt = ntohl(*(uint32_t *)&in->hdr[16]); + + ttt = ntohl(*(uint32_t *)&in->hdr[20]); + + statsn = ntohl(*(uint32_t *)&in->hdr[24]); + if (statsn > iscsi->statsn) { + iscsi->statsn = statsn; + } + + /* if the server does not want a response */ + if (ttt == 0xffffffff) { + return 0; + } + + iscsi_send_target_nop_out(iscsi, ttt); + + return 0; +} + + int iscsi_process_reject(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) { @@ -289,6 +315,13 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) return 0; } + if (opcode == ISCSI_PDU_NOP_IN && itt == 0xffffffff) { + if (iscsi_process_target_nop_in(iscsi, in) != 0) { + return -1; + } + return 0; + } + for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) { enum iscsi_opcode expected_response = pdu->response_opcode; int is_finished = 1;