Path: blob/master/drivers/infiniband/ulp/iser/iser_initiator.c
15112 views
/*1* Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.2*3* This software is available to you under a choice of one of two4* licenses. You may choose to be licensed under the terms of the GNU5* General Public License (GPL) Version 2, available from the file6* COPYING in the main directory of this source tree, or the7* OpenIB.org BSD license below:8*9* Redistribution and use in source and binary forms, with or10* without modification, are permitted provided that the following11* conditions are met:12*13* - Redistributions of source code must retain the above14* copyright notice, this list of conditions and the following15* disclaimer.16*17* - Redistributions in binary form must reproduce the above18* copyright notice, this list of conditions and the following19* disclaimer in the documentation and/or other materials20* provided with the distribution.21*22* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,23* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF24* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND25* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS26* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN27* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN28* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE29* SOFTWARE.30*/31#include <linux/kernel.h>32#include <linux/slab.h>33#include <linux/mm.h>34#include <linux/scatterlist.h>35#include <linux/kfifo.h>36#include <scsi/scsi_cmnd.h>37#include <scsi/scsi_host.h>3839#include "iscsi_iser.h"4041/* Register user buffer memory and initialize passive rdma42* dto descriptor. Total data size is stored in43* iser_task->data[ISER_DIR_IN].data_len44*/45static int iser_prepare_read_cmd(struct iscsi_task *task,46unsigned int edtl)4748{49struct iscsi_iser_task *iser_task = task->dd_data;50struct iser_regd_buf *regd_buf;51int err;52struct iser_hdr *hdr = &iser_task->desc.iser_header;53struct iser_data_buf *buf_in = &iser_task->data[ISER_DIR_IN];5455err = iser_dma_map_task_data(iser_task,56buf_in,57ISER_DIR_IN,58DMA_FROM_DEVICE);59if (err)60return err;6162if (edtl > iser_task->data[ISER_DIR_IN].data_len) {63iser_err("Total data length: %ld, less than EDTL: "64"%d, in READ cmd BHS itt: %d, conn: 0x%p\n",65iser_task->data[ISER_DIR_IN].data_len, edtl,66task->itt, iser_task->iser_conn);67return -EINVAL;68}6970err = iser_reg_rdma_mem(iser_task,ISER_DIR_IN);71if (err) {72iser_err("Failed to set up Data-IN RDMA\n");73return err;74}75regd_buf = &iser_task->rdma_regd[ISER_DIR_IN];7677hdr->flags |= ISER_RSV;78hdr->read_stag = cpu_to_be32(regd_buf->reg.rkey);79hdr->read_va = cpu_to_be64(regd_buf->reg.va);8081iser_dbg("Cmd itt:%d READ tags RKEY:%#.4X VA:%#llX\n",82task->itt, regd_buf->reg.rkey,83(unsigned long long)regd_buf->reg.va);8485return 0;86}8788/* Register user buffer memory and initialize passive rdma89* dto descriptor. Total data size is stored in90* task->data[ISER_DIR_OUT].data_len91*/92static int93iser_prepare_write_cmd(struct iscsi_task *task,94unsigned int imm_sz,95unsigned int unsol_sz,96unsigned int edtl)97{98struct iscsi_iser_task *iser_task = task->dd_data;99struct iser_regd_buf *regd_buf;100int err;101struct iser_hdr *hdr = &iser_task->desc.iser_header;102struct iser_data_buf *buf_out = &iser_task->data[ISER_DIR_OUT];103struct ib_sge *tx_dsg = &iser_task->desc.tx_sg[1];104105err = iser_dma_map_task_data(iser_task,106buf_out,107ISER_DIR_OUT,108DMA_TO_DEVICE);109if (err)110return err;111112if (edtl > iser_task->data[ISER_DIR_OUT].data_len) {113iser_err("Total data length: %ld, less than EDTL: %d, "114"in WRITE cmd BHS itt: %d, conn: 0x%p\n",115iser_task->data[ISER_DIR_OUT].data_len,116edtl, task->itt, task->conn);117return -EINVAL;118}119120err = iser_reg_rdma_mem(iser_task,ISER_DIR_OUT);121if (err != 0) {122iser_err("Failed to register write cmd RDMA mem\n");123return err;124}125126regd_buf = &iser_task->rdma_regd[ISER_DIR_OUT];127128if (unsol_sz < edtl) {129hdr->flags |= ISER_WSV;130hdr->write_stag = cpu_to_be32(regd_buf->reg.rkey);131hdr->write_va = cpu_to_be64(regd_buf->reg.va + unsol_sz);132133iser_dbg("Cmd itt:%d, WRITE tags, RKEY:%#.4X "134"VA:%#llX + unsol:%d\n",135task->itt, regd_buf->reg.rkey,136(unsigned long long)regd_buf->reg.va, unsol_sz);137}138139if (imm_sz > 0) {140iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n",141task->itt, imm_sz);142tx_dsg->addr = regd_buf->reg.va;143tx_dsg->length = imm_sz;144tx_dsg->lkey = regd_buf->reg.lkey;145iser_task->desc.num_sge = 2;146}147148return 0;149}150151/* creates a new tx descriptor and adds header regd buffer */152static void iser_create_send_desc(struct iser_conn *ib_conn,153struct iser_tx_desc *tx_desc)154{155struct iser_device *device = ib_conn->device;156157ib_dma_sync_single_for_cpu(device->ib_device,158tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE);159160memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr));161tx_desc->iser_header.flags = ISER_VER;162163tx_desc->num_sge = 1;164165if (tx_desc->tx_sg[0].lkey != device->mr->lkey) {166tx_desc->tx_sg[0].lkey = device->mr->lkey;167iser_dbg("sdesc %p lkey mismatch, fixing\n", tx_desc);168}169}170171172static int iser_alloc_rx_descriptors(struct iser_conn *ib_conn)173{174int i, j;175u64 dma_addr;176struct iser_rx_desc *rx_desc;177struct ib_sge *rx_sg;178struct iser_device *device = ib_conn->device;179180ib_conn->rx_descs = kmalloc(ISER_QP_MAX_RECV_DTOS *181sizeof(struct iser_rx_desc), GFP_KERNEL);182if (!ib_conn->rx_descs)183goto rx_desc_alloc_fail;184185rx_desc = ib_conn->rx_descs;186187for (i = 0; i < ISER_QP_MAX_RECV_DTOS; i++, rx_desc++) {188dma_addr = ib_dma_map_single(device->ib_device, (void *)rx_desc,189ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);190if (ib_dma_mapping_error(device->ib_device, dma_addr))191goto rx_desc_dma_map_failed;192193rx_desc->dma_addr = dma_addr;194195rx_sg = &rx_desc->rx_sg;196rx_sg->addr = rx_desc->dma_addr;197rx_sg->length = ISER_RX_PAYLOAD_SIZE;198rx_sg->lkey = device->mr->lkey;199}200201ib_conn->rx_desc_head = 0;202return 0;203204rx_desc_dma_map_failed:205rx_desc = ib_conn->rx_descs;206for (j = 0; j < i; j++, rx_desc++)207ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr,208ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);209kfree(ib_conn->rx_descs);210ib_conn->rx_descs = NULL;211rx_desc_alloc_fail:212iser_err("failed allocating rx descriptors / data buffers\n");213return -ENOMEM;214}215216void iser_free_rx_descriptors(struct iser_conn *ib_conn)217{218int i;219struct iser_rx_desc *rx_desc;220struct iser_device *device = ib_conn->device;221222if (ib_conn->login_buf) {223ib_dma_unmap_single(device->ib_device, ib_conn->login_dma,224ISER_RX_LOGIN_SIZE, DMA_FROM_DEVICE);225kfree(ib_conn->login_buf);226}227228if (!ib_conn->rx_descs)229return;230231rx_desc = ib_conn->rx_descs;232for (i = 0; i < ISER_QP_MAX_RECV_DTOS; i++, rx_desc++)233ib_dma_unmap_single(device->ib_device, rx_desc->dma_addr,234ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);235kfree(ib_conn->rx_descs);236}237238/**239* iser_conn_set_full_featured_mode - (iSER API)240*/241int iser_conn_set_full_featured_mode(struct iscsi_conn *conn)242{243struct iscsi_iser_conn *iser_conn = conn->dd_data;244245iser_dbg("Initially post: %d\n", ISER_MIN_POSTED_RX);246247/* Check that there is no posted recv or send buffers left - */248/* they must be consumed during the login phase */249BUG_ON(iser_conn->ib_conn->post_recv_buf_count != 0);250BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);251252if (iser_alloc_rx_descriptors(iser_conn->ib_conn))253return -ENOMEM;254255/* Initial post receive buffers */256if (iser_post_recvm(iser_conn->ib_conn, ISER_MIN_POSTED_RX))257return -ENOMEM;258259return 0;260}261262/**263* iser_send_command - send command PDU264*/265int iser_send_command(struct iscsi_conn *conn,266struct iscsi_task *task)267{268struct iscsi_iser_conn *iser_conn = conn->dd_data;269struct iscsi_iser_task *iser_task = task->dd_data;270unsigned long edtl;271int err;272struct iser_data_buf *data_buf;273struct iscsi_cmd *hdr = (struct iscsi_cmd *)task->hdr;274struct scsi_cmnd *sc = task->sc;275struct iser_tx_desc *tx_desc = &iser_task->desc;276277edtl = ntohl(hdr->data_length);278279/* build the tx desc regd header and add it to the tx desc dto */280tx_desc->type = ISCSI_TX_SCSI_COMMAND;281iser_create_send_desc(iser_conn->ib_conn, tx_desc);282283if (hdr->flags & ISCSI_FLAG_CMD_READ)284data_buf = &iser_task->data[ISER_DIR_IN];285else286data_buf = &iser_task->data[ISER_DIR_OUT];287288if (scsi_sg_count(sc)) { /* using a scatter list */289data_buf->buf = scsi_sglist(sc);290data_buf->size = scsi_sg_count(sc);291}292293data_buf->data_len = scsi_bufflen(sc);294295if (hdr->flags & ISCSI_FLAG_CMD_READ) {296err = iser_prepare_read_cmd(task, edtl);297if (err)298goto send_command_error;299}300if (hdr->flags & ISCSI_FLAG_CMD_WRITE) {301err = iser_prepare_write_cmd(task,302task->imm_count,303task->imm_count +304task->unsol_r2t.data_length,305edtl);306if (err)307goto send_command_error;308}309310iser_task->status = ISER_TASK_STATUS_STARTED;311312err = iser_post_send(iser_conn->ib_conn, tx_desc);313if (!err)314return 0;315316send_command_error:317iser_err("conn %p failed task->itt %d err %d\n",conn, task->itt, err);318return err;319}320321/**322* iser_send_data_out - send data out PDU323*/324int iser_send_data_out(struct iscsi_conn *conn,325struct iscsi_task *task,326struct iscsi_data *hdr)327{328struct iscsi_iser_conn *iser_conn = conn->dd_data;329struct iscsi_iser_task *iser_task = task->dd_data;330struct iser_tx_desc *tx_desc = NULL;331struct iser_regd_buf *regd_buf;332unsigned long buf_offset;333unsigned long data_seg_len;334uint32_t itt;335int err = 0;336struct ib_sge *tx_dsg;337338itt = (__force uint32_t)hdr->itt;339data_seg_len = ntoh24(hdr->dlength);340buf_offset = ntohl(hdr->offset);341342iser_dbg("%s itt %d dseg_len %d offset %d\n",343__func__,(int)itt,(int)data_seg_len,(int)buf_offset);344345tx_desc = kmem_cache_zalloc(ig.desc_cache, GFP_ATOMIC);346if (tx_desc == NULL) {347iser_err("Failed to alloc desc for post dataout\n");348return -ENOMEM;349}350351tx_desc->type = ISCSI_TX_DATAOUT;352tx_desc->iser_header.flags = ISER_VER;353memcpy(&tx_desc->iscsi_header, hdr, sizeof(struct iscsi_hdr));354355/* build the tx desc */356iser_initialize_task_headers(task, tx_desc);357358regd_buf = &iser_task->rdma_regd[ISER_DIR_OUT];359tx_dsg = &tx_desc->tx_sg[1];360tx_dsg->addr = regd_buf->reg.va + buf_offset;361tx_dsg->length = data_seg_len;362tx_dsg->lkey = regd_buf->reg.lkey;363tx_desc->num_sge = 2;364365if (buf_offset + data_seg_len > iser_task->data[ISER_DIR_OUT].data_len) {366iser_err("Offset:%ld & DSL:%ld in Data-Out "367"inconsistent with total len:%ld, itt:%d\n",368buf_offset, data_seg_len,369iser_task->data[ISER_DIR_OUT].data_len, itt);370err = -EINVAL;371goto send_data_out_error;372}373iser_dbg("data-out itt: %d, offset: %ld, sz: %ld\n",374itt, buf_offset, data_seg_len);375376377err = iser_post_send(iser_conn->ib_conn, tx_desc);378if (!err)379return 0;380381send_data_out_error:382kmem_cache_free(ig.desc_cache, tx_desc);383iser_err("conn %p failed err %d\n",conn, err);384return err;385}386387int iser_send_control(struct iscsi_conn *conn,388struct iscsi_task *task)389{390struct iscsi_iser_conn *iser_conn = conn->dd_data;391struct iscsi_iser_task *iser_task = task->dd_data;392struct iser_tx_desc *mdesc = &iser_task->desc;393unsigned long data_seg_len;394int err = 0;395struct iser_device *device;396397/* build the tx desc regd header and add it to the tx desc dto */398mdesc->type = ISCSI_TX_CONTROL;399iser_create_send_desc(iser_conn->ib_conn, mdesc);400401device = iser_conn->ib_conn->device;402403data_seg_len = ntoh24(task->hdr->dlength);404405if (data_seg_len > 0) {406struct ib_sge *tx_dsg = &mdesc->tx_sg[1];407if (task != conn->login_task) {408iser_err("data present on non login task!!!\n");409goto send_control_error;410}411memcpy(iser_conn->ib_conn->login_buf, task->data,412task->data_count);413tx_dsg->addr = iser_conn->ib_conn->login_dma;414tx_dsg->length = data_seg_len;415tx_dsg->lkey = device->mr->lkey;416mdesc->num_sge = 2;417}418419if (task == conn->login_task) {420err = iser_post_recvl(iser_conn->ib_conn);421if (err)422goto send_control_error;423}424425err = iser_post_send(iser_conn->ib_conn, mdesc);426if (!err)427return 0;428429send_control_error:430iser_err("conn %p failed err %d\n",conn, err);431return err;432}433434/**435* iser_rcv_dto_completion - recv DTO completion436*/437void iser_rcv_completion(struct iser_rx_desc *rx_desc,438unsigned long rx_xfer_len,439struct iser_conn *ib_conn)440{441struct iscsi_iser_conn *conn = ib_conn->iser_conn;442struct iscsi_hdr *hdr;443u64 rx_dma;444int rx_buflen, outstanding, count, err;445446/* differentiate between login to all other PDUs */447if ((char *)rx_desc == ib_conn->login_buf) {448rx_dma = ib_conn->login_dma;449rx_buflen = ISER_RX_LOGIN_SIZE;450} else {451rx_dma = rx_desc->dma_addr;452rx_buflen = ISER_RX_PAYLOAD_SIZE;453}454455ib_dma_sync_single_for_cpu(ib_conn->device->ib_device, rx_dma,456rx_buflen, DMA_FROM_DEVICE);457458hdr = &rx_desc->iscsi_header;459460iser_dbg("op 0x%x itt 0x%x dlen %d\n", hdr->opcode,461hdr->itt, (int)(rx_xfer_len - ISER_HEADERS_LEN));462463iscsi_iser_recv(conn->iscsi_conn, hdr,464rx_desc->data, rx_xfer_len - ISER_HEADERS_LEN);465466ib_dma_sync_single_for_device(ib_conn->device->ib_device, rx_dma,467rx_buflen, DMA_FROM_DEVICE);468469/* decrementing conn->post_recv_buf_count only --after-- freeing the *470* task eliminates the need to worry on tasks which are completed in *471* parallel to the execution of iser_conn_term. So the code that waits *472* for the posted rx bufs refcount to become zero handles everything */473conn->ib_conn->post_recv_buf_count--;474475if (rx_dma == ib_conn->login_dma)476return;477478outstanding = ib_conn->post_recv_buf_count;479if (outstanding + ISER_MIN_POSTED_RX <= ISER_QP_MAX_RECV_DTOS) {480count = min(ISER_QP_MAX_RECV_DTOS - outstanding,481ISER_MIN_POSTED_RX);482err = iser_post_recvm(ib_conn, count);483if (err)484iser_err("posting %d rx bufs err %d\n", count, err);485}486}487488void iser_snd_completion(struct iser_tx_desc *tx_desc,489struct iser_conn *ib_conn)490{491struct iscsi_task *task;492struct iser_device *device = ib_conn->device;493494if (tx_desc->type == ISCSI_TX_DATAOUT) {495ib_dma_unmap_single(device->ib_device, tx_desc->dma_addr,496ISER_HEADERS_LEN, DMA_TO_DEVICE);497kmem_cache_free(ig.desc_cache, tx_desc);498}499500atomic_dec(&ib_conn->post_send_buf_count);501502if (tx_desc->type == ISCSI_TX_CONTROL) {503/* this arithmetic is legal by libiscsi dd_data allocation */504task = (void *) ((long)(void *)tx_desc -505sizeof(struct iscsi_task));506if (task->hdr->itt == RESERVED_ITT)507iscsi_put_task(task);508}509}510511void iser_task_rdma_init(struct iscsi_iser_task *iser_task)512513{514iser_task->status = ISER_TASK_STATUS_INIT;515516iser_task->dir[ISER_DIR_IN] = 0;517iser_task->dir[ISER_DIR_OUT] = 0;518519iser_task->data[ISER_DIR_IN].data_len = 0;520iser_task->data[ISER_DIR_OUT].data_len = 0;521522memset(&iser_task->rdma_regd[ISER_DIR_IN], 0,523sizeof(struct iser_regd_buf));524memset(&iser_task->rdma_regd[ISER_DIR_OUT], 0,525sizeof(struct iser_regd_buf));526}527528void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)529{530int is_rdma_aligned = 1;531struct iser_regd_buf *regd;532533/* if we were reading, copy back to unaligned sglist,534* anyway dma_unmap and free the copy535*/536if (iser_task->data_copy[ISER_DIR_IN].copy_buf != NULL) {537is_rdma_aligned = 0;538iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_IN);539}540if (iser_task->data_copy[ISER_DIR_OUT].copy_buf != NULL) {541is_rdma_aligned = 0;542iser_finalize_rdma_unaligned_sg(iser_task, ISER_DIR_OUT);543}544545if (iser_task->dir[ISER_DIR_IN]) {546regd = &iser_task->rdma_regd[ISER_DIR_IN];547if (regd->reg.is_fmr)548iser_unreg_mem(®d->reg);549}550551if (iser_task->dir[ISER_DIR_OUT]) {552regd = &iser_task->rdma_regd[ISER_DIR_OUT];553if (regd->reg.is_fmr)554iser_unreg_mem(®d->reg);555}556557/* if the data was unaligned, it was already unmapped and then copied */558if (is_rdma_aligned)559iser_dma_unmap_task_data(iser_task);560}561562563