--- zzzz-none-000/linux-3.10.107/drivers/infiniband/ulp/isert/ib_isert.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/infiniband/ulp/isert/ib_isert.c 2021-02-04 17:41:59.000000000 +0000 @@ -1,7 +1,7 @@ /******************************************************************************* * This file contains iSCSI extentions for RDMA (iSER) Verbs * - * (c) Copyright 2013 RisingTide Systems LLC. + * (c) Copyright 2013 Datera, Inc. * * Nicholas A. Bellinger * @@ -35,14 +35,30 @@ #define ISERT_MAX_CONN 8 #define ISER_MAX_RX_CQ_LEN (ISERT_QP_MAX_RECV_DTOS * ISERT_MAX_CONN) #define ISER_MAX_TX_CQ_LEN (ISERT_QP_MAX_REQ_DTOS * ISERT_MAX_CONN) +#define ISER_MAX_CQ_LEN (ISER_MAX_RX_CQ_LEN + ISER_MAX_TX_CQ_LEN + \ + ISERT_MAX_CONN) + +static int isert_debug_level; +module_param_named(debug_level, isert_debug_level, int, 0644); +MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:0)"); static DEFINE_MUTEX(device_list_mutex); static LIST_HEAD(device_list); -static struct workqueue_struct *isert_rx_wq; static struct workqueue_struct *isert_comp_wq; static struct workqueue_struct *isert_release_wq; -static struct kmem_cache *isert_cmd_cache; +static void +isert_unmap_cmd(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn); +static int +isert_map_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd, + struct isert_rdma_wr *wr); +static void +isert_unreg_rdma(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn); +static int +isert_reg_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd, + struct isert_rdma_wr *wr); +static int +isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd); static int isert_rdma_post_recvl(struct isert_conn *isert_conn); static int @@ -50,19 +66,30 @@ struct rdma_cm_id *isert_setup_id(struct isert_np *isert_np); static void isert_release_work(struct work_struct *work); +static void isert_wait4flush(struct isert_conn *isert_conn); + +static inline bool +isert_prot_cmd(struct isert_conn *conn, struct se_cmd *cmd) +{ + return (conn->pi_support && + cmd->prot_op != TARGET_PROT_NORMAL); +} + static void isert_qp_event_callback(struct ib_event *e, void *context) { - struct isert_conn *isert_conn = (struct isert_conn *)context; + struct isert_conn *isert_conn = context; + + isert_err("%s (%d): conn %p\n", + ib_event_msg(e->event), e->event, isert_conn); - pr_err("isert_qp_event_callback event: %d\n", e->event); switch (e->event) { case IB_EVENT_COMM_EST: - rdma_notify(isert_conn->conn_cm_id, IB_EVENT_COMM_EST); + rdma_notify(isert_conn->cm_id, IB_EVENT_COMM_EST); break; case IB_EVENT_QP_LAST_WQE_REACHED: - pr_warn("Reached TX IB_EVENT_QP_LAST_WQE_REACHED:\n"); + isert_warn("Reached TX IB_EVENT_QP_LAST_WQE_REACHED\n"); break; default: break; @@ -76,101 +103,120 @@ ret = ib_query_device(ib_dev, devattr); if (ret) { - pr_err("ib_query_device() failed: %d\n", ret); + isert_err("ib_query_device() failed: %d\n", ret); return ret; } - pr_debug("devattr->max_sge: %d\n", devattr->max_sge); - pr_debug("devattr->max_sge_rd: %d\n", devattr->max_sge_rd); + isert_dbg("devattr->max_sge: %d\n", devattr->max_sge); + isert_dbg("devattr->max_sge_rd: %d\n", devattr->max_sge_rd); return 0; } -static int -isert_conn_setup_qp(struct isert_conn *isert_conn, struct rdma_cm_id *cma_id) +static struct isert_comp * +isert_comp_get(struct isert_conn *isert_conn) { - struct isert_device *device = isert_conn->conn_device; - struct ib_qp_init_attr attr; - struct ib_device_attr devattr; - int ret, index, min_index = 0; + struct isert_device *device = isert_conn->device; + struct isert_comp *comp; + int i, min = 0; - memset(&devattr, 0, sizeof(struct ib_device_attr)); - ret = isert_query_device(cma_id->device, &devattr); - if (ret) - return ret; + mutex_lock(&device_list_mutex); + for (i = 0; i < device->comps_used; i++) + if (device->comps[i].active_qps < + device->comps[min].active_qps) + min = i; + comp = &device->comps[min]; + comp->active_qps++; + mutex_unlock(&device_list_mutex); + + isert_info("conn %p, using comp %p min_index: %d\n", + isert_conn, comp, min); + return comp; +} + +static void +isert_comp_put(struct isert_comp *comp) +{ mutex_lock(&device_list_mutex); - for (index = 0; index < device->cqs_used; index++) - if (device->cq_active_qps[index] < - device->cq_active_qps[min_index]) - min_index = index; - device->cq_active_qps[min_index]++; - pr_debug("isert_conn_setup_qp: Using min_index: %d\n", min_index); + comp->active_qps--; mutex_unlock(&device_list_mutex); +} + +static struct ib_qp * +isert_create_qp(struct isert_conn *isert_conn, + struct isert_comp *comp, + struct rdma_cm_id *cma_id) +{ + struct isert_device *device = isert_conn->device; + struct ib_qp_init_attr attr; + int ret; memset(&attr, 0, sizeof(struct ib_qp_init_attr)); attr.event_handler = isert_qp_event_callback; attr.qp_context = isert_conn; - attr.send_cq = device->dev_tx_cq[min_index]; - attr.recv_cq = device->dev_rx_cq[min_index]; + attr.send_cq = comp->cq; + attr.recv_cq = comp->cq; attr.cap.max_send_wr = ISERT_QP_MAX_REQ_DTOS; - attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS; - /* - * FIXME: Use devattr.max_sge - 2 for max_send_sge as - * work-around for RDMA_READs with ConnectX-2. - * - * Also, still make sure to have at least two SGEs for - * outgoing control PDU responses. - */ - attr.cap.max_send_sge = max(2, devattr.max_sge - 2); - isert_conn->max_sge = attr.cap.max_send_sge; - + attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS + 1; + attr.cap.max_send_sge = device->dev_attr.max_sge; + isert_conn->max_sge = min(device->dev_attr.max_sge, + device->dev_attr.max_sge_rd); attr.cap.max_recv_sge = 1; attr.sq_sig_type = IB_SIGNAL_REQ_WR; attr.qp_type = IB_QPT_RC; + if (device->pi_capable) + attr.create_flags |= IB_QP_CREATE_SIGNATURE_EN; - pr_debug("isert_conn_setup_qp cma_id->device: %p\n", - cma_id->device); - pr_debug("isert_conn_setup_qp conn_pd->device: %p\n", - isert_conn->conn_pd->device); - - ret = rdma_create_qp(cma_id, isert_conn->conn_pd, &attr); + ret = rdma_create_qp(cma_id, device->pd, &attr); if (ret) { - pr_err("rdma_create_qp failed for cma_id %d\n", ret); + isert_err("rdma_create_qp failed for cma_id %d\n", ret); + return ERR_PTR(ret); + } + + return cma_id->qp; +} + +static int +isert_conn_setup_qp(struct isert_conn *isert_conn, struct rdma_cm_id *cma_id) +{ + struct isert_comp *comp; + int ret; + + comp = isert_comp_get(isert_conn); + isert_conn->qp = isert_create_qp(isert_conn, comp, cma_id); + if (IS_ERR(isert_conn->qp)) { + ret = PTR_ERR(isert_conn->qp); goto err; } - isert_conn->conn_qp = cma_id->qp; - pr_debug("rdma_create_qp() returned success >>>>>>>>>>>>>>>>>>>>>>>>>.\n"); return 0; err: - mutex_lock(&device_list_mutex); - device->cq_active_qps[min_index]--; - mutex_unlock(&device_list_mutex); - + isert_comp_put(comp); return ret; } static void isert_cq_event_callback(struct ib_event *e, void *context) { - pr_debug("isert_cq_event_callback event: %d\n", e->event); + isert_dbg("event: %d\n", e->event); } static int isert_alloc_rx_descriptors(struct isert_conn *isert_conn) { - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; struct iser_rx_desc *rx_desc; struct ib_sge *rx_sg; u64 dma_addr; int i, j; - isert_conn->conn_rx_descs = kzalloc(ISERT_QP_MAX_RECV_DTOS * + isert_conn->rx_descs = kzalloc(ISERT_QP_MAX_RECV_DTOS * sizeof(struct iser_rx_desc), GFP_KERNEL); - if (!isert_conn->conn_rx_descs) + if (!isert_conn->rx_descs) goto fail; - rx_desc = isert_conn->conn_rx_descs; + rx_desc = isert_conn->rx_descs; for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++) { dma_addr = ib_dma_map_single(ib_dev, (void *)rx_desc, @@ -183,177 +229,180 @@ rx_sg = &rx_desc->rx_sg; rx_sg->addr = rx_desc->dma_addr; rx_sg->length = ISER_RX_PAYLOAD_SIZE; - rx_sg->lkey = isert_conn->conn_mr->lkey; + rx_sg->lkey = device->pd->local_dma_lkey; } - isert_conn->conn_rx_desc_head = 0; return 0; dma_map_fail: - rx_desc = isert_conn->conn_rx_descs; + rx_desc = isert_conn->rx_descs; for (j = 0; j < i; j++, rx_desc++) { ib_dma_unmap_single(ib_dev, rx_desc->dma_addr, ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); } - kfree(isert_conn->conn_rx_descs); - isert_conn->conn_rx_descs = NULL; + kfree(isert_conn->rx_descs); + isert_conn->rx_descs = NULL; fail: + isert_err("conn %p failed to allocate rx descriptors\n", isert_conn); + return -ENOMEM; } static void isert_free_rx_descriptors(struct isert_conn *isert_conn) { - struct ib_device *ib_dev = isert_conn->conn_device->ib_device; + struct ib_device *ib_dev = isert_conn->device->ib_device; struct iser_rx_desc *rx_desc; int i; - if (!isert_conn->conn_rx_descs) + if (!isert_conn->rx_descs) return; - rx_desc = isert_conn->conn_rx_descs; + rx_desc = isert_conn->rx_descs; for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++) { ib_dma_unmap_single(ib_dev, rx_desc->dma_addr, ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE); } - kfree(isert_conn->conn_rx_descs); - isert_conn->conn_rx_descs = NULL; + kfree(isert_conn->rx_descs); + isert_conn->rx_descs = NULL; } -static void isert_cq_tx_callback(struct ib_cq *, void *); -static void isert_cq_rx_callback(struct ib_cq *, void *); +static void isert_cq_work(struct work_struct *); +static void isert_cq_callback(struct ib_cq *, void *); + +static void +isert_free_comps(struct isert_device *device) +{ + int i; + + for (i = 0; i < device->comps_used; i++) { + struct isert_comp *comp = &device->comps[i]; + + if (comp->cq) { + cancel_work_sync(&comp->work); + ib_destroy_cq(comp->cq); + } + } + kfree(device->comps); +} static int -isert_create_device_ib_res(struct isert_device *device) +isert_alloc_comps(struct isert_device *device, + struct ib_device_attr *attr) { - struct ib_device *ib_dev = device->ib_device; - struct isert_cq_desc *cq_desc; - int ret = 0, i, j; - int max_rx_cqe, max_tx_cqe; - struct ib_device_attr dev_attr; + int i, max_cqe, ret = 0; - memset(&dev_attr, 0, sizeof(struct ib_device_attr)); - ret = isert_query_device(device->ib_device, &dev_attr); - if (ret) - return ret; + device->comps_used = min(ISERT_MAX_CQ, min_t(int, num_online_cpus(), + device->ib_device->num_comp_vectors)); - device->cqs_used = min_t(int, num_online_cpus(), - device->ib_device->num_comp_vectors); - device->cqs_used = min(ISERT_MAX_CQ, device->cqs_used); - pr_debug("Using %d CQs, device %s supports %d vectors\n", - device->cqs_used, device->ib_device->name, - device->ib_device->num_comp_vectors); - device->cq_desc = kzalloc(sizeof(struct isert_cq_desc) * - device->cqs_used, GFP_KERNEL); - if (!device->cq_desc) { - pr_err("Unable to allocate device->cq_desc\n"); + isert_info("Using %d CQs, %s supports %d vectors support " + "Fast registration %d pi_capable %d\n", + device->comps_used, device->ib_device->name, + device->ib_device->num_comp_vectors, device->use_fastreg, + device->pi_capable); + + device->comps = kcalloc(device->comps_used, sizeof(struct isert_comp), + GFP_KERNEL); + if (!device->comps) { + isert_err("Unable to allocate completion contexts\n"); return -ENOMEM; } - cq_desc = device->cq_desc; - device->dev_pd = ib_alloc_pd(ib_dev); - if (IS_ERR(device->dev_pd)) { - ret = PTR_ERR(device->dev_pd); - pr_err("ib_alloc_pd failed for dev_pd: %d\n", ret); - goto out_cq_desc; - } - - max_rx_cqe = min(ISER_MAX_RX_CQ_LEN, dev_attr.max_cqe); - max_tx_cqe = min(ISER_MAX_TX_CQ_LEN, dev_attr.max_cqe); - - for (i = 0; i < device->cqs_used; i++) { - cq_desc[i].device = device; - cq_desc[i].cq_index = i; - - device->dev_rx_cq[i] = ib_create_cq(device->ib_device, - isert_cq_rx_callback, - isert_cq_event_callback, - (void *)&cq_desc[i], - max_rx_cqe, i); - if (IS_ERR(device->dev_rx_cq[i])) { - ret = PTR_ERR(device->dev_rx_cq[i]); - device->dev_rx_cq[i] = NULL; - goto out_cq; - } + max_cqe = min(ISER_MAX_CQ_LEN, attr->max_cqe); - device->dev_tx_cq[i] = ib_create_cq(device->ib_device, - isert_cq_tx_callback, - isert_cq_event_callback, - (void *)&cq_desc[i], - max_tx_cqe, i); - if (IS_ERR(device->dev_tx_cq[i])) { - ret = PTR_ERR(device->dev_tx_cq[i]); - device->dev_tx_cq[i] = NULL; + for (i = 0; i < device->comps_used; i++) { + struct ib_cq_init_attr cq_attr = {}; + struct isert_comp *comp = &device->comps[i]; + + comp->device = device; + INIT_WORK(&comp->work, isert_cq_work); + cq_attr.cqe = max_cqe; + cq_attr.comp_vector = i; + comp->cq = ib_create_cq(device->ib_device, + isert_cq_callback, + isert_cq_event_callback, + (void *)comp, + &cq_attr); + if (IS_ERR(comp->cq)) { + isert_err("Unable to allocate cq\n"); + ret = PTR_ERR(comp->cq); + comp->cq = NULL; goto out_cq; } - ret = ib_req_notify_cq(device->dev_rx_cq[i], IB_CQ_NEXT_COMP); + ret = ib_req_notify_cq(comp->cq, IB_CQ_NEXT_COMP); if (ret) goto out_cq; + } - ret = ib_req_notify_cq(device->dev_tx_cq[i], IB_CQ_NEXT_COMP); - if (ret) - goto out_cq; + return 0; +out_cq: + isert_free_comps(device); + return ret; +} + +static int +isert_create_device_ib_res(struct isert_device *device) +{ + struct ib_device_attr *dev_attr; + int ret; + + dev_attr = &device->dev_attr; + ret = isert_query_device(device->ib_device, dev_attr); + if (ret) + return ret; + + /* asign function handlers */ + if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS && + dev_attr->device_cap_flags & IB_DEVICE_SIGNATURE_HANDOVER) { + device->use_fastreg = 1; + device->reg_rdma_mem = isert_reg_rdma; + device->unreg_rdma_mem = isert_unreg_rdma; + } else { + device->use_fastreg = 0; + device->reg_rdma_mem = isert_map_rdma; + device->unreg_rdma_mem = isert_unmap_cmd; } - device->dev_mr = ib_get_dma_mr(device->dev_pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(device->dev_mr)) { - ret = PTR_ERR(device->dev_mr); - pr_err("ib_get_dma_mr failed for dev_mr: %d\n", ret); + ret = isert_alloc_comps(device, dev_attr); + if (ret) + return ret; + + device->pd = ib_alloc_pd(device->ib_device); + if (IS_ERR(device->pd)) { + ret = PTR_ERR(device->pd); + isert_err("failed to allocate pd, device %p, ret=%d\n", + device, ret); goto out_cq; } + /* Check signature cap */ + device->pi_capable = dev_attr->device_cap_flags & + IB_DEVICE_SIGNATURE_HANDOVER ? true : false; + return 0; out_cq: - for (j = 0; j < i; j++) { - cq_desc = &device->cq_desc[j]; - - if (device->dev_rx_cq[j]) { - cancel_work_sync(&cq_desc->cq_rx_work); - ib_destroy_cq(device->dev_rx_cq[j]); - } - if (device->dev_tx_cq[j]) { - cancel_work_sync(&cq_desc->cq_tx_work); - ib_destroy_cq(device->dev_tx_cq[j]); - } - } - ib_dealloc_pd(device->dev_pd); - -out_cq_desc: - kfree(device->cq_desc); - + isert_free_comps(device); return ret; } static void isert_free_device_ib_res(struct isert_device *device) { - struct isert_cq_desc *cq_desc; - int i; - - for (i = 0; i < device->cqs_used; i++) { - cq_desc = &device->cq_desc[i]; + isert_info("device %p\n", device); - cancel_work_sync(&cq_desc->cq_rx_work); - cancel_work_sync(&cq_desc->cq_tx_work); - ib_destroy_cq(device->dev_rx_cq[i]); - ib_destroy_cq(device->dev_tx_cq[i]); - device->dev_rx_cq[i] = NULL; - device->dev_tx_cq[i] = NULL; - } - - ib_dereg_mr(device->dev_mr); - ib_dealloc_pd(device->dev_pd); - kfree(device->cq_desc); + ib_dealloc_pd(device->pd); + isert_free_comps(device); } static void -isert_device_try_release(struct isert_device *device) +isert_device_put(struct isert_device *device) { mutex_lock(&device_list_mutex); device->refcount--; + isert_info("device %p refcount %d\n", device, device->refcount); if (!device->refcount) { isert_free_device_ib_res(device); list_del(&device->dev_node); @@ -363,7 +412,7 @@ } static struct isert_device * -isert_device_find_by_ib_dev(struct rdma_cm_id *cma_id) +isert_device_get(struct rdma_cm_id *cma_id) { struct isert_device *device; int ret; @@ -372,6 +421,8 @@ list_for_each_entry(device, &device_list, dev_node) { if (device->ib_device->node_guid == cma_id->device->node_guid) { device->refcount++; + isert_info("Found iser device %p refcount %d\n", + device, device->refcount); mutex_unlock(&device_list_mutex); return device; } @@ -395,65 +446,199 @@ device->refcount++; list_add_tail(&device->dev_node, &device_list); + isert_info("Created a new iser device %p refcount %d\n", + device, device->refcount); mutex_unlock(&device_list_mutex); return device; } -static int -isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) +static void +isert_conn_free_fastreg_pool(struct isert_conn *isert_conn) { - struct isert_np *isert_np = cma_id->context; - struct iscsi_np *np = isert_np->np; - struct isert_conn *isert_conn; - struct isert_device *device; - struct ib_device *ib_dev = cma_id->device; - int ret = 0; + struct fast_reg_descriptor *fr_desc, *tmp; + int i = 0; - spin_lock_bh(&np->np_thread_lock); - if (!np->enabled) { - spin_unlock_bh(&np->np_thread_lock); - pr_debug("iscsi_np is not enabled, reject connect request\n"); - return rdma_reject(cma_id, NULL, 0); + if (list_empty(&isert_conn->fr_pool)) + return; + + isert_info("Freeing conn %p fastreg pool", isert_conn); + + list_for_each_entry_safe(fr_desc, tmp, + &isert_conn->fr_pool, list) { + list_del(&fr_desc->list); + ib_dereg_mr(fr_desc->data_mr); + if (fr_desc->pi_ctx) { + ib_dereg_mr(fr_desc->pi_ctx->prot_mr); + ib_dereg_mr(fr_desc->pi_ctx->sig_mr); + kfree(fr_desc->pi_ctx); + } + kfree(fr_desc); + ++i; } - spin_unlock_bh(&np->np_thread_lock); - pr_debug("Entering isert_connect_request cma_id: %p, context: %p\n", - cma_id, cma_id->context); + if (i < isert_conn->fr_pool_size) + isert_warn("Pool still has %d regions registered\n", + isert_conn->fr_pool_size - i); +} - isert_conn = kzalloc(sizeof(struct isert_conn), GFP_KERNEL); - if (!isert_conn) { - pr_err("Unable to allocate isert_conn\n"); +static int +isert_create_pi_ctx(struct fast_reg_descriptor *desc, + struct ib_device *device, + struct ib_pd *pd) +{ + struct pi_context *pi_ctx; + int ret; + + pi_ctx = kzalloc(sizeof(*desc->pi_ctx), GFP_KERNEL); + if (!pi_ctx) { + isert_err("Failed to allocate pi context\n"); return -ENOMEM; } + + pi_ctx->prot_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, + ISCSI_ISER_SG_TABLESIZE); + if (IS_ERR(pi_ctx->prot_mr)) { + isert_err("Failed to allocate prot frmr err=%ld\n", + PTR_ERR(pi_ctx->prot_mr)); + ret = PTR_ERR(pi_ctx->prot_mr); + goto err_pi_ctx; + } + desc->ind |= ISERT_PROT_KEY_VALID; + + pi_ctx->sig_mr = ib_alloc_mr(pd, IB_MR_TYPE_SIGNATURE, 2); + if (IS_ERR(pi_ctx->sig_mr)) { + isert_err("Failed to allocate signature enabled mr err=%ld\n", + PTR_ERR(pi_ctx->sig_mr)); + ret = PTR_ERR(pi_ctx->sig_mr); + goto err_prot_mr; + } + + desc->pi_ctx = pi_ctx; + desc->ind |= ISERT_SIG_KEY_VALID; + desc->ind &= ~ISERT_PROTECTED; + + return 0; + +err_prot_mr: + ib_dereg_mr(pi_ctx->prot_mr); +err_pi_ctx: + kfree(pi_ctx); + + return ret; +} + +static int +isert_create_fr_desc(struct ib_device *ib_device, struct ib_pd *pd, + struct fast_reg_descriptor *fr_desc) +{ + fr_desc->data_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, + ISCSI_ISER_SG_TABLESIZE); + if (IS_ERR(fr_desc->data_mr)) { + isert_err("Failed to allocate data frmr err=%ld\n", + PTR_ERR(fr_desc->data_mr)); + return PTR_ERR(fr_desc->data_mr); + } + fr_desc->ind |= ISERT_DATA_KEY_VALID; + + isert_dbg("Created fr_desc %p\n", fr_desc); + + return 0; +} + +static int +isert_conn_create_fastreg_pool(struct isert_conn *isert_conn) +{ + struct fast_reg_descriptor *fr_desc; + struct isert_device *device = isert_conn->device; + struct se_session *se_sess = isert_conn->conn->sess->se_sess; + struct se_node_acl *se_nacl = se_sess->se_node_acl; + int i, ret, tag_num; + /* + * Setup the number of FRMRs based upon the number of tags + * available to session in iscsi_target_locate_portal(). + */ + tag_num = max_t(u32, ISCSIT_MIN_TAGS, se_nacl->queue_depth); + tag_num = (tag_num * 2) + ISCSIT_EXTRA_TAGS; + + isert_conn->fr_pool_size = 0; + for (i = 0; i < tag_num; i++) { + fr_desc = kzalloc(sizeof(*fr_desc), GFP_KERNEL); + if (!fr_desc) { + isert_err("Failed to allocate fast_reg descriptor\n"); + ret = -ENOMEM; + goto err; + } + + ret = isert_create_fr_desc(device->ib_device, + device->pd, fr_desc); + if (ret) { + isert_err("Failed to create fastreg descriptor err=%d\n", + ret); + kfree(fr_desc); + goto err; + } + + list_add_tail(&fr_desc->list, &isert_conn->fr_pool); + isert_conn->fr_pool_size++; + } + + isert_dbg("Creating conn %p fastreg pool size=%d", + isert_conn, isert_conn->fr_pool_size); + + return 0; + +err: + isert_conn_free_fastreg_pool(isert_conn); + return ret; +} + +static void +isert_init_conn(struct isert_conn *isert_conn) +{ isert_conn->state = ISER_CONN_INIT; - INIT_LIST_HEAD(&isert_conn->conn_accept_node); - init_completion(&isert_conn->conn_login_comp); + INIT_LIST_HEAD(&isert_conn->node); + init_completion(&isert_conn->login_comp); init_completion(&isert_conn->login_req_comp); - init_completion(&isert_conn->conn_wait); - init_completion(&isert_conn->conn_wait_comp_err); - kref_init(&isert_conn->conn_kref); - mutex_init(&isert_conn->conn_mutex); + init_completion(&isert_conn->wait); + kref_init(&isert_conn->kref); + mutex_init(&isert_conn->mutex); + spin_lock_init(&isert_conn->pool_lock); + INIT_LIST_HEAD(&isert_conn->fr_pool); INIT_WORK(&isert_conn->release_work, isert_release_work); +} - isert_conn->conn_cm_id = cma_id; - isert_conn->responder_resources = event->param.conn.responder_resources; - isert_conn->initiator_depth = event->param.conn.initiator_depth; - pr_debug("Using responder_resources: %u initiator_depth: %u\n", - isert_conn->responder_resources, isert_conn->initiator_depth); +static void +isert_free_login_buf(struct isert_conn *isert_conn) +{ + struct ib_device *ib_dev = isert_conn->device->ib_device; + + ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma, + ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE); + ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma, + ISCSI_DEF_MAX_RECV_SEG_LEN, + DMA_FROM_DEVICE); + kfree(isert_conn->login_buf); +} + +static int +isert_alloc_login_buf(struct isert_conn *isert_conn, + struct ib_device *ib_dev) +{ + int ret; isert_conn->login_buf = kzalloc(ISCSI_DEF_MAX_RECV_SEG_LEN + ISER_RX_LOGIN_SIZE, GFP_KERNEL); if (!isert_conn->login_buf) { - pr_err("Unable to allocate isert_conn->login_buf\n"); - ret = -ENOMEM; - goto out; + isert_err("Unable to allocate isert_conn->login_buf\n"); + return -ENOMEM; } isert_conn->login_req_buf = isert_conn->login_buf; isert_conn->login_rsp_buf = isert_conn->login_buf + ISCSI_DEF_MAX_RECV_SEG_LEN; - pr_debug("Set login_buf: %p login_req_buf: %p login_rsp_buf: %p\n", + + isert_dbg("Set login_buf: %p login_req_buf: %p login_rsp_buf: %p\n", isert_conn->login_buf, isert_conn->login_req_buf, isert_conn->login_rsp_buf); @@ -463,8 +648,7 @@ ret = ib_dma_mapping_error(ib_dev, isert_conn->login_req_dma); if (ret) { - pr_err("ib_dma_mapping_error failed for login_req_dma: %d\n", - ret); + isert_err("login_req_dma mapping error: %d\n", ret); isert_conn->login_req_dma = 0; goto out_login_buf; } @@ -475,21 +659,64 @@ ret = ib_dma_mapping_error(ib_dev, isert_conn->login_rsp_dma); if (ret) { - pr_err("ib_dma_mapping_error failed for login_rsp_dma: %d\n", - ret); + isert_err("login_rsp_dma mapping error: %d\n", ret); isert_conn->login_rsp_dma = 0; goto out_req_dma_map; } - device = isert_device_find_by_ib_dev(cma_id); + return 0; + +out_req_dma_map: + ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma, + ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_FROM_DEVICE); +out_login_buf: + kfree(isert_conn->login_buf); + return ret; +} + +static int +isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) +{ + struct isert_np *isert_np = cma_id->context; + struct iscsi_np *np = isert_np->np; + struct isert_conn *isert_conn; + struct isert_device *device; + int ret = 0; + + spin_lock_bh(&np->np_thread_lock); + if (!np->enabled) { + spin_unlock_bh(&np->np_thread_lock); + isert_dbg("iscsi_np is not enabled, reject connect request\n"); + return rdma_reject(cma_id, NULL, 0); + } + spin_unlock_bh(&np->np_thread_lock); + + isert_dbg("cma_id: %p, portal: %p\n", + cma_id, cma_id->context); + + isert_conn = kzalloc(sizeof(struct isert_conn), GFP_KERNEL); + if (!isert_conn) + return -ENOMEM; + + isert_init_conn(isert_conn); + isert_conn->cm_id = cma_id; + + ret = isert_alloc_login_buf(isert_conn, cma_id->device); + if (ret) + goto out; + + device = isert_device_get(cma_id); if (IS_ERR(device)) { ret = PTR_ERR(device); goto out_rsp_dma_map; } + isert_conn->device = device; - isert_conn->conn_device = device; - isert_conn->conn_pd = device->dev_pd; - isert_conn->conn_mr = device->dev_mr; + /* Set max inflight RDMA READ requests */ + isert_conn->initiator_depth = min_t(u8, + event->param.conn.initiator_depth, + device->dev_attr.max_qp_init_rd_atom); + isert_dbg("Using initiator_depth: %u\n", isert_conn->initiator_depth); ret = isert_conn_setup_qp(isert_conn, cma_id); if (ret) @@ -503,24 +730,16 @@ if (ret) goto out_conn_dev; - mutex_lock(&isert_np->np_accept_mutex); - list_add_tail(&isert_conn->conn_accept_node, &isert_np->np_accept_list); - mutex_unlock(&isert_np->np_accept_mutex); + mutex_lock(&isert_np->mutex); + list_add_tail(&isert_conn->node, &isert_np->accepted); + mutex_unlock(&isert_np->mutex); - pr_debug("isert_connect_request() up np_sem np: %p\n", np); - up(&isert_np->np_sem); return 0; out_conn_dev: - isert_device_try_release(device); + isert_device_put(device); out_rsp_dma_map: - ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma, - ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE); -out_req_dma_map: - ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma, - ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_FROM_DEVICE); -out_login_buf: - kfree(isert_conn->login_buf); + isert_free_login_buf(isert_conn); out: kfree(isert_conn); rdma_reject(cma_id, NULL, 0); @@ -530,69 +749,63 @@ static void isert_connect_release(struct isert_conn *isert_conn) { - struct isert_device *device = isert_conn->conn_device; - int cq_index; - struct ib_device *ib_dev = device->ib_device; + struct isert_device *device = isert_conn->device; + + isert_dbg("conn %p\n", isert_conn); - pr_debug("Entering isert_connect_release(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + BUG_ON(!device); + + if (device->use_fastreg) + isert_conn_free_fastreg_pool(isert_conn); isert_free_rx_descriptors(isert_conn); - if (isert_conn->conn_cm_id) - rdma_destroy_id(isert_conn->conn_cm_id); + if (isert_conn->cm_id) + rdma_destroy_id(isert_conn->cm_id); - if (isert_conn->conn_qp) { - cq_index = ((struct isert_cq_desc *) - isert_conn->conn_qp->recv_cq->cq_context)->cq_index; - pr_debug("isert_connect_release: cq_index: %d\n", cq_index); - mutex_lock(&device_list_mutex); - isert_conn->conn_device->cq_active_qps[cq_index]--; - mutex_unlock(&device_list_mutex); + if (isert_conn->qp) { + struct isert_comp *comp = isert_conn->qp->recv_cq->cq_context; - ib_destroy_qp(isert_conn->conn_qp); + isert_comp_put(comp); + ib_destroy_qp(isert_conn->qp); } - if (isert_conn->login_buf) { - ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma, - ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE); - ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma, - ISCSI_DEF_MAX_RECV_SEG_LEN, - DMA_FROM_DEVICE); - kfree(isert_conn->login_buf); - } - kfree(isert_conn); + if (isert_conn->login_buf) + isert_free_login_buf(isert_conn); - if (device) - isert_device_try_release(device); + isert_device_put(device); - pr_debug("Leaving isert_connect_release >>>>>>>>>>>>\n"); + kfree(isert_conn); } static void isert_connected_handler(struct rdma_cm_id *cma_id) { struct isert_conn *isert_conn = cma_id->qp->qp_context; + struct isert_np *isert_np = cma_id->context; - pr_info("conn %p\n", isert_conn); + isert_info("conn %p\n", isert_conn); - if (!kref_get_unless_zero(&isert_conn->conn_kref)) { - pr_warn("conn %p connect_release is running\n", isert_conn); - return; - } + mutex_lock(&isert_conn->mutex); + isert_conn->state = ISER_CONN_UP; + kref_get(&isert_conn->kref); + mutex_unlock(&isert_conn->mutex); - mutex_lock(&isert_conn->conn_mutex); - if (isert_conn->state != ISER_CONN_FULL_FEATURE) - isert_conn->state = ISER_CONN_UP; - mutex_unlock(&isert_conn->conn_mutex); + mutex_lock(&isert_np->mutex); + list_move_tail(&isert_conn->node, &isert_np->pending); + mutex_unlock(&isert_np->mutex); + + isert_info("np %p: Allow accept_np to continue\n", isert_np); + up(&isert_np->sem); } static void -isert_release_conn_kref(struct kref *kref) +isert_release_kref(struct kref *kref) { struct isert_conn *isert_conn = container_of(kref, - struct isert_conn, conn_kref); + struct isert_conn, kref); - pr_debug("Calling isert_connect_release for final kref %s/%d\n", - current->comm, current->pid); + isert_info("conn %p final kref %s/%d\n", isert_conn, current->comm, + current->pid); isert_connect_release(isert_conn); } @@ -600,7 +813,26 @@ static void isert_put_conn(struct isert_conn *isert_conn) { - kref_put(&isert_conn->conn_kref, isert_release_conn_kref); + kref_put(&isert_conn->kref, isert_release_kref); +} + +static void +isert_handle_unbound_conn(struct isert_conn *isert_conn) +{ + struct isert_np *isert_np = isert_conn->cm_id->context; + + mutex_lock(&isert_np->mutex); + if (!list_empty(&isert_conn->node)) { + /* + * This means iscsi doesn't know this connection + * so schedule a cleanup ourselves + */ + list_del_init(&isert_conn->node); + isert_put_conn(isert_conn); + complete(&isert_conn->wait); + queue_work(isert_release_wq, &isert_conn->release_work); + } + mutex_unlock(&isert_np->mutex); } /** @@ -608,11 +840,11 @@ * @isert_conn: isert connection struct * * Notes: - * In case the connection state is FULL_FEATURE, move state + * In case the connection state is BOUND, move state * to TEMINATING and start teardown sequence (rdma_disconnect). * In case the connection state is UP, complete flush as well. * - * This routine must be called with conn_mutex held. Thus it is + * This routine must be called with mutex held. Thus it is * safe to call multiple times. */ static void @@ -620,51 +852,42 @@ { int err; - switch (isert_conn->state) { - case ISER_CONN_TERMINATING: - break; - case ISER_CONN_UP: - /* - * No flush completions will occur as we didn't - * get to ISER_CONN_FULL_FEATURE yet, complete - * to allow teardown progress. - */ - complete(&isert_conn->conn_wait_comp_err); - case ISER_CONN_FULL_FEATURE: /* FALLTHRU */ - pr_info("Terminating conn %p state %d\n", - isert_conn, isert_conn->state); - isert_conn->state = ISER_CONN_TERMINATING; - err = rdma_disconnect(isert_conn->conn_cm_id); - if (err) - pr_warn("Failed rdma_disconnect isert_conn %p\n", - isert_conn); - break; - default: - pr_warn("conn %p teminating in state %d\n", - isert_conn, isert_conn->state); - } + if (isert_conn->state >= ISER_CONN_TERMINATING) + return; + + isert_info("Terminating conn %p state %d\n", + isert_conn, isert_conn->state); + isert_conn->state = ISER_CONN_TERMINATING; + err = rdma_disconnect(isert_conn->cm_id); + if (err) + isert_warn("Failed rdma_disconnect isert_conn %p\n", + isert_conn); + + isert_info("conn %p completing wait\n", isert_conn); + complete(&isert_conn->wait); } static int isert_np_cma_handler(struct isert_np *isert_np, enum rdma_cm_event_type event) { - pr_debug("isert np %p, handling event %d\n", isert_np, event); + isert_dbg("%s (%d): isert np %p\n", + rdma_event_msg(event), event, isert_np); switch (event) { case RDMA_CM_EVENT_DEVICE_REMOVAL: - isert_np->np_cm_id = NULL; + isert_np->cm_id = NULL; break; case RDMA_CM_EVENT_ADDR_CHANGE: - isert_np->np_cm_id = isert_setup_id(isert_np); - if (IS_ERR(isert_np->np_cm_id)) { - pr_err("isert np %p setup id failed: %ld\n", - isert_np, PTR_ERR(isert_np->np_cm_id)); - isert_np->np_cm_id = NULL; + isert_np->cm_id = isert_setup_id(isert_np); + if (IS_ERR(isert_np->cm_id)) { + isert_err("isert np %p setup id failed: %ld\n", + isert_np, PTR_ERR(isert_np->cm_id)); + isert_np->cm_id = NULL; } break; default: - pr_err("isert np %p Unexpected event %d\n", + isert_err("isert np %p Unexpected event %d\n", isert_np, event); } @@ -675,35 +898,27 @@ isert_disconnected_handler(struct rdma_cm_id *cma_id, enum rdma_cm_event_type event) { - struct isert_np *isert_np = cma_id->context; - struct isert_conn *isert_conn; - bool terminating = false; - - if (isert_np->np_cm_id == cma_id) - return isert_np_cma_handler(cma_id->context, event); - - isert_conn = cma_id->qp->qp_context; - - mutex_lock(&isert_conn->conn_mutex); - terminating = (isert_conn->state == ISER_CONN_TERMINATING); - isert_conn_terminate(isert_conn); - mutex_unlock(&isert_conn->conn_mutex); - - pr_info("conn %p completing conn_wait\n", isert_conn); - complete(&isert_conn->conn_wait); - - if (terminating) - goto out; + struct isert_conn *isert_conn = cma_id->qp->qp_context; - mutex_lock(&isert_np->np_accept_mutex); - if (!list_empty(&isert_conn->conn_accept_node)) { - list_del_init(&isert_conn->conn_accept_node); - isert_put_conn(isert_conn); - queue_work(isert_release_wq, &isert_conn->release_work); + mutex_lock(&isert_conn->mutex); + switch (isert_conn->state) { + case ISER_CONN_TERMINATING: + break; + case ISER_CONN_UP: + isert_conn_terminate(isert_conn); + isert_wait4flush(isert_conn); + isert_handle_unbound_conn(isert_conn); + break; + case ISER_CONN_BOUND: + case ISER_CONN_FULL_FEATURE: /* FALLTHRU */ + iscsit_cause_connection_reinstatement(isert_conn->conn, 0); + break; + default: + isert_warn("conn %p teminating in state %d\n", + isert_conn, isert_conn->state); } - mutex_unlock(&isert_np->np_accept_mutex); + mutex_unlock(&isert_conn->mutex); -out: return 0; } @@ -712,7 +927,8 @@ { struct isert_conn *isert_conn = cma_id->qp->qp_context; - isert_conn->conn_cm_id = NULL; + list_del_init(&isert_conn->node); + isert_conn->cm_id = NULL; isert_put_conn(isert_conn); return -1; @@ -721,17 +937,21 @@ static int isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) { + struct isert_np *isert_np = cma_id->context; int ret = 0; - pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n", - event->event, event->status, cma_id->context, cma_id); + isert_info("%s (%d): status %d id %p np %p\n", + rdma_event_msg(event->event), event->event, + event->status, cma_id, cma_id->context); + + if (isert_np->cm_id == cma_id) + return isert_np_cma_handler(cma_id->context, event->event); switch (event->event) { case RDMA_CM_EVENT_CONNECT_REQUEST: ret = isert_connect_request(cma_id, event); if (ret) - pr_err("isert_cma_handler failed RDMA_CM_EVENT: 0x%08x %d\n", - event->event, ret); + isert_err("failed handle connect request %d\n", ret); break; case RDMA_CM_EVENT_ESTABLISHED: isert_connected_handler(cma_id); @@ -748,7 +968,7 @@ ret = isert_connect_error(cma_id); break; default: - pr_err("Unhandled RDMA CMA event: %d\n", event->event); + isert_err("Unhandled RDMA CMA event: %d\n", event->event); break; } @@ -756,42 +976,52 @@ } static int -isert_post_recv(struct isert_conn *isert_conn, u32 count) +isert_post_recvm(struct isert_conn *isert_conn, u32 count) { struct ib_recv_wr *rx_wr, *rx_wr_failed; int i, ret; - unsigned int rx_head = isert_conn->conn_rx_desc_head; struct iser_rx_desc *rx_desc; - for (rx_wr = isert_conn->conn_rx_wr, i = 0; i < count; i++, rx_wr++) { - rx_desc = &isert_conn->conn_rx_descs[rx_head]; - rx_wr->wr_id = (unsigned long)rx_desc; - rx_wr->sg_list = &rx_desc->rx_sg; - rx_wr->num_sge = 1; - rx_wr->next = rx_wr + 1; - rx_head = (rx_head + 1) & (ISERT_QP_MAX_RECV_DTOS - 1); + for (rx_wr = isert_conn->rx_wr, i = 0; i < count; i++, rx_wr++) { + rx_desc = &isert_conn->rx_descs[i]; + rx_wr->wr_id = (uintptr_t)rx_desc; + rx_wr->sg_list = &rx_desc->rx_sg; + rx_wr->num_sge = 1; + rx_wr->next = rx_wr + 1; } - rx_wr--; rx_wr->next = NULL; /* mark end of work requests list */ - isert_conn->post_recv_buf_count += count; - ret = ib_post_recv(isert_conn->conn_qp, isert_conn->conn_rx_wr, - &rx_wr_failed); - if (ret) { - pr_err("ib_post_recv() failed with ret: %d\n", ret); - isert_conn->post_recv_buf_count -= count; - } else { - pr_debug("isert_post_recv(): Posted %d RX buffers\n", count); - isert_conn->conn_rx_desc_head = rx_head; - } + ret = ib_post_recv(isert_conn->qp, isert_conn->rx_wr, + &rx_wr_failed); + if (ret) + isert_err("ib_post_recv() failed with ret: %d\n", ret); + + return ret; +} + +static int +isert_post_recv(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc) +{ + struct ib_recv_wr *rx_wr_failed, rx_wr; + int ret; + + rx_wr.wr_id = (uintptr_t)rx_desc; + rx_wr.sg_list = &rx_desc->rx_sg; + rx_wr.num_sge = 1; + rx_wr.next = NULL; + + ret = ib_post_recv(isert_conn->qp, &rx_wr, &rx_wr_failed); + if (ret) + isert_err("ib_post_recv() failed with ret: %d\n", ret); + return ret; } static int isert_post_send(struct isert_conn *isert_conn, struct iser_tx_desc *tx_desc) { - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct ib_device *ib_dev = isert_conn->cm_id->device; struct ib_send_wr send_wr, *send_wr_failed; int ret; @@ -799,19 +1029,15 @@ ISER_HEADERS_LEN, DMA_TO_DEVICE); send_wr.next = NULL; - send_wr.wr_id = (unsigned long)tx_desc; + send_wr.wr_id = (uintptr_t)tx_desc; send_wr.sg_list = tx_desc->tx_sg; send_wr.num_sge = tx_desc->num_sge; send_wr.opcode = IB_WR_SEND; send_wr.send_flags = IB_SEND_SIGNALED; - atomic_inc(&isert_conn->post_send_buf_count); - - ret = ib_post_send(isert_conn->conn_qp, &send_wr, &send_wr_failed); - if (ret) { - pr_err("ib_post_send() failed, ret: %d\n", ret); - atomic_dec(&isert_conn->post_send_buf_count); - } + ret = ib_post_send(isert_conn->qp, &send_wr, &send_wr_failed); + if (ret) + isert_err("ib_post_send() failed, ret: %d\n", ret); return ret; } @@ -821,7 +1047,8 @@ struct isert_cmd *isert_cmd, struct iser_tx_desc *tx_desc) { - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); @@ -832,9 +1059,9 @@ tx_desc->num_sge = 1; tx_desc->isert_cmd = isert_cmd; - if (tx_desc->tx_sg[0].lkey != isert_conn->conn_mr->lkey) { - tx_desc->tx_sg[0].lkey = isert_conn->conn_mr->lkey; - pr_debug("tx_desc %p lkey mismatch, fixing\n", tx_desc); + if (tx_desc->tx_sg[0].lkey != device->pd->local_dma_lkey) { + tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey; + isert_dbg("tx_desc %p lkey mismatch, fixing\n", tx_desc); } } @@ -842,37 +1069,41 @@ isert_init_tx_hdrs(struct isert_conn *isert_conn, struct iser_tx_desc *tx_desc) { - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; u64 dma_addr; dma_addr = ib_dma_map_single(ib_dev, (void *)tx_desc, ISER_HEADERS_LEN, DMA_TO_DEVICE); if (ib_dma_mapping_error(ib_dev, dma_addr)) { - pr_err("ib_dma_mapping_error() failed\n"); + isert_err("ib_dma_mapping_error() failed\n"); return -ENOMEM; } tx_desc->dma_addr = dma_addr; tx_desc->tx_sg[0].addr = tx_desc->dma_addr; tx_desc->tx_sg[0].length = ISER_HEADERS_LEN; - tx_desc->tx_sg[0].lkey = isert_conn->conn_mr->lkey; + tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey; - pr_debug("isert_init_tx_hdrs: Setup tx_sg[0].addr: 0x%llx length: %u" - " lkey: 0x%08x\n", tx_desc->tx_sg[0].addr, - tx_desc->tx_sg[0].length, tx_desc->tx_sg[0].lkey); + isert_dbg("Setup tx_sg[0].addr: 0x%llx length: %u lkey: 0x%x\n", + tx_desc->tx_sg[0].addr, tx_desc->tx_sg[0].length, + tx_desc->tx_sg[0].lkey); return 0; } static void -isert_init_send_wr(struct isert_cmd *isert_cmd, struct ib_send_wr *send_wr) +isert_init_send_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, + struct ib_send_wr *send_wr) { + struct iser_tx_desc *tx_desc = &isert_cmd->tx_desc; + isert_cmd->rdma_wr.iser_ib_op = ISER_IB_SEND; - send_wr->wr_id = (unsigned long)&isert_cmd->tx_desc; + send_wr->wr_id = (uintptr_t)&isert_cmd->tx_desc; send_wr->opcode = IB_WR_SEND; - send_wr->send_flags = IB_SEND_SIGNALED; - send_wr->sg_list = &isert_cmd->tx_desc.tx_sg[0]; + send_wr->sg_list = &tx_desc->tx_sg[0]; send_wr->num_sge = isert_cmd->tx_desc.num_sge; + send_wr->send_flags = IB_SEND_SIGNALED; } static int @@ -885,24 +1116,20 @@ memset(&sge, 0, sizeof(struct ib_sge)); sge.addr = isert_conn->login_req_dma; sge.length = ISER_RX_LOGIN_SIZE; - sge.lkey = isert_conn->conn_mr->lkey; + sge.lkey = isert_conn->device->pd->local_dma_lkey; - pr_debug("Setup sge: addr: %llx length: %d 0x%08x\n", + isert_dbg("Setup sge: addr: %llx length: %d 0x%08x\n", sge.addr, sge.length, sge.lkey); memset(&rx_wr, 0, sizeof(struct ib_recv_wr)); - rx_wr.wr_id = (unsigned long)isert_conn->login_req_buf; + rx_wr.wr_id = (uintptr_t)isert_conn->login_req_buf; rx_wr.sg_list = &sge; rx_wr.num_sge = 1; - isert_conn->post_recv_buf_count++; - ret = ib_post_recv(isert_conn->conn_qp, &rx_wr, &rx_wr_fail); - if (ret) { - pr_err("ib_post_recv() failed: %d\n", ret); - isert_conn->post_recv_buf_count--; - } + ret = ib_post_recv(isert_conn->qp, &rx_wr, &rx_wr_fail); + if (ret) + isert_err("ib_post_recv() failed: %d\n", ret); - pr_debug("ib_post_recv(): returned success >>>>>>>>>>>>>>>>>>>>>>>>\n"); return ret; } @@ -911,8 +1138,9 @@ u32 length) { struct isert_conn *isert_conn = conn->context; - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; - struct iser_tx_desc *tx_desc = &isert_conn->conn_login_tx_desc; + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; + struct iser_tx_desc *tx_desc = &isert_conn->login_tx_desc; int ret; isert_create_send_desc(isert_conn, NULL, tx_desc); @@ -935,23 +1163,34 @@ tx_dsg->addr = isert_conn->login_rsp_dma; tx_dsg->length = length; - tx_dsg->lkey = isert_conn->conn_mr->lkey; + tx_dsg->lkey = isert_conn->device->pd->local_dma_lkey; tx_desc->num_sge = 2; } if (!login->login_failed) { if (login->login_complete) { + if (!conn->sess->sess_ops->SessionType && + isert_conn->device->use_fastreg) { + ret = isert_conn_create_fastreg_pool(isert_conn); + if (ret) { + isert_err("Conn: %p failed to create" + " fastreg pool\n", isert_conn); + return ret; + } + } + ret = isert_alloc_rx_descriptors(isert_conn); if (ret) return ret; - ret = isert_post_recv(isert_conn, ISERT_MIN_POSTED_RX); + ret = isert_post_recvm(isert_conn, + ISERT_QP_MAX_RECV_DTOS); if (ret) return ret; /* Now we are in FULL_FEATURE phase */ - mutex_lock(&isert_conn->conn_mutex); + mutex_lock(&isert_conn->mutex); isert_conn->state = ISER_CONN_FULL_FEATURE; - mutex_unlock(&isert_conn->conn_mutex); + mutex_unlock(&isert_conn->mutex); goto post_send; } @@ -976,7 +1215,7 @@ struct iscsi_login *login = conn->conn_login; int size; - pr_info("conn %p\n", isert_conn); + isert_info("conn %p\n", isert_conn); WARN_ON_ONCE(!login); @@ -1004,56 +1243,48 @@ memcpy(&login->req[0], (void *)&rx_desc->iscsi_header, ISCSI_HDR_LEN); size = min(rx_buflen, MAX_KEY_VALUE_PAIRS); - pr_debug("Using login payload size: %d, rx_buflen: %d MAX_KEY_VALUE_PAIRS: %d\n", - size, rx_buflen, MAX_KEY_VALUE_PAIRS); + isert_dbg("Using login payload size: %d, rx_buflen: %d " + "MAX_KEY_VALUE_PAIRS: %d\n", size, rx_buflen, + MAX_KEY_VALUE_PAIRS); memcpy(login->req_buf, &rx_desc->data[0], size); - if (login->first_request) - complete(&isert_conn->conn_login_comp); -} - -static void -isert_release_cmd(struct iscsi_cmd *cmd) -{ - struct isert_cmd *isert_cmd = container_of(cmd, struct isert_cmd, - iscsi_cmd); - - pr_debug("Entering isert_release_cmd %p >>>>>>>>>>>>>>>.\n", isert_cmd); - - kfree(cmd->buf_ptr); - kfree(cmd->tmr_req); - - kmem_cache_free(isert_cmd_cache, isert_cmd); + if (login->first_request) { + complete(&isert_conn->login_comp); + return; + } + schedule_delayed_work(&conn->login_work, 0); } static struct iscsi_cmd -*isert_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp) +*isert_allocate_cmd(struct iscsi_conn *conn, struct iser_rx_desc *rx_desc) { - struct isert_conn *isert_conn = (struct isert_conn *)conn->context; + struct isert_conn *isert_conn = conn->context; struct isert_cmd *isert_cmd; + struct iscsi_cmd *cmd; - isert_cmd = kmem_cache_zalloc(isert_cmd_cache, gfp); - if (!isert_cmd) { - pr_err("Unable to allocate isert_cmd\n"); + cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE); + if (!cmd) { + isert_err("Unable to allocate iscsi_cmd + isert_cmd\n"); return NULL; } + isert_cmd = iscsit_priv_cmd(cmd); isert_cmd->conn = isert_conn; - isert_cmd->iscsi_cmd.release_cmd = &isert_release_cmd; + isert_cmd->iscsi_cmd = cmd; + isert_cmd->rx_desc = rx_desc; - return &isert_cmd->iscsi_cmd; + return cmd; } static int isert_handle_scsi_cmd(struct isert_conn *isert_conn, - struct isert_cmd *isert_cmd, struct iser_rx_desc *rx_desc, - unsigned char *buf) + struct isert_cmd *isert_cmd, struct iscsi_cmd *cmd, + struct iser_rx_desc *rx_desc, unsigned char *buf) { - struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; struct iscsi_conn *conn = isert_conn->conn; struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)buf; - struct scatterlist *sg; int imm_data, imm_data_len, unsol_data, sg_nents, rc; bool dump_payload = false; + unsigned int data_len; rc = iscsit_setup_scsi_cmd(conn, cmd, buf); if (rc < 0) @@ -1062,7 +1293,10 @@ imm_data = cmd->immediate_data; imm_data_len = cmd->first_burst_len; unsol_data = cmd->unsolicited_data; + data_len = cmd->se_cmd.data_length; + if (imm_data && imm_data_len == data_len) + cmd->se_cmd.se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; rc = iscsit_process_scsi_cmd(conn, cmd, hdr); if (rc < 0) { return 0; @@ -1074,13 +1308,20 @@ if (!imm_data) return 0; - sg = &cmd->se_cmd.t_data_sg[0]; - sg_nents = max(1UL, DIV_ROUND_UP(imm_data_len, PAGE_SIZE)); - - pr_debug("Copying Immediate SG: %p sg_nents: %u from %p imm_data_len: %d\n", - sg, sg_nents, &rx_desc->data[0], imm_data_len); - - sg_copy_from_buffer(sg, sg_nents, &rx_desc->data[0], imm_data_len); + if (imm_data_len != data_len) { + sg_nents = max(1UL, DIV_ROUND_UP(imm_data_len, PAGE_SIZE)); + sg_copy_from_buffer(cmd->se_cmd.t_data_sg, sg_nents, + &rx_desc->data[0], imm_data_len); + isert_dbg("Copy Immediate sg_nents: %u imm_data_len: %d\n", + sg_nents, imm_data_len); + } else { + sg_init_table(&isert_cmd->sg, 1); + cmd->se_cmd.t_data_sg = &isert_cmd->sg; + cmd->se_cmd.t_data_nents = 1; + sg_set_buf(&isert_cmd->sg, &rx_desc->data[0], imm_data_len); + isert_dbg("Transfer Immediate imm_data_len: %d\n", + imm_data_len); + } cmd->write_data_done += imm_data_len; @@ -1097,7 +1338,7 @@ if (!rc && dump_payload == false && unsol_data) iscsit_set_unsoliticed_dataout(cmd); else if (dump_payload && imm_data) - target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); + target_put_sess_cmd(&cmd->se_cmd); return 0; } @@ -1122,13 +1363,15 @@ * FIXME: Unexpected unsolicited_data out */ if (!cmd->unsolicited_data) { - pr_err("Received unexpected solicited data payload\n"); + isert_err("Received unexpected solicited data payload\n"); dump_stack(); return -1; } - pr_debug("Unsolicited DataOut unsol_data_len: %u, write_data_done: %u, data_length: %u\n", - unsol_data_len, cmd->write_data_done, cmd->se_cmd.data_length); + isert_dbg("Unsolicited DataOut unsol_data_len: %u, " + "write_data_done: %u, data_length: %u\n", + unsol_data_len, cmd->write_data_done, + cmd->se_cmd.data_length); sg_off = cmd->write_data_done / PAGE_SIZE; sg_start = &cmd->se_cmd.t_data_sg[sg_off]; @@ -1138,12 +1381,13 @@ * FIXME: Non page-aligned unsolicited_data out */ if (page_off) { - pr_err("Received unexpected non-page aligned data payload\n"); + isert_err("unexpected non-page aligned data payload\n"); dump_stack(); return -1; } - pr_debug("Copying DataOut: sg_start: %p, sg_off: %u sg_nents: %u from %p %u\n", - sg_start, sg_off, sg_nents, &rx_desc->data[0], unsol_data_len); + isert_dbg("Copying DataOut: sg_start: %p, sg_off: %u " + "sg_nents: %u from %p %u\n", sg_start, sg_off, + sg_nents, &rx_desc->data[0], unsol_data_len); sg_copy_from_buffer(sg_start, sg_nents, &rx_desc->data[0], unsol_data_len); @@ -1152,10 +1396,67 @@ if (rc < 0) return rc; + /* + * multiple data-outs on the same command can arrive - + * so post the buffer before hand + */ + rc = isert_post_recv(isert_conn, rx_desc); + if (rc) { + isert_err("ib_post_recv failed with %d\n", rc); + return rc; + } return 0; } static int +isert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, + struct iscsi_cmd *cmd, struct iser_rx_desc *rx_desc, + unsigned char *buf) +{ + struct iscsi_conn *conn = isert_conn->conn; + struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf; + int rc; + + rc = iscsit_setup_nop_out(conn, cmd, hdr); + if (rc < 0) + return rc; + /* + * FIXME: Add support for NOPOUT payload using unsolicited RDMA payload + */ + + return iscsit_process_nop_out(conn, cmd, hdr); +} + +static int +isert_handle_text_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, + struct iscsi_cmd *cmd, struct iser_rx_desc *rx_desc, + struct iscsi_text *hdr) +{ + struct iscsi_conn *conn = isert_conn->conn; + u32 payload_length = ntoh24(hdr->dlength); + int rc; + unsigned char *text_in = NULL; + + rc = iscsit_setup_text_cmd(conn, cmd, hdr); + if (rc < 0) + return rc; + + if (payload_length) { + text_in = kzalloc(payload_length, GFP_KERNEL); + if (!text_in) { + isert_err("Unable to allocate text_in of payload_length: %u\n", + payload_length); + return -ENOMEM; + } + } + cmd->text_in_ptr = text_in; + + memcpy(cmd->text_in_ptr, &rx_desc->data[0], payload_length); + + return iscsit_process_text_cmd(conn, cmd, hdr); +} + +static int isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, uint32_t read_stag, uint64_t read_va, uint32_t write_stag, uint64_t write_va) @@ -1167,34 +1468,43 @@ int ret = -EINVAL; u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK); + if (conn->sess->sess_ops->SessionType && + (!(opcode & ISCSI_OP_TEXT) || !(opcode & ISCSI_OP_LOGOUT))) { + isert_err("Got illegal opcode: 0x%02x in SessionType=Discovery," + " ignoring\n", opcode); + return 0; + } + switch (opcode) { case ISCSI_OP_SCSI_CMD: - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); + cmd = isert_allocate_cmd(conn, rx_desc); if (!cmd) break; - isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd); + isert_cmd = iscsit_priv_cmd(cmd); isert_cmd->read_stag = read_stag; isert_cmd->read_va = read_va; isert_cmd->write_stag = write_stag; isert_cmd->write_va = write_va; - ret = isert_handle_scsi_cmd(isert_conn, isert_cmd, + ret = isert_handle_scsi_cmd(isert_conn, isert_cmd, cmd, rx_desc, (unsigned char *)hdr); break; case ISCSI_OP_NOOP_OUT: - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); + cmd = isert_allocate_cmd(conn, rx_desc); if (!cmd) break; - ret = iscsit_handle_nop_out(conn, cmd, (unsigned char *)hdr); + isert_cmd = iscsit_priv_cmd(cmd); + ret = isert_handle_nop_out(isert_conn, isert_cmd, cmd, + rx_desc, (unsigned char *)hdr); break; case ISCSI_OP_SCSI_DATA_OUT: ret = isert_handle_iscsi_dataout(isert_conn, rx_desc, (unsigned char *)hdr); break; case ISCSI_OP_SCSI_TMFUNC: - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); + cmd = isert_allocate_cmd(conn, rx_desc); if (!cmd) break; @@ -1202,18 +1512,27 @@ (unsigned char *)hdr); break; case ISCSI_OP_LOGOUT: - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); + cmd = isert_allocate_cmd(conn, rx_desc); if (!cmd) break; ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr); - if (ret > 0) - wait_for_completion_timeout(&conn->conn_logout_comp, - SECONDS_FOR_LOGOUT_COMP * - HZ); + break; + case ISCSI_OP_TEXT: + if (be32_to_cpu(hdr->ttt) != 0xFFFFFFFF) + cmd = iscsit_find_cmd_from_itt(conn, hdr->itt); + else + cmd = isert_allocate_cmd(conn, rx_desc); + + if (!cmd) + break; + + isert_cmd = iscsit_priv_cmd(cmd); + ret = isert_handle_text_cmd(isert_conn, isert_cmd, cmd, + rx_desc, (struct iscsi_text *)hdr); break; default: - pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode); + isert_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode); dump_stack(); break; } @@ -1227,62 +1546,62 @@ struct iser_hdr *iser_hdr = &rx_desc->iser_header; uint64_t read_va = 0, write_va = 0; uint32_t read_stag = 0, write_stag = 0; - int rc; switch (iser_hdr->flags & 0xF0) { case ISCSI_CTRL: if (iser_hdr->flags & ISER_RSV) { read_stag = be32_to_cpu(iser_hdr->read_stag); read_va = be64_to_cpu(iser_hdr->read_va); - pr_debug("ISER_RSV: read_stag: 0x%08x read_va: 0x%16llx\n", - read_stag, (unsigned long long)read_va); + isert_dbg("ISER_RSV: read_stag: 0x%x read_va: 0x%llx\n", + read_stag, (unsigned long long)read_va); } if (iser_hdr->flags & ISER_WSV) { write_stag = be32_to_cpu(iser_hdr->write_stag); write_va = be64_to_cpu(iser_hdr->write_va); - pr_debug("ISER_WSV: write__stag: 0x%08x write_va: 0x%16llx\n", - write_stag, (unsigned long long)write_va); + isert_dbg("ISER_WSV: write_stag: 0x%x write_va: 0x%llx\n", + write_stag, (unsigned long long)write_va); } - pr_debug("ISER ISCSI_CTRL PDU\n"); + isert_dbg("ISER ISCSI_CTRL PDU\n"); break; case ISER_HELLO: - pr_err("iSER Hello message\n"); + isert_err("iSER Hello message\n"); break; default: - pr_warn("Unknown iSER hdr flags: 0x%02x\n", iser_hdr->flags); + isert_warn("Unknown iSER hdr flags: 0x%02x\n", iser_hdr->flags); break; } - rc = isert_rx_opcode(isert_conn, rx_desc, - read_stag, read_va, write_stag, write_va); + isert_rx_opcode(isert_conn, rx_desc, + read_stag, read_va, write_stag, write_va); } static void -isert_rx_completion(struct iser_rx_desc *desc, struct isert_conn *isert_conn, - unsigned long xfer_len) +isert_rcv_completion(struct iser_rx_desc *desc, + struct isert_conn *isert_conn, + u32 xfer_len) { - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct ib_device *ib_dev = isert_conn->cm_id->device; struct iscsi_hdr *hdr; u64 rx_dma; - int rx_buflen, outstanding; + int rx_buflen; if ((char *)desc == isert_conn->login_req_buf) { rx_dma = isert_conn->login_req_dma; rx_buflen = ISER_RX_LOGIN_SIZE; - pr_debug("ISER login_buf: Using rx_dma: 0x%llx, rx_buflen: %d\n", + isert_dbg("login_buf: Using rx_dma: 0x%llx, rx_buflen: %d\n", rx_dma, rx_buflen); } else { rx_dma = desc->dma_addr; rx_buflen = ISER_RX_PAYLOAD_SIZE; - pr_debug("ISER req_buf: Using rx_dma: 0x%llx, rx_buflen: %d\n", + isert_dbg("req_buf: Using rx_dma: 0x%llx, rx_buflen: %d\n", rx_dma, rx_buflen); } ib_dma_sync_single_for_cpu(ib_dev, rx_dma, rx_buflen, DMA_FROM_DEVICE); hdr = &desc->iscsi_header; - pr_debug("iSCSI opcode: 0x%02x, ITT: 0x%08x, flags: 0x%02x dlen: %d\n", + isert_dbg("iSCSI opcode: 0x%02x, ITT: 0x%08x, flags: 0x%02x dlen: %d\n", hdr->opcode, hdr->itt, hdr->flags, (int)(xfer_len - ISER_HEADERS_LEN)); @@ -1294,9 +1613,9 @@ if (login && !login->first_request) isert_rx_login_req(isert_conn); } - mutex_lock(&isert_conn->conn_mutex); + mutex_lock(&isert_conn->mutex); complete(&isert_conn->login_req_comp); - mutex_unlock(&isert_conn->conn_mutex); + mutex_unlock(&isert_conn->mutex); } else { isert_rx_do_work(desc, isert_conn); } @@ -1304,53 +1623,115 @@ ib_dma_sync_single_for_device(ib_dev, rx_dma, rx_buflen, DMA_FROM_DEVICE); - isert_conn->post_recv_buf_count--; - pr_debug("iSERT: Decremented post_recv_buf_count: %d\n", - isert_conn->post_recv_buf_count); - - if ((char *)desc == isert_conn->login_req_buf) - return; +} - outstanding = isert_conn->post_recv_buf_count; - if (outstanding + ISERT_MIN_POSTED_RX <= ISERT_QP_MAX_RECV_DTOS) { - int err, count = min(ISERT_QP_MAX_RECV_DTOS - outstanding, - ISERT_MIN_POSTED_RX); - err = isert_post_recv(isert_conn, count); - if (err) { - pr_err("isert_post_recv() count: %d failed, %d\n", - count, err); - } +static int +isert_map_data_buf(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, + struct scatterlist *sg, u32 nents, u32 length, u32 offset, + enum iser_ib_op_code op, struct isert_data_buf *data) +{ + struct ib_device *ib_dev = isert_conn->cm_id->device; + + data->dma_dir = op == ISER_IB_RDMA_WRITE ? + DMA_TO_DEVICE : DMA_FROM_DEVICE; + + data->len = length - offset; + data->offset = offset; + data->sg_off = data->offset / PAGE_SIZE; + + data->sg = &sg[data->sg_off]; + data->nents = min_t(unsigned int, nents - data->sg_off, + ISCSI_ISER_SG_TABLESIZE); + data->len = min_t(unsigned int, data->len, ISCSI_ISER_SG_TABLESIZE * + PAGE_SIZE); + + data->dma_nents = ib_dma_map_sg(ib_dev, data->sg, data->nents, + data->dma_dir); + if (unlikely(!data->dma_nents)) { + isert_err("Cmd: unable to dma map SGs %p\n", sg); + return -EINVAL; } + + isert_dbg("Mapped cmd: %p count: %u sg: %p sg_nents: %u rdma_len %d\n", + isert_cmd, data->dma_nents, data->sg, data->nents, data->len); + + return 0; +} + +static void +isert_unmap_data_buf(struct isert_conn *isert_conn, struct isert_data_buf *data) +{ + struct ib_device *ib_dev = isert_conn->cm_id->device; + + ib_dma_unmap_sg(ib_dev, data->sg, data->nents, data->dma_dir); + memset(data, 0, sizeof(*data)); } + + static void isert_unmap_cmd(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn) { struct isert_rdma_wr *wr = &isert_cmd->rdma_wr; - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; - pr_debug("isert_unmap_cmd >>>>>>>>>>>>>>>>>>>>>>>\n"); + isert_dbg("Cmd %p\n", isert_cmd); + + if (wr->data.sg) { + isert_dbg("Cmd %p unmap_sg op\n", isert_cmd); + isert_unmap_data_buf(isert_conn, &wr->data); + } + + if (wr->rdma_wr) { + isert_dbg("Cmd %p free send_wr\n", isert_cmd); + kfree(wr->rdma_wr); + wr->rdma_wr = NULL; + } + + if (wr->ib_sge) { + isert_dbg("Cmd %p free ib_sge\n", isert_cmd); + kfree(wr->ib_sge); + wr->ib_sge = NULL; + } +} + +static void +isert_unreg_rdma(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn) +{ + struct isert_rdma_wr *wr = &isert_cmd->rdma_wr; + + isert_dbg("Cmd %p\n", isert_cmd); - if (wr->sge) { - ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge, DMA_TO_DEVICE); - wr->sge = NULL; + if (wr->fr_desc) { + isert_dbg("Cmd %p free fr_desc %p\n", isert_cmd, wr->fr_desc); + if (wr->fr_desc->ind & ISERT_PROTECTED) { + isert_unmap_data_buf(isert_conn, &wr->prot); + wr->fr_desc->ind &= ~ISERT_PROTECTED; + } + spin_lock_bh(&isert_conn->pool_lock); + list_add_tail(&wr->fr_desc->list, &isert_conn->fr_pool); + spin_unlock_bh(&isert_conn->pool_lock); + wr->fr_desc = NULL; } - kfree(wr->send_wr); - wr->send_wr = NULL; + if (wr->data.sg) { + isert_dbg("Cmd %p unmap_sg op\n", isert_cmd); + isert_unmap_data_buf(isert_conn, &wr->data); + } - kfree(isert_cmd->ib_sge); - isert_cmd->ib_sge = NULL; + wr->ib_sge = NULL; + wr->rdma_wr = NULL; } static void isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err) { - struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; + struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd; struct isert_conn *isert_conn = isert_cmd->conn; struct iscsi_conn *conn = isert_conn->conn; + struct isert_device *device = isert_conn->device; + struct iscsi_text_rsp *hdr; - pr_debug("Entering isert_put_cmd: %p\n", isert_cmd); + isert_dbg("Cmd %p\n", isert_cmd); switch (cmd->iscsi_opcode) { case ISCSI_OP_SCSI_CMD: @@ -1371,11 +1752,11 @@ cmd->se_cmd.t_state == TRANSPORT_WRITE_PENDING) { struct se_cmd *se_cmd = &cmd->se_cmd; - target_put_sess_cmd(se_cmd->se_sess, se_cmd); + target_put_sess_cmd(se_cmd); } } - isert_unmap_cmd(isert_cmd, isert_conn); + device->unreg_rdma_mem(isert_cmd, isert_conn); transport_generic_free_cmd(&cmd->se_cmd, 0); break; case ISCSI_OP_SCSI_TMFUNC: @@ -1388,6 +1769,12 @@ break; case ISCSI_OP_REJECT: case ISCSI_OP_NOOP_OUT: + case ISCSI_OP_TEXT: + hdr = (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header; + /* If the continue bit is on, keep the command alive */ + if (hdr->flags & ISCSI_FLAG_TEXT_CONTINUE) + break; + spin_lock_bh(&conn->cmd_lock); if (!list_empty(&cmd->i_conn_node)) list_del_init(&cmd->i_conn_node); @@ -1399,8 +1786,7 @@ * associated cmd->se_cmd needs to be released. */ if (cmd->se_cmd.se_tfo != NULL) { - pr_debug("Calling transport_generic_free_cmd from" - " isert_put_cmd for 0x%02x\n", + isert_dbg("Calling transport_generic_free_cmd for 0x%02x\n", cmd->iscsi_opcode); transport_generic_free_cmd(&cmd->se_cmd, 0); break; @@ -1409,7 +1795,7 @@ * Fall-through */ default: - isert_release_cmd(cmd); + iscsit_release_cmd(cmd); break; } } @@ -1418,7 +1804,7 @@ isert_unmap_tx_desc(struct iser_tx_desc *tx_desc, struct ib_device *ib_dev) { if (tx_desc->dma_addr != 0) { - pr_debug("Calling ib_dma_unmap_single for tx_desc->dma_addr\n"); + isert_dbg("unmap single for tx_desc->dma_addr\n"); ib_dma_unmap_single(ib_dev, tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); tx_desc->dma_addr = 0; @@ -1429,50 +1815,122 @@ isert_completion_put(struct iser_tx_desc *tx_desc, struct isert_cmd *isert_cmd, struct ib_device *ib_dev, bool comp_err) { - if (isert_cmd->sense_buf_dma != 0) { - pr_debug("Calling ib_dma_unmap_single for isert_cmd->sense_buf_dma\n"); - ib_dma_unmap_single(ib_dev, isert_cmd->sense_buf_dma, - isert_cmd->sense_buf_len, DMA_TO_DEVICE); - isert_cmd->sense_buf_dma = 0; + if (isert_cmd->pdu_buf_dma != 0) { + isert_dbg("unmap single for isert_cmd->pdu_buf_dma\n"); + ib_dma_unmap_single(ib_dev, isert_cmd->pdu_buf_dma, + isert_cmd->pdu_buf_len, DMA_TO_DEVICE); + isert_cmd->pdu_buf_dma = 0; } isert_unmap_tx_desc(tx_desc, ib_dev); isert_put_cmd(isert_cmd, comp_err); } +static int +isert_check_pi_status(struct se_cmd *se_cmd, struct ib_mr *sig_mr) +{ + struct ib_mr_status mr_status; + int ret; + + ret = ib_check_mr_status(sig_mr, IB_MR_CHECK_SIG_STATUS, &mr_status); + if (ret) { + isert_err("ib_check_mr_status failed, ret %d\n", ret); + goto fail_mr_status; + } + + if (mr_status.fail_status & IB_MR_CHECK_SIG_STATUS) { + u64 sec_offset_err; + u32 block_size = se_cmd->se_dev->dev_attrib.block_size + 8; + + switch (mr_status.sig_err.err_type) { + case IB_SIG_BAD_GUARD: + se_cmd->pi_err = TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED; + break; + case IB_SIG_BAD_REFTAG: + se_cmd->pi_err = TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED; + break; + case IB_SIG_BAD_APPTAG: + se_cmd->pi_err = TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED; + break; + } + sec_offset_err = mr_status.sig_err.sig_err_offset; + do_div(sec_offset_err, block_size); + se_cmd->bad_sector = sec_offset_err + se_cmd->t_task_lba; + + isert_err("PI error found type %d at sector 0x%llx " + "expected 0x%x vs actual 0x%x\n", + mr_status.sig_err.err_type, + (unsigned long long)se_cmd->bad_sector, + mr_status.sig_err.expected, + mr_status.sig_err.actual); + ret = 1; + } + +fail_mr_status: + return ret; +} + static void -isert_completion_rdma_read(struct iser_tx_desc *tx_desc, - struct isert_cmd *isert_cmd) +isert_completion_rdma_write(struct iser_tx_desc *tx_desc, + struct isert_cmd *isert_cmd) { struct isert_rdma_wr *wr = &isert_cmd->rdma_wr; - struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; + struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd; struct se_cmd *se_cmd = &cmd->se_cmd; - struct ib_device *ib_dev = isert_cmd->conn->conn_cm_id->device; - - iscsit_stop_dataout_timer(cmd); + struct isert_conn *isert_conn = isert_cmd->conn; + struct isert_device *device = isert_conn->device; + int ret = 0; - if (wr->sge) { - pr_debug("isert_do_rdma_read_comp: Unmapping wr->sge from t_data_sg\n"); - ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge, DMA_TO_DEVICE); - wr->sge = NULL; + if (wr->fr_desc && wr->fr_desc->ind & ISERT_PROTECTED) { + ret = isert_check_pi_status(se_cmd, + wr->fr_desc->pi_ctx->sig_mr); + wr->fr_desc->ind &= ~ISERT_PROTECTED; } - if (isert_cmd->ib_sge) { - pr_debug("isert_do_rdma_read_comp: Freeing isert_cmd->ib_sge\n"); - kfree(isert_cmd->ib_sge); - isert_cmd->ib_sge = NULL; + device->unreg_rdma_mem(isert_cmd, isert_conn); + wr->rdma_wr_num = 0; + if (ret) + transport_send_check_condition_and_sense(se_cmd, + se_cmd->pi_err, 0); + else + isert_put_response(isert_conn->conn, cmd); +} + +static void +isert_completion_rdma_read(struct iser_tx_desc *tx_desc, + struct isert_cmd *isert_cmd) +{ + struct isert_rdma_wr *wr = &isert_cmd->rdma_wr; + struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd; + struct se_cmd *se_cmd = &cmd->se_cmd; + struct isert_conn *isert_conn = isert_cmd->conn; + struct isert_device *device = isert_conn->device; + int ret = 0; + + if (wr->fr_desc && wr->fr_desc->ind & ISERT_PROTECTED) { + ret = isert_check_pi_status(se_cmd, + wr->fr_desc->pi_ctx->sig_mr); + wr->fr_desc->ind &= ~ISERT_PROTECTED; } - cmd->write_data_done = se_cmd->data_length; - wr->send_wr_num = 0; + iscsit_stop_dataout_timer(cmd); + device->unreg_rdma_mem(isert_cmd, isert_conn); + cmd->write_data_done = wr->data.len; + wr->rdma_wr_num = 0; - pr_debug("isert_do_rdma_read_comp, calling target_execute_cmd\n"); + isert_dbg("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd); spin_lock_bh(&cmd->istate_lock); cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT; cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT; spin_unlock_bh(&cmd->istate_lock); - target_execute_cmd(se_cmd); + if (ret) { + target_put_sess_cmd(se_cmd); + transport_send_check_condition_and_sense(se_cmd, + se_cmd->pi_err, 0); + } else { + target_execute_cmd(se_cmd); + } } static void @@ -1481,34 +1939,25 @@ struct isert_cmd *isert_cmd = container_of(work, struct isert_cmd, comp_work); struct isert_conn *isert_conn = isert_cmd->conn; - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; - struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; + struct ib_device *ib_dev = isert_conn->cm_id->device; + struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd; + + isert_dbg("Cmd %p i_state %d\n", isert_cmd, cmd->i_state); switch (cmd->i_state) { case ISTATE_SEND_TASKMGTRSP: - pr_debug("Calling iscsit_tmr_post_handler >>>>>>>>>>>>>>>>>\n"); - - atomic_dec(&isert_conn->post_send_buf_count); iscsit_tmr_post_handler(cmd, cmd->conn); - - cmd->i_state = ISTATE_SENT_STATUS; - isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev, false); - break; - case ISTATE_SEND_REJECT: - pr_debug("Got isert_do_control_comp ISTATE_SEND_REJECT: >>>\n"); - atomic_dec(&isert_conn->post_send_buf_count); - + case ISTATE_SEND_REJECT: /* FALLTHRU */ + case ISTATE_SEND_TEXTRSP: /* FALLTHRU */ cmd->i_state = ISTATE_SENT_STATUS; - isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev, false); + isert_completion_put(&isert_cmd->tx_desc, isert_cmd, + ib_dev, false); break; case ISTATE_SEND_LOGOUTRSP: - pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n"); - - atomic_dec(&isert_conn->post_send_buf_count); iscsit_logout_post_handler(cmd, cmd->conn); break; default: - pr_err("Unknown do_control_comp i_state %d\n", cmd->i_state); + isert_err("Unknown i_state %d\n", cmd->i_state); dump_stack(); break; } @@ -1520,181 +1969,160 @@ struct isert_conn *isert_conn, struct ib_device *ib_dev) { - struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; - struct isert_rdma_wr *wr = &isert_cmd->rdma_wr; + struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd; if (cmd->i_state == ISTATE_SEND_TASKMGTRSP || cmd->i_state == ISTATE_SEND_LOGOUTRSP || - cmd->i_state == ISTATE_SEND_REJECT) { + cmd->i_state == ISTATE_SEND_REJECT || + cmd->i_state == ISTATE_SEND_TEXTRSP) { isert_unmap_tx_desc(tx_desc, ib_dev); INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp); queue_work(isert_comp_wq, &isert_cmd->comp_work); return; } - atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count); cmd->i_state = ISTATE_SENT_STATUS; isert_completion_put(tx_desc, isert_cmd, ib_dev, false); } static void -isert_send_completion(struct iser_tx_desc *tx_desc, +isert_snd_completion(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn) { - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct ib_device *ib_dev = isert_conn->cm_id->device; struct isert_cmd *isert_cmd = tx_desc->isert_cmd; struct isert_rdma_wr *wr; if (!isert_cmd) { - atomic_dec(&isert_conn->post_send_buf_count); isert_unmap_tx_desc(tx_desc, ib_dev); return; } wr = &isert_cmd->rdma_wr; + isert_dbg("Cmd %p iser_ib_op %d\n", isert_cmd, wr->iser_ib_op); + switch (wr->iser_ib_op) { - case ISER_IB_RECV: - pr_err("isert_send_completion: Got ISER_IB_RECV\n"); - dump_stack(); - break; case ISER_IB_SEND: - pr_debug("isert_send_completion: Got ISER_IB_SEND\n"); isert_response_completion(tx_desc, isert_cmd, isert_conn, ib_dev); break; case ISER_IB_RDMA_WRITE: - pr_err("isert_send_completion: Got ISER_IB_RDMA_WRITE\n"); - dump_stack(); + isert_completion_rdma_write(tx_desc, isert_cmd); break; case ISER_IB_RDMA_READ: - pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n"); - - atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count); isert_completion_rdma_read(tx_desc, isert_cmd); break; default: - pr_err("Unknown wr->iser_ib_op: 0x%02x\n", wr->iser_ib_op); + isert_err("Unknown wr->iser_ib_op: 0x%x\n", wr->iser_ib_op); dump_stack(); break; } } -static void -isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn) +/** + * is_isert_tx_desc() - Indicate if the completion wr_id + * is a TX descriptor or not. + * @isert_conn: iser connection + * @wr_id: completion WR identifier + * + * Since we cannot rely on wc opcode in FLUSH errors + * we must work around it by checking if the wr_id address + * falls in the iser connection rx_descs buffer. If so + * it is an RX descriptor, otherwize it is a TX. + */ +static inline bool +is_isert_tx_desc(struct isert_conn *isert_conn, void *wr_id) { - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; - struct isert_cmd *isert_cmd = tx_desc->isert_cmd; + void *start = isert_conn->rx_descs; + int len = ISERT_QP_MAX_RECV_DTOS * sizeof(*isert_conn->rx_descs); - if (!isert_cmd) - isert_unmap_tx_desc(tx_desc, ib_dev); - else - isert_completion_put(tx_desc, isert_cmd, ib_dev, true); + if ((wr_id >= start && wr_id < start + len) || + (wr_id == isert_conn->login_req_buf)) + return false; + + return true; } static void -isert_cq_rx_comp_err(struct isert_conn *isert_conn) +isert_cq_comp_err(struct isert_conn *isert_conn, struct ib_wc *wc) { - struct iscsi_conn *conn = isert_conn->conn; - - if (isert_conn->post_recv_buf_count) - return; + if (wc->wr_id == ISER_BEACON_WRID) { + isert_info("conn %p completing wait_comp_err\n", + isert_conn); + complete(&isert_conn->wait_comp_err); + } else if (is_isert_tx_desc(isert_conn, (void *)(uintptr_t)wc->wr_id)) { + struct ib_device *ib_dev = isert_conn->cm_id->device; + struct isert_cmd *isert_cmd; + struct iser_tx_desc *desc; - if (conn->sess) { - target_sess_cmd_list_set_waiting(conn->sess->se_sess); - target_wait_for_sess_cmds(conn->sess->se_sess); + desc = (struct iser_tx_desc *)(uintptr_t)wc->wr_id; + isert_cmd = desc->isert_cmd; + if (!isert_cmd) + isert_unmap_tx_desc(desc, ib_dev); + else + isert_completion_put(desc, isert_cmd, ib_dev, true); } - - while (atomic_read(&isert_conn->post_send_buf_count)) - msleep(3000); - - mutex_lock(&isert_conn->conn_mutex); - isert_conn_terminate(isert_conn); - mutex_unlock(&isert_conn->conn_mutex); - - iscsit_cause_connection_reinstatement(isert_conn->conn, 0); - - complete(&isert_conn->conn_wait_comp_err); } static void -isert_cq_tx_work(struct work_struct *work) +isert_handle_wc(struct ib_wc *wc) { - struct isert_cq_desc *cq_desc = container_of(work, - struct isert_cq_desc, cq_tx_work); - struct isert_device *device = cq_desc->device; - int cq_index = cq_desc->cq_index; - struct ib_cq *tx_cq = device->dev_tx_cq[cq_index]; struct isert_conn *isert_conn; struct iser_tx_desc *tx_desc; - struct ib_wc wc; - - while (ib_poll_cq(tx_cq, 1, &wc) == 1) { - tx_desc = (struct iser_tx_desc *)(unsigned long)wc.wr_id; - isert_conn = wc.qp->qp_context; + struct iser_rx_desc *rx_desc; - if (wc.status == IB_WC_SUCCESS) { - isert_send_completion(tx_desc, isert_conn); + isert_conn = wc->qp->qp_context; + if (likely(wc->status == IB_WC_SUCCESS)) { + if (wc->opcode == IB_WC_RECV) { + rx_desc = (struct iser_rx_desc *)(uintptr_t)wc->wr_id; + isert_rcv_completion(rx_desc, isert_conn, wc->byte_len); } else { - pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n"); - pr_debug("TX wc.status: 0x%08x\n", wc.status); - atomic_dec(&isert_conn->post_send_buf_count); - isert_cq_tx_comp_err(tx_desc, isert_conn); + tx_desc = (struct iser_tx_desc *)(uintptr_t)wc->wr_id; + isert_snd_completion(tx_desc, isert_conn); } - } - - ib_req_notify_cq(tx_cq, IB_CQ_NEXT_COMP); -} - -static void -isert_cq_tx_callback(struct ib_cq *cq, void *context) -{ - struct isert_cq_desc *cq_desc = (struct isert_cq_desc *)context; + } else { + if (wc->status != IB_WC_WR_FLUSH_ERR) + isert_err("%s (%d): wr id %llx vend_err %x\n", + ib_wc_status_msg(wc->status), wc->status, + wc->wr_id, wc->vendor_err); + else + isert_dbg("%s (%d): wr id %llx\n", + ib_wc_status_msg(wc->status), wc->status, + wc->wr_id); - INIT_WORK(&cq_desc->cq_tx_work, isert_cq_tx_work); - queue_work(isert_comp_wq, &cq_desc->cq_tx_work); + if (wc->wr_id != ISER_FASTREG_LI_WRID) + isert_cq_comp_err(isert_conn, wc); + } } static void -isert_cq_rx_work(struct work_struct *work) +isert_cq_work(struct work_struct *work) { - struct isert_cq_desc *cq_desc = container_of(work, - struct isert_cq_desc, cq_rx_work); - struct isert_device *device = cq_desc->device; - int cq_index = cq_desc->cq_index; - struct ib_cq *rx_cq = device->dev_rx_cq[cq_index]; - struct isert_conn *isert_conn; - struct iser_rx_desc *rx_desc; - struct ib_wc wc; - unsigned long xfer_len; + enum { isert_poll_budget = 65536 }; + struct isert_comp *comp = container_of(work, struct isert_comp, + work); + struct ib_wc *const wcs = comp->wcs; + int i, n, completed = 0; - while (ib_poll_cq(rx_cq, 1, &wc) == 1) { - rx_desc = (struct iser_rx_desc *)(unsigned long)wc.wr_id; - isert_conn = wc.qp->qp_context; - - if (wc.status == IB_WC_SUCCESS) { - xfer_len = (unsigned long)wc.byte_len; - isert_rx_completion(rx_desc, isert_conn, xfer_len); - } else { - pr_debug("RX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n"); - if (wc.status != IB_WC_WR_FLUSH_ERR) - pr_debug("RX wc.status: 0x%08x\n", wc.status); + while ((n = ib_poll_cq(comp->cq, ARRAY_SIZE(comp->wcs), wcs)) > 0) { + for (i = 0; i < n; i++) + isert_handle_wc(&wcs[i]); - isert_conn->post_recv_buf_count--; - isert_cq_rx_comp_err(isert_conn); - } + completed += n; + if (completed >= isert_poll_budget) + break; } - ib_req_notify_cq(rx_cq, IB_CQ_NEXT_COMP); + ib_req_notify_cq(comp->cq, IB_CQ_NEXT_COMP); } static void -isert_cq_rx_callback(struct ib_cq *cq, void *context) +isert_cq_callback(struct ib_cq *cq, void *context) { - struct isert_cq_desc *cq_desc = (struct isert_cq_desc *)context; + struct isert_comp *comp = context; - INIT_WORK(&cq_desc->cq_rx_work, isert_cq_rx_work); - queue_work(isert_rx_wq, &cq_desc->cq_rx_work); + queue_work(isert_comp_wq, &comp->work); } static int @@ -1703,13 +2131,16 @@ struct ib_send_wr *wr_failed; int ret; - atomic_inc(&isert_conn->post_send_buf_count); + ret = isert_post_recv(isert_conn, isert_cmd->rx_desc); + if (ret) { + isert_err("ib_post_recv failed with %d\n", ret); + return ret; + } - ret = ib_post_send(isert_conn->conn_qp, &isert_cmd->tx_desc.send_wr, + ret = ib_post_send(isert_conn->qp, &isert_cmd->tx_desc.send_wr, &wr_failed); if (ret) { - pr_err("ib_post_send failed with %d\n", ret); - atomic_dec(&isert_conn->post_send_buf_count); + isert_err("ib_post_send failed with %d\n", ret); return ret; } return ret; @@ -1718,9 +2149,8 @@ static int isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd) { - struct isert_cmd *isert_cmd = container_of(cmd, - struct isert_cmd, iscsi_cmd); - struct isert_conn *isert_conn = (struct isert_conn *)conn->context; + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_conn *isert_conn = conn->context; struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; struct iscsi_scsi_rsp *hdr = (struct iscsi_scsi_rsp *) &isert_cmd->tx_desc.iscsi_header; @@ -1734,9 +2164,10 @@ if (cmd->se_cmd.sense_buffer && ((cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) || (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) { - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1]; - u32 padding, sense_len; + u32 padding, pdu_len; put_unaligned_be16(cmd->se_cmd.scsi_sense_length, cmd->sense_buffer); @@ -1744,33 +2175,70 @@ padding = -(cmd->se_cmd.scsi_sense_length) & 3; hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length); - sense_len = cmd->se_cmd.scsi_sense_length + padding; + pdu_len = cmd->se_cmd.scsi_sense_length + padding; - isert_cmd->sense_buf_dma = ib_dma_map_single(ib_dev, - (void *)cmd->sense_buffer, sense_len, + isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, + (void *)cmd->sense_buffer, pdu_len, DMA_TO_DEVICE); - isert_cmd->sense_buf_len = sense_len; - tx_dsg->addr = isert_cmd->sense_buf_dma; - tx_dsg->length = sense_len; - tx_dsg->lkey = isert_conn->conn_mr->lkey; + isert_cmd->pdu_buf_len = pdu_len; + tx_dsg->addr = isert_cmd->pdu_buf_dma; + tx_dsg->length = pdu_len; + tx_dsg->lkey = device->pd->local_dma_lkey; isert_cmd->tx_desc.num_sge = 2; } - isert_init_send_wr(isert_cmd, send_wr); + isert_init_send_wr(isert_conn, isert_cmd, send_wr); - pr_debug("Posting SCSI Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n"); + isert_dbg("Posting SCSI Response\n"); return isert_post_response(isert_conn, isert_cmd); } +static void +isert_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd) +{ + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_conn *isert_conn = conn->context; + struct isert_device *device = isert_conn->device; + + spin_lock_bh(&conn->cmd_lock); + if (!list_empty(&cmd->i_conn_node)) + list_del_init(&cmd->i_conn_node); + spin_unlock_bh(&conn->cmd_lock); + + if (cmd->data_direction == DMA_TO_DEVICE) + iscsit_stop_dataout_timer(cmd); + + device->unreg_rdma_mem(isert_cmd, isert_conn); +} + +static enum target_prot_op +isert_get_sup_prot_ops(struct iscsi_conn *conn) +{ + struct isert_conn *isert_conn = conn->context; + struct isert_device *device = isert_conn->device; + + if (conn->tpg->tpg_attrib.t10_pi) { + if (device->pi_capable) { + isert_info("conn %p PI offload enabled\n", isert_conn); + isert_conn->pi_support = true; + return TARGET_PROT_ALL; + } + } + + isert_info("conn %p PI offload disabled\n", isert_conn); + isert_conn->pi_support = false; + + return TARGET_PROT_NORMAL; +} + static int isert_put_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn, bool nopout_response) { - struct isert_cmd *isert_cmd = container_of(cmd, - struct isert_cmd, iscsi_cmd); - struct isert_conn *isert_conn = (struct isert_conn *)conn->context; + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_conn *isert_conn = conn->context; struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); @@ -1778,9 +2246,9 @@ &isert_cmd->tx_desc.iscsi_header, nopout_response); isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); - isert_init_send_wr(isert_cmd, send_wr); + isert_init_send_wr(isert_conn, isert_cmd, send_wr); - pr_debug("Posting NOPIN Reponse IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n"); + isert_dbg("conn %p Posting NOPIN Response\n", isert_conn); return isert_post_response(isert_conn, isert_cmd); } @@ -1788,18 +2256,17 @@ static int isert_put_logout_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn) { - struct isert_cmd *isert_cmd = container_of(cmd, - struct isert_cmd, iscsi_cmd); - struct isert_conn *isert_conn = (struct isert_conn *)conn->context; + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_conn *isert_conn = conn->context; struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); iscsit_build_logout_rsp(cmd, conn, (struct iscsi_logout_rsp *) &isert_cmd->tx_desc.iscsi_header); isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); - isert_init_send_wr(isert_cmd, send_wr); + isert_init_send_wr(isert_conn, isert_cmd, send_wr); - pr_debug("Posting Logout Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n"); + isert_dbg("conn %p Posting Logout Response\n", isert_conn); return isert_post_response(isert_conn, isert_cmd); } @@ -1807,18 +2274,17 @@ static int isert_put_tm_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn) { - struct isert_cmd *isert_cmd = container_of(cmd, - struct isert_cmd, iscsi_cmd); - struct isert_conn *isert_conn = (struct isert_conn *)conn->context; + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_conn *isert_conn = conn->context; struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); iscsit_build_task_mgt_rsp(cmd, conn, (struct iscsi_tm_rsp *) &isert_cmd->tx_desc.iscsi_header); isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); - isert_init_send_wr(isert_cmd, send_wr); + isert_init_send_wr(isert_conn, isert_cmd, send_wr); - pr_debug("Posting Task Management Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n"); + isert_dbg("conn %p Posting Task Management Response\n", isert_conn); return isert_post_response(isert_conn, isert_cmd); } @@ -1826,11 +2292,11 @@ static int isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn) { - struct isert_cmd *isert_cmd = container_of(cmd, - struct isert_cmd, iscsi_cmd); - struct isert_conn *isert_conn = (struct isert_conn *)conn->context; + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_conn *isert_conn = conn->context; struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1]; struct iscsi_reject *hdr = (struct iscsi_reject *)&isert_cmd->tx_desc.iscsi_header; @@ -1840,30 +2306,72 @@ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); hton24(hdr->dlength, ISCSI_HDR_LEN); - isert_cmd->sense_buf_dma = ib_dma_map_single(ib_dev, + isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, (void *)cmd->buf_ptr, ISCSI_HDR_LEN, DMA_TO_DEVICE); - isert_cmd->sense_buf_len = ISCSI_HDR_LEN; - tx_dsg->addr = isert_cmd->sense_buf_dma; + isert_cmd->pdu_buf_len = ISCSI_HDR_LEN; + tx_dsg->addr = isert_cmd->pdu_buf_dma; tx_dsg->length = ISCSI_HDR_LEN; - tx_dsg->lkey = isert_conn->conn_mr->lkey; + tx_dsg->lkey = device->pd->local_dma_lkey; isert_cmd->tx_desc.num_sge = 2; - isert_init_send_wr(isert_cmd, send_wr); + isert_init_send_wr(isert_conn, isert_cmd, send_wr); - pr_debug("Posting Reject IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n"); + isert_dbg("conn %p Posting Reject\n", isert_conn); + + return isert_post_response(isert_conn, isert_cmd); +} + +static int +isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn) +{ + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_conn *isert_conn = conn->context; + struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; + struct iscsi_text_rsp *hdr = + (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header; + u32 txt_rsp_len; + int rc; + + isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); + rc = iscsit_build_text_rsp(cmd, conn, hdr, ISCSI_INFINIBAND); + if (rc < 0) + return rc; + + txt_rsp_len = rc; + isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); + + if (txt_rsp_len) { + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; + struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1]; + void *txt_rsp_buf = cmd->buf_ptr; + + isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, + txt_rsp_buf, txt_rsp_len, DMA_TO_DEVICE); + + isert_cmd->pdu_buf_len = txt_rsp_len; + tx_dsg->addr = isert_cmd->pdu_buf_dma; + tx_dsg->length = txt_rsp_len; + tx_dsg->lkey = device->pd->local_dma_lkey; + isert_cmd->tx_desc.num_sge = 2; + } + isert_init_send_wr(isert_conn, isert_cmd, send_wr); + + isert_dbg("conn %p Text Response\n", isert_conn); return isert_post_response(isert_conn, isert_cmd); } static int isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, - struct ib_sge *ib_sge, struct ib_send_wr *send_wr, + struct ib_sge *ib_sge, struct ib_rdma_wr *rdma_wr, u32 data_left, u32 offset) { - struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; + struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd; struct scatterlist *sg_start, *tmp_sg; - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; u32 sg_off, page_off; int i = 0, sg_nents; @@ -1872,259 +2380,582 @@ sg_nents = min(cmd->se_cmd.t_data_nents - sg_off, isert_conn->max_sge); page_off = offset % PAGE_SIZE; - send_wr->sg_list = ib_sge; - send_wr->num_sge = sg_nents; - send_wr->wr_id = (unsigned long)&isert_cmd->tx_desc; + rdma_wr->wr.sg_list = ib_sge; + rdma_wr->wr.wr_id = (uintptr_t)&isert_cmd->tx_desc; /* * Perform mapping of TCM scatterlist memory ib_sge dma_addr. */ for_each_sg(sg_start, tmp_sg, sg_nents, i) { - pr_debug("ISER RDMA from SGL dma_addr: 0x%16llx dma_len: %u, page_off: %u\n", - (unsigned long long)tmp_sg->dma_address, - tmp_sg->length, page_off); + isert_dbg("RDMA from SGL dma_addr: 0x%llx dma_len: %u, " + "page_off: %u\n", + (unsigned long long)tmp_sg->dma_address, + tmp_sg->length, page_off); ib_sge->addr = ib_sg_dma_address(ib_dev, tmp_sg) + page_off; ib_sge->length = min_t(u32, data_left, ib_sg_dma_len(ib_dev, tmp_sg) - page_off); - ib_sge->lkey = isert_conn->conn_mr->lkey; + ib_sge->lkey = device->pd->local_dma_lkey; - pr_debug("RDMA ib_sge: addr: 0x%16llx length: %u\n", - ib_sge->addr, ib_sge->length); + isert_dbg("RDMA ib_sge: addr: 0x%llx length: %u lkey: %x\n", + ib_sge->addr, ib_sge->length, ib_sge->lkey); page_off = 0; data_left -= ib_sge->length; + if (!data_left) + break; ib_sge++; - pr_debug("Incrementing ib_sge pointer to %p\n", ib_sge); + isert_dbg("Incrementing ib_sge pointer to %p\n", ib_sge); } - pr_debug("Set outgoing sg_list: %p num_sg: %u from TCM SGLs\n", - send_wr->sg_list, send_wr->num_sge); + rdma_wr->wr.num_sge = ++i; + isert_dbg("Set outgoing sg_list: %p num_sg: %u from TCM SGLs\n", + rdma_wr->wr.sg_list, rdma_wr->wr.num_sge); - return sg_nents; + return rdma_wr->wr.num_sge; } static int -isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd) +isert_map_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd, + struct isert_rdma_wr *wr) { struct se_cmd *se_cmd = &cmd->se_cmd; - struct isert_cmd *isert_cmd = container_of(cmd, - struct isert_cmd, iscsi_cmd); - struct isert_rdma_wr *wr = &isert_cmd->rdma_wr; - struct isert_conn *isert_conn = (struct isert_conn *)conn->context; - struct ib_send_wr *wr_failed, *send_wr; - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_conn *isert_conn = conn->context; + struct isert_data_buf *data = &wr->data; + struct ib_rdma_wr *rdma_wr; struct ib_sge *ib_sge; - struct scatterlist *sg; - u32 offset = 0, data_len, data_left, rdma_write_max; - int rc, ret = 0, count, sg_nents, i, ib_sge_cnt; - - pr_debug("RDMA_WRITE: data_length: %u\n", se_cmd->data_length); - - sg = &se_cmd->t_data_sg[0]; - sg_nents = se_cmd->t_data_nents; - - count = ib_dma_map_sg(ib_dev, sg, sg_nents, DMA_TO_DEVICE); - if (unlikely(!count)) { - pr_err("Unable to map put_datain SGs\n"); - return -EINVAL; - } - wr->sge = sg; - wr->num_sge = sg_nents; - pr_debug("Mapped IB count: %u sg: %p sg_nents: %u for RDMA_WRITE\n", - count, sg, sg_nents); + u32 offset, data_len, data_left, rdma_write_max, va_offset = 0; + int ret = 0, i, ib_sge_cnt; + + isert_cmd->tx_desc.isert_cmd = isert_cmd; + + offset = wr->iser_ib_op == ISER_IB_RDMA_READ ? cmd->write_data_done : 0; + ret = isert_map_data_buf(isert_conn, isert_cmd, se_cmd->t_data_sg, + se_cmd->t_data_nents, se_cmd->data_length, + offset, wr->iser_ib_op, &wr->data); + if (ret) + return ret; - ib_sge = kzalloc(sizeof(struct ib_sge) * sg_nents, GFP_KERNEL); + data_left = data->len; + offset = data->offset; + + ib_sge = kzalloc(sizeof(struct ib_sge) * data->nents, GFP_KERNEL); if (!ib_sge) { - pr_warn("Unable to allocate datain ib_sge\n"); + isert_warn("Unable to allocate ib_sge\n"); ret = -ENOMEM; - goto unmap_sg; + goto unmap_cmd; } - isert_cmd->ib_sge = ib_sge; - - pr_debug("Allocated ib_sge: %p from t_data_ents: %d for RDMA_WRITE\n", - ib_sge, se_cmd->t_data_nents); + wr->ib_sge = ib_sge; - wr->send_wr_num = DIV_ROUND_UP(sg_nents, isert_conn->max_sge); - wr->send_wr = kzalloc(sizeof(struct ib_send_wr) * wr->send_wr_num, + wr->rdma_wr_num = DIV_ROUND_UP(data->nents, isert_conn->max_sge); + wr->rdma_wr = kzalloc(sizeof(struct ib_rdma_wr) * wr->rdma_wr_num, GFP_KERNEL); - if (!wr->send_wr) { - pr_err("Unable to allocate wr->send_wr\n"); + if (!wr->rdma_wr) { + isert_dbg("Unable to allocate wr->rdma_wr\n"); ret = -ENOMEM; - goto unmap_sg; + goto unmap_cmd; } - pr_debug("Allocated wr->send_wr: %p wr->send_wr_num: %u\n", - wr->send_wr, wr->send_wr_num); - - iscsit_increment_maxcmdsn(cmd, conn->sess); - cmd->stat_sn = conn->stat_sn++; wr->isert_cmd = isert_cmd; rdma_write_max = isert_conn->max_sge * PAGE_SIZE; - data_left = se_cmd->data_length; - for (i = 0; i < wr->send_wr_num; i++) { - send_wr = &isert_cmd->rdma_wr.send_wr[i]; + for (i = 0; i < wr->rdma_wr_num; i++) { + rdma_wr = &isert_cmd->rdma_wr.rdma_wr[i]; data_len = min(data_left, rdma_write_max); - send_wr->opcode = IB_WR_RDMA_WRITE; - send_wr->send_flags = 0; - send_wr->wr.rdma.remote_addr = isert_cmd->read_va + offset; - send_wr->wr.rdma.rkey = isert_cmd->read_stag; + rdma_wr->wr.send_flags = 0; + if (wr->iser_ib_op == ISER_IB_RDMA_WRITE) { + rdma_wr->wr.opcode = IB_WR_RDMA_WRITE; + rdma_wr->remote_addr = isert_cmd->read_va + offset; + rdma_wr->rkey = isert_cmd->read_stag; + if (i + 1 == wr->rdma_wr_num) + rdma_wr->wr.next = &isert_cmd->tx_desc.send_wr; + else + rdma_wr->wr.next = &wr->rdma_wr[i + 1].wr; + } else { + rdma_wr->wr.opcode = IB_WR_RDMA_READ; + rdma_wr->remote_addr = isert_cmd->write_va + va_offset; + rdma_wr->rkey = isert_cmd->write_stag; + if (i + 1 == wr->rdma_wr_num) + rdma_wr->wr.send_flags = IB_SEND_SIGNALED; + else + rdma_wr->wr.next = &wr->rdma_wr[i + 1].wr; + } ib_sge_cnt = isert_build_rdma_wr(isert_conn, isert_cmd, ib_sge, - send_wr, data_len, offset); + rdma_wr, data_len, offset); ib_sge += ib_sge_cnt; - if (i + 1 == wr->send_wr_num) - send_wr->next = &isert_cmd->tx_desc.send_wr; - else - send_wr->next = &wr->send_wr[i + 1]; - offset += data_len; + va_offset += data_len; data_left -= data_len; } - /* - * Build isert_conn->tx_desc for iSCSI response PDU and attach - */ - isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); - iscsit_build_rsp_pdu(cmd, conn, false, (struct iscsi_scsi_rsp *) - &isert_cmd->tx_desc.iscsi_header); - isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); - isert_init_send_wr(isert_cmd, &isert_cmd->tx_desc.send_wr); - atomic_add(wr->send_wr_num + 1, &isert_conn->post_send_buf_count); + return 0; +unmap_cmd: + isert_unmap_data_buf(isert_conn, data); - rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed); - if (rc) { - pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n"); - atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count); + return ret; +} + +static inline void +isert_inv_rkey(struct ib_send_wr *inv_wr, struct ib_mr *mr) +{ + u32 rkey; + + memset(inv_wr, 0, sizeof(*inv_wr)); + inv_wr->wr_id = ISER_FASTREG_LI_WRID; + inv_wr->opcode = IB_WR_LOCAL_INV; + inv_wr->ex.invalidate_rkey = mr->rkey; + + /* Bump the key */ + rkey = ib_inc_rkey(mr->rkey); + ib_update_fast_reg_key(mr, rkey); +} + +static int +isert_fast_reg_mr(struct isert_conn *isert_conn, + struct fast_reg_descriptor *fr_desc, + struct isert_data_buf *mem, + enum isert_indicator ind, + struct ib_sge *sge) +{ + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; + struct ib_mr *mr; + struct ib_reg_wr reg_wr; + struct ib_send_wr inv_wr, *bad_wr, *wr = NULL; + int ret, n; + + if (mem->dma_nents == 1) { + sge->lkey = device->pd->local_dma_lkey; + sge->addr = ib_sg_dma_address(ib_dev, &mem->sg[0]); + sge->length = ib_sg_dma_len(ib_dev, &mem->sg[0]); + isert_dbg("sge: addr: 0x%llx length: %u lkey: %x\n", + sge->addr, sge->length, sge->lkey); + return 0; } - pr_debug("Posted RDMA_WRITE + Response for iSER Data READ\n"); - return 1; -unmap_sg: - ib_dma_unmap_sg(ib_dev, sg, sg_nents, DMA_TO_DEVICE); + if (ind == ISERT_DATA_KEY_VALID) + /* Registering data buffer */ + mr = fr_desc->data_mr; + else + /* Registering protection buffer */ + mr = fr_desc->pi_ctx->prot_mr; + + if (!(fr_desc->ind & ind)) { + isert_inv_rkey(&inv_wr, mr); + wr = &inv_wr; + } + + n = ib_map_mr_sg(mr, mem->sg, mem->nents, PAGE_SIZE); + if (unlikely(n != mem->nents)) { + isert_err("failed to map mr sg (%d/%d)\n", + n, mem->nents); + return n < 0 ? n : -EINVAL; + } + + isert_dbg("Use fr_desc %p sg_nents %d offset %u\n", + fr_desc, mem->nents, mem->offset); + + reg_wr.wr.next = NULL; + reg_wr.wr.opcode = IB_WR_REG_MR; + reg_wr.wr.wr_id = ISER_FASTREG_LI_WRID; + reg_wr.wr.send_flags = 0; + reg_wr.wr.num_sge = 0; + reg_wr.mr = mr; + reg_wr.key = mr->lkey; + reg_wr.access = IB_ACCESS_LOCAL_WRITE; + + if (!wr) + wr = ®_wr.wr; + else + wr->next = ®_wr.wr; + + ret = ib_post_send(isert_conn->qp, wr, &bad_wr); + if (ret) { + isert_err("fast registration failed, ret:%d\n", ret); + return ret; + } + fr_desc->ind &= ~ind; + + sge->lkey = mr->lkey; + sge->addr = mr->iova; + sge->length = mr->length; + + isert_dbg("sge: addr: 0x%llx length: %u lkey: %x\n", + sge->addr, sge->length, sge->lkey); + return ret; } +static inline void +isert_set_dif_domain(struct se_cmd *se_cmd, struct ib_sig_attrs *sig_attrs, + struct ib_sig_domain *domain) +{ + domain->sig_type = IB_SIG_TYPE_T10_DIF; + domain->sig.dif.bg_type = IB_T10DIF_CRC; + domain->sig.dif.pi_interval = se_cmd->se_dev->dev_attrib.block_size; + domain->sig.dif.ref_tag = se_cmd->reftag_seed; + /* + * At the moment we hard code those, but if in the future + * the target core would like to use it, we will take it + * from se_cmd. + */ + domain->sig.dif.apptag_check_mask = 0xffff; + domain->sig.dif.app_escape = true; + domain->sig.dif.ref_escape = true; + if (se_cmd->prot_type == TARGET_DIF_TYPE1_PROT || + se_cmd->prot_type == TARGET_DIF_TYPE2_PROT) + domain->sig.dif.ref_remap = true; +}; + static int -isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery) +isert_set_sig_attrs(struct se_cmd *se_cmd, struct ib_sig_attrs *sig_attrs) { - struct se_cmd *se_cmd = &cmd->se_cmd; - struct isert_cmd *isert_cmd = container_of(cmd, - struct isert_cmd, iscsi_cmd); - struct isert_rdma_wr *wr = &isert_cmd->rdma_wr; - struct isert_conn *isert_conn = (struct isert_conn *)conn->context; - struct ib_send_wr *wr_failed, *send_wr; - struct ib_sge *ib_sge; - struct ib_device *ib_dev = isert_conn->conn_cm_id->device; - struct scatterlist *sg_start; - u32 sg_off, sg_nents, page_off, va_offset = 0; - u32 offset = 0, data_len, data_left, rdma_write_max; - int rc, ret = 0, count, i, ib_sge_cnt; + switch (se_cmd->prot_op) { + case TARGET_PROT_DIN_INSERT: + case TARGET_PROT_DOUT_STRIP: + sig_attrs->mem.sig_type = IB_SIG_TYPE_NONE; + isert_set_dif_domain(se_cmd, sig_attrs, &sig_attrs->wire); + break; + case TARGET_PROT_DOUT_INSERT: + case TARGET_PROT_DIN_STRIP: + sig_attrs->wire.sig_type = IB_SIG_TYPE_NONE; + isert_set_dif_domain(se_cmd, sig_attrs, &sig_attrs->mem); + break; + case TARGET_PROT_DIN_PASS: + case TARGET_PROT_DOUT_PASS: + isert_set_dif_domain(se_cmd, sig_attrs, &sig_attrs->wire); + isert_set_dif_domain(se_cmd, sig_attrs, &sig_attrs->mem); + break; + default: + isert_err("Unsupported PI operation %d\n", se_cmd->prot_op); + return -EINVAL; + } - pr_debug("RDMA_READ: data_length: %u write_data_done: %u\n", - se_cmd->data_length, cmd->write_data_done); + return 0; +} - sg_off = cmd->write_data_done / PAGE_SIZE; - sg_start = &cmd->se_cmd.t_data_sg[sg_off]; - page_off = cmd->write_data_done % PAGE_SIZE; +static inline u8 +isert_set_prot_checks(u8 prot_checks) +{ + return (prot_checks & TARGET_DIF_CHECK_GUARD ? 0xc0 : 0) | + (prot_checks & TARGET_DIF_CHECK_REFTAG ? 0x30 : 0) | + (prot_checks & TARGET_DIF_CHECK_REFTAG ? 0x0f : 0); +} - pr_debug("RDMA_READ: sg_off: %d, sg_start: %p page_off: %d\n", - sg_off, sg_start, page_off); +static int +isert_reg_sig_mr(struct isert_conn *isert_conn, + struct se_cmd *se_cmd, + struct isert_rdma_wr *rdma_wr, + struct fast_reg_descriptor *fr_desc) +{ + struct ib_sig_handover_wr sig_wr; + struct ib_send_wr inv_wr, *bad_wr, *wr = NULL; + struct pi_context *pi_ctx = fr_desc->pi_ctx; + struct ib_sig_attrs sig_attrs; + int ret; - data_left = se_cmd->data_length - cmd->write_data_done; - sg_nents = se_cmd->t_data_nents - sg_off; + memset(&sig_attrs, 0, sizeof(sig_attrs)); + ret = isert_set_sig_attrs(se_cmd, &sig_attrs); + if (ret) + goto err; - pr_debug("RDMA_READ: data_left: %d, sg_nents: %d\n", - data_left, sg_nents); + sig_attrs.check_mask = isert_set_prot_checks(se_cmd->prot_checks); - count = ib_dma_map_sg(ib_dev, sg_start, sg_nents, DMA_FROM_DEVICE); - if (unlikely(!count)) { - pr_err("Unable to map get_dataout SGs\n"); - return -EINVAL; + if (!(fr_desc->ind & ISERT_SIG_KEY_VALID)) { + isert_inv_rkey(&inv_wr, pi_ctx->sig_mr); + wr = &inv_wr; + } + + memset(&sig_wr, 0, sizeof(sig_wr)); + sig_wr.wr.opcode = IB_WR_REG_SIG_MR; + sig_wr.wr.wr_id = ISER_FASTREG_LI_WRID; + sig_wr.wr.sg_list = &rdma_wr->ib_sg[DATA]; + sig_wr.wr.num_sge = 1; + sig_wr.access_flags = IB_ACCESS_LOCAL_WRITE; + sig_wr.sig_attrs = &sig_attrs; + sig_wr.sig_mr = pi_ctx->sig_mr; + if (se_cmd->t_prot_sg) + sig_wr.prot = &rdma_wr->ib_sg[PROT]; + + if (!wr) + wr = &sig_wr.wr; + else + wr->next = &sig_wr.wr; + + ret = ib_post_send(isert_conn->qp, wr, &bad_wr); + if (ret) { + isert_err("fast registration failed, ret:%d\n", ret); + goto err; } - wr->sge = sg_start; - wr->num_sge = sg_nents; - pr_debug("Mapped IB count: %u sg_start: %p sg_nents: %u for RDMA_READ\n", - count, sg_start, sg_nents); + fr_desc->ind &= ~ISERT_SIG_KEY_VALID; - ib_sge = kzalloc(sizeof(struct ib_sge) * sg_nents, GFP_KERNEL); - if (!ib_sge) { - pr_warn("Unable to allocate dataout ib_sge\n"); - ret = -ENOMEM; - goto unmap_sg; + rdma_wr->ib_sg[SIG].lkey = pi_ctx->sig_mr->lkey; + rdma_wr->ib_sg[SIG].addr = 0; + rdma_wr->ib_sg[SIG].length = se_cmd->data_length; + if (se_cmd->prot_op != TARGET_PROT_DIN_STRIP && + se_cmd->prot_op != TARGET_PROT_DOUT_INSERT) + /* + * We have protection guards on the wire + * so we need to set a larget transfer + */ + rdma_wr->ib_sg[SIG].length += se_cmd->prot_length; + + isert_dbg("sig_sge: addr: 0x%llx length: %u lkey: %x\n", + rdma_wr->ib_sg[SIG].addr, rdma_wr->ib_sg[SIG].length, + rdma_wr->ib_sg[SIG].lkey); +err: + return ret; +} + +static int +isert_handle_prot_cmd(struct isert_conn *isert_conn, + struct isert_cmd *isert_cmd, + struct isert_rdma_wr *wr) +{ + struct isert_device *device = isert_conn->device; + struct se_cmd *se_cmd = &isert_cmd->iscsi_cmd->se_cmd; + int ret; + + if (!wr->fr_desc->pi_ctx) { + ret = isert_create_pi_ctx(wr->fr_desc, + device->ib_device, + device->pd); + if (ret) { + isert_err("conn %p failed to allocate pi_ctx\n", + isert_conn); + return ret; + } } - isert_cmd->ib_sge = ib_sge; - pr_debug("Using ib_sge: %p from sg_ents: %d for RDMA_READ\n", - ib_sge, sg_nents); + if (se_cmd->t_prot_sg) { + ret = isert_map_data_buf(isert_conn, isert_cmd, + se_cmd->t_prot_sg, + se_cmd->t_prot_nents, + se_cmd->prot_length, + 0, wr->iser_ib_op, &wr->prot); + if (ret) { + isert_err("conn %p failed to map protection buffer\n", + isert_conn); + return ret; + } - wr->send_wr_num = DIV_ROUND_UP(sg_nents, isert_conn->max_sge); - wr->send_wr = kzalloc(sizeof(struct ib_send_wr) * wr->send_wr_num, - GFP_KERNEL); - if (!wr->send_wr) { - pr_debug("Unable to allocate wr->send_wr\n"); - ret = -ENOMEM; - goto unmap_sg; + memset(&wr->ib_sg[PROT], 0, sizeof(wr->ib_sg[PROT])); + ret = isert_fast_reg_mr(isert_conn, wr->fr_desc, &wr->prot, + ISERT_PROT_KEY_VALID, &wr->ib_sg[PROT]); + if (ret) { + isert_err("conn %p failed to fast reg mr\n", + isert_conn); + goto unmap_prot_cmd; + } } - pr_debug("Allocated wr->send_wr: %p wr->send_wr_num: %u\n", - wr->send_wr, wr->send_wr_num); + + ret = isert_reg_sig_mr(isert_conn, se_cmd, wr, wr->fr_desc); + if (ret) { + isert_err("conn %p failed to fast reg mr\n", + isert_conn); + goto unmap_prot_cmd; + } + wr->fr_desc->ind |= ISERT_PROTECTED; + + return 0; + +unmap_prot_cmd: + if (se_cmd->t_prot_sg) + isert_unmap_data_buf(isert_conn, &wr->prot); + + return ret; +} + +static int +isert_reg_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd, + struct isert_rdma_wr *wr) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_conn *isert_conn = conn->context; + struct fast_reg_descriptor *fr_desc = NULL; + struct ib_rdma_wr *rdma_wr; + struct ib_sge *ib_sg; + u32 offset; + int ret = 0; + unsigned long flags; isert_cmd->tx_desc.isert_cmd = isert_cmd; - wr->iser_ib_op = ISER_IB_RDMA_READ; + offset = wr->iser_ib_op == ISER_IB_RDMA_READ ? cmd->write_data_done : 0; + ret = isert_map_data_buf(isert_conn, isert_cmd, se_cmd->t_data_sg, + se_cmd->t_data_nents, se_cmd->data_length, + offset, wr->iser_ib_op, &wr->data); + if (ret) + return ret; + + if (wr->data.dma_nents != 1 || isert_prot_cmd(isert_conn, se_cmd)) { + spin_lock_irqsave(&isert_conn->pool_lock, flags); + fr_desc = list_first_entry(&isert_conn->fr_pool, + struct fast_reg_descriptor, list); + list_del(&fr_desc->list); + spin_unlock_irqrestore(&isert_conn->pool_lock, flags); + wr->fr_desc = fr_desc; + } + + ret = isert_fast_reg_mr(isert_conn, fr_desc, &wr->data, + ISERT_DATA_KEY_VALID, &wr->ib_sg[DATA]); + if (ret) + goto unmap_cmd; + + if (isert_prot_cmd(isert_conn, se_cmd)) { + ret = isert_handle_prot_cmd(isert_conn, isert_cmd, wr); + if (ret) + goto unmap_cmd; + + ib_sg = &wr->ib_sg[SIG]; + } else { + ib_sg = &wr->ib_sg[DATA]; + } + + memcpy(&wr->s_ib_sge, ib_sg, sizeof(*ib_sg)); + wr->ib_sge = &wr->s_ib_sge; + wr->rdma_wr_num = 1; + memset(&wr->s_rdma_wr, 0, sizeof(wr->s_rdma_wr)); + wr->rdma_wr = &wr->s_rdma_wr; wr->isert_cmd = isert_cmd; - rdma_write_max = isert_conn->max_sge * PAGE_SIZE; - offset = cmd->write_data_done; - for (i = 0; i < wr->send_wr_num; i++) { - send_wr = &isert_cmd->rdma_wr.send_wr[i]; - data_len = min(data_left, rdma_write_max); + rdma_wr = &isert_cmd->rdma_wr.s_rdma_wr; + rdma_wr->wr.sg_list = &wr->s_ib_sge; + rdma_wr->wr.num_sge = 1; + rdma_wr->wr.wr_id = (uintptr_t)&isert_cmd->tx_desc; + if (wr->iser_ib_op == ISER_IB_RDMA_WRITE) { + rdma_wr->wr.opcode = IB_WR_RDMA_WRITE; + rdma_wr->remote_addr = isert_cmd->read_va; + rdma_wr->rkey = isert_cmd->read_stag; + rdma_wr->wr.send_flags = !isert_prot_cmd(isert_conn, se_cmd) ? + 0 : IB_SEND_SIGNALED; + } else { + rdma_wr->wr.opcode = IB_WR_RDMA_READ; + rdma_wr->remote_addr = isert_cmd->write_va; + rdma_wr->rkey = isert_cmd->write_stag; + rdma_wr->wr.send_flags = IB_SEND_SIGNALED; + } - send_wr->opcode = IB_WR_RDMA_READ; - send_wr->wr.rdma.remote_addr = isert_cmd->write_va + va_offset; - send_wr->wr.rdma.rkey = isert_cmd->write_stag; + return 0; - ib_sge_cnt = isert_build_rdma_wr(isert_conn, isert_cmd, ib_sge, - send_wr, data_len, offset); - ib_sge += ib_sge_cnt; +unmap_cmd: + if (fr_desc) { + spin_lock_irqsave(&isert_conn->pool_lock, flags); + list_add_tail(&fr_desc->list, &isert_conn->fr_pool); + spin_unlock_irqrestore(&isert_conn->pool_lock, flags); + } + isert_unmap_data_buf(isert_conn, &wr->data); - if (i + 1 == wr->send_wr_num) - send_wr->send_flags = IB_SEND_SIGNALED; - else - send_wr->next = &wr->send_wr[i + 1]; + return ret; +} - offset += data_len; - va_offset += data_len; - data_left -= data_len; +static int +isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_rdma_wr *wr = &isert_cmd->rdma_wr; + struct isert_conn *isert_conn = conn->context; + struct isert_device *device = isert_conn->device; + struct ib_send_wr *wr_failed; + int rc; + + isert_dbg("Cmd: %p RDMA_WRITE data_length: %u\n", + isert_cmd, se_cmd->data_length); + + wr->iser_ib_op = ISER_IB_RDMA_WRITE; + rc = device->reg_rdma_mem(conn, cmd, wr); + if (rc) { + isert_err("Cmd: %p failed to prepare RDMA res\n", isert_cmd); + return rc; } - atomic_add(wr->send_wr_num, &isert_conn->post_send_buf_count); + if (!isert_prot_cmd(isert_conn, se_cmd)) { + /* + * Build isert_conn->tx_desc for iSCSI response PDU and attach + */ + isert_create_send_desc(isert_conn, isert_cmd, + &isert_cmd->tx_desc); + iscsit_build_rsp_pdu(cmd, conn, true, (struct iscsi_scsi_rsp *) + &isert_cmd->tx_desc.iscsi_header); + isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); + isert_init_send_wr(isert_conn, isert_cmd, + &isert_cmd->tx_desc.send_wr); + isert_cmd->rdma_wr.s_rdma_wr.wr.next = &isert_cmd->tx_desc.send_wr; + wr->rdma_wr_num += 1; + + rc = isert_post_recv(isert_conn, isert_cmd->rx_desc); + if (rc) { + isert_err("ib_post_recv failed with %d\n", rc); + return rc; + } + } - rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed); + rc = ib_post_send(isert_conn->qp, &wr->rdma_wr->wr, &wr_failed); + if (rc) + isert_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n"); + + if (!isert_prot_cmd(isert_conn, se_cmd)) + isert_dbg("Cmd: %p posted RDMA_WRITE + Response for iSER Data " + "READ\n", isert_cmd); + else + isert_dbg("Cmd: %p posted RDMA_WRITE for iSER Data READ\n", + isert_cmd); + + return 1; +} + +static int +isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + struct isert_rdma_wr *wr = &isert_cmd->rdma_wr; + struct isert_conn *isert_conn = conn->context; + struct isert_device *device = isert_conn->device; + struct ib_send_wr *wr_failed; + int rc; + + isert_dbg("Cmd: %p RDMA_READ data_length: %u write_data_done: %u\n", + isert_cmd, se_cmd->data_length, cmd->write_data_done); + wr->iser_ib_op = ISER_IB_RDMA_READ; + rc = device->reg_rdma_mem(conn, cmd, wr); if (rc) { - pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n"); - atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count); + isert_err("Cmd: %p failed to prepare RDMA res\n", isert_cmd); + return rc; } - pr_debug("Posted RDMA_READ memory for ISER Data WRITE\n"); - return 0; -unmap_sg: - ib_dma_unmap_sg(ib_dev, sg_start, sg_nents, DMA_FROM_DEVICE); - return ret; + rc = ib_post_send(isert_conn->qp, &wr->rdma_wr->wr, &wr_failed); + if (rc) + isert_warn("ib_post_send() failed for IB_WR_RDMA_READ\n"); + + isert_dbg("Cmd: %p posted RDMA_READ memory for ISER Data WRITE\n", + isert_cmd); + + return 0; } static int isert_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state) { - int ret; + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + int ret = 0; switch (state) { + case ISTATE_REMOVE: + spin_lock_bh(&conn->cmd_lock); + list_del_init(&cmd->i_conn_node); + spin_unlock_bh(&conn->cmd_lock); + isert_put_cmd(isert_cmd, true); + break; case ISTATE_SEND_NOPIN_WANT_RESPONSE: ret = isert_put_nopin(cmd, conn, false); break; default: - pr_err("Unknown immediate state: 0x%02x\n", state); + isert_err("Unknown immediate state: 0x%02x\n", state); ret = -EINVAL; break; } @@ -2135,15 +2966,14 @@ static int isert_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state) { + struct isert_conn *isert_conn = conn->context; int ret; switch (state) { case ISTATE_SEND_LOGOUTRSP: ret = isert_put_logout_rsp(cmd, conn); - if (!ret) { - pr_debug("Returning iSER Logout -EAGAIN\n"); - ret = -EAGAIN; - } + if (!ret) + isert_conn->logout_posted = true; break; case ISTATE_SEND_NOPIN: ret = isert_put_nopin(cmd, conn, true); @@ -2154,6 +2984,9 @@ case ISTATE_SEND_REJECT: ret = isert_put_reject(cmd, conn); break; + case ISTATE_SEND_TEXTRSP: + ret = isert_put_text_rsp(cmd, conn); + break; case ISTATE_SEND_STATUS: /* * Special case for sending non GOOD SCSI status from TX thread @@ -2162,7 +2995,7 @@ ret = isert_put_response(conn, cmd); break; default: - pr_err("Unknown response state: 0x%02x\n", state); + isert_err("Unknown response state: 0x%02x\n", state); ret = -EINVAL; break; } @@ -2179,26 +3012,26 @@ int ret; sa = (struct sockaddr *)&np->np_sockaddr; - pr_debug("ksockaddr: %p, sa: %p\n", &np->np_sockaddr, sa); + isert_dbg("ksockaddr: %p, sa: %p\n", &np->np_sockaddr, sa); - id = rdma_create_id(isert_cma_handler, isert_np, + id = rdma_create_id(&init_net, isert_cma_handler, isert_np, RDMA_PS_TCP, IB_QPT_RC); if (IS_ERR(id)) { - pr_err("rdma_create_id() failed: %ld\n", PTR_ERR(id)); + isert_err("rdma_create_id() failed: %ld\n", PTR_ERR(id)); ret = PTR_ERR(id); goto out; } - pr_debug("id %p context %p\n", id, id->context); + isert_dbg("id %p context %p\n", id, id->context); ret = rdma_bind_addr(id, sa); if (ret) { - pr_err("rdma_bind_addr() failed: %d\n", ret); + isert_err("rdma_bind_addr() failed: %d\n", ret); goto out_id; } - ret = rdma_listen(id, ISERT_RDMA_LISTEN_BACKLOG); + ret = rdma_listen(id, 0); if (ret) { - pr_err("rdma_listen() failed: %d\n", ret); + isert_err("rdma_listen() failed: %d\n", ret); goto out_id; } @@ -2211,7 +3044,7 @@ static int isert_setup_np(struct iscsi_np *np, - struct __kernel_sockaddr_storage *ksockaddr) + struct sockaddr_storage *ksockaddr) { struct isert_np *isert_np; struct rdma_cm_id *isert_lid; @@ -2219,13 +3052,13 @@ isert_np = kzalloc(sizeof(struct isert_np), GFP_KERNEL); if (!isert_np) { - pr_err("Unable to allocate struct isert_np\n"); + isert_err("Unable to allocate struct isert_np\n"); return -ENOMEM; } - sema_init(&isert_np->np_sem, 0); - mutex_init(&isert_np->np_accept_mutex); - INIT_LIST_HEAD(&isert_np->np_accept_list); - init_completion(&isert_np->np_login_comp); + sema_init(&isert_np->sem, 0); + mutex_init(&isert_np->mutex); + INIT_LIST_HEAD(&isert_np->accepted); + INIT_LIST_HEAD(&isert_np->pending); isert_np->np = np; /* @@ -2233,7 +3066,7 @@ * in iscsi_target_configfs.c code.. */ memcpy(&np->np_sockaddr, ksockaddr, - sizeof(struct __kernel_sockaddr_storage)); + sizeof(struct sockaddr_storage)); isert_lid = isert_setup_id(isert_np); if (IS_ERR(isert_lid)) { @@ -2241,7 +3074,7 @@ goto out; } - isert_np->np_cm_id = isert_lid; + isert_np->cm_id = isert_lid; np->np_context = isert_np; return 0; @@ -2255,56 +3088,57 @@ static int isert_rdma_accept(struct isert_conn *isert_conn) { - struct rdma_cm_id *cm_id = isert_conn->conn_cm_id; + struct rdma_cm_id *cm_id = isert_conn->cm_id; struct rdma_conn_param cp; int ret; memset(&cp, 0, sizeof(struct rdma_conn_param)); - cp.responder_resources = isert_conn->responder_resources; cp.initiator_depth = isert_conn->initiator_depth; cp.retry_count = 7; cp.rnr_retry_count = 7; - pr_debug("Before rdma_accept >>>>>>>>>>>>>>>>>>>>.\n"); - ret = rdma_accept(cm_id, &cp); if (ret) { - pr_err("rdma_accept() failed with: %d\n", ret); + isert_err("rdma_accept() failed with: %d\n", ret); return ret; } - pr_debug("After rdma_accept >>>>>>>>>>>>>>>>>>>>>.\n"); - return 0; } static int isert_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login) { - struct isert_conn *isert_conn = (struct isert_conn *)conn->context; + struct isert_conn *isert_conn = conn->context; int ret; - pr_info("before login_req comp conn: %p\n", isert_conn); + isert_info("before login_req comp conn: %p\n", isert_conn); ret = wait_for_completion_interruptible(&isert_conn->login_req_comp); if (ret) { - pr_err("isert_conn %p interrupted before got login req\n", - isert_conn); + isert_err("isert_conn %p interrupted before got login req\n", + isert_conn); return ret; } - isert_conn->login_req_comp.done = 0; + reinit_completion(&isert_conn->login_req_comp); + /* + * For login requests after the first PDU, isert_rx_login_req() will + * kick schedule_delayed_work(&conn->login_work) as the packet is + * received, which turns this callback from iscsi_target_do_login_rx() + * into a NOP. + */ if (!login->first_request) return 0; isert_rx_login_req(isert_conn); - pr_info("before conn_login_comp conn: %p\n", conn); - - ret = wait_for_completion_interruptible(&isert_conn->conn_login_comp); + isert_info("before login_comp conn: %p\n", conn); + ret = wait_for_completion_interruptible(&isert_conn->login_comp); if (ret) return ret; - pr_info("processing login->req: %p\n", login->req); + isert_info("processing login->req: %p\n", login->req); + return 0; } @@ -2312,52 +3146,31 @@ isert_set_conn_info(struct iscsi_np *np, struct iscsi_conn *conn, struct isert_conn *isert_conn) { - struct rdma_cm_id *cm_id = isert_conn->conn_cm_id; + struct rdma_cm_id *cm_id = isert_conn->cm_id; struct rdma_route *cm_route = &cm_id->route; - struct sockaddr_in *sock_in; - struct sockaddr_in6 *sock_in6; conn->login_family = np->np_sockaddr.ss_family; - if (np->np_sockaddr.ss_family == AF_INET6) { - sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.dst_addr; - snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c", - &sock_in6->sin6_addr.in6_u); - conn->login_port = ntohs(sock_in6->sin6_port); - - sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.src_addr; - snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c", - &sock_in6->sin6_addr.in6_u); - conn->local_port = ntohs(sock_in6->sin6_port); - } else { - sock_in = (struct sockaddr_in *)&cm_route->addr.dst_addr; - sprintf(conn->login_ip, "%pI4", - &sock_in->sin_addr.s_addr); - conn->login_port = ntohs(sock_in->sin_port); - - sock_in = (struct sockaddr_in *)&cm_route->addr.src_addr; - sprintf(conn->local_ip, "%pI4", - &sock_in->sin_addr.s_addr); - conn->local_port = ntohs(sock_in->sin_port); - } + conn->login_sockaddr = cm_route->addr.dst_addr; + conn->local_sockaddr = cm_route->addr.src_addr; } static int isert_accept_np(struct iscsi_np *np, struct iscsi_conn *conn) { - struct isert_np *isert_np = (struct isert_np *)np->np_context; + struct isert_np *isert_np = np->np_context; struct isert_conn *isert_conn; - int max_accept = 0, ret; + int ret; accept_wait: - ret = down_interruptible(&isert_np->np_sem); - if (max_accept > 5) + ret = down_interruptible(&isert_np->sem); + if (ret) return -ENODEV; spin_lock_bh(&np->np_thread_lock); if (np->np_thread_state >= ISCSI_NP_THREAD_RESET) { spin_unlock_bh(&np->np_thread_lock); - pr_debug("np_thread_state %d for isert_accept_np\n", + isert_dbg("np_thread_state %d\n", np->np_thread_state); /** * No point in stalling here when np_thread @@ -2367,24 +3180,23 @@ } spin_unlock_bh(&np->np_thread_lock); - mutex_lock(&isert_np->np_accept_mutex); - if (list_empty(&isert_np->np_accept_list)) { - mutex_unlock(&isert_np->np_accept_mutex); - max_accept++; + mutex_lock(&isert_np->mutex); + if (list_empty(&isert_np->pending)) { + mutex_unlock(&isert_np->mutex); goto accept_wait; } - isert_conn = list_first_entry(&isert_np->np_accept_list, - struct isert_conn, conn_accept_node); - list_del_init(&isert_conn->conn_accept_node); - mutex_unlock(&isert_np->np_accept_mutex); + isert_conn = list_first_entry(&isert_np->pending, + struct isert_conn, node); + list_del_init(&isert_conn->node); + mutex_unlock(&isert_np->mutex); conn->context = isert_conn; isert_conn->conn = conn; - max_accept = 0; + isert_conn->state = ISER_CONN_BOUND; isert_set_conn_info(np, conn, isert_conn); - pr_debug("Processing isert_conn: %p\n", isert_conn); + isert_dbg("Processing isert_conn: %p\n", isert_conn); return 0; } @@ -2392,10 +3204,42 @@ static void isert_free_np(struct iscsi_np *np) { - struct isert_np *isert_np = (struct isert_np *)np->np_context; + struct isert_np *isert_np = np->np_context; + struct isert_conn *isert_conn, *n; + + if (isert_np->cm_id) + rdma_destroy_id(isert_np->cm_id); + + /* + * FIXME: At this point we don't have a good way to insure + * that at this point we don't have hanging connections that + * completed RDMA establishment but didn't start iscsi login + * process. So work-around this by cleaning up what ever piled + * up in accepted and pending lists. + */ + mutex_lock(&isert_np->mutex); + if (!list_empty(&isert_np->pending)) { + isert_info("Still have isert pending connections\n"); + list_for_each_entry_safe(isert_conn, n, + &isert_np->pending, + node) { + isert_info("cleaning isert_conn %p state (%d)\n", + isert_conn, isert_conn->state); + isert_connect_release(isert_conn); + } + } - if (isert_np->np_cm_id) - rdma_destroy_id(isert_np->np_cm_id); + if (!list_empty(&isert_np->accepted)) { + isert_info("Still have isert accepted connections\n"); + list_for_each_entry_safe(isert_conn, n, + &isert_np->accepted, + node) { + isert_info("cleaning isert_conn %p state (%d)\n", + isert_conn, isert_conn->state); + isert_connect_release(isert_conn); + } + } + mutex_unlock(&isert_np->mutex); np->np_context = NULL; kfree(isert_np); @@ -2407,37 +3251,118 @@ struct isert_conn, release_work); - pr_info("Starting release conn %p\n", isert_conn); + isert_info("Starting release conn %p\n", isert_conn); - wait_for_completion(&isert_conn->conn_wait); + wait_for_completion(&isert_conn->wait); - mutex_lock(&isert_conn->conn_mutex); + mutex_lock(&isert_conn->mutex); isert_conn->state = ISER_CONN_DOWN; - mutex_unlock(&isert_conn->conn_mutex); + mutex_unlock(&isert_conn->mutex); - pr_info("Destroying conn %p\n", isert_conn); + isert_info("Destroying conn %p\n", isert_conn); isert_put_conn(isert_conn); } +static void +isert_wait4logout(struct isert_conn *isert_conn) +{ + struct iscsi_conn *conn = isert_conn->conn; + + isert_info("conn %p\n", isert_conn); + + if (isert_conn->logout_posted) { + isert_info("conn %p wait for conn_logout_comp\n", isert_conn); + wait_for_completion_timeout(&conn->conn_logout_comp, + SECONDS_FOR_LOGOUT_COMP * HZ); + } +} + +static void +isert_wait4cmds(struct iscsi_conn *conn) +{ + isert_info("iscsi_conn %p\n", conn); + + if (conn->sess) { + target_sess_cmd_list_set_waiting(conn->sess->se_sess); + target_wait_for_sess_cmds(conn->sess->se_sess); + } +} + +static void +isert_wait4flush(struct isert_conn *isert_conn) +{ + struct ib_recv_wr *bad_wr; + + isert_info("conn %p\n", isert_conn); + + init_completion(&isert_conn->wait_comp_err); + isert_conn->beacon.wr_id = ISER_BEACON_WRID; + /* post an indication that all flush errors were consumed */ + if (ib_post_recv(isert_conn->qp, &isert_conn->beacon, &bad_wr)) { + isert_err("conn %p failed to post beacon", isert_conn); + return; + } + + wait_for_completion(&isert_conn->wait_comp_err); +} + +/** + * isert_put_unsol_pending_cmds() - Drop commands waiting for + * unsolicitate dataout + * @conn: iscsi connection + * + * We might still have commands that are waiting for unsolicited + * dataouts messages. We must put the extra reference on those + * before blocking on the target_wait_for_session_cmds + */ +static void +isert_put_unsol_pending_cmds(struct iscsi_conn *conn) +{ + struct iscsi_cmd *cmd, *tmp; + static LIST_HEAD(drop_cmd_list); + + spin_lock_bh(&conn->cmd_lock); + list_for_each_entry_safe(cmd, tmp, &conn->conn_cmd_list, i_conn_node) { + if ((cmd->cmd_flags & ICF_NON_IMMEDIATE_UNSOLICITED_DATA) && + (cmd->write_data_done < conn->sess->sess_ops->FirstBurstLength) && + (cmd->write_data_done < cmd->se_cmd.data_length)) + list_move_tail(&cmd->i_conn_node, &drop_cmd_list); + } + spin_unlock_bh(&conn->cmd_lock); + + list_for_each_entry_safe(cmd, tmp, &drop_cmd_list, i_conn_node) { + list_del_init(&cmd->i_conn_node); + if (cmd->i_state != ISTATE_REMOVE) { + struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); + + isert_info("conn %p dropping cmd %p\n", conn, cmd); + isert_put_cmd(isert_cmd, true); + } + } +} + static void isert_wait_conn(struct iscsi_conn *conn) { struct isert_conn *isert_conn = conn->context; - pr_debug("isert_wait_conn: Starting \n"); + isert_info("Starting conn %p\n", isert_conn); - mutex_lock(&isert_conn->conn_mutex); + mutex_lock(&isert_conn->mutex); /* - * Only wait for conn_wait_comp_err if the isert_conn made it + * Only wait for wait_comp_err if the isert_conn made it * into full feature phase.. */ if (isert_conn->state == ISER_CONN_INIT) { - mutex_unlock(&isert_conn->conn_mutex); + mutex_unlock(&isert_conn->mutex); return; } isert_conn_terminate(isert_conn); - mutex_unlock(&isert_conn->conn_mutex); + mutex_unlock(&isert_conn->mutex); - wait_for_completion(&isert_conn->conn_wait_comp_err); + isert_wait4flush(isert_conn); + isert_put_unsol_pending_cmds(conn); + isert_wait4cmds(conn); + isert_wait4logout(isert_conn); queue_work(isert_release_wq, &isert_conn->release_work); } @@ -2446,19 +3371,20 @@ { struct isert_conn *isert_conn = conn->context; + isert_wait4flush(isert_conn); isert_put_conn(isert_conn); } static struct iscsit_transport iser_target_transport = { .name = "IB/iSER", .transport_type = ISCSI_INFINIBAND, + .priv_size = sizeof(struct isert_cmd), .owner = THIS_MODULE, .iscsit_setup_np = isert_setup_np, .iscsit_accept_np = isert_accept_np, .iscsit_free_np = isert_free_np, .iscsit_wait_conn = isert_wait_conn, .iscsit_free_conn = isert_free_conn, - .iscsit_alloc_cmd = isert_alloc_cmd, .iscsit_get_login_rx = isert_get_login_rx, .iscsit_put_login_tx = isert_put_login_tx, .iscsit_immediate_queue = isert_immediate_queue, @@ -2466,68 +3392,52 @@ .iscsit_get_dataout = isert_get_dataout, .iscsit_queue_data_in = isert_put_datain, .iscsit_queue_status = isert_put_response, + .iscsit_aborted_task = isert_aborted_task, + .iscsit_get_sup_prot_ops = isert_get_sup_prot_ops, }; static int __init isert_init(void) { int ret; - isert_rx_wq = alloc_workqueue("isert_rx_wq", 0, 0); - if (!isert_rx_wq) { - pr_err("Unable to allocate isert_rx_wq\n"); - return -ENOMEM; - } - - isert_comp_wq = alloc_workqueue("isert_comp_wq", 0, 0); + isert_comp_wq = alloc_workqueue("isert_comp_wq", + WQ_UNBOUND | WQ_HIGHPRI, 0); if (!isert_comp_wq) { - pr_err("Unable to allocate isert_comp_wq\n"); + isert_err("Unable to allocate isert_comp_wq\n"); ret = -ENOMEM; - goto destroy_rx_wq; + return -ENOMEM; } isert_release_wq = alloc_workqueue("isert_release_wq", WQ_UNBOUND, WQ_UNBOUND_MAX_ACTIVE); if (!isert_release_wq) { - pr_err("Unable to allocate isert_release_wq\n"); + isert_err("Unable to allocate isert_release_wq\n"); ret = -ENOMEM; goto destroy_comp_wq; } - isert_cmd_cache = kmem_cache_create("isert_cmd_cache", - sizeof(struct isert_cmd), __alignof__(struct isert_cmd), - 0, NULL); - if (!isert_cmd_cache) { - pr_err("Unable to create isert_cmd_cache\n"); - ret = -ENOMEM; - goto destroy_release_wq; - } - iscsit_register_transport(&iser_target_transport); - pr_info("iSER_TARGET[0] - Loaded iser_target_transport\n"); + isert_info("iSER_TARGET[0] - Loaded iser_target_transport\n"); + return 0; -destroy_release_wq: - destroy_workqueue(isert_release_wq); destroy_comp_wq: destroy_workqueue(isert_comp_wq); -destroy_rx_wq: - destroy_workqueue(isert_rx_wq); + return ret; } static void __exit isert_exit(void) { flush_scheduled_work(); - kmem_cache_destroy(isert_cmd_cache); destroy_workqueue(isert_release_wq); destroy_workqueue(isert_comp_wq); - destroy_workqueue(isert_rx_wq); iscsit_unregister_transport(&iser_target_transport); - pr_debug("iSER_TARGET[0] - Released iser_target_transport\n"); + isert_info("iSER_TARGET[0] - Released iser_target_transport\n"); } MODULE_DESCRIPTION("iSER-Target for mainline target infrastructure"); -MODULE_VERSION("0.1"); +MODULE_VERSION("1.0"); MODULE_AUTHOR("nab@Linux-iSCSI.org"); MODULE_LICENSE("GPL");