···378378 via sysfs to userspace. If you wish to export this information,379379 say Y. Otherwise, say N.380380381381-source "drivers/scsi/cxgb3i/Kconfig"382381source "drivers/scsi/cxgbi/Kconfig"383382source "drivers/scsi/bnx2i/Kconfig"384383source "drivers/scsi/be2iscsi/Kconfig"
···11config SCSI_CXGB3_ISCSI22- tristate "Chelsio S3xx iSCSI support"22+ tristate "Chelsio T3 iSCSI support"33 depends on CHELSIO_T3_DEPENDS44 select CHELSIO_T355 select SCSI_ISCSI_ATTRS66 ---help---77- This driver supports iSCSI offload for the Chelsio S3 series devices.77+ This driver supports iSCSI offload for the Chelsio T3 devices.
-161
drivers/scsi/cxgb3i/cxgb3i.h
···11-/*22- * cxgb3i.h: Chelsio S3xx iSCSI driver.33- *44- * Copyright (c) 2008 Chelsio Communications, Inc.55- *66- * This program is free software; you can redistribute it and/or modify77- * it under the terms of the GNU General Public License as published by88- * the Free Software Foundation.99- *1010- * Written by: Karen Xie (kxie@chelsio.com)1111- */1212-1313-#ifndef __CXGB3I_H__1414-#define __CXGB3I_H__1515-1616-#include <linux/module.h>1717-#include <linux/moduleparam.h>1818-#include <linux/errno.h>1919-#include <linux/types.h>2020-#include <linux/list.h>2121-#include <linux/netdevice.h>2222-#include <linux/scatterlist.h>2323-#include <linux/skbuff.h>2424-#include <scsi/libiscsi_tcp.h>2525-2626-/* from cxgb3 LLD */2727-#include "common.h"2828-#include "t3_cpl.h"2929-#include "t3cdev.h"3030-#include "cxgb3_ctl_defs.h"3131-#include "cxgb3_offload.h"3232-#include "firmware_exports.h"3333-3434-#include "cxgb3i_offload.h"3535-#include "cxgb3i_ddp.h"3636-3737-#define CXGB3I_SCSI_HOST_QDEPTH 10243838-#define CXGB3I_MAX_TARGET CXGB3I_MAX_CONN3939-#define CXGB3I_MAX_LUN 5124040-#define ISCSI_PDU_NONPAYLOAD_MAX \4141- (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE + 2*ISCSI_DIGEST_SIZE)4242-4343-struct cxgb3i_adapter;4444-struct cxgb3i_hba;4545-struct cxgb3i_endpoint;4646-4747-/**4848- * struct cxgb3i_hba - cxgb3i iscsi structure (per port)4949- *5050- * @snic: cxgb3i adapter containing this port5151- * @ndev: pointer to netdev structure5252- * @shost: pointer to scsi host structure5353- */5454-struct cxgb3i_hba {5555- struct cxgb3i_adapter *snic;5656- struct net_device *ndev;5757- struct Scsi_Host *shost;5858-};5959-6060-/**6161- * struct cxgb3i_adapter - cxgb3i adapter structure (per pci)6262- *6363- * @listhead: list head to link elements6464- * @lock: lock for this structure6565- * @tdev: pointer to t3cdev used by cxgb3 driver6666- * @pdev: pointer to pci dev6767- * @hba_cnt: # of hbas (the same as # of ports)6868- * @hba: all the hbas on this adapter6969- * @flags: bit flag for adapter event/status7070- * @tx_max_size: max. tx packet size supported7171- * @rx_max_size: max. rx packet size supported7272- * @tag_format: ddp tag format settings7373- */7474-#define CXGB3I_ADAPTER_FLAG_RESET 0x17575-struct cxgb3i_adapter {7676- struct list_head list_head;7777- spinlock_t lock;7878- struct t3cdev *tdev;7979- struct pci_dev *pdev;8080- unsigned char hba_cnt;8181- struct cxgb3i_hba *hba[MAX_NPORTS];8282-8383- unsigned int flags;8484- unsigned int tx_max_size;8585- unsigned int rx_max_size;8686-8787- struct cxgb3i_tag_format tag_format;8888-};8989-9090-/**9191- * struct cxgb3i_conn - cxgb3i iscsi connection9292- *9393- * @listhead: list head to link elements9494- * @cep: pointer to iscsi_endpoint structure9595- * @conn: pointer to iscsi_conn structure9696- * @hba: pointer to the hba this conn. is going through9797- * @task_idx_bits: # of bits needed for session->cmds_max9898- */9999-struct cxgb3i_conn {100100- struct list_head list_head;101101- struct cxgb3i_endpoint *cep;102102- struct iscsi_conn *conn;103103- struct cxgb3i_hba *hba;104104- unsigned int task_idx_bits;105105-};106106-107107-/**108108- * struct cxgb3i_endpoint - iscsi tcp endpoint109109- *110110- * @c3cn: the h/w tcp connection representation111111- * @hba: pointer to the hba this conn. is going through112112- * @cconn: pointer to the associated cxgb3i iscsi connection113113- */114114-struct cxgb3i_endpoint {115115- struct s3_conn *c3cn;116116- struct cxgb3i_hba *hba;117117- struct cxgb3i_conn *cconn;118118-};119119-120120-/**121121- * struct cxgb3i_task_data - private iscsi task data122122- *123123- * @nr_frags: # of coalesced page frags (from scsi sgl)124124- * @frags: coalesced page frags (from scsi sgl)125125- * @skb: tx pdu skb126126- * @offset: data offset for the next pdu127127- * @count: max. possible pdu payload128128- * @sgoffset: offset to the first sg entry for a given offset129129- */130130-#define MAX_PDU_FRAGS ((ULP2_MAX_PDU_PAYLOAD + 512 - 1) / 512)131131-struct cxgb3i_task_data {132132- unsigned short nr_frags;133133- skb_frag_t frags[MAX_PDU_FRAGS];134134- struct sk_buff *skb;135135- unsigned int offset;136136- unsigned int count;137137- unsigned int sgoffset;138138-};139139-140140-int cxgb3i_iscsi_init(void);141141-void cxgb3i_iscsi_cleanup(void);142142-143143-struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *);144144-void cxgb3i_adapter_open(struct t3cdev *);145145-void cxgb3i_adapter_close(struct t3cdev *);146146-147147-struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *,148148- struct net_device *);149149-void cxgb3i_hba_host_remove(struct cxgb3i_hba *);150150-151151-int cxgb3i_pdu_init(void);152152-void cxgb3i_pdu_cleanup(void);153153-void cxgb3i_conn_cleanup_task(struct iscsi_task *);154154-int cxgb3i_conn_alloc_pdu(struct iscsi_task *, u8);155155-int cxgb3i_conn_init_pdu(struct iscsi_task *, unsigned int, unsigned int);156156-int cxgb3i_conn_xmit_pdu(struct iscsi_task *);157157-158158-void cxgb3i_release_itt(struct iscsi_task *task, itt_t hdr_itt);159159-int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt);160160-161161-#endif
-773
drivers/scsi/cxgb3i/cxgb3i_ddp.c
···11-/*22- * cxgb3i_ddp.c: Chelsio S3xx iSCSI DDP Manager.33- *44- * Copyright (c) 2008 Chelsio Communications, Inc.55- *66- * This program is free software; you can redistribute it and/or modify77- * it under the terms of the GNU General Public License as published by88- * the Free Software Foundation.99- *1010- * Written by: Karen Xie (kxie@chelsio.com)1111- */1212-1313-#include <linux/slab.h>1414-#include <linux/skbuff.h>1515-#include <linux/scatterlist.h>1616-1717-/* from cxgb3 LLD */1818-#include "common.h"1919-#include "t3_cpl.h"2020-#include "t3cdev.h"2121-#include "cxgb3_ctl_defs.h"2222-#include "cxgb3_offload.h"2323-#include "firmware_exports.h"2424-2525-#include "cxgb3i_ddp.h"2626-2727-#define ddp_log_error(fmt...) printk(KERN_ERR "cxgb3i_ddp: ERR! " fmt)2828-#define ddp_log_warn(fmt...) printk(KERN_WARNING "cxgb3i_ddp: WARN! " fmt)2929-#define ddp_log_info(fmt...) printk(KERN_INFO "cxgb3i_ddp: " fmt)3030-3131-#ifdef __DEBUG_CXGB3I_DDP__3232-#define ddp_log_debug(fmt, args...) \3333- printk(KERN_INFO "cxgb3i_ddp: %s - " fmt, __func__ , ## args)3434-#else3535-#define ddp_log_debug(fmt...)3636-#endif3737-3838-/*3939- * iSCSI Direct Data Placement4040- *4141- * T3 h/w can directly place the iSCSI Data-In or Data-Out PDU's payload into4242- * pre-posted final destination host-memory buffers based on the Initiator4343- * Task Tag (ITT) in Data-In or Target Task Tag (TTT) in Data-Out PDUs.4444- *4545- * The host memory address is programmed into h/w in the format of pagepod4646- * entries.4747- * The location of the pagepod entry is encoded into ddp tag which is used or4848- * is the base for ITT/TTT.4949- */5050-5151-#define DDP_PGIDX_MAX 45252-#define DDP_THRESHOLD 20485353-static unsigned char ddp_page_order[DDP_PGIDX_MAX] = {0, 1, 2, 4};5454-static unsigned char ddp_page_shift[DDP_PGIDX_MAX] = {12, 13, 14, 16};5555-static unsigned char page_idx = DDP_PGIDX_MAX;5656-5757-/*5858- * functions to program the pagepod in h/w5959- */6060-static inline void ulp_mem_io_set_hdr(struct sk_buff *skb, unsigned int addr)6161-{6262- struct ulp_mem_io *req = (struct ulp_mem_io *)skb->head;6363-6464- req->wr.wr_lo = 0;6565- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_BYPASS));6666- req->cmd_lock_addr = htonl(V_ULP_MEMIO_ADDR(addr >> 5) |6767- V_ULPTX_CMD(ULP_MEM_WRITE));6868- req->len = htonl(V_ULP_MEMIO_DATA_LEN(PPOD_SIZE >> 5) |6969- V_ULPTX_NFLITS((PPOD_SIZE >> 3) + 1));7070-}7171-7272-static int set_ddp_map(struct cxgb3i_ddp_info *ddp, struct pagepod_hdr *hdr,7373- unsigned int idx, unsigned int npods,7474- struct cxgb3i_gather_list *gl)7575-{7676- unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit;7777- int i;7878-7979- for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) {8080- struct sk_buff *skb = ddp->gl_skb[idx];8181- struct pagepod *ppod;8282- int j, pidx;8383-8484- /* hold on to the skb until we clear the ddp mapping */8585- skb_get(skb);8686-8787- ulp_mem_io_set_hdr(skb, pm_addr);8888- ppod = (struct pagepod *)8989- (skb->head + sizeof(struct ulp_mem_io));9090- memcpy(&(ppod->hdr), hdr, sizeof(struct pagepod));9191- for (pidx = 4 * i, j = 0; j < 5; ++j, ++pidx)9292- ppod->addr[j] = pidx < gl->nelem ?9393- cpu_to_be64(gl->phys_addr[pidx]) : 0UL;9494-9595- skb->priority = CPL_PRIORITY_CONTROL;9696- cxgb3_ofld_send(ddp->tdev, skb);9797- }9898- return 0;9999-}100100-101101-static void clear_ddp_map(struct cxgb3i_ddp_info *ddp, unsigned int tag,102102- unsigned int idx, unsigned int npods)103103-{104104- unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit;105105- int i;106106-107107- for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) {108108- struct sk_buff *skb = ddp->gl_skb[idx];109109-110110- if (!skb) {111111- ddp_log_error("ddp tag 0x%x, 0x%x, %d/%u, skb NULL.\n",112112- tag, idx, i, npods);113113- continue;114114- }115115- ddp->gl_skb[idx] = NULL;116116- memset((skb->head + sizeof(struct ulp_mem_io)), 0, PPOD_SIZE);117117- ulp_mem_io_set_hdr(skb, pm_addr);118118- skb->priority = CPL_PRIORITY_CONTROL;119119- cxgb3_ofld_send(ddp->tdev, skb);120120- }121121-}122122-123123-static inline int ddp_find_unused_entries(struct cxgb3i_ddp_info *ddp,124124- unsigned int start, unsigned int max,125125- unsigned int count,126126- struct cxgb3i_gather_list *gl)127127-{128128- unsigned int i, j, k;129129-130130- /* not enough entries */131131- if ((max - start) < count)132132- return -EBUSY;133133-134134- max -= count;135135- spin_lock(&ddp->map_lock);136136- for (i = start; i < max;) {137137- for (j = 0, k = i; j < count; j++, k++) {138138- if (ddp->gl_map[k])139139- break;140140- }141141- if (j == count) {142142- for (j = 0, k = i; j < count; j++, k++)143143- ddp->gl_map[k] = gl;144144- spin_unlock(&ddp->map_lock);145145- return i;146146- }147147- i += j + 1;148148- }149149- spin_unlock(&ddp->map_lock);150150- return -EBUSY;151151-}152152-153153-static inline void ddp_unmark_entries(struct cxgb3i_ddp_info *ddp,154154- int start, int count)155155-{156156- spin_lock(&ddp->map_lock);157157- memset(&ddp->gl_map[start], 0,158158- count * sizeof(struct cxgb3i_gather_list *));159159- spin_unlock(&ddp->map_lock);160160-}161161-162162-static inline void ddp_free_gl_skb(struct cxgb3i_ddp_info *ddp,163163- int idx, int count)164164-{165165- int i;166166-167167- for (i = 0; i < count; i++, idx++)168168- if (ddp->gl_skb[idx]) {169169- kfree_skb(ddp->gl_skb[idx]);170170- ddp->gl_skb[idx] = NULL;171171- }172172-}173173-174174-static inline int ddp_alloc_gl_skb(struct cxgb3i_ddp_info *ddp, int idx,175175- int count, gfp_t gfp)176176-{177177- int i;178178-179179- for (i = 0; i < count; i++) {180180- struct sk_buff *skb = alloc_skb(sizeof(struct ulp_mem_io) +181181- PPOD_SIZE, gfp);182182- if (skb) {183183- ddp->gl_skb[idx + i] = skb;184184- skb_put(skb, sizeof(struct ulp_mem_io) + PPOD_SIZE);185185- } else {186186- ddp_free_gl_skb(ddp, idx, i);187187- return -ENOMEM;188188- }189189- }190190- return 0;191191-}192192-193193-/**194194- * cxgb3i_ddp_find_page_index - return ddp page index for a given page size195195- * @pgsz: page size196196- * return the ddp page index, if no match is found return DDP_PGIDX_MAX.197197- */198198-int cxgb3i_ddp_find_page_index(unsigned long pgsz)199199-{200200- int i;201201-202202- for (i = 0; i < DDP_PGIDX_MAX; i++) {203203- if (pgsz == (1UL << ddp_page_shift[i]))204204- return i;205205- }206206- ddp_log_debug("ddp page size 0x%lx not supported.\n", pgsz);207207- return DDP_PGIDX_MAX;208208-}209209-210210-/**211211- * cxgb3i_ddp_adjust_page_table - adjust page table with PAGE_SIZE212212- * return the ddp page index, if no match is found return DDP_PGIDX_MAX.213213- */214214-int cxgb3i_ddp_adjust_page_table(void)215215-{216216- int i;217217- unsigned int base_order, order;218218-219219- if (PAGE_SIZE < (1UL << ddp_page_shift[0])) {220220- ddp_log_info("PAGE_SIZE 0x%lx too small, min. 0x%lx.\n",221221- PAGE_SIZE, 1UL << ddp_page_shift[0]);222222- return -EINVAL;223223- }224224-225225- base_order = get_order(1UL << ddp_page_shift[0]);226226- order = get_order(1 << PAGE_SHIFT);227227- for (i = 0; i < DDP_PGIDX_MAX; i++) {228228- /* first is the kernel page size, then just doubling the size */229229- ddp_page_order[i] = order - base_order + i;230230- ddp_page_shift[i] = PAGE_SHIFT + i;231231- }232232- return 0;233233-}234234-235235-static inline void ddp_gl_unmap(struct pci_dev *pdev,236236- struct cxgb3i_gather_list *gl)237237-{238238- int i;239239-240240- for (i = 0; i < gl->nelem; i++)241241- pci_unmap_page(pdev, gl->phys_addr[i], PAGE_SIZE,242242- PCI_DMA_FROMDEVICE);243243-}244244-245245-static inline int ddp_gl_map(struct pci_dev *pdev,246246- struct cxgb3i_gather_list *gl)247247-{248248- int i;249249-250250- for (i = 0; i < gl->nelem; i++) {251251- gl->phys_addr[i] = pci_map_page(pdev, gl->pages[i], 0,252252- PAGE_SIZE,253253- PCI_DMA_FROMDEVICE);254254- if (unlikely(pci_dma_mapping_error(pdev, gl->phys_addr[i])))255255- goto unmap;256256- }257257-258258- return i;259259-260260-unmap:261261- if (i) {262262- unsigned int nelem = gl->nelem;263263-264264- gl->nelem = i;265265- ddp_gl_unmap(pdev, gl);266266- gl->nelem = nelem;267267- }268268- return -ENOMEM;269269-}270270-271271-/**272272- * cxgb3i_ddp_make_gl - build ddp page buffer list273273- * @xferlen: total buffer length274274- * @sgl: page buffer scatter-gather list275275- * @sgcnt: # of page buffers276276- * @pdev: pci_dev, used for pci map277277- * @gfp: allocation mode278278- *279279- * construct a ddp page buffer list from the scsi scattergather list.280280- * coalesce buffers as much as possible, and obtain dma addresses for281281- * each page.282282- *283283- * Return the cxgb3i_gather_list constructed from the page buffers if the284284- * memory can be used for ddp. Return NULL otherwise.285285- */286286-struct cxgb3i_gather_list *cxgb3i_ddp_make_gl(unsigned int xferlen,287287- struct scatterlist *sgl,288288- unsigned int sgcnt,289289- struct pci_dev *pdev,290290- gfp_t gfp)291291-{292292- struct cxgb3i_gather_list *gl;293293- struct scatterlist *sg = sgl;294294- struct page *sgpage = sg_page(sg);295295- unsigned int sglen = sg->length;296296- unsigned int sgoffset = sg->offset;297297- unsigned int npages = (xferlen + sgoffset + PAGE_SIZE - 1) >>298298- PAGE_SHIFT;299299- int i = 1, j = 0;300300-301301- if (xferlen < DDP_THRESHOLD) {302302- ddp_log_debug("xfer %u < threshold %u, no ddp.\n",303303- xferlen, DDP_THRESHOLD);304304- return NULL;305305- }306306-307307- gl = kzalloc(sizeof(struct cxgb3i_gather_list) +308308- npages * (sizeof(dma_addr_t) + sizeof(struct page *)),309309- gfp);310310- if (!gl)311311- return NULL;312312-313313- gl->pages = (struct page **)&gl->phys_addr[npages];314314- gl->length = xferlen;315315- gl->offset = sgoffset;316316- gl->pages[0] = sgpage;317317-318318- sg = sg_next(sg);319319- while (sg) {320320- struct page *page = sg_page(sg);321321-322322- if (sgpage == page && sg->offset == sgoffset + sglen)323323- sglen += sg->length;324324- else {325325- /* make sure the sgl is fit for ddp:326326- * each has the same page size, and327327- * all of the middle pages are used completely328328- */329329- if ((j && sgoffset) ||330330- ((i != sgcnt - 1) &&331331- ((sglen + sgoffset) & ~PAGE_MASK)))332332- goto error_out;333333-334334- j++;335335- if (j == gl->nelem || sg->offset)336336- goto error_out;337337- gl->pages[j] = page;338338- sglen = sg->length;339339- sgoffset = sg->offset;340340- sgpage = page;341341- }342342- i++;343343- sg = sg_next(sg);344344- }345345- gl->nelem = ++j;346346-347347- if (ddp_gl_map(pdev, gl) < 0)348348- goto error_out;349349-350350- return gl;351351-352352-error_out:353353- kfree(gl);354354- return NULL;355355-}356356-357357-/**358358- * cxgb3i_ddp_release_gl - release a page buffer list359359- * @gl: a ddp page buffer list360360- * @pdev: pci_dev used for pci_unmap361361- * free a ddp page buffer list resulted from cxgb3i_ddp_make_gl().362362- */363363-void cxgb3i_ddp_release_gl(struct cxgb3i_gather_list *gl,364364- struct pci_dev *pdev)365365-{366366- ddp_gl_unmap(pdev, gl);367367- kfree(gl);368368-}369369-370370-/**371371- * cxgb3i_ddp_tag_reserve - set up ddp for a data transfer372372- * @tdev: t3cdev adapter373373- * @tid: connection id374374- * @tformat: tag format375375- * @tagp: contains s/w tag initially, will be updated with ddp/hw tag376376- * @gl: the page momory list377377- * @gfp: allocation mode378378- *379379- * ddp setup for a given page buffer list and construct the ddp tag.380380- * return 0 if success, < 0 otherwise.381381- */382382-int cxgb3i_ddp_tag_reserve(struct t3cdev *tdev, unsigned int tid,383383- struct cxgb3i_tag_format *tformat, u32 *tagp,384384- struct cxgb3i_gather_list *gl, gfp_t gfp)385385-{386386- struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi;387387- struct pagepod_hdr hdr;388388- unsigned int npods;389389- int idx = -1;390390- int err = -ENOMEM;391391- u32 sw_tag = *tagp;392392- u32 tag;393393-394394- if (page_idx >= DDP_PGIDX_MAX || !ddp || !gl || !gl->nelem ||395395- gl->length < DDP_THRESHOLD) {396396- ddp_log_debug("pgidx %u, xfer %u/%u, NO ddp.\n",397397- page_idx, gl->length, DDP_THRESHOLD);398398- return -EINVAL;399399- }400400-401401- npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT;402402-403403- if (ddp->idx_last == ddp->nppods)404404- idx = ddp_find_unused_entries(ddp, 0, ddp->nppods, npods, gl);405405- else {406406- idx = ddp_find_unused_entries(ddp, ddp->idx_last + 1,407407- ddp->nppods, npods, gl);408408- if (idx < 0 && ddp->idx_last >= npods) {409409- idx = ddp_find_unused_entries(ddp, 0,410410- min(ddp->idx_last + npods, ddp->nppods),411411- npods, gl);412412- }413413- }414414- if (idx < 0) {415415- ddp_log_debug("xferlen %u, gl %u, npods %u NO DDP.\n",416416- gl->length, gl->nelem, npods);417417- return idx;418418- }419419-420420- err = ddp_alloc_gl_skb(ddp, idx, npods, gfp);421421- if (err < 0)422422- goto unmark_entries;423423-424424- tag = cxgb3i_ddp_tag_base(tformat, sw_tag);425425- tag |= idx << PPOD_IDX_SHIFT;426426-427427- hdr.rsvd = 0;428428- hdr.vld_tid = htonl(F_PPOD_VALID | V_PPOD_TID(tid));429429- hdr.pgsz_tag_clr = htonl(tag & ddp->rsvd_tag_mask);430430- hdr.maxoffset = htonl(gl->length);431431- hdr.pgoffset = htonl(gl->offset);432432-433433- err = set_ddp_map(ddp, &hdr, idx, npods, gl);434434- if (err < 0)435435- goto free_gl_skb;436436-437437- ddp->idx_last = idx;438438- ddp_log_debug("xfer %u, gl %u,%u, tid 0x%x, 0x%x -> 0x%x(%u,%u).\n",439439- gl->length, gl->nelem, gl->offset, tid, sw_tag, tag,440440- idx, npods);441441- *tagp = tag;442442- return 0;443443-444444-free_gl_skb:445445- ddp_free_gl_skb(ddp, idx, npods);446446-unmark_entries:447447- ddp_unmark_entries(ddp, idx, npods);448448- return err;449449-}450450-451451-/**452452- * cxgb3i_ddp_tag_release - release a ddp tag453453- * @tdev: t3cdev adapter454454- * @tag: ddp tag455455- * ddp cleanup for a given ddp tag and release all the resources held456456- */457457-void cxgb3i_ddp_tag_release(struct t3cdev *tdev, u32 tag)458458-{459459- struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi;460460- u32 idx;461461-462462- if (!ddp) {463463- ddp_log_error("release ddp tag 0x%x, ddp NULL.\n", tag);464464- return;465465- }466466-467467- idx = (tag >> PPOD_IDX_SHIFT) & ddp->idx_mask;468468- if (idx < ddp->nppods) {469469- struct cxgb3i_gather_list *gl = ddp->gl_map[idx];470470- unsigned int npods;471471-472472- if (!gl || !gl->nelem) {473473- ddp_log_error("release 0x%x, idx 0x%x, gl 0x%p, %u.\n",474474- tag, idx, gl, gl ? gl->nelem : 0);475475- return;476476- }477477- npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT;478478- ddp_log_debug("ddp tag 0x%x, release idx 0x%x, npods %u.\n",479479- tag, idx, npods);480480- clear_ddp_map(ddp, tag, idx, npods);481481- ddp_unmark_entries(ddp, idx, npods);482482- cxgb3i_ddp_release_gl(gl, ddp->pdev);483483- } else484484- ddp_log_error("ddp tag 0x%x, idx 0x%x > max 0x%x.\n",485485- tag, idx, ddp->nppods);486486-}487487-488488-static int setup_conn_pgidx(struct t3cdev *tdev, unsigned int tid, int pg_idx,489489- int reply)490490-{491491- struct sk_buff *skb = alloc_skb(sizeof(struct cpl_set_tcb_field),492492- GFP_KERNEL);493493- struct cpl_set_tcb_field *req;494494- u64 val = pg_idx < DDP_PGIDX_MAX ? pg_idx : 0;495495-496496- if (!skb)497497- return -ENOMEM;498498-499499- /* set up ulp submode and page size */500500- req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));501501- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));502502- req->wr.wr_lo = 0;503503- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));504504- req->reply = V_NO_REPLY(reply ? 0 : 1);505505- req->cpu_idx = 0;506506- req->word = htons(31);507507- req->mask = cpu_to_be64(0xF0000000);508508- req->val = cpu_to_be64(val << 28);509509- skb->priority = CPL_PRIORITY_CONTROL;510510-511511- cxgb3_ofld_send(tdev, skb);512512- return 0;513513-}514514-515515-/**516516- * cxgb3i_setup_conn_host_pagesize - setup the conn.'s ddp page size517517- * @tdev: t3cdev adapter518518- * @tid: connection id519519- * @reply: request reply from h/w520520- * set up the ddp page size based on the host PAGE_SIZE for a connection521521- * identified by tid522522- */523523-int cxgb3i_setup_conn_host_pagesize(struct t3cdev *tdev, unsigned int tid,524524- int reply)525525-{526526- return setup_conn_pgidx(tdev, tid, page_idx, reply);527527-}528528-529529-/**530530- * cxgb3i_setup_conn_pagesize - setup the conn.'s ddp page size531531- * @tdev: t3cdev adapter532532- * @tid: connection id533533- * @reply: request reply from h/w534534- * @pgsz: ddp page size535535- * set up the ddp page size for a connection identified by tid536536- */537537-int cxgb3i_setup_conn_pagesize(struct t3cdev *tdev, unsigned int tid,538538- int reply, unsigned long pgsz)539539-{540540- int pgidx = cxgb3i_ddp_find_page_index(pgsz);541541-542542- return setup_conn_pgidx(tdev, tid, pgidx, reply);543543-}544544-545545-/**546546- * cxgb3i_setup_conn_digest - setup conn. digest setting547547- * @tdev: t3cdev adapter548548- * @tid: connection id549549- * @hcrc: header digest enabled550550- * @dcrc: data digest enabled551551- * @reply: request reply from h/w552552- * set up the iscsi digest settings for a connection identified by tid553553- */554554-int cxgb3i_setup_conn_digest(struct t3cdev *tdev, unsigned int tid,555555- int hcrc, int dcrc, int reply)556556-{557557- struct sk_buff *skb = alloc_skb(sizeof(struct cpl_set_tcb_field),558558- GFP_KERNEL);559559- struct cpl_set_tcb_field *req;560560- u64 val = (hcrc ? 1 : 0) | (dcrc ? 2 : 0);561561-562562- if (!skb)563563- return -ENOMEM;564564-565565- /* set up ulp submode and page size */566566- req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));567567- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));568568- req->wr.wr_lo = 0;569569- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));570570- req->reply = V_NO_REPLY(reply ? 0 : 1);571571- req->cpu_idx = 0;572572- req->word = htons(31);573573- req->mask = cpu_to_be64(0x0F000000);574574- req->val = cpu_to_be64(val << 24);575575- skb->priority = CPL_PRIORITY_CONTROL;576576-577577- cxgb3_ofld_send(tdev, skb);578578- return 0;579579-}580580-581581-582582-/**583583- * cxgb3i_adapter_ddp_info - read the adapter's ddp information584584- * @tdev: t3cdev adapter585585- * @tformat: tag format586586- * @txsz: max tx pdu payload size, filled in by this func.587587- * @rxsz: max rx pdu payload size, filled in by this func.588588- * setup the tag format for a given iscsi entity589589- */590590-int cxgb3i_adapter_ddp_info(struct t3cdev *tdev,591591- struct cxgb3i_tag_format *tformat,592592- unsigned int *txsz, unsigned int *rxsz)593593-{594594- struct cxgb3i_ddp_info *ddp;595595- unsigned char idx_bits;596596-597597- if (!tformat)598598- return -EINVAL;599599-600600- if (!tdev->ulp_iscsi)601601- return -EINVAL;602602-603603- ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi;604604-605605- idx_bits = 32 - tformat->sw_bits;606606- tformat->rsvd_bits = ddp->idx_bits;607607- tformat->rsvd_shift = PPOD_IDX_SHIFT;608608- tformat->rsvd_mask = (1 << tformat->rsvd_bits) - 1;609609-610610- ddp_log_info("tag format: sw %u, rsvd %u,%u, mask 0x%x.\n",611611- tformat->sw_bits, tformat->rsvd_bits,612612- tformat->rsvd_shift, tformat->rsvd_mask);613613-614614- *txsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,615615- ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN);616616- *rxsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,617617- ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN);618618- ddp_log_info("max payload size: %u/%u, %u/%u.\n",619619- *txsz, ddp->max_txsz, *rxsz, ddp->max_rxsz);620620- return 0;621621-}622622-623623-/**624624- * cxgb3i_ddp_cleanup - release the cxgb3 adapter's ddp resource625625- * @tdev: t3cdev adapter626626- * release all the resource held by the ddp pagepod manager for a given627627- * adapter if needed628628- */629629-630630-static void ddp_cleanup(struct kref *kref)631631-{632632- struct cxgb3i_ddp_info *ddp = container_of(kref,633633- struct cxgb3i_ddp_info,634634- refcnt);635635- int i = 0;636636-637637- ddp_log_info("kref release ddp 0x%p, t3dev 0x%p.\n", ddp, ddp->tdev);638638-639639- ddp->tdev->ulp_iscsi = NULL;640640- while (i < ddp->nppods) {641641- struct cxgb3i_gather_list *gl = ddp->gl_map[i];642642- if (gl) {643643- int npods = (gl->nelem + PPOD_PAGES_MAX - 1)644644- >> PPOD_PAGES_SHIFT;645645- ddp_log_info("t3dev 0x%p, ddp %d + %d.\n",646646- ddp->tdev, i, npods);647647- kfree(gl);648648- ddp_free_gl_skb(ddp, i, npods);649649- i += npods;650650- } else651651- i++;652652- }653653- cxgb3i_free_big_mem(ddp);654654-}655655-656656-void cxgb3i_ddp_cleanup(struct t3cdev *tdev)657657-{658658- struct cxgb3i_ddp_info *ddp = (struct cxgb3i_ddp_info *)tdev->ulp_iscsi;659659-660660- ddp_log_info("t3dev 0x%p, release ddp 0x%p.\n", tdev, ddp);661661- if (ddp)662662- kref_put(&ddp->refcnt, ddp_cleanup);663663-}664664-665665-/**666666- * ddp_init - initialize the cxgb3 adapter's ddp resource667667- * @tdev: t3cdev adapter668668- * initialize the ddp pagepod manager for a given adapter669669- */670670-static void ddp_init(struct t3cdev *tdev)671671-{672672- struct cxgb3i_ddp_info *ddp = tdev->ulp_iscsi;673673- struct ulp_iscsi_info uinfo;674674- unsigned int ppmax, bits;675675- int i, err;676676-677677- if (ddp) {678678- kref_get(&ddp->refcnt);679679- ddp_log_warn("t3dev 0x%p, ddp 0x%p already set up.\n",680680- tdev, tdev->ulp_iscsi);681681- return;682682- }683683-684684- err = tdev->ctl(tdev, ULP_ISCSI_GET_PARAMS, &uinfo);685685- if (err < 0) {686686- ddp_log_error("%s, failed to get iscsi param err=%d.\n",687687- tdev->name, err);688688- return;689689- }690690-691691- ppmax = (uinfo.ulimit - uinfo.llimit + 1) >> PPOD_SIZE_SHIFT;692692- bits = __ilog2_u32(ppmax) + 1;693693- if (bits > PPOD_IDX_MAX_SIZE)694694- bits = PPOD_IDX_MAX_SIZE;695695- ppmax = (1 << (bits - 1)) - 1;696696-697697- ddp = cxgb3i_alloc_big_mem(sizeof(struct cxgb3i_ddp_info) +698698- ppmax *699699- (sizeof(struct cxgb3i_gather_list *) +700700- sizeof(struct sk_buff *)),701701- GFP_KERNEL);702702- if (!ddp) {703703- ddp_log_warn("%s unable to alloc ddp 0x%d, ddp disabled.\n",704704- tdev->name, ppmax);705705- return;706706- }707707- ddp->gl_map = (struct cxgb3i_gather_list **)(ddp + 1);708708- ddp->gl_skb = (struct sk_buff **)(((char *)ddp->gl_map) +709709- ppmax *710710- sizeof(struct cxgb3i_gather_list *));711711- spin_lock_init(&ddp->map_lock);712712- kref_init(&ddp->refcnt);713713-714714- ddp->tdev = tdev;715715- ddp->pdev = uinfo.pdev;716716- ddp->max_txsz = min_t(unsigned int, uinfo.max_txsz, ULP2_MAX_PKT_SIZE);717717- ddp->max_rxsz = min_t(unsigned int, uinfo.max_rxsz, ULP2_MAX_PKT_SIZE);718718- ddp->llimit = uinfo.llimit;719719- ddp->ulimit = uinfo.ulimit;720720- ddp->nppods = ppmax;721721- ddp->idx_last = ppmax;722722- ddp->idx_bits = bits;723723- ddp->idx_mask = (1 << bits) - 1;724724- ddp->rsvd_tag_mask = (1 << (bits + PPOD_IDX_SHIFT)) - 1;725725-726726- uinfo.tagmask = ddp->idx_mask << PPOD_IDX_SHIFT;727727- for (i = 0; i < DDP_PGIDX_MAX; i++)728728- uinfo.pgsz_factor[i] = ddp_page_order[i];729729- uinfo.ulimit = uinfo.llimit + (ppmax << PPOD_SIZE_SHIFT);730730-731731- err = tdev->ctl(tdev, ULP_ISCSI_SET_PARAMS, &uinfo);732732- if (err < 0) {733733- ddp_log_warn("%s unable to set iscsi param err=%d, "734734- "ddp disabled.\n", tdev->name, err);735735- goto free_ddp_map;736736- }737737-738738- tdev->ulp_iscsi = ddp;739739-740740- ddp_log_info("tdev 0x%p, nppods %u, bits %u, mask 0x%x,0x%x pkt %u/%u,"741741- " %u/%u.\n",742742- tdev, ppmax, ddp->idx_bits, ddp->idx_mask,743743- ddp->rsvd_tag_mask, ddp->max_txsz, uinfo.max_txsz,744744- ddp->max_rxsz, uinfo.max_rxsz);745745- return;746746-747747-free_ddp_map:748748- cxgb3i_free_big_mem(ddp);749749-}750750-751751-/**752752- * cxgb3i_ddp_init - initialize ddp functions753753- */754754-void cxgb3i_ddp_init(struct t3cdev *tdev)755755-{756756- if (page_idx == DDP_PGIDX_MAX) {757757- page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE);758758-759759- if (page_idx == DDP_PGIDX_MAX) {760760- ddp_log_info("system PAGE_SIZE %lu, update hw.\n",761761- PAGE_SIZE);762762- if (cxgb3i_ddp_adjust_page_table() < 0) {763763- ddp_log_info("PAGE_SIZE %lu, ddp disabled.\n",764764- PAGE_SIZE);765765- return;766766- }767767- page_idx = cxgb3i_ddp_find_page_index(PAGE_SIZE);768768- }769769- ddp_log_info("system PAGE_SIZE %lu, ddp idx %u.\n",770770- PAGE_SIZE, page_idx);771771- }772772- ddp_init(tdev);773773-}
-312
drivers/scsi/cxgb3i/cxgb3i_ddp.h
···11-/*22- * cxgb3i_ddp.h: Chelsio S3xx iSCSI DDP Manager.33- *44- * Copyright (c) 2008 Chelsio Communications, Inc.55- *66- * This program is free software; you can redistribute it and/or modify77- * it under the terms of the GNU General Public License as published by88- * the Free Software Foundation.99- *1010- * Written by: Karen Xie (kxie@chelsio.com)1111- */1212-1313-#ifndef __CXGB3I_ULP2_DDP_H__1414-#define __CXGB3I_ULP2_DDP_H__1515-1616-#include <linux/slab.h>1717-#include <linux/vmalloc.h>1818-1919-/**2020- * struct cxgb3i_tag_format - cxgb3i ulp tag format for an iscsi entity2121- *2222- * @sw_bits: # of bits used by iscsi software layer2323- * @rsvd_bits: # of bits used by h/w2424- * @rsvd_shift: h/w bits shift left2525- * @rsvd_mask: reserved bit mask2626- */2727-struct cxgb3i_tag_format {2828- unsigned char sw_bits;2929- unsigned char rsvd_bits;3030- unsigned char rsvd_shift;3131- unsigned char filler[1];3232- u32 rsvd_mask;3333-};3434-3535-/**3636- * struct cxgb3i_gather_list - cxgb3i direct data placement memory3737- *3838- * @tag: ddp tag3939- * @length: total data buffer length4040- * @offset: initial offset to the 1st page4141- * @nelem: # of pages4242- * @pages: page pointers4343- * @phys_addr: physical address4444- */4545-struct cxgb3i_gather_list {4646- u32 tag;4747- unsigned int length;4848- unsigned int offset;4949- unsigned int nelem;5050- struct page **pages;5151- dma_addr_t phys_addr[0];5252-};5353-5454-/**5555- * struct cxgb3i_ddp_info - cxgb3i direct data placement for pdu payload5656- *5757- * @list: list head to link elements5858- * @refcnt: ref. count5959- * @tdev: pointer to t3cdev used by cxgb3 driver6060- * @max_txsz: max tx packet size for ddp6161- * @max_rxsz: max rx packet size for ddp6262- * @llimit: lower bound of the page pod memory6363- * @ulimit: upper bound of the page pod memory6464- * @nppods: # of page pod entries6565- * @idx_last: page pod entry last used6666- * @idx_bits: # of bits the pagepod index would take6767- * @idx_mask: pagepod index mask6868- * @rsvd_tag_mask: tag mask6969- * @map_lock: lock to synchonize access to the page pod map7070- * @gl_map: ddp memory gather list7171- * @gl_skb: skb used to program the pagepod7272- */7373-struct cxgb3i_ddp_info {7474- struct list_head list;7575- struct kref refcnt;7676- struct t3cdev *tdev;7777- struct pci_dev *pdev;7878- unsigned int max_txsz;7979- unsigned int max_rxsz;8080- unsigned int llimit;8181- unsigned int ulimit;8282- unsigned int nppods;8383- unsigned int idx_last;8484- unsigned char idx_bits;8585- unsigned char filler[3];8686- u32 idx_mask;8787- u32 rsvd_tag_mask;8888- spinlock_t map_lock;8989- struct cxgb3i_gather_list **gl_map;9090- struct sk_buff **gl_skb;9191-};9292-9393-#define ISCSI_PDU_NONPAYLOAD_LEN 312 /* bhs(48) + ahs(256) + digest(8) */9494-#define ULP2_MAX_PKT_SIZE 162249595-#define ULP2_MAX_PDU_PAYLOAD (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN)9696-#define PPOD_PAGES_MAX 49797-#define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */9898-9999-/*100100- * struct pagepod_hdr, pagepod - pagepod format101101- */102102-struct pagepod_hdr {103103- u32 vld_tid;104104- u32 pgsz_tag_clr;105105- u32 maxoffset;106106- u32 pgoffset;107107- u64 rsvd;108108-};109109-110110-struct pagepod {111111- struct pagepod_hdr hdr;112112- u64 addr[PPOD_PAGES_MAX + 1];113113-};114114-115115-#define PPOD_SIZE sizeof(struct pagepod) /* 64 */116116-#define PPOD_SIZE_SHIFT 6117117-118118-#define PPOD_COLOR_SHIFT 0119119-#define PPOD_COLOR_SIZE 6120120-#define PPOD_COLOR_MASK ((1 << PPOD_COLOR_SIZE) - 1)121121-122122-#define PPOD_IDX_SHIFT PPOD_COLOR_SIZE123123-#define PPOD_IDX_MAX_SIZE 24124124-125125-#define S_PPOD_TID 0126126-#define M_PPOD_TID 0xFFFFFF127127-#define V_PPOD_TID(x) ((x) << S_PPOD_TID)128128-129129-#define S_PPOD_VALID 24130130-#define V_PPOD_VALID(x) ((x) << S_PPOD_VALID)131131-#define F_PPOD_VALID V_PPOD_VALID(1U)132132-133133-#define S_PPOD_COLOR 0134134-#define M_PPOD_COLOR 0x3F135135-#define V_PPOD_COLOR(x) ((x) << S_PPOD_COLOR)136136-137137-#define S_PPOD_TAG 6138138-#define M_PPOD_TAG 0xFFFFFF139139-#define V_PPOD_TAG(x) ((x) << S_PPOD_TAG)140140-141141-#define S_PPOD_PGSZ 30142142-#define M_PPOD_PGSZ 0x3143143-#define V_PPOD_PGSZ(x) ((x) << S_PPOD_PGSZ)144144-145145-/*146146- * large memory chunk allocation/release147147- * use vmalloc() if kmalloc() fails148148- */149149-static inline void *cxgb3i_alloc_big_mem(unsigned int size,150150- gfp_t gfp)151151-{152152- void *p = kmalloc(size, gfp);153153- if (!p)154154- p = vmalloc(size);155155- if (p)156156- memset(p, 0, size);157157- return p;158158-}159159-160160-static inline void cxgb3i_free_big_mem(void *addr)161161-{162162- if (is_vmalloc_addr(addr))163163- vfree(addr);164164- else165165- kfree(addr);166166-}167167-168168-/*169169- * cxgb3i ddp tag are 32 bits, it consists of reserved bits used by h/w and170170- * non-reserved bits that can be used by the iscsi s/w.171171- * The reserved bits are identified by the rsvd_bits and rsvd_shift fields172172- * in struct cxgb3i_tag_format.173173- *174174- * The upper most reserved bit can be used to check if a tag is ddp tag or not:175175- * if the bit is 0, the tag is a valid ddp tag176176- */177177-178178-/**179179- * cxgb3i_is_ddp_tag - check if a given tag is a hw/ddp tag180180- * @tformat: tag format information181181- * @tag: tag to be checked182182- *183183- * return true if the tag is a ddp tag, false otherwise.184184- */185185-static inline int cxgb3i_is_ddp_tag(struct cxgb3i_tag_format *tformat, u32 tag)186186-{187187- return !(tag & (1 << (tformat->rsvd_bits + tformat->rsvd_shift - 1)));188188-}189189-190190-/**191191- * cxgb3i_sw_tag_usable - check if s/w tag has enough bits left for hw bits192192- * @tformat: tag format information193193- * @sw_tag: s/w tag to be checked194194- *195195- * return true if the tag can be used for hw ddp tag, false otherwise.196196- */197197-static inline int cxgb3i_sw_tag_usable(struct cxgb3i_tag_format *tformat,198198- u32 sw_tag)199199-{200200- sw_tag >>= (32 - tformat->rsvd_bits);201201- return !sw_tag;202202-}203203-204204-/**205205- * cxgb3i_set_non_ddp_tag - mark a given s/w tag as an invalid ddp tag206206- * @tformat: tag format information207207- * @sw_tag: s/w tag to be checked208208- *209209- * insert 1 at the upper most reserved bit to mark it as an invalid ddp tag.210210- */211211-static inline u32 cxgb3i_set_non_ddp_tag(struct cxgb3i_tag_format *tformat,212212- u32 sw_tag)213213-{214214- unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1;215215- u32 mask = (1 << shift) - 1;216216-217217- if (sw_tag && (sw_tag & ~mask)) {218218- u32 v1 = sw_tag & ((1 << shift) - 1);219219- u32 v2 = (sw_tag >> (shift - 1)) << shift;220220-221221- return v2 | v1 | 1 << shift;222222- }223223- return sw_tag | 1 << shift;224224-}225225-226226-/**227227- * cxgb3i_ddp_tag_base - shift s/w tag bits so that reserved bits are not used228228- * @tformat: tag format information229229- * @sw_tag: s/w tag to be checked230230- */231231-static inline u32 cxgb3i_ddp_tag_base(struct cxgb3i_tag_format *tformat,232232- u32 sw_tag)233233-{234234- u32 mask = (1 << tformat->rsvd_shift) - 1;235235-236236- if (sw_tag && (sw_tag & ~mask)) {237237- u32 v1 = sw_tag & mask;238238- u32 v2 = sw_tag >> tformat->rsvd_shift;239239-240240- v2 <<= tformat->rsvd_shift + tformat->rsvd_bits;241241- return v2 | v1;242242- }243243- return sw_tag;244244-}245245-246246-/**247247- * cxgb3i_tag_rsvd_bits - get the reserved bits used by the h/w248248- * @tformat: tag format information249249- * @tag: tag to be checked250250- *251251- * return the reserved bits in the tag252252- */253253-static inline u32 cxgb3i_tag_rsvd_bits(struct cxgb3i_tag_format *tformat,254254- u32 tag)255255-{256256- if (cxgb3i_is_ddp_tag(tformat, tag))257257- return (tag >> tformat->rsvd_shift) & tformat->rsvd_mask;258258- return 0;259259-}260260-261261-/**262262- * cxgb3i_tag_nonrsvd_bits - get the non-reserved bits used by the s/w263263- * @tformat: tag format information264264- * @tag: tag to be checked265265- *266266- * return the non-reserved bits in the tag.267267- */268268-static inline u32 cxgb3i_tag_nonrsvd_bits(struct cxgb3i_tag_format *tformat,269269- u32 tag)270270-{271271- unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1;272272- u32 v1, v2;273273-274274- if (cxgb3i_is_ddp_tag(tformat, tag)) {275275- v1 = tag & ((1 << tformat->rsvd_shift) - 1);276276- v2 = (tag >> (shift + 1)) << tformat->rsvd_shift;277277- } else {278278- u32 mask = (1 << shift) - 1;279279-280280- tag &= ~(1 << shift);281281- v1 = tag & mask;282282- v2 = (tag >> 1) & ~mask;283283- }284284- return v1 | v2;285285-}286286-287287-int cxgb3i_ddp_tag_reserve(struct t3cdev *, unsigned int tid,288288- struct cxgb3i_tag_format *, u32 *tag,289289- struct cxgb3i_gather_list *, gfp_t gfp);290290-void cxgb3i_ddp_tag_release(struct t3cdev *, u32 tag);291291-292292-struct cxgb3i_gather_list *cxgb3i_ddp_make_gl(unsigned int xferlen,293293- struct scatterlist *sgl,294294- unsigned int sgcnt,295295- struct pci_dev *pdev,296296- gfp_t gfp);297297-void cxgb3i_ddp_release_gl(struct cxgb3i_gather_list *gl,298298- struct pci_dev *pdev);299299-300300-int cxgb3i_setup_conn_host_pagesize(struct t3cdev *, unsigned int tid,301301- int reply);302302-int cxgb3i_setup_conn_pagesize(struct t3cdev *, unsigned int tid, int reply,303303- unsigned long pgsz);304304-int cxgb3i_setup_conn_digest(struct t3cdev *, unsigned int tid,305305- int hcrc, int dcrc, int reply);306306-int cxgb3i_ddp_find_page_index(unsigned long pgsz);307307-int cxgb3i_adapter_ddp_info(struct t3cdev *, struct cxgb3i_tag_format *,308308- unsigned int *txsz, unsigned int *rxsz);309309-310310-void cxgb3i_ddp_init(struct t3cdev *);311311-void cxgb3i_ddp_cleanup(struct t3cdev *);312312-#endif
-132
drivers/scsi/cxgb3i/cxgb3i_init.c
···11-/* cxgb3i_init.c: Chelsio S3xx iSCSI driver.22- *33- * Copyright (c) 2008 Chelsio Communications, Inc.44- *55- * This program is free software; you can redistribute it and/or modify66- * it under the terms of the GNU General Public License as published by77- * the Free Software Foundation.88- *99- * Written by: Karen Xie (kxie@chelsio.com)1010- */1111-1212-#include "cxgb3i.h"1313-1414-#define DRV_MODULE_NAME "cxgb3i"1515-#define DRV_MODULE_VERSION "1.0.2"1616-#define DRV_MODULE_RELDATE "Mar. 2009"1717-1818-static char version[] =1919- "Chelsio S3xx iSCSI Driver " DRV_MODULE_NAME2020- " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";2121-2222-MODULE_AUTHOR("Karen Xie <kxie@chelsio.com>");2323-MODULE_DESCRIPTION("Chelsio S3xx iSCSI Driver");2424-MODULE_LICENSE("GPL");2525-MODULE_VERSION(DRV_MODULE_VERSION);2626-2727-static void open_s3_dev(struct t3cdev *);2828-static void close_s3_dev(struct t3cdev *);2929-static void s3_event_handler(struct t3cdev *tdev, u32 event, u32 port);3030-3131-static cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS];3232-static struct cxgb3_client t3c_client = {3333- .name = "iscsi_cxgb3",3434- .handlers = cxgb3i_cpl_handlers,3535- .add = open_s3_dev,3636- .remove = close_s3_dev,3737- .event_handler = s3_event_handler,3838-};3939-4040-/**4141- * open_s3_dev - register with cxgb3 LLD4242- * @t3dev: cxgb3 adapter instance4343- */4444-static void open_s3_dev(struct t3cdev *t3dev)4545-{4646- static int vers_printed;4747-4848- if (!vers_printed) {4949- printk(KERN_INFO "%s", version);5050- vers_printed = 1;5151- }5252-5353- cxgb3i_ddp_init(t3dev);5454- cxgb3i_sdev_add(t3dev, &t3c_client);5555- cxgb3i_adapter_open(t3dev);5656-}5757-5858-/**5959- * close_s3_dev - de-register with cxgb3 LLD6060- * @t3dev: cxgb3 adapter instance6161- */6262-static void close_s3_dev(struct t3cdev *t3dev)6363-{6464- cxgb3i_adapter_close(t3dev);6565- cxgb3i_sdev_remove(t3dev);6666- cxgb3i_ddp_cleanup(t3dev);6767-}6868-6969-static void s3_event_handler(struct t3cdev *tdev, u32 event, u32 port)7070-{7171- struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(tdev);7272-7373- cxgb3i_log_info("snic 0x%p, tdev 0x%p, event 0x%x, port 0x%x.\n",7474- snic, tdev, event, port);7575- if (!snic)7676- return;7777-7878- switch (event) {7979- case OFFLOAD_STATUS_DOWN:8080- snic->flags |= CXGB3I_ADAPTER_FLAG_RESET;8181- break;8282- case OFFLOAD_STATUS_UP:8383- snic->flags &= ~CXGB3I_ADAPTER_FLAG_RESET;8484- break;8585- }8686-}8787-8888-/**8989- * cxgb3i_init_module - module init entry point9090- *9191- * initialize any driver wide global data structures and register itself9292- * with the cxgb3 module9393- */9494-static int __init cxgb3i_init_module(void)9595-{9696- int err;9797-9898- err = cxgb3i_sdev_init(cxgb3i_cpl_handlers);9999- if (err < 0)100100- return err;101101-102102- err = cxgb3i_iscsi_init();103103- if (err < 0)104104- return err;105105-106106- err = cxgb3i_pdu_init();107107- if (err < 0) {108108- cxgb3i_iscsi_cleanup();109109- return err;110110- }111111-112112- cxgb3_register_client(&t3c_client);113113-114114- return 0;115115-}116116-117117-/**118118- * cxgb3i_exit_module - module cleanup/exit entry point119119- *120120- * go through the driver hba list and for each hba, release any resource held.121121- * and unregisters iscsi transport and the cxgb3 module122122- */123123-static void __exit cxgb3i_exit_module(void)124124-{125125- cxgb3_unregister_client(&t3c_client);126126- cxgb3i_pdu_cleanup();127127- cxgb3i_iscsi_cleanup();128128- cxgb3i_sdev_cleanup();129129-}130130-131131-module_init(cxgb3i_init_module);132132-module_exit(cxgb3i_exit_module);
-1018
drivers/scsi/cxgb3i/cxgb3i_iscsi.c
···11-/* cxgb3i_iscsi.c: Chelsio S3xx iSCSI driver.22- *33- * Copyright (c) 2008 Chelsio Communications, Inc.44- * Copyright (c) 2008 Mike Christie55- * Copyright (c) 2008 Red Hat, Inc. All rights reserved.66- *77- * This program is free software; you can redistribute it and/or modify88- * it under the terms of the GNU General Public License as published by99- * the Free Software Foundation.1010- *1111- * Written by: Karen Xie (kxie@chelsio.com)1212- */1313-1414-#include <linux/inet.h>1515-#include <linux/slab.h>1616-#include <linux/crypto.h>1717-#include <linux/if_vlan.h>1818-#include <net/dst.h>1919-#include <net/tcp.h>2020-#include <scsi/scsi_cmnd.h>2121-#include <scsi/scsi_device.h>2222-#include <scsi/scsi_eh.h>2323-#include <scsi/scsi_host.h>2424-#include <scsi/scsi.h>2525-#include <scsi/iscsi_proto.h>2626-#include <scsi/libiscsi.h>2727-#include <scsi/scsi_transport_iscsi.h>2828-2929-#include "cxgb3i.h"3030-#include "cxgb3i_pdu.h"3131-3232-#ifdef __DEBUG_CXGB3I_TAG__3333-#define cxgb3i_tag_debug cxgb3i_log_debug3434-#else3535-#define cxgb3i_tag_debug(fmt...)3636-#endif3737-3838-#ifdef __DEBUG_CXGB3I_API__3939-#define cxgb3i_api_debug cxgb3i_log_debug4040-#else4141-#define cxgb3i_api_debug(fmt...)4242-#endif4343-4444-/*4545- * align pdu size to multiple of 512 for better performance4646- */4747-#define align_pdu_size(n) do { n = (n) & (~511); } while (0)4848-4949-static struct scsi_transport_template *cxgb3i_scsi_transport;5050-static struct scsi_host_template cxgb3i_host_template;5151-static struct iscsi_transport cxgb3i_iscsi_transport;5252-static unsigned char sw_tag_idx_bits;5353-static unsigned char sw_tag_age_bits;5454-5555-static LIST_HEAD(cxgb3i_snic_list);5656-static DEFINE_RWLOCK(cxgb3i_snic_rwlock);5757-5858-/**5959- * cxgb3i_adpater_find_by_tdev - find the cxgb3i_adapter structure via t3cdev6060- * @tdev: t3cdev pointer6161- */6262-struct cxgb3i_adapter *cxgb3i_adapter_find_by_tdev(struct t3cdev *tdev)6363-{6464- struct cxgb3i_adapter *snic;6565-6666- read_lock(&cxgb3i_snic_rwlock);6767- list_for_each_entry(snic, &cxgb3i_snic_list, list_head) {6868- if (snic->tdev == tdev) {6969- read_unlock(&cxgb3i_snic_rwlock);7070- return snic;7171- }7272- }7373- read_unlock(&cxgb3i_snic_rwlock);7474- return NULL;7575-}7676-7777-static inline int adapter_update(struct cxgb3i_adapter *snic)7878-{7979- cxgb3i_log_info("snic 0x%p, t3dev 0x%p, updating.\n",8080- snic, snic->tdev);8181- return cxgb3i_adapter_ddp_info(snic->tdev, &snic->tag_format,8282- &snic->tx_max_size,8383- &snic->rx_max_size);8484-}8585-8686-static int adapter_add(struct cxgb3i_adapter *snic)8787-{8888- struct t3cdev *t3dev = snic->tdev;8989- struct adapter *adapter = tdev2adap(t3dev);9090- int i, err;9191-9292- snic->pdev = adapter->pdev;9393- snic->tag_format.sw_bits = sw_tag_idx_bits + sw_tag_age_bits;9494-9595- err = cxgb3i_adapter_ddp_info(t3dev, &snic->tag_format,9696- &snic->tx_max_size,9797- &snic->rx_max_size);9898- if (err < 0)9999- return err;100100-101101- for_each_port(adapter, i) {102102- snic->hba[i] = cxgb3i_hba_host_add(snic, adapter->port[i]);103103- if (!snic->hba[i])104104- return -EINVAL;105105- }106106- snic->hba_cnt = adapter->params.nports;107107-108108- /* add to the list */109109- write_lock(&cxgb3i_snic_rwlock);110110- list_add_tail(&snic->list_head, &cxgb3i_snic_list);111111- write_unlock(&cxgb3i_snic_rwlock);112112-113113- cxgb3i_log_info("t3dev 0x%p open, snic 0x%p, %u scsi hosts added.\n",114114- t3dev, snic, snic->hba_cnt);115115- return 0;116116-}117117-118118-/**119119- * cxgb3i_adapter_open - init a s3 adapter structure and any h/w settings120120- * @t3dev: t3cdev adapter121121- */122122-void cxgb3i_adapter_open(struct t3cdev *t3dev)123123-{124124- struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(t3dev);125125- int err;126126-127127- if (snic)128128- err = adapter_update(snic);129129- else {130130- snic = kzalloc(sizeof(*snic), GFP_KERNEL);131131- if (snic) {132132- spin_lock_init(&snic->lock);133133- snic->tdev = t3dev;134134- err = adapter_add(snic);135135- } else136136- err = -ENOMEM;137137- }138138-139139- if (err < 0) {140140- cxgb3i_log_info("snic 0x%p, f 0x%x, t3dev 0x%p open, err %d.\n",141141- snic, snic ? snic->flags : 0, t3dev, err);142142- if (snic) {143143- snic->flags &= ~CXGB3I_ADAPTER_FLAG_RESET;144144- cxgb3i_adapter_close(t3dev);145145- }146146- }147147-}148148-149149-/**150150- * cxgb3i_adapter_close - release the resources held and cleanup h/w settings151151- * @t3dev: t3cdev adapter152152- */153153-void cxgb3i_adapter_close(struct t3cdev *t3dev)154154-{155155- struct cxgb3i_adapter *snic = cxgb3i_adapter_find_by_tdev(t3dev);156156- int i;157157-158158- if (!snic || snic->flags & CXGB3I_ADAPTER_FLAG_RESET) {159159- cxgb3i_log_info("t3dev 0x%p close, snic 0x%p, f 0x%x.\n",160160- t3dev, snic, snic ? snic->flags : 0);161161- return;162162- }163163-164164- /* remove from the list */165165- write_lock(&cxgb3i_snic_rwlock);166166- list_del(&snic->list_head);167167- write_unlock(&cxgb3i_snic_rwlock);168168-169169- for (i = 0; i < snic->hba_cnt; i++) {170170- if (snic->hba[i]) {171171- cxgb3i_hba_host_remove(snic->hba[i]);172172- snic->hba[i] = NULL;173173- }174174- }175175- cxgb3i_log_info("t3dev 0x%p close, snic 0x%p, %u scsi hosts removed.\n",176176- t3dev, snic, snic->hba_cnt);177177- kfree(snic);178178-}179179-180180-/**181181- * cxgb3i_hba_find_by_netdev - find the cxgb3i_hba structure via net_device182182- * @t3dev: t3cdev adapter183183- */184184-static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)185185-{186186- struct cxgb3i_adapter *snic;187187- int i;188188-189189- if (ndev->priv_flags & IFF_802_1Q_VLAN)190190- ndev = vlan_dev_real_dev(ndev);191191-192192- read_lock(&cxgb3i_snic_rwlock);193193- list_for_each_entry(snic, &cxgb3i_snic_list, list_head) {194194- for (i = 0; i < snic->hba_cnt; i++) {195195- if (snic->hba[i]->ndev == ndev) {196196- read_unlock(&cxgb3i_snic_rwlock);197197- return snic->hba[i];198198- }199199- }200200- }201201- read_unlock(&cxgb3i_snic_rwlock);202202- return NULL;203203-}204204-205205-/**206206- * cxgb3i_hba_host_add - register a new host with scsi/iscsi207207- * @snic: the cxgb3i adapter208208- * @ndev: associated net_device209209- */210210-struct cxgb3i_hba *cxgb3i_hba_host_add(struct cxgb3i_adapter *snic,211211- struct net_device *ndev)212212-{213213- struct cxgb3i_hba *hba;214214- struct Scsi_Host *shost;215215- int err;216216-217217- shost = iscsi_host_alloc(&cxgb3i_host_template,218218- sizeof(struct cxgb3i_hba), 1);219219- if (!shost) {220220- cxgb3i_log_info("snic 0x%p, ndev 0x%p, host_alloc failed.\n",221221- snic, ndev);222222- return NULL;223223- }224224-225225- shost->transportt = cxgb3i_scsi_transport;226226- shost->max_lun = CXGB3I_MAX_LUN;227227- shost->max_id = CXGB3I_MAX_TARGET;228228- shost->max_channel = 0;229229- shost->max_cmd_len = 16;230230-231231- hba = iscsi_host_priv(shost);232232- hba->snic = snic;233233- hba->ndev = ndev;234234- hba->shost = shost;235235-236236- pci_dev_get(snic->pdev);237237- err = iscsi_host_add(shost, &snic->pdev->dev);238238- if (err) {239239- cxgb3i_log_info("snic 0x%p, ndev 0x%p, host_add failed.\n",240240- snic, ndev);241241- goto pci_dev_put;242242- }243243-244244- cxgb3i_api_debug("shost 0x%p, hba 0x%p, no %u.\n",245245- shost, hba, shost->host_no);246246-247247- return hba;248248-249249-pci_dev_put:250250- pci_dev_put(snic->pdev);251251- scsi_host_put(shost);252252- return NULL;253253-}254254-255255-/**256256- * cxgb3i_hba_host_remove - de-register the host with scsi/iscsi257257- * @hba: the cxgb3i hba258258- */259259-void cxgb3i_hba_host_remove(struct cxgb3i_hba *hba)260260-{261261- cxgb3i_api_debug("shost 0x%p, hba 0x%p, no %u.\n",262262- hba->shost, hba, hba->shost->host_no);263263- iscsi_host_remove(hba->shost);264264- pci_dev_put(hba->snic->pdev);265265- iscsi_host_free(hba->shost);266266-}267267-268268-/**269269- * cxgb3i_ep_connect - establish TCP connection to target portal270270- * @shost: scsi host to use271271- * @dst_addr: target IP address272272- * @non_blocking: blocking or non-blocking call273273- *274274- * Initiates a TCP/IP connection to the dst_addr275275- */276276-static struct iscsi_endpoint *cxgb3i_ep_connect(struct Scsi_Host *shost,277277- struct sockaddr *dst_addr,278278- int non_blocking)279279-{280280- struct iscsi_endpoint *ep;281281- struct cxgb3i_endpoint *cep;282282- struct cxgb3i_hba *hba = NULL;283283- struct s3_conn *c3cn = NULL;284284- int err = 0;285285-286286- if (shost)287287- hba = iscsi_host_priv(shost);288288-289289- cxgb3i_api_debug("shost 0x%p, hba 0x%p.\n", shost, hba);290290-291291- c3cn = cxgb3i_c3cn_create();292292- if (!c3cn) {293293- cxgb3i_log_info("ep connect OOM.\n");294294- err = -ENOMEM;295295- goto release_conn;296296- }297297-298298- err = cxgb3i_c3cn_connect(hba ? hba->ndev : NULL, c3cn,299299- (struct sockaddr_in *)dst_addr);300300- if (err < 0) {301301- cxgb3i_log_info("ep connect failed.\n");302302- goto release_conn;303303- }304304-305305- hba = cxgb3i_hba_find_by_netdev(c3cn->dst_cache->dev);306306- if (!hba) {307307- err = -ENOSPC;308308- cxgb3i_log_info("NOT going through cxgbi device.\n");309309- goto release_conn;310310- }311311-312312- if (shost && hba != iscsi_host_priv(shost)) {313313- err = -ENOSPC;314314- cxgb3i_log_info("Could not connect through request host%u\n",315315- shost->host_no);316316- goto release_conn;317317- }318318-319319- if (c3cn_is_closing(c3cn)) {320320- err = -ENOSPC;321321- cxgb3i_log_info("ep connect unable to connect.\n");322322- goto release_conn;323323- }324324-325325- ep = iscsi_create_endpoint(sizeof(*cep));326326- if (!ep) {327327- err = -ENOMEM;328328- cxgb3i_log_info("iscsi alloc ep, OOM.\n");329329- goto release_conn;330330- }331331- cep = ep->dd_data;332332- cep->c3cn = c3cn;333333- cep->hba = hba;334334-335335- cxgb3i_api_debug("ep 0x%p, 0x%p, c3cn 0x%p, hba 0x%p.\n",336336- ep, cep, c3cn, hba);337337- return ep;338338-339339-release_conn:340340- cxgb3i_api_debug("conn 0x%p failed, release.\n", c3cn);341341- if (c3cn)342342- cxgb3i_c3cn_release(c3cn);343343- return ERR_PTR(err);344344-}345345-346346-/**347347- * cxgb3i_ep_poll - polls for TCP connection establishement348348- * @ep: TCP connection (endpoint) handle349349- * @timeout_ms: timeout value in milli secs350350- *351351- * polls for TCP connect request to complete352352- */353353-static int cxgb3i_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)354354-{355355- struct cxgb3i_endpoint *cep = ep->dd_data;356356- struct s3_conn *c3cn = cep->c3cn;357357-358358- if (!c3cn_is_established(c3cn))359359- return 0;360360- cxgb3i_api_debug("ep 0x%p, c3cn 0x%p established.\n", ep, c3cn);361361- return 1;362362-}363363-364364-/**365365- * cxgb3i_ep_disconnect - teardown TCP connection366366- * @ep: TCP connection (endpoint) handle367367- *368368- * teardown TCP connection369369- */370370-static void cxgb3i_ep_disconnect(struct iscsi_endpoint *ep)371371-{372372- struct cxgb3i_endpoint *cep = ep->dd_data;373373- struct cxgb3i_conn *cconn = cep->cconn;374374-375375- cxgb3i_api_debug("ep 0x%p, cep 0x%p.\n", ep, cep);376376-377377- if (cconn && cconn->conn) {378378- /*379379- * stop the xmit path so the xmit_pdu function is380380- * not being called381381- */382382- iscsi_suspend_tx(cconn->conn);383383-384384- write_lock_bh(&cep->c3cn->callback_lock);385385- cep->c3cn->user_data = NULL;386386- cconn->cep = NULL;387387- write_unlock_bh(&cep->c3cn->callback_lock);388388- }389389-390390- cxgb3i_api_debug("ep 0x%p, cep 0x%p, release c3cn 0x%p.\n",391391- ep, cep, cep->c3cn);392392- cxgb3i_c3cn_release(cep->c3cn);393393- iscsi_destroy_endpoint(ep);394394-}395395-396396-/**397397- * cxgb3i_session_create - create a new iscsi session398398- * @cmds_max: max # of commands399399- * @qdepth: scsi queue depth400400- * @initial_cmdsn: initial iscsi CMDSN for this session401401- *402402- * Creates a new iSCSI session403403- */404404-static struct iscsi_cls_session *405405-cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth,406406- u32 initial_cmdsn)407407-{408408- struct cxgb3i_endpoint *cep;409409- struct cxgb3i_hba *hba;410410- struct Scsi_Host *shost;411411- struct iscsi_cls_session *cls_session;412412- struct iscsi_session *session;413413-414414- if (!ep) {415415- cxgb3i_log_error("%s, missing endpoint.\n", __func__);416416- return NULL;417417- }418418-419419- cep = ep->dd_data;420420- hba = cep->hba;421421- shost = hba->shost;422422- cxgb3i_api_debug("ep 0x%p, cep 0x%p, hba 0x%p.\n", ep, cep, hba);423423- BUG_ON(hba != iscsi_host_priv(shost));424424-425425- cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost,426426- cmds_max, 0,427427- sizeof(struct iscsi_tcp_task) +428428- sizeof(struct cxgb3i_task_data),429429- initial_cmdsn, ISCSI_MAX_TARGET);430430- if (!cls_session)431431- return NULL;432432- session = cls_session->dd_data;433433- if (iscsi_tcp_r2tpool_alloc(session))434434- goto remove_session;435435-436436- return cls_session;437437-438438-remove_session:439439- iscsi_session_teardown(cls_session);440440- return NULL;441441-}442442-443443-/**444444- * cxgb3i_session_destroy - destroys iscsi session445445- * @cls_session: pointer to iscsi cls session446446- *447447- * Destroys an iSCSI session instance and releases its all resources held448448- */449449-static void cxgb3i_session_destroy(struct iscsi_cls_session *cls_session)450450-{451451- cxgb3i_api_debug("sess 0x%p.\n", cls_session);452452- iscsi_tcp_r2tpool_free(cls_session->dd_data);453453- iscsi_session_teardown(cls_session);454454-}455455-456456-/**457457- * cxgb3i_conn_max_xmit_dlength -- calc the max. xmit pdu segment size458458- * @conn: iscsi connection459459- * check the max. xmit pdu payload, reduce it if needed460460- */461461-static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn)462462-463463-{464464- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;465465- struct cxgb3i_conn *cconn = tcp_conn->dd_data;466466- unsigned int max = max(512 * MAX_SKB_FRAGS, SKB_TX_HEADROOM);467467-468468- max = min(cconn->hba->snic->tx_max_size, max);469469- if (conn->max_xmit_dlength)470470- conn->max_xmit_dlength = min(conn->max_xmit_dlength, max);471471- else472472- conn->max_xmit_dlength = max;473473- align_pdu_size(conn->max_xmit_dlength);474474- cxgb3i_api_debug("conn 0x%p, max xmit %u.\n",475475- conn, conn->max_xmit_dlength);476476- return 0;477477-}478478-479479-/**480480- * cxgb3i_conn_max_recv_dlength -- check the max. recv pdu segment size481481- * @conn: iscsi connection482482- * return 0 if the value is valid, < 0 otherwise.483483- */484484-static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn)485485-{486486- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;487487- struct cxgb3i_conn *cconn = tcp_conn->dd_data;488488- unsigned int max = cconn->hba->snic->rx_max_size;489489-490490- align_pdu_size(max);491491- if (conn->max_recv_dlength) {492492- if (conn->max_recv_dlength > max) {493493- cxgb3i_log_error("MaxRecvDataSegmentLength %u too big."494494- " Need to be <= %u.\n",495495- conn->max_recv_dlength, max);496496- return -EINVAL;497497- }498498- conn->max_recv_dlength = min(conn->max_recv_dlength, max);499499- align_pdu_size(conn->max_recv_dlength);500500- } else501501- conn->max_recv_dlength = max;502502- cxgb3i_api_debug("conn 0x%p, max recv %u.\n",503503- conn, conn->max_recv_dlength);504504- return 0;505505-}506506-507507-/**508508- * cxgb3i_conn_create - create iscsi connection instance509509- * @cls_session: pointer to iscsi cls session510510- * @cid: iscsi cid511511- *512512- * Creates a new iSCSI connection instance for a given session513513- */514514-static struct iscsi_cls_conn *cxgb3i_conn_create(struct iscsi_cls_session515515- *cls_session, u32 cid)516516-{517517- struct iscsi_cls_conn *cls_conn;518518- struct iscsi_conn *conn;519519- struct iscsi_tcp_conn *tcp_conn;520520- struct cxgb3i_conn *cconn;521521-522522- cxgb3i_api_debug("sess 0x%p, cid %u.\n", cls_session, cid);523523-524524- cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*cconn), cid);525525- if (!cls_conn)526526- return NULL;527527- conn = cls_conn->dd_data;528528- tcp_conn = conn->dd_data;529529- cconn = tcp_conn->dd_data;530530-531531- cconn->conn = conn;532532- return cls_conn;533533-}534534-535535-/**536536- * cxgb3i_conn_bind - binds iscsi sess, conn and endpoint together537537- * @cls_session: pointer to iscsi cls session538538- * @cls_conn: pointer to iscsi cls conn539539- * @transport_eph: 64-bit EP handle540540- * @is_leading: leading connection on this session?541541- *542542- * Binds together an iSCSI session, an iSCSI connection and a543543- * TCP connection. This routine returns error code if the TCP544544- * connection does not belong on the device iSCSI sess/conn is bound545545- */546546-547547-static int cxgb3i_conn_bind(struct iscsi_cls_session *cls_session,548548- struct iscsi_cls_conn *cls_conn,549549- u64 transport_eph, int is_leading)550550-{551551- struct iscsi_conn *conn = cls_conn->dd_data;552552- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;553553- struct cxgb3i_conn *cconn = tcp_conn->dd_data;554554- struct cxgb3i_adapter *snic;555555- struct iscsi_endpoint *ep;556556- struct cxgb3i_endpoint *cep;557557- struct s3_conn *c3cn;558558- int err;559559-560560- ep = iscsi_lookup_endpoint(transport_eph);561561- if (!ep)562562- return -EINVAL;563563-564564- /* setup ddp pagesize */565565- cep = ep->dd_data;566566- c3cn = cep->c3cn;567567- snic = cep->hba->snic;568568- err = cxgb3i_setup_conn_host_pagesize(snic->tdev, c3cn->tid, 0);569569- if (err < 0)570570- return err;571571-572572- cxgb3i_api_debug("ep 0x%p, cls sess 0x%p, cls conn 0x%p.\n",573573- ep, cls_session, cls_conn);574574-575575- err = iscsi_conn_bind(cls_session, cls_conn, is_leading);576576- if (err)577577- return -EINVAL;578578-579579- /* calculate the tag idx bits needed for this conn based on cmds_max */580580- cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1;581581- cxgb3i_api_debug("session cmds_max 0x%x, bits %u.\n",582582- conn->session->cmds_max, cconn->task_idx_bits);583583-584584- read_lock(&c3cn->callback_lock);585585- c3cn->user_data = conn;586586- cconn->hba = cep->hba;587587- cconn->cep = cep;588588- cep->cconn = cconn;589589- read_unlock(&c3cn->callback_lock);590590-591591- cxgb3i_conn_max_xmit_dlength(conn);592592- cxgb3i_conn_max_recv_dlength(conn);593593-594594- spin_lock_bh(&conn->session->lock);595595- sprintf(conn->portal_address, "%pI4", &c3cn->daddr.sin_addr.s_addr);596596- conn->portal_port = ntohs(c3cn->daddr.sin_port);597597- spin_unlock_bh(&conn->session->lock);598598-599599- /* init recv engine */600600- iscsi_tcp_hdr_recv_prep(tcp_conn);601601-602602- return 0;603603-}604604-605605-/**606606- * cxgb3i_conn_get_param - return iscsi connection parameter to caller607607- * @cls_conn: pointer to iscsi cls conn608608- * @param: parameter type identifier609609- * @buf: buffer pointer610610- *611611- * returns iSCSI connection parameters612612- */613613-static int cxgb3i_conn_get_param(struct iscsi_cls_conn *cls_conn,614614- enum iscsi_param param, char *buf)615615-{616616- struct iscsi_conn *conn = cls_conn->dd_data;617617- int len;618618-619619- cxgb3i_api_debug("cls_conn 0x%p, param %d.\n", cls_conn, param);620620-621621- switch (param) {622622- case ISCSI_PARAM_CONN_PORT:623623- spin_lock_bh(&conn->session->lock);624624- len = sprintf(buf, "%hu\n", conn->portal_port);625625- spin_unlock_bh(&conn->session->lock);626626- break;627627- case ISCSI_PARAM_CONN_ADDRESS:628628- spin_lock_bh(&conn->session->lock);629629- len = sprintf(buf, "%s\n", conn->portal_address);630630- spin_unlock_bh(&conn->session->lock);631631- break;632632- default:633633- return iscsi_conn_get_param(cls_conn, param, buf);634634- }635635-636636- return len;637637-}638638-639639-/**640640- * cxgb3i_conn_set_param - set iscsi connection parameter641641- * @cls_conn: pointer to iscsi cls conn642642- * @param: parameter type identifier643643- * @buf: buffer pointer644644- * @buflen: buffer length645645- *646646- * set iSCSI connection parameters647647- */648648-static int cxgb3i_conn_set_param(struct iscsi_cls_conn *cls_conn,649649- enum iscsi_param param, char *buf, int buflen)650650-{651651- struct iscsi_conn *conn = cls_conn->dd_data;652652- struct iscsi_session *session = conn->session;653653- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;654654- struct cxgb3i_conn *cconn = tcp_conn->dd_data;655655- struct cxgb3i_adapter *snic = cconn->hba->snic;656656- struct s3_conn *c3cn = cconn->cep->c3cn;657657- int value, err = 0;658658-659659- switch (param) {660660- case ISCSI_PARAM_HDRDGST_EN:661661- err = iscsi_set_param(cls_conn, param, buf, buflen);662662- if (!err && conn->hdrdgst_en)663663- err = cxgb3i_setup_conn_digest(snic->tdev, c3cn->tid,664664- conn->hdrdgst_en,665665- conn->datadgst_en, 0);666666- break;667667- case ISCSI_PARAM_DATADGST_EN:668668- err = iscsi_set_param(cls_conn, param, buf, buflen);669669- if (!err && conn->datadgst_en)670670- err = cxgb3i_setup_conn_digest(snic->tdev, c3cn->tid,671671- conn->hdrdgst_en,672672- conn->datadgst_en, 0);673673- break;674674- case ISCSI_PARAM_MAX_R2T:675675- sscanf(buf, "%d", &value);676676- if (value <= 0 || !is_power_of_2(value))677677- return -EINVAL;678678- if (session->max_r2t == value)679679- break;680680- iscsi_tcp_r2tpool_free(session);681681- err = iscsi_set_param(cls_conn, param, buf, buflen);682682- if (!err && iscsi_tcp_r2tpool_alloc(session))683683- return -ENOMEM;684684- case ISCSI_PARAM_MAX_RECV_DLENGTH:685685- err = iscsi_set_param(cls_conn, param, buf, buflen);686686- if (!err)687687- err = cxgb3i_conn_max_recv_dlength(conn);688688- break;689689- case ISCSI_PARAM_MAX_XMIT_DLENGTH:690690- err = iscsi_set_param(cls_conn, param, buf, buflen);691691- if (!err)692692- err = cxgb3i_conn_max_xmit_dlength(conn);693693- break;694694- default:695695- return iscsi_set_param(cls_conn, param, buf, buflen);696696- }697697- return err;698698-}699699-700700-/**701701- * cxgb3i_host_set_param - configure host (adapter) related parameters702702- * @shost: scsi host pointer703703- * @param: parameter type identifier704704- * @buf: buffer pointer705705- */706706-static int cxgb3i_host_set_param(struct Scsi_Host *shost,707707- enum iscsi_host_param param,708708- char *buf, int buflen)709709-{710710- struct cxgb3i_hba *hba = iscsi_host_priv(shost);711711-712712- if (!hba->ndev) {713713- shost_printk(KERN_ERR, shost, "Could not set host param. "714714- "Netdev for host not set.\n");715715- return -ENODEV;716716- }717717-718718- cxgb3i_api_debug("param %d, buf %s.\n", param, buf);719719-720720- switch (param) {721721- case ISCSI_HOST_PARAM_IPADDRESS:722722- {723723- __be32 addr = in_aton(buf);724724- cxgb3i_set_private_ipv4addr(hba->ndev, addr);725725- return 0;726726- }727727- case ISCSI_HOST_PARAM_HWADDRESS:728728- case ISCSI_HOST_PARAM_NETDEV_NAME:729729- /* ignore */730730- return 0;731731- default:732732- return iscsi_host_set_param(shost, param, buf, buflen);733733- }734734-}735735-736736-/**737737- * cxgb3i_host_get_param - returns host (adapter) related parameters738738- * @shost: scsi host pointer739739- * @param: parameter type identifier740740- * @buf: buffer pointer741741- */742742-static int cxgb3i_host_get_param(struct Scsi_Host *shost,743743- enum iscsi_host_param param, char *buf)744744-{745745- struct cxgb3i_hba *hba = iscsi_host_priv(shost);746746- int len = 0;747747-748748- if (!hba->ndev) {749749- shost_printk(KERN_ERR, shost, "Could not set host param. "750750- "Netdev for host not set.\n");751751- return -ENODEV;752752- }753753-754754- cxgb3i_api_debug("hba %s, param %d.\n", hba->ndev->name, param);755755-756756- switch (param) {757757- case ISCSI_HOST_PARAM_HWADDRESS:758758- len = sysfs_format_mac(buf, hba->ndev->dev_addr, 6);759759- break;760760- case ISCSI_HOST_PARAM_NETDEV_NAME:761761- len = sprintf(buf, "%s\n", hba->ndev->name);762762- break;763763- case ISCSI_HOST_PARAM_IPADDRESS:764764- {765765- __be32 addr;766766-767767- addr = cxgb3i_get_private_ipv4addr(hba->ndev);768768- len = sprintf(buf, "%pI4", &addr);769769- break;770770- }771771- default:772772- return iscsi_host_get_param(shost, param, buf);773773- }774774- return len;775775-}776776-777777-/**778778- * cxgb3i_conn_get_stats - returns iSCSI stats779779- * @cls_conn: pointer to iscsi cls conn780780- * @stats: pointer to iscsi statistic struct781781- */782782-static void cxgb3i_conn_get_stats(struct iscsi_cls_conn *cls_conn,783783- struct iscsi_stats *stats)784784-{785785- struct iscsi_conn *conn = cls_conn->dd_data;786786-787787- stats->txdata_octets = conn->txdata_octets;788788- stats->rxdata_octets = conn->rxdata_octets;789789- stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;790790- stats->dataout_pdus = conn->dataout_pdus_cnt;791791- stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;792792- stats->datain_pdus = conn->datain_pdus_cnt;793793- stats->r2t_pdus = conn->r2t_pdus_cnt;794794- stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;795795- stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;796796- stats->digest_err = 0;797797- stats->timeout_err = 0;798798- stats->custom_length = 1;799799- strcpy(stats->custom[0].desc, "eh_abort_cnt");800800- stats->custom[0].value = conn->eh_abort_cnt;801801-}802802-803803-/**804804- * cxgb3i_parse_itt - get the idx and age bits from a given tag805805- * @conn: iscsi connection806806- * @itt: itt tag807807- * @idx: task index, filled in by this function808808- * @age: session age, filled in by this function809809- */810810-static void cxgb3i_parse_itt(struct iscsi_conn *conn, itt_t itt,811811- int *idx, int *age)812812-{813813- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;814814- struct cxgb3i_conn *cconn = tcp_conn->dd_data;815815- struct cxgb3i_adapter *snic = cconn->hba->snic;816816- u32 tag = ntohl((__force u32) itt);817817- u32 sw_bits;818818-819819- sw_bits = cxgb3i_tag_nonrsvd_bits(&snic->tag_format, tag);820820- if (idx)821821- *idx = sw_bits & ((1 << cconn->task_idx_bits) - 1);822822- if (age)823823- *age = (sw_bits >> cconn->task_idx_bits) & ISCSI_AGE_MASK;824824-825825- cxgb3i_tag_debug("parse tag 0x%x/0x%x, sw 0x%x, itt 0x%x, age 0x%x.\n",826826- tag, itt, sw_bits, idx ? *idx : 0xFFFFF,827827- age ? *age : 0xFF);828828-}829829-830830-/**831831- * cxgb3i_reserve_itt - generate tag for a give task832832- * @task: iscsi task833833- * @hdr_itt: tag, filled in by this function834834- * Set up ddp for scsi read tasks if possible.835835- */836836-int cxgb3i_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt)837837-{838838- struct scsi_cmnd *sc = task->sc;839839- struct iscsi_conn *conn = task->conn;840840- struct iscsi_session *sess = conn->session;841841- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;842842- struct cxgb3i_conn *cconn = tcp_conn->dd_data;843843- struct cxgb3i_adapter *snic = cconn->hba->snic;844844- struct cxgb3i_tag_format *tformat = &snic->tag_format;845845- u32 sw_tag = (sess->age << cconn->task_idx_bits) | task->itt;846846- u32 tag;847847- int err = -EINVAL;848848-849849- if (sc &&850850- (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_FROM_DEVICE) &&851851- cxgb3i_sw_tag_usable(tformat, sw_tag)) {852852- struct s3_conn *c3cn = cconn->cep->c3cn;853853- struct cxgb3i_gather_list *gl;854854-855855- gl = cxgb3i_ddp_make_gl(scsi_in(sc)->length,856856- scsi_in(sc)->table.sgl,857857- scsi_in(sc)->table.nents,858858- snic->pdev,859859- GFP_ATOMIC);860860- if (gl) {861861- tag = sw_tag;862862- err = cxgb3i_ddp_tag_reserve(snic->tdev, c3cn->tid,863863- tformat, &tag,864864- gl, GFP_ATOMIC);865865- if (err < 0)866866- cxgb3i_ddp_release_gl(gl, snic->pdev);867867- }868868- }869869-870870- if (err < 0)871871- tag = cxgb3i_set_non_ddp_tag(tformat, sw_tag);872872- /* the itt need to sent in big-endian order */873873- *hdr_itt = (__force itt_t)htonl(tag);874874-875875- cxgb3i_tag_debug("new tag 0x%x/0x%x (itt 0x%x, age 0x%x).\n",876876- tag, *hdr_itt, task->itt, sess->age);877877- return 0;878878-}879879-880880-/**881881- * cxgb3i_release_itt - release the tag for a given task882882- * @task: iscsi task883883- * @hdr_itt: tag884884- * If the tag is a ddp tag, release the ddp setup885885- */886886-void cxgb3i_release_itt(struct iscsi_task *task, itt_t hdr_itt)887887-{888888- struct scsi_cmnd *sc = task->sc;889889- struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data;890890- struct cxgb3i_conn *cconn = tcp_conn->dd_data;891891- struct cxgb3i_adapter *snic = cconn->hba->snic;892892- struct cxgb3i_tag_format *tformat = &snic->tag_format;893893- u32 tag = ntohl((__force u32)hdr_itt);894894-895895- cxgb3i_tag_debug("release tag 0x%x.\n", tag);896896-897897- if (sc &&898898- (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_FROM_DEVICE) &&899899- cxgb3i_is_ddp_tag(tformat, tag))900900- cxgb3i_ddp_tag_release(snic->tdev, tag);901901-}902902-903903-/**904904- * cxgb3i_host_template -- Scsi_Host_Template structure905905- * used when registering with the scsi mid layer906906- */907907-static struct scsi_host_template cxgb3i_host_template = {908908- .module = THIS_MODULE,909909- .name = "Chelsio S3xx iSCSI Initiator",910910- .proc_name = "cxgb3i",911911- .queuecommand = iscsi_queuecommand,912912- .change_queue_depth = iscsi_change_queue_depth,913913- .can_queue = CXGB3I_SCSI_HOST_QDEPTH,914914- .sg_tablesize = SG_ALL,915915- .max_sectors = 0xFFFF,916916- .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,917917- .eh_abort_handler = iscsi_eh_abort,918918- .eh_device_reset_handler = iscsi_eh_device_reset,919919- .eh_target_reset_handler = iscsi_eh_recover_target,920920- .target_alloc = iscsi_target_alloc,921921- .use_clustering = DISABLE_CLUSTERING,922922- .this_id = -1,923923-};924924-925925-static struct iscsi_transport cxgb3i_iscsi_transport = {926926- .owner = THIS_MODULE,927927- .name = "cxgb3i",928928- .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST929929- | CAP_DATADGST | CAP_DIGEST_OFFLOAD |930930- CAP_PADDING_OFFLOAD,931931- .param_mask = ISCSI_MAX_RECV_DLENGTH |932932- ISCSI_MAX_XMIT_DLENGTH |933933- ISCSI_HDRDGST_EN |934934- ISCSI_DATADGST_EN |935935- ISCSI_INITIAL_R2T_EN |936936- ISCSI_MAX_R2T |937937- ISCSI_IMM_DATA_EN |938938- ISCSI_FIRST_BURST |939939- ISCSI_MAX_BURST |940940- ISCSI_PDU_INORDER_EN |941941- ISCSI_DATASEQ_INORDER_EN |942942- ISCSI_ERL |943943- ISCSI_CONN_PORT |944944- ISCSI_CONN_ADDRESS |945945- ISCSI_EXP_STATSN |946946- ISCSI_PERSISTENT_PORT |947947- ISCSI_PERSISTENT_ADDRESS |948948- ISCSI_TARGET_NAME | ISCSI_TPGT |949949- ISCSI_USERNAME | ISCSI_PASSWORD |950950- ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |951951- ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |952952- ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO |953953- ISCSI_PING_TMO | ISCSI_RECV_TMO |954954- ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,955955- .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |956956- ISCSI_HOST_INITIATOR_NAME | ISCSI_HOST_NETDEV_NAME,957957- .get_host_param = cxgb3i_host_get_param,958958- .set_host_param = cxgb3i_host_set_param,959959- /* session management */960960- .create_session = cxgb3i_session_create,961961- .destroy_session = cxgb3i_session_destroy,962962- .get_session_param = iscsi_session_get_param,963963- /* connection management */964964- .create_conn = cxgb3i_conn_create,965965- .bind_conn = cxgb3i_conn_bind,966966- .destroy_conn = iscsi_tcp_conn_teardown,967967- .start_conn = iscsi_conn_start,968968- .stop_conn = iscsi_conn_stop,969969- .get_conn_param = cxgb3i_conn_get_param,970970- .set_param = cxgb3i_conn_set_param,971971- .get_stats = cxgb3i_conn_get_stats,972972- /* pdu xmit req. from user space */973973- .send_pdu = iscsi_conn_send_pdu,974974- /* task */975975- .init_task = iscsi_tcp_task_init,976976- .xmit_task = iscsi_tcp_task_xmit,977977- .cleanup_task = cxgb3i_conn_cleanup_task,978978-979979- /* pdu */980980- .alloc_pdu = cxgb3i_conn_alloc_pdu,981981- .init_pdu = cxgb3i_conn_init_pdu,982982- .xmit_pdu = cxgb3i_conn_xmit_pdu,983983- .parse_pdu_itt = cxgb3i_parse_itt,984984-985985- /* TCP connect/disconnect */986986- .ep_connect = cxgb3i_ep_connect,987987- .ep_poll = cxgb3i_ep_poll,988988- .ep_disconnect = cxgb3i_ep_disconnect,989989- /* Error recovery timeout call */990990- .session_recovery_timedout = iscsi_session_recovery_timedout,991991-};992992-993993-int cxgb3i_iscsi_init(void)994994-{995995- sw_tag_idx_bits = (__ilog2_u32(ISCSI_ITT_MASK)) + 1;996996- sw_tag_age_bits = (__ilog2_u32(ISCSI_AGE_MASK)) + 1;997997- cxgb3i_log_info("tag itt 0x%x, %u bits, age 0x%x, %u bits.\n",998998- ISCSI_ITT_MASK, sw_tag_idx_bits,999999- ISCSI_AGE_MASK, sw_tag_age_bits);10001000-10011001- cxgb3i_scsi_transport =10021002- iscsi_register_transport(&cxgb3i_iscsi_transport);10031003- if (!cxgb3i_scsi_transport) {10041004- cxgb3i_log_error("Could not register cxgb3i transport.\n");10051005- return -ENODEV;10061006- }10071007- cxgb3i_api_debug("cxgb3i transport 0x%p.\n", cxgb3i_scsi_transport);10081008- return 0;10091009-}10101010-10111011-void cxgb3i_iscsi_cleanup(void)10121012-{10131013- if (cxgb3i_scsi_transport) {10141014- cxgb3i_api_debug("cxgb3i transport 0x%p.\n",10151015- cxgb3i_scsi_transport);10161016- iscsi_unregister_transport(&cxgb3i_iscsi_transport);10171017- }10181018-}
-1944
drivers/scsi/cxgb3i/cxgb3i_offload.c
···11-/*22- * cxgb3i_offload.c: Chelsio S3xx iscsi offloaded tcp connection management33- *44- * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved.55- *66- * This program is distributed in the hope that it will be useful, but WITHOUT77- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or88- * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this99- * release for licensing terms and conditions.1010- *1111- * Written by: Dimitris Michailidis (dm@chelsio.com)1212- * Karen Xie (kxie@chelsio.com)1313- */1414-1515-#include <linux/if_vlan.h>1616-#include <linux/slab.h>1717-#include <linux/version.h>1818-1919-#include "cxgb3_defs.h"2020-#include "cxgb3_ctl_defs.h"2121-#include "firmware_exports.h"2222-#include "cxgb3i_offload.h"2323-#include "cxgb3i_pdu.h"2424-#include "cxgb3i_ddp.h"2525-2626-#ifdef __DEBUG_C3CN_CONN__2727-#define c3cn_conn_debug cxgb3i_log_debug2828-#else2929-#define c3cn_conn_debug(fmt...)3030-#endif3131-3232-#ifdef __DEBUG_C3CN_TX__3333-#define c3cn_tx_debug cxgb3i_log_debug3434-#else3535-#define c3cn_tx_debug(fmt...)3636-#endif3737-3838-#ifdef __DEBUG_C3CN_RX__3939-#define c3cn_rx_debug cxgb3i_log_debug4040-#else4141-#define c3cn_rx_debug(fmt...)4242-#endif4343-4444-/*4545- * module parameters releated to offloaded iscsi connection4646- */4747-static int cxgb3_rcv_win = 256 * 1024;4848-module_param(cxgb3_rcv_win, int, 0644);4949-MODULE_PARM_DESC(cxgb3_rcv_win, "TCP receive window in bytes (default=256KB)");5050-5151-static int cxgb3_snd_win = 128 * 1024;5252-module_param(cxgb3_snd_win, int, 0644);5353-MODULE_PARM_DESC(cxgb3_snd_win, "TCP send window in bytes (default=128KB)");5454-5555-static int cxgb3_rx_credit_thres = 10 * 1024;5656-module_param(cxgb3_rx_credit_thres, int, 0644);5757-MODULE_PARM_DESC(rx_credit_thres,5858- "RX credits return threshold in bytes (default=10KB)");5959-6060-static unsigned int cxgb3_max_connect = 8 * 1024;6161-module_param(cxgb3_max_connect, uint, 0644);6262-MODULE_PARM_DESC(cxgb3_max_connect, "Max. # of connections (default=8092)");6363-6464-static unsigned int cxgb3_sport_base = 20000;6565-module_param(cxgb3_sport_base, uint, 0644);6666-MODULE_PARM_DESC(cxgb3_sport_base, "starting port number (default=20000)");6767-6868-/*6969- * cxgb3i tcp connection data(per adapter) list7070- */7171-static LIST_HEAD(cdata_list);7272-static DEFINE_RWLOCK(cdata_rwlock);7373-7474-static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion);7575-static void c3cn_release_offload_resources(struct s3_conn *c3cn);7676-7777-/*7878- * iscsi source port management7979- *8080- * Find a free source port in the port allocation map. We use a very simple8181- * rotor scheme to look for the next free port.8282- *8383- * If a source port has been specified make sure that it doesn't collide with8484- * our normal source port allocation map. If it's outside the range of our8585- * allocation/deallocation scheme just let them use it.8686- *8787- * If the source port is outside our allocation range, the caller is8888- * responsible for keeping track of their port usage.8989- */9090-static int c3cn_get_port(struct s3_conn *c3cn, struct cxgb3i_sdev_data *cdata)9191-{9292- unsigned int start;9393- int idx;9494-9595- if (!cdata)9696- goto error_out;9797-9898- if (c3cn->saddr.sin_port) {9999- cxgb3i_log_error("connect, sin_port NON-ZERO %u.\n",100100- c3cn->saddr.sin_port);101101- return -EADDRINUSE;102102- }103103-104104- spin_lock_bh(&cdata->lock);105105- start = idx = cdata->sport_next;106106- do {107107- if (++idx >= cxgb3_max_connect)108108- idx = 0;109109- if (!cdata->sport_conn[idx]) {110110- c3cn->saddr.sin_port = htons(cxgb3_sport_base + idx);111111- cdata->sport_next = idx;112112- cdata->sport_conn[idx] = c3cn;113113- spin_unlock_bh(&cdata->lock);114114-115115- c3cn_conn_debug("%s reserve port %u.\n",116116- cdata->cdev->name,117117- cxgb3_sport_base + idx);118118- return 0;119119- }120120- } while (idx != start);121121- spin_unlock_bh(&cdata->lock);122122-123123-error_out:124124- return -EADDRNOTAVAIL;125125-}126126-127127-static void c3cn_put_port(struct s3_conn *c3cn)128128-{129129- if (!c3cn->cdev)130130- return;131131-132132- if (c3cn->saddr.sin_port) {133133- struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(c3cn->cdev);134134- int idx = ntohs(c3cn->saddr.sin_port) - cxgb3_sport_base;135135-136136- c3cn->saddr.sin_port = 0;137137- if (idx < 0 || idx >= cxgb3_max_connect)138138- return;139139- spin_lock_bh(&cdata->lock);140140- cdata->sport_conn[idx] = NULL;141141- spin_unlock_bh(&cdata->lock);142142- c3cn_conn_debug("%s, release port %u.\n",143143- cdata->cdev->name, cxgb3_sport_base + idx);144144- }145145-}146146-147147-static inline void c3cn_set_flag(struct s3_conn *c3cn, enum c3cn_flags flag)148148-{149149- __set_bit(flag, &c3cn->flags);150150- c3cn_conn_debug("c3cn 0x%p, set %d, s %u, f 0x%lx.\n",151151- c3cn, flag, c3cn->state, c3cn->flags);152152-}153153-154154-static inline void c3cn_clear_flag(struct s3_conn *c3cn, enum c3cn_flags flag)155155-{156156- __clear_bit(flag, &c3cn->flags);157157- c3cn_conn_debug("c3cn 0x%p, clear %d, s %u, f 0x%lx.\n",158158- c3cn, flag, c3cn->state, c3cn->flags);159159-}160160-161161-static inline int c3cn_flag(struct s3_conn *c3cn, enum c3cn_flags flag)162162-{163163- if (c3cn == NULL)164164- return 0;165165- return test_bit(flag, &c3cn->flags);166166-}167167-168168-static void c3cn_set_state(struct s3_conn *c3cn, int state)169169-{170170- c3cn_conn_debug("c3cn 0x%p state -> %u.\n", c3cn, state);171171- c3cn->state = state;172172-}173173-174174-static inline void c3cn_hold(struct s3_conn *c3cn)175175-{176176- atomic_inc(&c3cn->refcnt);177177-}178178-179179-static inline void c3cn_put(struct s3_conn *c3cn)180180-{181181- if (atomic_dec_and_test(&c3cn->refcnt)) {182182- c3cn_conn_debug("free c3cn 0x%p, s %u, f 0x%lx.\n",183183- c3cn, c3cn->state, c3cn->flags);184184- kfree(c3cn);185185- }186186-}187187-188188-static void c3cn_closed(struct s3_conn *c3cn)189189-{190190- c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n",191191- c3cn, c3cn->state, c3cn->flags);192192-193193- c3cn_put_port(c3cn);194194- c3cn_release_offload_resources(c3cn);195195- c3cn_set_state(c3cn, C3CN_STATE_CLOSED);196196- cxgb3i_conn_closing(c3cn);197197-}198198-199199-/*200200- * CPL (Chelsio Protocol Language) defines a message passing interface between201201- * the host driver and T3 asic.202202- * The section below implments CPLs that related to iscsi tcp connection203203- * open/close/abort and data send/receive.204204- */205205-206206-/*207207- * CPL connection active open request: host ->208208- */209209-static unsigned int find_best_mtu(const struct t3c_data *d, unsigned short mtu)210210-{211211- int i = 0;212212-213213- while (i < d->nmtus - 1 && d->mtus[i + 1] <= mtu)214214- ++i;215215- return i;216216-}217217-218218-static unsigned int select_mss(struct s3_conn *c3cn, unsigned int pmtu)219219-{220220- unsigned int idx;221221- struct dst_entry *dst = c3cn->dst_cache;222222- struct t3cdev *cdev = c3cn->cdev;223223- const struct t3c_data *td = T3C_DATA(cdev);224224- u16 advmss = dst_metric(dst, RTAX_ADVMSS);225225-226226- if (advmss > pmtu - 40)227227- advmss = pmtu - 40;228228- if (advmss < td->mtus[0] - 40)229229- advmss = td->mtus[0] - 40;230230- idx = find_best_mtu(td, advmss + 40);231231- return idx;232232-}233233-234234-static inline int compute_wscale(int win)235235-{236236- int wscale = 0;237237- while (wscale < 14 && (65535<<wscale) < win)238238- wscale++;239239- return wscale;240240-}241241-242242-static inline unsigned int calc_opt0h(struct s3_conn *c3cn)243243-{244244- int wscale = compute_wscale(cxgb3_rcv_win);245245- return V_KEEP_ALIVE(1) |246246- F_TCAM_BYPASS |247247- V_WND_SCALE(wscale) |248248- V_MSS_IDX(c3cn->mss_idx);249249-}250250-251251-static inline unsigned int calc_opt0l(struct s3_conn *c3cn)252252-{253253- return V_ULP_MODE(ULP_MODE_ISCSI) |254254- V_RCV_BUFSIZ(cxgb3_rcv_win>>10);255255-}256256-257257-static void make_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb,258258- unsigned int atid, const struct l2t_entry *e)259259-{260260- struct cpl_act_open_req *req;261261-262262- c3cn_conn_debug("c3cn 0x%p, atid 0x%x.\n", c3cn, atid);263263-264264- skb->priority = CPL_PRIORITY_SETUP;265265- req = (struct cpl_act_open_req *)__skb_put(skb, sizeof(*req));266266- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));267267- req->wr.wr_lo = 0;268268- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, atid));269269- req->local_port = c3cn->saddr.sin_port;270270- req->peer_port = c3cn->daddr.sin_port;271271- req->local_ip = c3cn->saddr.sin_addr.s_addr;272272- req->peer_ip = c3cn->daddr.sin_addr.s_addr;273273- req->opt0h = htonl(calc_opt0h(c3cn) | V_L2T_IDX(e->idx) |274274- V_TX_CHANNEL(e->smt_idx));275275- req->opt0l = htonl(calc_opt0l(c3cn));276276- req->params = 0;277277- req->opt2 = 0;278278-}279279-280280-static void fail_act_open(struct s3_conn *c3cn, int errno)281281-{282282- c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n",283283- c3cn, c3cn->state, c3cn->flags);284284- c3cn->err = errno;285285- c3cn_closed(c3cn);286286-}287287-288288-static void act_open_req_arp_failure(struct t3cdev *dev, struct sk_buff *skb)289289-{290290- struct s3_conn *c3cn = (struct s3_conn *)skb->sk;291291-292292- c3cn_conn_debug("c3cn 0x%p, state %u.\n", c3cn, c3cn->state);293293-294294- c3cn_hold(c3cn);295295- spin_lock_bh(&c3cn->lock);296296- if (c3cn->state == C3CN_STATE_CONNECTING)297297- fail_act_open(c3cn, -EHOSTUNREACH);298298- spin_unlock_bh(&c3cn->lock);299299- c3cn_put(c3cn);300300- __kfree_skb(skb);301301-}302302-303303-/*304304- * CPL connection close request: host ->305305- *306306- * Close a connection by sending a CPL_CLOSE_CON_REQ message and queue it to307307- * the write queue (i.e., after any unsent txt data).308308- */309309-static void skb_entail(struct s3_conn *c3cn, struct sk_buff *skb,310310- int flags)311311-{312312- skb_tcp_seq(skb) = c3cn->write_seq;313313- skb_flags(skb) = flags;314314- __skb_queue_tail(&c3cn->write_queue, skb);315315-}316316-317317-static void send_close_req(struct s3_conn *c3cn)318318-{319319- struct sk_buff *skb = c3cn->cpl_close;320320- struct cpl_close_con_req *req = (struct cpl_close_con_req *)skb->head;321321- unsigned int tid = c3cn->tid;322322-323323- c3cn_conn_debug("c3cn 0x%p, state 0x%x, flag 0x%lx.\n",324324- c3cn, c3cn->state, c3cn->flags);325325-326326- c3cn->cpl_close = NULL;327327-328328- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_CLOSE_CON));329329- req->wr.wr_lo = htonl(V_WR_TID(tid));330330- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid));331331- req->rsvd = htonl(c3cn->write_seq);332332-333333- skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND);334334- if (c3cn->state != C3CN_STATE_CONNECTING)335335- c3cn_push_tx_frames(c3cn, 1);336336-}337337-338338-/*339339- * CPL connection abort request: host ->340340- *341341- * Send an ABORT_REQ message. Makes sure we do not send multiple ABORT_REQs342342- * for the same connection and also that we do not try to send a message343343- * after the connection has closed.344344- */345345-static void abort_arp_failure(struct t3cdev *cdev, struct sk_buff *skb)346346-{347347- struct cpl_abort_req *req = cplhdr(skb);348348-349349- c3cn_conn_debug("tdev 0x%p.\n", cdev);350350-351351- req->cmd = CPL_ABORT_NO_RST;352352- cxgb3_ofld_send(cdev, skb);353353-}354354-355355-static inline void c3cn_purge_write_queue(struct s3_conn *c3cn)356356-{357357- struct sk_buff *skb;358358-359359- while ((skb = __skb_dequeue(&c3cn->write_queue)))360360- __kfree_skb(skb);361361-}362362-363363-static void send_abort_req(struct s3_conn *c3cn)364364-{365365- struct sk_buff *skb = c3cn->cpl_abort_req;366366- struct cpl_abort_req *req;367367- unsigned int tid = c3cn->tid;368368-369369- if (unlikely(c3cn->state == C3CN_STATE_ABORTING) || !skb ||370370- !c3cn->cdev)371371- return;372372-373373- c3cn_set_state(c3cn, C3CN_STATE_ABORTING);374374-375375- c3cn_conn_debug("c3cn 0x%p, flag ABORT_RPL + ABORT_SHUT.\n", c3cn);376376-377377- c3cn_set_flag(c3cn, C3CN_ABORT_RPL_PENDING);378378-379379- /* Purge the send queue so we don't send anything after an abort. */380380- c3cn_purge_write_queue(c3cn);381381-382382- c3cn->cpl_abort_req = NULL;383383- req = (struct cpl_abort_req *)skb->head;384384- memset(req, 0, sizeof(*req));385385-386386- skb->priority = CPL_PRIORITY_DATA;387387- set_arp_failure_handler(skb, abort_arp_failure);388388-389389- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ));390390- req->wr.wr_lo = htonl(V_WR_TID(tid));391391- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, tid));392392- req->rsvd0 = htonl(c3cn->snd_nxt);393393- req->rsvd1 = !c3cn_flag(c3cn, C3CN_TX_DATA_SENT);394394- req->cmd = CPL_ABORT_SEND_RST;395395-396396- l2t_send(c3cn->cdev, skb, c3cn->l2t);397397-}398398-399399-/*400400- * CPL connection abort reply: host ->401401- *402402- * Send an ABORT_RPL message in response of the ABORT_REQ received.403403- */404404-static void send_abort_rpl(struct s3_conn *c3cn, int rst_status)405405-{406406- struct sk_buff *skb = c3cn->cpl_abort_rpl;407407- struct cpl_abort_rpl *rpl = (struct cpl_abort_rpl *)skb->head;408408-409409- c3cn->cpl_abort_rpl = NULL;410410-411411- skb->priority = CPL_PRIORITY_DATA;412412- memset(rpl, 0, sizeof(*rpl));413413- rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));414414- rpl->wr.wr_lo = htonl(V_WR_TID(c3cn->tid));415415- OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, c3cn->tid));416416- rpl->cmd = rst_status;417417-418418- cxgb3_ofld_send(c3cn->cdev, skb);419419-}420420-421421-/*422422- * CPL connection rx data ack: host ->423423- * Send RX credits through an RX_DATA_ACK CPL message. Returns the number of424424- * credits sent.425425- */426426-static u32 send_rx_credits(struct s3_conn *c3cn, u32 credits, u32 dack)427427-{428428- struct sk_buff *skb;429429- struct cpl_rx_data_ack *req;430430-431431- skb = alloc_skb(sizeof(*req), GFP_ATOMIC);432432- if (!skb)433433- return 0;434434-435435- req = (struct cpl_rx_data_ack *)__skb_put(skb, sizeof(*req));436436- req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));437437- req->wr.wr_lo = 0;438438- OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, c3cn->tid));439439- req->credit_dack = htonl(dack | V_RX_CREDITS(credits));440440- skb->priority = CPL_PRIORITY_ACK;441441- cxgb3_ofld_send(c3cn->cdev, skb);442442- return credits;443443-}444444-445445-/*446446- * CPL connection tx data: host ->447447- *448448- * Send iscsi PDU via TX_DATA CPL message. Returns the number of449449- * credits sent.450450- * Each TX_DATA consumes work request credit (wrs), so we need to keep track of451451- * how many we've used so far and how many are pending (i.e., yet ack'ed by T3).452452- */453453-454454-/*455455- * For ULP connections HW may inserts digest bytes into the pdu. Those digest456456- * bytes are not sent by the host but are part of the TCP payload and therefore457457- * consume TCP sequence space.458458- */459459-static const unsigned int cxgb3_ulp_extra_len[] = { 0, 4, 4, 8 };460460-static inline unsigned int ulp_extra_len(const struct sk_buff *skb)461461-{462462- return cxgb3_ulp_extra_len[skb_ulp_mode(skb) & 3];463463-}464464-465465-static unsigned int wrlen __read_mostly;466466-467467-/*468468- * The number of WRs needed for an skb depends on the number of fragments469469- * in the skb and whether it has any payload in its main body. This maps the470470- * length of the gather list represented by an skb into the # of necessary WRs.471471- * The extra two fragments are for iscsi bhs and payload padding.472472- */473473-#define SKB_WR_LIST_SIZE (MAX_SKB_FRAGS + 2)474474-static unsigned int skb_wrs[SKB_WR_LIST_SIZE] __read_mostly;475475-476476-static void s3_init_wr_tab(unsigned int wr_len)477477-{478478- int i;479479-480480- if (skb_wrs[1]) /* already initialized */481481- return;482482-483483- for (i = 1; i < SKB_WR_LIST_SIZE; i++) {484484- int sgl_len = (3 * i) / 2 + (i & 1);485485-486486- sgl_len += 3;487487- skb_wrs[i] = (sgl_len <= wr_len488488- ? 1 : 1 + (sgl_len - 2) / (wr_len - 1));489489- }490490-491491- wrlen = wr_len * 8;492492-}493493-494494-static inline void reset_wr_list(struct s3_conn *c3cn)495495-{496496- c3cn->wr_pending_head = c3cn->wr_pending_tail = NULL;497497-}498498-499499-/*500500- * Add a WR to a connections's list of pending WRs. This is a singly-linked501501- * list of sk_buffs operating as a FIFO. The head is kept in wr_pending_head502502- * and the tail in wr_pending_tail.503503- */504504-static inline void enqueue_wr(struct s3_conn *c3cn,505505- struct sk_buff *skb)506506-{507507- skb_tx_wr_next(skb) = NULL;508508-509509- /*510510- * We want to take an extra reference since both us and the driver511511- * need to free the packet before it's really freed. We know there's512512- * just one user currently so we use atomic_set rather than skb_get513513- * to avoid the atomic op.514514- */515515- atomic_set(&skb->users, 2);516516-517517- if (!c3cn->wr_pending_head)518518- c3cn->wr_pending_head = skb;519519- else520520- skb_tx_wr_next(c3cn->wr_pending_tail) = skb;521521- c3cn->wr_pending_tail = skb;522522-}523523-524524-static int count_pending_wrs(struct s3_conn *c3cn)525525-{526526- int n = 0;527527- const struct sk_buff *skb = c3cn->wr_pending_head;528528-529529- while (skb) {530530- n += skb->csum;531531- skb = skb_tx_wr_next(skb);532532- }533533- return n;534534-}535535-536536-static inline struct sk_buff *peek_wr(const struct s3_conn *c3cn)537537-{538538- return c3cn->wr_pending_head;539539-}540540-541541-static inline void free_wr_skb(struct sk_buff *skb)542542-{543543- kfree_skb(skb);544544-}545545-546546-static inline struct sk_buff *dequeue_wr(struct s3_conn *c3cn)547547-{548548- struct sk_buff *skb = c3cn->wr_pending_head;549549-550550- if (likely(skb)) {551551- /* Don't bother clearing the tail */552552- c3cn->wr_pending_head = skb_tx_wr_next(skb);553553- skb_tx_wr_next(skb) = NULL;554554- }555555- return skb;556556-}557557-558558-static void purge_wr_queue(struct s3_conn *c3cn)559559-{560560- struct sk_buff *skb;561561- while ((skb = dequeue_wr(c3cn)) != NULL)562562- free_wr_skb(skb);563563-}564564-565565-static inline void make_tx_data_wr(struct s3_conn *c3cn, struct sk_buff *skb,566566- int len, int req_completion)567567-{568568- struct tx_data_wr *req;569569-570570- skb_reset_transport_header(skb);571571- req = (struct tx_data_wr *)__skb_push(skb, sizeof(*req));572572- req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA) |573573- (req_completion ? F_WR_COMPL : 0));574574- req->wr_lo = htonl(V_WR_TID(c3cn->tid));575575- req->sndseq = htonl(c3cn->snd_nxt);576576- /* len includes the length of any HW ULP additions */577577- req->len = htonl(len);578578- req->param = htonl(V_TX_PORT(c3cn->l2t->smt_idx));579579- /* V_TX_ULP_SUBMODE sets both the mode and submode */580580- req->flags = htonl(V_TX_ULP_SUBMODE(skb_ulp_mode(skb)) |581581- V_TX_SHOVE((skb_peek(&c3cn->write_queue) ? 0 : 1)));582582-583583- if (!c3cn_flag(c3cn, C3CN_TX_DATA_SENT)) {584584- req->flags |= htonl(V_TX_ACK_PAGES(2) | F_TX_INIT |585585- V_TX_CPU_IDX(c3cn->qset));586586- /* Sendbuffer is in units of 32KB. */587587- req->param |= htonl(V_TX_SNDBUF(cxgb3_snd_win >> 15));588588- c3cn_set_flag(c3cn, C3CN_TX_DATA_SENT);589589- }590590-}591591-592592-/**593593- * c3cn_push_tx_frames -- start transmit594594- * @c3cn: the offloaded connection595595- * @req_completion: request wr_ack or not596596- *597597- * Prepends TX_DATA_WR or CPL_CLOSE_CON_REQ headers to buffers waiting in a598598- * connection's send queue and sends them on to T3. Must be called with the599599- * connection's lock held. Returns the amount of send buffer space that was600600- * freed as a result of sending queued data to T3.601601- */602602-static void arp_failure_discard(struct t3cdev *cdev, struct sk_buff *skb)603603-{604604- kfree_skb(skb);605605-}606606-607607-static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion)608608-{609609- int total_size = 0;610610- struct sk_buff *skb;611611- struct t3cdev *cdev;612612- struct cxgb3i_sdev_data *cdata;613613-614614- if (unlikely(c3cn->state == C3CN_STATE_CONNECTING ||615615- c3cn->state == C3CN_STATE_CLOSE_WAIT_1 ||616616- c3cn->state >= C3CN_STATE_ABORTING)) {617617- c3cn_tx_debug("c3cn 0x%p, in closing state %u.\n",618618- c3cn, c3cn->state);619619- return 0;620620- }621621-622622- cdev = c3cn->cdev;623623- cdata = CXGB3_SDEV_DATA(cdev);624624-625625- while (c3cn->wr_avail626626- && (skb = skb_peek(&c3cn->write_queue)) != NULL) {627627- int len = skb->len; /* length before skb_push */628628- int frags = skb_shinfo(skb)->nr_frags + (len != skb->data_len);629629- int wrs_needed = skb_wrs[frags];630630-631631- if (wrs_needed > 1 && len + sizeof(struct tx_data_wr) <= wrlen)632632- wrs_needed = 1;633633-634634- WARN_ON(frags >= SKB_WR_LIST_SIZE || wrs_needed < 1);635635-636636- if (c3cn->wr_avail < wrs_needed) {637637- c3cn_tx_debug("c3cn 0x%p, skb len %u/%u, frag %u, "638638- "wr %d < %u.\n",639639- c3cn, skb->len, skb->data_len, frags,640640- wrs_needed, c3cn->wr_avail);641641- break;642642- }643643-644644- __skb_unlink(skb, &c3cn->write_queue);645645- skb->priority = CPL_PRIORITY_DATA;646646- skb->csum = wrs_needed; /* remember this until the WR_ACK */647647- c3cn->wr_avail -= wrs_needed;648648- c3cn->wr_unacked += wrs_needed;649649- enqueue_wr(c3cn, skb);650650-651651- c3cn_tx_debug("c3cn 0x%p, enqueue, skb len %u/%u, frag %u, "652652- "wr %d, left %u, unack %u.\n",653653- c3cn, skb->len, skb->data_len, frags,654654- wrs_needed, c3cn->wr_avail, c3cn->wr_unacked);655655-656656-657657- if (likely(skb_flags(skb) & C3CB_FLAG_NEED_HDR)) {658658- if ((req_completion &&659659- c3cn->wr_unacked == wrs_needed) ||660660- (skb_flags(skb) & C3CB_FLAG_COMPL) ||661661- c3cn->wr_unacked >= c3cn->wr_max / 2) {662662- req_completion = 1;663663- c3cn->wr_unacked = 0;664664- }665665- len += ulp_extra_len(skb);666666- make_tx_data_wr(c3cn, skb, len, req_completion);667667- c3cn->snd_nxt += len;668668- skb_flags(skb) &= ~C3CB_FLAG_NEED_HDR;669669- }670670-671671- total_size += skb->truesize;672672- set_arp_failure_handler(skb, arp_failure_discard);673673- l2t_send(cdev, skb, c3cn->l2t);674674- }675675- return total_size;676676-}677677-678678-/*679679- * process_cpl_msg: -> host680680- * Top-level CPL message processing used by most CPL messages that681681- * pertain to connections.682682- */683683-static inline void process_cpl_msg(void (*fn)(struct s3_conn *,684684- struct sk_buff *),685685- struct s3_conn *c3cn,686686- struct sk_buff *skb)687687-{688688- spin_lock_bh(&c3cn->lock);689689- fn(c3cn, skb);690690- spin_unlock_bh(&c3cn->lock);691691-}692692-693693-/*694694- * process_cpl_msg_ref: -> host695695- * Similar to process_cpl_msg() but takes an extra connection reference around696696- * the call to the handler. Should be used if the handler may drop a697697- * connection reference.698698- */699699-static inline void process_cpl_msg_ref(void (*fn) (struct s3_conn *,700700- struct sk_buff *),701701- struct s3_conn *c3cn,702702- struct sk_buff *skb)703703-{704704- c3cn_hold(c3cn);705705- process_cpl_msg(fn, c3cn, skb);706706- c3cn_put(c3cn);707707-}708708-709709-/*710710- * Process a CPL_ACT_ESTABLISH message: -> host711711- * Updates connection state from an active establish CPL message. Runs with712712- * the connection lock held.713713- */714714-715715-static inline void s3_free_atid(struct t3cdev *cdev, unsigned int tid)716716-{717717- struct s3_conn *c3cn = cxgb3_free_atid(cdev, tid);718718- if (c3cn)719719- c3cn_put(c3cn);720720-}721721-722722-static void c3cn_established(struct s3_conn *c3cn, u32 snd_isn,723723- unsigned int opt)724724-{725725- c3cn_conn_debug("c3cn 0x%p, state %u.\n", c3cn, c3cn->state);726726-727727- c3cn->write_seq = c3cn->snd_nxt = c3cn->snd_una = snd_isn;728728-729729- /*730730- * Causes the first RX_DATA_ACK to supply any Rx credits we couldn't731731- * pass through opt0.732732- */733733- if (cxgb3_rcv_win > (M_RCV_BUFSIZ << 10))734734- c3cn->rcv_wup -= cxgb3_rcv_win - (M_RCV_BUFSIZ << 10);735735-736736- dst_confirm(c3cn->dst_cache);737737-738738- smp_mb();739739-740740- c3cn_set_state(c3cn, C3CN_STATE_ESTABLISHED);741741-}742742-743743-static void process_act_establish(struct s3_conn *c3cn, struct sk_buff *skb)744744-{745745- struct cpl_act_establish *req = cplhdr(skb);746746- u32 rcv_isn = ntohl(req->rcv_isn); /* real RCV_ISN + 1 */747747-748748- c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n",749749- c3cn, c3cn->state, c3cn->flags);750750-751751- if (unlikely(c3cn->state != C3CN_STATE_CONNECTING))752752- cxgb3i_log_error("TID %u expected SYN_SENT, got EST., s %u\n",753753- c3cn->tid, c3cn->state);754754-755755- c3cn->copied_seq = c3cn->rcv_wup = c3cn->rcv_nxt = rcv_isn;756756- c3cn_established(c3cn, ntohl(req->snd_isn), ntohs(req->tcp_opt));757757-758758- __kfree_skb(skb);759759-760760- if (unlikely(c3cn_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED)))761761- /* upper layer has requested closing */762762- send_abort_req(c3cn);763763- else {764764- if (skb_queue_len(&c3cn->write_queue))765765- c3cn_push_tx_frames(c3cn, 1);766766- cxgb3i_conn_tx_open(c3cn);767767- }768768-}769769-770770-static int do_act_establish(struct t3cdev *cdev, struct sk_buff *skb,771771- void *ctx)772772-{773773- struct cpl_act_establish *req = cplhdr(skb);774774- unsigned int tid = GET_TID(req);775775- unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));776776- struct s3_conn *c3cn = ctx;777777- struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev);778778-779779- c3cn_conn_debug("rcv, tid 0x%x, c3cn 0x%p, s %u, f 0x%lx.\n",780780- tid, c3cn, c3cn->state, c3cn->flags);781781-782782- c3cn->tid = tid;783783- c3cn_hold(c3cn);784784- cxgb3_insert_tid(cdata->cdev, cdata->client, c3cn, tid);785785- s3_free_atid(cdev, atid);786786-787787- c3cn->qset = G_QNUM(ntohl(skb->csum));788788-789789- process_cpl_msg(process_act_establish, c3cn, skb);790790- return 0;791791-}792792-793793-/*794794- * Process a CPL_ACT_OPEN_RPL message: -> host795795- * Handle active open failures.796796- */797797-static int act_open_rpl_status_to_errno(int status)798798-{799799- switch (status) {800800- case CPL_ERR_CONN_RESET:801801- return -ECONNREFUSED;802802- case CPL_ERR_ARP_MISS:803803- return -EHOSTUNREACH;804804- case CPL_ERR_CONN_TIMEDOUT:805805- return -ETIMEDOUT;806806- case CPL_ERR_TCAM_FULL:807807- return -ENOMEM;808808- case CPL_ERR_CONN_EXIST:809809- cxgb3i_log_error("ACTIVE_OPEN_RPL: 4-tuple in use\n");810810- return -EADDRINUSE;811811- default:812812- return -EIO;813813- }814814-}815815-816816-static void act_open_retry_timer(unsigned long data)817817-{818818- struct sk_buff *skb;819819- struct s3_conn *c3cn = (struct s3_conn *)data;820820-821821- c3cn_conn_debug("c3cn 0x%p, state %u.\n", c3cn, c3cn->state);822822-823823- spin_lock_bh(&c3cn->lock);824824- skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_ATOMIC);825825- if (!skb)826826- fail_act_open(c3cn, -ENOMEM);827827- else {828828- skb->sk = (struct sock *)c3cn;829829- set_arp_failure_handler(skb, act_open_req_arp_failure);830830- make_act_open_req(c3cn, skb, c3cn->tid, c3cn->l2t);831831- l2t_send(c3cn->cdev, skb, c3cn->l2t);832832- }833833- spin_unlock_bh(&c3cn->lock);834834- c3cn_put(c3cn);835835-}836836-837837-static void process_act_open_rpl(struct s3_conn *c3cn, struct sk_buff *skb)838838-{839839- struct cpl_act_open_rpl *rpl = cplhdr(skb);840840-841841- c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n",842842- c3cn, c3cn->state, c3cn->flags);843843-844844- if (rpl->status == CPL_ERR_CONN_EXIST &&845845- c3cn->retry_timer.function != act_open_retry_timer) {846846- c3cn->retry_timer.function = act_open_retry_timer;847847- if (!mod_timer(&c3cn->retry_timer, jiffies + HZ / 2))848848- c3cn_hold(c3cn);849849- } else850850- fail_act_open(c3cn, act_open_rpl_status_to_errno(rpl->status));851851- __kfree_skb(skb);852852-}853853-854854-static int do_act_open_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx)855855-{856856- struct s3_conn *c3cn = ctx;857857- struct cpl_act_open_rpl *rpl = cplhdr(skb);858858-859859- c3cn_conn_debug("rcv, status 0x%x, c3cn 0x%p, s %u, f 0x%lx.\n",860860- rpl->status, c3cn, c3cn->state, c3cn->flags);861861-862862- if (rpl->status != CPL_ERR_TCAM_FULL &&863863- rpl->status != CPL_ERR_CONN_EXIST &&864864- rpl->status != CPL_ERR_ARP_MISS)865865- cxgb3_queue_tid_release(cdev, GET_TID(rpl));866866-867867- process_cpl_msg_ref(process_act_open_rpl, c3cn, skb);868868- return 0;869869-}870870-871871-/*872872- * Process PEER_CLOSE CPL messages: -> host873873- * Handle peer FIN.874874- */875875-static void process_peer_close(struct s3_conn *c3cn, struct sk_buff *skb)876876-{877877- c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n",878878- c3cn, c3cn->state, c3cn->flags);879879-880880- if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING))881881- goto out;882882-883883- switch (c3cn->state) {884884- case C3CN_STATE_ESTABLISHED:885885- c3cn_set_state(c3cn, C3CN_STATE_PASSIVE_CLOSE);886886- break;887887- case C3CN_STATE_ACTIVE_CLOSE:888888- c3cn_set_state(c3cn, C3CN_STATE_CLOSE_WAIT_2);889889- break;890890- case C3CN_STATE_CLOSE_WAIT_1:891891- c3cn_closed(c3cn);892892- break;893893- case C3CN_STATE_ABORTING:894894- break;895895- default:896896- cxgb3i_log_error("%s: peer close, TID %u in bad state %u\n",897897- c3cn->cdev->name, c3cn->tid, c3cn->state);898898- }899899-900900- cxgb3i_conn_closing(c3cn);901901-out:902902- __kfree_skb(skb);903903-}904904-905905-static int do_peer_close(struct t3cdev *cdev, struct sk_buff *skb, void *ctx)906906-{907907- struct s3_conn *c3cn = ctx;908908-909909- c3cn_conn_debug("rcv, c3cn 0x%p, s %u, f 0x%lx.\n",910910- c3cn, c3cn->state, c3cn->flags);911911- process_cpl_msg_ref(process_peer_close, c3cn, skb);912912- return 0;913913-}914914-915915-/*916916- * Process CLOSE_CONN_RPL CPL message: -> host917917- * Process a peer ACK to our FIN.918918- */919919-static void process_close_con_rpl(struct s3_conn *c3cn, struct sk_buff *skb)920920-{921921- struct cpl_close_con_rpl *rpl = cplhdr(skb);922922-923923- c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n",924924- c3cn, c3cn->state, c3cn->flags);925925-926926- c3cn->snd_una = ntohl(rpl->snd_nxt) - 1; /* exclude FIN */927927-928928- if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING))929929- goto out;930930-931931- switch (c3cn->state) {932932- case C3CN_STATE_ACTIVE_CLOSE:933933- c3cn_set_state(c3cn, C3CN_STATE_CLOSE_WAIT_1);934934- break;935935- case C3CN_STATE_CLOSE_WAIT_1:936936- case C3CN_STATE_CLOSE_WAIT_2:937937- c3cn_closed(c3cn);938938- break;939939- case C3CN_STATE_ABORTING:940940- break;941941- default:942942- cxgb3i_log_error("%s: close_rpl, TID %u in bad state %u\n",943943- c3cn->cdev->name, c3cn->tid, c3cn->state);944944- }945945-946946-out:947947- kfree_skb(skb);948948-}949949-950950-static int do_close_con_rpl(struct t3cdev *cdev, struct sk_buff *skb,951951- void *ctx)952952-{953953- struct s3_conn *c3cn = ctx;954954-955955- c3cn_conn_debug("rcv, c3cn 0x%p, s %u, f 0x%lx.\n",956956- c3cn, c3cn->state, c3cn->flags);957957-958958- process_cpl_msg_ref(process_close_con_rpl, c3cn, skb);959959- return 0;960960-}961961-962962-/*963963- * Process ABORT_REQ_RSS CPL message: -> host964964- * Process abort requests. If we are waiting for an ABORT_RPL we ignore this965965- * request except that we need to reply to it.966966- */967967-968968-static int abort_status_to_errno(struct s3_conn *c3cn, int abort_reason,969969- int *need_rst)970970-{971971- switch (abort_reason) {972972- case CPL_ERR_BAD_SYN: /* fall through */973973- case CPL_ERR_CONN_RESET:974974- return c3cn->state > C3CN_STATE_ESTABLISHED ?975975- -EPIPE : -ECONNRESET;976976- case CPL_ERR_XMIT_TIMEDOUT:977977- case CPL_ERR_PERSIST_TIMEDOUT:978978- case CPL_ERR_FINWAIT2_TIMEDOUT:979979- case CPL_ERR_KEEPALIVE_TIMEDOUT:980980- return -ETIMEDOUT;981981- default:982982- return -EIO;983983- }984984-}985985-986986-static void process_abort_req(struct s3_conn *c3cn, struct sk_buff *skb)987987-{988988- int rst_status = CPL_ABORT_NO_RST;989989- const struct cpl_abort_req_rss *req = cplhdr(skb);990990-991991- c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n",992992- c3cn, c3cn->state, c3cn->flags);993993-994994- if (!c3cn_flag(c3cn, C3CN_ABORT_REQ_RCVD)) {995995- c3cn_set_flag(c3cn, C3CN_ABORT_REQ_RCVD);996996- c3cn_set_state(c3cn, C3CN_STATE_ABORTING);997997- __kfree_skb(skb);998998- return;999999- }10001000-10011001- c3cn_clear_flag(c3cn, C3CN_ABORT_REQ_RCVD);10021002- send_abort_rpl(c3cn, rst_status);10031003-10041004- if (!c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) {10051005- c3cn->err =10061006- abort_status_to_errno(c3cn, req->status, &rst_status);10071007- c3cn_closed(c3cn);10081008- }10091009-}10101010-10111011-static int do_abort_req(struct t3cdev *cdev, struct sk_buff *skb, void *ctx)10121012-{10131013- const struct cpl_abort_req_rss *req = cplhdr(skb);10141014- struct s3_conn *c3cn = ctx;10151015-10161016- c3cn_conn_debug("rcv, c3cn 0x%p, s 0x%x, f 0x%lx.\n",10171017- c3cn, c3cn->state, c3cn->flags);10181018-10191019- if (req->status == CPL_ERR_RTX_NEG_ADVICE ||10201020- req->status == CPL_ERR_PERSIST_NEG_ADVICE) {10211021- __kfree_skb(skb);10221022- return 0;10231023- }10241024-10251025- process_cpl_msg_ref(process_abort_req, c3cn, skb);10261026- return 0;10271027-}10281028-10291029-/*10301030- * Process ABORT_RPL_RSS CPL message: -> host10311031- * Process abort replies. We only process these messages if we anticipate10321032- * them as the coordination between SW and HW in this area is somewhat lacking10331033- * and sometimes we get ABORT_RPLs after we are done with the connection that10341034- * originated the ABORT_REQ.10351035- */10361036-static void process_abort_rpl(struct s3_conn *c3cn, struct sk_buff *skb)10371037-{10381038- c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n",10391039- c3cn, c3cn->state, c3cn->flags);10401040-10411041- if (c3cn_flag(c3cn, C3CN_ABORT_RPL_PENDING)) {10421042- if (!c3cn_flag(c3cn, C3CN_ABORT_RPL_RCVD))10431043- c3cn_set_flag(c3cn, C3CN_ABORT_RPL_RCVD);10441044- else {10451045- c3cn_clear_flag(c3cn, C3CN_ABORT_RPL_RCVD);10461046- c3cn_clear_flag(c3cn, C3CN_ABORT_RPL_PENDING);10471047- if (c3cn_flag(c3cn, C3CN_ABORT_REQ_RCVD))10481048- cxgb3i_log_error("%s tid %u, ABORT_RPL_RSS\n",10491049- c3cn->cdev->name, c3cn->tid);10501050- c3cn_closed(c3cn);10511051- }10521052- }10531053- __kfree_skb(skb);10541054-}10551055-10561056-static int do_abort_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx)10571057-{10581058- struct cpl_abort_rpl_rss *rpl = cplhdr(skb);10591059- struct s3_conn *c3cn = ctx;10601060-10611061- c3cn_conn_debug("rcv, status 0x%x, c3cn 0x%p, s %u, 0x%lx.\n",10621062- rpl->status, c3cn, c3cn ? c3cn->state : 0,10631063- c3cn ? c3cn->flags : 0UL);10641064-10651065- /*10661066- * Ignore replies to post-close aborts indicating that the abort was10671067- * requested too late. These connections are terminated when we get10681068- * PEER_CLOSE or CLOSE_CON_RPL and by the time the abort_rpl_rss10691069- * arrives the TID is either no longer used or it has been recycled.10701070- */10711071- if (rpl->status == CPL_ERR_ABORT_FAILED)10721072- goto discard;10731073-10741074- /*10751075- * Sometimes we've already closed the connection, e.g., a post-close10761076- * abort races with ABORT_REQ_RSS, the latter frees the connection10771077- * expecting the ABORT_REQ will fail with CPL_ERR_ABORT_FAILED,10781078- * but FW turns the ABORT_REQ into a regular one and so we get10791079- * ABORT_RPL_RSS with status 0 and no connection.10801080- */10811081- if (!c3cn)10821082- goto discard;10831083-10841084- process_cpl_msg_ref(process_abort_rpl, c3cn, skb);10851085- return 0;10861086-10871087-discard:10881088- __kfree_skb(skb);10891089- return 0;10901090-}10911091-10921092-/*10931093- * Process RX_ISCSI_HDR CPL message: -> host10941094- * Handle received PDUs, the payload could be DDP'ed. If not, the payload10951095- * follow after the bhs.10961096- */10971097-static void process_rx_iscsi_hdr(struct s3_conn *c3cn, struct sk_buff *skb)10981098-{10991099- struct cpl_iscsi_hdr *hdr_cpl = cplhdr(skb);11001100- struct cpl_iscsi_hdr_norss data_cpl;11011101- struct cpl_rx_data_ddp_norss ddp_cpl;11021102- unsigned int hdr_len, data_len, status;11031103- unsigned int len;11041104- int err;11051105-11061106- if (unlikely(c3cn->state >= C3CN_STATE_PASSIVE_CLOSE)) {11071107- if (c3cn->state != C3CN_STATE_ABORTING)11081108- send_abort_req(c3cn);11091109- __kfree_skb(skb);11101110- return;11111111- }11121112-11131113- skb_tcp_seq(skb) = ntohl(hdr_cpl->seq);11141114- skb_flags(skb) = 0;11151115-11161116- skb_reset_transport_header(skb);11171117- __skb_pull(skb, sizeof(struct cpl_iscsi_hdr));11181118-11191119- len = hdr_len = ntohs(hdr_cpl->len);11201120- /* msg coalesce is off or not enough data received */11211121- if (skb->len <= hdr_len) {11221122- cxgb3i_log_error("%s: TID %u, ISCSI_HDR, skb len %u < %u.\n",11231123- c3cn->cdev->name, c3cn->tid,11241124- skb->len, hdr_len);11251125- goto abort_conn;11261126- }11271127-11281128- err = skb_copy_bits(skb, skb->len - sizeof(ddp_cpl), &ddp_cpl,11291129- sizeof(ddp_cpl));11301130- if (err < 0)11311131- goto abort_conn;11321132-11331133- skb_ulp_mode(skb) = ULP2_FLAG_DATA_READY;11341134- skb_rx_pdulen(skb) = ntohs(ddp_cpl.len);11351135- skb_rx_ddigest(skb) = ntohl(ddp_cpl.ulp_crc);11361136- status = ntohl(ddp_cpl.ddp_status);11371137-11381138- c3cn_rx_debug("rx skb 0x%p, len %u, pdulen %u, ddp status 0x%x.\n",11391139- skb, skb->len, skb_rx_pdulen(skb), status);11401140-11411141- if (status & (1 << RX_DDP_STATUS_HCRC_SHIFT))11421142- skb_ulp_mode(skb) |= ULP2_FLAG_HCRC_ERROR;11431143- if (status & (1 << RX_DDP_STATUS_DCRC_SHIFT))11441144- skb_ulp_mode(skb) |= ULP2_FLAG_DCRC_ERROR;11451145- if (status & (1 << RX_DDP_STATUS_PAD_SHIFT))11461146- skb_ulp_mode(skb) |= ULP2_FLAG_PAD_ERROR;11471147-11481148- if (skb->len > (hdr_len + sizeof(ddp_cpl))) {11491149- err = skb_copy_bits(skb, hdr_len, &data_cpl, sizeof(data_cpl));11501150- if (err < 0)11511151- goto abort_conn;11521152- data_len = ntohs(data_cpl.len);11531153- len += sizeof(data_cpl) + data_len;11541154- } else if (status & (1 << RX_DDP_STATUS_DDP_SHIFT))11551155- skb_ulp_mode(skb) |= ULP2_FLAG_DATA_DDPED;11561156-11571157- c3cn->rcv_nxt = ntohl(ddp_cpl.seq) + skb_rx_pdulen(skb);11581158- __pskb_trim(skb, len);11591159- __skb_queue_tail(&c3cn->receive_queue, skb);11601160- cxgb3i_conn_pdu_ready(c3cn);11611161-11621162- return;11631163-11641164-abort_conn:11651165- send_abort_req(c3cn);11661166- __kfree_skb(skb);11671167-}11681168-11691169-static int do_iscsi_hdr(struct t3cdev *t3dev, struct sk_buff *skb, void *ctx)11701170-{11711171- struct s3_conn *c3cn = ctx;11721172-11731173- process_cpl_msg(process_rx_iscsi_hdr, c3cn, skb);11741174- return 0;11751175-}11761176-11771177-/*11781178- * Process TX_DATA_ACK CPL messages: -> host11791179- * Process an acknowledgment of WR completion. Advance snd_una and send the11801180- * next batch of work requests from the write queue.11811181- */11821182-static void check_wr_invariants(struct s3_conn *c3cn)11831183-{11841184- int pending = count_pending_wrs(c3cn);11851185-11861186- if (unlikely(c3cn->wr_avail + pending != c3cn->wr_max))11871187- cxgb3i_log_error("TID %u: credit imbalance: avail %u, "11881188- "pending %u, total should be %u\n",11891189- c3cn->tid, c3cn->wr_avail, pending,11901190- c3cn->wr_max);11911191-}11921192-11931193-static void process_wr_ack(struct s3_conn *c3cn, struct sk_buff *skb)11941194-{11951195- struct cpl_wr_ack *hdr = cplhdr(skb);11961196- unsigned int credits = ntohs(hdr->credits);11971197- u32 snd_una = ntohl(hdr->snd_una);11981198-11991199- c3cn_tx_debug("%u WR credits, avail %u, unack %u, TID %u, state %u.\n",12001200- credits, c3cn->wr_avail, c3cn->wr_unacked,12011201- c3cn->tid, c3cn->state);12021202-12031203- c3cn->wr_avail += credits;12041204- if (c3cn->wr_unacked > c3cn->wr_max - c3cn->wr_avail)12051205- c3cn->wr_unacked = c3cn->wr_max - c3cn->wr_avail;12061206-12071207- while (credits) {12081208- struct sk_buff *p = peek_wr(c3cn);12091209-12101210- if (unlikely(!p)) {12111211- cxgb3i_log_error("%u WR_ACK credits for TID %u with "12121212- "nothing pending, state %u\n",12131213- credits, c3cn->tid, c3cn->state);12141214- break;12151215- }12161216- if (unlikely(credits < p->csum)) {12171217- struct tx_data_wr *w = cplhdr(p);12181218- cxgb3i_log_error("TID %u got %u WR credits need %u, "12191219- "len %u, main body %u, frags %u, "12201220- "seq # %u, ACK una %u, ACK nxt %u, "12211221- "WR_AVAIL %u, WRs pending %u\n",12221222- c3cn->tid, credits, p->csum, p->len,12231223- p->len - p->data_len,12241224- skb_shinfo(p)->nr_frags,12251225- ntohl(w->sndseq), snd_una,12261226- ntohl(hdr->snd_nxt), c3cn->wr_avail,12271227- count_pending_wrs(c3cn) - credits);12281228- p->csum -= credits;12291229- break;12301230- } else {12311231- dequeue_wr(c3cn);12321232- credits -= p->csum;12331233- free_wr_skb(p);12341234- }12351235- }12361236-12371237- check_wr_invariants(c3cn);12381238-12391239- if (unlikely(before(snd_una, c3cn->snd_una))) {12401240- cxgb3i_log_error("TID %u, unexpected sequence # %u in WR_ACK "12411241- "snd_una %u\n",12421242- c3cn->tid, snd_una, c3cn->snd_una);12431243- goto out_free;12441244- }12451245-12461246- if (c3cn->snd_una != snd_una) {12471247- c3cn->snd_una = snd_una;12481248- dst_confirm(c3cn->dst_cache);12491249- }12501250-12511251- if (skb_queue_len(&c3cn->write_queue)) {12521252- if (c3cn_push_tx_frames(c3cn, 0))12531253- cxgb3i_conn_tx_open(c3cn);12541254- } else12551255- cxgb3i_conn_tx_open(c3cn);12561256-out_free:12571257- __kfree_skb(skb);12581258-}12591259-12601260-static int do_wr_ack(struct t3cdev *cdev, struct sk_buff *skb, void *ctx)12611261-{12621262- struct s3_conn *c3cn = ctx;12631263-12641264- process_cpl_msg(process_wr_ack, c3cn, skb);12651265- return 0;12661266-}12671267-12681268-/*12691269- * for each connection, pre-allocate skbs needed for close/abort requests. So12701270- * that we can service the request right away.12711271- */12721272-static void c3cn_free_cpl_skbs(struct s3_conn *c3cn)12731273-{12741274- if (c3cn->cpl_close)12751275- kfree_skb(c3cn->cpl_close);12761276- if (c3cn->cpl_abort_req)12771277- kfree_skb(c3cn->cpl_abort_req);12781278- if (c3cn->cpl_abort_rpl)12791279- kfree_skb(c3cn->cpl_abort_rpl);12801280-}12811281-12821282-static int c3cn_alloc_cpl_skbs(struct s3_conn *c3cn)12831283-{12841284- c3cn->cpl_close = alloc_skb(sizeof(struct cpl_close_con_req),12851285- GFP_KERNEL);12861286- if (!c3cn->cpl_close)12871287- return -ENOMEM;12881288- skb_put(c3cn->cpl_close, sizeof(struct cpl_close_con_req));12891289-12901290- c3cn->cpl_abort_req = alloc_skb(sizeof(struct cpl_abort_req),12911291- GFP_KERNEL);12921292- if (!c3cn->cpl_abort_req)12931293- goto free_cpl_skbs;12941294- skb_put(c3cn->cpl_abort_req, sizeof(struct cpl_abort_req));12951295-12961296- c3cn->cpl_abort_rpl = alloc_skb(sizeof(struct cpl_abort_rpl),12971297- GFP_KERNEL);12981298- if (!c3cn->cpl_abort_rpl)12991299- goto free_cpl_skbs;13001300- skb_put(c3cn->cpl_abort_rpl, sizeof(struct cpl_abort_rpl));13011301-13021302- return 0;13031303-13041304-free_cpl_skbs:13051305- c3cn_free_cpl_skbs(c3cn);13061306- return -ENOMEM;13071307-}13081308-13091309-/**13101310- * c3cn_release_offload_resources - release offload resource13111311- * @c3cn: the offloaded iscsi tcp connection.13121312- * Release resources held by an offload connection (TID, L2T entry, etc.)13131313- */13141314-static void c3cn_release_offload_resources(struct s3_conn *c3cn)13151315-{13161316- struct t3cdev *cdev = c3cn->cdev;13171317- unsigned int tid = c3cn->tid;13181318-13191319- c3cn->qset = 0;13201320- c3cn_free_cpl_skbs(c3cn);13211321-13221322- if (c3cn->wr_avail != c3cn->wr_max) {13231323- purge_wr_queue(c3cn);13241324- reset_wr_list(c3cn);13251325- }13261326-13271327- if (cdev) {13281328- if (c3cn->l2t) {13291329- l2t_release(L2DATA(cdev), c3cn->l2t);13301330- c3cn->l2t = NULL;13311331- }13321332- if (c3cn->state == C3CN_STATE_CONNECTING)13331333- /* we have ATID */13341334- s3_free_atid(cdev, tid);13351335- else {13361336- /* we have TID */13371337- cxgb3_remove_tid(cdev, (void *)c3cn, tid);13381338- c3cn_put(c3cn);13391339- }13401340- }13411341-13421342- c3cn->dst_cache = NULL;13431343- c3cn->cdev = NULL;13441344-}13451345-13461346-/**13471347- * cxgb3i_c3cn_create - allocate and initialize an s3_conn structure13481348- * returns the s3_conn structure allocated.13491349- */13501350-struct s3_conn *cxgb3i_c3cn_create(void)13511351-{13521352- struct s3_conn *c3cn;13531353-13541354- c3cn = kzalloc(sizeof(*c3cn), GFP_KERNEL);13551355- if (!c3cn)13561356- return NULL;13571357-13581358- /* pre-allocate close/abort cpl, so we don't need to wait for memory13591359- when close/abort is requested. */13601360- if (c3cn_alloc_cpl_skbs(c3cn) < 0)13611361- goto free_c3cn;13621362-13631363- c3cn_conn_debug("alloc c3cn 0x%p.\n", c3cn);13641364-13651365- c3cn->flags = 0;13661366- spin_lock_init(&c3cn->lock);13671367- atomic_set(&c3cn->refcnt, 1);13681368- skb_queue_head_init(&c3cn->receive_queue);13691369- skb_queue_head_init(&c3cn->write_queue);13701370- setup_timer(&c3cn->retry_timer, NULL, (unsigned long)c3cn);13711371- rwlock_init(&c3cn->callback_lock);13721372-13731373- return c3cn;13741374-13751375-free_c3cn:13761376- kfree(c3cn);13771377- return NULL;13781378-}13791379-13801380-static void c3cn_active_close(struct s3_conn *c3cn)13811381-{13821382- int data_lost;13831383- int close_req = 0;13841384-13851385- c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n",13861386- c3cn, c3cn->state, c3cn->flags);13871387-13881388- dst_confirm(c3cn->dst_cache);13891389-13901390- c3cn_hold(c3cn);13911391- spin_lock_bh(&c3cn->lock);13921392-13931393- data_lost = skb_queue_len(&c3cn->receive_queue);13941394- __skb_queue_purge(&c3cn->receive_queue);13951395-13961396- switch (c3cn->state) {13971397- case C3CN_STATE_CLOSED:13981398- case C3CN_STATE_ACTIVE_CLOSE:13991399- case C3CN_STATE_CLOSE_WAIT_1:14001400- case C3CN_STATE_CLOSE_WAIT_2:14011401- case C3CN_STATE_ABORTING:14021402- /* nothing need to be done */14031403- break;14041404- case C3CN_STATE_CONNECTING:14051405- /* defer until cpl_act_open_rpl or cpl_act_establish */14061406- c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED);14071407- break;14081408- case C3CN_STATE_ESTABLISHED:14091409- close_req = 1;14101410- c3cn_set_state(c3cn, C3CN_STATE_ACTIVE_CLOSE);14111411- break;14121412- case C3CN_STATE_PASSIVE_CLOSE:14131413- close_req = 1;14141414- c3cn_set_state(c3cn, C3CN_STATE_CLOSE_WAIT_2);14151415- break;14161416- }14171417-14181418- if (close_req) {14191419- if (data_lost)14201420- /* Unread data was tossed, zap the connection. */14211421- send_abort_req(c3cn);14221422- else14231423- send_close_req(c3cn);14241424- }14251425-14261426- spin_unlock_bh(&c3cn->lock);14271427- c3cn_put(c3cn);14281428-}14291429-14301430-/**14311431- * cxgb3i_c3cn_release - close and release an iscsi tcp connection and any14321432- * resource held14331433- * @c3cn: the iscsi tcp connection14341434- */14351435-void cxgb3i_c3cn_release(struct s3_conn *c3cn)14361436-{14371437- c3cn_conn_debug("c3cn 0x%p, s %u, f 0x%lx.\n",14381438- c3cn, c3cn->state, c3cn->flags);14391439- if (unlikely(c3cn->state == C3CN_STATE_CONNECTING))14401440- c3cn_set_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED);14411441- else if (likely(c3cn->state != C3CN_STATE_CLOSED))14421442- c3cn_active_close(c3cn);14431443- c3cn_put(c3cn);14441444-}14451445-14461446-static int is_cxgb3_dev(struct net_device *dev)14471447-{14481448- struct cxgb3i_sdev_data *cdata;14491449- struct net_device *ndev = dev;14501450-14511451- if (dev->priv_flags & IFF_802_1Q_VLAN)14521452- ndev = vlan_dev_real_dev(dev);14531453-14541454- write_lock(&cdata_rwlock);14551455- list_for_each_entry(cdata, &cdata_list, list) {14561456- struct adap_ports *ports = &cdata->ports;14571457- int i;14581458-14591459- for (i = 0; i < ports->nports; i++)14601460- if (ndev == ports->lldevs[i]) {14611461- write_unlock(&cdata_rwlock);14621462- return 1;14631463- }14641464- }14651465- write_unlock(&cdata_rwlock);14661466- return 0;14671467-}14681468-14691469-/**14701470- * cxgb3_egress_dev - return the cxgb3 egress device14711471- * @root_dev: the root device anchoring the search14721472- * @c3cn: the connection used to determine egress port in bonding mode14731473- * @context: in bonding mode, indicates a connection set up or failover14741474- *14751475- * Return egress device or NULL if the egress device isn't one of our ports.14761476- */14771477-static struct net_device *cxgb3_egress_dev(struct net_device *root_dev,14781478- struct s3_conn *c3cn,14791479- int context)14801480-{14811481- while (root_dev) {14821482- if (root_dev->priv_flags & IFF_802_1Q_VLAN)14831483- root_dev = vlan_dev_real_dev(root_dev);14841484- else if (is_cxgb3_dev(root_dev))14851485- return root_dev;14861486- else14871487- return NULL;14881488- }14891489- return NULL;14901490-}14911491-14921492-static struct rtable *find_route(struct net_device *dev,14931493- __be32 saddr, __be32 daddr,14941494- __be16 sport, __be16 dport)14951495-{14961496- struct rtable *rt;14971497- struct flowi fl = {14981498- .oif = dev ? dev->ifindex : 0,14991499- .nl_u = {15001500- .ip4_u = {15011501- .daddr = daddr,15021502- .saddr = saddr,15031503- .tos = 0 } },15041504- .proto = IPPROTO_TCP,15051505- .uli_u = {15061506- .ports = {15071507- .sport = sport,15081508- .dport = dport } } };15091509-15101510- if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0))15111511- return NULL;15121512- return rt;15131513-}15141514-15151515-/*15161516- * Assign offload parameters to some connection fields.15171517- */15181518-static void init_offload_conn(struct s3_conn *c3cn,15191519- struct t3cdev *cdev,15201520- struct dst_entry *dst)15211521-{15221522- BUG_ON(c3cn->cdev != cdev);15231523- c3cn->wr_max = c3cn->wr_avail = T3C_DATA(cdev)->max_wrs - 1;15241524- c3cn->wr_unacked = 0;15251525- c3cn->mss_idx = select_mss(c3cn, dst_mtu(dst));15261526-15271527- reset_wr_list(c3cn);15281528-}15291529-15301530-static int initiate_act_open(struct s3_conn *c3cn, struct net_device *dev)15311531-{15321532- struct cxgb3i_sdev_data *cdata = NDEV2CDATA(dev);15331533- struct t3cdev *cdev = cdata->cdev;15341534- struct dst_entry *dst = c3cn->dst_cache;15351535- struct sk_buff *skb;15361536-15371537- c3cn_conn_debug("c3cn 0x%p, state %u, flag 0x%lx.\n",15381538- c3cn, c3cn->state, c3cn->flags);15391539- /*15401540- * Initialize connection data. Note that the flags and ULP mode are15411541- * initialized higher up ...15421542- */15431543- c3cn->dev = dev;15441544- c3cn->cdev = cdev;15451545- c3cn->tid = cxgb3_alloc_atid(cdev, cdata->client, c3cn);15461546- if (c3cn->tid < 0)15471547- goto out_err;15481548-15491549- c3cn->qset = 0;15501550- c3cn->l2t = t3_l2t_get(cdev, dst->neighbour, dev);15511551- if (!c3cn->l2t)15521552- goto free_tid;15531553-15541554- skb = alloc_skb(sizeof(struct cpl_act_open_req), GFP_KERNEL);15551555- if (!skb)15561556- goto free_l2t;15571557-15581558- skb->sk = (struct sock *)c3cn;15591559- set_arp_failure_handler(skb, act_open_req_arp_failure);15601560-15611561- c3cn_hold(c3cn);15621562-15631563- init_offload_conn(c3cn, cdev, dst);15641564- c3cn->err = 0;15651565-15661566- make_act_open_req(c3cn, skb, c3cn->tid, c3cn->l2t);15671567- l2t_send(cdev, skb, c3cn->l2t);15681568- return 0;15691569-15701570-free_l2t:15711571- l2t_release(L2DATA(cdev), c3cn->l2t);15721572-free_tid:15731573- s3_free_atid(cdev, c3cn->tid);15741574- c3cn->tid = 0;15751575-out_err:15761576- return -EINVAL;15771577-}15781578-15791579-/**15801580- * cxgb3i_find_dev - find the interface associated with the given address15811581- * @ipaddr: ip address15821582- */15831583-static struct net_device *15841584-cxgb3i_find_dev(struct net_device *dev, __be32 ipaddr)15851585-{15861586- struct flowi fl;15871587- int err;15881588- struct rtable *rt;15891589-15901590- memset(&fl, 0, sizeof(fl));15911591- fl.nl_u.ip4_u.daddr = ipaddr;15921592-15931593- err = ip_route_output_key(dev ? dev_net(dev) : &init_net, &rt, &fl);15941594- if (!err)15951595- return (&rt->dst)->dev;15961596-15971597- return NULL;15981598-}15991599-16001600-/**16011601- * cxgb3i_c3cn_connect - initiates an iscsi tcp connection to a given address16021602- * @c3cn: the iscsi tcp connection16031603- * @usin: destination address16041604- *16051605- * return 0 if active open request is sent, < 0 otherwise.16061606- */16071607-int cxgb3i_c3cn_connect(struct net_device *dev, struct s3_conn *c3cn,16081608- struct sockaddr_in *usin)16091609-{16101610- struct rtable *rt;16111611- struct cxgb3i_sdev_data *cdata;16121612- struct t3cdev *cdev;16131613- __be32 sipv4;16141614- struct net_device *dstdev;16151615- int err;16161616-16171617- c3cn_conn_debug("c3cn 0x%p, dev 0x%p.\n", c3cn, dev);16181618-16191619- if (usin->sin_family != AF_INET)16201620- return -EAFNOSUPPORT;16211621-16221622- c3cn->daddr.sin_port = usin->sin_port;16231623- c3cn->daddr.sin_addr.s_addr = usin->sin_addr.s_addr;16241624-16251625- dstdev = cxgb3i_find_dev(dev, usin->sin_addr.s_addr);16261626- if (!dstdev || !is_cxgb3_dev(dstdev))16271627- return -ENETUNREACH;16281628-16291629- if (dstdev->priv_flags & IFF_802_1Q_VLAN)16301630- dev = dstdev;16311631-16321632- rt = find_route(dev, c3cn->saddr.sin_addr.s_addr,16331633- c3cn->daddr.sin_addr.s_addr,16341634- c3cn->saddr.sin_port,16351635- c3cn->daddr.sin_port);16361636- if (rt == NULL) {16371637- c3cn_conn_debug("NO route to 0x%x, port %u, dev %s.\n",16381638- c3cn->daddr.sin_addr.s_addr,16391639- ntohs(c3cn->daddr.sin_port),16401640- dev ? dev->name : "any");16411641- return -ENETUNREACH;16421642- }16431643-16441644- if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {16451645- c3cn_conn_debug("multi-cast route to 0x%x, port %u, dev %s.\n",16461646- c3cn->daddr.sin_addr.s_addr,16471647- ntohs(c3cn->daddr.sin_port),16481648- dev ? dev->name : "any");16491649- ip_rt_put(rt);16501650- return -ENETUNREACH;16511651- }16521652-16531653- if (!c3cn->saddr.sin_addr.s_addr)16541654- c3cn->saddr.sin_addr.s_addr = rt->rt_src;16551655-16561656- /* now commit destination to connection */16571657- c3cn->dst_cache = &rt->dst;16581658-16591659- /* try to establish an offloaded connection */16601660- dev = cxgb3_egress_dev(c3cn->dst_cache->dev, c3cn, 0);16611661- if (dev == NULL) {16621662- c3cn_conn_debug("c3cn 0x%p, egress dev NULL.\n", c3cn);16631663- return -ENETUNREACH;16641664- }16651665- cdata = NDEV2CDATA(dev);16661666- cdev = cdata->cdev;16671667-16681668- /* get a source port if one hasn't been provided */16691669- err = c3cn_get_port(c3cn, cdata);16701670- if (err)16711671- return err;16721672-16731673- c3cn_conn_debug("c3cn 0x%p get port %u.\n",16741674- c3cn, ntohs(c3cn->saddr.sin_port));16751675-16761676- sipv4 = cxgb3i_get_private_ipv4addr(dev);16771677- if (!sipv4) {16781678- c3cn_conn_debug("c3cn 0x%p, iscsi ip not configured.\n", c3cn);16791679- sipv4 = c3cn->saddr.sin_addr.s_addr;16801680- cxgb3i_set_private_ipv4addr(dev, sipv4);16811681- } else16821682- c3cn->saddr.sin_addr.s_addr = sipv4;16831683-16841684- c3cn_conn_debug("c3cn 0x%p, %pI4,%u-%pI4,%u SYN_SENT.\n",16851685- c3cn,16861686- &c3cn->saddr.sin_addr.s_addr,16871687- ntohs(c3cn->saddr.sin_port),16881688- &c3cn->daddr.sin_addr.s_addr,16891689- ntohs(c3cn->daddr.sin_port));16901690-16911691- c3cn_set_state(c3cn, C3CN_STATE_CONNECTING);16921692- if (!initiate_act_open(c3cn, dev))16931693- return 0;16941694-16951695- /*16961696- * If we get here, we don't have an offload connection so simply16971697- * return a failure.16981698- */16991699- err = -ENOTSUPP;17001700-17011701- /*17021702- * This trashes the connection and releases the local port,17031703- * if necessary.17041704- */17051705- c3cn_conn_debug("c3cn 0x%p -> CLOSED.\n", c3cn);17061706- c3cn_set_state(c3cn, C3CN_STATE_CLOSED);17071707- ip_rt_put(rt);17081708- c3cn_put_port(c3cn);17091709- return err;17101710-}17111711-17121712-/**17131713- * cxgb3i_c3cn_rx_credits - ack received tcp data.17141714- * @c3cn: iscsi tcp connection17151715- * @copied: # of bytes processed17161716- *17171717- * Called after some received data has been read. It returns RX credits17181718- * to the HW for the amount of data processed.17191719- */17201720-void cxgb3i_c3cn_rx_credits(struct s3_conn *c3cn, int copied)17211721-{17221722- struct t3cdev *cdev;17231723- int must_send;17241724- u32 credits, dack = 0;17251725-17261726- if (c3cn->state != C3CN_STATE_ESTABLISHED)17271727- return;17281728-17291729- credits = c3cn->copied_seq - c3cn->rcv_wup;17301730- if (unlikely(!credits))17311731- return;17321732-17331733- cdev = c3cn->cdev;17341734-17351735- if (unlikely(cxgb3_rx_credit_thres == 0))17361736- return;17371737-17381738- dack = F_RX_DACK_CHANGE | V_RX_DACK_MODE(1);17391739-17401740- /*17411741- * For coalescing to work effectively ensure the receive window has17421742- * at least 16KB left.17431743- */17441744- must_send = credits + 16384 >= cxgb3_rcv_win;17451745-17461746- if (must_send || credits >= cxgb3_rx_credit_thres)17471747- c3cn->rcv_wup += send_rx_credits(c3cn, credits, dack);17481748-}17491749-17501750-/**17511751- * cxgb3i_c3cn_send_pdus - send the skbs containing iscsi pdus17521752- * @c3cn: iscsi tcp connection17531753- * @skb: skb contains the iscsi pdu17541754- *17551755- * Add a list of skbs to a connection send queue. The skbs must comply with17561756- * the max size limit of the device and have a headroom of at least17571757- * TX_HEADER_LEN bytes.17581758- * Return # of bytes queued.17591759- */17601760-int cxgb3i_c3cn_send_pdus(struct s3_conn *c3cn, struct sk_buff *skb)17611761-{17621762- struct sk_buff *next;17631763- int err, copied = 0;17641764-17651765- spin_lock_bh(&c3cn->lock);17661766-17671767- if (c3cn->state != C3CN_STATE_ESTABLISHED) {17681768- c3cn_tx_debug("c3cn 0x%p, not in est. state %u.\n",17691769- c3cn, c3cn->state);17701770- err = -EAGAIN;17711771- goto out_err;17721772- }17731773-17741774- if (c3cn->err) {17751775- c3cn_tx_debug("c3cn 0x%p, err %d.\n", c3cn, c3cn->err);17761776- err = -EPIPE;17771777- goto out_err;17781778- }17791779-17801780- if (c3cn->write_seq - c3cn->snd_una >= cxgb3_snd_win) {17811781- c3cn_tx_debug("c3cn 0x%p, snd %u - %u > %u.\n",17821782- c3cn, c3cn->write_seq, c3cn->snd_una,17831783- cxgb3_snd_win);17841784- err = -ENOBUFS;17851785- goto out_err;17861786- }17871787-17881788- while (skb) {17891789- int frags = skb_shinfo(skb)->nr_frags +17901790- (skb->len != skb->data_len);17911791-17921792- if (unlikely(skb_headroom(skb) < TX_HEADER_LEN)) {17931793- c3cn_tx_debug("c3cn 0x%p, skb head.\n", c3cn);17941794- err = -EINVAL;17951795- goto out_err;17961796- }17971797-17981798- if (frags >= SKB_WR_LIST_SIZE) {17991799- cxgb3i_log_error("c3cn 0x%p, tx frags %d, len %u,%u.\n",18001800- c3cn, skb_shinfo(skb)->nr_frags,18011801- skb->len, skb->data_len);18021802- err = -EINVAL;18031803- goto out_err;18041804- }18051805-18061806- next = skb->next;18071807- skb->next = NULL;18081808- skb_entail(c3cn, skb, C3CB_FLAG_NO_APPEND | C3CB_FLAG_NEED_HDR);18091809- copied += skb->len;18101810- c3cn->write_seq += skb->len + ulp_extra_len(skb);18111811- skb = next;18121812- }18131813-done:18141814- if (likely(skb_queue_len(&c3cn->write_queue)))18151815- c3cn_push_tx_frames(c3cn, 1);18161816- spin_unlock_bh(&c3cn->lock);18171817- return copied;18181818-18191819-out_err:18201820- if (copied == 0 && err == -EPIPE)18211821- copied = c3cn->err ? c3cn->err : -EPIPE;18221822- else18231823- copied = err;18241824- goto done;18251825-}18261826-18271827-static void sdev_data_cleanup(struct cxgb3i_sdev_data *cdata)18281828-{18291829- struct adap_ports *ports = &cdata->ports;18301830- struct s3_conn *c3cn;18311831- int i;18321832-18331833- for (i = 0; i < cxgb3_max_connect; i++) {18341834- if (cdata->sport_conn[i]) {18351835- c3cn = cdata->sport_conn[i];18361836- cdata->sport_conn[i] = NULL;18371837-18381838- spin_lock_bh(&c3cn->lock);18391839- c3cn->cdev = NULL;18401840- c3cn_set_flag(c3cn, C3CN_OFFLOAD_DOWN);18411841- c3cn_closed(c3cn);18421842- spin_unlock_bh(&c3cn->lock);18431843- }18441844- }18451845-18461846- for (i = 0; i < ports->nports; i++)18471847- NDEV2CDATA(ports->lldevs[i]) = NULL;18481848-18491849- cxgb3i_free_big_mem(cdata);18501850-}18511851-18521852-void cxgb3i_sdev_cleanup(void)18531853-{18541854- struct cxgb3i_sdev_data *cdata;18551855-18561856- write_lock(&cdata_rwlock);18571857- list_for_each_entry(cdata, &cdata_list, list) {18581858- list_del(&cdata->list);18591859- sdev_data_cleanup(cdata);18601860- }18611861- write_unlock(&cdata_rwlock);18621862-}18631863-18641864-int cxgb3i_sdev_init(cxgb3_cpl_handler_func *cpl_handlers)18651865-{18661866- cpl_handlers[CPL_ACT_ESTABLISH] = do_act_establish;18671867- cpl_handlers[CPL_ACT_OPEN_RPL] = do_act_open_rpl;18681868- cpl_handlers[CPL_PEER_CLOSE] = do_peer_close;18691869- cpl_handlers[CPL_ABORT_REQ_RSS] = do_abort_req;18701870- cpl_handlers[CPL_ABORT_RPL_RSS] = do_abort_rpl;18711871- cpl_handlers[CPL_CLOSE_CON_RPL] = do_close_con_rpl;18721872- cpl_handlers[CPL_TX_DMA_ACK] = do_wr_ack;18731873- cpl_handlers[CPL_ISCSI_HDR] = do_iscsi_hdr;18741874-18751875- if (cxgb3_max_connect > CXGB3I_MAX_CONN)18761876- cxgb3_max_connect = CXGB3I_MAX_CONN;18771877- return 0;18781878-}18791879-18801880-/**18811881- * cxgb3i_sdev_add - allocate and initialize resources for each adapter found18821882- * @cdev: t3cdev adapter18831883- * @client: cxgb3 driver client18841884- */18851885-void cxgb3i_sdev_add(struct t3cdev *cdev, struct cxgb3_client *client)18861886-{18871887- struct cxgb3i_sdev_data *cdata;18881888- struct ofld_page_info rx_page_info;18891889- unsigned int wr_len;18901890- int mapsize = cxgb3_max_connect * sizeof(struct s3_conn *);18911891- int i;18921892-18931893- cdata = cxgb3i_alloc_big_mem(sizeof(*cdata) + mapsize, GFP_KERNEL);18941894- if (!cdata) {18951895- cxgb3i_log_warn("t3dev 0x%p, offload up, OOM %d.\n",18961896- cdev, mapsize);18971897- return;18981898- }18991899-19001900- if (cdev->ctl(cdev, GET_WR_LEN, &wr_len) < 0 ||19011901- cdev->ctl(cdev, GET_PORTS, &cdata->ports) < 0 ||19021902- cdev->ctl(cdev, GET_RX_PAGE_INFO, &rx_page_info) < 0) {19031903- cxgb3i_log_warn("t3dev 0x%p, offload up, ioctl failed.\n",19041904- cdev);19051905- goto free_cdata;19061906- }19071907-19081908- s3_init_wr_tab(wr_len);19091909-19101910- spin_lock_init(&cdata->lock);19111911- INIT_LIST_HEAD(&cdata->list);19121912- cdata->cdev = cdev;19131913- cdata->client = client;19141914-19151915- for (i = 0; i < cdata->ports.nports; i++)19161916- NDEV2CDATA(cdata->ports.lldevs[i]) = cdata;19171917-19181918- write_lock(&cdata_rwlock);19191919- list_add_tail(&cdata->list, &cdata_list);19201920- write_unlock(&cdata_rwlock);19211921-19221922- cxgb3i_log_info("t3dev 0x%p, offload up, added.\n", cdev);19231923- return;19241924-19251925-free_cdata:19261926- cxgb3i_free_big_mem(cdata);19271927-}19281928-19291929-/**19301930- * cxgb3i_sdev_remove - free the allocated resources for the adapter19311931- * @cdev: t3cdev adapter19321932- */19331933-void cxgb3i_sdev_remove(struct t3cdev *cdev)19341934-{19351935- struct cxgb3i_sdev_data *cdata = CXGB3_SDEV_DATA(cdev);19361936-19371937- cxgb3i_log_info("t3dev 0x%p, offload down, remove.\n", cdev);19381938-19391939- write_lock(&cdata_rwlock);19401940- list_del(&cdata->list);19411941- write_unlock(&cdata_rwlock);19421942-19431943- sdev_data_cleanup(cdata);19441944-}
-243
drivers/scsi/cxgb3i/cxgb3i_offload.h
···11-/*22- * cxgb3i_offload.h: Chelsio S3xx iscsi offloaded tcp connection management33- *44- * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved.55- *66- * This program is distributed in the hope that it will be useful, but WITHOUT77- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or88- * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this99- * release for licensing terms and conditions.1010- *1111- * Written by: Dimitris Michailidis (dm@chelsio.com)1212- * Karen Xie (kxie@chelsio.com)1313- */1414-1515-#ifndef _CXGB3I_OFFLOAD_H1616-#define _CXGB3I_OFFLOAD_H1717-1818-#include <linux/skbuff.h>1919-#include <linux/in.h>2020-2121-#include "common.h"2222-#include "adapter.h"2323-#include "t3cdev.h"2424-#include "cxgb3_offload.h"2525-2626-#define cxgb3i_log_error(fmt...) printk(KERN_ERR "cxgb3i: ERR! " fmt)2727-#define cxgb3i_log_warn(fmt...) printk(KERN_WARNING "cxgb3i: WARN! " fmt)2828-#define cxgb3i_log_info(fmt...) printk(KERN_INFO "cxgb3i: " fmt)2929-#define cxgb3i_log_debug(fmt, args...) \3030- printk(KERN_INFO "cxgb3i: %s - " fmt, __func__ , ## args)3131-3232-/**3333- * struct s3_conn - an iscsi tcp connection structure3434- *3535- * @dev: net device of with connection3636- * @cdev: adapter t3cdev for net device3737- * @flags: see c3cn_flags below3838- * @tid: connection id assigned by the h/w3939- * @qset: queue set used by connection4040- * @mss_idx: Maximum Segment Size table index4141- * @l2t: ARP resolution entry for offload packets4242- * @wr_max: maximum in-flight writes4343- * @wr_avail: number of writes available4444- * @wr_unacked: writes since last request for completion notification4545- * @wr_pending_head: head of pending write queue4646- * @wr_pending_tail: tail of pending write queue4747- * @cpl_close: skb for cpl_close_req4848- * @cpl_abort_req: skb for cpl_abort_req4949- * @cpl_abort_rpl: skb for cpl_abort_rpl5050- * @lock: connection status lock5151- * @refcnt: reference count on connection5252- * @state: connection state5353- * @saddr: source ip/port address5454- * @daddr: destination ip/port address5555- * @dst_cache: reference to destination route5656- * @receive_queue: received PDUs5757- * @write_queue: un-pushed pending writes5858- * @retry_timer: retry timer for various operations5959- * @err: connection error status6060- * @callback_lock: lock for opaque user context6161- * @user_data: opaque user context6262- * @rcv_nxt: next receive seq. #6363- * @copied_seq: head of yet unread data6464- * @rcv_wup: rcv_nxt on last window update sent6565- * @snd_nxt: next sequence we send6666- * @snd_una: first byte we want an ack for6767- * @write_seq: tail+1 of data held in send buffer6868- */6969-struct s3_conn {7070- struct net_device *dev;7171- struct t3cdev *cdev;7272- unsigned long flags;7373- int tid;7474- int qset;7575- int mss_idx;7676- struct l2t_entry *l2t;7777- int wr_max;7878- int wr_avail;7979- int wr_unacked;8080- struct sk_buff *wr_pending_head;8181- struct sk_buff *wr_pending_tail;8282- struct sk_buff *cpl_close;8383- struct sk_buff *cpl_abort_req;8484- struct sk_buff *cpl_abort_rpl;8585- spinlock_t lock;8686- atomic_t refcnt;8787- volatile unsigned int state;8888- struct sockaddr_in saddr;8989- struct sockaddr_in daddr;9090- struct dst_entry *dst_cache;9191- struct sk_buff_head receive_queue;9292- struct sk_buff_head write_queue;9393- struct timer_list retry_timer;9494- int err;9595- rwlock_t callback_lock;9696- void *user_data;9797-9898- u32 rcv_nxt;9999- u32 copied_seq;100100- u32 rcv_wup;101101- u32 snd_nxt;102102- u32 snd_una;103103- u32 write_seq;104104-};105105-106106-/*107107- * connection state108108- */109109-enum conn_states {110110- C3CN_STATE_CONNECTING = 1,111111- C3CN_STATE_ESTABLISHED,112112- C3CN_STATE_ACTIVE_CLOSE,113113- C3CN_STATE_PASSIVE_CLOSE,114114- C3CN_STATE_CLOSE_WAIT_1,115115- C3CN_STATE_CLOSE_WAIT_2,116116- C3CN_STATE_ABORTING,117117- C3CN_STATE_CLOSED,118118-};119119-120120-static inline unsigned int c3cn_is_closing(const struct s3_conn *c3cn)121121-{122122- return c3cn->state >= C3CN_STATE_ACTIVE_CLOSE;123123-}124124-static inline unsigned int c3cn_is_established(const struct s3_conn *c3cn)125125-{126126- return c3cn->state == C3CN_STATE_ESTABLISHED;127127-}128128-129129-/*130130- * Connection flags -- many to track some close related events.131131- */132132-enum c3cn_flags {133133- C3CN_ABORT_RPL_RCVD, /* received one ABORT_RPL_RSS message */134134- C3CN_ABORT_REQ_RCVD, /* received one ABORT_REQ_RSS message */135135- C3CN_ABORT_RPL_PENDING, /* expecting an abort reply */136136- C3CN_TX_DATA_SENT, /* already sent a TX_DATA WR */137137- C3CN_ACTIVE_CLOSE_NEEDED, /* need to be closed */138138- C3CN_OFFLOAD_DOWN /* offload function off */139139-};140140-141141-/**142142- * cxgb3i_sdev_data - Per adapter data.143143- * Linked off of each Ethernet device port on the adapter.144144- * Also available via the t3cdev structure since we have pointers to our port145145- * net_device's there ...146146- *147147- * @list: list head to link elements148148- * @cdev: t3cdev adapter149149- * @client: CPL client pointer150150- * @ports: array of adapter ports151151- * @sport_next: next port152152- * @sport_conn: source port connection153153- */154154-struct cxgb3i_sdev_data {155155- struct list_head list;156156- struct t3cdev *cdev;157157- struct cxgb3_client *client;158158- struct adap_ports ports;159159- spinlock_t lock;160160- unsigned int sport_next;161161- struct s3_conn *sport_conn[0];162162-};163163-#define NDEV2CDATA(ndev) (*(struct cxgb3i_sdev_data **)&(ndev)->ec_ptr)164164-#define CXGB3_SDEV_DATA(cdev) NDEV2CDATA((cdev)->lldev)165165-166166-void cxgb3i_sdev_cleanup(void);167167-int cxgb3i_sdev_init(cxgb3_cpl_handler_func *);168168-void cxgb3i_sdev_add(struct t3cdev *, struct cxgb3_client *);169169-void cxgb3i_sdev_remove(struct t3cdev *);170170-171171-struct s3_conn *cxgb3i_c3cn_create(void);172172-int cxgb3i_c3cn_connect(struct net_device *, struct s3_conn *,173173- struct sockaddr_in *);174174-void cxgb3i_c3cn_rx_credits(struct s3_conn *, int);175175-int cxgb3i_c3cn_send_pdus(struct s3_conn *, struct sk_buff *);176176-void cxgb3i_c3cn_release(struct s3_conn *);177177-178178-/**179179- * cxgb3_skb_cb - control block for received pdu state and ULP mode management.180180- *181181- * @flag: see C3CB_FLAG_* below182182- * @ulp_mode: ULP mode/submode of sk_buff183183- * @seq: tcp sequence number184184- */185185-struct cxgb3_skb_rx_cb {186186- __u32 ddigest; /* data digest */187187- __u32 pdulen; /* recovered pdu length */188188-};189189-190190-struct cxgb3_skb_tx_cb {191191- struct sk_buff *wr_next; /* next wr */192192-};193193-194194-struct cxgb3_skb_cb {195195- __u8 flags;196196- __u8 ulp_mode;197197- __u32 seq;198198- union {199199- struct cxgb3_skb_rx_cb rx;200200- struct cxgb3_skb_tx_cb tx;201201- };202202-};203203-204204-#define CXGB3_SKB_CB(skb) ((struct cxgb3_skb_cb *)&((skb)->cb[0]))205205-#define skb_flags(skb) (CXGB3_SKB_CB(skb)->flags)206206-#define skb_ulp_mode(skb) (CXGB3_SKB_CB(skb)->ulp_mode)207207-#define skb_tcp_seq(skb) (CXGB3_SKB_CB(skb)->seq)208208-#define skb_rx_ddigest(skb) (CXGB3_SKB_CB(skb)->rx.ddigest)209209-#define skb_rx_pdulen(skb) (CXGB3_SKB_CB(skb)->rx.pdulen)210210-#define skb_tx_wr_next(skb) (CXGB3_SKB_CB(skb)->tx.wr_next)211211-212212-enum c3cb_flags {213213- C3CB_FLAG_NEED_HDR = 1 << 0, /* packet needs a TX_DATA_WR header */214214- C3CB_FLAG_NO_APPEND = 1 << 1, /* don't grow this skb */215215- C3CB_FLAG_COMPL = 1 << 2, /* request WR completion */216216-};217217-218218-/**219219- * sge_opaque_hdr -220220- * Opaque version of structure the SGE stores at skb->head of TX_DATA packets221221- * and for which we must reserve space.222222- */223223-struct sge_opaque_hdr {224224- void *dev;225225- dma_addr_t addr[MAX_SKB_FRAGS + 1];226226-};227227-228228-/* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */229229-#define TX_HEADER_LEN \230230- (sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr))231231-#define SKB_TX_HEADROOM SKB_MAX_HEAD(TX_HEADER_LEN)232232-233233-/*234234- * get and set private ip for iscsi traffic235235- */236236-#define cxgb3i_get_private_ipv4addr(ndev) \237237- (((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr)238238-#define cxgb3i_set_private_ipv4addr(ndev, addr) \239239- (((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr) = addr240240-241241-/* max. connections per adapter */242242-#define CXGB3I_MAX_CONN 16384243243-#endif /* _CXGB3_OFFLOAD_H */
-495
drivers/scsi/cxgb3i/cxgb3i_pdu.c
···11-/*22- * cxgb3i_pdu.c: Chelsio S3xx iSCSI driver.33- *44- * Copyright (c) 2008 Chelsio Communications, Inc.55- * Copyright (c) 2008 Mike Christie66- * Copyright (c) 2008 Red Hat, Inc. All rights reserved.77- *88- * This program is free software; you can redistribute it and/or modify99- * it under the terms of the GNU General Public License as published by1010- * the Free Software Foundation.1111- *1212- * Written by: Karen Xie (kxie@chelsio.com)1313- */1414-1515-#include <linux/slab.h>1616-#include <linux/skbuff.h>1717-#include <linux/crypto.h>1818-#include <scsi/scsi_cmnd.h>1919-#include <scsi/scsi_host.h>2020-2121-#include "cxgb3i.h"2222-#include "cxgb3i_pdu.h"2323-2424-#ifdef __DEBUG_CXGB3I_RX__2525-#define cxgb3i_rx_debug cxgb3i_log_debug2626-#else2727-#define cxgb3i_rx_debug(fmt...)2828-#endif2929-3030-#ifdef __DEBUG_CXGB3I_TX__3131-#define cxgb3i_tx_debug cxgb3i_log_debug3232-#else3333-#define cxgb3i_tx_debug(fmt...)3434-#endif3535-3636-/* always allocate rooms for AHS */3737-#define SKB_TX_PDU_HEADER_LEN \3838- (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE)3939-static unsigned int skb_extra_headroom;4040-static struct page *pad_page;4141-4242-/*4343- * pdu receive, interact with libiscsi_tcp4444- */4545-static inline int read_pdu_skb(struct iscsi_conn *conn, struct sk_buff *skb,4646- unsigned int offset, int offloaded)4747-{4848- int status = 0;4949- int bytes_read;5050-5151- bytes_read = iscsi_tcp_recv_skb(conn, skb, offset, offloaded, &status);5252- switch (status) {5353- case ISCSI_TCP_CONN_ERR:5454- return -EIO;5555- case ISCSI_TCP_SUSPENDED:5656- /* no transfer - just have caller flush queue */5757- return bytes_read;5858- case ISCSI_TCP_SKB_DONE:5959- /*6060- * pdus should always fit in the skb and we should get6161- * segment done notifcation.6262- */6363- iscsi_conn_printk(KERN_ERR, conn, "Invalid pdu or skb.");6464- return -EFAULT;6565- case ISCSI_TCP_SEGMENT_DONE:6666- return bytes_read;6767- default:6868- iscsi_conn_printk(KERN_ERR, conn, "Invalid iscsi_tcp_recv_skb "6969- "status %d\n", status);7070- return -EINVAL;7171- }7272-}7373-7474-static int cxgb3i_conn_read_pdu_skb(struct iscsi_conn *conn,7575- struct sk_buff *skb)7676-{7777- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;7878- bool offloaded = 0;7979- unsigned int offset;8080- int rc;8181-8282- cxgb3i_rx_debug("conn 0x%p, skb 0x%p, len %u, flag 0x%x.\n",8383- conn, skb, skb->len, skb_ulp_mode(skb));8484-8585- if (!iscsi_tcp_recv_segment_is_hdr(tcp_conn)) {8686- iscsi_conn_failure(conn, ISCSI_ERR_PROTO);8787- return -EIO;8888- }8989-9090- if (conn->hdrdgst_en && (skb_ulp_mode(skb) & ULP2_FLAG_HCRC_ERROR)) {9191- iscsi_conn_failure(conn, ISCSI_ERR_HDR_DGST);9292- return -EIO;9393- }9494-9595- if (conn->datadgst_en && (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) {9696- iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST);9797- return -EIO;9898- }9999-100100- /* iscsi hdr */101101- rc = read_pdu_skb(conn, skb, 0, 0);102102- if (rc <= 0)103103- return rc;104104-105105- if (iscsi_tcp_recv_segment_is_hdr(tcp_conn))106106- return 0;107107-108108- offset = rc;109109- if (conn->hdrdgst_en)110110- offset += ISCSI_DIGEST_SIZE;111111-112112- /* iscsi data */113113- if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) {114114- cxgb3i_rx_debug("skb 0x%p, opcode 0x%x, data %u, ddp'ed, "115115- "itt 0x%x.\n",116116- skb,117117- tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK,118118- tcp_conn->in.datalen,119119- ntohl(tcp_conn->in.hdr->itt));120120- offloaded = 1;121121- } else {122122- cxgb3i_rx_debug("skb 0x%p, opcode 0x%x, data %u, NOT ddp'ed, "123123- "itt 0x%x.\n",124124- skb,125125- tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK,126126- tcp_conn->in.datalen,127127- ntohl(tcp_conn->in.hdr->itt));128128- offset += sizeof(struct cpl_iscsi_hdr_norss);129129- }130130-131131- rc = read_pdu_skb(conn, skb, offset, offloaded);132132- if (rc < 0)133133- return rc;134134- else135135- return 0;136136-}137137-138138-/*139139- * pdu transmit, interact with libiscsi_tcp140140- */141141-static inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc)142142-{143143- u8 submode = 0;144144-145145- if (hcrc)146146- submode |= 1;147147- if (dcrc)148148- submode |= 2;149149- skb_ulp_mode(skb) = (ULP_MODE_ISCSI << 4) | submode;150150-}151151-152152-void cxgb3i_conn_cleanup_task(struct iscsi_task *task)153153-{154154- struct cxgb3i_task_data *tdata = task->dd_data +155155- sizeof(struct iscsi_tcp_task);156156-157157- /* never reached the xmit task callout */158158- if (tdata->skb)159159- __kfree_skb(tdata->skb);160160- memset(tdata, 0, sizeof(struct cxgb3i_task_data));161161-162162- /* MNC - Do we need a check in case this is called but163163- * cxgb3i_conn_alloc_pdu has never been called on the task */164164- cxgb3i_release_itt(task, task->hdr_itt);165165- iscsi_tcp_cleanup_task(task);166166-}167167-168168-static int sgl_seek_offset(struct scatterlist *sgl, unsigned int sgcnt,169169- unsigned int offset, unsigned int *off,170170- struct scatterlist **sgp)171171-{172172- int i;173173- struct scatterlist *sg;174174-175175- for_each_sg(sgl, sg, sgcnt, i) {176176- if (offset < sg->length) {177177- *off = offset;178178- *sgp = sg;179179- return 0;180180- }181181- offset -= sg->length;182182- }183183- return -EFAULT;184184-}185185-186186-static int sgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset,187187- unsigned int dlen, skb_frag_t *frags,188188- int frag_max)189189-{190190- unsigned int datalen = dlen;191191- unsigned int sglen = sg->length - sgoffset;192192- struct page *page = sg_page(sg);193193- int i;194194-195195- i = 0;196196- do {197197- unsigned int copy;198198-199199- if (!sglen) {200200- sg = sg_next(sg);201201- if (!sg) {202202- cxgb3i_log_error("%s, sg NULL, len %u/%u.\n",203203- __func__, datalen, dlen);204204- return -EINVAL;205205- }206206- sgoffset = 0;207207- sglen = sg->length;208208- page = sg_page(sg);209209-210210- }211211- copy = min(datalen, sglen);212212- if (i && page == frags[i - 1].page &&213213- sgoffset + sg->offset ==214214- frags[i - 1].page_offset + frags[i - 1].size) {215215- frags[i - 1].size += copy;216216- } else {217217- if (i >= frag_max) {218218- cxgb3i_log_error("%s, too many pages %u, "219219- "dlen %u.\n", __func__,220220- frag_max, dlen);221221- return -EINVAL;222222- }223223-224224- frags[i].page = page;225225- frags[i].page_offset = sg->offset + sgoffset;226226- frags[i].size = copy;227227- i++;228228- }229229- datalen -= copy;230230- sgoffset += copy;231231- sglen -= copy;232232- } while (datalen);233233-234234- return i;235235-}236236-237237-int cxgb3i_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)238238-{239239- struct iscsi_conn *conn = task->conn;240240- struct iscsi_tcp_task *tcp_task = task->dd_data;241241- struct cxgb3i_task_data *tdata = task->dd_data + sizeof(*tcp_task);242242- struct scsi_cmnd *sc = task->sc;243243- int headroom = SKB_TX_PDU_HEADER_LEN;244244-245245- tcp_task->dd_data = tdata;246246- task->hdr = NULL;247247-248248- /* write command, need to send data pdus */249249- if (skb_extra_headroom && (opcode == ISCSI_OP_SCSI_DATA_OUT ||250250- (opcode == ISCSI_OP_SCSI_CMD &&251251- (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_TO_DEVICE))))252252- headroom += min(skb_extra_headroom, conn->max_xmit_dlength);253253-254254- tdata->skb = alloc_skb(TX_HEADER_LEN + headroom, GFP_ATOMIC);255255- if (!tdata->skb)256256- return -ENOMEM;257257- skb_reserve(tdata->skb, TX_HEADER_LEN);258258-259259- cxgb3i_tx_debug("task 0x%p, opcode 0x%x, skb 0x%p.\n",260260- task, opcode, tdata->skb);261261-262262- task->hdr = (struct iscsi_hdr *)tdata->skb->data;263263- task->hdr_max = SKB_TX_PDU_HEADER_LEN;264264-265265- /* data_out uses scsi_cmd's itt */266266- if (opcode != ISCSI_OP_SCSI_DATA_OUT)267267- cxgb3i_reserve_itt(task, &task->hdr->itt);268268-269269- return 0;270270-}271271-272272-int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset,273273- unsigned int count)274274-{275275- struct iscsi_conn *conn = task->conn;276276- struct iscsi_tcp_task *tcp_task = task->dd_data;277277- struct cxgb3i_task_data *tdata = tcp_task->dd_data;278278- struct sk_buff *skb = tdata->skb;279279- unsigned int datalen = count;280280- int i, padlen = iscsi_padding(count);281281- struct page *pg;282282-283283- cxgb3i_tx_debug("task 0x%p,0x%p, offset %u, count %u, skb 0x%p.\n",284284- task, task->sc, offset, count, skb);285285-286286- skb_put(skb, task->hdr_len);287287- tx_skb_setmode(skb, conn->hdrdgst_en, datalen ? conn->datadgst_en : 0);288288- if (!count)289289- return 0;290290-291291- if (task->sc) {292292- struct scsi_data_buffer *sdb = scsi_out(task->sc);293293- struct scatterlist *sg = NULL;294294- int err;295295-296296- tdata->offset = offset;297297- tdata->count = count;298298- err = sgl_seek_offset(sdb->table.sgl, sdb->table.nents,299299- tdata->offset, &tdata->sgoffset, &sg);300300- if (err < 0) {301301- cxgb3i_log_warn("tpdu, sgl %u, bad offset %u/%u.\n",302302- sdb->table.nents, tdata->offset,303303- sdb->length);304304- return err;305305- }306306- err = sgl_read_to_frags(sg, tdata->sgoffset, tdata->count,307307- tdata->frags, MAX_PDU_FRAGS);308308- if (err < 0) {309309- cxgb3i_log_warn("tpdu, sgl %u, bad offset %u + %u.\n",310310- sdb->table.nents, tdata->offset,311311- tdata->count);312312- return err;313313- }314314- tdata->nr_frags = err;315315-316316- if (tdata->nr_frags > MAX_SKB_FRAGS ||317317- (padlen && tdata->nr_frags == MAX_SKB_FRAGS)) {318318- char *dst = skb->data + task->hdr_len;319319- skb_frag_t *frag = tdata->frags;320320-321321- /* data fits in the skb's headroom */322322- for (i = 0; i < tdata->nr_frags; i++, frag++) {323323- char *src = kmap_atomic(frag->page,324324- KM_SOFTIRQ0);325325-326326- memcpy(dst, src+frag->page_offset, frag->size);327327- dst += frag->size;328328- kunmap_atomic(src, KM_SOFTIRQ0);329329- }330330- if (padlen) {331331- memset(dst, 0, padlen);332332- padlen = 0;333333- }334334- skb_put(skb, count + padlen);335335- } else {336336- /* data fit into frag_list */337337- for (i = 0; i < tdata->nr_frags; i++)338338- get_page(tdata->frags[i].page);339339-340340- memcpy(skb_shinfo(skb)->frags, tdata->frags,341341- sizeof(skb_frag_t) * tdata->nr_frags);342342- skb_shinfo(skb)->nr_frags = tdata->nr_frags;343343- skb->len += count;344344- skb->data_len += count;345345- skb->truesize += count;346346- }347347-348348- } else {349349- pg = virt_to_page(task->data);350350-351351- get_page(pg);352352- skb_fill_page_desc(skb, 0, pg, offset_in_page(task->data),353353- count);354354- skb->len += count;355355- skb->data_len += count;356356- skb->truesize += count;357357- }358358-359359- if (padlen) {360360- i = skb_shinfo(skb)->nr_frags;361361- get_page(pad_page);362362- skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, pad_page, 0,363363- padlen);364364-365365- skb->data_len += padlen;366366- skb->truesize += padlen;367367- skb->len += padlen;368368- }369369-370370- return 0;371371-}372372-373373-int cxgb3i_conn_xmit_pdu(struct iscsi_task *task)374374-{375375- struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data;376376- struct cxgb3i_conn *cconn = tcp_conn->dd_data;377377- struct iscsi_tcp_task *tcp_task = task->dd_data;378378- struct cxgb3i_task_data *tdata = tcp_task->dd_data;379379- struct sk_buff *skb = tdata->skb;380380- unsigned int datalen;381381- int err;382382-383383- if (!skb)384384- return 0;385385-386386- datalen = skb->data_len;387387- tdata->skb = NULL;388388- err = cxgb3i_c3cn_send_pdus(cconn->cep->c3cn, skb);389389- if (err > 0) {390390- int pdulen = err;391391-392392- cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n",393393- task, skb, skb->len, skb->data_len, err);394394-395395- if (task->conn->hdrdgst_en)396396- pdulen += ISCSI_DIGEST_SIZE;397397- if (datalen && task->conn->datadgst_en)398398- pdulen += ISCSI_DIGEST_SIZE;399399-400400- task->conn->txdata_octets += pdulen;401401- return 0;402402- }403403-404404- if (err == -EAGAIN || err == -ENOBUFS) {405405- /* reset skb to send when we are called again */406406- tdata->skb = skb;407407- return err;408408- }409409-410410- kfree_skb(skb);411411- cxgb3i_tx_debug("itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n",412412- task->itt, skb, skb->len, skb->data_len, err);413413- iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err);414414- iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED);415415- return err;416416-}417417-418418-int cxgb3i_pdu_init(void)419419-{420420- if (SKB_TX_HEADROOM > (512 * MAX_SKB_FRAGS))421421- skb_extra_headroom = SKB_TX_HEADROOM;422422- pad_page = alloc_page(GFP_KERNEL);423423- if (!pad_page)424424- return -ENOMEM;425425- memset(page_address(pad_page), 0, PAGE_SIZE);426426- return 0;427427-}428428-429429-void cxgb3i_pdu_cleanup(void)430430-{431431- if (pad_page) {432432- __free_page(pad_page);433433- pad_page = NULL;434434- }435435-}436436-437437-void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn)438438-{439439- struct sk_buff *skb;440440- unsigned int read = 0;441441- struct iscsi_conn *conn = c3cn->user_data;442442- int err = 0;443443-444444- cxgb3i_rx_debug("cn 0x%p.\n", c3cn);445445-446446- read_lock(&c3cn->callback_lock);447447- if (unlikely(!conn || conn->suspend_rx)) {448448- cxgb3i_rx_debug("conn 0x%p, id %d, suspend_rx %lu!\n",449449- conn, conn ? conn->id : 0xFF,450450- conn ? conn->suspend_rx : 0xFF);451451- read_unlock(&c3cn->callback_lock);452452- return;453453- }454454- skb = skb_peek(&c3cn->receive_queue);455455- while (!err && skb) {456456- __skb_unlink(skb, &c3cn->receive_queue);457457- read += skb_rx_pdulen(skb);458458- cxgb3i_rx_debug("conn 0x%p, cn 0x%p, rx skb 0x%p, pdulen %u.\n",459459- conn, c3cn, skb, skb_rx_pdulen(skb));460460- err = cxgb3i_conn_read_pdu_skb(conn, skb);461461- __kfree_skb(skb);462462- skb = skb_peek(&c3cn->receive_queue);463463- }464464- read_unlock(&c3cn->callback_lock);465465- c3cn->copied_seq += read;466466- cxgb3i_c3cn_rx_credits(c3cn, read);467467- conn->rxdata_octets += read;468468-469469- if (err) {470470- cxgb3i_log_info("conn 0x%p rx failed err %d.\n", conn, err);471471- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);472472- }473473-}474474-475475-void cxgb3i_conn_tx_open(struct s3_conn *c3cn)476476-{477477- struct iscsi_conn *conn = c3cn->user_data;478478-479479- cxgb3i_tx_debug("cn 0x%p.\n", c3cn);480480- if (conn) {481481- cxgb3i_tx_debug("cn 0x%p, cid %d.\n", c3cn, conn->id);482482- iscsi_conn_queue_work(conn);483483- }484484-}485485-486486-void cxgb3i_conn_closing(struct s3_conn *c3cn)487487-{488488- struct iscsi_conn *conn;489489-490490- read_lock(&c3cn->callback_lock);491491- conn = c3cn->user_data;492492- if (conn && c3cn->state != C3CN_STATE_ESTABLISHED)493493- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);494494- read_unlock(&c3cn->callback_lock);495495-}
-59
drivers/scsi/cxgb3i/cxgb3i_pdu.h
···11-/*22- * cxgb3i_ulp2.h: Chelsio S3xx iSCSI driver.33- *44- * Copyright (c) 2008 Chelsio Communications, Inc.55- *66- * This program is free software; you can redistribute it and/or modify77- * it under the terms of the GNU General Public License as published by88- * the Free Software Foundation.99- *1010- * Written by: Karen Xie (kxie@chelsio.com)1111- */1212-1313-#ifndef __CXGB3I_ULP2_PDU_H__1414-#define __CXGB3I_ULP2_PDU_H__1515-1616-struct cpl_iscsi_hdr_norss {1717- union opcode_tid ot;1818- u16 pdu_len_ddp;1919- u16 len;2020- u32 seq;2121- u16 urg;2222- u8 rsvd;2323- u8 status;2424-};2525-2626-struct cpl_rx_data_ddp_norss {2727- union opcode_tid ot;2828- u16 urg;2929- u16 len;3030- u32 seq;3131- u32 nxt_seq;3232- u32 ulp_crc;3333- u32 ddp_status;3434-};3535-3636-#define RX_DDP_STATUS_IPP_SHIFT 27 /* invalid pagepod */3737-#define RX_DDP_STATUS_TID_SHIFT 26 /* tid mismatch */3838-#define RX_DDP_STATUS_COLOR_SHIFT 25 /* color mismatch */3939-#define RX_DDP_STATUS_OFFSET_SHIFT 24 /* offset mismatch */4040-#define RX_DDP_STATUS_ULIMIT_SHIFT 23 /* ulimit error */4141-#define RX_DDP_STATUS_TAG_SHIFT 22 /* tag mismatch */4242-#define RX_DDP_STATUS_DCRC_SHIFT 21 /* dcrc error */4343-#define RX_DDP_STATUS_HCRC_SHIFT 20 /* hcrc error */4444-#define RX_DDP_STATUS_PAD_SHIFT 19 /* pad error */4545-#define RX_DDP_STATUS_PPP_SHIFT 18 /* pagepod parity error */4646-#define RX_DDP_STATUS_LLIMIT_SHIFT 17 /* llimit error */4747-#define RX_DDP_STATUS_DDP_SHIFT 16 /* ddp'able */4848-#define RX_DDP_STATUS_PMM_SHIFT 15 /* pagepod mismatch */4949-5050-#define ULP2_FLAG_DATA_READY 0x15151-#define ULP2_FLAG_DATA_DDPED 0x25252-#define ULP2_FLAG_HCRC_ERROR 0x105353-#define ULP2_FLAG_DCRC_ERROR 0x205454-#define ULP2_FLAG_PAD_ERROR 0x405555-5656-void cxgb3i_conn_closing(struct s3_conn *c3cn);5757-void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn);5858-void cxgb3i_conn_tx_open(struct s3_conn *c3cn);5959-#endif