18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2013-2014 Mellanox Technologies. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 68c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 78c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 88c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 98c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 128c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 138c2ecf20Sopenharmony_ci * conditions are met: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 168c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 178c2ecf20Sopenharmony_ci * disclaimer. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 208c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 218c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 228c2ecf20Sopenharmony_ci * provided with the distribution. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 258c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 268c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 278c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 288c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 298c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 308c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 318c2ecf20Sopenharmony_ci * SOFTWARE. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci#include <linux/kernel.h> 348c2ecf20Sopenharmony_ci#include <linux/slab.h> 358c2ecf20Sopenharmony_ci#include <linux/mm.h> 368c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 378c2ecf20Sopenharmony_ci#include <linux/kfifo.h> 388c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 398c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include "iscsi_iser.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* Register user buffer memory and initialize passive rdma 448c2ecf20Sopenharmony_ci * dto descriptor. Data size is stored in 458c2ecf20Sopenharmony_ci * task->data[ISER_DIR_IN].data_len, Protection size 468c2ecf20Sopenharmony_ci * os stored in task->prot[ISER_DIR_IN].data_len 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_cistatic int iser_prepare_read_cmd(struct iscsi_task *task) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 528c2ecf20Sopenharmony_ci struct iser_mem_reg *mem_reg; 538c2ecf20Sopenharmony_ci int err; 548c2ecf20Sopenharmony_ci struct iser_ctrl *hdr = &iser_task->desc.iser_header; 558c2ecf20Sopenharmony_ci struct iser_data_buf *buf_in = &iser_task->data[ISER_DIR_IN]; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci err = iser_dma_map_task_data(iser_task, 588c2ecf20Sopenharmony_ci buf_in, 598c2ecf20Sopenharmony_ci ISER_DIR_IN, 608c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 618c2ecf20Sopenharmony_ci if (err) 628c2ecf20Sopenharmony_ci return err; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (scsi_prot_sg_count(iser_task->sc)) { 658c2ecf20Sopenharmony_ci struct iser_data_buf *pbuf_in = &iser_task->prot[ISER_DIR_IN]; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci err = iser_dma_map_task_data(iser_task, 688c2ecf20Sopenharmony_ci pbuf_in, 698c2ecf20Sopenharmony_ci ISER_DIR_IN, 708c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 718c2ecf20Sopenharmony_ci if (err) 728c2ecf20Sopenharmony_ci return err; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci err = iser_reg_mem_fastreg(iser_task, ISER_DIR_IN, false); 768c2ecf20Sopenharmony_ci if (err) { 778c2ecf20Sopenharmony_ci iser_err("Failed to set up Data-IN RDMA\n"); 788c2ecf20Sopenharmony_ci return err; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci mem_reg = &iser_task->rdma_reg[ISER_DIR_IN]; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci hdr->flags |= ISER_RSV; 838c2ecf20Sopenharmony_ci hdr->read_stag = cpu_to_be32(mem_reg->rkey); 848c2ecf20Sopenharmony_ci hdr->read_va = cpu_to_be64(mem_reg->sge.addr); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci iser_dbg("Cmd itt:%d READ tags RKEY:%#.4X VA:%#llX\n", 878c2ecf20Sopenharmony_ci task->itt, mem_reg->rkey, 888c2ecf20Sopenharmony_ci (unsigned long long)mem_reg->sge.addr); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* Register user buffer memory and initialize passive rdma 948c2ecf20Sopenharmony_ci * dto descriptor. Data size is stored in 958c2ecf20Sopenharmony_ci * task->data[ISER_DIR_OUT].data_len, Protection size 968c2ecf20Sopenharmony_ci * is stored at task->prot[ISER_DIR_OUT].data_len 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_cistatic int 998c2ecf20Sopenharmony_ciiser_prepare_write_cmd(struct iscsi_task *task, 1008c2ecf20Sopenharmony_ci unsigned int imm_sz, 1018c2ecf20Sopenharmony_ci unsigned int unsol_sz, 1028c2ecf20Sopenharmony_ci unsigned int edtl) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 1058c2ecf20Sopenharmony_ci struct iser_mem_reg *mem_reg; 1068c2ecf20Sopenharmony_ci int err; 1078c2ecf20Sopenharmony_ci struct iser_ctrl *hdr = &iser_task->desc.iser_header; 1088c2ecf20Sopenharmony_ci struct iser_data_buf *buf_out = &iser_task->data[ISER_DIR_OUT]; 1098c2ecf20Sopenharmony_ci struct ib_sge *tx_dsg = &iser_task->desc.tx_sg[1]; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci err = iser_dma_map_task_data(iser_task, 1128c2ecf20Sopenharmony_ci buf_out, 1138c2ecf20Sopenharmony_ci ISER_DIR_OUT, 1148c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 1158c2ecf20Sopenharmony_ci if (err) 1168c2ecf20Sopenharmony_ci return err; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (scsi_prot_sg_count(iser_task->sc)) { 1198c2ecf20Sopenharmony_ci struct iser_data_buf *pbuf_out = &iser_task->prot[ISER_DIR_OUT]; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci err = iser_dma_map_task_data(iser_task, 1228c2ecf20Sopenharmony_ci pbuf_out, 1238c2ecf20Sopenharmony_ci ISER_DIR_OUT, 1248c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 1258c2ecf20Sopenharmony_ci if (err) 1268c2ecf20Sopenharmony_ci return err; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci err = iser_reg_mem_fastreg(iser_task, ISER_DIR_OUT, 1308c2ecf20Sopenharmony_ci buf_out->data_len == imm_sz); 1318c2ecf20Sopenharmony_ci if (err != 0) { 1328c2ecf20Sopenharmony_ci iser_err("Failed to register write cmd RDMA mem\n"); 1338c2ecf20Sopenharmony_ci return err; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci mem_reg = &iser_task->rdma_reg[ISER_DIR_OUT]; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (unsol_sz < edtl) { 1398c2ecf20Sopenharmony_ci hdr->flags |= ISER_WSV; 1408c2ecf20Sopenharmony_ci if (buf_out->data_len > imm_sz) { 1418c2ecf20Sopenharmony_ci hdr->write_stag = cpu_to_be32(mem_reg->rkey); 1428c2ecf20Sopenharmony_ci hdr->write_va = cpu_to_be64(mem_reg->sge.addr + unsol_sz); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci iser_dbg("Cmd itt:%d, WRITE tags, RKEY:%#.4X VA:%#llX + unsol:%d\n", 1468c2ecf20Sopenharmony_ci task->itt, mem_reg->rkey, 1478c2ecf20Sopenharmony_ci (unsigned long long)mem_reg->sge.addr, unsol_sz); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (imm_sz > 0) { 1518c2ecf20Sopenharmony_ci iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n", 1528c2ecf20Sopenharmony_ci task->itt, imm_sz); 1538c2ecf20Sopenharmony_ci tx_dsg->addr = mem_reg->sge.addr; 1548c2ecf20Sopenharmony_ci tx_dsg->length = imm_sz; 1558c2ecf20Sopenharmony_ci tx_dsg->lkey = mem_reg->sge.lkey; 1568c2ecf20Sopenharmony_ci iser_task->desc.num_sge = 2; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* creates a new tx descriptor and adds header regd buffer */ 1638c2ecf20Sopenharmony_cistatic void iser_create_send_desc(struct iser_conn *iser_conn, 1648c2ecf20Sopenharmony_ci struct iser_tx_desc *tx_desc) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct iser_device *device = iser_conn->ib_conn.device; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci ib_dma_sync_single_for_cpu(device->ib_device, 1698c2ecf20Sopenharmony_ci tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci memset(&tx_desc->iser_header, 0, sizeof(struct iser_ctrl)); 1728c2ecf20Sopenharmony_ci tx_desc->iser_header.flags = ISER_VER; 1738c2ecf20Sopenharmony_ci tx_desc->num_sge = 1; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void iser_free_login_buf(struct iser_conn *iser_conn) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct iser_device *device = iser_conn->ib_conn.device; 1798c2ecf20Sopenharmony_ci struct iser_login_desc *desc = &iser_conn->login_desc; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (!desc->req) 1828c2ecf20Sopenharmony_ci return; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci ib_dma_unmap_single(device->ib_device, desc->req_dma, 1858c2ecf20Sopenharmony_ci ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_TO_DEVICE); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci ib_dma_unmap_single(device->ib_device, desc->rsp_dma, 1888c2ecf20Sopenharmony_ci ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci kfree(desc->req); 1918c2ecf20Sopenharmony_ci kfree(desc->rsp); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* make sure we never redo any unmapping */ 1948c2ecf20Sopenharmony_ci desc->req = NULL; 1958c2ecf20Sopenharmony_ci desc->rsp = NULL; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int iser_alloc_login_buf(struct iser_conn *iser_conn) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct iser_device *device = iser_conn->ib_conn.device; 2018c2ecf20Sopenharmony_ci struct iser_login_desc *desc = &iser_conn->login_desc; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci desc->req = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); 2048c2ecf20Sopenharmony_ci if (!desc->req) 2058c2ecf20Sopenharmony_ci return -ENOMEM; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci desc->req_dma = ib_dma_map_single(device->ib_device, desc->req, 2088c2ecf20Sopenharmony_ci ISCSI_DEF_MAX_RECV_SEG_LEN, 2098c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 2108c2ecf20Sopenharmony_ci if (ib_dma_mapping_error(device->ib_device, 2118c2ecf20Sopenharmony_ci desc->req_dma)) 2128c2ecf20Sopenharmony_ci goto free_req; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci desc->rsp = kmalloc(ISER_RX_LOGIN_SIZE, GFP_KERNEL); 2158c2ecf20Sopenharmony_ci if (!desc->rsp) 2168c2ecf20Sopenharmony_ci goto unmap_req; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci desc->rsp_dma = ib_dma_map_single(device->ib_device, desc->rsp, 2198c2ecf20Sopenharmony_ci ISER_RX_LOGIN_SIZE, 2208c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 2218c2ecf20Sopenharmony_ci if (ib_dma_mapping_error(device->ib_device, 2228c2ecf20Sopenharmony_ci desc->rsp_dma)) 2238c2ecf20Sopenharmony_ci goto free_rsp; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return 0; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cifree_rsp: 2288c2ecf20Sopenharmony_ci kfree(desc->rsp); 2298c2ecf20Sopenharmony_ciunmap_req: 2308c2ecf20Sopenharmony_ci ib_dma_unmap_single(device->ib_device, desc->req_dma, 2318c2ecf20Sopenharmony_ci ISCSI_DEF_MAX_RECV_SEG_LEN, 2328c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 2338c2ecf20Sopenharmony_cifree_req: 2348c2ecf20Sopenharmony_ci kfree(desc->req); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return -ENOMEM; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ciint iser_alloc_rx_descriptors(struct iser_conn *iser_conn, 2408c2ecf20Sopenharmony_ci struct iscsi_session *session) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci int i, j; 2438c2ecf20Sopenharmony_ci u64 dma_addr; 2448c2ecf20Sopenharmony_ci struct iser_rx_desc *rx_desc; 2458c2ecf20Sopenharmony_ci struct ib_sge *rx_sg; 2468c2ecf20Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 2478c2ecf20Sopenharmony_ci struct iser_device *device = ib_conn->device; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci iser_conn->qp_max_recv_dtos = session->cmds_max; 2508c2ecf20Sopenharmony_ci iser_conn->qp_max_recv_dtos_mask = session->cmds_max - 1; /* cmds_max is 2^N */ 2518c2ecf20Sopenharmony_ci iser_conn->min_posted_rx = iser_conn->qp_max_recv_dtos >> 2; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (iser_alloc_fastreg_pool(ib_conn, session->scsi_cmds_max, 2548c2ecf20Sopenharmony_ci iser_conn->pages_per_mr)) 2558c2ecf20Sopenharmony_ci goto create_rdma_reg_res_failed; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (iser_alloc_login_buf(iser_conn)) 2588c2ecf20Sopenharmony_ci goto alloc_login_buf_fail; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci iser_conn->num_rx_descs = session->cmds_max; 2618c2ecf20Sopenharmony_ci iser_conn->rx_descs = kmalloc_array(iser_conn->num_rx_descs, 2628c2ecf20Sopenharmony_ci sizeof(struct iser_rx_desc), 2638c2ecf20Sopenharmony_ci GFP_KERNEL); 2648c2ecf20Sopenharmony_ci if (!iser_conn->rx_descs) 2658c2ecf20Sopenharmony_ci goto rx_desc_alloc_fail; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci rx_desc = iser_conn->rx_descs; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci for (i = 0; i < iser_conn->qp_max_recv_dtos; i++, rx_desc++) { 2708c2ecf20Sopenharmony_ci dma_addr = ib_dma_map_single(device->ib_device, (void *)rx_desc, 2718c2ecf20Sopenharmony_ci ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); 2728c2ecf20Sopenharmony_ci if (ib_dma_mapping_error(device->ib_device, dma_addr)) 2738c2ecf20Sopenharmony_ci goto rx_desc_dma_map_failed; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci rx_desc->dma_addr = dma_addr; 2768c2ecf20Sopenharmony_ci rx_desc->cqe.done = iser_task_rsp; 2778c2ecf20Sopenharmony_ci rx_sg = &rx_desc->rx_sg; 2788c2ecf20Sopenharmony_ci rx_sg->addr = rx_desc->dma_addr; 2798c2ecf20Sopenharmony_ci rx_sg->length = ISER_RX_PAYLOAD_SIZE; 2808c2ecf20Sopenharmony_ci rx_sg->lkey = device->pd->local_dma_lkey; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci iser_conn->rx_desc_head = 0; 2848c2ecf20Sopenharmony_ci return 0; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cirx_desc_dma_map_failed: 2878c2ecf20Sopenharmony_ci rx_desc = iser_conn->rx_descs; 2888c2ecf20Sopenharmony_ci for (j = 0; j < i; j++, rx_desc++) 2898c2ecf20Sopenharmony_ci ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr, 2908c2ecf20Sopenharmony_ci ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); 2918c2ecf20Sopenharmony_ci kfree(iser_conn->rx_descs); 2928c2ecf20Sopenharmony_ci iser_conn->rx_descs = NULL; 2938c2ecf20Sopenharmony_cirx_desc_alloc_fail: 2948c2ecf20Sopenharmony_ci iser_free_login_buf(iser_conn); 2958c2ecf20Sopenharmony_cialloc_login_buf_fail: 2968c2ecf20Sopenharmony_ci iser_free_fastreg_pool(ib_conn); 2978c2ecf20Sopenharmony_cicreate_rdma_reg_res_failed: 2988c2ecf20Sopenharmony_ci iser_err("failed allocating rx descriptors / data buffers\n"); 2998c2ecf20Sopenharmony_ci return -ENOMEM; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_civoid iser_free_rx_descriptors(struct iser_conn *iser_conn) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci int i; 3058c2ecf20Sopenharmony_ci struct iser_rx_desc *rx_desc; 3068c2ecf20Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 3078c2ecf20Sopenharmony_ci struct iser_device *device = ib_conn->device; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci iser_free_fastreg_pool(ib_conn); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci rx_desc = iser_conn->rx_descs; 3128c2ecf20Sopenharmony_ci for (i = 0; i < iser_conn->qp_max_recv_dtos; i++, rx_desc++) 3138c2ecf20Sopenharmony_ci ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr, 3148c2ecf20Sopenharmony_ci ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); 3158c2ecf20Sopenharmony_ci kfree(iser_conn->rx_descs); 3168c2ecf20Sopenharmony_ci /* make sure we never redo any unmapping */ 3178c2ecf20Sopenharmony_ci iser_conn->rx_descs = NULL; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci iser_free_login_buf(iser_conn); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int iser_post_rx_bufs(struct iscsi_conn *conn, struct iscsi_hdr *req) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct iser_conn *iser_conn = conn->dd_data; 3258c2ecf20Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 3268c2ecf20Sopenharmony_ci struct iscsi_session *session = conn->session; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci iser_dbg("req op %x flags %x\n", req->opcode, req->flags); 3298c2ecf20Sopenharmony_ci /* check if this is the last login - going to full feature phase */ 3308c2ecf20Sopenharmony_ci if ((req->flags & ISCSI_FULL_FEATURE_PHASE) != ISCSI_FULL_FEATURE_PHASE) 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* 3348c2ecf20Sopenharmony_ci * Check that there is one posted recv buffer 3358c2ecf20Sopenharmony_ci * (for the last login response). 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci WARN_ON(ib_conn->post_recv_buf_count != 1); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (session->discovery_sess) { 3408c2ecf20Sopenharmony_ci iser_info("Discovery session, re-using login RX buffer\n"); 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci } else 3438c2ecf20Sopenharmony_ci iser_info("Normal session, posting batch of RX %d buffers\n", 3448c2ecf20Sopenharmony_ci iser_conn->min_posted_rx); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Initial post receive buffers */ 3478c2ecf20Sopenharmony_ci if (iser_post_recvm(iser_conn, iser_conn->min_posted_rx)) 3488c2ecf20Sopenharmony_ci return -ENOMEM; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic inline bool iser_signal_comp(u8 sig_count) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci return ((sig_count % ISER_SIGNAL_CMD_COUNT) == 0); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci/** 3598c2ecf20Sopenharmony_ci * iser_send_command - send command PDU 3608c2ecf20Sopenharmony_ci * @conn: link to matching iscsi connection 3618c2ecf20Sopenharmony_ci * @task: SCSI command task 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ciint iser_send_command(struct iscsi_conn *conn, 3648c2ecf20Sopenharmony_ci struct iscsi_task *task) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct iser_conn *iser_conn = conn->dd_data; 3678c2ecf20Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 3688c2ecf20Sopenharmony_ci unsigned long edtl; 3698c2ecf20Sopenharmony_ci int err; 3708c2ecf20Sopenharmony_ci struct iser_data_buf *data_buf, *prot_buf; 3718c2ecf20Sopenharmony_ci struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr; 3728c2ecf20Sopenharmony_ci struct scsi_cmnd *sc = task->sc; 3738c2ecf20Sopenharmony_ci struct iser_tx_desc *tx_desc = &iser_task->desc; 3748c2ecf20Sopenharmony_ci u8 sig_count = ++iser_conn->ib_conn.sig_count; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci edtl = ntohl(hdr->data_length); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* build the tx desc regd header and add it to the tx desc dto */ 3798c2ecf20Sopenharmony_ci tx_desc->type = ISCSI_TX_SCSI_COMMAND; 3808c2ecf20Sopenharmony_ci tx_desc->cqe.done = iser_cmd_comp; 3818c2ecf20Sopenharmony_ci iser_create_send_desc(iser_conn, tx_desc); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (hdr->flags & ISCSI_FLAG_CMD_READ) { 3848c2ecf20Sopenharmony_ci data_buf = &iser_task->data[ISER_DIR_IN]; 3858c2ecf20Sopenharmony_ci prot_buf = &iser_task->prot[ISER_DIR_IN]; 3868c2ecf20Sopenharmony_ci } else { 3878c2ecf20Sopenharmony_ci data_buf = &iser_task->data[ISER_DIR_OUT]; 3888c2ecf20Sopenharmony_ci prot_buf = &iser_task->prot[ISER_DIR_OUT]; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (scsi_sg_count(sc)) { /* using a scatter list */ 3928c2ecf20Sopenharmony_ci data_buf->sg = scsi_sglist(sc); 3938c2ecf20Sopenharmony_ci data_buf->size = scsi_sg_count(sc); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci data_buf->data_len = scsi_bufflen(sc); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (scsi_prot_sg_count(sc)) { 3988c2ecf20Sopenharmony_ci prot_buf->sg = scsi_prot_sglist(sc); 3998c2ecf20Sopenharmony_ci prot_buf->size = scsi_prot_sg_count(sc); 4008c2ecf20Sopenharmony_ci prot_buf->data_len = (data_buf->data_len >> 4018c2ecf20Sopenharmony_ci ilog2(sc->device->sector_size)) * 8; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (hdr->flags & ISCSI_FLAG_CMD_READ) { 4058c2ecf20Sopenharmony_ci err = iser_prepare_read_cmd(task); 4068c2ecf20Sopenharmony_ci if (err) 4078c2ecf20Sopenharmony_ci goto send_command_error; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci if (hdr->flags & ISCSI_FLAG_CMD_WRITE) { 4108c2ecf20Sopenharmony_ci err = iser_prepare_write_cmd(task, 4118c2ecf20Sopenharmony_ci task->imm_count, 4128c2ecf20Sopenharmony_ci task->imm_count + 4138c2ecf20Sopenharmony_ci task->unsol_r2t.data_length, 4148c2ecf20Sopenharmony_ci edtl); 4158c2ecf20Sopenharmony_ci if (err) 4168c2ecf20Sopenharmony_ci goto send_command_error; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci iser_task->status = ISER_TASK_STATUS_STARTED; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci err = iser_post_send(&iser_conn->ib_conn, tx_desc, 4228c2ecf20Sopenharmony_ci iser_signal_comp(sig_count)); 4238c2ecf20Sopenharmony_ci if (!err) 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cisend_command_error: 4278c2ecf20Sopenharmony_ci iser_err("conn %p failed task->itt %d err %d\n",conn, task->itt, err); 4288c2ecf20Sopenharmony_ci return err; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/** 4328c2ecf20Sopenharmony_ci * iser_send_data_out - send data out PDU 4338c2ecf20Sopenharmony_ci * @conn: link to matching iscsi connection 4348c2ecf20Sopenharmony_ci * @task: SCSI command task 4358c2ecf20Sopenharmony_ci * @hdr: pointer to the LLD's iSCSI message header 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ciint iser_send_data_out(struct iscsi_conn *conn, 4388c2ecf20Sopenharmony_ci struct iscsi_task *task, 4398c2ecf20Sopenharmony_ci struct iscsi_data *hdr) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct iser_conn *iser_conn = conn->dd_data; 4428c2ecf20Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 4438c2ecf20Sopenharmony_ci struct iser_tx_desc *tx_desc; 4448c2ecf20Sopenharmony_ci struct iser_mem_reg *mem_reg; 4458c2ecf20Sopenharmony_ci unsigned long buf_offset; 4468c2ecf20Sopenharmony_ci unsigned long data_seg_len; 4478c2ecf20Sopenharmony_ci uint32_t itt; 4488c2ecf20Sopenharmony_ci int err; 4498c2ecf20Sopenharmony_ci struct ib_sge *tx_dsg; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci itt = (__force uint32_t)hdr->itt; 4528c2ecf20Sopenharmony_ci data_seg_len = ntoh24(hdr->dlength); 4538c2ecf20Sopenharmony_ci buf_offset = ntohl(hdr->offset); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci iser_dbg("%s itt %d dseg_len %d offset %d\n", 4568c2ecf20Sopenharmony_ci __func__,(int)itt,(int)data_seg_len,(int)buf_offset); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci tx_desc = kmem_cache_zalloc(ig.desc_cache, GFP_ATOMIC); 4598c2ecf20Sopenharmony_ci if (!tx_desc) 4608c2ecf20Sopenharmony_ci return -ENOMEM; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci tx_desc->type = ISCSI_TX_DATAOUT; 4638c2ecf20Sopenharmony_ci tx_desc->cqe.done = iser_dataout_comp; 4648c2ecf20Sopenharmony_ci tx_desc->iser_header.flags = ISER_VER; 4658c2ecf20Sopenharmony_ci memcpy(&tx_desc->iscsi_header, hdr, sizeof(struct iscsi_hdr)); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* build the tx desc */ 4688c2ecf20Sopenharmony_ci err = iser_initialize_task_headers(task, tx_desc); 4698c2ecf20Sopenharmony_ci if (err) 4708c2ecf20Sopenharmony_ci goto send_data_out_error; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci mem_reg = &iser_task->rdma_reg[ISER_DIR_OUT]; 4738c2ecf20Sopenharmony_ci tx_dsg = &tx_desc->tx_sg[1]; 4748c2ecf20Sopenharmony_ci tx_dsg->addr = mem_reg->sge.addr + buf_offset; 4758c2ecf20Sopenharmony_ci tx_dsg->length = data_seg_len; 4768c2ecf20Sopenharmony_ci tx_dsg->lkey = mem_reg->sge.lkey; 4778c2ecf20Sopenharmony_ci tx_desc->num_sge = 2; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (buf_offset + data_seg_len > iser_task->data[ISER_DIR_OUT].data_len) { 4808c2ecf20Sopenharmony_ci iser_err("Offset:%ld & DSL:%ld in Data-Out inconsistent with total len:%ld, itt:%d\n", 4818c2ecf20Sopenharmony_ci buf_offset, data_seg_len, 4828c2ecf20Sopenharmony_ci iser_task->data[ISER_DIR_OUT].data_len, itt); 4838c2ecf20Sopenharmony_ci err = -EINVAL; 4848c2ecf20Sopenharmony_ci goto send_data_out_error; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci iser_dbg("data-out itt: %d, offset: %ld, sz: %ld\n", 4878c2ecf20Sopenharmony_ci itt, buf_offset, data_seg_len); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci err = iser_post_send(&iser_conn->ib_conn, tx_desc, true); 4918c2ecf20Sopenharmony_ci if (!err) 4928c2ecf20Sopenharmony_ci return 0; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cisend_data_out_error: 4958c2ecf20Sopenharmony_ci kmem_cache_free(ig.desc_cache, tx_desc); 4968c2ecf20Sopenharmony_ci iser_err("conn %p failed err %d\n", conn, err); 4978c2ecf20Sopenharmony_ci return err; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ciint iser_send_control(struct iscsi_conn *conn, 5018c2ecf20Sopenharmony_ci struct iscsi_task *task) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct iser_conn *iser_conn = conn->dd_data; 5048c2ecf20Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 5058c2ecf20Sopenharmony_ci struct iser_tx_desc *mdesc = &iser_task->desc; 5068c2ecf20Sopenharmony_ci unsigned long data_seg_len; 5078c2ecf20Sopenharmony_ci int err = 0; 5088c2ecf20Sopenharmony_ci struct iser_device *device; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* build the tx desc regd header and add it to the tx desc dto */ 5118c2ecf20Sopenharmony_ci mdesc->type = ISCSI_TX_CONTROL; 5128c2ecf20Sopenharmony_ci mdesc->cqe.done = iser_ctrl_comp; 5138c2ecf20Sopenharmony_ci iser_create_send_desc(iser_conn, mdesc); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci device = iser_conn->ib_conn.device; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci data_seg_len = ntoh24(task->hdr->dlength); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (data_seg_len > 0) { 5208c2ecf20Sopenharmony_ci struct iser_login_desc *desc = &iser_conn->login_desc; 5218c2ecf20Sopenharmony_ci struct ib_sge *tx_dsg = &mdesc->tx_sg[1]; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (task != conn->login_task) { 5248c2ecf20Sopenharmony_ci iser_err("data present on non login task!!!\n"); 5258c2ecf20Sopenharmony_ci goto send_control_error; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ib_dma_sync_single_for_cpu(device->ib_device, desc->req_dma, 5298c2ecf20Sopenharmony_ci task->data_count, DMA_TO_DEVICE); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci memcpy(desc->req, task->data, task->data_count); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci ib_dma_sync_single_for_device(device->ib_device, desc->req_dma, 5348c2ecf20Sopenharmony_ci task->data_count, DMA_TO_DEVICE); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci tx_dsg->addr = desc->req_dma; 5378c2ecf20Sopenharmony_ci tx_dsg->length = task->data_count; 5388c2ecf20Sopenharmony_ci tx_dsg->lkey = device->pd->local_dma_lkey; 5398c2ecf20Sopenharmony_ci mdesc->num_sge = 2; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (task == conn->login_task) { 5438c2ecf20Sopenharmony_ci iser_dbg("op %x dsl %lx, posting login rx buffer\n", 5448c2ecf20Sopenharmony_ci task->hdr->opcode, data_seg_len); 5458c2ecf20Sopenharmony_ci err = iser_post_recvl(iser_conn); 5468c2ecf20Sopenharmony_ci if (err) 5478c2ecf20Sopenharmony_ci goto send_control_error; 5488c2ecf20Sopenharmony_ci err = iser_post_rx_bufs(conn, task->hdr); 5498c2ecf20Sopenharmony_ci if (err) 5508c2ecf20Sopenharmony_ci goto send_control_error; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci err = iser_post_send(&iser_conn->ib_conn, mdesc, true); 5548c2ecf20Sopenharmony_ci if (!err) 5558c2ecf20Sopenharmony_ci return 0; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cisend_control_error: 5588c2ecf20Sopenharmony_ci iser_err("conn %p failed err %d\n",conn, err); 5598c2ecf20Sopenharmony_ci return err; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_civoid iser_login_rsp(struct ib_cq *cq, struct ib_wc *wc) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci struct ib_conn *ib_conn = wc->qp->qp_context; 5658c2ecf20Sopenharmony_ci struct iser_conn *iser_conn = to_iser_conn(ib_conn); 5668c2ecf20Sopenharmony_ci struct iser_login_desc *desc = iser_login(wc->wr_cqe); 5678c2ecf20Sopenharmony_ci struct iscsi_hdr *hdr; 5688c2ecf20Sopenharmony_ci char *data; 5698c2ecf20Sopenharmony_ci int length; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 5728c2ecf20Sopenharmony_ci iser_err_comp(wc, "login_rsp"); 5738c2ecf20Sopenharmony_ci return; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci ib_dma_sync_single_for_cpu(ib_conn->device->ib_device, 5778c2ecf20Sopenharmony_ci desc->rsp_dma, ISER_RX_LOGIN_SIZE, 5788c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci hdr = desc->rsp + sizeof(struct iser_ctrl); 5818c2ecf20Sopenharmony_ci data = desc->rsp + ISER_HEADERS_LEN; 5828c2ecf20Sopenharmony_ci length = wc->byte_len - ISER_HEADERS_LEN; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode, 5858c2ecf20Sopenharmony_ci hdr->itt, length); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci iscsi_iser_recv(iser_conn->iscsi_conn, hdr, data, length); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci ib_dma_sync_single_for_device(ib_conn->device->ib_device, 5908c2ecf20Sopenharmony_ci desc->rsp_dma, ISER_RX_LOGIN_SIZE, 5918c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci ib_conn->post_recv_buf_count--; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic inline int 5978c2ecf20Sopenharmony_ciiser_inv_desc(struct iser_fr_desc *desc, u32 rkey) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci if (unlikely((!desc->sig_protected && rkey != desc->rsc.mr->rkey) || 6008c2ecf20Sopenharmony_ci (desc->sig_protected && rkey != desc->rsc.sig_mr->rkey))) { 6018c2ecf20Sopenharmony_ci iser_err("Bogus remote invalidation for rkey %#x\n", rkey); 6028c2ecf20Sopenharmony_ci return -EINVAL; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (desc->sig_protected) 6068c2ecf20Sopenharmony_ci desc->rsc.sig_mr->need_inval = false; 6078c2ecf20Sopenharmony_ci else 6088c2ecf20Sopenharmony_ci desc->rsc.mr->need_inval = false; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic int 6148c2ecf20Sopenharmony_ciiser_check_remote_inv(struct iser_conn *iser_conn, 6158c2ecf20Sopenharmony_ci struct ib_wc *wc, 6168c2ecf20Sopenharmony_ci struct iscsi_hdr *hdr) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci if (wc->wc_flags & IB_WC_WITH_INVALIDATE) { 6198c2ecf20Sopenharmony_ci struct iscsi_task *task; 6208c2ecf20Sopenharmony_ci u32 rkey = wc->ex.invalidate_rkey; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci iser_dbg("conn %p: remote invalidation for rkey %#x\n", 6238c2ecf20Sopenharmony_ci iser_conn, rkey); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (unlikely(!iser_conn->snd_w_inv)) { 6268c2ecf20Sopenharmony_ci iser_err("conn %p: unexpected remote invalidation, terminating connection\n", 6278c2ecf20Sopenharmony_ci iser_conn); 6288c2ecf20Sopenharmony_ci return -EPROTO; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci task = iscsi_itt_to_ctask(iser_conn->iscsi_conn, hdr->itt); 6328c2ecf20Sopenharmony_ci if (likely(task)) { 6338c2ecf20Sopenharmony_ci struct iscsi_iser_task *iser_task = task->dd_data; 6348c2ecf20Sopenharmony_ci struct iser_fr_desc *desc; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (iser_task->dir[ISER_DIR_IN]) { 6378c2ecf20Sopenharmony_ci desc = iser_task->rdma_reg[ISER_DIR_IN].mem_h; 6388c2ecf20Sopenharmony_ci if (unlikely(iser_inv_desc(desc, rkey))) 6398c2ecf20Sopenharmony_ci return -EINVAL; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (iser_task->dir[ISER_DIR_OUT]) { 6438c2ecf20Sopenharmony_ci desc = iser_task->rdma_reg[ISER_DIR_OUT].mem_h; 6448c2ecf20Sopenharmony_ci if (unlikely(iser_inv_desc(desc, rkey))) 6458c2ecf20Sopenharmony_ci return -EINVAL; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci } else { 6488c2ecf20Sopenharmony_ci iser_err("failed to get task for itt=%d\n", hdr->itt); 6498c2ecf20Sopenharmony_ci return -EINVAL; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci return 0; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_civoid iser_task_rsp(struct ib_cq *cq, struct ib_wc *wc) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct ib_conn *ib_conn = wc->qp->qp_context; 6608c2ecf20Sopenharmony_ci struct iser_conn *iser_conn = to_iser_conn(ib_conn); 6618c2ecf20Sopenharmony_ci struct iser_rx_desc *desc = iser_rx(wc->wr_cqe); 6628c2ecf20Sopenharmony_ci struct iscsi_hdr *hdr; 6638c2ecf20Sopenharmony_ci int length; 6648c2ecf20Sopenharmony_ci int outstanding, count, err; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 6678c2ecf20Sopenharmony_ci iser_err_comp(wc, "task_rsp"); 6688c2ecf20Sopenharmony_ci return; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci ib_dma_sync_single_for_cpu(ib_conn->device->ib_device, 6728c2ecf20Sopenharmony_ci desc->dma_addr, ISER_RX_PAYLOAD_SIZE, 6738c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci hdr = &desc->iscsi_header; 6768c2ecf20Sopenharmony_ci length = wc->byte_len - ISER_HEADERS_LEN; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode, 6798c2ecf20Sopenharmony_ci hdr->itt, length); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (iser_check_remote_inv(iser_conn, wc, hdr)) { 6828c2ecf20Sopenharmony_ci iscsi_conn_failure(iser_conn->iscsi_conn, 6838c2ecf20Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 6848c2ecf20Sopenharmony_ci return; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci iscsi_iser_recv(iser_conn->iscsi_conn, hdr, desc->data, length); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci ib_dma_sync_single_for_device(ib_conn->device->ib_device, 6908c2ecf20Sopenharmony_ci desc->dma_addr, ISER_RX_PAYLOAD_SIZE, 6918c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* decrementing conn->post_recv_buf_count only --after-- freeing the * 6948c2ecf20Sopenharmony_ci * task eliminates the need to worry on tasks which are completed in * 6958c2ecf20Sopenharmony_ci * parallel to the execution of iser_conn_term. So the code that waits * 6968c2ecf20Sopenharmony_ci * for the posted rx bufs refcount to become zero handles everything */ 6978c2ecf20Sopenharmony_ci ib_conn->post_recv_buf_count--; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci outstanding = ib_conn->post_recv_buf_count; 7008c2ecf20Sopenharmony_ci if (outstanding + iser_conn->min_posted_rx <= iser_conn->qp_max_recv_dtos) { 7018c2ecf20Sopenharmony_ci count = min(iser_conn->qp_max_recv_dtos - outstanding, 7028c2ecf20Sopenharmony_ci iser_conn->min_posted_rx); 7038c2ecf20Sopenharmony_ci err = iser_post_recvm(iser_conn, count); 7048c2ecf20Sopenharmony_ci if (err) 7058c2ecf20Sopenharmony_ci iser_err("posting %d rx bufs err %d\n", count, err); 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_civoid iser_cmd_comp(struct ib_cq *cq, struct ib_wc *wc) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) 7128c2ecf20Sopenharmony_ci iser_err_comp(wc, "command"); 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_civoid iser_ctrl_comp(struct ib_cq *cq, struct ib_wc *wc) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci struct iser_tx_desc *desc = iser_tx(wc->wr_cqe); 7188c2ecf20Sopenharmony_ci struct iscsi_task *task; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 7218c2ecf20Sopenharmony_ci iser_err_comp(wc, "control"); 7228c2ecf20Sopenharmony_ci return; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* this arithmetic is legal by libiscsi dd_data allocation */ 7268c2ecf20Sopenharmony_ci task = (void *)desc - sizeof(struct iscsi_task); 7278c2ecf20Sopenharmony_ci if (task->hdr->itt == RESERVED_ITT) 7288c2ecf20Sopenharmony_ci iscsi_put_task(task); 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_civoid iser_dataout_comp(struct ib_cq *cq, struct ib_wc *wc) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct iser_tx_desc *desc = iser_tx(wc->wr_cqe); 7348c2ecf20Sopenharmony_ci struct ib_conn *ib_conn = wc->qp->qp_context; 7358c2ecf20Sopenharmony_ci struct iser_device *device = ib_conn->device; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) 7388c2ecf20Sopenharmony_ci iser_err_comp(wc, "dataout"); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci ib_dma_unmap_single(device->ib_device, desc->dma_addr, 7418c2ecf20Sopenharmony_ci ISER_HEADERS_LEN, DMA_TO_DEVICE); 7428c2ecf20Sopenharmony_ci kmem_cache_free(ig.desc_cache, desc); 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_civoid iser_task_rdma_init(struct iscsi_iser_task *iser_task) 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci iser_task->status = ISER_TASK_STATUS_INIT; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci iser_task->dir[ISER_DIR_IN] = 0; 7518c2ecf20Sopenharmony_ci iser_task->dir[ISER_DIR_OUT] = 0; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci iser_task->data[ISER_DIR_IN].data_len = 0; 7548c2ecf20Sopenharmony_ci iser_task->data[ISER_DIR_OUT].data_len = 0; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci iser_task->prot[ISER_DIR_IN].data_len = 0; 7578c2ecf20Sopenharmony_ci iser_task->prot[ISER_DIR_OUT].data_len = 0; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci iser_task->prot[ISER_DIR_IN].dma_nents = 0; 7608c2ecf20Sopenharmony_ci iser_task->prot[ISER_DIR_OUT].dma_nents = 0; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci memset(&iser_task->rdma_reg[ISER_DIR_IN], 0, 7638c2ecf20Sopenharmony_ci sizeof(struct iser_mem_reg)); 7648c2ecf20Sopenharmony_ci memset(&iser_task->rdma_reg[ISER_DIR_OUT], 0, 7658c2ecf20Sopenharmony_ci sizeof(struct iser_mem_reg)); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_civoid iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci int prot_count = scsi_prot_sg_count(iser_task->sc); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (iser_task->dir[ISER_DIR_IN]) { 7738c2ecf20Sopenharmony_ci iser_unreg_mem_fastreg(iser_task, ISER_DIR_IN); 7748c2ecf20Sopenharmony_ci iser_dma_unmap_task_data(iser_task, 7758c2ecf20Sopenharmony_ci &iser_task->data[ISER_DIR_IN], 7768c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 7778c2ecf20Sopenharmony_ci if (prot_count) 7788c2ecf20Sopenharmony_ci iser_dma_unmap_task_data(iser_task, 7798c2ecf20Sopenharmony_ci &iser_task->prot[ISER_DIR_IN], 7808c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (iser_task->dir[ISER_DIR_OUT]) { 7848c2ecf20Sopenharmony_ci iser_unreg_mem_fastreg(iser_task, ISER_DIR_OUT); 7858c2ecf20Sopenharmony_ci iser_dma_unmap_task_data(iser_task, 7868c2ecf20Sopenharmony_ci &iser_task->data[ISER_DIR_OUT], 7878c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 7888c2ecf20Sopenharmony_ci if (prot_count) 7898c2ecf20Sopenharmony_ci iser_dma_unmap_task_data(iser_task, 7908c2ecf20Sopenharmony_ci &iser_task->prot[ISER_DIR_OUT], 7918c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci} 794