162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Chelsio Communications, Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define DRV_NAME "cxgbit" 762306a36Sopenharmony_ci#define DRV_VERSION "1.0.0-ko" 862306a36Sopenharmony_ci#define pr_fmt(fmt) DRV_NAME ": " fmt 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "cxgbit.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 1362306a36Sopenharmony_ci#include <net/dcbevent.h> 1462306a36Sopenharmony_ci#include "cxgb4_dcb.h" 1562306a36Sopenharmony_ci#endif 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciLIST_HEAD(cdev_list_head); 1862306a36Sopenharmony_ci/* cdev list lock */ 1962306a36Sopenharmony_ciDEFINE_MUTEX(cdev_list_lock); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_civoid _cxgbit_free_cdev(struct kref *kref) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct cxgbit_device *cdev; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci cdev = container_of(kref, struct cxgbit_device, kref); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci cxgbi_ppm_release(cdev2ppm(cdev)); 2862306a36Sopenharmony_ci kfree(cdev); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void cxgbit_set_mdsl(struct cxgbit_device *cdev) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = &cdev->lldi; 3462306a36Sopenharmony_ci u32 mdsl; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define CXGBIT_T5_MAX_PDU_LEN 16224 3762306a36Sopenharmony_ci#define CXGBIT_PDU_NONPAYLOAD_LEN 312 /* 48(BHS) + 256(AHS) + 8(Digest) */ 3862306a36Sopenharmony_ci if (is_t5(lldi->adapter_type)) { 3962306a36Sopenharmony_ci mdsl = min_t(u32, lldi->iscsi_iolen - CXGBIT_PDU_NONPAYLOAD_LEN, 4062306a36Sopenharmony_ci CXGBIT_T5_MAX_PDU_LEN - CXGBIT_PDU_NONPAYLOAD_LEN); 4162306a36Sopenharmony_ci } else { 4262306a36Sopenharmony_ci mdsl = lldi->iscsi_iolen - CXGBIT_PDU_NONPAYLOAD_LEN; 4362306a36Sopenharmony_ci mdsl = min(mdsl, 16384U); 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci mdsl = round_down(mdsl, 4); 4762306a36Sopenharmony_ci mdsl = min_t(u32, mdsl, 4 * PAGE_SIZE); 4862306a36Sopenharmony_ci mdsl = min_t(u32, mdsl, (MAX_SKB_FRAGS - 1) * PAGE_SIZE); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci cdev->mdsl = mdsl; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic void *cxgbit_uld_add(const struct cxgb4_lld_info *lldi) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct cxgbit_device *cdev; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (is_t4(lldi->adapter_type)) 5862306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); 6162306a36Sopenharmony_ci if (!cdev) 6262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci kref_init(&cdev->kref); 6562306a36Sopenharmony_ci spin_lock_init(&cdev->np_lock); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci cdev->lldi = *lldi; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci cxgbit_set_mdsl(cdev); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (cxgbit_ddp_init(cdev) < 0) { 7262306a36Sopenharmony_ci kfree(cdev); 7362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (!test_bit(CDEV_DDP_ENABLE, &cdev->flags)) 7762306a36Sopenharmony_ci pr_info("cdev %s ddp init failed\n", 7862306a36Sopenharmony_ci pci_name(lldi->pdev)); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (lldi->fw_vers >= 0x10d2b00) 8162306a36Sopenharmony_ci set_bit(CDEV_ISO_ENABLE, &cdev->flags); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci spin_lock_init(&cdev->cskq.lock); 8462306a36Sopenharmony_ci INIT_LIST_HEAD(&cdev->cskq.list); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci mutex_lock(&cdev_list_lock); 8762306a36Sopenharmony_ci list_add_tail(&cdev->list, &cdev_list_head); 8862306a36Sopenharmony_ci mutex_unlock(&cdev_list_lock); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci pr_info("cdev %s added for iSCSI target transport\n", 9162306a36Sopenharmony_ci pci_name(lldi->pdev)); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci return cdev; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void cxgbit_close_conn(struct cxgbit_device *cdev) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct cxgbit_sock *csk; 9962306a36Sopenharmony_ci struct sk_buff *skb; 10062306a36Sopenharmony_ci bool wakeup_thread = false; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci spin_lock_bh(&cdev->cskq.lock); 10362306a36Sopenharmony_ci list_for_each_entry(csk, &cdev->cskq.list, list) { 10462306a36Sopenharmony_ci skb = alloc_skb(0, GFP_ATOMIC); 10562306a36Sopenharmony_ci if (!skb) 10662306a36Sopenharmony_ci continue; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci spin_lock_bh(&csk->rxq.lock); 10962306a36Sopenharmony_ci __skb_queue_tail(&csk->rxq, skb); 11062306a36Sopenharmony_ci if (skb_queue_len(&csk->rxq) == 1) 11162306a36Sopenharmony_ci wakeup_thread = true; 11262306a36Sopenharmony_ci spin_unlock_bh(&csk->rxq.lock); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (wakeup_thread) { 11562306a36Sopenharmony_ci wake_up(&csk->waitq); 11662306a36Sopenharmony_ci wakeup_thread = false; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci spin_unlock_bh(&cdev->cskq.lock); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void cxgbit_detach_cdev(struct cxgbit_device *cdev) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci bool free_cdev = false; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci spin_lock_bh(&cdev->cskq.lock); 12762306a36Sopenharmony_ci if (list_empty(&cdev->cskq.list)) 12862306a36Sopenharmony_ci free_cdev = true; 12962306a36Sopenharmony_ci spin_unlock_bh(&cdev->cskq.lock); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (free_cdev) { 13262306a36Sopenharmony_ci mutex_lock(&cdev_list_lock); 13362306a36Sopenharmony_ci list_del(&cdev->list); 13462306a36Sopenharmony_ci mutex_unlock(&cdev_list_lock); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci cxgbit_put_cdev(cdev); 13762306a36Sopenharmony_ci } else { 13862306a36Sopenharmony_ci cxgbit_close_conn(cdev); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int cxgbit_uld_state_change(void *handle, enum cxgb4_state state) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct cxgbit_device *cdev = handle; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci switch (state) { 14762306a36Sopenharmony_ci case CXGB4_STATE_UP: 14862306a36Sopenharmony_ci set_bit(CDEV_STATE_UP, &cdev->flags); 14962306a36Sopenharmony_ci pr_info("cdev %s state UP.\n", pci_name(cdev->lldi.pdev)); 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci case CXGB4_STATE_START_RECOVERY: 15262306a36Sopenharmony_ci clear_bit(CDEV_STATE_UP, &cdev->flags); 15362306a36Sopenharmony_ci cxgbit_close_conn(cdev); 15462306a36Sopenharmony_ci pr_info("cdev %s state RECOVERY.\n", pci_name(cdev->lldi.pdev)); 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci case CXGB4_STATE_DOWN: 15762306a36Sopenharmony_ci pr_info("cdev %s state DOWN.\n", pci_name(cdev->lldi.pdev)); 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci case CXGB4_STATE_DETACH: 16062306a36Sopenharmony_ci clear_bit(CDEV_STATE_UP, &cdev->flags); 16162306a36Sopenharmony_ci pr_info("cdev %s state DETACH.\n", pci_name(cdev->lldi.pdev)); 16262306a36Sopenharmony_ci cxgbit_detach_cdev(cdev); 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci default: 16562306a36Sopenharmony_ci pr_info("cdev %s unknown state %d.\n", 16662306a36Sopenharmony_ci pci_name(cdev->lldi.pdev), state); 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void 17362306a36Sopenharmony_cicxgbit_process_ddpvld(struct cxgbit_sock *csk, struct cxgbit_lro_pdu_cb *pdu_cb, 17462306a36Sopenharmony_ci u32 ddpvld) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_HCRC_SHIFT)) { 17862306a36Sopenharmony_ci pr_info("tid 0x%x, status 0x%x, hcrc bad.\n", csk->tid, ddpvld); 17962306a36Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_HCRC_ERR; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_DCRC_SHIFT)) { 18362306a36Sopenharmony_ci pr_info("tid 0x%x, status 0x%x, dcrc bad.\n", csk->tid, ddpvld); 18462306a36Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_DCRC_ERR; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_PAD_SHIFT)) 18862306a36Sopenharmony_ci pr_info("tid 0x%x, status 0x%x, pad bad.\n", csk->tid, ddpvld); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if ((ddpvld & (1 << CPL_RX_ISCSI_DDP_STATUS_DDP_SHIFT)) && 19162306a36Sopenharmony_ci (!(pdu_cb->flags & PDUCBF_RX_DATA))) { 19262306a36Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_DATA_DDPD; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void 19762306a36Sopenharmony_cicxgbit_lro_add_packet_rsp(struct sk_buff *skb, u8 op, const __be64 *rsp) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb); 20062306a36Sopenharmony_ci struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 20162306a36Sopenharmony_ci lro_cb->pdu_idx); 20262306a36Sopenharmony_ci struct cpl_rx_iscsi_ddp *cpl = (struct cpl_rx_iscsi_ddp *)(rsp + 1); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci cxgbit_process_ddpvld(lro_cb->csk, pdu_cb, be32_to_cpu(cpl->ddpvld)); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_STATUS; 20762306a36Sopenharmony_ci pdu_cb->ddigest = ntohl(cpl->ulp_crc); 20862306a36Sopenharmony_ci pdu_cb->pdulen = ntohs(cpl->len); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (pdu_cb->flags & PDUCBF_RX_HDR) 21162306a36Sopenharmony_ci pdu_cb->complete = true; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci lro_cb->pdu_totallen += pdu_cb->pdulen; 21462306a36Sopenharmony_ci lro_cb->complete = true; 21562306a36Sopenharmony_ci lro_cb->pdu_idx++; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void 21962306a36Sopenharmony_cicxgbit_copy_frags(struct sk_buff *skb, const struct pkt_gl *gl, 22062306a36Sopenharmony_ci unsigned int offset) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci u8 skb_frag_idx = skb_shinfo(skb)->nr_frags; 22362306a36Sopenharmony_ci u8 i; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* usually there's just one frag */ 22662306a36Sopenharmony_ci __skb_fill_page_desc(skb, skb_frag_idx, gl->frags[0].page, 22762306a36Sopenharmony_ci gl->frags[0].offset + offset, 22862306a36Sopenharmony_ci gl->frags[0].size - offset); 22962306a36Sopenharmony_ci for (i = 1; i < gl->nfrags; i++) 23062306a36Sopenharmony_ci __skb_fill_page_desc(skb, skb_frag_idx + i, 23162306a36Sopenharmony_ci gl->frags[i].page, 23262306a36Sopenharmony_ci gl->frags[i].offset, 23362306a36Sopenharmony_ci gl->frags[i].size); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci skb_shinfo(skb)->nr_frags += gl->nfrags; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* get a reference to the last page, we don't own it */ 23862306a36Sopenharmony_ci get_page(gl->frags[gl->nfrags - 1].page); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic void 24262306a36Sopenharmony_cicxgbit_lro_add_packet_gl(struct sk_buff *skb, u8 op, const struct pkt_gl *gl) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb); 24562306a36Sopenharmony_ci struct cxgbit_lro_pdu_cb *pdu_cb = cxgbit_skb_lro_pdu_cb(skb, 24662306a36Sopenharmony_ci lro_cb->pdu_idx); 24762306a36Sopenharmony_ci u32 len, offset; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (op == CPL_ISCSI_HDR) { 25062306a36Sopenharmony_ci struct cpl_iscsi_hdr *cpl = (struct cpl_iscsi_hdr *)gl->va; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci offset = sizeof(struct cpl_iscsi_hdr); 25362306a36Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_HDR; 25462306a36Sopenharmony_ci pdu_cb->seq = ntohl(cpl->seq); 25562306a36Sopenharmony_ci len = ntohs(cpl->len); 25662306a36Sopenharmony_ci pdu_cb->hdr = gl->va + offset; 25762306a36Sopenharmony_ci pdu_cb->hlen = len; 25862306a36Sopenharmony_ci pdu_cb->hfrag_idx = skb_shinfo(skb)->nr_frags; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (unlikely(gl->nfrags > 1)) 26162306a36Sopenharmony_ci cxgbit_skcb_flags(skb) = 0; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci lro_cb->complete = false; 26462306a36Sopenharmony_ci } else if (op == CPL_ISCSI_DATA) { 26562306a36Sopenharmony_ci struct cpl_iscsi_data *cpl = (struct cpl_iscsi_data *)gl->va; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci offset = sizeof(struct cpl_iscsi_data); 26862306a36Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_DATA; 26962306a36Sopenharmony_ci len = ntohs(cpl->len); 27062306a36Sopenharmony_ci pdu_cb->dlen = len; 27162306a36Sopenharmony_ci pdu_cb->doffset = lro_cb->offset; 27262306a36Sopenharmony_ci pdu_cb->nr_dfrags = gl->nfrags; 27362306a36Sopenharmony_ci pdu_cb->dfrag_idx = skb_shinfo(skb)->nr_frags; 27462306a36Sopenharmony_ci lro_cb->complete = false; 27562306a36Sopenharmony_ci } else { 27662306a36Sopenharmony_ci struct cpl_rx_iscsi_cmp *cpl; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci cpl = (struct cpl_rx_iscsi_cmp *)gl->va; 27962306a36Sopenharmony_ci offset = sizeof(struct cpl_rx_iscsi_cmp); 28062306a36Sopenharmony_ci pdu_cb->flags |= (PDUCBF_RX_HDR | PDUCBF_RX_STATUS); 28162306a36Sopenharmony_ci len = be16_to_cpu(cpl->len); 28262306a36Sopenharmony_ci pdu_cb->hdr = gl->va + offset; 28362306a36Sopenharmony_ci pdu_cb->hlen = len; 28462306a36Sopenharmony_ci pdu_cb->hfrag_idx = skb_shinfo(skb)->nr_frags; 28562306a36Sopenharmony_ci pdu_cb->ddigest = be32_to_cpu(cpl->ulp_crc); 28662306a36Sopenharmony_ci pdu_cb->pdulen = ntohs(cpl->len); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (unlikely(gl->nfrags > 1)) 28962306a36Sopenharmony_ci cxgbit_skcb_flags(skb) = 0; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci cxgbit_process_ddpvld(lro_cb->csk, pdu_cb, 29262306a36Sopenharmony_ci be32_to_cpu(cpl->ddpvld)); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (pdu_cb->flags & PDUCBF_RX_DATA_DDPD) { 29562306a36Sopenharmony_ci pdu_cb->flags |= PDUCBF_RX_DDP_CMP; 29662306a36Sopenharmony_ci pdu_cb->complete = true; 29762306a36Sopenharmony_ci } else if (pdu_cb->flags & PDUCBF_RX_DATA) { 29862306a36Sopenharmony_ci pdu_cb->complete = true; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci lro_cb->pdu_totallen += pdu_cb->hlen + pdu_cb->dlen; 30262306a36Sopenharmony_ci lro_cb->complete = true; 30362306a36Sopenharmony_ci lro_cb->pdu_idx++; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci cxgbit_copy_frags(skb, gl, offset); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci pdu_cb->frags += gl->nfrags; 30962306a36Sopenharmony_ci lro_cb->offset += len; 31062306a36Sopenharmony_ci skb->len += len; 31162306a36Sopenharmony_ci skb->data_len += len; 31262306a36Sopenharmony_ci skb->truesize += len; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic struct sk_buff * 31662306a36Sopenharmony_cicxgbit_lro_init_skb(struct cxgbit_sock *csk, u8 op, const struct pkt_gl *gl, 31762306a36Sopenharmony_ci const __be64 *rsp, struct napi_struct *napi) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct sk_buff *skb; 32062306a36Sopenharmony_ci struct cxgbit_lro_cb *lro_cb; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci skb = napi_alloc_skb(napi, LRO_SKB_MAX_HEADROOM); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (unlikely(!skb)) 32562306a36Sopenharmony_ci return NULL; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci memset(skb->data, 0, LRO_SKB_MAX_HEADROOM); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci cxgbit_skcb_flags(skb) |= SKCBF_RX_LRO; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci lro_cb = cxgbit_skb_lro_cb(skb); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci cxgbit_get_csk(csk); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci lro_cb->csk = csk; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return skb; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void cxgbit_queue_lro_skb(struct cxgbit_sock *csk, struct sk_buff *skb) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci bool wakeup_thread = false; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci spin_lock(&csk->rxq.lock); 34562306a36Sopenharmony_ci __skb_queue_tail(&csk->rxq, skb); 34662306a36Sopenharmony_ci if (skb_queue_len(&csk->rxq) == 1) 34762306a36Sopenharmony_ci wakeup_thread = true; 34862306a36Sopenharmony_ci spin_unlock(&csk->rxq.lock); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (wakeup_thread) 35162306a36Sopenharmony_ci wake_up(&csk->waitq); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic void cxgbit_lro_flush(struct t4_lro_mgr *lro_mgr, struct sk_buff *skb) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct cxgbit_lro_cb *lro_cb = cxgbit_skb_lro_cb(skb); 35762306a36Sopenharmony_ci struct cxgbit_sock *csk = lro_cb->csk; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci csk->lro_skb = NULL; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci __skb_unlink(skb, &lro_mgr->lroq); 36262306a36Sopenharmony_ci cxgbit_queue_lro_skb(csk, skb); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci cxgbit_put_csk(csk); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci lro_mgr->lro_pkts++; 36762306a36Sopenharmony_ci lro_mgr->lro_session_cnt--; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic void cxgbit_uld_lro_flush(struct t4_lro_mgr *lro_mgr) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct sk_buff *skb; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci while ((skb = skb_peek(&lro_mgr->lroq))) 37562306a36Sopenharmony_ci cxgbit_lro_flush(lro_mgr, skb); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic int 37962306a36Sopenharmony_cicxgbit_lro_receive(struct cxgbit_sock *csk, u8 op, const __be64 *rsp, 38062306a36Sopenharmony_ci const struct pkt_gl *gl, struct t4_lro_mgr *lro_mgr, 38162306a36Sopenharmony_ci struct napi_struct *napi) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct sk_buff *skb; 38462306a36Sopenharmony_ci struct cxgbit_lro_cb *lro_cb; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (!csk) { 38762306a36Sopenharmony_ci pr_err("%s: csk NULL, op 0x%x.\n", __func__, op); 38862306a36Sopenharmony_ci goto out; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (csk->lro_skb) 39262306a36Sopenharmony_ci goto add_packet; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistart_lro: 39562306a36Sopenharmony_ci if (lro_mgr->lro_session_cnt >= MAX_LRO_SESSIONS) { 39662306a36Sopenharmony_ci cxgbit_uld_lro_flush(lro_mgr); 39762306a36Sopenharmony_ci goto start_lro; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci skb = cxgbit_lro_init_skb(csk, op, gl, rsp, napi); 40162306a36Sopenharmony_ci if (unlikely(!skb)) 40262306a36Sopenharmony_ci goto out; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci csk->lro_skb = skb; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci __skb_queue_tail(&lro_mgr->lroq, skb); 40762306a36Sopenharmony_ci lro_mgr->lro_session_cnt++; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ciadd_packet: 41062306a36Sopenharmony_ci skb = csk->lro_skb; 41162306a36Sopenharmony_ci lro_cb = cxgbit_skb_lro_cb(skb); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if ((gl && (((skb_shinfo(skb)->nr_frags + gl->nfrags) > 41462306a36Sopenharmony_ci MAX_SKB_FRAGS) || (lro_cb->pdu_totallen >= LRO_FLUSH_LEN_MAX))) || 41562306a36Sopenharmony_ci (lro_cb->pdu_idx >= MAX_SKB_FRAGS)) { 41662306a36Sopenharmony_ci cxgbit_lro_flush(lro_mgr, skb); 41762306a36Sopenharmony_ci goto start_lro; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (gl) 42162306a36Sopenharmony_ci cxgbit_lro_add_packet_gl(skb, op, gl); 42262306a36Sopenharmony_ci else 42362306a36Sopenharmony_ci cxgbit_lro_add_packet_rsp(skb, op, rsp); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci lro_mgr->lro_merged++; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciout: 43062306a36Sopenharmony_ci return -1; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic int 43462306a36Sopenharmony_cicxgbit_uld_lro_rx_handler(void *hndl, const __be64 *rsp, 43562306a36Sopenharmony_ci const struct pkt_gl *gl, struct t4_lro_mgr *lro_mgr, 43662306a36Sopenharmony_ci struct napi_struct *napi) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct cxgbit_device *cdev = hndl; 43962306a36Sopenharmony_ci struct cxgb4_lld_info *lldi = &cdev->lldi; 44062306a36Sopenharmony_ci struct cpl_tx_data *rpl = NULL; 44162306a36Sopenharmony_ci struct cxgbit_sock *csk = NULL; 44262306a36Sopenharmony_ci unsigned int tid = 0; 44362306a36Sopenharmony_ci struct sk_buff *skb; 44462306a36Sopenharmony_ci unsigned int op = *(u8 *)rsp; 44562306a36Sopenharmony_ci bool lro_flush = true; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci switch (op) { 44862306a36Sopenharmony_ci case CPL_ISCSI_HDR: 44962306a36Sopenharmony_ci case CPL_ISCSI_DATA: 45062306a36Sopenharmony_ci case CPL_RX_ISCSI_CMP: 45162306a36Sopenharmony_ci case CPL_RX_ISCSI_DDP: 45262306a36Sopenharmony_ci case CPL_FW4_ACK: 45362306a36Sopenharmony_ci lro_flush = false; 45462306a36Sopenharmony_ci fallthrough; 45562306a36Sopenharmony_ci case CPL_ABORT_RPL_RSS: 45662306a36Sopenharmony_ci case CPL_PASS_ESTABLISH: 45762306a36Sopenharmony_ci case CPL_PEER_CLOSE: 45862306a36Sopenharmony_ci case CPL_CLOSE_CON_RPL: 45962306a36Sopenharmony_ci case CPL_ABORT_REQ_RSS: 46062306a36Sopenharmony_ci case CPL_SET_TCB_RPL: 46162306a36Sopenharmony_ci case CPL_RX_DATA: 46262306a36Sopenharmony_ci rpl = gl ? (struct cpl_tx_data *)gl->va : 46362306a36Sopenharmony_ci (struct cpl_tx_data *)(rsp + 1); 46462306a36Sopenharmony_ci tid = GET_TID(rpl); 46562306a36Sopenharmony_ci csk = lookup_tid(lldi->tids, tid); 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci default: 46862306a36Sopenharmony_ci break; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (csk && csk->lro_skb && lro_flush) 47262306a36Sopenharmony_ci cxgbit_lro_flush(lro_mgr, csk->lro_skb); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (!gl) { 47562306a36Sopenharmony_ci unsigned int len; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (op == CPL_RX_ISCSI_DDP) { 47862306a36Sopenharmony_ci if (!cxgbit_lro_receive(csk, op, rsp, NULL, lro_mgr, 47962306a36Sopenharmony_ci napi)) 48062306a36Sopenharmony_ci return 0; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci len = 64 - sizeof(struct rsp_ctrl) - 8; 48462306a36Sopenharmony_ci skb = napi_alloc_skb(napi, len); 48562306a36Sopenharmony_ci if (!skb) 48662306a36Sopenharmony_ci goto nomem; 48762306a36Sopenharmony_ci __skb_put(skb, len); 48862306a36Sopenharmony_ci skb_copy_to_linear_data(skb, &rsp[1], len); 48962306a36Sopenharmony_ci } else { 49062306a36Sopenharmony_ci if (unlikely(op != *(u8 *)gl->va)) { 49162306a36Sopenharmony_ci pr_info("? FL 0x%p,RSS%#llx,FL %#llx,len %u.\n", 49262306a36Sopenharmony_ci gl->va, be64_to_cpu(*rsp), 49362306a36Sopenharmony_ci get_unaligned_be64(gl->va), 49462306a36Sopenharmony_ci gl->tot_len); 49562306a36Sopenharmony_ci return 0; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if ((op == CPL_ISCSI_HDR) || (op == CPL_ISCSI_DATA) || 49962306a36Sopenharmony_ci (op == CPL_RX_ISCSI_CMP)) { 50062306a36Sopenharmony_ci if (!cxgbit_lro_receive(csk, op, rsp, gl, lro_mgr, 50162306a36Sopenharmony_ci napi)) 50262306a36Sopenharmony_ci return 0; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci#define RX_PULL_LEN 128 50662306a36Sopenharmony_ci skb = cxgb4_pktgl_to_skb(gl, RX_PULL_LEN, RX_PULL_LEN); 50762306a36Sopenharmony_ci if (unlikely(!skb)) 50862306a36Sopenharmony_ci goto nomem; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci rpl = (struct cpl_tx_data *)skb->data; 51262306a36Sopenharmony_ci op = rpl->ot.opcode; 51362306a36Sopenharmony_ci cxgbit_skcb_rx_opcode(skb) = op; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci pr_debug("cdev %p, opcode 0x%x(0x%x,0x%x), skb %p.\n", 51662306a36Sopenharmony_ci cdev, op, rpl->ot.opcode_tid, 51762306a36Sopenharmony_ci ntohl(rpl->ot.opcode_tid), skb); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (op < NUM_CPL_CMDS && cxgbit_cplhandlers[op]) { 52062306a36Sopenharmony_ci cxgbit_cplhandlers[op](cdev, skb); 52162306a36Sopenharmony_ci } else { 52262306a36Sopenharmony_ci pr_err("No handler for opcode 0x%x.\n", op); 52362306a36Sopenharmony_ci __kfree_skb(skb); 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci return 0; 52662306a36Sopenharmony_cinomem: 52762306a36Sopenharmony_ci pr_err("%s OOM bailing out.\n", __func__); 52862306a36Sopenharmony_ci return 1; 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 53262306a36Sopenharmony_cistruct cxgbit_dcb_work { 53362306a36Sopenharmony_ci struct dcb_app_type dcb_app; 53462306a36Sopenharmony_ci struct work_struct work; 53562306a36Sopenharmony_ci}; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic void 53862306a36Sopenharmony_cicxgbit_update_dcb_priority(struct cxgbit_device *cdev, u8 port_id, 53962306a36Sopenharmony_ci u8 dcb_priority, u16 port_num) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci struct cxgbit_sock *csk; 54262306a36Sopenharmony_ci struct sk_buff *skb; 54362306a36Sopenharmony_ci u16 local_port; 54462306a36Sopenharmony_ci bool wakeup_thread = false; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci spin_lock_bh(&cdev->cskq.lock); 54762306a36Sopenharmony_ci list_for_each_entry(csk, &cdev->cskq.list, list) { 54862306a36Sopenharmony_ci if (csk->port_id != port_id) 54962306a36Sopenharmony_ci continue; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (csk->com.local_addr.ss_family == AF_INET6) { 55262306a36Sopenharmony_ci struct sockaddr_in6 *sock_in6; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci sock_in6 = (struct sockaddr_in6 *)&csk->com.local_addr; 55562306a36Sopenharmony_ci local_port = ntohs(sock_in6->sin6_port); 55662306a36Sopenharmony_ci } else { 55762306a36Sopenharmony_ci struct sockaddr_in *sock_in; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci sock_in = (struct sockaddr_in *)&csk->com.local_addr; 56062306a36Sopenharmony_ci local_port = ntohs(sock_in->sin_port); 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (local_port != port_num) 56462306a36Sopenharmony_ci continue; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (csk->dcb_priority == dcb_priority) 56762306a36Sopenharmony_ci continue; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci skb = alloc_skb(0, GFP_ATOMIC); 57062306a36Sopenharmony_ci if (!skb) 57162306a36Sopenharmony_ci continue; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci spin_lock(&csk->rxq.lock); 57462306a36Sopenharmony_ci __skb_queue_tail(&csk->rxq, skb); 57562306a36Sopenharmony_ci if (skb_queue_len(&csk->rxq) == 1) 57662306a36Sopenharmony_ci wakeup_thread = true; 57762306a36Sopenharmony_ci spin_unlock(&csk->rxq.lock); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (wakeup_thread) { 58062306a36Sopenharmony_ci wake_up(&csk->waitq); 58162306a36Sopenharmony_ci wakeup_thread = false; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci spin_unlock_bh(&cdev->cskq.lock); 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic void cxgbit_dcb_workfn(struct work_struct *work) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct cxgbit_dcb_work *dcb_work; 59062306a36Sopenharmony_ci struct net_device *ndev; 59162306a36Sopenharmony_ci struct cxgbit_device *cdev = NULL; 59262306a36Sopenharmony_ci struct dcb_app_type *iscsi_app; 59362306a36Sopenharmony_ci u8 priority, port_id = 0xff; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci dcb_work = container_of(work, struct cxgbit_dcb_work, work); 59662306a36Sopenharmony_ci iscsi_app = &dcb_work->dcb_app; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) { 59962306a36Sopenharmony_ci if ((iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_STREAM) && 60062306a36Sopenharmony_ci (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)) 60162306a36Sopenharmony_ci goto out; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci priority = iscsi_app->app.priority; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci } else if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_CEE) { 60662306a36Sopenharmony_ci if (iscsi_app->app.selector != DCB_APP_IDTYPE_PORTNUM) 60762306a36Sopenharmony_ci goto out; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (!iscsi_app->app.priority) 61062306a36Sopenharmony_ci goto out; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci priority = ffs(iscsi_app->app.priority) - 1; 61362306a36Sopenharmony_ci } else { 61462306a36Sopenharmony_ci goto out; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci pr_debug("priority for ifid %d is %u\n", 61862306a36Sopenharmony_ci iscsi_app->ifindex, priority); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci ndev = dev_get_by_index(&init_net, iscsi_app->ifindex); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (!ndev) 62362306a36Sopenharmony_ci goto out; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci mutex_lock(&cdev_list_lock); 62662306a36Sopenharmony_ci cdev = cxgbit_find_device(ndev, &port_id); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci dev_put(ndev); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!cdev) { 63162306a36Sopenharmony_ci mutex_unlock(&cdev_list_lock); 63262306a36Sopenharmony_ci goto out; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci cxgbit_update_dcb_priority(cdev, port_id, priority, 63662306a36Sopenharmony_ci iscsi_app->app.protocol); 63762306a36Sopenharmony_ci mutex_unlock(&cdev_list_lock); 63862306a36Sopenharmony_ciout: 63962306a36Sopenharmony_ci kfree(dcb_work); 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic int 64362306a36Sopenharmony_cicxgbit_dcbevent_notify(struct notifier_block *nb, unsigned long action, 64462306a36Sopenharmony_ci void *data) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct cxgbit_dcb_work *dcb_work; 64762306a36Sopenharmony_ci struct dcb_app_type *dcb_app = data; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci dcb_work = kzalloc(sizeof(*dcb_work), GFP_ATOMIC); 65062306a36Sopenharmony_ci if (!dcb_work) 65162306a36Sopenharmony_ci return NOTIFY_DONE; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci dcb_work->dcb_app = *dcb_app; 65462306a36Sopenharmony_ci INIT_WORK(&dcb_work->work, cxgbit_dcb_workfn); 65562306a36Sopenharmony_ci schedule_work(&dcb_work->work); 65662306a36Sopenharmony_ci return NOTIFY_OK; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci#endif 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic enum target_prot_op cxgbit_get_sup_prot_ops(struct iscsit_conn *conn) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci return TARGET_PROT_NORMAL; 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic struct iscsit_transport cxgbit_transport = { 66662306a36Sopenharmony_ci .name = DRV_NAME, 66762306a36Sopenharmony_ci .transport_type = ISCSI_CXGBIT, 66862306a36Sopenharmony_ci .rdma_shutdown = false, 66962306a36Sopenharmony_ci .priv_size = sizeof(struct cxgbit_cmd), 67062306a36Sopenharmony_ci .owner = THIS_MODULE, 67162306a36Sopenharmony_ci .iscsit_setup_np = cxgbit_setup_np, 67262306a36Sopenharmony_ci .iscsit_accept_np = cxgbit_accept_np, 67362306a36Sopenharmony_ci .iscsit_free_np = cxgbit_free_np, 67462306a36Sopenharmony_ci .iscsit_free_conn = cxgbit_free_conn, 67562306a36Sopenharmony_ci .iscsit_get_login_rx = cxgbit_get_login_rx, 67662306a36Sopenharmony_ci .iscsit_put_login_tx = cxgbit_put_login_tx, 67762306a36Sopenharmony_ci .iscsit_immediate_queue = iscsit_immediate_queue, 67862306a36Sopenharmony_ci .iscsit_response_queue = iscsit_response_queue, 67962306a36Sopenharmony_ci .iscsit_get_dataout = iscsit_build_r2ts_for_cmd, 68062306a36Sopenharmony_ci .iscsit_queue_data_in = iscsit_queue_rsp, 68162306a36Sopenharmony_ci .iscsit_queue_status = iscsit_queue_rsp, 68262306a36Sopenharmony_ci .iscsit_xmit_pdu = cxgbit_xmit_pdu, 68362306a36Sopenharmony_ci .iscsit_get_r2t_ttt = cxgbit_get_r2t_ttt, 68462306a36Sopenharmony_ci .iscsit_get_rx_pdu = cxgbit_get_rx_pdu, 68562306a36Sopenharmony_ci .iscsit_validate_params = cxgbit_validate_params, 68662306a36Sopenharmony_ci .iscsit_unmap_cmd = cxgbit_unmap_cmd, 68762306a36Sopenharmony_ci .iscsit_aborted_task = iscsit_aborted_task, 68862306a36Sopenharmony_ci .iscsit_get_sup_prot_ops = cxgbit_get_sup_prot_ops, 68962306a36Sopenharmony_ci}; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic struct cxgb4_uld_info cxgbit_uld_info = { 69262306a36Sopenharmony_ci .name = DRV_NAME, 69362306a36Sopenharmony_ci .nrxq = MAX_ULD_QSETS, 69462306a36Sopenharmony_ci .ntxq = MAX_ULD_QSETS, 69562306a36Sopenharmony_ci .rxq_size = 1024, 69662306a36Sopenharmony_ci .lro = true, 69762306a36Sopenharmony_ci .add = cxgbit_uld_add, 69862306a36Sopenharmony_ci .state_change = cxgbit_uld_state_change, 69962306a36Sopenharmony_ci .lro_rx_handler = cxgbit_uld_lro_rx_handler, 70062306a36Sopenharmony_ci .lro_flush = cxgbit_uld_lro_flush, 70162306a36Sopenharmony_ci}; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 70462306a36Sopenharmony_cistatic struct notifier_block cxgbit_dcbevent_nb = { 70562306a36Sopenharmony_ci .notifier_call = cxgbit_dcbevent_notify, 70662306a36Sopenharmony_ci}; 70762306a36Sopenharmony_ci#endif 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic int __init cxgbit_init(void) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci cxgb4_register_uld(CXGB4_ULD_ISCSIT, &cxgbit_uld_info); 71262306a36Sopenharmony_ci iscsit_register_transport(&cxgbit_transport); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 71562306a36Sopenharmony_ci pr_info("%s dcb enabled.\n", DRV_NAME); 71662306a36Sopenharmony_ci register_dcbevent_notifier(&cxgbit_dcbevent_nb); 71762306a36Sopenharmony_ci#endif 71862306a36Sopenharmony_ci BUILD_BUG_ON(sizeof_field(struct sk_buff, cb) < 71962306a36Sopenharmony_ci sizeof(union cxgbit_skb_cb)); 72062306a36Sopenharmony_ci return 0; 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic void __exit cxgbit_exit(void) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci struct cxgbit_device *cdev, *tmp; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci#ifdef CONFIG_CHELSIO_T4_DCB 72862306a36Sopenharmony_ci unregister_dcbevent_notifier(&cxgbit_dcbevent_nb); 72962306a36Sopenharmony_ci#endif 73062306a36Sopenharmony_ci mutex_lock(&cdev_list_lock); 73162306a36Sopenharmony_ci list_for_each_entry_safe(cdev, tmp, &cdev_list_head, list) { 73262306a36Sopenharmony_ci list_del(&cdev->list); 73362306a36Sopenharmony_ci cxgbit_put_cdev(cdev); 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci mutex_unlock(&cdev_list_lock); 73662306a36Sopenharmony_ci iscsit_unregister_transport(&cxgbit_transport); 73762306a36Sopenharmony_ci cxgb4_unregister_uld(CXGB4_ULD_ISCSIT); 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cimodule_init(cxgbit_init); 74162306a36Sopenharmony_cimodule_exit(cxgbit_exit); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ciMODULE_DESCRIPTION("Chelsio iSCSI target offload driver"); 74462306a36Sopenharmony_ciMODULE_AUTHOR("Chelsio Communications"); 74562306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 74662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 747