}
static void
-cxgbit_proc_ddp_status(unsigned int tid, struct cpl_rx_data_ddp *cpl,
- struct cxgbit_lro_pdu_cb *pdu_cb)
+cxgbit_process_ddpvld(struct cxgbit_sock *csk, struct cxgbit_lro_pdu_cb *pdu_cb,
+ u32 ddpvld)
{
- unsigned int status = ntohl(cpl->ddpvld);
- pdu_cb->flags |= PDUCBF_RX_STATUS;
- pdu_cb->ddigest = ntohl(cpl->ulp_crc);
- pdu_cb->pdulen = ntohs(cpl->len);
-
- if (status & (1 << CPL_RX_ISCSI_DDP_STATUS_HCRC_SHIFT)) {
- pr_info("tid 0x%x, status 0x%x, hcrc bad.\n", tid, status);
+ if (ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_HCRC_SHIFT)) {
+ pr_info("tid 0x%x, status 0x%x, hcrc bad.\n", csk->tid, ddpvld);
pdu_cb->flags |= PDUCBF_RX_HCRC_ERR;
}
- if (status & (1 << CPL_RX_ISCSI_DDP_STATUS_DCRC_SHIFT)) {
- pr_info("tid 0x%x, status 0x%x, dcrc bad.\n", tid, status);
+ if (ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_DCRC_SHIFT)) {
+ pr_info("tid 0x%x, status 0x%x, dcrc bad.\n", csk->tid, ddpvld);
pdu_cb->flags |= PDUCBF_RX_DCRC_ERR;
}
- if (status & (1 << CPL_RX_ISCSI_DDP_STATUS_PAD_SHIFT))
- pr_info("tid 0x%x, status 0x%x, pad bad.\n", tid, status);
+ if (ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_PAD_SHIFT))
+ pr_info("tid 0x%x, status 0x%x, pad bad.\n", csk->tid, ddpvld);
- if ((status & (1 << CPL_RX_ISCSI_DDP_STATUS_DDP_SHIFT)) &&
+ if ((ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_DDP_SHIFT)) &&
(!(pdu_cb->flags & PDUCBF_RX_DATA))) {
pdu_cb->flags |= PDUCBF_RX_DATA_DDPD;
}
lro_cb->pdu_idx);
struct cpl_rx_iscsi_ddp *cpl = (struct cpl_rx_iscsi_ddp *)(rsp + 1);
- cxgbit_proc_ddp_status(lro_cb->csk->tid, cpl, pdu_cb);
+ cxgbit_process_ddpvld(lro_cb->csk, pdu_cb, be32_to_cpu(cpl->ddpvld));
+
+ pdu_cb->flags |= PDUCBF_RX_STATUS;
+ pdu_cb->ddigest = ntohl(cpl->ulp_crc);
+ pdu_cb->pdulen = ntohs(cpl->len);
if (pdu_cb->flags & PDUCBF_RX_HDR)
pdu_cb->complete = true;
- lro_cb->complete = true;
lro_cb->pdu_totallen += pdu_cb->pdulen;
+ lro_cb->complete = true;
lro_cb->pdu_idx++;
}
cxgbit_skcb_flags(skb) = 0;
lro_cb->complete = false;
- } else {
+ } else if (op == CPL_ISCSI_DATA) {
struct cpl_iscsi_data *cpl = (struct cpl_iscsi_data *)gl->va;
offset = sizeof(struct cpl_iscsi_data);
pdu_cb->doffset = lro_cb->offset;
pdu_cb->nr_dfrags = gl->nfrags;
pdu_cb->dfrag_idx = skb_shinfo(skb)->nr_frags;
+ lro_cb->complete = false;
+ } else {
+ struct cpl_rx_iscsi_cmp *cpl;
+
+ cpl = (struct cpl_rx_iscsi_cmp *)gl->va;
+ offset = sizeof(struct cpl_rx_iscsi_cmp);
+ pdu_cb->flags |= (PDUCBF_RX_HDR | PDUCBF_RX_STATUS);
+ len = be16_to_cpu(cpl->len);
+ pdu_cb->hdr = gl->va + offset;
+ pdu_cb->hlen = len;
+ pdu_cb->hfrag_idx = skb_shinfo(skb)->nr_frags;
+ pdu_cb->ddigest = be32_to_cpu(cpl->ulp_crc);
+ pdu_cb->pdulen = ntohs(cpl->len);
+
+ if (unlikely(gl->nfrags > 1))
+ cxgbit_skcb_flags(skb) = 0;
+
+ cxgbit_process_ddpvld(lro_cb->csk, pdu_cb,
+ be32_to_cpu(cpl->ddpvld));
+
+ if (pdu_cb->flags & PDUCBF_RX_DATA_DDPD) {
+ pdu_cb->flags |= PDUCBF_RX_DDP_CMP;
+ pdu_cb->complete = true;
+ } else if (pdu_cb->flags & PDUCBF_RX_DATA) {
+ pdu_cb->complete = true;
+ }
+
+ lro_cb->pdu_totallen += pdu_cb->hlen + pdu_cb->dlen;
+ lro_cb->complete = true;
+ lro_cb->pdu_idx++;
}
cxgbit_copy_frags(skb, gl, offset);
switch (op) {
case CPL_ISCSI_HDR:
case CPL_ISCSI_DATA:
+ case CPL_RX_ISCSI_CMP:
case CPL_RX_ISCSI_DDP:
case CPL_FW4_ACK:
lro_flush = false;
return 0;
}
- if (op == CPL_ISCSI_HDR || op == CPL_ISCSI_DATA) {
+ if ((op == CPL_ISCSI_HDR) || (op == CPL_ISCSI_DATA) ||
+ (op == CPL_RX_ISCSI_CMP)) {
if (!cxgbit_lro_receive(csk, op, rsp, gl, lro_mgr,
napi))
return 0;
int rc, sg_nents, sg_off;
bool dcrc_err = false;
- rc = iscsit_check_dataout_hdr(conn, (unsigned char *)hdr, &cmd);
- if (rc < 0)
- return rc;
- else if (!cmd)
- return 0;
+ if (pdu_cb->flags & PDUCBF_RX_DDP_CMP) {
+ u32 offset = be32_to_cpu(hdr->offset);
+ u32 ddp_data_len;
+ u32 payload_length = ntoh24(hdr->dlength);
+ bool success = false;
+
+ cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, 0);
+ if (!cmd)
+ return 0;
+
+ ddp_data_len = offset - cmd->write_data_done;
+ atomic_long_add(ddp_data_len, &conn->sess->rx_data_octets);
+
+ cmd->write_data_done = offset;
+ cmd->next_burst_len = ddp_data_len;
+ cmd->data_sn = be32_to_cpu(hdr->datasn);
+
+ rc = __iscsit_check_dataout_hdr(conn, (unsigned char *)hdr,
+ cmd, payload_length, &success);
+ if (rc < 0)
+ return rc;
+ else if (!success)
+ return 0;
+ } else {
+ rc = iscsit_check_dataout_hdr(conn, (unsigned char *)hdr, &cmd);
+ if (rc < 0)
+ return rc;
+ else if (!cmd)
+ return 0;
+ }
if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) {
pr_err("ITT: 0x%08x, Offset: %u, Length: %u,"
for (i = 0; i < ssi->nr_frags; i++)
put_page(skb_frag_page(&ssi->frags[i]));
ssi->nr_frags = 0;
+ skb->data_len = 0;
+ skb->truesize -= skb->len;
+ skb->len = 0;
}
static void
unsigned int len = 0;
if (pdu_cb->flags & PDUCBF_RX_HDR) {
- hpdu_cb->flags = pdu_cb->flags;
+ u8 hfrag_idx = hssi->nr_frags;
+
+ hpdu_cb->flags |= pdu_cb->flags;
hpdu_cb->seq = pdu_cb->seq;
hpdu_cb->hdr = pdu_cb->hdr;
hpdu_cb->hlen = pdu_cb->hlen;
- memcpy(&hssi->frags[0], &ssi->frags[pdu_cb->hfrag_idx],
+ memcpy(&hssi->frags[hfrag_idx], &ssi->frags[pdu_cb->hfrag_idx],
sizeof(skb_frag_t));
- get_page(skb_frag_page(&hssi->frags[0]));
- hssi->nr_frags = 1;
- hpdu_cb->frags = 1;
- hpdu_cb->hfrag_idx = 0;
+ get_page(skb_frag_page(&hssi->frags[hfrag_idx]));
+ hssi->nr_frags++;
+ hpdu_cb->frags++;
+ hpdu_cb->hfrag_idx = hfrag_idx;
- len = hssi->frags[0].size;
- hskb->len = len;
- hskb->data_len = len;
- hskb->truesize = len;
+ len = hssi->frags[hfrag_idx].size;
+ hskb->len += len;
+ hskb->data_len += len;
+ hskb->truesize += len;
}
if (pdu_cb->flags & PDUCBF_RX_DATA) {
- u8 hfrag_idx = 1, i;
+ u8 dfrag_idx = hssi->nr_frags, i;
hpdu_cb->flags |= pdu_cb->flags;
+ hpdu_cb->dfrag_idx = dfrag_idx;
len = 0;
- for (i = 0; i < pdu_cb->nr_dfrags; hfrag_idx++, i++) {
- memcpy(&hssi->frags[hfrag_idx],
+ for (i = 0; i < pdu_cb->nr_dfrags; dfrag_idx++, i++) {
+ memcpy(&hssi->frags[dfrag_idx],
&ssi->frags[pdu_cb->dfrag_idx + i],
sizeof(skb_frag_t));
- get_page(skb_frag_page(&hssi->frags[hfrag_idx]));
+ get_page(skb_frag_page(&hssi->frags[dfrag_idx]));
- len += hssi->frags[hfrag_idx].size;
+ len += hssi->frags[dfrag_idx].size;
hssi->nr_frags++;
hpdu_cb->frags++;
hpdu_cb->dlen = pdu_cb->dlen;
hpdu_cb->doffset = hpdu_cb->hlen;
hpdu_cb->nr_dfrags = pdu_cb->nr_dfrags;
- hpdu_cb->dfrag_idx = 1;
hskb->len += len;
hskb->data_len += len;
hskb->truesize += len;
static int cxgbit_rx_skb(struct cxgbit_sock *csk, struct sk_buff *skb)
{
+ struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi;
int ret = -1;
- if (likely(cxgbit_skcb_flags(skb) & SKCBF_RX_LRO))
- ret = cxgbit_rx_lro_skb(csk, skb);
+ if (likely(cxgbit_skcb_flags(skb) & SKCBF_RX_LRO)) {
+ if (is_t5(lldi->adapter_type))
+ ret = cxgbit_rx_lro_skb(csk, skb);
+ else
+ ret = cxgbit_process_lro_skb(csk, skb);
+ }
__kfree_skb(skb);
return ret;