Path: blob/master/drivers/infiniband/ulp/iser/iser_verbs.c
15112 views
/*1* Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.2* Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.3*4* This software is available to you under a choice of one of two5* licenses. You may choose to be licensed under the terms of the GNU6* General Public License (GPL) Version 2, available from the file7* COPYING in the main directory of this source tree, or the8* OpenIB.org BSD license below:9*10* Redistribution and use in source and binary forms, with or11* without modification, are permitted provided that the following12* conditions are met:13*14* - Redistributions of source code must retain the above15* copyright notice, this list of conditions and the following16* disclaimer.17*18* - Redistributions in binary form must reproduce the above19* copyright notice, this list of conditions and the following20* disclaimer in the documentation and/or other materials21* provided with the distribution.22*23* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30* SOFTWARE.31*/32#include <linux/kernel.h>33#include <linux/module.h>34#include <linux/slab.h>35#include <linux/delay.h>3637#include "iscsi_iser.h"3839#define ISCSI_ISER_MAX_CONN 840#define ISER_MAX_RX_CQ_LEN (ISER_QP_MAX_RECV_DTOS * ISCSI_ISER_MAX_CONN)41#define ISER_MAX_TX_CQ_LEN (ISER_QP_MAX_REQ_DTOS * ISCSI_ISER_MAX_CONN)4243static void iser_cq_tasklet_fn(unsigned long data);44static void iser_cq_callback(struct ib_cq *cq, void *cq_context);4546static void iser_cq_event_callback(struct ib_event *cause, void *context)47{48iser_err("got cq event %d \n", cause->event);49}5051static void iser_qp_event_callback(struct ib_event *cause, void *context)52{53iser_err("got qp event %d\n",cause->event);54}5556static void iser_event_handler(struct ib_event_handler *handler,57struct ib_event *event)58{59iser_err("async event %d on device %s port %d\n", event->event,60event->device->name, event->element.port_num);61}6263/**64* iser_create_device_ib_res - creates Protection Domain (PD), Completion65* Queue (CQ), DMA Memory Region (DMA MR) with the device associated with66* the adapator.67*68* returns 0 on success, -1 on failure69*/70static int iser_create_device_ib_res(struct iser_device *device)71{72device->pd = ib_alloc_pd(device->ib_device);73if (IS_ERR(device->pd))74goto pd_err;7576device->rx_cq = ib_create_cq(device->ib_device,77iser_cq_callback,78iser_cq_event_callback,79(void *)device,80ISER_MAX_RX_CQ_LEN, 0);81if (IS_ERR(device->rx_cq))82goto rx_cq_err;8384device->tx_cq = ib_create_cq(device->ib_device,85NULL, iser_cq_event_callback,86(void *)device,87ISER_MAX_TX_CQ_LEN, 0);8889if (IS_ERR(device->tx_cq))90goto tx_cq_err;9192if (ib_req_notify_cq(device->rx_cq, IB_CQ_NEXT_COMP))93goto cq_arm_err;9495tasklet_init(&device->cq_tasklet,96iser_cq_tasklet_fn,97(unsigned long)device);9899device->mr = ib_get_dma_mr(device->pd, IB_ACCESS_LOCAL_WRITE |100IB_ACCESS_REMOTE_WRITE |101IB_ACCESS_REMOTE_READ);102if (IS_ERR(device->mr))103goto dma_mr_err;104105INIT_IB_EVENT_HANDLER(&device->event_handler, device->ib_device,106iser_event_handler);107if (ib_register_event_handler(&device->event_handler))108goto handler_err;109110return 0;111112handler_err:113ib_dereg_mr(device->mr);114dma_mr_err:115tasklet_kill(&device->cq_tasklet);116cq_arm_err:117ib_destroy_cq(device->tx_cq);118tx_cq_err:119ib_destroy_cq(device->rx_cq);120rx_cq_err:121ib_dealloc_pd(device->pd);122pd_err:123iser_err("failed to allocate an IB resource\n");124return -1;125}126127/**128* iser_free_device_ib_res - destroy/dealloc/dereg the DMA MR,129* CQ and PD created with the device associated with the adapator.130*/131static void iser_free_device_ib_res(struct iser_device *device)132{133BUG_ON(device->mr == NULL);134135tasklet_kill(&device->cq_tasklet);136(void)ib_unregister_event_handler(&device->event_handler);137(void)ib_dereg_mr(device->mr);138(void)ib_destroy_cq(device->tx_cq);139(void)ib_destroy_cq(device->rx_cq);140(void)ib_dealloc_pd(device->pd);141142device->mr = NULL;143device->tx_cq = NULL;144device->rx_cq = NULL;145device->pd = NULL;146}147148/**149* iser_create_ib_conn_res - Creates FMR pool and Queue-Pair (QP)150*151* returns 0 on success, -1 on failure152*/153static int iser_create_ib_conn_res(struct iser_conn *ib_conn)154{155struct iser_device *device;156struct ib_qp_init_attr init_attr;157int ret = -ENOMEM;158struct ib_fmr_pool_param params;159160BUG_ON(ib_conn->device == NULL);161162device = ib_conn->device;163164ib_conn->login_buf = kmalloc(ISER_RX_LOGIN_SIZE, GFP_KERNEL);165if (!ib_conn->login_buf)166goto out_err;167168ib_conn->login_dma = ib_dma_map_single(ib_conn->device->ib_device,169(void *)ib_conn->login_buf, ISER_RX_LOGIN_SIZE,170DMA_FROM_DEVICE);171172ib_conn->page_vec = kmalloc(sizeof(struct iser_page_vec) +173(sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE +1)),174GFP_KERNEL);175if (!ib_conn->page_vec)176goto out_err;177178ib_conn->page_vec->pages = (u64 *) (ib_conn->page_vec + 1);179180params.page_shift = SHIFT_4K;181/* when the first/last SG element are not start/end *182* page aligned, the map whould be of N+1 pages */183params.max_pages_per_fmr = ISCSI_ISER_SG_TABLESIZE + 1;184/* make the pool size twice the max number of SCSI commands *185* the ML is expected to queue, watermark for unmap at 50% */186params.pool_size = ISCSI_DEF_XMIT_CMDS_MAX * 2;187params.dirty_watermark = ISCSI_DEF_XMIT_CMDS_MAX;188params.cache = 0;189params.flush_function = NULL;190params.access = (IB_ACCESS_LOCAL_WRITE |191IB_ACCESS_REMOTE_WRITE |192IB_ACCESS_REMOTE_READ);193194ib_conn->fmr_pool = ib_create_fmr_pool(device->pd, ¶ms);195if (IS_ERR(ib_conn->fmr_pool)) {196ret = PTR_ERR(ib_conn->fmr_pool);197ib_conn->fmr_pool = NULL;198goto out_err;199}200201memset(&init_attr, 0, sizeof init_attr);202203init_attr.event_handler = iser_qp_event_callback;204init_attr.qp_context = (void *)ib_conn;205init_attr.send_cq = device->tx_cq;206init_attr.recv_cq = device->rx_cq;207init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS;208init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS;209init_attr.cap.max_send_sge = 2;210init_attr.cap.max_recv_sge = 1;211init_attr.sq_sig_type = IB_SIGNAL_REQ_WR;212init_attr.qp_type = IB_QPT_RC;213214ret = rdma_create_qp(ib_conn->cma_id, device->pd, &init_attr);215if (ret)216goto out_err;217218ib_conn->qp = ib_conn->cma_id->qp;219iser_err("setting conn %p cma_id %p: fmr_pool %p qp %p\n",220ib_conn, ib_conn->cma_id,221ib_conn->fmr_pool, ib_conn->cma_id->qp);222return ret;223224out_err:225iser_err("unable to alloc mem or create resource, err %d\n", ret);226return ret;227}228229/**230* releases the FMR pool, QP and CMA ID objects, returns 0 on success,231* -1 on failure232*/233static int iser_free_ib_conn_res(struct iser_conn *ib_conn, int can_destroy_id)234{235BUG_ON(ib_conn == NULL);236237iser_err("freeing conn %p cma_id %p fmr pool %p qp %p\n",238ib_conn, ib_conn->cma_id,239ib_conn->fmr_pool, ib_conn->qp);240241/* qp is created only once both addr & route are resolved */242if (ib_conn->fmr_pool != NULL)243ib_destroy_fmr_pool(ib_conn->fmr_pool);244245if (ib_conn->qp != NULL)246rdma_destroy_qp(ib_conn->cma_id);247248/* if cma handler context, the caller acts s.t the cma destroy the id */249if (ib_conn->cma_id != NULL && can_destroy_id)250rdma_destroy_id(ib_conn->cma_id);251252ib_conn->fmr_pool = NULL;253ib_conn->qp = NULL;254ib_conn->cma_id = NULL;255kfree(ib_conn->page_vec);256257return 0;258}259260/**261* based on the resolved device node GUID see if there already allocated262* device for this device. If there's no such, create one.263*/264static265struct iser_device *iser_device_find_by_ib_device(struct rdma_cm_id *cma_id)266{267struct iser_device *device;268269mutex_lock(&ig.device_list_mutex);270271list_for_each_entry(device, &ig.device_list, ig_list)272/* find if there's a match using the node GUID */273if (device->ib_device->node_guid == cma_id->device->node_guid)274goto inc_refcnt;275276device = kzalloc(sizeof *device, GFP_KERNEL);277if (device == NULL)278goto out;279280/* assign this device to the device */281device->ib_device = cma_id->device;282/* init the device and link it into ig device list */283if (iser_create_device_ib_res(device)) {284kfree(device);285device = NULL;286goto out;287}288list_add(&device->ig_list, &ig.device_list);289290inc_refcnt:291device->refcount++;292out:293mutex_unlock(&ig.device_list_mutex);294return device;295}296297/* if there's no demand for this device, release it */298static void iser_device_try_release(struct iser_device *device)299{300mutex_lock(&ig.device_list_mutex);301device->refcount--;302iser_err("device %p refcount %d\n",device,device->refcount);303if (!device->refcount) {304iser_free_device_ib_res(device);305list_del(&device->ig_list);306kfree(device);307}308mutex_unlock(&ig.device_list_mutex);309}310311static int iser_conn_state_comp_exch(struct iser_conn *ib_conn,312enum iser_ib_conn_state comp,313enum iser_ib_conn_state exch)314{315int ret;316317spin_lock_bh(&ib_conn->lock);318if ((ret = (ib_conn->state == comp)))319ib_conn->state = exch;320spin_unlock_bh(&ib_conn->lock);321return ret;322}323324/**325* Frees all conn objects and deallocs conn descriptor326*/327static void iser_conn_release(struct iser_conn *ib_conn, int can_destroy_id)328{329struct iser_device *device = ib_conn->device;330331BUG_ON(ib_conn->state != ISER_CONN_DOWN);332333mutex_lock(&ig.connlist_mutex);334list_del(&ib_conn->conn_list);335mutex_unlock(&ig.connlist_mutex);336iser_free_rx_descriptors(ib_conn);337iser_free_ib_conn_res(ib_conn, can_destroy_id);338ib_conn->device = NULL;339/* on EVENT_ADDR_ERROR there's no device yet for this conn */340if (device != NULL)341iser_device_try_release(device);342iscsi_destroy_endpoint(ib_conn->ep);343}344345void iser_conn_get(struct iser_conn *ib_conn)346{347atomic_inc(&ib_conn->refcount);348}349350int iser_conn_put(struct iser_conn *ib_conn, int can_destroy_id)351{352if (atomic_dec_and_test(&ib_conn->refcount)) {353iser_conn_release(ib_conn, can_destroy_id);354return 1;355}356return 0;357}358359/**360* triggers start of the disconnect procedures and wait for them to be done361*/362void iser_conn_terminate(struct iser_conn *ib_conn)363{364int err = 0;365366/* change the ib conn state only if the conn is UP, however always call367* rdma_disconnect since this is the only way to cause the CMA to change368* the QP state to ERROR369*/370371iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP, ISER_CONN_TERMINATING);372err = rdma_disconnect(ib_conn->cma_id);373if (err)374iser_err("Failed to disconnect, conn: 0x%p err %d\n",375ib_conn,err);376377wait_event_interruptible(ib_conn->wait,378ib_conn->state == ISER_CONN_DOWN);379380iser_conn_put(ib_conn, 1); /* deref ib conn deallocate */381}382383static int iser_connect_error(struct rdma_cm_id *cma_id)384{385struct iser_conn *ib_conn;386ib_conn = (struct iser_conn *)cma_id->context;387388ib_conn->state = ISER_CONN_DOWN;389wake_up_interruptible(&ib_conn->wait);390return iser_conn_put(ib_conn, 0); /* deref ib conn's cma id */391}392393static int iser_addr_handler(struct rdma_cm_id *cma_id)394{395struct iser_device *device;396struct iser_conn *ib_conn;397int ret;398399device = iser_device_find_by_ib_device(cma_id);400if (!device) {401iser_err("device lookup/creation failed\n");402return iser_connect_error(cma_id);403}404405ib_conn = (struct iser_conn *)cma_id->context;406ib_conn->device = device;407408ret = rdma_resolve_route(cma_id, 1000);409if (ret) {410iser_err("resolve route failed: %d\n", ret);411return iser_connect_error(cma_id);412}413414return 0;415}416417static int iser_route_handler(struct rdma_cm_id *cma_id)418{419struct rdma_conn_param conn_param;420int ret;421422ret = iser_create_ib_conn_res((struct iser_conn *)cma_id->context);423if (ret)424goto failure;425426memset(&conn_param, 0, sizeof conn_param);427conn_param.responder_resources = 4;428conn_param.initiator_depth = 1;429conn_param.retry_count = 7;430conn_param.rnr_retry_count = 6;431432ret = rdma_connect(cma_id, &conn_param);433if (ret) {434iser_err("failure connecting: %d\n", ret);435goto failure;436}437438return 0;439failure:440return iser_connect_error(cma_id);441}442443static void iser_connected_handler(struct rdma_cm_id *cma_id)444{445struct iser_conn *ib_conn;446447ib_conn = (struct iser_conn *)cma_id->context;448ib_conn->state = ISER_CONN_UP;449wake_up_interruptible(&ib_conn->wait);450}451452static int iser_disconnected_handler(struct rdma_cm_id *cma_id)453{454struct iser_conn *ib_conn;455int ret;456457ib_conn = (struct iser_conn *)cma_id->context;458459/* getting here when the state is UP means that the conn is being *460* terminated asynchronously from the iSCSI layer's perspective. */461if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP,462ISER_CONN_TERMINATING))463iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn,464ISCSI_ERR_CONN_FAILED);465466/* Complete the termination process if no posts are pending */467if (ib_conn->post_recv_buf_count == 0 &&468(atomic_read(&ib_conn->post_send_buf_count) == 0)) {469ib_conn->state = ISER_CONN_DOWN;470wake_up_interruptible(&ib_conn->wait);471}472473ret = iser_conn_put(ib_conn, 0); /* deref ib conn's cma id */474return ret;475}476477static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)478{479int ret = 0;480481iser_err("event %d status %d conn %p id %p\n",482event->event, event->status, cma_id->context, cma_id);483484switch (event->event) {485case RDMA_CM_EVENT_ADDR_RESOLVED:486ret = iser_addr_handler(cma_id);487break;488case RDMA_CM_EVENT_ROUTE_RESOLVED:489ret = iser_route_handler(cma_id);490break;491case RDMA_CM_EVENT_ESTABLISHED:492iser_connected_handler(cma_id);493break;494case RDMA_CM_EVENT_ADDR_ERROR:495case RDMA_CM_EVENT_ROUTE_ERROR:496case RDMA_CM_EVENT_CONNECT_ERROR:497case RDMA_CM_EVENT_UNREACHABLE:498case RDMA_CM_EVENT_REJECTED:499ret = iser_connect_error(cma_id);500break;501case RDMA_CM_EVENT_DISCONNECTED:502case RDMA_CM_EVENT_DEVICE_REMOVAL:503case RDMA_CM_EVENT_ADDR_CHANGE:504ret = iser_disconnected_handler(cma_id);505break;506default:507iser_err("Unexpected RDMA CM event (%d)\n", event->event);508break;509}510return ret;511}512513void iser_conn_init(struct iser_conn *ib_conn)514{515ib_conn->state = ISER_CONN_INIT;516init_waitqueue_head(&ib_conn->wait);517ib_conn->post_recv_buf_count = 0;518atomic_set(&ib_conn->post_send_buf_count, 0);519atomic_set(&ib_conn->refcount, 1); /* ref ib conn allocation */520INIT_LIST_HEAD(&ib_conn->conn_list);521spin_lock_init(&ib_conn->lock);522}523524/**525* starts the process of connecting to the target526* sleeps until the connection is established or rejected527*/528int iser_connect(struct iser_conn *ib_conn,529struct sockaddr_in *src_addr,530struct sockaddr_in *dst_addr,531int non_blocking)532{533struct sockaddr *src, *dst;534int err = 0;535536sprintf(ib_conn->name, "%pI4:%d",537&dst_addr->sin_addr.s_addr, dst_addr->sin_port);538539/* the device is known only --after-- address resolution */540ib_conn->device = NULL;541542iser_err("connecting to: %pI4, port 0x%x\n",543&dst_addr->sin_addr, dst_addr->sin_port);544545ib_conn->state = ISER_CONN_PENDING;546547iser_conn_get(ib_conn); /* ref ib conn's cma id */548ib_conn->cma_id = rdma_create_id(iser_cma_handler,549(void *)ib_conn,550RDMA_PS_TCP, IB_QPT_RC);551if (IS_ERR(ib_conn->cma_id)) {552err = PTR_ERR(ib_conn->cma_id);553iser_err("rdma_create_id failed: %d\n", err);554goto id_failure;555}556557src = (struct sockaddr *)src_addr;558dst = (struct sockaddr *)dst_addr;559err = rdma_resolve_addr(ib_conn->cma_id, src, dst, 1000);560if (err) {561iser_err("rdma_resolve_addr failed: %d\n", err);562goto addr_failure;563}564565if (!non_blocking) {566wait_event_interruptible(ib_conn->wait,567(ib_conn->state != ISER_CONN_PENDING));568569if (ib_conn->state != ISER_CONN_UP) {570err = -EIO;571goto connect_failure;572}573}574575mutex_lock(&ig.connlist_mutex);576list_add(&ib_conn->conn_list, &ig.connlist);577mutex_unlock(&ig.connlist_mutex);578return 0;579580id_failure:581ib_conn->cma_id = NULL;582addr_failure:583ib_conn->state = ISER_CONN_DOWN;584connect_failure:585iser_conn_release(ib_conn, 1);586return err;587}588589/**590* iser_reg_page_vec - Register physical memory591*592* returns: 0 on success, errno code on failure593*/594int iser_reg_page_vec(struct iser_conn *ib_conn,595struct iser_page_vec *page_vec,596struct iser_mem_reg *mem_reg)597{598struct ib_pool_fmr *mem;599u64 io_addr;600u64 *page_list;601int status;602603page_list = page_vec->pages;604io_addr = page_list[0];605606mem = ib_fmr_pool_map_phys(ib_conn->fmr_pool,607page_list,608page_vec->length,609io_addr);610611if (IS_ERR(mem)) {612status = (int)PTR_ERR(mem);613iser_err("ib_fmr_pool_map_phys failed: %d\n", status);614return status;615}616617mem_reg->lkey = mem->fmr->lkey;618mem_reg->rkey = mem->fmr->rkey;619mem_reg->len = page_vec->length * SIZE_4K;620mem_reg->va = io_addr;621mem_reg->is_fmr = 1;622mem_reg->mem_h = (void *)mem;623624mem_reg->va += page_vec->offset;625mem_reg->len = page_vec->data_size;626627iser_dbg("PHYSICAL Mem.register, [PHYS p_array: 0x%p, sz: %d, "628"entry[0]: (0x%08lx,%ld)] -> "629"[lkey: 0x%08X mem_h: 0x%p va: 0x%08lX sz: %ld]\n",630page_vec, page_vec->length,631(unsigned long)page_vec->pages[0],632(unsigned long)page_vec->data_size,633(unsigned int)mem_reg->lkey, mem_reg->mem_h,634(unsigned long)mem_reg->va, (unsigned long)mem_reg->len);635return 0;636}637638/**639* Unregister (previosuly registered) memory.640*/641void iser_unreg_mem(struct iser_mem_reg *reg)642{643int ret;644645iser_dbg("PHYSICAL Mem.Unregister mem_h %p\n",reg->mem_h);646647ret = ib_fmr_pool_unmap((struct ib_pool_fmr *)reg->mem_h);648if (ret)649iser_err("ib_fmr_pool_unmap failed %d\n", ret);650651reg->mem_h = NULL;652}653654int iser_post_recvl(struct iser_conn *ib_conn)655{656struct ib_recv_wr rx_wr, *rx_wr_failed;657struct ib_sge sge;658int ib_ret;659660sge.addr = ib_conn->login_dma;661sge.length = ISER_RX_LOGIN_SIZE;662sge.lkey = ib_conn->device->mr->lkey;663664rx_wr.wr_id = (unsigned long)ib_conn->login_buf;665rx_wr.sg_list = &sge;666rx_wr.num_sge = 1;667rx_wr.next = NULL;668669ib_conn->post_recv_buf_count++;670ib_ret = ib_post_recv(ib_conn->qp, &rx_wr, &rx_wr_failed);671if (ib_ret) {672iser_err("ib_post_recv failed ret=%d\n", ib_ret);673ib_conn->post_recv_buf_count--;674}675return ib_ret;676}677678int iser_post_recvm(struct iser_conn *ib_conn, int count)679{680struct ib_recv_wr *rx_wr, *rx_wr_failed;681int i, ib_ret;682unsigned int my_rx_head = ib_conn->rx_desc_head;683struct iser_rx_desc *rx_desc;684685for (rx_wr = ib_conn->rx_wr, i = 0; i < count; i++, rx_wr++) {686rx_desc = &ib_conn->rx_descs[my_rx_head];687rx_wr->wr_id = (unsigned long)rx_desc;688rx_wr->sg_list = &rx_desc->rx_sg;689rx_wr->num_sge = 1;690rx_wr->next = rx_wr + 1;691my_rx_head = (my_rx_head + 1) & (ISER_QP_MAX_RECV_DTOS - 1);692}693694rx_wr--;695rx_wr->next = NULL; /* mark end of work requests list */696697ib_conn->post_recv_buf_count += count;698ib_ret = ib_post_recv(ib_conn->qp, ib_conn->rx_wr, &rx_wr_failed);699if (ib_ret) {700iser_err("ib_post_recv failed ret=%d\n", ib_ret);701ib_conn->post_recv_buf_count -= count;702} else703ib_conn->rx_desc_head = my_rx_head;704return ib_ret;705}706707708/**709* iser_start_send - Initiate a Send DTO operation710*711* returns 0 on success, -1 on failure712*/713int iser_post_send(struct iser_conn *ib_conn, struct iser_tx_desc *tx_desc)714{715int ib_ret;716struct ib_send_wr send_wr, *send_wr_failed;717718ib_dma_sync_single_for_device(ib_conn->device->ib_device,719tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE);720721send_wr.next = NULL;722send_wr.wr_id = (unsigned long)tx_desc;723send_wr.sg_list = tx_desc->tx_sg;724send_wr.num_sge = tx_desc->num_sge;725send_wr.opcode = IB_WR_SEND;726send_wr.send_flags = IB_SEND_SIGNALED;727728atomic_inc(&ib_conn->post_send_buf_count);729730ib_ret = ib_post_send(ib_conn->qp, &send_wr, &send_wr_failed);731if (ib_ret) {732iser_err("ib_post_send failed, ret:%d\n", ib_ret);733atomic_dec(&ib_conn->post_send_buf_count);734}735return ib_ret;736}737738static void iser_handle_comp_error(struct iser_tx_desc *desc,739struct iser_conn *ib_conn)740{741if (desc && desc->type == ISCSI_TX_DATAOUT)742kmem_cache_free(ig.desc_cache, desc);743744if (ib_conn->post_recv_buf_count == 0 &&745atomic_read(&ib_conn->post_send_buf_count) == 0) {746/* getting here when the state is UP means that the conn is *747* being terminated asynchronously from the iSCSI layer's *748* perspective. */749if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP,750ISER_CONN_TERMINATING))751iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn,752ISCSI_ERR_CONN_FAILED);753754/* no more non completed posts to the QP, complete the755* termination process w.o worrying on disconnect event */756ib_conn->state = ISER_CONN_DOWN;757wake_up_interruptible(&ib_conn->wait);758}759}760761static int iser_drain_tx_cq(struct iser_device *device)762{763struct ib_cq *cq = device->tx_cq;764struct ib_wc wc;765struct iser_tx_desc *tx_desc;766struct iser_conn *ib_conn;767int completed_tx = 0;768769while (ib_poll_cq(cq, 1, &wc) == 1) {770tx_desc = (struct iser_tx_desc *) (unsigned long) wc.wr_id;771ib_conn = wc.qp->qp_context;772if (wc.status == IB_WC_SUCCESS) {773if (wc.opcode == IB_WC_SEND)774iser_snd_completion(tx_desc, ib_conn);775else776iser_err("expected opcode %d got %d\n",777IB_WC_SEND, wc.opcode);778} else {779iser_err("tx id %llx status %d vend_err %x\n",780wc.wr_id, wc.status, wc.vendor_err);781atomic_dec(&ib_conn->post_send_buf_count);782iser_handle_comp_error(tx_desc, ib_conn);783}784completed_tx++;785}786return completed_tx;787}788789790static void iser_cq_tasklet_fn(unsigned long data)791{792struct iser_device *device = (struct iser_device *)data;793struct ib_cq *cq = device->rx_cq;794struct ib_wc wc;795struct iser_rx_desc *desc;796unsigned long xfer_len;797struct iser_conn *ib_conn;798int completed_tx, completed_rx;799completed_tx = completed_rx = 0;800801while (ib_poll_cq(cq, 1, &wc) == 1) {802desc = (struct iser_rx_desc *) (unsigned long) wc.wr_id;803BUG_ON(desc == NULL);804ib_conn = wc.qp->qp_context;805if (wc.status == IB_WC_SUCCESS) {806if (wc.opcode == IB_WC_RECV) {807xfer_len = (unsigned long)wc.byte_len;808iser_rcv_completion(desc, xfer_len, ib_conn);809} else810iser_err("expected opcode %d got %d\n",811IB_WC_RECV, wc.opcode);812} else {813if (wc.status != IB_WC_WR_FLUSH_ERR)814iser_err("rx id %llx status %d vend_err %x\n",815wc.wr_id, wc.status, wc.vendor_err);816ib_conn->post_recv_buf_count--;817iser_handle_comp_error(NULL, ib_conn);818}819completed_rx++;820if (!(completed_rx & 63))821completed_tx += iser_drain_tx_cq(device);822}823/* #warning "it is assumed here that arming CQ only once its empty" *824* " would not cause interrupts to be missed" */825ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);826827completed_tx += iser_drain_tx_cq(device);828iser_dbg("got %d rx %d tx completions\n", completed_rx, completed_tx);829}830831static void iser_cq_callback(struct ib_cq *cq, void *cq_context)832{833struct iser_device *device = (struct iser_device *)cq_context;834835tasklet_schedule(&device->cq_tasklet);836}837838839