aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/iscsi/iscsi.c
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2021-08-06 21:03:00 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2021-08-06 21:03:00 +0000
commitf0594f52f6fdabecee134dd5700bf936283959ad (patch)
treebf0fb68eb6801fae9b51ef6a5f069c0fd2689b6c /sys/dev/iscsi/iscsi.c
parentd35164539b14a6d14fb587e58a0c7a1668d7643a (diff)
downloadsrc-f0594f52f6fdabecee134dd5700bf936283959ad.tar.gz
src-f0594f52f6fdabecee134dd5700bf936283959ad.zip
iSCSI: Add support for segmentation offload for hardware offloads.
Similar to TSO, iSCSI segmentation offload permits the upper layers to submit a "large" virtual PDU which is split up into multiple segments (PDUs) on the wire. Similar to how the TCP/IP headers are used as templates for TSO, the BHS at the start of a large PDU is used as a template to construct the specific BHS at the start of each PDU. In particular, the DataSN is incremented for each subsequent PDU, and the 'F' flag is only set on the last PDU. struct icl_conn has a new 'ic_hw_isomax' field which defaults to 0, but can be set to the largest virtual PDU a backend supports. If this value is non-zero, the iSCSI target and initiator use this size instead of 'ic_max_send_data_segment_length' to determine the maximum size for SCSI Data-In and SCSI Data-Out PDUs. Note that since PDUs can be constructed from multiple buffers before being dispatched, the target and initiator must wait for the PDU to be fully constructed before determining the number of DataSN values were consumed (and thus updating the per-transfer DataSN value used for the start of the next PDU). The target generates large PDUs for SCSI Data-In PDUs in cfiscsi_datamove_in(). The initiator generates large PDUs for SCSI Data-Out PDUs generated in response to an R2T. Reviewed by: mav Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D31222
Diffstat (limited to 'sys/dev/iscsi/iscsi.c')
-rw-r--r--sys/dev/iscsi/iscsi.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/sys/dev/iscsi/iscsi.c b/sys/dev/iscsi/iscsi.c
index 9a1b539e539b..60b3e3766da7 100644
--- a/sys/dev/iscsi/iscsi.c
+++ b/sys/dev/iscsi/iscsi.c
@@ -1154,7 +1154,7 @@ iscsi_pdu_handle_r2t(struct icl_pdu *response)
struct iscsi_bhs_data_out *bhsdo;
struct iscsi_outstanding *io;
struct ccb_scsiio *csio;
- size_t off, len, total_len;
+ size_t off, len, max_send_data_segment_length, total_len;
int error;
uint32_t datasn = 0;
@@ -1203,11 +1203,16 @@ iscsi_pdu_handle_r2t(struct icl_pdu *response)
//ISCSI_SESSION_DEBUG(is, "r2t; off %zd, len %zd", off, total_len);
+ if (is->is_conn->ic_hw_isomax != 0)
+ max_send_data_segment_length = is->is_conn->ic_hw_isomax;
+ else
+ max_send_data_segment_length =
+ is->is_conn->ic_max_send_data_segment_length;
for (;;) {
len = total_len;
- if (len > is->is_conn->ic_max_send_data_segment_length)
- len = is->is_conn->ic_max_send_data_segment_length;
+ if (len > max_send_data_segment_length)
+ len = max_send_data_segment_length;
if (off + len > csio->dxfer_len) {
ISCSI_SESSION_WARN(is, "target requested invalid "
@@ -1232,7 +1237,7 @@ iscsi_pdu_handle_r2t(struct icl_pdu *response)
bhsr2t->bhsr2t_initiator_task_tag;
bhsdo->bhsdo_target_transfer_tag =
bhsr2t->bhsr2t_target_transfer_tag;
- bhsdo->bhsdo_datasn = htonl(datasn++);
+ bhsdo->bhsdo_datasn = htonl(datasn);
bhsdo->bhsdo_buffer_offset = htonl(off);
error = icl_pdu_append_data(request, csio->data_ptr + off, len,
M_NOWAIT);
@@ -1245,6 +1250,8 @@ iscsi_pdu_handle_r2t(struct icl_pdu *response)
return;
}
+ datasn += howmany(len,
+ is->is_conn->ic_max_send_data_segment_length);
off += len;
total_len -= len;