1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 29730ffcbSVarun Prakash /* 39730ffcbSVarun Prakash * Copyright (c) 2016 Chelsio Communications, Inc. 49730ffcbSVarun Prakash */ 59730ffcbSVarun Prakash 69730ffcbSVarun Prakash #include <linux/workqueue.h> 79730ffcbSVarun Prakash #include <linux/kthread.h> 8174cd4b1SIngo Molnar #include <linux/sched/signal.h> 9174cd4b1SIngo Molnar 109730ffcbSVarun Prakash #include <asm/unaligned.h> 113bc71e1fSBart Van Assche #include <net/tcp.h> 129730ffcbSVarun Prakash #include <target/target_core_base.h> 139730ffcbSVarun Prakash #include <target/target_core_fabric.h> 149730ffcbSVarun Prakash #include "cxgbit.h" 159730ffcbSVarun Prakash 169730ffcbSVarun Prakash struct sge_opaque_hdr { 179730ffcbSVarun Prakash void *dev; 189730ffcbSVarun Prakash dma_addr_t addr[MAX_SKB_FRAGS + 1]; 199730ffcbSVarun Prakash }; 209730ffcbSVarun Prakash 219730ffcbSVarun Prakash static const u8 cxgbit_digest_len[] = {0, 4, 4, 8}; 229730ffcbSVarun Prakash 239730ffcbSVarun Prakash #define TX_HDR_LEN (sizeof(struct sge_opaque_hdr) + \ 249730ffcbSVarun Prakash sizeof(struct fw_ofld_tx_data_wr)) 259730ffcbSVarun Prakash 269730ffcbSVarun Prakash static struct sk_buff * 279730ffcbSVarun Prakash __cxgbit_alloc_skb(struct cxgbit_sock *csk, u32 len, bool iso) 289730ffcbSVarun Prakash { 299730ffcbSVarun Prakash struct sk_buff *skb = NULL; 309730ffcbSVarun Prakash u8 submode = 0; 319730ffcbSVarun Prakash int errcode; 329730ffcbSVarun Prakash static const u32 hdr_len = TX_HDR_LEN + ISCSI_HDR_LEN; 339730ffcbSVarun Prakash 349730ffcbSVarun Prakash if (len) { 359730ffcbSVarun Prakash skb = alloc_skb_with_frags(hdr_len, len, 369730ffcbSVarun Prakash 0, &errcode, 379730ffcbSVarun Prakash GFP_KERNEL); 389730ffcbSVarun Prakash if (!skb) 399730ffcbSVarun Prakash return NULL; 409730ffcbSVarun Prakash 419730ffcbSVarun Prakash skb_reserve(skb, TX_HDR_LEN); 429730ffcbSVarun Prakash skb_reset_transport_header(skb); 439730ffcbSVarun Prakash __skb_put(skb, ISCSI_HDR_LEN); 449730ffcbSVarun Prakash skb->data_len = len; 459730ffcbSVarun Prakash skb->len += len; 469730ffcbSVarun Prakash submode |= (csk->submode & CXGBIT_SUBMODE_DCRC); 479730ffcbSVarun Prakash 489730ffcbSVarun Prakash } else { 499730ffcbSVarun Prakash u32 iso_len = iso ? sizeof(struct cpl_tx_data_iso) : 0; 509730ffcbSVarun Prakash 519730ffcbSVarun Prakash skb = alloc_skb(hdr_len + iso_len, GFP_KERNEL); 529730ffcbSVarun Prakash if (!skb) 539730ffcbSVarun Prakash return NULL; 549730ffcbSVarun Prakash 559730ffcbSVarun Prakash skb_reserve(skb, TX_HDR_LEN + iso_len); 569730ffcbSVarun Prakash skb_reset_transport_header(skb); 579730ffcbSVarun Prakash __skb_put(skb, ISCSI_HDR_LEN); 589730ffcbSVarun Prakash } 599730ffcbSVarun Prakash 609730ffcbSVarun Prakash submode |= (csk->submode & CXGBIT_SUBMODE_HCRC); 619730ffcbSVarun Prakash cxgbit_skcb_submode(skb) = submode; 629730ffcbSVarun Prakash cxgbit_skcb_tx_extralen(skb) = cxgbit_digest_len[submode]; 639730ffcbSVarun Prakash cxgbit_skcb_flags(skb) |= SKCBF_TX_NEED_HDR; 649730ffcbSVarun Prakash return skb; 659730ffcbSVarun Prakash } 669730ffcbSVarun Prakash 679730ffcbSVarun Prakash static struct sk_buff *cxgbit_alloc_skb(struct cxgbit_sock *csk, u32 len) 689730ffcbSVarun Prakash { 699730ffcbSVarun Prakash return __cxgbit_alloc_skb(csk, len, false); 709730ffcbSVarun Prakash } 719730ffcbSVarun Prakash 729730ffcbSVarun Prakash /* 739730ffcbSVarun Prakash * cxgbit_is_ofld_imm - check whether a packet can be sent as immediate data 749730ffcbSVarun Prakash * @skb: the packet 759730ffcbSVarun Prakash * 769730ffcbSVarun Prakash * Returns true if a packet can be sent as an offload WR with immediate 779730ffcbSVarun Prakash * data. We currently use the same limit as for Ethernet packets. 789730ffcbSVarun Prakash */ 799730ffcbSVarun Prakash static int cxgbit_is_ofld_imm(const struct sk_buff *skb) 809730ffcbSVarun Prakash { 819730ffcbSVarun Prakash int length = skb->len; 829730ffcbSVarun Prakash 839730ffcbSVarun Prakash if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR)) 849730ffcbSVarun Prakash length += sizeof(struct fw_ofld_tx_data_wr); 859730ffcbSVarun Prakash 869730ffcbSVarun Prakash if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_ISO)) 879730ffcbSVarun Prakash length += sizeof(struct cpl_tx_data_iso); 889730ffcbSVarun Prakash 899730ffcbSVarun Prakash #define MAX_IMM_TX_PKT_LEN 256 909730ffcbSVarun Prakash return length <= MAX_IMM_TX_PKT_LEN; 919730ffcbSVarun Prakash } 929730ffcbSVarun Prakash 939730ffcbSVarun Prakash /* 949730ffcbSVarun Prakash * cxgbit_sgl_len - calculates the size of an SGL of the given capacity 959730ffcbSVarun Prakash * @n: the number of SGL entries 969730ffcbSVarun Prakash * Calculates the number of flits needed for a scatter/gather list that 979730ffcbSVarun Prakash * can hold the given number of entries. 989730ffcbSVarun Prakash */ 999730ffcbSVarun Prakash static inline unsigned int cxgbit_sgl_len(unsigned int n) 1009730ffcbSVarun Prakash { 1019730ffcbSVarun Prakash n--; 1029730ffcbSVarun Prakash return (3 * n) / 2 + (n & 1) + 2; 1039730ffcbSVarun Prakash } 1049730ffcbSVarun Prakash 1059730ffcbSVarun Prakash /* 1069730ffcbSVarun Prakash * cxgbit_calc_tx_flits_ofld - calculate # of flits for an offload packet 1079730ffcbSVarun Prakash * @skb: the packet 1089730ffcbSVarun Prakash * 1099730ffcbSVarun Prakash * Returns the number of flits needed for the given offload packet. 1109730ffcbSVarun Prakash * These packets are already fully constructed and no additional headers 1119730ffcbSVarun Prakash * will be added. 1129730ffcbSVarun Prakash */ 1139730ffcbSVarun Prakash static unsigned int cxgbit_calc_tx_flits_ofld(const struct sk_buff *skb) 1149730ffcbSVarun Prakash { 1159730ffcbSVarun Prakash unsigned int flits, cnt; 1169730ffcbSVarun Prakash 1179730ffcbSVarun Prakash if (cxgbit_is_ofld_imm(skb)) 1189730ffcbSVarun Prakash return DIV_ROUND_UP(skb->len, 8); 1199730ffcbSVarun Prakash flits = skb_transport_offset(skb) / 8; 1209730ffcbSVarun Prakash cnt = skb_shinfo(skb)->nr_frags; 1219730ffcbSVarun Prakash if (skb_tail_pointer(skb) != skb_transport_header(skb)) 1229730ffcbSVarun Prakash cnt++; 1239730ffcbSVarun Prakash return flits + cxgbit_sgl_len(cnt); 1249730ffcbSVarun Prakash } 1259730ffcbSVarun Prakash 1269730ffcbSVarun Prakash #define CXGBIT_ISO_FSLICE 0x1 1279730ffcbSVarun Prakash #define CXGBIT_ISO_LSLICE 0x2 1289730ffcbSVarun Prakash static void 1299730ffcbSVarun Prakash cxgbit_cpl_tx_data_iso(struct sk_buff *skb, struct cxgbit_iso_info *iso_info) 1309730ffcbSVarun Prakash { 1319730ffcbSVarun Prakash struct cpl_tx_data_iso *cpl; 1329730ffcbSVarun Prakash unsigned int submode = cxgbit_skcb_submode(skb); 1339730ffcbSVarun Prakash unsigned int fslice = !!(iso_info->flags & CXGBIT_ISO_FSLICE); 1349730ffcbSVarun Prakash unsigned int lslice = !!(iso_info->flags & CXGBIT_ISO_LSLICE); 1359730ffcbSVarun Prakash 136d58ff351SJohannes Berg cpl = __skb_push(skb, sizeof(*cpl)); 1379730ffcbSVarun Prakash 1389730ffcbSVarun Prakash cpl->op_to_scsi = htonl(CPL_TX_DATA_ISO_OP_V(CPL_TX_DATA_ISO) | 1399730ffcbSVarun Prakash CPL_TX_DATA_ISO_FIRST_V(fslice) | 1409730ffcbSVarun Prakash CPL_TX_DATA_ISO_LAST_V(lslice) | 1419730ffcbSVarun Prakash CPL_TX_DATA_ISO_CPLHDRLEN_V(0) | 1429730ffcbSVarun Prakash CPL_TX_DATA_ISO_HDRCRC_V(submode & 1) | 1439730ffcbSVarun Prakash CPL_TX_DATA_ISO_PLDCRC_V(((submode >> 1) & 1)) | 1449730ffcbSVarun Prakash CPL_TX_DATA_ISO_IMMEDIATE_V(0) | 1459730ffcbSVarun Prakash CPL_TX_DATA_ISO_SCSI_V(2)); 1469730ffcbSVarun Prakash 1479730ffcbSVarun Prakash cpl->ahs_len = 0; 1489730ffcbSVarun Prakash cpl->mpdu = htons(DIV_ROUND_UP(iso_info->mpdu, 4)); 1499730ffcbSVarun Prakash cpl->burst_size = htonl(DIV_ROUND_UP(iso_info->burst_len, 4)); 1509730ffcbSVarun Prakash cpl->len = htonl(iso_info->len); 1519730ffcbSVarun Prakash cpl->reserved2_seglen_offset = htonl(0); 1529730ffcbSVarun Prakash cpl->datasn_offset = htonl(0); 1539730ffcbSVarun Prakash cpl->buffer_offset = htonl(0); 1549730ffcbSVarun Prakash cpl->reserved3 = 0; 1559730ffcbSVarun Prakash 1569730ffcbSVarun Prakash __skb_pull(skb, sizeof(*cpl)); 1579730ffcbSVarun Prakash } 1589730ffcbSVarun Prakash 1599730ffcbSVarun Prakash static void 1609730ffcbSVarun Prakash cxgbit_tx_data_wr(struct cxgbit_sock *csk, struct sk_buff *skb, u32 dlen, 1619730ffcbSVarun Prakash u32 len, u32 credits, u32 compl) 1629730ffcbSVarun Prakash { 1639730ffcbSVarun Prakash struct fw_ofld_tx_data_wr *req; 164bdec5188SVarun Prakash const struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi; 1659730ffcbSVarun Prakash u32 submode = cxgbit_skcb_submode(skb); 1669730ffcbSVarun Prakash u32 wr_ulp_mode = 0; 1679730ffcbSVarun Prakash u32 hdr_size = sizeof(*req); 1689730ffcbSVarun Prakash u32 opcode = FW_OFLD_TX_DATA_WR; 1699730ffcbSVarun Prakash u32 immlen = 0; 170bdec5188SVarun Prakash u32 force = is_t5(lldi->adapter_type) ? TX_FORCE_V(!submode) : 171bdec5188SVarun Prakash T6_TX_FORCE_F; 1729730ffcbSVarun Prakash 1739730ffcbSVarun Prakash if (cxgbit_skcb_flags(skb) & SKCBF_TX_ISO) { 1749730ffcbSVarun Prakash opcode = FW_ISCSI_TX_DATA_WR; 1759730ffcbSVarun Prakash immlen += sizeof(struct cpl_tx_data_iso); 1769730ffcbSVarun Prakash hdr_size += sizeof(struct cpl_tx_data_iso); 1779730ffcbSVarun Prakash submode |= 8; 1789730ffcbSVarun Prakash } 1799730ffcbSVarun Prakash 1809730ffcbSVarun Prakash if (cxgbit_is_ofld_imm(skb)) 1819730ffcbSVarun Prakash immlen += dlen; 1829730ffcbSVarun Prakash 183d58ff351SJohannes Berg req = __skb_push(skb, hdr_size); 1849730ffcbSVarun Prakash req->op_to_immdlen = cpu_to_be32(FW_WR_OP_V(opcode) | 1859730ffcbSVarun Prakash FW_WR_COMPL_V(compl) | 1869730ffcbSVarun Prakash FW_WR_IMMDLEN_V(immlen)); 1879730ffcbSVarun Prakash req->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(csk->tid) | 1889730ffcbSVarun Prakash FW_WR_LEN16_V(credits)); 1899730ffcbSVarun Prakash req->plen = htonl(len); 1909730ffcbSVarun Prakash wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE_V(ULP_MODE_ISCSI) | 1919730ffcbSVarun Prakash FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(submode); 1929730ffcbSVarun Prakash 1939730ffcbSVarun Prakash req->tunnel_to_proxy = htonl((wr_ulp_mode) | force | 1949730ffcbSVarun Prakash FW_OFLD_TX_DATA_WR_SHOVE_V(skb_peek(&csk->txq) ? 0 : 1)); 1959730ffcbSVarun Prakash } 1969730ffcbSVarun Prakash 1979730ffcbSVarun Prakash static void cxgbit_arp_failure_skb_discard(void *handle, struct sk_buff *skb) 1989730ffcbSVarun Prakash { 1999730ffcbSVarun Prakash kfree_skb(skb); 2009730ffcbSVarun Prakash } 2019730ffcbSVarun Prakash 2029730ffcbSVarun Prakash void cxgbit_push_tx_frames(struct cxgbit_sock *csk) 2039730ffcbSVarun Prakash { 2049730ffcbSVarun Prakash struct sk_buff *skb; 2059730ffcbSVarun Prakash 2069730ffcbSVarun Prakash while (csk->wr_cred && ((skb = skb_peek(&csk->txq)) != NULL)) { 2079730ffcbSVarun Prakash u32 dlen = skb->len; 2089730ffcbSVarun Prakash u32 len = skb->len; 2099730ffcbSVarun Prakash u32 credits_needed; 2109730ffcbSVarun Prakash u32 compl = 0; 2119730ffcbSVarun Prakash u32 flowclen16 = 0; 2129730ffcbSVarun Prakash u32 iso_cpl_len = 0; 2139730ffcbSVarun Prakash 2149730ffcbSVarun Prakash if (cxgbit_skcb_flags(skb) & SKCBF_TX_ISO) 2159730ffcbSVarun Prakash iso_cpl_len = sizeof(struct cpl_tx_data_iso); 2169730ffcbSVarun Prakash 2179730ffcbSVarun Prakash if (cxgbit_is_ofld_imm(skb)) 2189730ffcbSVarun Prakash credits_needed = DIV_ROUND_UP(dlen + iso_cpl_len, 16); 2199730ffcbSVarun Prakash else 2209730ffcbSVarun Prakash credits_needed = DIV_ROUND_UP((8 * 2219730ffcbSVarun Prakash cxgbit_calc_tx_flits_ofld(skb)) + 2229730ffcbSVarun Prakash iso_cpl_len, 16); 2239730ffcbSVarun Prakash 2249730ffcbSVarun Prakash if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR)) 2259730ffcbSVarun Prakash credits_needed += DIV_ROUND_UP( 2269730ffcbSVarun Prakash sizeof(struct fw_ofld_tx_data_wr), 16); 2279730ffcbSVarun Prakash /* 2289730ffcbSVarun Prakash * Assumes the initial credits is large enough to support 2299730ffcbSVarun Prakash * fw_flowc_wr plus largest possible first payload 2309730ffcbSVarun Prakash */ 2319730ffcbSVarun Prakash 2329730ffcbSVarun Prakash if (!test_and_set_bit(CSK_TX_DATA_SENT, &csk->com.flags)) { 2339730ffcbSVarun Prakash flowclen16 = cxgbit_send_tx_flowc_wr(csk); 2349730ffcbSVarun Prakash csk->wr_cred -= flowclen16; 2359730ffcbSVarun Prakash csk->wr_una_cred += flowclen16; 2369730ffcbSVarun Prakash } 2379730ffcbSVarun Prakash 2389730ffcbSVarun Prakash if (csk->wr_cred < credits_needed) { 2399730ffcbSVarun Prakash pr_debug("csk 0x%p, skb %u/%u, wr %d < %u.\n", 2409730ffcbSVarun Prakash csk, skb->len, skb->data_len, 2419730ffcbSVarun Prakash credits_needed, csk->wr_cred); 2429730ffcbSVarun Prakash break; 2439730ffcbSVarun Prakash } 2449730ffcbSVarun Prakash __skb_unlink(skb, &csk->txq); 2459730ffcbSVarun Prakash set_wr_txq(skb, CPL_PRIORITY_DATA, csk->txq_idx); 2465cadafb2SBart Van Assche skb->csum = (__force __wsum)(credits_needed + flowclen16); 2479730ffcbSVarun Prakash csk->wr_cred -= credits_needed; 2489730ffcbSVarun Prakash csk->wr_una_cred += credits_needed; 2499730ffcbSVarun Prakash 2509730ffcbSVarun Prakash pr_debug("csk 0x%p, skb %u/%u, wr %d, left %u, unack %u.\n", 2519730ffcbSVarun Prakash csk, skb->len, skb->data_len, credits_needed, 2529730ffcbSVarun Prakash csk->wr_cred, csk->wr_una_cred); 2539730ffcbSVarun Prakash 2549730ffcbSVarun Prakash if (likely(cxgbit_skcb_flags(skb) & SKCBF_TX_NEED_HDR)) { 2559730ffcbSVarun Prakash len += cxgbit_skcb_tx_extralen(skb); 2569730ffcbSVarun Prakash 2579730ffcbSVarun Prakash if ((csk->wr_una_cred >= (csk->wr_max_cred / 2)) || 2589730ffcbSVarun Prakash (!before(csk->write_seq, 2599730ffcbSVarun Prakash csk->snd_una + csk->snd_win))) { 2609730ffcbSVarun Prakash compl = 1; 2619730ffcbSVarun Prakash csk->wr_una_cred = 0; 2629730ffcbSVarun Prakash } 2639730ffcbSVarun Prakash 2649730ffcbSVarun Prakash cxgbit_tx_data_wr(csk, skb, dlen, len, credits_needed, 2659730ffcbSVarun Prakash compl); 2669730ffcbSVarun Prakash csk->snd_nxt += len; 2679730ffcbSVarun Prakash 2689730ffcbSVarun Prakash } else if ((cxgbit_skcb_flags(skb) & SKCBF_TX_FLAG_COMPL) || 2699730ffcbSVarun Prakash (csk->wr_una_cred >= (csk->wr_max_cred / 2))) { 2709730ffcbSVarun Prakash struct cpl_close_con_req *req = 2719730ffcbSVarun Prakash (struct cpl_close_con_req *)skb->data; 2729730ffcbSVarun Prakash req->wr.wr_hi |= htonl(FW_WR_COMPL_F); 2739730ffcbSVarun Prakash csk->wr_una_cred = 0; 2749730ffcbSVarun Prakash } 2759730ffcbSVarun Prakash 2769730ffcbSVarun Prakash cxgbit_sock_enqueue_wr(csk, skb); 2779730ffcbSVarun Prakash t4_set_arp_err_handler(skb, csk, 2789730ffcbSVarun Prakash cxgbit_arp_failure_skb_discard); 2799730ffcbSVarun Prakash 2809730ffcbSVarun Prakash pr_debug("csk 0x%p,%u, skb 0x%p, %u.\n", 2819730ffcbSVarun Prakash csk, csk->tid, skb, len); 2829730ffcbSVarun Prakash 2839730ffcbSVarun Prakash cxgbit_l2t_send(csk->com.cdev, skb, csk->l2t); 2849730ffcbSVarun Prakash } 2859730ffcbSVarun Prakash } 2869730ffcbSVarun Prakash 2879730ffcbSVarun Prakash static bool cxgbit_lock_sock(struct cxgbit_sock *csk) 2889730ffcbSVarun Prakash { 2899730ffcbSVarun Prakash spin_lock_bh(&csk->lock); 2909730ffcbSVarun Prakash 2919730ffcbSVarun Prakash if (before(csk->write_seq, csk->snd_una + csk->snd_win)) 2929730ffcbSVarun Prakash csk->lock_owner = true; 2939730ffcbSVarun Prakash 2949730ffcbSVarun Prakash spin_unlock_bh(&csk->lock); 2959730ffcbSVarun Prakash 2969730ffcbSVarun Prakash return csk->lock_owner; 2979730ffcbSVarun Prakash } 2989730ffcbSVarun Prakash 2999730ffcbSVarun Prakash static void cxgbit_unlock_sock(struct cxgbit_sock *csk) 3009730ffcbSVarun Prakash { 3019730ffcbSVarun Prakash struct sk_buff_head backlogq; 3029730ffcbSVarun Prakash struct sk_buff *skb; 3039730ffcbSVarun Prakash void (*fn)(struct cxgbit_sock *, struct sk_buff *); 3049730ffcbSVarun Prakash 3059730ffcbSVarun Prakash skb_queue_head_init(&backlogq); 3069730ffcbSVarun Prakash 3079730ffcbSVarun Prakash spin_lock_bh(&csk->lock); 3089730ffcbSVarun Prakash while (skb_queue_len(&csk->backlogq)) { 3099730ffcbSVarun Prakash skb_queue_splice_init(&csk->backlogq, &backlogq); 3109730ffcbSVarun Prakash spin_unlock_bh(&csk->lock); 3119730ffcbSVarun Prakash 3129730ffcbSVarun Prakash while ((skb = __skb_dequeue(&backlogq))) { 3139730ffcbSVarun Prakash fn = cxgbit_skcb_rx_backlog_fn(skb); 3149730ffcbSVarun Prakash fn(csk, skb); 3159730ffcbSVarun Prakash } 3169730ffcbSVarun Prakash 3179730ffcbSVarun Prakash spin_lock_bh(&csk->lock); 3189730ffcbSVarun Prakash } 3199730ffcbSVarun Prakash 3209730ffcbSVarun Prakash csk->lock_owner = false; 3219730ffcbSVarun Prakash spin_unlock_bh(&csk->lock); 3229730ffcbSVarun Prakash } 3239730ffcbSVarun Prakash 3249730ffcbSVarun Prakash static int cxgbit_queue_skb(struct cxgbit_sock *csk, struct sk_buff *skb) 3259730ffcbSVarun Prakash { 3269730ffcbSVarun Prakash int ret = 0; 3279730ffcbSVarun Prakash 3289730ffcbSVarun Prakash wait_event_interruptible(csk->ack_waitq, cxgbit_lock_sock(csk)); 3299730ffcbSVarun Prakash 3309730ffcbSVarun Prakash if (unlikely((csk->com.state != CSK_STATE_ESTABLISHED) || 3319730ffcbSVarun Prakash signal_pending(current))) { 3329730ffcbSVarun Prakash __kfree_skb(skb); 3339730ffcbSVarun Prakash __skb_queue_purge(&csk->ppodq); 3349730ffcbSVarun Prakash ret = -1; 3359730ffcbSVarun Prakash spin_lock_bh(&csk->lock); 3369730ffcbSVarun Prakash if (csk->lock_owner) { 3379730ffcbSVarun Prakash spin_unlock_bh(&csk->lock); 3389730ffcbSVarun Prakash goto unlock; 3399730ffcbSVarun Prakash } 3409730ffcbSVarun Prakash spin_unlock_bh(&csk->lock); 3419730ffcbSVarun Prakash return ret; 3429730ffcbSVarun Prakash } 3439730ffcbSVarun Prakash 3449730ffcbSVarun Prakash csk->write_seq += skb->len + 3459730ffcbSVarun Prakash cxgbit_skcb_tx_extralen(skb); 3469730ffcbSVarun Prakash 3479730ffcbSVarun Prakash skb_queue_splice_tail_init(&csk->ppodq, &csk->txq); 3489730ffcbSVarun Prakash __skb_queue_tail(&csk->txq, skb); 3499730ffcbSVarun Prakash cxgbit_push_tx_frames(csk); 3509730ffcbSVarun Prakash 3519730ffcbSVarun Prakash unlock: 3529730ffcbSVarun Prakash cxgbit_unlock_sock(csk); 3539730ffcbSVarun Prakash return ret; 3549730ffcbSVarun Prakash } 3559730ffcbSVarun Prakash 3569730ffcbSVarun Prakash static int 3579730ffcbSVarun Prakash cxgbit_map_skb(struct iscsi_cmd *cmd, struct sk_buff *skb, u32 data_offset, 3589730ffcbSVarun Prakash u32 data_length) 3599730ffcbSVarun Prakash { 3609730ffcbSVarun Prakash u32 i = 0, nr_frags = MAX_SKB_FRAGS; 3619730ffcbSVarun Prakash u32 padding = ((-data_length) & 3); 3629730ffcbSVarun Prakash struct scatterlist *sg; 3639730ffcbSVarun Prakash struct page *page; 3649730ffcbSVarun Prakash unsigned int page_off; 3659730ffcbSVarun Prakash 3669730ffcbSVarun Prakash if (padding) 3679730ffcbSVarun Prakash nr_frags--; 3689730ffcbSVarun Prakash 3699730ffcbSVarun Prakash /* 3709730ffcbSVarun Prakash * We know each entry in t_data_sg contains a page. 3719730ffcbSVarun Prakash */ 3729730ffcbSVarun Prakash sg = &cmd->se_cmd.t_data_sg[data_offset / PAGE_SIZE]; 3739730ffcbSVarun Prakash page_off = (data_offset % PAGE_SIZE); 3749730ffcbSVarun Prakash 3759730ffcbSVarun Prakash while (data_length && (i < nr_frags)) { 3769730ffcbSVarun Prakash u32 cur_len = min_t(u32, data_length, sg->length - page_off); 3779730ffcbSVarun Prakash 3789730ffcbSVarun Prakash page = sg_page(sg); 3799730ffcbSVarun Prakash 3809730ffcbSVarun Prakash get_page(page); 3819730ffcbSVarun Prakash skb_fill_page_desc(skb, i, page, sg->offset + page_off, 3829730ffcbSVarun Prakash cur_len); 3839730ffcbSVarun Prakash skb->data_len += cur_len; 3849730ffcbSVarun Prakash skb->len += cur_len; 3859730ffcbSVarun Prakash skb->truesize += cur_len; 3869730ffcbSVarun Prakash 3879730ffcbSVarun Prakash data_length -= cur_len; 3889730ffcbSVarun Prakash page_off = 0; 3899730ffcbSVarun Prakash sg = sg_next(sg); 3909730ffcbSVarun Prakash i++; 3919730ffcbSVarun Prakash } 3929730ffcbSVarun Prakash 3939730ffcbSVarun Prakash if (data_length) 3949730ffcbSVarun Prakash return -1; 3959730ffcbSVarun Prakash 3969730ffcbSVarun Prakash if (padding) { 3979730ffcbSVarun Prakash page = alloc_page(GFP_KERNEL | __GFP_ZERO); 3989730ffcbSVarun Prakash if (!page) 3999730ffcbSVarun Prakash return -1; 4009730ffcbSVarun Prakash skb_fill_page_desc(skb, i, page, 0, padding); 4019730ffcbSVarun Prakash skb->data_len += padding; 4029730ffcbSVarun Prakash skb->len += padding; 4039730ffcbSVarun Prakash skb->truesize += padding; 4049730ffcbSVarun Prakash } 4059730ffcbSVarun Prakash 4069730ffcbSVarun Prakash return 0; 4079730ffcbSVarun Prakash } 4089730ffcbSVarun Prakash 4099730ffcbSVarun Prakash static int 4109730ffcbSVarun Prakash cxgbit_tx_datain_iso(struct cxgbit_sock *csk, struct iscsi_cmd *cmd, 4119730ffcbSVarun Prakash struct iscsi_datain_req *dr) 4129730ffcbSVarun Prakash { 4139730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 4149730ffcbSVarun Prakash struct sk_buff *skb; 4159730ffcbSVarun Prakash struct iscsi_datain datain; 4169730ffcbSVarun Prakash struct cxgbit_iso_info iso_info; 4179730ffcbSVarun Prakash u32 data_length = cmd->se_cmd.data_length; 4189730ffcbSVarun Prakash u32 mrdsl = conn->conn_ops->MaxRecvDataSegmentLength; 4199730ffcbSVarun Prakash u32 num_pdu, plen, tx_data = 0; 4209730ffcbSVarun Prakash bool task_sense = !!(cmd->se_cmd.se_cmd_flags & 4219730ffcbSVarun Prakash SCF_TRANSPORT_TASK_SENSE); 4229730ffcbSVarun Prakash bool set_statsn = false; 4239730ffcbSVarun Prakash int ret = -1; 4249730ffcbSVarun Prakash 4259730ffcbSVarun Prakash while (data_length) { 4269730ffcbSVarun Prakash num_pdu = (data_length + mrdsl - 1) / mrdsl; 4279730ffcbSVarun Prakash if (num_pdu > csk->max_iso_npdu) 4289730ffcbSVarun Prakash num_pdu = csk->max_iso_npdu; 4299730ffcbSVarun Prakash 4309730ffcbSVarun Prakash plen = num_pdu * mrdsl; 4319730ffcbSVarun Prakash if (plen > data_length) 4329730ffcbSVarun Prakash plen = data_length; 4339730ffcbSVarun Prakash 4349730ffcbSVarun Prakash skb = __cxgbit_alloc_skb(csk, 0, true); 4359730ffcbSVarun Prakash if (unlikely(!skb)) 4369730ffcbSVarun Prakash return -ENOMEM; 4379730ffcbSVarun Prakash 4389730ffcbSVarun Prakash memset(skb->data, 0, ISCSI_HDR_LEN); 4399730ffcbSVarun Prakash cxgbit_skcb_flags(skb) |= SKCBF_TX_ISO; 4409730ffcbSVarun Prakash cxgbit_skcb_submode(skb) |= (csk->submode & 4419730ffcbSVarun Prakash CXGBIT_SUBMODE_DCRC); 4429730ffcbSVarun Prakash cxgbit_skcb_tx_extralen(skb) = (num_pdu * 4439730ffcbSVarun Prakash cxgbit_digest_len[cxgbit_skcb_submode(skb)]) + 4449730ffcbSVarun Prakash ((num_pdu - 1) * ISCSI_HDR_LEN); 4459730ffcbSVarun Prakash 4469730ffcbSVarun Prakash memset(&datain, 0, sizeof(struct iscsi_datain)); 4479730ffcbSVarun Prakash memset(&iso_info, 0, sizeof(iso_info)); 4489730ffcbSVarun Prakash 4499730ffcbSVarun Prakash if (!tx_data) 4509730ffcbSVarun Prakash iso_info.flags |= CXGBIT_ISO_FSLICE; 4519730ffcbSVarun Prakash 4529730ffcbSVarun Prakash if (!(data_length - plen)) { 4539730ffcbSVarun Prakash iso_info.flags |= CXGBIT_ISO_LSLICE; 4549730ffcbSVarun Prakash if (!task_sense) { 4559730ffcbSVarun Prakash datain.flags = ISCSI_FLAG_DATA_STATUS; 4569730ffcbSVarun Prakash iscsit_increment_maxcmdsn(cmd, conn->sess); 4579730ffcbSVarun Prakash cmd->stat_sn = conn->stat_sn++; 4589730ffcbSVarun Prakash set_statsn = true; 4599730ffcbSVarun Prakash } 4609730ffcbSVarun Prakash } 4619730ffcbSVarun Prakash 4629730ffcbSVarun Prakash iso_info.burst_len = num_pdu * mrdsl; 4639730ffcbSVarun Prakash iso_info.mpdu = mrdsl; 4649730ffcbSVarun Prakash iso_info.len = ISCSI_HDR_LEN + plen; 4659730ffcbSVarun Prakash 4669730ffcbSVarun Prakash cxgbit_cpl_tx_data_iso(skb, &iso_info); 4679730ffcbSVarun Prakash 4689730ffcbSVarun Prakash datain.offset = tx_data; 4699730ffcbSVarun Prakash datain.data_sn = cmd->data_sn - 1; 4709730ffcbSVarun Prakash 4719730ffcbSVarun Prakash iscsit_build_datain_pdu(cmd, conn, &datain, 4729730ffcbSVarun Prakash (struct iscsi_data_rsp *)skb->data, 4739730ffcbSVarun Prakash set_statsn); 4749730ffcbSVarun Prakash 4759730ffcbSVarun Prakash ret = cxgbit_map_skb(cmd, skb, tx_data, plen); 4769730ffcbSVarun Prakash if (unlikely(ret)) { 4779730ffcbSVarun Prakash __kfree_skb(skb); 4789730ffcbSVarun Prakash goto out; 4799730ffcbSVarun Prakash } 4809730ffcbSVarun Prakash 4819730ffcbSVarun Prakash ret = cxgbit_queue_skb(csk, skb); 4829730ffcbSVarun Prakash if (unlikely(ret)) 4839730ffcbSVarun Prakash goto out; 4849730ffcbSVarun Prakash 4859730ffcbSVarun Prakash tx_data += plen; 4869730ffcbSVarun Prakash data_length -= plen; 4879730ffcbSVarun Prakash 4889730ffcbSVarun Prakash cmd->read_data_done += plen; 4899730ffcbSVarun Prakash cmd->data_sn += num_pdu; 4909730ffcbSVarun Prakash } 4919730ffcbSVarun Prakash 4929730ffcbSVarun Prakash dr->dr_complete = DATAIN_COMPLETE_NORMAL; 4939730ffcbSVarun Prakash 4949730ffcbSVarun Prakash return 0; 4959730ffcbSVarun Prakash 4969730ffcbSVarun Prakash out: 4979730ffcbSVarun Prakash return ret; 4989730ffcbSVarun Prakash } 4999730ffcbSVarun Prakash 5009730ffcbSVarun Prakash static int 5019730ffcbSVarun Prakash cxgbit_tx_datain(struct cxgbit_sock *csk, struct iscsi_cmd *cmd, 5029730ffcbSVarun Prakash const struct iscsi_datain *datain) 5039730ffcbSVarun Prakash { 5049730ffcbSVarun Prakash struct sk_buff *skb; 5059730ffcbSVarun Prakash int ret = 0; 5069730ffcbSVarun Prakash 5079730ffcbSVarun Prakash skb = cxgbit_alloc_skb(csk, 0); 5089730ffcbSVarun Prakash if (unlikely(!skb)) 5099730ffcbSVarun Prakash return -ENOMEM; 5109730ffcbSVarun Prakash 5119730ffcbSVarun Prakash memcpy(skb->data, cmd->pdu, ISCSI_HDR_LEN); 5129730ffcbSVarun Prakash 5139730ffcbSVarun Prakash if (datain->length) { 5149730ffcbSVarun Prakash cxgbit_skcb_submode(skb) |= (csk->submode & 5159730ffcbSVarun Prakash CXGBIT_SUBMODE_DCRC); 5169730ffcbSVarun Prakash cxgbit_skcb_tx_extralen(skb) = 5179730ffcbSVarun Prakash cxgbit_digest_len[cxgbit_skcb_submode(skb)]; 5189730ffcbSVarun Prakash } 5199730ffcbSVarun Prakash 5209730ffcbSVarun Prakash ret = cxgbit_map_skb(cmd, skb, datain->offset, datain->length); 5219730ffcbSVarun Prakash if (ret < 0) { 5229730ffcbSVarun Prakash __kfree_skb(skb); 5239730ffcbSVarun Prakash return ret; 5249730ffcbSVarun Prakash } 5259730ffcbSVarun Prakash 5269730ffcbSVarun Prakash return cxgbit_queue_skb(csk, skb); 5279730ffcbSVarun Prakash } 5289730ffcbSVarun Prakash 5299730ffcbSVarun Prakash static int 5309730ffcbSVarun Prakash cxgbit_xmit_datain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd, 5319730ffcbSVarun Prakash struct iscsi_datain_req *dr, 5329730ffcbSVarun Prakash const struct iscsi_datain *datain) 5339730ffcbSVarun Prakash { 5349730ffcbSVarun Prakash struct cxgbit_sock *csk = conn->context; 5359730ffcbSVarun Prakash u32 data_length = cmd->se_cmd.data_length; 5369730ffcbSVarun Prakash u32 padding = ((-data_length) & 3); 5379730ffcbSVarun Prakash u32 mrdsl = conn->conn_ops->MaxRecvDataSegmentLength; 5389730ffcbSVarun Prakash 5399730ffcbSVarun Prakash if ((data_length > mrdsl) && (!dr->recovery) && 5409730ffcbSVarun Prakash (!padding) && (!datain->offset) && csk->max_iso_npdu) { 5419730ffcbSVarun Prakash atomic_long_add(data_length - datain->length, 5429730ffcbSVarun Prakash &conn->sess->tx_data_octets); 5439730ffcbSVarun Prakash return cxgbit_tx_datain_iso(csk, cmd, dr); 5449730ffcbSVarun Prakash } 5459730ffcbSVarun Prakash 5469730ffcbSVarun Prakash return cxgbit_tx_datain(csk, cmd, datain); 5479730ffcbSVarun Prakash } 5489730ffcbSVarun Prakash 5499730ffcbSVarun Prakash static int 5509730ffcbSVarun Prakash cxgbit_xmit_nondatain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd, 5519730ffcbSVarun Prakash const void *data_buf, u32 data_buf_len) 5529730ffcbSVarun Prakash { 5539730ffcbSVarun Prakash struct cxgbit_sock *csk = conn->context; 5549730ffcbSVarun Prakash struct sk_buff *skb; 5559730ffcbSVarun Prakash u32 padding = ((-data_buf_len) & 3); 5569730ffcbSVarun Prakash 5579730ffcbSVarun Prakash skb = cxgbit_alloc_skb(csk, data_buf_len + padding); 5589730ffcbSVarun Prakash if (unlikely(!skb)) 5599730ffcbSVarun Prakash return -ENOMEM; 5609730ffcbSVarun Prakash 5619730ffcbSVarun Prakash memcpy(skb->data, cmd->pdu, ISCSI_HDR_LEN); 5629730ffcbSVarun Prakash 5639730ffcbSVarun Prakash if (data_buf_len) { 5649730ffcbSVarun Prakash u32 pad_bytes = 0; 5659730ffcbSVarun Prakash 5669730ffcbSVarun Prakash skb_store_bits(skb, ISCSI_HDR_LEN, data_buf, data_buf_len); 5679730ffcbSVarun Prakash 5689730ffcbSVarun Prakash if (padding) 5699730ffcbSVarun Prakash skb_store_bits(skb, ISCSI_HDR_LEN + data_buf_len, 5709730ffcbSVarun Prakash &pad_bytes, padding); 5719730ffcbSVarun Prakash } 5729730ffcbSVarun Prakash 5739730ffcbSVarun Prakash cxgbit_skcb_tx_extralen(skb) = cxgbit_digest_len[ 5749730ffcbSVarun Prakash cxgbit_skcb_submode(skb)]; 5759730ffcbSVarun Prakash 5769730ffcbSVarun Prakash return cxgbit_queue_skb(csk, skb); 5779730ffcbSVarun Prakash } 5789730ffcbSVarun Prakash 5799730ffcbSVarun Prakash int 5809730ffcbSVarun Prakash cxgbit_xmit_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd, 5819730ffcbSVarun Prakash struct iscsi_datain_req *dr, const void *buf, u32 buf_len) 5829730ffcbSVarun Prakash { 5839730ffcbSVarun Prakash if (dr) 5849730ffcbSVarun Prakash return cxgbit_xmit_datain_pdu(conn, cmd, dr, buf); 5859730ffcbSVarun Prakash else 5869730ffcbSVarun Prakash return cxgbit_xmit_nondatain_pdu(conn, cmd, buf, buf_len); 5879730ffcbSVarun Prakash } 5889730ffcbSVarun Prakash 5899730ffcbSVarun Prakash int cxgbit_validate_params(struct iscsi_conn *conn) 5909730ffcbSVarun Prakash { 5919730ffcbSVarun Prakash struct cxgbit_sock *csk = conn->context; 5929730ffcbSVarun Prakash struct cxgbit_device *cdev = csk->com.cdev; 5939730ffcbSVarun Prakash struct iscsi_param *param; 5949730ffcbSVarun Prakash u32 max_xmitdsl; 5959730ffcbSVarun Prakash 5969730ffcbSVarun Prakash param = iscsi_find_param_from_key(MAXXMITDATASEGMENTLENGTH, 5979730ffcbSVarun Prakash conn->param_list); 5989730ffcbSVarun Prakash if (!param) 5999730ffcbSVarun Prakash return -1; 6009730ffcbSVarun Prakash 6019730ffcbSVarun Prakash if (kstrtou32(param->value, 0, &max_xmitdsl) < 0) 6029730ffcbSVarun Prakash return -1; 6039730ffcbSVarun Prakash 6049730ffcbSVarun Prakash if (max_xmitdsl > cdev->mdsl) { 6059730ffcbSVarun Prakash if (iscsi_change_param_sprintf( 6069730ffcbSVarun Prakash conn, "MaxXmitDataSegmentLength=%u", cdev->mdsl)) 6079730ffcbSVarun Prakash return -1; 6089730ffcbSVarun Prakash } 6099730ffcbSVarun Prakash 6109730ffcbSVarun Prakash return 0; 6119730ffcbSVarun Prakash } 6129730ffcbSVarun Prakash 6139730ffcbSVarun Prakash static int cxgbit_set_digest(struct cxgbit_sock *csk) 6149730ffcbSVarun Prakash { 6159730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 6169730ffcbSVarun Prakash struct iscsi_param *param; 6179730ffcbSVarun Prakash 6189730ffcbSVarun Prakash param = iscsi_find_param_from_key(HEADERDIGEST, conn->param_list); 6199730ffcbSVarun Prakash if (!param) { 6209730ffcbSVarun Prakash pr_err("param not found key %s\n", HEADERDIGEST); 6219730ffcbSVarun Prakash return -1; 6229730ffcbSVarun Prakash } 6239730ffcbSVarun Prakash 6249730ffcbSVarun Prakash if (!strcmp(param->value, CRC32C)) 6259730ffcbSVarun Prakash csk->submode |= CXGBIT_SUBMODE_HCRC; 6269730ffcbSVarun Prakash 6279730ffcbSVarun Prakash param = iscsi_find_param_from_key(DATADIGEST, conn->param_list); 6289730ffcbSVarun Prakash if (!param) { 6299730ffcbSVarun Prakash csk->submode = 0; 6309730ffcbSVarun Prakash pr_err("param not found key %s\n", DATADIGEST); 6319730ffcbSVarun Prakash return -1; 6329730ffcbSVarun Prakash } 6339730ffcbSVarun Prakash 6349730ffcbSVarun Prakash if (!strcmp(param->value, CRC32C)) 6359730ffcbSVarun Prakash csk->submode |= CXGBIT_SUBMODE_DCRC; 6369730ffcbSVarun Prakash 6379730ffcbSVarun Prakash if (cxgbit_setup_conn_digest(csk)) { 6389730ffcbSVarun Prakash csk->submode = 0; 6399730ffcbSVarun Prakash return -1; 6409730ffcbSVarun Prakash } 6419730ffcbSVarun Prakash 6429730ffcbSVarun Prakash return 0; 6439730ffcbSVarun Prakash } 6449730ffcbSVarun Prakash 6459730ffcbSVarun Prakash static int cxgbit_set_iso_npdu(struct cxgbit_sock *csk) 6469730ffcbSVarun Prakash { 6479730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 6489730ffcbSVarun Prakash struct iscsi_conn_ops *conn_ops = conn->conn_ops; 6499730ffcbSVarun Prakash struct iscsi_param *param; 6509730ffcbSVarun Prakash u32 mrdsl, mbl; 6519730ffcbSVarun Prakash u32 max_npdu, max_iso_npdu; 6521b350ea0SVarun Prakash u32 max_iso_payload; 6539730ffcbSVarun Prakash 6549730ffcbSVarun Prakash if (conn->login->leading_connection) { 6559730ffcbSVarun Prakash param = iscsi_find_param_from_key(MAXBURSTLENGTH, 6569730ffcbSVarun Prakash conn->param_list); 6579730ffcbSVarun Prakash if (!param) { 6589730ffcbSVarun Prakash pr_err("param not found key %s\n", MAXBURSTLENGTH); 6599730ffcbSVarun Prakash return -1; 6609730ffcbSVarun Prakash } 6619730ffcbSVarun Prakash 6629730ffcbSVarun Prakash if (kstrtou32(param->value, 0, &mbl) < 0) 6639730ffcbSVarun Prakash return -1; 6649730ffcbSVarun Prakash } else { 6659730ffcbSVarun Prakash mbl = conn->sess->sess_ops->MaxBurstLength; 6669730ffcbSVarun Prakash } 6679730ffcbSVarun Prakash 6689730ffcbSVarun Prakash mrdsl = conn_ops->MaxRecvDataSegmentLength; 6699730ffcbSVarun Prakash max_npdu = mbl / mrdsl; 6709730ffcbSVarun Prakash 6711b350ea0SVarun Prakash max_iso_payload = rounddown(CXGBIT_MAX_ISO_PAYLOAD, csk->emss); 6721b350ea0SVarun Prakash 6731b350ea0SVarun Prakash max_iso_npdu = max_iso_payload / 6749730ffcbSVarun Prakash (ISCSI_HDR_LEN + mrdsl + 6759730ffcbSVarun Prakash cxgbit_digest_len[csk->submode]); 6769730ffcbSVarun Prakash 6779730ffcbSVarun Prakash csk->max_iso_npdu = min(max_npdu, max_iso_npdu); 6789730ffcbSVarun Prakash 6799730ffcbSVarun Prakash if (csk->max_iso_npdu <= 1) 6809730ffcbSVarun Prakash csk->max_iso_npdu = 0; 6819730ffcbSVarun Prakash 6829730ffcbSVarun Prakash return 0; 6839730ffcbSVarun Prakash } 6849730ffcbSVarun Prakash 6855248788eSVarun Prakash /* 6865248788eSVarun Prakash * cxgbit_seq_pdu_inorder() 6875248788eSVarun Prakash * @csk: pointer to cxgbit socket structure 6885248788eSVarun Prakash * 6895248788eSVarun Prakash * This function checks whether data sequence and data 6905248788eSVarun Prakash * pdu are in order. 6915248788eSVarun Prakash * 6925248788eSVarun Prakash * Return: returns -1 on error, 0 if data sequence and 6935248788eSVarun Prakash * data pdu are in order, 1 if data sequence or data pdu 6945248788eSVarun Prakash * is not in order. 6955248788eSVarun Prakash */ 6965248788eSVarun Prakash static int cxgbit_seq_pdu_inorder(struct cxgbit_sock *csk) 6975248788eSVarun Prakash { 6985248788eSVarun Prakash struct iscsi_conn *conn = csk->conn; 6995248788eSVarun Prakash struct iscsi_param *param; 7005248788eSVarun Prakash 7015248788eSVarun Prakash if (conn->login->leading_connection) { 7025248788eSVarun Prakash param = iscsi_find_param_from_key(DATASEQUENCEINORDER, 7035248788eSVarun Prakash conn->param_list); 7045248788eSVarun Prakash if (!param) { 7055248788eSVarun Prakash pr_err("param not found key %s\n", DATASEQUENCEINORDER); 7065248788eSVarun Prakash return -1; 7075248788eSVarun Prakash } 7085248788eSVarun Prakash 7095248788eSVarun Prakash if (strcmp(param->value, YES)) 7105248788eSVarun Prakash return 1; 7115248788eSVarun Prakash 7125248788eSVarun Prakash param = iscsi_find_param_from_key(DATAPDUINORDER, 7135248788eSVarun Prakash conn->param_list); 7145248788eSVarun Prakash if (!param) { 7155248788eSVarun Prakash pr_err("param not found key %s\n", DATAPDUINORDER); 7165248788eSVarun Prakash return -1; 7175248788eSVarun Prakash } 7185248788eSVarun Prakash 7195248788eSVarun Prakash if (strcmp(param->value, YES)) 7205248788eSVarun Prakash return 1; 7215248788eSVarun Prakash 7225248788eSVarun Prakash } else { 7235248788eSVarun Prakash if (!conn->sess->sess_ops->DataSequenceInOrder) 7245248788eSVarun Prakash return 1; 7255248788eSVarun Prakash if (!conn->sess->sess_ops->DataPDUInOrder) 7265248788eSVarun Prakash return 1; 7275248788eSVarun Prakash } 7285248788eSVarun Prakash 7295248788eSVarun Prakash return 0; 7305248788eSVarun Prakash } 7315248788eSVarun Prakash 7329730ffcbSVarun Prakash static int cxgbit_set_params(struct iscsi_conn *conn) 7339730ffcbSVarun Prakash { 7349730ffcbSVarun Prakash struct cxgbit_sock *csk = conn->context; 7359730ffcbSVarun Prakash struct cxgbit_device *cdev = csk->com.cdev; 7369730ffcbSVarun Prakash struct cxgbi_ppm *ppm = *csk->com.cdev->lldi.iscsi_ppm; 7379730ffcbSVarun Prakash struct iscsi_conn_ops *conn_ops = conn->conn_ops; 7389730ffcbSVarun Prakash struct iscsi_param *param; 7399730ffcbSVarun Prakash u8 erl; 7409730ffcbSVarun Prakash 7419730ffcbSVarun Prakash if (conn_ops->MaxRecvDataSegmentLength > cdev->mdsl) 7429730ffcbSVarun Prakash conn_ops->MaxRecvDataSegmentLength = cdev->mdsl; 7439730ffcbSVarun Prakash 7441b350ea0SVarun Prakash if (cxgbit_set_digest(csk)) 7451b350ea0SVarun Prakash return -1; 7461b350ea0SVarun Prakash 7479730ffcbSVarun Prakash if (conn->login->leading_connection) { 7489730ffcbSVarun Prakash param = iscsi_find_param_from_key(ERRORRECOVERYLEVEL, 7499730ffcbSVarun Prakash conn->param_list); 7509730ffcbSVarun Prakash if (!param) { 7519730ffcbSVarun Prakash pr_err("param not found key %s\n", ERRORRECOVERYLEVEL); 7529730ffcbSVarun Prakash return -1; 7539730ffcbSVarun Prakash } 7549730ffcbSVarun Prakash if (kstrtou8(param->value, 0, &erl) < 0) 7559730ffcbSVarun Prakash return -1; 7569730ffcbSVarun Prakash } else { 7579730ffcbSVarun Prakash erl = conn->sess->sess_ops->ErrorRecoveryLevel; 7589730ffcbSVarun Prakash } 7599730ffcbSVarun Prakash 7609730ffcbSVarun Prakash if (!erl) { 7615248788eSVarun Prakash int ret; 7625248788eSVarun Prakash 7635248788eSVarun Prakash ret = cxgbit_seq_pdu_inorder(csk); 7645248788eSVarun Prakash if (ret < 0) { 7655248788eSVarun Prakash return -1; 7665248788eSVarun Prakash } else if (ret > 0) { 7675248788eSVarun Prakash if (is_t5(cdev->lldi.adapter_type)) 7685248788eSVarun Prakash goto enable_ddp; 7695248788eSVarun Prakash else 7701b350ea0SVarun Prakash return 0; 7715248788eSVarun Prakash } 7725248788eSVarun Prakash 7739730ffcbSVarun Prakash if (test_bit(CDEV_ISO_ENABLE, &cdev->flags)) { 7749730ffcbSVarun Prakash if (cxgbit_set_iso_npdu(csk)) 7759730ffcbSVarun Prakash return -1; 7769730ffcbSVarun Prakash } 7779730ffcbSVarun Prakash 7785248788eSVarun Prakash enable_ddp: 7799730ffcbSVarun Prakash if (test_bit(CDEV_DDP_ENABLE, &cdev->flags)) { 7809730ffcbSVarun Prakash if (cxgbit_setup_conn_pgidx(csk, 7819730ffcbSVarun Prakash ppm->tformat.pgsz_idx_dflt)) 7829730ffcbSVarun Prakash return -1; 7839730ffcbSVarun Prakash set_bit(CSK_DDP_ENABLE, &csk->com.flags); 7849730ffcbSVarun Prakash } 7859730ffcbSVarun Prakash } 7869730ffcbSVarun Prakash 7879730ffcbSVarun Prakash return 0; 7889730ffcbSVarun Prakash } 7899730ffcbSVarun Prakash 7909730ffcbSVarun Prakash int 7919730ffcbSVarun Prakash cxgbit_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login, 7929730ffcbSVarun Prakash u32 length) 7939730ffcbSVarun Prakash { 7949730ffcbSVarun Prakash struct cxgbit_sock *csk = conn->context; 7959730ffcbSVarun Prakash struct sk_buff *skb; 7969730ffcbSVarun Prakash u32 padding_buf = 0; 7979730ffcbSVarun Prakash u8 padding = ((-length) & 3); 7989730ffcbSVarun Prakash 7999730ffcbSVarun Prakash skb = cxgbit_alloc_skb(csk, length + padding); 8009730ffcbSVarun Prakash if (!skb) 8019730ffcbSVarun Prakash return -ENOMEM; 8029730ffcbSVarun Prakash skb_store_bits(skb, 0, login->rsp, ISCSI_HDR_LEN); 8039730ffcbSVarun Prakash skb_store_bits(skb, ISCSI_HDR_LEN, login->rsp_buf, length); 8049730ffcbSVarun Prakash 8059730ffcbSVarun Prakash if (padding) 8069730ffcbSVarun Prakash skb_store_bits(skb, ISCSI_HDR_LEN + length, 8079730ffcbSVarun Prakash &padding_buf, padding); 8089730ffcbSVarun Prakash 8099730ffcbSVarun Prakash if (login->login_complete) { 8109730ffcbSVarun Prakash if (cxgbit_set_params(conn)) { 8119730ffcbSVarun Prakash kfree_skb(skb); 8129730ffcbSVarun Prakash return -1; 8139730ffcbSVarun Prakash } 8149730ffcbSVarun Prakash 8159730ffcbSVarun Prakash set_bit(CSK_LOGIN_DONE, &csk->com.flags); 8169730ffcbSVarun Prakash } 8179730ffcbSVarun Prakash 8189730ffcbSVarun Prakash if (cxgbit_queue_skb(csk, skb)) 8199730ffcbSVarun Prakash return -1; 8209730ffcbSVarun Prakash 8219730ffcbSVarun Prakash if ((!login->login_complete) && (!login->login_failed)) 8229730ffcbSVarun Prakash schedule_delayed_work(&conn->login_work, 0); 8239730ffcbSVarun Prakash 8249730ffcbSVarun Prakash return 0; 8259730ffcbSVarun Prakash } 8269730ffcbSVarun Prakash 8279730ffcbSVarun Prakash static void 8289730ffcbSVarun Prakash cxgbit_skb_copy_to_sg(struct sk_buff *skb, struct scatterlist *sg, 829d96adb9bSVarun Prakash unsigned int nents, u32 skip) 8309730ffcbSVarun Prakash { 8319730ffcbSVarun Prakash struct skb_seq_state st; 8329730ffcbSVarun Prakash const u8 *buf; 8339730ffcbSVarun Prakash unsigned int consumed = 0, buf_len; 8349730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(skb); 8359730ffcbSVarun Prakash 8369730ffcbSVarun Prakash skb_prepare_seq_read(skb, pdu_cb->doffset, 8379730ffcbSVarun Prakash pdu_cb->doffset + pdu_cb->dlen, 8389730ffcbSVarun Prakash &st); 8399730ffcbSVarun Prakash 8409730ffcbSVarun Prakash while (true) { 8419730ffcbSVarun Prakash buf_len = skb_seq_read(consumed, &buf, &st); 8429730ffcbSVarun Prakash if (!buf_len) { 8439730ffcbSVarun Prakash skb_abort_seq_read(&st); 8449730ffcbSVarun Prakash break; 8459730ffcbSVarun Prakash } 8469730ffcbSVarun Prakash 8479730ffcbSVarun Prakash consumed += sg_pcopy_from_buffer(sg, nents, (void *)buf, 848d96adb9bSVarun Prakash buf_len, skip + consumed); 8499730ffcbSVarun Prakash } 8509730ffcbSVarun Prakash } 8519730ffcbSVarun Prakash 8529730ffcbSVarun Prakash static struct iscsi_cmd *cxgbit_allocate_cmd(struct cxgbit_sock *csk) 8539730ffcbSVarun Prakash { 8549730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 8559730ffcbSVarun Prakash struct cxgbi_ppm *ppm = cdev2ppm(csk->com.cdev); 8569730ffcbSVarun Prakash struct cxgbit_cmd *ccmd; 8579730ffcbSVarun Prakash struct iscsi_cmd *cmd; 8589730ffcbSVarun Prakash 8599730ffcbSVarun Prakash cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE); 8609730ffcbSVarun Prakash if (!cmd) { 8619730ffcbSVarun Prakash pr_err("Unable to allocate iscsi_cmd + cxgbit_cmd\n"); 8629730ffcbSVarun Prakash return NULL; 8639730ffcbSVarun Prakash } 8649730ffcbSVarun Prakash 8659730ffcbSVarun Prakash ccmd = iscsit_priv_cmd(cmd); 8669730ffcbSVarun Prakash ccmd->ttinfo.tag = ppm->tformat.no_ddp_mask; 8679730ffcbSVarun Prakash ccmd->setup_ddp = true; 8689730ffcbSVarun Prakash 8699730ffcbSVarun Prakash return cmd; 8709730ffcbSVarun Prakash } 8719730ffcbSVarun Prakash 8729730ffcbSVarun Prakash static int 8739730ffcbSVarun Prakash cxgbit_handle_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, 8749730ffcbSVarun Prakash u32 length) 8759730ffcbSVarun Prakash { 8769730ffcbSVarun Prakash struct iscsi_conn *conn = cmd->conn; 8779730ffcbSVarun Prakash struct cxgbit_sock *csk = conn->context; 8789730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb); 8799730ffcbSVarun Prakash 8809730ffcbSVarun Prakash if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) { 8819730ffcbSVarun Prakash pr_err("ImmediateData CRC32C DataDigest error\n"); 8829730ffcbSVarun Prakash if (!conn->sess->sess_ops->ErrorRecoveryLevel) { 8839730ffcbSVarun Prakash pr_err("Unable to recover from" 8849730ffcbSVarun Prakash " Immediate Data digest failure while" 8859730ffcbSVarun Prakash " in ERL=0.\n"); 8869730ffcbSVarun Prakash iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR, 8879730ffcbSVarun Prakash (unsigned char *)hdr); 8889730ffcbSVarun Prakash return IMMEDIATE_DATA_CANNOT_RECOVER; 8899730ffcbSVarun Prakash } 8909730ffcbSVarun Prakash 8919730ffcbSVarun Prakash iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR, 8929730ffcbSVarun Prakash (unsigned char *)hdr); 8939730ffcbSVarun Prakash return IMMEDIATE_DATA_ERL1_CRC_FAILURE; 8949730ffcbSVarun Prakash } 8959730ffcbSVarun Prakash 8969730ffcbSVarun Prakash if (cmd->se_cmd.se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) { 8979730ffcbSVarun Prakash struct cxgbit_cmd *ccmd = iscsit_priv_cmd(cmd); 8989730ffcbSVarun Prakash struct skb_shared_info *ssi = skb_shinfo(csk->skb); 8999730ffcbSVarun Prakash skb_frag_t *dfrag = &ssi->frags[pdu_cb->dfrag_idx]; 9009730ffcbSVarun Prakash 9019730ffcbSVarun Prakash sg_init_table(&ccmd->sg, 1); 9029730ffcbSVarun Prakash sg_set_page(&ccmd->sg, dfrag->page.p, skb_frag_size(dfrag), 9039730ffcbSVarun Prakash dfrag->page_offset); 9049730ffcbSVarun Prakash get_page(dfrag->page.p); 9059730ffcbSVarun Prakash 9069730ffcbSVarun Prakash cmd->se_cmd.t_data_sg = &ccmd->sg; 9079730ffcbSVarun Prakash cmd->se_cmd.t_data_nents = 1; 9089730ffcbSVarun Prakash 9099730ffcbSVarun Prakash ccmd->release = true; 9109730ffcbSVarun Prakash } else { 9119730ffcbSVarun Prakash struct scatterlist *sg = &cmd->se_cmd.t_data_sg[0]; 9129730ffcbSVarun Prakash u32 sg_nents = max(1UL, DIV_ROUND_UP(pdu_cb->dlen, PAGE_SIZE)); 9139730ffcbSVarun Prakash 914d96adb9bSVarun Prakash cxgbit_skb_copy_to_sg(csk->skb, sg, sg_nents, 0); 9159730ffcbSVarun Prakash } 9169730ffcbSVarun Prakash 9179730ffcbSVarun Prakash cmd->write_data_done += pdu_cb->dlen; 9189730ffcbSVarun Prakash 9199730ffcbSVarun Prakash if (cmd->write_data_done == cmd->se_cmd.data_length) { 9209730ffcbSVarun Prakash spin_lock_bh(&cmd->istate_lock); 9219730ffcbSVarun Prakash cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT; 9229730ffcbSVarun Prakash cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT; 9239730ffcbSVarun Prakash spin_unlock_bh(&cmd->istate_lock); 9249730ffcbSVarun Prakash } 9259730ffcbSVarun Prakash 9269730ffcbSVarun Prakash return IMMEDIATE_DATA_NORMAL_OPERATION; 9279730ffcbSVarun Prakash } 9289730ffcbSVarun Prakash 9299730ffcbSVarun Prakash static int 9309730ffcbSVarun Prakash cxgbit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, 9319730ffcbSVarun Prakash bool dump_payload) 9329730ffcbSVarun Prakash { 9339730ffcbSVarun Prakash struct iscsi_conn *conn = cmd->conn; 9349730ffcbSVarun Prakash int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; 9359730ffcbSVarun Prakash /* 9369730ffcbSVarun Prakash * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. 9379730ffcbSVarun Prakash */ 9389730ffcbSVarun Prakash if (dump_payload) 9399730ffcbSVarun Prakash goto after_immediate_data; 9409730ffcbSVarun Prakash 9419730ffcbSVarun Prakash immed_ret = cxgbit_handle_immediate_data(cmd, hdr, 9429730ffcbSVarun Prakash cmd->first_burst_len); 9439730ffcbSVarun Prakash after_immediate_data: 9449730ffcbSVarun Prakash if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) { 9459730ffcbSVarun Prakash /* 9469730ffcbSVarun Prakash * A PDU/CmdSN carrying Immediate Data passed 9479730ffcbSVarun Prakash * DataCRC, check against ExpCmdSN/MaxCmdSN if 9489730ffcbSVarun Prakash * Immediate Bit is not set. 9499730ffcbSVarun Prakash */ 9509730ffcbSVarun Prakash cmdsn_ret = iscsit_sequence_cmd(conn, cmd, 9519730ffcbSVarun Prakash (unsigned char *)hdr, 9529730ffcbSVarun Prakash hdr->cmdsn); 9539730ffcbSVarun Prakash if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) 9549730ffcbSVarun Prakash return -1; 9559730ffcbSVarun Prakash 9569730ffcbSVarun Prakash if (cmd->sense_reason || cmdsn_ret == CMDSN_LOWER_THAN_EXP) { 9579730ffcbSVarun Prakash target_put_sess_cmd(&cmd->se_cmd); 9589730ffcbSVarun Prakash return 0; 9599730ffcbSVarun Prakash } else if (cmd->unsolicited_data) { 9600300b114SBart Van Assche iscsit_set_unsolicited_dataout(cmd); 9619730ffcbSVarun Prakash } 9629730ffcbSVarun Prakash 9639730ffcbSVarun Prakash } else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) { 9649730ffcbSVarun Prakash /* 9659730ffcbSVarun Prakash * Immediate Data failed DataCRC and ERL>=1, 9669730ffcbSVarun Prakash * silently drop this PDU and let the initiator 9679730ffcbSVarun Prakash * plug the CmdSN gap. 9689730ffcbSVarun Prakash * 9699730ffcbSVarun Prakash * FIXME: Send Unsolicited NOPIN with reserved 9709730ffcbSVarun Prakash * TTT here to help the initiator figure out 9719730ffcbSVarun Prakash * the missing CmdSN, although they should be 9729730ffcbSVarun Prakash * intelligent enough to determine the missing 9739730ffcbSVarun Prakash * CmdSN and issue a retry to plug the sequence. 9749730ffcbSVarun Prakash */ 9759730ffcbSVarun Prakash cmd->i_state = ISTATE_REMOVE; 9769730ffcbSVarun Prakash iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state); 9779730ffcbSVarun Prakash } else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */ 9789730ffcbSVarun Prakash return -1; 9799730ffcbSVarun Prakash 9809730ffcbSVarun Prakash return 0; 9819730ffcbSVarun Prakash } 9829730ffcbSVarun Prakash 9839730ffcbSVarun Prakash static int 9849730ffcbSVarun Prakash cxgbit_handle_scsi_cmd(struct cxgbit_sock *csk, struct iscsi_cmd *cmd) 9859730ffcbSVarun Prakash { 9869730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 9879730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb); 9889730ffcbSVarun Prakash struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)pdu_cb->hdr; 9899730ffcbSVarun Prakash int rc; 9909730ffcbSVarun Prakash bool dump_payload = false; 9919730ffcbSVarun Prakash 9929730ffcbSVarun Prakash rc = iscsit_setup_scsi_cmd(conn, cmd, (unsigned char *)hdr); 9939730ffcbSVarun Prakash if (rc < 0) 9949730ffcbSVarun Prakash return rc; 9959730ffcbSVarun Prakash 9969730ffcbSVarun Prakash if (pdu_cb->dlen && (pdu_cb->dlen == cmd->se_cmd.data_length) && 9979730ffcbSVarun Prakash (pdu_cb->nr_dfrags == 1)) 9989730ffcbSVarun Prakash cmd->se_cmd.se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; 9999730ffcbSVarun Prakash 10009730ffcbSVarun Prakash rc = iscsit_process_scsi_cmd(conn, cmd, hdr); 10019730ffcbSVarun Prakash if (rc < 0) 10029730ffcbSVarun Prakash return 0; 10039730ffcbSVarun Prakash else if (rc > 0) 10049730ffcbSVarun Prakash dump_payload = true; 10059730ffcbSVarun Prakash 10069730ffcbSVarun Prakash if (!pdu_cb->dlen) 10079730ffcbSVarun Prakash return 0; 10089730ffcbSVarun Prakash 10099730ffcbSVarun Prakash return cxgbit_get_immediate_data(cmd, hdr, dump_payload); 10109730ffcbSVarun Prakash } 10119730ffcbSVarun Prakash 10129730ffcbSVarun Prakash static int cxgbit_handle_iscsi_dataout(struct cxgbit_sock *csk) 10139730ffcbSVarun Prakash { 10149730ffcbSVarun Prakash struct scatterlist *sg_start; 10159730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 10169730ffcbSVarun Prakash struct iscsi_cmd *cmd = NULL; 10179730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb); 10189730ffcbSVarun Prakash struct iscsi_data *hdr = (struct iscsi_data *)pdu_cb->hdr; 10199730ffcbSVarun Prakash u32 data_offset = be32_to_cpu(hdr->offset); 10209730ffcbSVarun Prakash u32 data_len = pdu_cb->dlen; 10219730ffcbSVarun Prakash int rc, sg_nents, sg_off; 10229730ffcbSVarun Prakash bool dcrc_err = false; 10239730ffcbSVarun Prakash 102479e57cfeSVarun Prakash if (pdu_cb->flags & PDUCBF_RX_DDP_CMP) { 102579e57cfeSVarun Prakash u32 offset = be32_to_cpu(hdr->offset); 102679e57cfeSVarun Prakash u32 ddp_data_len; 102779e57cfeSVarun Prakash u32 payload_length = ntoh24(hdr->dlength); 102879e57cfeSVarun Prakash bool success = false; 102979e57cfeSVarun Prakash 103079e57cfeSVarun Prakash cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, 0); 103179e57cfeSVarun Prakash if (!cmd) 103279e57cfeSVarun Prakash return 0; 103379e57cfeSVarun Prakash 103479e57cfeSVarun Prakash ddp_data_len = offset - cmd->write_data_done; 103579e57cfeSVarun Prakash atomic_long_add(ddp_data_len, &conn->sess->rx_data_octets); 103679e57cfeSVarun Prakash 103779e57cfeSVarun Prakash cmd->write_data_done = offset; 103879e57cfeSVarun Prakash cmd->next_burst_len = ddp_data_len; 103979e57cfeSVarun Prakash cmd->data_sn = be32_to_cpu(hdr->datasn); 104079e57cfeSVarun Prakash 104179e57cfeSVarun Prakash rc = __iscsit_check_dataout_hdr(conn, (unsigned char *)hdr, 104279e57cfeSVarun Prakash cmd, payload_length, &success); 104379e57cfeSVarun Prakash if (rc < 0) 104479e57cfeSVarun Prakash return rc; 104579e57cfeSVarun Prakash else if (!success) 104679e57cfeSVarun Prakash return 0; 104779e57cfeSVarun Prakash } else { 10489730ffcbSVarun Prakash rc = iscsit_check_dataout_hdr(conn, (unsigned char *)hdr, &cmd); 10499730ffcbSVarun Prakash if (rc < 0) 10509730ffcbSVarun Prakash return rc; 10519730ffcbSVarun Prakash else if (!cmd) 10529730ffcbSVarun Prakash return 0; 105379e57cfeSVarun Prakash } 10549730ffcbSVarun Prakash 10559730ffcbSVarun Prakash if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) { 10569730ffcbSVarun Prakash pr_err("ITT: 0x%08x, Offset: %u, Length: %u," 10579730ffcbSVarun Prakash " DataSN: 0x%08x\n", 10589730ffcbSVarun Prakash hdr->itt, hdr->offset, data_len, 10599730ffcbSVarun Prakash hdr->datasn); 10609730ffcbSVarun Prakash 10619730ffcbSVarun Prakash dcrc_err = true; 10629730ffcbSVarun Prakash goto check_payload; 10639730ffcbSVarun Prakash } 10649730ffcbSVarun Prakash 10659730ffcbSVarun Prakash pr_debug("DataOut data_len: %u, " 10669730ffcbSVarun Prakash "write_data_done: %u, data_length: %u\n", 10679730ffcbSVarun Prakash data_len, cmd->write_data_done, 10689730ffcbSVarun Prakash cmd->se_cmd.data_length); 10699730ffcbSVarun Prakash 10709730ffcbSVarun Prakash if (!(pdu_cb->flags & PDUCBF_RX_DATA_DDPD)) { 1071d96adb9bSVarun Prakash u32 skip = data_offset % PAGE_SIZE; 1072d96adb9bSVarun Prakash 10739730ffcbSVarun Prakash sg_off = data_offset / PAGE_SIZE; 10749730ffcbSVarun Prakash sg_start = &cmd->se_cmd.t_data_sg[sg_off]; 1075d96adb9bSVarun Prakash sg_nents = max(1UL, DIV_ROUND_UP(skip + data_len, PAGE_SIZE)); 10769730ffcbSVarun Prakash 1077d96adb9bSVarun Prakash cxgbit_skb_copy_to_sg(csk->skb, sg_start, sg_nents, skip); 10789730ffcbSVarun Prakash } 10799730ffcbSVarun Prakash 10809730ffcbSVarun Prakash check_payload: 10819730ffcbSVarun Prakash 10829730ffcbSVarun Prakash rc = iscsit_check_dataout_payload(cmd, hdr, dcrc_err); 10839730ffcbSVarun Prakash if (rc < 0) 10849730ffcbSVarun Prakash return rc; 10859730ffcbSVarun Prakash 10869730ffcbSVarun Prakash return 0; 10879730ffcbSVarun Prakash } 10889730ffcbSVarun Prakash 10899730ffcbSVarun Prakash static int cxgbit_handle_nop_out(struct cxgbit_sock *csk, struct iscsi_cmd *cmd) 10909730ffcbSVarun Prakash { 10919730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 10929730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb); 10939730ffcbSVarun Prakash struct iscsi_nopout *hdr = (struct iscsi_nopout *)pdu_cb->hdr; 10949730ffcbSVarun Prakash unsigned char *ping_data = NULL; 10959730ffcbSVarun Prakash u32 payload_length = pdu_cb->dlen; 10969730ffcbSVarun Prakash int ret; 10979730ffcbSVarun Prakash 10989730ffcbSVarun Prakash ret = iscsit_setup_nop_out(conn, cmd, hdr); 10999730ffcbSVarun Prakash if (ret < 0) 11009730ffcbSVarun Prakash return 0; 11019730ffcbSVarun Prakash 11029730ffcbSVarun Prakash if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) { 11039730ffcbSVarun Prakash if (!conn->sess->sess_ops->ErrorRecoveryLevel) { 11049730ffcbSVarun Prakash pr_err("Unable to recover from" 11059730ffcbSVarun Prakash " NOPOUT Ping DataCRC failure while in" 11069730ffcbSVarun Prakash " ERL=0.\n"); 11079730ffcbSVarun Prakash ret = -1; 11089730ffcbSVarun Prakash goto out; 11099730ffcbSVarun Prakash } else { 11109730ffcbSVarun Prakash /* 11119730ffcbSVarun Prakash * drop this PDU and let the 11129730ffcbSVarun Prakash * initiator plug the CmdSN gap. 11139730ffcbSVarun Prakash */ 11149730ffcbSVarun Prakash pr_info("Dropping NOPOUT" 11159730ffcbSVarun Prakash " Command CmdSN: 0x%08x due to" 11169730ffcbSVarun Prakash " DataCRC error.\n", hdr->cmdsn); 11179730ffcbSVarun Prakash ret = 0; 11189730ffcbSVarun Prakash goto out; 11199730ffcbSVarun Prakash } 11209730ffcbSVarun Prakash } 11219730ffcbSVarun Prakash 11229730ffcbSVarun Prakash /* 11239730ffcbSVarun Prakash * Handle NOP-OUT payload for traditional iSCSI sockets 11249730ffcbSVarun Prakash */ 11259730ffcbSVarun Prakash if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { 11269730ffcbSVarun Prakash ping_data = kzalloc(payload_length + 1, GFP_KERNEL); 11279730ffcbSVarun Prakash if (!ping_data) { 11289730ffcbSVarun Prakash pr_err("Unable to allocate memory for" 11299730ffcbSVarun Prakash " NOPOUT ping data.\n"); 11309730ffcbSVarun Prakash ret = -1; 11319730ffcbSVarun Prakash goto out; 11329730ffcbSVarun Prakash } 11339730ffcbSVarun Prakash 11349730ffcbSVarun Prakash skb_copy_bits(csk->skb, pdu_cb->doffset, 11359730ffcbSVarun Prakash ping_data, payload_length); 11369730ffcbSVarun Prakash 11379730ffcbSVarun Prakash ping_data[payload_length] = '\0'; 11389730ffcbSVarun Prakash /* 11399730ffcbSVarun Prakash * Attach ping data to struct iscsi_cmd->buf_ptr. 11409730ffcbSVarun Prakash */ 11419730ffcbSVarun Prakash cmd->buf_ptr = ping_data; 11429730ffcbSVarun Prakash cmd->buf_ptr_size = payload_length; 11439730ffcbSVarun Prakash 11449730ffcbSVarun Prakash pr_debug("Got %u bytes of NOPOUT ping" 11459730ffcbSVarun Prakash " data.\n", payload_length); 11469730ffcbSVarun Prakash pr_debug("Ping Data: \"%s\"\n", ping_data); 11479730ffcbSVarun Prakash } 11489730ffcbSVarun Prakash 11499730ffcbSVarun Prakash return iscsit_process_nop_out(conn, cmd, hdr); 11509730ffcbSVarun Prakash out: 11519730ffcbSVarun Prakash if (cmd) 11529730ffcbSVarun Prakash iscsit_free_cmd(cmd, false); 11539730ffcbSVarun Prakash return ret; 11549730ffcbSVarun Prakash } 11559730ffcbSVarun Prakash 11569730ffcbSVarun Prakash static int 11579730ffcbSVarun Prakash cxgbit_handle_text_cmd(struct cxgbit_sock *csk, struct iscsi_cmd *cmd) 11589730ffcbSVarun Prakash { 11599730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 11609730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb); 11619730ffcbSVarun Prakash struct iscsi_text *hdr = (struct iscsi_text *)pdu_cb->hdr; 11629730ffcbSVarun Prakash u32 payload_length = pdu_cb->dlen; 11639730ffcbSVarun Prakash int rc; 11649730ffcbSVarun Prakash unsigned char *text_in = NULL; 11659730ffcbSVarun Prakash 11669730ffcbSVarun Prakash rc = iscsit_setup_text_cmd(conn, cmd, hdr); 11679730ffcbSVarun Prakash if (rc < 0) 11689730ffcbSVarun Prakash return rc; 11699730ffcbSVarun Prakash 11709730ffcbSVarun Prakash if (pdu_cb->flags & PDUCBF_RX_DCRC_ERR) { 11719730ffcbSVarun Prakash if (!conn->sess->sess_ops->ErrorRecoveryLevel) { 11729730ffcbSVarun Prakash pr_err("Unable to recover from" 11739730ffcbSVarun Prakash " Text Data digest failure while in" 11749730ffcbSVarun Prakash " ERL=0.\n"); 11759730ffcbSVarun Prakash goto reject; 11769730ffcbSVarun Prakash } else { 11779730ffcbSVarun Prakash /* 11789730ffcbSVarun Prakash * drop this PDU and let the 11799730ffcbSVarun Prakash * initiator plug the CmdSN gap. 11809730ffcbSVarun Prakash */ 11819730ffcbSVarun Prakash pr_info("Dropping Text" 11829730ffcbSVarun Prakash " Command CmdSN: 0x%08x due to" 11839730ffcbSVarun Prakash " DataCRC error.\n", hdr->cmdsn); 11849730ffcbSVarun Prakash return 0; 11859730ffcbSVarun Prakash } 11869730ffcbSVarun Prakash } 11879730ffcbSVarun Prakash 11889730ffcbSVarun Prakash if (payload_length) { 11899730ffcbSVarun Prakash text_in = kzalloc(payload_length, GFP_KERNEL); 11909730ffcbSVarun Prakash if (!text_in) { 11919730ffcbSVarun Prakash pr_err("Unable to allocate text_in of payload_length: %u\n", 11929730ffcbSVarun Prakash payload_length); 11939730ffcbSVarun Prakash return -ENOMEM; 11949730ffcbSVarun Prakash } 11959730ffcbSVarun Prakash skb_copy_bits(csk->skb, pdu_cb->doffset, 11969730ffcbSVarun Prakash text_in, payload_length); 11979730ffcbSVarun Prakash 11989730ffcbSVarun Prakash text_in[payload_length - 1] = '\0'; 11999730ffcbSVarun Prakash 12009730ffcbSVarun Prakash cmd->text_in_ptr = text_in; 12019730ffcbSVarun Prakash } 12029730ffcbSVarun Prakash 12039730ffcbSVarun Prakash return iscsit_process_text_cmd(conn, cmd, hdr); 12049730ffcbSVarun Prakash 12059730ffcbSVarun Prakash reject: 12069730ffcbSVarun Prakash return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, 12079730ffcbSVarun Prakash pdu_cb->hdr); 12089730ffcbSVarun Prakash } 12099730ffcbSVarun Prakash 12109730ffcbSVarun Prakash static int cxgbit_target_rx_opcode(struct cxgbit_sock *csk) 12119730ffcbSVarun Prakash { 12129730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb); 12139730ffcbSVarun Prakash struct iscsi_hdr *hdr = (struct iscsi_hdr *)pdu_cb->hdr; 12149730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 12159730ffcbSVarun Prakash struct iscsi_cmd *cmd = NULL; 12169730ffcbSVarun Prakash u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK); 12179730ffcbSVarun Prakash int ret = -EINVAL; 12189730ffcbSVarun Prakash 12199730ffcbSVarun Prakash switch (opcode) { 12209730ffcbSVarun Prakash case ISCSI_OP_SCSI_CMD: 12219730ffcbSVarun Prakash cmd = cxgbit_allocate_cmd(csk); 12229730ffcbSVarun Prakash if (!cmd) 12239730ffcbSVarun Prakash goto reject; 12249730ffcbSVarun Prakash 12259730ffcbSVarun Prakash ret = cxgbit_handle_scsi_cmd(csk, cmd); 12269730ffcbSVarun Prakash break; 12279730ffcbSVarun Prakash case ISCSI_OP_SCSI_DATA_OUT: 12289730ffcbSVarun Prakash ret = cxgbit_handle_iscsi_dataout(csk); 12299730ffcbSVarun Prakash break; 12309730ffcbSVarun Prakash case ISCSI_OP_NOOP_OUT: 12319730ffcbSVarun Prakash if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { 12329730ffcbSVarun Prakash cmd = cxgbit_allocate_cmd(csk); 12339730ffcbSVarun Prakash if (!cmd) 12349730ffcbSVarun Prakash goto reject; 12359730ffcbSVarun Prakash } 12369730ffcbSVarun Prakash 12379730ffcbSVarun Prakash ret = cxgbit_handle_nop_out(csk, cmd); 12389730ffcbSVarun Prakash break; 12399730ffcbSVarun Prakash case ISCSI_OP_SCSI_TMFUNC: 12409730ffcbSVarun Prakash cmd = cxgbit_allocate_cmd(csk); 12419730ffcbSVarun Prakash if (!cmd) 12429730ffcbSVarun Prakash goto reject; 12439730ffcbSVarun Prakash 12449730ffcbSVarun Prakash ret = iscsit_handle_task_mgt_cmd(conn, cmd, 12459730ffcbSVarun Prakash (unsigned char *)hdr); 12469730ffcbSVarun Prakash break; 12479730ffcbSVarun Prakash case ISCSI_OP_TEXT: 12489730ffcbSVarun Prakash if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) { 12499730ffcbSVarun Prakash cmd = iscsit_find_cmd_from_itt(conn, hdr->itt); 12509730ffcbSVarun Prakash if (!cmd) 12519730ffcbSVarun Prakash goto reject; 12529730ffcbSVarun Prakash } else { 12539730ffcbSVarun Prakash cmd = cxgbit_allocate_cmd(csk); 12549730ffcbSVarun Prakash if (!cmd) 12559730ffcbSVarun Prakash goto reject; 12569730ffcbSVarun Prakash } 12579730ffcbSVarun Prakash 12589730ffcbSVarun Prakash ret = cxgbit_handle_text_cmd(csk, cmd); 12599730ffcbSVarun Prakash break; 12609730ffcbSVarun Prakash case ISCSI_OP_LOGOUT: 12619730ffcbSVarun Prakash cmd = cxgbit_allocate_cmd(csk); 12629730ffcbSVarun Prakash if (!cmd) 12639730ffcbSVarun Prakash goto reject; 12649730ffcbSVarun Prakash 12659730ffcbSVarun Prakash ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr); 12669730ffcbSVarun Prakash if (ret > 0) 12679730ffcbSVarun Prakash wait_for_completion_timeout(&conn->conn_logout_comp, 12689730ffcbSVarun Prakash SECONDS_FOR_LOGOUT_COMP 12699730ffcbSVarun Prakash * HZ); 12709730ffcbSVarun Prakash break; 12719730ffcbSVarun Prakash case ISCSI_OP_SNACK: 12729730ffcbSVarun Prakash ret = iscsit_handle_snack(conn, (unsigned char *)hdr); 12739730ffcbSVarun Prakash break; 12749730ffcbSVarun Prakash default: 12759730ffcbSVarun Prakash pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode); 12769730ffcbSVarun Prakash dump_stack(); 12779730ffcbSVarun Prakash break; 12789730ffcbSVarun Prakash } 12799730ffcbSVarun Prakash 12809730ffcbSVarun Prakash return ret; 12819730ffcbSVarun Prakash 12829730ffcbSVarun Prakash reject: 12839730ffcbSVarun Prakash return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, 12849730ffcbSVarun Prakash (unsigned char *)hdr); 12859730ffcbSVarun Prakash return ret; 12869730ffcbSVarun Prakash } 12879730ffcbSVarun Prakash 12889730ffcbSVarun Prakash static int cxgbit_rx_opcode(struct cxgbit_sock *csk) 12899730ffcbSVarun Prakash { 12909730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb); 12919730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 12929730ffcbSVarun Prakash struct iscsi_hdr *hdr = pdu_cb->hdr; 12939730ffcbSVarun Prakash u8 opcode; 12949730ffcbSVarun Prakash 12959730ffcbSVarun Prakash if (pdu_cb->flags & PDUCBF_RX_HCRC_ERR) { 12969730ffcbSVarun Prakash atomic_long_inc(&conn->sess->conn_digest_errors); 12979730ffcbSVarun Prakash goto transport_err; 12989730ffcbSVarun Prakash } 12999730ffcbSVarun Prakash 13009730ffcbSVarun Prakash if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) 13019730ffcbSVarun Prakash goto transport_err; 13029730ffcbSVarun Prakash 13039730ffcbSVarun Prakash opcode = hdr->opcode & ISCSI_OPCODE_MASK; 13049730ffcbSVarun Prakash 13059730ffcbSVarun Prakash if (conn->sess->sess_ops->SessionType && 13069730ffcbSVarun Prakash ((!(opcode & ISCSI_OP_TEXT)) || 13079730ffcbSVarun Prakash (!(opcode & ISCSI_OP_LOGOUT)))) { 13089730ffcbSVarun Prakash pr_err("Received illegal iSCSI Opcode: 0x%02x" 13099730ffcbSVarun Prakash " while in Discovery Session, rejecting.\n", opcode); 13109730ffcbSVarun Prakash iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, 13119730ffcbSVarun Prakash (unsigned char *)hdr); 13129730ffcbSVarun Prakash goto transport_err; 13139730ffcbSVarun Prakash } 13149730ffcbSVarun Prakash 13159730ffcbSVarun Prakash if (cxgbit_target_rx_opcode(csk) < 0) 13169730ffcbSVarun Prakash goto transport_err; 13179730ffcbSVarun Prakash 13189730ffcbSVarun Prakash return 0; 13199730ffcbSVarun Prakash 13209730ffcbSVarun Prakash transport_err: 13219730ffcbSVarun Prakash return -1; 13229730ffcbSVarun Prakash } 13239730ffcbSVarun Prakash 13249730ffcbSVarun Prakash static int cxgbit_rx_login_pdu(struct cxgbit_sock *csk) 13259730ffcbSVarun Prakash { 13269730ffcbSVarun Prakash struct iscsi_conn *conn = csk->conn; 13279730ffcbSVarun Prakash struct iscsi_login *login = conn->login; 13289730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_rx_pdu_cb(csk->skb); 13299730ffcbSVarun Prakash struct iscsi_login_req *login_req; 13309730ffcbSVarun Prakash 13319730ffcbSVarun Prakash login_req = (struct iscsi_login_req *)login->req; 13329730ffcbSVarun Prakash memcpy(login_req, pdu_cb->hdr, sizeof(*login_req)); 13339730ffcbSVarun Prakash 13349730ffcbSVarun Prakash pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x," 13359730ffcbSVarun Prakash " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n", 13369730ffcbSVarun Prakash login_req->flags, login_req->itt, login_req->cmdsn, 13379730ffcbSVarun Prakash login_req->exp_statsn, login_req->cid, pdu_cb->dlen); 13389730ffcbSVarun Prakash /* 13399730ffcbSVarun Prakash * Setup the initial iscsi_login values from the leading 13409730ffcbSVarun Prakash * login request PDU. 13419730ffcbSVarun Prakash */ 13429730ffcbSVarun Prakash if (login->first_request) { 13439730ffcbSVarun Prakash login_req = (struct iscsi_login_req *)login->req; 13449730ffcbSVarun Prakash login->leading_connection = (!login_req->tsih) ? 1 : 0; 13459730ffcbSVarun Prakash login->current_stage = ISCSI_LOGIN_CURRENT_STAGE( 13469730ffcbSVarun Prakash login_req->flags); 13479730ffcbSVarun Prakash login->version_min = login_req->min_version; 13489730ffcbSVarun Prakash login->version_max = login_req->max_version; 13499730ffcbSVarun Prakash memcpy(login->isid, login_req->isid, 6); 13509730ffcbSVarun Prakash login->cmd_sn = be32_to_cpu(login_req->cmdsn); 13519730ffcbSVarun Prakash login->init_task_tag = login_req->itt; 13529730ffcbSVarun Prakash login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn); 13539730ffcbSVarun Prakash login->cid = be16_to_cpu(login_req->cid); 13549730ffcbSVarun Prakash login->tsih = be16_to_cpu(login_req->tsih); 13559730ffcbSVarun Prakash } 13569730ffcbSVarun Prakash 13579730ffcbSVarun Prakash if (iscsi_target_check_login_request(conn, login) < 0) 13589730ffcbSVarun Prakash return -1; 13599730ffcbSVarun Prakash 13609730ffcbSVarun Prakash memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS); 13619730ffcbSVarun Prakash skb_copy_bits(csk->skb, pdu_cb->doffset, login->req_buf, pdu_cb->dlen); 13629730ffcbSVarun Prakash 13639730ffcbSVarun Prakash return 0; 13649730ffcbSVarun Prakash } 13659730ffcbSVarun Prakash 13669730ffcbSVarun Prakash static int 13679730ffcbSVarun Prakash cxgbit_process_iscsi_pdu(struct cxgbit_sock *csk, struct sk_buff *skb, int idx) 13689730ffcbSVarun Prakash { 13699730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, idx); 13709730ffcbSVarun Prakash int ret; 13719730ffcbSVarun Prakash 13729730ffcbSVarun Prakash cxgbit_rx_pdu_cb(skb) = pdu_cb; 13739730ffcbSVarun Prakash 13749730ffcbSVarun Prakash csk->skb = skb; 13759730ffcbSVarun Prakash 13769730ffcbSVarun Prakash if (!test_bit(CSK_LOGIN_DONE, &csk->com.flags)) { 13779730ffcbSVarun Prakash ret = cxgbit_rx_login_pdu(csk); 13789730ffcbSVarun Prakash set_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags); 13799730ffcbSVarun Prakash } else { 13809730ffcbSVarun Prakash ret = cxgbit_rx_opcode(csk); 13819730ffcbSVarun Prakash } 13829730ffcbSVarun Prakash 13839730ffcbSVarun Prakash return ret; 13849730ffcbSVarun Prakash } 13859730ffcbSVarun Prakash 13869730ffcbSVarun Prakash static void cxgbit_lro_skb_dump(struct sk_buff *skb) 13879730ffcbSVarun Prakash { 13889730ffcbSVarun Prakash struct skb_shared_info *ssi = skb_shinfo(skb); 13899730ffcbSVarun Prakash struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb); 13909730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0); 13919730ffcbSVarun Prakash u8 i; 13929730ffcbSVarun Prakash 13939730ffcbSVarun Prakash pr_info("skb 0x%p, head 0x%p, 0x%p, len %u,%u, frags %u.\n", 13949730ffcbSVarun Prakash skb, skb->head, skb->data, skb->len, skb->data_len, 13959730ffcbSVarun Prakash ssi->nr_frags); 13969730ffcbSVarun Prakash pr_info("skb 0x%p, lro_cb, csk 0x%p, pdu %u, %u.\n", 13979730ffcbSVarun Prakash skb, lro_cb->csk, lro_cb->pdu_idx, lro_cb->pdu_totallen); 13989730ffcbSVarun Prakash 13999730ffcbSVarun Prakash for (i = 0; i < lro_cb->pdu_idx; i++, pdu_cb++) 14009730ffcbSVarun Prakash pr_info("skb 0x%p, pdu %d, %u, f 0x%x, seq 0x%x, dcrc 0x%x, " 14019730ffcbSVarun Prakash "frags %u.\n", 14029730ffcbSVarun Prakash skb, i, pdu_cb->pdulen, pdu_cb->flags, pdu_cb->seq, 14039730ffcbSVarun Prakash pdu_cb->ddigest, pdu_cb->frags); 14049730ffcbSVarun Prakash for (i = 0; i < ssi->nr_frags; i++) 14059730ffcbSVarun Prakash pr_info("skb 0x%p, frag %d, off %u, sz %u.\n", 14069730ffcbSVarun Prakash skb, i, ssi->frags[i].page_offset, ssi->frags[i].size); 14079730ffcbSVarun Prakash } 14089730ffcbSVarun Prakash 14099730ffcbSVarun Prakash static void cxgbit_lro_hskb_reset(struct cxgbit_sock *csk) 14109730ffcbSVarun Prakash { 14119730ffcbSVarun Prakash struct sk_buff *skb = csk->lro_hskb; 14129730ffcbSVarun Prakash struct skb_shared_info *ssi = skb_shinfo(skb); 14139730ffcbSVarun Prakash u8 i; 14149730ffcbSVarun Prakash 14159730ffcbSVarun Prakash memset(skb->data, 0, LRO_SKB_MIN_HEADROOM); 14169730ffcbSVarun Prakash for (i = 0; i < ssi->nr_frags; i++) 14179730ffcbSVarun Prakash put_page(skb_frag_page(&ssi->frags[i])); 14189730ffcbSVarun Prakash ssi->nr_frags = 0; 141979e57cfeSVarun Prakash skb->data_len = 0; 142079e57cfeSVarun Prakash skb->truesize -= skb->len; 142179e57cfeSVarun Prakash skb->len = 0; 14229730ffcbSVarun Prakash } 14239730ffcbSVarun Prakash 14249730ffcbSVarun Prakash static void 14259730ffcbSVarun Prakash cxgbit_lro_skb_merge(struct cxgbit_sock *csk, struct sk_buff *skb, u8 pdu_idx) 14269730ffcbSVarun Prakash { 14279730ffcbSVarun Prakash struct sk_buff *hskb = csk->lro_hskb; 14289730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *hpdu_cb = cxgbit_skb_lro_pdu_cb(hskb, 0); 14299730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, pdu_idx); 14309730ffcbSVarun Prakash struct skb_shared_info *hssi = skb_shinfo(hskb); 14319730ffcbSVarun Prakash struct skb_shared_info *ssi = skb_shinfo(skb); 14329730ffcbSVarun Prakash unsigned int len = 0; 14339730ffcbSVarun Prakash 14349730ffcbSVarun Prakash if (pdu_cb->flags & PDUCBF_RX_HDR) { 143579e57cfeSVarun Prakash u8 hfrag_idx = hssi->nr_frags; 143679e57cfeSVarun Prakash 143779e57cfeSVarun Prakash hpdu_cb->flags |= pdu_cb->flags; 14389730ffcbSVarun Prakash hpdu_cb->seq = pdu_cb->seq; 14399730ffcbSVarun Prakash hpdu_cb->hdr = pdu_cb->hdr; 14409730ffcbSVarun Prakash hpdu_cb->hlen = pdu_cb->hlen; 14419730ffcbSVarun Prakash 144279e57cfeSVarun Prakash memcpy(&hssi->frags[hfrag_idx], &ssi->frags[pdu_cb->hfrag_idx], 14439730ffcbSVarun Prakash sizeof(skb_frag_t)); 14449730ffcbSVarun Prakash 14459730ffcbSVarun Prakash get_page(skb_frag_page(&hssi->frags[hfrag_idx])); 144679e57cfeSVarun Prakash hssi->nr_frags++; 144779e57cfeSVarun Prakash hpdu_cb->frags++; 144879e57cfeSVarun Prakash hpdu_cb->hfrag_idx = hfrag_idx; 14499730ffcbSVarun Prakash 145079e57cfeSVarun Prakash len = hssi->frags[hfrag_idx].size; 145179e57cfeSVarun Prakash hskb->len += len; 145279e57cfeSVarun Prakash hskb->data_len += len; 145379e57cfeSVarun Prakash hskb->truesize += len; 145479e57cfeSVarun Prakash } 145579e57cfeSVarun Prakash 145679e57cfeSVarun Prakash if (pdu_cb->flags & PDUCBF_RX_DATA) { 145779e57cfeSVarun Prakash u8 dfrag_idx = hssi->nr_frags, i; 145879e57cfeSVarun Prakash 145979e57cfeSVarun Prakash hpdu_cb->flags |= pdu_cb->flags; 146079e57cfeSVarun Prakash hpdu_cb->dfrag_idx = dfrag_idx; 146179e57cfeSVarun Prakash 146279e57cfeSVarun Prakash len = 0; 146379e57cfeSVarun Prakash for (i = 0; i < pdu_cb->nr_dfrags; dfrag_idx++, i++) { 146479e57cfeSVarun Prakash memcpy(&hssi->frags[dfrag_idx], 146579e57cfeSVarun Prakash &ssi->frags[pdu_cb->dfrag_idx + i], 146679e57cfeSVarun Prakash sizeof(skb_frag_t)); 146779e57cfeSVarun Prakash 146879e57cfeSVarun Prakash get_page(skb_frag_page(&hssi->frags[dfrag_idx])); 146979e57cfeSVarun Prakash 147079e57cfeSVarun Prakash len += hssi->frags[dfrag_idx].size; 14719730ffcbSVarun Prakash 14729730ffcbSVarun Prakash hssi->nr_frags++; 14739730ffcbSVarun Prakash hpdu_cb->frags++; 14749730ffcbSVarun Prakash } 14759730ffcbSVarun Prakash 14769730ffcbSVarun Prakash hpdu_cb->dlen = pdu_cb->dlen; 14779730ffcbSVarun Prakash hpdu_cb->doffset = hpdu_cb->hlen; 14789730ffcbSVarun Prakash hpdu_cb->nr_dfrags = pdu_cb->nr_dfrags; 14799730ffcbSVarun Prakash hskb->len += len; 14809730ffcbSVarun Prakash hskb->data_len += len; 14819730ffcbSVarun Prakash hskb->truesize += len; 14829730ffcbSVarun Prakash } 14839730ffcbSVarun Prakash 14849730ffcbSVarun Prakash if (pdu_cb->flags & PDUCBF_RX_STATUS) { 14859730ffcbSVarun Prakash hpdu_cb->flags |= pdu_cb->flags; 14869730ffcbSVarun Prakash 14879730ffcbSVarun Prakash if (hpdu_cb->flags & PDUCBF_RX_DATA) 14889730ffcbSVarun Prakash hpdu_cb->flags &= ~PDUCBF_RX_DATA_DDPD; 14899730ffcbSVarun Prakash 14909730ffcbSVarun Prakash hpdu_cb->ddigest = pdu_cb->ddigest; 14919730ffcbSVarun Prakash hpdu_cb->pdulen = pdu_cb->pdulen; 14929730ffcbSVarun Prakash } 14939730ffcbSVarun Prakash } 14949730ffcbSVarun Prakash 14959730ffcbSVarun Prakash static int cxgbit_process_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb) 14969730ffcbSVarun Prakash { 14979730ffcbSVarun Prakash struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb); 14989730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0); 14999730ffcbSVarun Prakash u8 pdu_idx = 0, last_idx = 0; 15009730ffcbSVarun Prakash int ret = 0; 15019730ffcbSVarun Prakash 15029730ffcbSVarun Prakash if (!pdu_cb->complete) { 15039730ffcbSVarun Prakash cxgbit_lro_skb_merge(csk, skb, 0); 15049730ffcbSVarun Prakash 15059730ffcbSVarun Prakash if (pdu_cb->flags & PDUCBF_RX_STATUS) { 15069730ffcbSVarun Prakash struct sk_buff *hskb = csk->lro_hskb; 15079730ffcbSVarun Prakash 15089730ffcbSVarun Prakash ret = cxgbit_process_iscsi_pdu(csk, hskb, 0); 15099730ffcbSVarun Prakash 15109730ffcbSVarun Prakash cxgbit_lro_hskb_reset(csk); 15119730ffcbSVarun Prakash 15129730ffcbSVarun Prakash if (ret < 0) 15139730ffcbSVarun Prakash goto out; 15149730ffcbSVarun Prakash } 15159730ffcbSVarun Prakash 15169730ffcbSVarun Prakash pdu_idx = 1; 15179730ffcbSVarun Prakash } 15189730ffcbSVarun Prakash 15199730ffcbSVarun Prakash if (lro_cb->pdu_idx) 15209730ffcbSVarun Prakash last_idx = lro_cb->pdu_idx - 1; 15219730ffcbSVarun Prakash 15229730ffcbSVarun Prakash for (; pdu_idx <= last_idx; pdu_idx++) { 15239730ffcbSVarun Prakash ret = cxgbit_process_iscsi_pdu(csk, skb, pdu_idx); 15249730ffcbSVarun Prakash if (ret < 0) 15259730ffcbSVarun Prakash goto out; 15269730ffcbSVarun Prakash } 15279730ffcbSVarun Prakash 15289730ffcbSVarun Prakash if ((!lro_cb->complete) && lro_cb->pdu_idx) 15299730ffcbSVarun Prakash cxgbit_lro_skb_merge(csk, skb, lro_cb->pdu_idx); 15309730ffcbSVarun Prakash 15319730ffcbSVarun Prakash out: 15329730ffcbSVarun Prakash return ret; 15339730ffcbSVarun Prakash } 15349730ffcbSVarun Prakash 15359730ffcbSVarun Prakash static int cxgbit_rx_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb) 15369730ffcbSVarun Prakash { 15379730ffcbSVarun Prakash struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb); 15389730ffcbSVarun Prakash struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 0); 15399730ffcbSVarun Prakash int ret = -1; 15409730ffcbSVarun Prakash 15419730ffcbSVarun Prakash if ((pdu_cb->flags & PDUCBF_RX_HDR) && 15429730ffcbSVarun Prakash (pdu_cb->seq != csk->rcv_nxt)) { 15439730ffcbSVarun Prakash pr_info("csk 0x%p, tid 0x%x, seq 0x%x != 0x%x.\n", 15449730ffcbSVarun Prakash csk, csk->tid, pdu_cb->seq, csk->rcv_nxt); 15459730ffcbSVarun Prakash cxgbit_lro_skb_dump(skb); 15469730ffcbSVarun Prakash return ret; 15479730ffcbSVarun Prakash } 15489730ffcbSVarun Prakash 15499730ffcbSVarun Prakash csk->rcv_nxt += lro_cb->pdu_totallen; 15509730ffcbSVarun Prakash 15519730ffcbSVarun Prakash ret = cxgbit_process_lro_skb(csk, skb); 15529730ffcbSVarun Prakash 15539730ffcbSVarun Prakash csk->rx_credits += lro_cb->pdu_totallen; 15549730ffcbSVarun Prakash 15559730ffcbSVarun Prakash if (csk->rx_credits >= (csk->rcv_win / 4)) 15569730ffcbSVarun Prakash cxgbit_rx_data_ack(csk); 15579730ffcbSVarun Prakash 15589730ffcbSVarun Prakash return ret; 15599730ffcbSVarun Prakash } 15609730ffcbSVarun Prakash 15619730ffcbSVarun Prakash static int cxgbit_rx_skb(struct cxgbit_sock *csk, struct sk_buff *skb) 15629730ffcbSVarun Prakash { 156379e57cfeSVarun Prakash struct cxgb4_lld_info *lldi = &csk->com.cdev->lldi; 15649730ffcbSVarun Prakash int ret = -1; 15659730ffcbSVarun Prakash 156679e57cfeSVarun Prakash if (likely(cxgbit_skcb_flags(skb) & SKCBF_RX_LRO)) { 156779e57cfeSVarun Prakash if (is_t5(lldi->adapter_type)) 15689730ffcbSVarun Prakash ret = cxgbit_rx_lro_skb(csk, skb); 156979e57cfeSVarun Prakash else 157079e57cfeSVarun Prakash ret = cxgbit_process_lro_skb(csk, skb); 157179e57cfeSVarun Prakash } 15729730ffcbSVarun Prakash 15739730ffcbSVarun Prakash __kfree_skb(skb); 15749730ffcbSVarun Prakash return ret; 15759730ffcbSVarun Prakash } 15769730ffcbSVarun Prakash 15779730ffcbSVarun Prakash static bool cxgbit_rxq_len(struct cxgbit_sock *csk, struct sk_buff_head *rxq) 15789730ffcbSVarun Prakash { 15799730ffcbSVarun Prakash spin_lock_bh(&csk->rxq.lock); 15809730ffcbSVarun Prakash if (skb_queue_len(&csk->rxq)) { 15819730ffcbSVarun Prakash skb_queue_splice_init(&csk->rxq, rxq); 15829730ffcbSVarun Prakash spin_unlock_bh(&csk->rxq.lock); 15839730ffcbSVarun Prakash return true; 15849730ffcbSVarun Prakash } 15859730ffcbSVarun Prakash spin_unlock_bh(&csk->rxq.lock); 15869730ffcbSVarun Prakash return false; 15879730ffcbSVarun Prakash } 15889730ffcbSVarun Prakash 15899730ffcbSVarun Prakash static int cxgbit_wait_rxq(struct cxgbit_sock *csk) 15909730ffcbSVarun Prakash { 15919730ffcbSVarun Prakash struct sk_buff *skb; 15929730ffcbSVarun Prakash struct sk_buff_head rxq; 15939730ffcbSVarun Prakash 15949730ffcbSVarun Prakash skb_queue_head_init(&rxq); 15959730ffcbSVarun Prakash 15969730ffcbSVarun Prakash wait_event_interruptible(csk->waitq, cxgbit_rxq_len(csk, &rxq)); 15979730ffcbSVarun Prakash 15989730ffcbSVarun Prakash if (signal_pending(current)) 15999730ffcbSVarun Prakash goto out; 16009730ffcbSVarun Prakash 16019730ffcbSVarun Prakash while ((skb = __skb_dequeue(&rxq))) { 16029730ffcbSVarun Prakash if (cxgbit_rx_skb(csk, skb)) 16039730ffcbSVarun Prakash goto out; 16049730ffcbSVarun Prakash } 16059730ffcbSVarun Prakash 16069730ffcbSVarun Prakash return 0; 16079730ffcbSVarun Prakash out: 16089730ffcbSVarun Prakash __skb_queue_purge(&rxq); 16099730ffcbSVarun Prakash return -1; 16109730ffcbSVarun Prakash } 16119730ffcbSVarun Prakash 16129730ffcbSVarun Prakash int cxgbit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login) 16139730ffcbSVarun Prakash { 16149730ffcbSVarun Prakash struct cxgbit_sock *csk = conn->context; 16159730ffcbSVarun Prakash int ret = -1; 16169730ffcbSVarun Prakash 16179730ffcbSVarun Prakash while (!test_and_clear_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags)) { 16189730ffcbSVarun Prakash ret = cxgbit_wait_rxq(csk); 16199730ffcbSVarun Prakash if (ret) { 16209730ffcbSVarun Prakash clear_bit(CSK_LOGIN_PDU_DONE, &csk->com.flags); 16219730ffcbSVarun Prakash break; 16229730ffcbSVarun Prakash } 16239730ffcbSVarun Prakash } 16249730ffcbSVarun Prakash 16259730ffcbSVarun Prakash return ret; 16269730ffcbSVarun Prakash } 16279730ffcbSVarun Prakash 16289730ffcbSVarun Prakash void cxgbit_get_rx_pdu(struct iscsi_conn *conn) 16299730ffcbSVarun Prakash { 16309730ffcbSVarun Prakash struct cxgbit_sock *csk = conn->context; 16319730ffcbSVarun Prakash 16329730ffcbSVarun Prakash while (!kthread_should_stop()) { 16339730ffcbSVarun Prakash iscsit_thread_check_cpumask(conn, current, 0); 16349730ffcbSVarun Prakash if (cxgbit_wait_rxq(csk)) 16359730ffcbSVarun Prakash return; 16369730ffcbSVarun Prakash } 16379730ffcbSVarun Prakash } 1638