18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Chelsio Communications, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define DRV_NAME "cxgbit" 78c2ecf20Sopenharmony_ci#define DRV_VERSION "1.0.0-ko" 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) DRV_NAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "cxgbit.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 138c2ecf20Sopenharmony_ci#include <net/dcbevent.h> 148c2ecf20Sopenharmony_ci#include "cxgb4_dcb.h" 158c2ecf20Sopenharmony_ci#endif 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ciLIST_HEAD(cdev_list_head); 188c2ecf20Sopenharmony_ci/* cdev list lock */ 198c2ecf20Sopenharmony_ciDEFINE_MUTEX(cdev_list_lock); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_civoid _cxgbit_free_cdev(struct kref *kref) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci struct cxgbit_device *cdev; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci cdev = container_of(kref, struct cxgbit_device, kref); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci cxgbi_ppm_release(cdev2ppm(cdev)); 288c2ecf20Sopenharmony_ci kfree(cdev); 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void cxgbit_set_mdsl(struct cxgbit_device *cdev) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = &cdev->lldi; 348c2ecf20Sopenharmony_ci u32 mdsl; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define ULP2_MAX_PKT_LEN 16224 378c2ecf20Sopenharmony_ci#define ISCSI_PDU_NONPAYLOAD_LEN 312 388c2ecf20Sopenharmony_ci mdsl = min_t(u32, lldi->iscsi_iolen - ISCSI_PDU_NONPAYLOAD_LEN, 398c2ecf20Sopenharmony_ci ULP2_MAX_PKT_LEN - ISCSI_PDU_NONPAYLOAD_LEN); 408c2ecf20Sopenharmony_ci mdsl = min_t(u32, mdsl, 8192); 418c2ecf20Sopenharmony_ci mdsl = min_t(u32, mdsl, (MAX_SKB_FRAGS - 1) * PAGE_SIZE); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci cdev->mdsl = mdsl; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void *cxgbit_uld_add(const struct cxgb4_lld_info *lldi) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct cxgbit_device *cdev; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (is_t4(lldi->adapter_type)) 518c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); 548c2ecf20Sopenharmony_ci if (!cdev) 558c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci kref_init(&cdev->kref); 588c2ecf20Sopenharmony_ci spin_lock_init(&cdev->np_lock); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci cdev->lldi = *lldi; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci cxgbit_set_mdsl(cdev); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (cxgbit_ddp_init(cdev) < 0) { 658c2ecf20Sopenharmony_ci kfree(cdev); 668c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!test_bit(CDEV_DDP_ENABLE, &cdev->flags)) 708c2ecf20Sopenharmony_ci pr_info("cdev %s ddp init failed\n", 718c2ecf20Sopenharmony_ci pci_name(lldi->pdev)); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (lldi->fw_vers >= 0x10d2b00) 748c2ecf20Sopenharmony_ci set_bit(CDEV_ISO_ENABLE, &cdev->flags); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci spin_lock_init(&cdev->cskq.lock); 778c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cdev->cskq.list); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci mutex_lock(&cdev_list_lock); 808c2ecf20Sopenharmony_ci list_add_tail(&cdev->list, &cdev_list_head); 818c2ecf20Sopenharmony_ci mutex_unlock(&cdev_list_lock); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci pr_info("cdev %s added for iSCSI target transport\n", 848c2ecf20Sopenharmony_ci pci_name(lldi->pdev)); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return cdev; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic void cxgbit_close_conn(struct cxgbit_device *cdev) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct cxgbit_sock *csk; 928c2ecf20Sopenharmony_ci struct sk_buff *skb; 938c2ecf20Sopenharmony_ci bool wakeup_thread = false; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci spin_lock_bh(&cdev->cskq.lock); 968c2ecf20Sopenharmony_ci list_for_each_entry(csk, &cdev->cskq.list, list) { 978c2ecf20Sopenharmony_ci skb = alloc_skb(0, GFP_ATOMIC); 988c2ecf20Sopenharmony_ci if (!skb) 998c2ecf20Sopenharmony_ci continue; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci spin_lock_bh(&csk->rxq.lock); 1028c2ecf20Sopenharmony_ci __skb_queue_tail(&csk->rxq, skb); 1038c2ecf20Sopenharmony_ci if (skb_queue_len(&csk->rxq) == 1) 1048c2ecf20Sopenharmony_ci wakeup_thread = true; 1058c2ecf20Sopenharmony_ci spin_unlock_bh(&csk->rxq.lock); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (wakeup_thread) { 1088c2ecf20Sopenharmony_ci wake_up(&csk->waitq); 1098c2ecf20Sopenharmony_ci wakeup_thread = false; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci spin_unlock_bh(&cdev->cskq.lock); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void cxgbit_detach_cdev(struct cxgbit_device *cdev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci bool free_cdev = false; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci spin_lock_bh(&cdev->cskq.lock); 1208c2ecf20Sopenharmony_ci if (list_empty(&cdev->cskq.list)) 1218c2ecf20Sopenharmony_ci free_cdev = true; 1228c2ecf20Sopenharmony_ci spin_unlock_bh(&cdev->cskq.lock); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (free_cdev) { 1258c2ecf20Sopenharmony_ci mutex_lock(&cdev_list_lock); 1268c2ecf20Sopenharmony_ci list_del(&cdev->list); 1278c2ecf20Sopenharmony_ci mutex_unlock(&cdev_list_lock); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci cxgbit_put_cdev(cdev); 1308c2ecf20Sopenharmony_ci } else { 1318c2ecf20Sopenharmony_ci cxgbit_close_conn(cdev); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int cxgbit_uld_state_change(void *handle, enum cxgb4_state state) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct cxgbit_device *cdev = handle; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci switch (state) { 1408c2ecf20Sopenharmony_ci case CXGB4_STATE_UP: 1418c2ecf20Sopenharmony_ci set_bit(CDEV_STATE_UP, &cdev->flags); 1428c2ecf20Sopenharmony_ci pr_info("cdev %s state UP.\n", pci_name(cdev->lldi.pdev)); 1438c2ecf20Sopenharmony_ci break; 1448c2ecf20Sopenharmony_ci case CXGB4_STATE_START_RECOVERY: 1458c2ecf20Sopenharmony_ci clear_bit(CDEV_STATE_UP, &cdev->flags); 1468c2ecf20Sopenharmony_ci cxgbit_close_conn(cdev); 1478c2ecf20Sopenharmony_ci pr_info("cdev %s state RECOVERY.\n", pci_name(cdev->lldi.pdev)); 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci case CXGB4_STATE_DOWN: 1508c2ecf20Sopenharmony_ci pr_info("cdev %s state DOWN.\n", pci_name(cdev->lldi.pdev)); 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case CXGB4_STATE_DETACH: 1538c2ecf20Sopenharmony_ci clear_bit(CDEV_STATE_UP, &cdev->flags); 1548c2ecf20Sopenharmony_ci pr_info("cdev %s state DETACH.\n", pci_name(cdev->lldi.pdev)); 1558c2ecf20Sopenharmony_ci cxgbit_detach_cdev(cdev); 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci default: 1588c2ecf20Sopenharmony_ci pr_info("cdev %s unknown state %d.\n", 1598c2ecf20Sopenharmony_ci pci_name(cdev->lldi.pdev), state); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void 1668c2ecf20Sopenharmony_cicxgbit_process_ddpvld(struct cxgbit_sock *csk, struct cxgbit_lro_pdu_cb *pdu_cb, 1678c2ecf20Sopenharmony_ci u32 ddpvld) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_HCRC_SHIFT)) { 1718c2ecf20Sopenharmony_ci pr_info("tid 0x%x, status 0x%x, hcrc bad.\n", csk->tid, ddpvld); 1728c2ecf20Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_HCRC_ERR; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_DCRC_SHIFT)) { 1768c2ecf20Sopenharmony_ci pr_info("tid 0x%x, status 0x%x, dcrc bad.\n", csk->tid, ddpvld); 1778c2ecf20Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_DCRC_ERR; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_PAD_SHIFT)) 1818c2ecf20Sopenharmony_ci pr_info("tid 0x%x, status 0x%x, pad bad.\n", csk->tid, ddpvld); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if ((ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_DDP_SHIFT)) && 1848c2ecf20Sopenharmony_ci (!(pdu_cb->flags & PDUCBF_RX_DATA))) { 1858c2ecf20Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_DATA_DDPD; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void 1908c2ecf20Sopenharmony_cicxgbit_lro_add_packet_rsp(struct sk_buff *skb, u8 op, const __be64 *rsp) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb); 1938c2ecf20Sopenharmony_ci struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 1948c2ecf20Sopenharmony_ci lro_cb->pdu_idx); 1958c2ecf20Sopenharmony_ci struct cpl_rx_iscsi_ddp *cpl = (struct cpl_rx_iscsi_ddp *)(rsp + 1); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci cxgbit_process_ddpvld(lro_cb->csk, pdu_cb, be32_to_cpu(cpl->ddpvld)); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_STATUS; 2008c2ecf20Sopenharmony_ci pdu_cb->ddigest = ntohl(cpl->ulp_crc); 2018c2ecf20Sopenharmony_ci pdu_cb->pdulen = ntohs(cpl->len); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (pdu_cb->flags & PDUCBF_RX_HDR) 2048c2ecf20Sopenharmony_ci pdu_cb->complete = true; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci lro_cb->pdu_totallen += pdu_cb->pdulen; 2078c2ecf20Sopenharmony_ci lro_cb->complete = true; 2088c2ecf20Sopenharmony_ci lro_cb->pdu_idx++; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void 2128c2ecf20Sopenharmony_cicxgbit_copy_frags(struct sk_buff *skb, const struct pkt_gl *gl, 2138c2ecf20Sopenharmony_ci unsigned int offset) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci u8 skb_frag_idx = skb_shinfo(skb)->nr_frags; 2168c2ecf20Sopenharmony_ci u8 i; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* usually there's just one frag */ 2198c2ecf20Sopenharmony_ci __skb_fill_page_desc(skb, skb_frag_idx, gl->frags[0].page, 2208c2ecf20Sopenharmony_ci gl->frags[0].offset + offset, 2218c2ecf20Sopenharmony_ci gl->frags[0].size - offset); 2228c2ecf20Sopenharmony_ci for (i = 1; i < gl->nfrags; i++) 2238c2ecf20Sopenharmony_ci __skb_fill_page_desc(skb, skb_frag_idx + i, 2248c2ecf20Sopenharmony_ci gl->frags[i].page, 2258c2ecf20Sopenharmony_ci gl->frags[i].offset, 2268c2ecf20Sopenharmony_ci gl->frags[i].size); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags += gl->nfrags; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* get a reference to the last page, we don't own it */ 2318c2ecf20Sopenharmony_ci get_page(gl->frags[gl->nfrags - 1].page); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void 2358c2ecf20Sopenharmony_cicxgbit_lro_add_packet_gl(struct sk_buff *skb, u8 op, const struct pkt_gl *gl) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb); 2388c2ecf20Sopenharmony_ci struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 2398c2ecf20Sopenharmony_ci lro_cb->pdu_idx); 2408c2ecf20Sopenharmony_ci u32 len, offset; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (op == CPL_ISCSI_HDR) { 2438c2ecf20Sopenharmony_ci struct cpl_iscsi_hdr *cpl = (struct cpl_iscsi_hdr *)gl->va; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci offset = sizeof(struct cpl_iscsi_hdr); 2468c2ecf20Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_HDR; 2478c2ecf20Sopenharmony_ci pdu_cb->seq = ntohl(cpl->seq); 2488c2ecf20Sopenharmony_ci len = ntohs(cpl->len); 2498c2ecf20Sopenharmony_ci pdu_cb->hdr = gl->va + offset; 2508c2ecf20Sopenharmony_ci pdu_cb->hlen = len; 2518c2ecf20Sopenharmony_ci pdu_cb->hfrag_idx = skb_shinfo(skb)->nr_frags; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (unlikely(gl->nfrags > 1)) 2548c2ecf20Sopenharmony_ci cxgbit_skcb_flags(skb) = 0; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci lro_cb->complete = false; 2578c2ecf20Sopenharmony_ci } else if (op == CPL_ISCSI_DATA) { 2588c2ecf20Sopenharmony_ci struct cpl_iscsi_data *cpl = (struct cpl_iscsi_data *)gl->va; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci offset = sizeof(struct cpl_iscsi_data); 2618c2ecf20Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_DATA; 2628c2ecf20Sopenharmony_ci len = ntohs(cpl->len); 2638c2ecf20Sopenharmony_ci pdu_cb->dlen = len; 2648c2ecf20Sopenharmony_ci pdu_cb->doffset = lro_cb->offset; 2658c2ecf20Sopenharmony_ci pdu_cb->nr_dfrags = gl->nfrags; 2668c2ecf20Sopenharmony_ci pdu_cb->dfrag_idx = skb_shinfo(skb)->nr_frags; 2678c2ecf20Sopenharmony_ci lro_cb->complete = false; 2688c2ecf20Sopenharmony_ci } else { 2698c2ecf20Sopenharmony_ci struct cpl_rx_iscsi_cmp *cpl; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci cpl = (struct cpl_rx_iscsi_cmp *)gl->va; 2728c2ecf20Sopenharmony_ci offset = sizeof(struct cpl_rx_iscsi_cmp); 2738c2ecf20Sopenharmony_ci pdu_cb->flags |= (PDUCBF_RX_HDR | PDUCBF_RX_STATUS); 2748c2ecf20Sopenharmony_ci len = be16_to_cpu(cpl->len); 2758c2ecf20Sopenharmony_ci pdu_cb->hdr = gl->va + offset; 2768c2ecf20Sopenharmony_ci pdu_cb->hlen = len; 2778c2ecf20Sopenharmony_ci pdu_cb->hfrag_idx = skb_shinfo(skb)->nr_frags; 2788c2ecf20Sopenharmony_ci pdu_cb->ddigest = be32_to_cpu(cpl->ulp_crc); 2798c2ecf20Sopenharmony_ci pdu_cb->pdulen = ntohs(cpl->len); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (unlikely(gl->nfrags > 1)) 2828c2ecf20Sopenharmony_ci cxgbit_skcb_flags(skb) = 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci cxgbit_process_ddpvld(lro_cb->csk, pdu_cb, 2858c2ecf20Sopenharmony_ci be32_to_cpu(cpl->ddpvld)); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (pdu_cb->flags & PDUCBF_RX_DATA_DDPD) { 2888c2ecf20Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_DDP_CMP; 2898c2ecf20Sopenharmony_ci pdu_cb->complete = true; 2908c2ecf20Sopenharmony_ci } else if (pdu_cb->flags & PDUCBF_RX_DATA) { 2918c2ecf20Sopenharmony_ci pdu_cb->complete = true; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci lro_cb->pdu_totallen += pdu_cb->hlen + pdu_cb->dlen; 2958c2ecf20Sopenharmony_ci lro_cb->complete = true; 2968c2ecf20Sopenharmony_ci lro_cb->pdu_idx++; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci cxgbit_copy_frags(skb, gl, offset); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci pdu_cb->frags += gl->nfrags; 3028c2ecf20Sopenharmony_ci lro_cb->offset += len; 3038c2ecf20Sopenharmony_ci skb->len += len; 3048c2ecf20Sopenharmony_ci skb->data_len += len; 3058c2ecf20Sopenharmony_ci skb->truesize += len; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic struct sk_buff * 3098c2ecf20Sopenharmony_cicxgbit_lro_init_skb(struct cxgbit_sock *csk, u8 op, const struct pkt_gl *gl, 3108c2ecf20Sopenharmony_ci const __be64 *rsp, struct napi_struct *napi) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct sk_buff *skb; 3138c2ecf20Sopenharmony_ci struct cxgbit_lro_cb *lro_cb; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci skb = napi_alloc_skb(napi, LRO_SKB_MAX_HEADROOM); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (unlikely(!skb)) 3188c2ecf20Sopenharmony_ci return NULL; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci memset(skb->data, 0, LRO_SKB_MAX_HEADROOM); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci cxgbit_skcb_flags(skb) |= SKCBF_RX_LRO; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci lro_cb = cxgbit_skb_lro_cb(skb); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci cxgbit_get_csk(csk); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci lro_cb->csk = csk; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return skb; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic void cxgbit_queue_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci bool wakeup_thread = false; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci spin_lock(&csk->rxq.lock); 3388c2ecf20Sopenharmony_ci __skb_queue_tail(&csk->rxq, skb); 3398c2ecf20Sopenharmony_ci if (skb_queue_len(&csk->rxq) == 1) 3408c2ecf20Sopenharmony_ci wakeup_thread = true; 3418c2ecf20Sopenharmony_ci spin_unlock(&csk->rxq.lock); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (wakeup_thread) 3448c2ecf20Sopenharmony_ci wake_up(&csk->waitq); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic void cxgbit_lro_flush(struct t4_lro_mgr *lro_mgr, struct sk_buff *skb) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb); 3508c2ecf20Sopenharmony_ci struct cxgbit_sock *csk = lro_cb->csk; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci csk->lro_skb = NULL; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci __skb_unlink(skb, &lro_mgr->lroq); 3558c2ecf20Sopenharmony_ci cxgbit_queue_lro_skb(csk, skb); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci cxgbit_put_csk(csk); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci lro_mgr->lro_pkts++; 3608c2ecf20Sopenharmony_ci lro_mgr->lro_session_cnt--; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic void cxgbit_uld_lro_flush(struct t4_lro_mgr *lro_mgr) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct sk_buff *skb; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci while ((skb = skb_peek(&lro_mgr->lroq))) 3688c2ecf20Sopenharmony_ci cxgbit_lro_flush(lro_mgr, skb); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int 3728c2ecf20Sopenharmony_cicxgbit_lro_receive(struct cxgbit_sock *csk, u8 op, const __be64 *rsp, 3738c2ecf20Sopenharmony_ci const struct pkt_gl *gl, struct t4_lro_mgr *lro_mgr, 3748c2ecf20Sopenharmony_ci struct napi_struct *napi) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct sk_buff *skb; 3778c2ecf20Sopenharmony_ci struct cxgbit_lro_cb *lro_cb; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (!csk) { 3808c2ecf20Sopenharmony_ci pr_err("%s: csk NULL, op 0x%x.\n", __func__, op); 3818c2ecf20Sopenharmony_ci goto out; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (csk->lro_skb) 3858c2ecf20Sopenharmony_ci goto add_packet; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistart_lro: 3888c2ecf20Sopenharmony_ci if (lro_mgr->lro_session_cnt >= MAX_LRO_SESSIONS) { 3898c2ecf20Sopenharmony_ci cxgbit_uld_lro_flush(lro_mgr); 3908c2ecf20Sopenharmony_ci goto start_lro; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci skb = cxgbit_lro_init_skb(csk, op, gl, rsp, napi); 3948c2ecf20Sopenharmony_ci if (unlikely(!skb)) 3958c2ecf20Sopenharmony_ci goto out; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci csk->lro_skb = skb; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci __skb_queue_tail(&lro_mgr->lroq, skb); 4008c2ecf20Sopenharmony_ci lro_mgr->lro_session_cnt++; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ciadd_packet: 4038c2ecf20Sopenharmony_ci skb = csk->lro_skb; 4048c2ecf20Sopenharmony_ci lro_cb = cxgbit_skb_lro_cb(skb); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if ((gl && (((skb_shinfo(skb)->nr_frags + gl->nfrags) > 4078c2ecf20Sopenharmony_ci MAX_SKB_FRAGS) || (lro_cb->pdu_totallen >= LRO_FLUSH_LEN_MAX))) || 4088c2ecf20Sopenharmony_ci (lro_cb->pdu_idx >= MAX_SKB_FRAGS)) { 4098c2ecf20Sopenharmony_ci cxgbit_lro_flush(lro_mgr, skb); 4108c2ecf20Sopenharmony_ci goto start_lro; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (gl) 4148c2ecf20Sopenharmony_ci cxgbit_lro_add_packet_gl(skb, op, gl); 4158c2ecf20Sopenharmony_ci else 4168c2ecf20Sopenharmony_ci cxgbit_lro_add_packet_rsp(skb, op, rsp); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci lro_mgr->lro_merged++; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ciout: 4238c2ecf20Sopenharmony_ci return -1; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int 4278c2ecf20Sopenharmony_cicxgbit_uld_lro_rx_handler(void *hndl, const __be64 *rsp, 4288c2ecf20Sopenharmony_ci const struct pkt_gl *gl, struct t4_lro_mgr *lro_mgr, 4298c2ecf20Sopenharmony_ci struct napi_struct *napi) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct cxgbit_device *cdev = hndl; 4328c2ecf20Sopenharmony_ci struct cxgb4_lld_info *lldi = &cdev->lldi; 4338c2ecf20Sopenharmony_ci struct cpl_tx_data *rpl = NULL; 4348c2ecf20Sopenharmony_ci struct cxgbit_sock *csk = NULL; 4358c2ecf20Sopenharmony_ci unsigned int tid = 0; 4368c2ecf20Sopenharmony_ci struct sk_buff *skb; 4378c2ecf20Sopenharmony_ci unsigned int op = *(u8 *)rsp; 4388c2ecf20Sopenharmony_ci bool lro_flush = true; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci switch (op) { 4418c2ecf20Sopenharmony_ci case CPL_ISCSI_HDR: 4428c2ecf20Sopenharmony_ci case CPL_ISCSI_DATA: 4438c2ecf20Sopenharmony_ci case CPL_RX_ISCSI_CMP: 4448c2ecf20Sopenharmony_ci case CPL_RX_ISCSI_DDP: 4458c2ecf20Sopenharmony_ci case CPL_FW4_ACK: 4468c2ecf20Sopenharmony_ci lro_flush = false; 4478c2ecf20Sopenharmony_ci fallthrough; 4488c2ecf20Sopenharmony_ci case CPL_ABORT_RPL_RSS: 4498c2ecf20Sopenharmony_ci case CPL_PASS_ESTABLISH: 4508c2ecf20Sopenharmony_ci case CPL_PEER_CLOSE: 4518c2ecf20Sopenharmony_ci case CPL_CLOSE_CON_RPL: 4528c2ecf20Sopenharmony_ci case CPL_ABORT_REQ_RSS: 4538c2ecf20Sopenharmony_ci case CPL_SET_TCB_RPL: 4548c2ecf20Sopenharmony_ci case CPL_RX_DATA: 4558c2ecf20Sopenharmony_ci rpl = gl ? (struct cpl_tx_data *)gl->va : 4568c2ecf20Sopenharmony_ci (struct cpl_tx_data *)(rsp + 1); 4578c2ecf20Sopenharmony_ci tid = GET_TID(rpl); 4588c2ecf20Sopenharmony_ci csk = lookup_tid(lldi->tids, tid); 4598c2ecf20Sopenharmony_ci break; 4608c2ecf20Sopenharmony_ci default: 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (csk && csk->lro_skb && lro_flush) 4658c2ecf20Sopenharmony_ci cxgbit_lro_flush(lro_mgr, csk->lro_skb); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (!gl) { 4688c2ecf20Sopenharmony_ci unsigned int len; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (op == CPL_RX_ISCSI_DDP) { 4718c2ecf20Sopenharmony_ci if (!cxgbit_lro_receive(csk, op, rsp, NULL, lro_mgr, 4728c2ecf20Sopenharmony_ci napi)) 4738c2ecf20Sopenharmony_ci return 0; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci len = 64 - sizeof(struct rsp_ctrl) - 8; 4778c2ecf20Sopenharmony_ci skb = napi_alloc_skb(napi, len); 4788c2ecf20Sopenharmony_ci if (!skb) 4798c2ecf20Sopenharmony_ci goto nomem; 4808c2ecf20Sopenharmony_ci __skb_put(skb, len); 4818c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, &rsp[1], len); 4828c2ecf20Sopenharmony_ci } else { 4838c2ecf20Sopenharmony_ci if (unlikely(op != *(u8 *)gl->va)) { 4848c2ecf20Sopenharmony_ci pr_info("? FL 0x%p,RSS%#llx,FL %#llx,len %u.\n", 4858c2ecf20Sopenharmony_ci gl->va, be64_to_cpu(*rsp), 4868c2ecf20Sopenharmony_ci get_unaligned_be64(gl->va), 4878c2ecf20Sopenharmony_ci gl->tot_len); 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if ((op == CPL_ISCSI_HDR) || (op == CPL_ISCSI_DATA) || 4928c2ecf20Sopenharmony_ci (op == CPL_RX_ISCSI_CMP)) { 4938c2ecf20Sopenharmony_ci if (!cxgbit_lro_receive(csk, op, rsp, gl, lro_mgr, 4948c2ecf20Sopenharmony_ci napi)) 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci#define RX_PULL_LEN 128 4998c2ecf20Sopenharmony_ci skb = cxgb4_pktgl_to_skb(gl, RX_PULL_LEN, RX_PULL_LEN); 5008c2ecf20Sopenharmony_ci if (unlikely(!skb)) 5018c2ecf20Sopenharmony_ci goto nomem; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci rpl = (struct cpl_tx_data *)skb->data; 5058c2ecf20Sopenharmony_ci op = rpl->ot.opcode; 5068c2ecf20Sopenharmony_ci cxgbit_skcb_rx_opcode(skb) = op; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci pr_debug("cdev %p, opcode 0x%x(0x%x,0x%x), skb %p.\n", 5098c2ecf20Sopenharmony_ci cdev, op, rpl->ot.opcode_tid, 5108c2ecf20Sopenharmony_ci ntohl(rpl->ot.opcode_tid), skb); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (op < NUM_CPL_CMDS && cxgbit_cplhandlers[op]) { 5138c2ecf20Sopenharmony_ci cxgbit_cplhandlers[op](cdev, skb); 5148c2ecf20Sopenharmony_ci } else { 5158c2ecf20Sopenharmony_ci pr_err("No handler for opcode 0x%x.\n", op); 5168c2ecf20Sopenharmony_ci __kfree_skb(skb); 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_cinomem: 5208c2ecf20Sopenharmony_ci pr_err("%s OOM bailing out.\n", __func__); 5218c2ecf20Sopenharmony_ci return 1; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 5258c2ecf20Sopenharmony_cistruct cxgbit_dcb_work { 5268c2ecf20Sopenharmony_ci struct dcb_app_type dcb_app; 5278c2ecf20Sopenharmony_ci struct work_struct work; 5288c2ecf20Sopenharmony_ci}; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic void 5318c2ecf20Sopenharmony_cicxgbit_update_dcb_priority(struct cxgbit_device *cdev, u8 port_id, 5328c2ecf20Sopenharmony_ci u8 dcb_priority, u16 port_num) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct cxgbit_sock *csk; 5358c2ecf20Sopenharmony_ci struct sk_buff *skb; 5368c2ecf20Sopenharmony_ci u16 local_port; 5378c2ecf20Sopenharmony_ci bool wakeup_thread = false; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci spin_lock_bh(&cdev->cskq.lock); 5408c2ecf20Sopenharmony_ci list_for_each_entry(csk, &cdev->cskq.list, list) { 5418c2ecf20Sopenharmony_ci if (csk->port_id != port_id) 5428c2ecf20Sopenharmony_ci continue; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (csk->com.local_addr.ss_family == AF_INET6) { 5458c2ecf20Sopenharmony_ci struct sockaddr_in6 *sock_in6; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci sock_in6 = (struct sockaddr_in6 *)&csk->com.local_addr; 5488c2ecf20Sopenharmony_ci local_port = ntohs(sock_in6->sin6_port); 5498c2ecf20Sopenharmony_ci } else { 5508c2ecf20Sopenharmony_ci struct sockaddr_in *sock_in; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci sock_in = (struct sockaddr_in *)&csk->com.local_addr; 5538c2ecf20Sopenharmony_ci local_port = ntohs(sock_in->sin_port); 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (local_port != port_num) 5578c2ecf20Sopenharmony_ci continue; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (csk->dcb_priority == dcb_priority) 5608c2ecf20Sopenharmony_ci continue; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci skb = alloc_skb(0, GFP_ATOMIC); 5638c2ecf20Sopenharmony_ci if (!skb) 5648c2ecf20Sopenharmony_ci continue; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci spin_lock(&csk->rxq.lock); 5678c2ecf20Sopenharmony_ci __skb_queue_tail(&csk->rxq, skb); 5688c2ecf20Sopenharmony_ci if (skb_queue_len(&csk->rxq) == 1) 5698c2ecf20Sopenharmony_ci wakeup_thread = true; 5708c2ecf20Sopenharmony_ci spin_unlock(&csk->rxq.lock); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (wakeup_thread) { 5738c2ecf20Sopenharmony_ci wake_up(&csk->waitq); 5748c2ecf20Sopenharmony_ci wakeup_thread = false; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci spin_unlock_bh(&cdev->cskq.lock); 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic void cxgbit_dcb_workfn(struct work_struct *work) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci struct cxgbit_dcb_work *dcb_work; 5838c2ecf20Sopenharmony_ci struct net_device *ndev; 5848c2ecf20Sopenharmony_ci struct cxgbit_device *cdev = NULL; 5858c2ecf20Sopenharmony_ci struct dcb_app_type *iscsi_app; 5868c2ecf20Sopenharmony_ci u8 priority, port_id = 0xff; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci dcb_work = container_of(work, struct cxgbit_dcb_work, work); 5898c2ecf20Sopenharmony_ci iscsi_app = &dcb_work->dcb_app; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) { 5928c2ecf20Sopenharmony_ci if ((iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_STREAM) && 5938c2ecf20Sopenharmony_ci (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)) 5948c2ecf20Sopenharmony_ci goto out; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci priority = iscsi_app->app.priority; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci } else if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_CEE) { 5998c2ecf20Sopenharmony_ci if (iscsi_app->app.selector != DCB_APP_IDTYPE_PORTNUM) 6008c2ecf20Sopenharmony_ci goto out; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (!iscsi_app->app.priority) 6038c2ecf20Sopenharmony_ci goto out; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci priority = ffs(iscsi_app->app.priority) - 1; 6068c2ecf20Sopenharmony_ci } else { 6078c2ecf20Sopenharmony_ci goto out; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci pr_debug("priority for ifid %d is %u\n", 6118c2ecf20Sopenharmony_ci iscsi_app->ifindex, priority); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci ndev = dev_get_by_index(&init_net, iscsi_app->ifindex); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (!ndev) 6168c2ecf20Sopenharmony_ci goto out; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci mutex_lock(&cdev_list_lock); 6198c2ecf20Sopenharmony_ci cdev = cxgbit_find_device(ndev, &port_id); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci dev_put(ndev); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (!cdev) { 6248c2ecf20Sopenharmony_ci mutex_unlock(&cdev_list_lock); 6258c2ecf20Sopenharmony_ci goto out; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci cxgbit_update_dcb_priority(cdev, port_id, priority, 6298c2ecf20Sopenharmony_ci iscsi_app->app.protocol); 6308c2ecf20Sopenharmony_ci mutex_unlock(&cdev_list_lock); 6318c2ecf20Sopenharmony_ciout: 6328c2ecf20Sopenharmony_ci kfree(dcb_work); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int 6368c2ecf20Sopenharmony_cicxgbit_dcbevent_notify(struct notifier_block *nb, unsigned long action, 6378c2ecf20Sopenharmony_ci void *data) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci struct cxgbit_dcb_work *dcb_work; 6408c2ecf20Sopenharmony_ci struct dcb_app_type *dcb_app = data; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci dcb_work = kzalloc(sizeof(*dcb_work), GFP_ATOMIC); 6438c2ecf20Sopenharmony_ci if (!dcb_work) 6448c2ecf20Sopenharmony_ci return NOTIFY_DONE; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci dcb_work->dcb_app = *dcb_app; 6478c2ecf20Sopenharmony_ci INIT_WORK(&dcb_work->work, cxgbit_dcb_workfn); 6488c2ecf20Sopenharmony_ci schedule_work(&dcb_work->work); 6498c2ecf20Sopenharmony_ci return NOTIFY_OK; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci#endif 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic enum target_prot_op cxgbit_get_sup_prot_ops(struct iscsi_conn *conn) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci return TARGET_PROT_NORMAL; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic struct iscsit_transport cxgbit_transport = { 6598c2ecf20Sopenharmony_ci .name = DRV_NAME, 6608c2ecf20Sopenharmony_ci .transport_type = ISCSI_CXGBIT, 6618c2ecf20Sopenharmony_ci .rdma_shutdown = false, 6628c2ecf20Sopenharmony_ci .priv_size = sizeof(struct cxgbit_cmd), 6638c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6648c2ecf20Sopenharmony_ci .iscsit_setup_np = cxgbit_setup_np, 6658c2ecf20Sopenharmony_ci .iscsit_accept_np = cxgbit_accept_np, 6668c2ecf20Sopenharmony_ci .iscsit_free_np = cxgbit_free_np, 6678c2ecf20Sopenharmony_ci .iscsit_free_conn = cxgbit_free_conn, 6688c2ecf20Sopenharmony_ci .iscsit_get_login_rx = cxgbit_get_login_rx, 6698c2ecf20Sopenharmony_ci .iscsit_put_login_tx = cxgbit_put_login_tx, 6708c2ecf20Sopenharmony_ci .iscsit_immediate_queue = iscsit_immediate_queue, 6718c2ecf20Sopenharmony_ci .iscsit_response_queue = iscsit_response_queue, 6728c2ecf20Sopenharmony_ci .iscsit_get_dataout = iscsit_build_r2ts_for_cmd, 6738c2ecf20Sopenharmony_ci .iscsit_queue_data_in = iscsit_queue_rsp, 6748c2ecf20Sopenharmony_ci .iscsit_queue_status = iscsit_queue_rsp, 6758c2ecf20Sopenharmony_ci .iscsit_xmit_pdu = cxgbit_xmit_pdu, 6768c2ecf20Sopenharmony_ci .iscsit_get_r2t_ttt = cxgbit_get_r2t_ttt, 6778c2ecf20Sopenharmony_ci .iscsit_get_rx_pdu = cxgbit_get_rx_pdu, 6788c2ecf20Sopenharmony_ci .iscsit_validate_params = cxgbit_validate_params, 6798c2ecf20Sopenharmony_ci .iscsit_unmap_cmd = cxgbit_unmap_cmd, 6808c2ecf20Sopenharmony_ci .iscsit_aborted_task = iscsit_aborted_task, 6818c2ecf20Sopenharmony_ci .iscsit_get_sup_prot_ops = cxgbit_get_sup_prot_ops, 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic struct cxgb4_uld_info cxgbit_uld_info = { 6858c2ecf20Sopenharmony_ci .name = DRV_NAME, 6868c2ecf20Sopenharmony_ci .nrxq = MAX_ULD_QSETS, 6878c2ecf20Sopenharmony_ci .ntxq = MAX_ULD_QSETS, 6888c2ecf20Sopenharmony_ci .rxq_size = 1024, 6898c2ecf20Sopenharmony_ci .lro = true, 6908c2ecf20Sopenharmony_ci .add = cxgbit_uld_add, 6918c2ecf20Sopenharmony_ci .state_change = cxgbit_uld_state_change, 6928c2ecf20Sopenharmony_ci .lro_rx_handler = cxgbit_uld_lro_rx_handler, 6938c2ecf20Sopenharmony_ci .lro_flush = cxgbit_uld_lro_flush, 6948c2ecf20Sopenharmony_ci}; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 6978c2ecf20Sopenharmony_cistatic struct notifier_block cxgbit_dcbevent_nb = { 6988c2ecf20Sopenharmony_ci .notifier_call = cxgbit_dcbevent_notify, 6998c2ecf20Sopenharmony_ci}; 7008c2ecf20Sopenharmony_ci#endif 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic int __init cxgbit_init(void) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci cxgb4_register_uld(CXGB4_ULD_ISCSIT, &cxgbit_uld_info); 7058c2ecf20Sopenharmony_ci iscsit_register_transport(&cxgbit_transport); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 7088c2ecf20Sopenharmony_ci pr_info("%s dcb enabled.\n", DRV_NAME); 7098c2ecf20Sopenharmony_ci register_dcbevent_notifier(&cxgbit_dcbevent_nb); 7108c2ecf20Sopenharmony_ci#endif 7118c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof_field(struct sk_buff, cb) < 7128c2ecf20Sopenharmony_ci sizeof(union cxgbit_skb_cb)); 7138c2ecf20Sopenharmony_ci return 0; 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic void __exit cxgbit_exit(void) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct cxgbit_device *cdev, *tmp; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 7218c2ecf20Sopenharmony_ci unregister_dcbevent_notifier(&cxgbit_dcbevent_nb); 7228c2ecf20Sopenharmony_ci#endif 7238c2ecf20Sopenharmony_ci mutex_lock(&cdev_list_lock); 7248c2ecf20Sopenharmony_ci list_for_each_entry_safe(cdev, tmp, &cdev_list_head, list) { 7258c2ecf20Sopenharmony_ci list_del(&cdev->list); 7268c2ecf20Sopenharmony_ci cxgbit_put_cdev(cdev); 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci mutex_unlock(&cdev_list_lock); 7298c2ecf20Sopenharmony_ci iscsit_unregister_transport(&cxgbit_transport); 7308c2ecf20Sopenharmony_ci cxgb4_unregister_uld(CXGB4_ULD_ISCSIT); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cimodule_init(cxgbit_init); 7348c2ecf20Sopenharmony_cimodule_exit(cxgbit_exit); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Chelsio iSCSI target offload driver"); 7378c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chelsio Communications"); 7388c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 7398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 740