mirror of
https://github.com/opnsense/src.git
synced 2026-06-08 16:22:46 -04:00
iscsi: Teach the iSCSI stack about "large" received PDUs.
When using iSCSI PDU offload (cxgbei) on T6 adapters, a burst of received PDUs can be reported via a single message to the driver. Previously the driver passed these multi-PDU bursts up to the iSCSI stack up as a single "large" PDU by rewriting the buffer offset, data segment length, and DataSN fields in the iSCSI header. The DataSN field in particular was rewritten so that each of the "large" PDUs used consecutively increasing values. While this worked, the forged DataSN values did not match the ExpDataSN value in the subsequent SCSI Response PDU. The initiator does not currently verify this value, but the forged DataSN values prevent adding a check. To avoid this, allow a logical iSCSI PDU (struct icl_pdu) to describe a burst of PDUs via a new 'ip_additional_pdus' field. Normally this field is set to zero when 'struct icl_pdu' represents a single PDU. If logical PDU represents a burst of on-the-wire PDUs, then 'ip_npdus' contains the count of additional on-the-wire PDUs. The header of this "large" PDU is still modified, but the DataSN field now contains the DataSN value of the first on-the-wire PDU in the burst. Reviewed by: mav Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D31577
This commit is contained in:
parent
d7e1bdfeba
commit
c261b6ea4e
5 changed files with 20 additions and 10 deletions
|
|
@ -917,7 +917,7 @@ cfiscsi_pdu_handle_data_out(struct icl_pdu *request)
|
|||
cfiscsi_session_terminate(cs);
|
||||
return;
|
||||
}
|
||||
cdw->cdw_datasn++;
|
||||
cdw->cdw_datasn += request->ip_additional_pdus + 1;
|
||||
|
||||
io = cdw->cdw_ctl_io;
|
||||
KASSERT((io->io_hdr.flags & CTL_FLAG_DATA_MASK) != CTL_FLAG_DATA_IN,
|
||||
|
|
|
|||
|
|
@ -583,10 +583,12 @@ do_rx_iscsi_cmp(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
|
|||
cmp->next_buffer_offset;
|
||||
|
||||
if (prev_seg_len != 0) {
|
||||
uint32_t orig_datasn;
|
||||
|
||||
/*
|
||||
* Since cfiscsi doesn't know about previous
|
||||
* headers, pretend that the entire r2t data
|
||||
* length was received in this single segment.
|
||||
* Return a "large" PDU representing the burst
|
||||
* of PDUs. Adjust the offset and length of
|
||||
* this PDU to represent the entire burst.
|
||||
*/
|
||||
ip->ip_data_len += prev_seg_len;
|
||||
bhsdo->bhsdo_data_segment_len[2] = ip->ip_data_len;
|
||||
|
|
@ -595,17 +597,19 @@ do_rx_iscsi_cmp(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
|
|||
bhsdo->bhsdo_buffer_offset =
|
||||
htobe32(cmp->next_buffer_offset);
|
||||
|
||||
npdus = htobe32(bhsdo->bhsdo_datasn) - cmp->last_datasn;
|
||||
orig_datasn = htobe32(bhsdo->bhsdo_datasn);
|
||||
npdus = orig_datasn - cmp->last_datasn;
|
||||
bhsdo->bhsdo_datasn = htobe32(cmp->last_datasn + 1);
|
||||
cmp->last_datasn = orig_datasn;
|
||||
ip->ip_additional_pdus = npdus - 1;
|
||||
} else {
|
||||
MPASS(htobe32(bhsdo->bhsdo_datasn) ==
|
||||
cmp->last_datasn + 1);
|
||||
npdus = 1;
|
||||
cmp->last_datasn = htobe32(bhsdo->bhsdo_datasn);
|
||||
}
|
||||
|
||||
cmp->next_buffer_offset += ip->ip_data_len;
|
||||
cmp->last_datasn = htobe32(bhsdo->bhsdo_datasn);
|
||||
bhsdo->bhsdo_datasn = htobe32(cmp->next_datasn);
|
||||
cmp->next_datasn++;
|
||||
toep->ofld_rxq->rx_iscsi_ddp_pdus += npdus;
|
||||
toep->ofld_rxq->rx_iscsi_ddp_octets += ip->ip_data_len;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ struct cxgbei_cmp {
|
|||
|
||||
uint32_t tt; /* Transfer tag. */
|
||||
|
||||
uint32_t next_datasn;
|
||||
uint32_t next_buffer_offset;
|
||||
uint32_t last_datasn;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1346,7 +1346,6 @@ no_ddp:
|
|||
prsv->prsv_tag &= ~pr->pr_alias_mask;
|
||||
prsv->prsv_tag |= alias << pr->pr_alias_shift & pr->pr_alias_mask;
|
||||
|
||||
ddp->cmp.next_datasn = 0;
|
||||
ddp->cmp.last_datasn = -1;
|
||||
cxgbei_insert_cmp(icc, &ddp->cmp, prsv->prsv_tag);
|
||||
*tttp = htobe32(prsv->prsv_tag);
|
||||
|
|
|
|||
|
|
@ -75,6 +75,14 @@ struct icl_pdu {
|
|||
size_t ip_data_len;
|
||||
struct mbuf *ip_data_mbuf;
|
||||
|
||||
/*
|
||||
* When a "large" received PDU represents multiple on-the-wire
|
||||
* PDUs, this is the count of additional on-the-wire PDUs.
|
||||
* For PDUs that match on-the-wire PDUs, this should be set to
|
||||
* zero.
|
||||
*/
|
||||
u_int ip_additional_pdus;
|
||||
|
||||
/*
|
||||
* User (initiator or provider) private fields.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue