162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2013-2014 Mellanox Technologies. All rights reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This software is available to you under a choice of one of two 662306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 762306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 862306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 962306a36Sopenharmony_ci * OpenIB.org BSD license below: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1262306a36Sopenharmony_ci * without modification, are permitted provided that the following 1362306a36Sopenharmony_ci * conditions are met: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1662306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1762306a36Sopenharmony_ci * disclaimer. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2062306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2162306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2262306a36Sopenharmony_ci * provided with the distribution. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2562306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2662306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2762306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2862306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2962306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3062306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3162306a36Sopenharmony_ci * SOFTWARE. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci#include <linux/kernel.h> 3462306a36Sopenharmony_ci#include <linux/slab.h> 3562306a36Sopenharmony_ci#include <linux/mm.h> 3662306a36Sopenharmony_ci#include <linux/scatterlist.h> 3762306a36Sopenharmony_ci#include <linux/kfifo.h> 3862306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 3962306a36Sopenharmony_ci#include <scsi/scsi_host.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include "iscsi_iser.h" 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Register user buffer memory and initialize passive rdma 4462306a36Sopenharmony_ci * dto descriptor. Data size is stored in 4562306a36Sopenharmony_ci * task->data[ISER_DIR_IN].data_len, Protection size 4662306a36Sopenharmony_ci * os stored in task->prot[ISER_DIR_IN].data_len 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_cistatic int iser_prepare_read_cmd(struct iscsi_task *task) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 5262306a36Sopenharmony_ci struct iser_mem_reg *mem_reg; 5362306a36Sopenharmony_ci int err; 5462306a36Sopenharmony_ci struct iser_ctrl *hdr = &iser_task->desc.iser_header; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci err = iser_dma_map_task_data(iser_task, 5762306a36Sopenharmony_ci ISER_DIR_IN, 5862306a36Sopenharmony_ci DMA_FROM_DEVICE); 5962306a36Sopenharmony_ci if (err) 6062306a36Sopenharmony_ci return err; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci err = iser_reg_mem_fastreg(iser_task, ISER_DIR_IN, false); 6362306a36Sopenharmony_ci if (err) { 6462306a36Sopenharmony_ci iser_err("Failed to set up Data-IN RDMA\n"); 6562306a36Sopenharmony_ci goto out_err; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci mem_reg = &iser_task->rdma_reg[ISER_DIR_IN]; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci hdr->flags |= ISER_RSV; 7062306a36Sopenharmony_ci hdr->read_stag = cpu_to_be32(mem_reg->rkey); 7162306a36Sopenharmony_ci hdr->read_va = cpu_to_be64(mem_reg->sge.addr); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci iser_dbg("Cmd itt:%d READ tags RKEY:%#.4X VA:%#llX\n", 7462306a36Sopenharmony_ci task->itt, mem_reg->rkey, 7562306a36Sopenharmony_ci (unsigned long long)mem_reg->sge.addr); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciout_err: 8062306a36Sopenharmony_ci iser_dma_unmap_task_data(iser_task, ISER_DIR_IN, DMA_FROM_DEVICE); 8162306a36Sopenharmony_ci return err; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* Register user buffer memory and initialize passive rdma 8562306a36Sopenharmony_ci * dto descriptor. Data size is stored in 8662306a36Sopenharmony_ci * task->data[ISER_DIR_OUT].data_len, Protection size 8762306a36Sopenharmony_ci * is stored at task->prot[ISER_DIR_OUT].data_len 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cistatic int iser_prepare_write_cmd(struct iscsi_task *task, unsigned int imm_sz, 9062306a36Sopenharmony_ci unsigned int unsol_sz, unsigned int edtl) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 9362306a36Sopenharmony_ci struct iser_mem_reg *mem_reg; 9462306a36Sopenharmony_ci int err; 9562306a36Sopenharmony_ci struct iser_ctrl *hdr = &iser_task->desc.iser_header; 9662306a36Sopenharmony_ci struct iser_data_buf *buf_out = &iser_task->data[ISER_DIR_OUT]; 9762306a36Sopenharmony_ci struct ib_sge *tx_dsg = &iser_task->desc.tx_sg[1]; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci err = iser_dma_map_task_data(iser_task, 10062306a36Sopenharmony_ci ISER_DIR_OUT, 10162306a36Sopenharmony_ci DMA_TO_DEVICE); 10262306a36Sopenharmony_ci if (err) 10362306a36Sopenharmony_ci return err; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci err = iser_reg_mem_fastreg(iser_task, ISER_DIR_OUT, 10662306a36Sopenharmony_ci buf_out->data_len == imm_sz); 10762306a36Sopenharmony_ci if (err) { 10862306a36Sopenharmony_ci iser_err("Failed to register write cmd RDMA mem\n"); 10962306a36Sopenharmony_ci goto out_err; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci mem_reg = &iser_task->rdma_reg[ISER_DIR_OUT]; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (unsol_sz < edtl) { 11562306a36Sopenharmony_ci hdr->flags |= ISER_WSV; 11662306a36Sopenharmony_ci if (buf_out->data_len > imm_sz) { 11762306a36Sopenharmony_ci hdr->write_stag = cpu_to_be32(mem_reg->rkey); 11862306a36Sopenharmony_ci hdr->write_va = cpu_to_be64(mem_reg->sge.addr + unsol_sz); 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci iser_dbg("Cmd itt:%d, WRITE tags, RKEY:%#.4X VA:%#llX + unsol:%d\n", 12262306a36Sopenharmony_ci task->itt, mem_reg->rkey, 12362306a36Sopenharmony_ci (unsigned long long)mem_reg->sge.addr, unsol_sz); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (imm_sz > 0) { 12762306a36Sopenharmony_ci iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n", 12862306a36Sopenharmony_ci task->itt, imm_sz); 12962306a36Sopenharmony_ci tx_dsg->addr = mem_reg->sge.addr; 13062306a36Sopenharmony_ci tx_dsg->length = imm_sz; 13162306a36Sopenharmony_ci tx_dsg->lkey = mem_reg->sge.lkey; 13262306a36Sopenharmony_ci iser_task->desc.num_sge = 2; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciout_err: 13862306a36Sopenharmony_ci iser_dma_unmap_task_data(iser_task, ISER_DIR_OUT, DMA_TO_DEVICE); 13962306a36Sopenharmony_ci return err; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* creates a new tx descriptor and adds header regd buffer */ 14362306a36Sopenharmony_cistatic void iser_create_send_desc(struct iser_conn *iser_conn, 14462306a36Sopenharmony_ci struct iser_tx_desc *tx_desc, enum iser_desc_type type, 14562306a36Sopenharmony_ci void (*done)(struct ib_cq *cq, struct ib_wc *wc)) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct iser_device *device = iser_conn->ib_conn.device; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci tx_desc->type = type; 15062306a36Sopenharmony_ci tx_desc->cqe.done = done; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(device->ib_device, 15362306a36Sopenharmony_ci tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci memset(&tx_desc->iser_header, 0, sizeof(struct iser_ctrl)); 15662306a36Sopenharmony_ci tx_desc->iser_header.flags = ISER_VER; 15762306a36Sopenharmony_ci tx_desc->num_sge = 1; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void iser_free_login_buf(struct iser_conn *iser_conn) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct iser_device *device = iser_conn->ib_conn.device; 16362306a36Sopenharmony_ci struct iser_login_desc *desc = &iser_conn->login_desc; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (!desc->req) 16662306a36Sopenharmony_ci return; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci ib_dma_unmap_single(device->ib_device, desc->req_dma, 16962306a36Sopenharmony_ci ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_TO_DEVICE); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci ib_dma_unmap_single(device->ib_device, desc->rsp_dma, 17262306a36Sopenharmony_ci ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci kfree(desc->req); 17562306a36Sopenharmony_ci kfree(desc->rsp); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* make sure we never redo any unmapping */ 17862306a36Sopenharmony_ci desc->req = NULL; 17962306a36Sopenharmony_ci desc->rsp = NULL; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int iser_alloc_login_buf(struct iser_conn *iser_conn) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct iser_device *device = iser_conn->ib_conn.device; 18562306a36Sopenharmony_ci struct iser_login_desc *desc = &iser_conn->login_desc; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci desc->req = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); 18862306a36Sopenharmony_ci if (!desc->req) 18962306a36Sopenharmony_ci return -ENOMEM; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci desc->req_dma = ib_dma_map_single(device->ib_device, desc->req, 19262306a36Sopenharmony_ci ISCSI_DEF_MAX_RECV_SEG_LEN, 19362306a36Sopenharmony_ci DMA_TO_DEVICE); 19462306a36Sopenharmony_ci if (ib_dma_mapping_error(device->ib_device, 19562306a36Sopenharmony_ci desc->req_dma)) 19662306a36Sopenharmony_ci goto free_req; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci desc->rsp = kmalloc(ISER_RX_LOGIN_SIZE, GFP_KERNEL); 19962306a36Sopenharmony_ci if (!desc->rsp) 20062306a36Sopenharmony_ci goto unmap_req; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci desc->rsp_dma = ib_dma_map_single(device->ib_device, desc->rsp, 20362306a36Sopenharmony_ci ISER_RX_LOGIN_SIZE, 20462306a36Sopenharmony_ci DMA_FROM_DEVICE); 20562306a36Sopenharmony_ci if (ib_dma_mapping_error(device->ib_device, 20662306a36Sopenharmony_ci desc->rsp_dma)) 20762306a36Sopenharmony_ci goto free_rsp; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cifree_rsp: 21262306a36Sopenharmony_ci kfree(desc->rsp); 21362306a36Sopenharmony_ciunmap_req: 21462306a36Sopenharmony_ci ib_dma_unmap_single(device->ib_device, desc->req_dma, 21562306a36Sopenharmony_ci ISCSI_DEF_MAX_RECV_SEG_LEN, 21662306a36Sopenharmony_ci DMA_TO_DEVICE); 21762306a36Sopenharmony_cifree_req: 21862306a36Sopenharmony_ci kfree(desc->req); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return -ENOMEM; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciint iser_alloc_rx_descriptors(struct iser_conn *iser_conn, 22462306a36Sopenharmony_ci struct iscsi_session *session) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci int i, j; 22762306a36Sopenharmony_ci u64 dma_addr; 22862306a36Sopenharmony_ci struct iser_rx_desc *rx_desc; 22962306a36Sopenharmony_ci struct ib_sge *rx_sg; 23062306a36Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 23162306a36Sopenharmony_ci struct iser_device *device = ib_conn->device; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci iser_conn->qp_max_recv_dtos = session->cmds_max; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (iser_alloc_fastreg_pool(ib_conn, session->scsi_cmds_max, 23662306a36Sopenharmony_ci iser_conn->pages_per_mr)) 23762306a36Sopenharmony_ci goto create_rdma_reg_res_failed; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (iser_alloc_login_buf(iser_conn)) 24062306a36Sopenharmony_ci goto alloc_login_buf_fail; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci iser_conn->num_rx_descs = session->cmds_max; 24362306a36Sopenharmony_ci iser_conn->rx_descs = kmalloc_array(iser_conn->num_rx_descs, 24462306a36Sopenharmony_ci sizeof(struct iser_rx_desc), 24562306a36Sopenharmony_ci GFP_KERNEL); 24662306a36Sopenharmony_ci if (!iser_conn->rx_descs) 24762306a36Sopenharmony_ci goto rx_desc_alloc_fail; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci rx_desc = iser_conn->rx_descs; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci for (i = 0; i < iser_conn->qp_max_recv_dtos; i++, rx_desc++) { 25262306a36Sopenharmony_ci dma_addr = ib_dma_map_single(device->ib_device, (void *)rx_desc, 25362306a36Sopenharmony_ci ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); 25462306a36Sopenharmony_ci if (ib_dma_mapping_error(device->ib_device, dma_addr)) 25562306a36Sopenharmony_ci goto rx_desc_dma_map_failed; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci rx_desc->dma_addr = dma_addr; 25862306a36Sopenharmony_ci rx_desc->cqe.done = iser_task_rsp; 25962306a36Sopenharmony_ci rx_sg = &rx_desc->rx_sg; 26062306a36Sopenharmony_ci rx_sg->addr = rx_desc->dma_addr; 26162306a36Sopenharmony_ci rx_sg->length = ISER_RX_PAYLOAD_SIZE; 26262306a36Sopenharmony_ci rx_sg->lkey = device->pd->local_dma_lkey; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cirx_desc_dma_map_failed: 26862306a36Sopenharmony_ci rx_desc = iser_conn->rx_descs; 26962306a36Sopenharmony_ci for (j = 0; j < i; j++, rx_desc++) 27062306a36Sopenharmony_ci ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr, 27162306a36Sopenharmony_ci ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); 27262306a36Sopenharmony_ci kfree(iser_conn->rx_descs); 27362306a36Sopenharmony_ci iser_conn->rx_descs = NULL; 27462306a36Sopenharmony_cirx_desc_alloc_fail: 27562306a36Sopenharmony_ci iser_free_login_buf(iser_conn); 27662306a36Sopenharmony_cialloc_login_buf_fail: 27762306a36Sopenharmony_ci iser_free_fastreg_pool(ib_conn); 27862306a36Sopenharmony_cicreate_rdma_reg_res_failed: 27962306a36Sopenharmony_ci iser_err("failed allocating rx descriptors / data buffers\n"); 28062306a36Sopenharmony_ci return -ENOMEM; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_civoid iser_free_rx_descriptors(struct iser_conn *iser_conn) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci int i; 28662306a36Sopenharmony_ci struct iser_rx_desc *rx_desc; 28762306a36Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 28862306a36Sopenharmony_ci struct iser_device *device = ib_conn->device; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci iser_free_fastreg_pool(ib_conn); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci rx_desc = iser_conn->rx_descs; 29362306a36Sopenharmony_ci for (i = 0; i < iser_conn->qp_max_recv_dtos; i++, rx_desc++) 29462306a36Sopenharmony_ci ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr, 29562306a36Sopenharmony_ci ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); 29662306a36Sopenharmony_ci kfree(iser_conn->rx_descs); 29762306a36Sopenharmony_ci /* make sure we never redo any unmapping */ 29862306a36Sopenharmony_ci iser_conn->rx_descs = NULL; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci iser_free_login_buf(iser_conn); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct iser_conn *iser_conn = conn->dd_data; 30662306a36Sopenharmony_ci struct iscsi_session *session = conn->session; 30762306a36Sopenharmony_ci int err = 0; 30862306a36Sopenharmony_ci int i; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci iser_dbg("req op %x flags %x\n", req->opcode, req->flags); 31162306a36Sopenharmony_ci /* check if this is the last login - going to full feature phase */ 31262306a36Sopenharmony_ci if ((req->flags & ISCSI_FULL_FEATURE_PHASE) != ISCSI_FULL_FEATURE_PHASE) 31362306a36Sopenharmony_ci goto out; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (session->discovery_sess) { 31662306a36Sopenharmony_ci iser_info("Discovery session, re-using login RX buffer\n"); 31762306a36Sopenharmony_ci goto out; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci iser_info("Normal session, posting batch of RX %d buffers\n", 32162306a36Sopenharmony_ci iser_conn->qp_max_recv_dtos - 1); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* 32462306a36Sopenharmony_ci * Initial post receive buffers. 32562306a36Sopenharmony_ci * There is one already posted recv buffer (for the last login 32662306a36Sopenharmony_ci * response). Therefore, the first recv buffer is skipped here. 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ci for (i = 1; i < iser_conn->qp_max_recv_dtos; i++) { 32962306a36Sopenharmony_ci err = iser_post_recvm(iser_conn, &iser_conn->rx_descs[i]); 33062306a36Sopenharmony_ci if (err) 33162306a36Sopenharmony_ci goto out; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ciout: 33462306a36Sopenharmony_ci return err; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci/** 33862306a36Sopenharmony_ci * iser_send_command - send command PDU 33962306a36Sopenharmony_ci * @conn: link to matching iscsi connection 34062306a36Sopenharmony_ci * @task: SCSI command task 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ciint iser_send_command(struct iscsi_conn *conn, struct iscsi_task *task) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct iser_conn *iser_conn = conn->dd_data; 34562306a36Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 34662306a36Sopenharmony_ci unsigned long edtl; 34762306a36Sopenharmony_ci int err; 34862306a36Sopenharmony_ci struct iser_data_buf *data_buf, *prot_buf; 34962306a36Sopenharmony_ci struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr; 35062306a36Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 35162306a36Sopenharmony_ci struct iser_tx_desc *tx_desc = &iser_task->desc; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci edtl = ntohl(hdr->data_length); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* build the tx desc regd header and add it to the tx desc dto */ 35662306a36Sopenharmony_ci iser_create_send_desc(iser_conn, tx_desc, ISCSI_TX_SCSI_COMMAND, 35762306a36Sopenharmony_ci iser_cmd_comp); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (hdr->flags & ISCSI_FLAG_CMD_READ) { 36062306a36Sopenharmony_ci data_buf = &iser_task->data[ISER_DIR_IN]; 36162306a36Sopenharmony_ci prot_buf = &iser_task->prot[ISER_DIR_IN]; 36262306a36Sopenharmony_ci } else { 36362306a36Sopenharmony_ci data_buf = &iser_task->data[ISER_DIR_OUT]; 36462306a36Sopenharmony_ci prot_buf = &iser_task->prot[ISER_DIR_OUT]; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (scsi_sg_count(sc)) { /* using a scatter list */ 36862306a36Sopenharmony_ci data_buf->sg = scsi_sglist(sc); 36962306a36Sopenharmony_ci data_buf->size = scsi_sg_count(sc); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci data_buf->data_len = scsi_bufflen(sc); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (scsi_prot_sg_count(sc)) { 37462306a36Sopenharmony_ci prot_buf->sg = scsi_prot_sglist(sc); 37562306a36Sopenharmony_ci prot_buf->size = scsi_prot_sg_count(sc); 37662306a36Sopenharmony_ci prot_buf->data_len = (data_buf->data_len >> 37762306a36Sopenharmony_ci ilog2(sc->device->sector_size)) * 8; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (hdr->flags & ISCSI_FLAG_CMD_READ) { 38162306a36Sopenharmony_ci err = iser_prepare_read_cmd(task); 38262306a36Sopenharmony_ci if (err) 38362306a36Sopenharmony_ci goto send_command_error; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci if (hdr->flags & ISCSI_FLAG_CMD_WRITE) { 38662306a36Sopenharmony_ci err = iser_prepare_write_cmd(task, 38762306a36Sopenharmony_ci task->imm_count, 38862306a36Sopenharmony_ci task->imm_count + 38962306a36Sopenharmony_ci task->unsol_r2t.data_length, 39062306a36Sopenharmony_ci edtl); 39162306a36Sopenharmony_ci if (err) 39262306a36Sopenharmony_ci goto send_command_error; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci iser_task->status = ISER_TASK_STATUS_STARTED; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci err = iser_post_send(&iser_conn->ib_conn, tx_desc); 39862306a36Sopenharmony_ci if (!err) 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cisend_command_error: 40262306a36Sopenharmony_ci iser_err("conn %p failed task->itt %d err %d\n",conn, task->itt, err); 40362306a36Sopenharmony_ci return err; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci/** 40762306a36Sopenharmony_ci * iser_send_data_out - send data out PDU 40862306a36Sopenharmony_ci * @conn: link to matching iscsi connection 40962306a36Sopenharmony_ci * @task: SCSI command task 41062306a36Sopenharmony_ci * @hdr: pointer to the LLD's iSCSI message header 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ciint iser_send_data_out(struct iscsi_conn *conn, struct iscsi_task *task, 41362306a36Sopenharmony_ci struct iscsi_data *hdr) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct iser_conn *iser_conn = conn->dd_data; 41662306a36Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 41762306a36Sopenharmony_ci struct iser_tx_desc *tx_desc; 41862306a36Sopenharmony_ci struct iser_mem_reg *mem_reg; 41962306a36Sopenharmony_ci unsigned long buf_offset; 42062306a36Sopenharmony_ci unsigned long data_seg_len; 42162306a36Sopenharmony_ci uint32_t itt; 42262306a36Sopenharmony_ci int err; 42362306a36Sopenharmony_ci struct ib_sge *tx_dsg; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci itt = (__force uint32_t)hdr->itt; 42662306a36Sopenharmony_ci data_seg_len = ntoh24(hdr->dlength); 42762306a36Sopenharmony_ci buf_offset = ntohl(hdr->offset); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci iser_dbg("%s itt %d dseg_len %d offset %d\n", 43062306a36Sopenharmony_ci __func__,(int)itt,(int)data_seg_len,(int)buf_offset); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci tx_desc = kmem_cache_zalloc(ig.desc_cache, GFP_ATOMIC); 43362306a36Sopenharmony_ci if (!tx_desc) 43462306a36Sopenharmony_ci return -ENOMEM; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci tx_desc->type = ISCSI_TX_DATAOUT; 43762306a36Sopenharmony_ci tx_desc->cqe.done = iser_dataout_comp; 43862306a36Sopenharmony_ci tx_desc->iser_header.flags = ISER_VER; 43962306a36Sopenharmony_ci memcpy(&tx_desc->iscsi_header, hdr, sizeof(struct iscsi_hdr)); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* build the tx desc */ 44262306a36Sopenharmony_ci err = iser_initialize_task_headers(task, tx_desc); 44362306a36Sopenharmony_ci if (err) 44462306a36Sopenharmony_ci goto send_data_out_error; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci mem_reg = &iser_task->rdma_reg[ISER_DIR_OUT]; 44762306a36Sopenharmony_ci tx_dsg = &tx_desc->tx_sg[1]; 44862306a36Sopenharmony_ci tx_dsg->addr = mem_reg->sge.addr + buf_offset; 44962306a36Sopenharmony_ci tx_dsg->length = data_seg_len; 45062306a36Sopenharmony_ci tx_dsg->lkey = mem_reg->sge.lkey; 45162306a36Sopenharmony_ci tx_desc->num_sge = 2; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (buf_offset + data_seg_len > iser_task->data[ISER_DIR_OUT].data_len) { 45462306a36Sopenharmony_ci iser_err("Offset:%ld & DSL:%ld in Data-Out inconsistent with total len:%ld, itt:%d\n", 45562306a36Sopenharmony_ci buf_offset, data_seg_len, 45662306a36Sopenharmony_ci iser_task->data[ISER_DIR_OUT].data_len, itt); 45762306a36Sopenharmony_ci err = -EINVAL; 45862306a36Sopenharmony_ci goto send_data_out_error; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci iser_dbg("data-out itt: %d, offset: %ld, sz: %ld\n", 46162306a36Sopenharmony_ci itt, buf_offset, data_seg_len); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci err = iser_post_send(&iser_conn->ib_conn, tx_desc); 46462306a36Sopenharmony_ci if (!err) 46562306a36Sopenharmony_ci return 0; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cisend_data_out_error: 46862306a36Sopenharmony_ci kmem_cache_free(ig.desc_cache, tx_desc); 46962306a36Sopenharmony_ci iser_err("conn %p failed err %d\n", conn, err); 47062306a36Sopenharmony_ci return err; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ciint iser_send_control(struct iscsi_conn *conn, struct iscsi_task *task) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct iser_conn *iser_conn = conn->dd_data; 47662306a36Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 47762306a36Sopenharmony_ci struct iser_tx_desc *mdesc = &iser_task->desc; 47862306a36Sopenharmony_ci unsigned long data_seg_len; 47962306a36Sopenharmony_ci int err = 0; 48062306a36Sopenharmony_ci struct iser_device *device; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* build the tx desc regd header and add it to the tx desc dto */ 48362306a36Sopenharmony_ci iser_create_send_desc(iser_conn, mdesc, ISCSI_TX_CONTROL, 48462306a36Sopenharmony_ci iser_ctrl_comp); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci device = iser_conn->ib_conn.device; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci data_seg_len = ntoh24(task->hdr->dlength); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (data_seg_len > 0) { 49162306a36Sopenharmony_ci struct iser_login_desc *desc = &iser_conn->login_desc; 49262306a36Sopenharmony_ci struct ib_sge *tx_dsg = &mdesc->tx_sg[1]; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (task != conn->login_task) { 49562306a36Sopenharmony_ci iser_err("data present on non login task!!!\n"); 49662306a36Sopenharmony_ci goto send_control_error; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(device->ib_device, desc->req_dma, 50062306a36Sopenharmony_ci task->data_count, DMA_TO_DEVICE); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci memcpy(desc->req, task->data, task->data_count); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci ib_dma_sync_single_for_device(device->ib_device, desc->req_dma, 50562306a36Sopenharmony_ci task->data_count, DMA_TO_DEVICE); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci tx_dsg->addr = desc->req_dma; 50862306a36Sopenharmony_ci tx_dsg->length = task->data_count; 50962306a36Sopenharmony_ci tx_dsg->lkey = device->pd->local_dma_lkey; 51062306a36Sopenharmony_ci mdesc->num_sge = 2; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (task == conn->login_task) { 51462306a36Sopenharmony_ci iser_dbg("op %x dsl %lx, posting login rx buffer\n", 51562306a36Sopenharmony_ci task->hdr->opcode, data_seg_len); 51662306a36Sopenharmony_ci err = iser_post_recvl(iser_conn); 51762306a36Sopenharmony_ci if (err) 51862306a36Sopenharmony_ci goto send_control_error; 51962306a36Sopenharmony_ci err = iser_post_rx_bufs(conn, task->hdr); 52062306a36Sopenharmony_ci if (err) 52162306a36Sopenharmony_ci goto send_control_error; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci err = iser_post_send(&iser_conn->ib_conn, mdesc); 52562306a36Sopenharmony_ci if (!err) 52662306a36Sopenharmony_ci return 0; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cisend_control_error: 52962306a36Sopenharmony_ci iser_err("conn %p failed err %d\n",conn, err); 53062306a36Sopenharmony_ci return err; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_civoid iser_login_rsp(struct ib_cq *cq, struct ib_wc *wc) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci struct ib_conn *ib_conn = wc->qp->qp_context; 53662306a36Sopenharmony_ci struct iser_conn *iser_conn = to_iser_conn(ib_conn); 53762306a36Sopenharmony_ci struct iser_login_desc *desc = iser_login(wc->wr_cqe); 53862306a36Sopenharmony_ci struct iscsi_hdr *hdr; 53962306a36Sopenharmony_ci char *data; 54062306a36Sopenharmony_ci int length; 54162306a36Sopenharmony_ci bool full_feature_phase; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 54462306a36Sopenharmony_ci iser_err_comp(wc, "login_rsp"); 54562306a36Sopenharmony_ci return; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(ib_conn->device->ib_device, 54962306a36Sopenharmony_ci desc->rsp_dma, ISER_RX_LOGIN_SIZE, 55062306a36Sopenharmony_ci DMA_FROM_DEVICE); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci hdr = desc->rsp + sizeof(struct iser_ctrl); 55362306a36Sopenharmony_ci data = desc->rsp + ISER_HEADERS_LEN; 55462306a36Sopenharmony_ci length = wc->byte_len - ISER_HEADERS_LEN; 55562306a36Sopenharmony_ci full_feature_phase = ((hdr->flags & ISCSI_FULL_FEATURE_PHASE) == 55662306a36Sopenharmony_ci ISCSI_FULL_FEATURE_PHASE) && 55762306a36Sopenharmony_ci (hdr->flags & ISCSI_FLAG_CMD_FINAL); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode, 56062306a36Sopenharmony_ci hdr->itt, length); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci iscsi_iser_recv(iser_conn->iscsi_conn, hdr, data, length); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ib_dma_sync_single_for_device(ib_conn->device->ib_device, 56562306a36Sopenharmony_ci desc->rsp_dma, ISER_RX_LOGIN_SIZE, 56662306a36Sopenharmony_ci DMA_FROM_DEVICE); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (!full_feature_phase || 56962306a36Sopenharmony_ci iser_conn->iscsi_conn->session->discovery_sess) 57062306a36Sopenharmony_ci return; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Post the first RX buffer that is skipped in iser_post_rx_bufs() */ 57362306a36Sopenharmony_ci iser_post_recvm(iser_conn, iser_conn->rx_descs); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic inline int iser_inv_desc(struct iser_fr_desc *desc, u32 rkey) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci if (unlikely((!desc->sig_protected && rkey != desc->rsc.mr->rkey) || 57962306a36Sopenharmony_ci (desc->sig_protected && rkey != desc->rsc.sig_mr->rkey))) { 58062306a36Sopenharmony_ci iser_err("Bogus remote invalidation for rkey %#x\n", rkey); 58162306a36Sopenharmony_ci return -EINVAL; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (desc->sig_protected) 58562306a36Sopenharmony_ci desc->rsc.sig_mr->need_inval = false; 58662306a36Sopenharmony_ci else 58762306a36Sopenharmony_ci desc->rsc.mr->need_inval = false; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci return 0; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_cistatic int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc, 59362306a36Sopenharmony_ci struct iscsi_hdr *hdr) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci if (wc->wc_flags & IB_WC_WITH_INVALIDATE) { 59662306a36Sopenharmony_ci struct iscsi_task *task; 59762306a36Sopenharmony_ci u32 rkey = wc->ex.invalidate_rkey; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci iser_dbg("conn %p: remote invalidation for rkey %#x\n", 60062306a36Sopenharmony_ci iser_conn, rkey); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (unlikely(!iser_conn->snd_w_inv)) { 60362306a36Sopenharmony_ci iser_err("conn %p: unexpected remote invalidation, terminating connection\n", 60462306a36Sopenharmony_ci iser_conn); 60562306a36Sopenharmony_ci return -EPROTO; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci task = iscsi_itt_to_ctask(iser_conn->iscsi_conn, hdr->itt); 60962306a36Sopenharmony_ci if (likely(task)) { 61062306a36Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 61162306a36Sopenharmony_ci struct iser_fr_desc *desc; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (iser_task->dir[ISER_DIR_IN]) { 61462306a36Sopenharmony_ci desc = iser_task->rdma_reg[ISER_DIR_IN].desc; 61562306a36Sopenharmony_ci if (unlikely(iser_inv_desc(desc, rkey))) 61662306a36Sopenharmony_ci return -EINVAL; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (iser_task->dir[ISER_DIR_OUT]) { 62062306a36Sopenharmony_ci desc = iser_task->rdma_reg[ISER_DIR_OUT].desc; 62162306a36Sopenharmony_ci if (unlikely(iser_inv_desc(desc, rkey))) 62262306a36Sopenharmony_ci return -EINVAL; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci } else { 62562306a36Sopenharmony_ci iser_err("failed to get task for itt=%d\n", hdr->itt); 62662306a36Sopenharmony_ci return -EINVAL; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci return 0; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_civoid iser_task_rsp(struct ib_cq *cq, struct ib_wc *wc) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci struct ib_conn *ib_conn = wc->qp->qp_context; 63762306a36Sopenharmony_ci struct iser_conn *iser_conn = to_iser_conn(ib_conn); 63862306a36Sopenharmony_ci struct iser_rx_desc *desc = iser_rx(wc->wr_cqe); 63962306a36Sopenharmony_ci struct iscsi_hdr *hdr; 64062306a36Sopenharmony_ci int length, err; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 64362306a36Sopenharmony_ci iser_err_comp(wc, "task_rsp"); 64462306a36Sopenharmony_ci return; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(ib_conn->device->ib_device, 64862306a36Sopenharmony_ci desc->dma_addr, ISER_RX_PAYLOAD_SIZE, 64962306a36Sopenharmony_ci DMA_FROM_DEVICE); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci hdr = &desc->iscsi_header; 65262306a36Sopenharmony_ci length = wc->byte_len - ISER_HEADERS_LEN; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode, 65562306a36Sopenharmony_ci hdr->itt, length); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (iser_check_remote_inv(iser_conn, wc, hdr)) { 65862306a36Sopenharmony_ci iscsi_conn_failure(iser_conn->iscsi_conn, 65962306a36Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 66062306a36Sopenharmony_ci return; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci iscsi_iser_recv(iser_conn->iscsi_conn, hdr, desc->data, length); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci ib_dma_sync_single_for_device(ib_conn->device->ib_device, 66662306a36Sopenharmony_ci desc->dma_addr, ISER_RX_PAYLOAD_SIZE, 66762306a36Sopenharmony_ci DMA_FROM_DEVICE); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci err = iser_post_recvm(iser_conn, desc); 67062306a36Sopenharmony_ci if (err) 67162306a36Sopenharmony_ci iser_err("posting rx buffer err %d\n", err); 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_civoid iser_cmd_comp(struct ib_cq *cq, struct ib_wc *wc) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) 67762306a36Sopenharmony_ci iser_err_comp(wc, "command"); 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_civoid iser_ctrl_comp(struct ib_cq *cq, struct ib_wc *wc) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct iser_tx_desc *desc = iser_tx(wc->wr_cqe); 68362306a36Sopenharmony_ci struct iscsi_task *task; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 68662306a36Sopenharmony_ci iser_err_comp(wc, "control"); 68762306a36Sopenharmony_ci return; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* this arithmetic is legal by libiscsi dd_data allocation */ 69162306a36Sopenharmony_ci task = (void *)desc - sizeof(struct iscsi_task); 69262306a36Sopenharmony_ci if (task->hdr->itt == RESERVED_ITT) 69362306a36Sopenharmony_ci iscsi_put_task(task); 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_civoid iser_dataout_comp(struct ib_cq *cq, struct ib_wc *wc) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct iser_tx_desc *desc = iser_tx(wc->wr_cqe); 69962306a36Sopenharmony_ci struct ib_conn *ib_conn = wc->qp->qp_context; 70062306a36Sopenharmony_ci struct iser_device *device = ib_conn->device; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) 70362306a36Sopenharmony_ci iser_err_comp(wc, "dataout"); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci ib_dma_unmap_single(device->ib_device, desc->dma_addr, 70662306a36Sopenharmony_ci ISER_HEADERS_LEN, DMA_TO_DEVICE); 70762306a36Sopenharmony_ci kmem_cache_free(ig.desc_cache, desc); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_civoid iser_task_rdma_init(struct iscsi_iser_task *iser_task) 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci iser_task->status = ISER_TASK_STATUS_INIT; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci iser_task->dir[ISER_DIR_IN] = 0; 71662306a36Sopenharmony_ci iser_task->dir[ISER_DIR_OUT] = 0; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci iser_task->data[ISER_DIR_IN].data_len = 0; 71962306a36Sopenharmony_ci iser_task->data[ISER_DIR_OUT].data_len = 0; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci iser_task->prot[ISER_DIR_IN].data_len = 0; 72262306a36Sopenharmony_ci iser_task->prot[ISER_DIR_OUT].data_len = 0; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci iser_task->prot[ISER_DIR_IN].dma_nents = 0; 72562306a36Sopenharmony_ci iser_task->prot[ISER_DIR_OUT].dma_nents = 0; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci memset(&iser_task->rdma_reg[ISER_DIR_IN], 0, 72862306a36Sopenharmony_ci sizeof(struct iser_mem_reg)); 72962306a36Sopenharmony_ci memset(&iser_task->rdma_reg[ISER_DIR_OUT], 0, 73062306a36Sopenharmony_ci sizeof(struct iser_mem_reg)); 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_civoid iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (iser_task->dir[ISER_DIR_IN]) { 73762306a36Sopenharmony_ci iser_unreg_mem_fastreg(iser_task, ISER_DIR_IN); 73862306a36Sopenharmony_ci iser_dma_unmap_task_data(iser_task, ISER_DIR_IN, 73962306a36Sopenharmony_ci DMA_FROM_DEVICE); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (iser_task->dir[ISER_DIR_OUT]) { 74362306a36Sopenharmony_ci iser_unreg_mem_fastreg(iser_task, ISER_DIR_OUT); 74462306a36Sopenharmony_ci iser_dma_unmap_task_data(iser_task, ISER_DIR_OUT, 74562306a36Sopenharmony_ci DMA_TO_DEVICE); 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci} 748