Add support for R2T PDUs.
Update the "send scsi command" fucntion to honour "FirstBurstLength" so that we only send this many bytes as unsolicited data. The wait for a train of R2T from the target to clock out additional busrts of data until the full task data has been sent to the Target. We should now honour, and handle the case of ImmediateData=No InitialR2T=No correctly for targets that are limited on receiveing data too fast.
This commit is contained in:
@@ -62,12 +62,15 @@ void write10_cb(struct iscsi_context *iscsi _U_, int status, void *command_data,
|
||||
struct scsi_task *task = command_data;
|
||||
|
||||
if (status == SCSI_STATUS_CHECK_CONDITION) {
|
||||
|
||||
printf("Write10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq);
|
||||
exit(10);
|
||||
}
|
||||
if (status != SCSI_STATUS_GOOD) {
|
||||
printf("Write10 failed with %s\n", iscsi_get_error(iscsi));
|
||||
exit(10);
|
||||
}
|
||||
|
||||
printf("Write successful\n");
|
||||
printf("Write successful :%d\n", status);
|
||||
exit(10);
|
||||
}
|
||||
|
||||
|
||||
@@ -147,6 +147,7 @@ enum iscsi_opcode {
|
||||
ISCSI_PDU_TEXT_RESPONSE = 0x24,
|
||||
ISCSI_PDU_DATA_IN = 0x25,
|
||||
ISCSI_PDU_LOGOUT_RESPONSE = 0x26,
|
||||
ISCSI_PDU_R2T = 0x31,
|
||||
ISCSI_PDU_NO_PDU = 0xff
|
||||
};
|
||||
|
||||
@@ -228,11 +229,8 @@ int iscsi_process_scsi_data_in(struct iscsi_context *iscsi,
|
||||
int iscsi_process_nop_out_reply(struct iscsi_context *iscsi,
|
||||
struct iscsi_pdu *pdu,
|
||||
struct iscsi_in_pdu *in);
|
||||
|
||||
int iscsi_send_data_out(struct iscsi_context *iscsi,
|
||||
struct iscsi_pdu *pdu,
|
||||
uint32_t offset,
|
||||
uint32_t len);
|
||||
int iscsi_process_r2t(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
||||
struct iscsi_in_pdu *in);
|
||||
|
||||
void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string,
|
||||
...);
|
||||
|
||||
20
lib/pdu.c
20
lib/pdu.c
@@ -213,6 +213,14 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
|
||||
expected_response = ISCSI_PDU_DATA_IN;
|
||||
}
|
||||
|
||||
/* Another special case is if we get a R2T.
|
||||
* In this case we should find the original request and just send an additional
|
||||
* DATAOUT segment for this task.
|
||||
*/
|
||||
if (opcode == ISCSI_PDU_R2T) {
|
||||
expected_response = ISCSI_PDU_R2T;
|
||||
}
|
||||
|
||||
if (opcode != expected_response) {
|
||||
iscsi_set_error(iscsi, "Got wrong opcode back for "
|
||||
"itt:%d got:%d expected %d",
|
||||
@@ -274,9 +282,19 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case ISCSI_PDU_R2T:
|
||||
if (iscsi_process_r2t(iscsi, pdu, in) != 0) {
|
||||
SLIST_REMOVE(&iscsi->waitpdu, pdu);
|
||||
iscsi_free_pdu(iscsi, pdu);
|
||||
iscsi_set_error(iscsi, "iscsi r2t "
|
||||
"failed");
|
||||
return -1;
|
||||
}
|
||||
is_finished = 0;
|
||||
break;
|
||||
default:
|
||||
iscsi_set_error(iscsi, "Dont know how to handle "
|
||||
"opcode %d", opcode);
|
||||
"opcode 0x%02x", opcode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,9 +80,9 @@ iscsi_scsi_response_cb(struct iscsi_context *iscsi, int status,
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu,
|
||||
uint32_t offset, uint32_t tot_len)
|
||||
uint32_t ttt, uint32_t offset, uint32_t tot_len)
|
||||
{
|
||||
while (tot_len > 0) {
|
||||
uint32_t len = tot_len;
|
||||
@@ -122,7 +122,7 @@ iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu,
|
||||
iscsi_pdu_set_lun(pdu, cmd_pdu->lun);
|
||||
|
||||
/* ttt */
|
||||
iscsi_pdu_set_ttt(pdu, 0xffffffff);
|
||||
iscsi_pdu_set_ttt(pdu, ttt);
|
||||
|
||||
/* exp statsn */
|
||||
iscsi_pdu_set_expstatsn(pdu, iscsi->statsn+1);
|
||||
@@ -176,6 +176,7 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
|
||||
struct iscsi_pdu *pdu;
|
||||
struct iscsi_scsi_cbdata *scsi_cbdata;
|
||||
struct iscsi_data data;
|
||||
uint32_t offset = 0;
|
||||
|
||||
int flags;
|
||||
|
||||
@@ -300,7 +301,12 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
|
||||
|
||||
/* Can we send some unsolicited data ? */
|
||||
if (pdu->nidata.size != 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO) {
|
||||
iscsi_send_data_out(iscsi, pdu, 0, pdu->nidata.size);
|
||||
uint32_t len = pdu->nidata.size - offset;
|
||||
|
||||
if (len > iscsi->first_burst_length) {
|
||||
len = iscsi->first_burst_length;
|
||||
}
|
||||
iscsi_send_data_out(iscsi, pdu, 0xffffffff, offset, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -444,8 +450,19 @@ iscsi_process_scsi_data_in(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
iscsi_process_r2t(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
||||
struct iscsi_in_pdu *in)
|
||||
{
|
||||
uint32_t ttt, offset, len;
|
||||
|
||||
ttt = ntohl(*(uint32_t *)&in->hdr[20]);
|
||||
offset = ntohl(*(uint32_t *)&in->hdr[40]);
|
||||
len = ntohl(*(uint32_t *)&in->hdr[44]);
|
||||
|
||||
iscsi_send_data_out(iscsi, pdu, ttt, offset, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SCSI commands
|
||||
|
||||
Reference in New Issue
Block a user