From 0433a5c9654e9df4172f6dd4af9885d089f42cad Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 20 Mar 2014 15:22:19 +0000 Subject: [PATCH] ib_srpt: Rework multi-channel support Store initiator and target port ID's once per nexus instead of in each channel data structure. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5354 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- srpt/src/ib_srpt.c | 144 +++++++++++++++++++++++++++++++-------------- srpt/src/ib_srpt.h | 35 +++++++---- 2 files changed, 125 insertions(+), 54 deletions(-) diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index cb2ce48ac..e71832f38 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -2367,6 +2367,7 @@ static void srpt_drain_channel(struct ib_cm_id *cm_id) static void __srpt_close_all_ch(struct srpt_tgt *srpt_tgt) { + struct srpt_nexus *nexus; struct srpt_rdma_ch *ch; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) @@ -2374,14 +2375,16 @@ static void __srpt_close_all_ch(struct srpt_tgt *srpt_tgt) #endif restart: - list_for_each_entry(ch, &srpt_tgt->rch_list, list) { - if (ch->state >= CH_DISCONNECTING) - continue; - PRINT_INFO("Closing channel %s because target %s has been" - " disabled", ch->sess_name, - srpt_tgt->scst_tgt->tgt_name); - WARN_ON_ONCE(!__srpt_close_ch(ch)); - goto restart; + list_for_each_entry(nexus, &srpt_tgt->nexus_list, entry) { + list_for_each_entry(ch, &nexus->ch_list, list) { + if (ch->state >= CH_DISCONNECTING) + continue; + PRINT_INFO("Closing channel %s because target %s has" + " been disabled", ch->sess_name, + srpt_tgt->scst_tgt->tgt_name); + WARN_ON_ONCE(!__srpt_close_ch(ch)); + goto restart; + } } } @@ -2401,6 +2404,48 @@ static struct srpt_tgt *srpt_convert_scst_tgt(struct scst_tgt *scst_tgt) return srpt_tgt; } +/* + * Look up (i_port_id, t_port_id) in srpt_tgt->nexus_list. Create an entry if + * it does not yet exist. + */ +static struct srpt_nexus *srpt_get_nexus(struct srpt_tgt *srpt_tgt, + u8 i_port_id[16], u8 t_port_id[16]) +{ + unsigned long flags; + struct srpt_nexus *nexus = NULL, *tmp_nexus = NULL, *n; + + for (;;) { + spin_lock_irqsave(&srpt_tgt->spinlock, flags); + list_for_each_entry(n, &srpt_tgt->nexus_list, entry) { + if (memcmp(n->i_port_id, i_port_id, 16) == 0 && + memcmp(n->t_port_id, t_port_id, 16) == 0) { + nexus = n; + break; + } + } + if (!nexus && tmp_nexus) { + list_add_tail(&tmp_nexus->entry, &srpt_tgt->nexus_list); + swap(nexus, tmp_nexus); + } + spin_unlock_irqrestore(&srpt_tgt->spinlock, flags); + + if (nexus) + break; + tmp_nexus = kzalloc(sizeof(*nexus), GFP_KERNEL); + if (!tmp_nexus) { + nexus = ERR_PTR(-ENOMEM); + break; + } + INIT_LIST_HEAD(&tmp_nexus->ch_list); + memcpy(tmp_nexus->i_port_id, i_port_id, 16); + memcpy(tmp_nexus->t_port_id, t_port_id, 16); + } + + kfree(tmp_nexus); + + return nexus; +} + #if !defined(CONFIG_SCST_PROC) /** * srpt_enable_target - Set the "enabled" status of a target. @@ -2455,10 +2500,11 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, struct srpt_port *const sport = &sdev->port[param->port - 1]; struct srpt_tgt *const srpt_tgt = one_target_per_port ? &sport->srpt_tgt : &sdev->srpt_tgt; + struct srpt_nexus *nexus; struct srp_login_req *req; - struct srp_login_rsp *rsp; - struct srp_login_rej *rej; - struct ib_cm_rep_param *rep_param; + struct srp_login_rsp *rsp = NULL; + struct srp_login_rej *rej = NULL; + struct ib_cm_rep_param *rep_param = NULL; struct srpt_rdma_ch *ch = NULL; struct task_struct *thread; u32 it_iu_len; @@ -2512,6 +2558,13 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, be16_to_cpu(*(__be16 *)&sdev->port[param->port - 1].gid.raw[12]), be16_to_cpu(*(__be16 *)&sdev->port[param->port - 1].gid.raw[14])); + nexus = srpt_get_nexus(srpt_tgt, req->initiator_port_id, + req->target_port_id); + if (IS_ERR(nexus)) { + ret = PTR_ERR(nexus); + goto out; + } + ret = -ENOMEM; rsp = kzalloc(sizeof(*rsp), GFP_KERNEL); rej = kzalloc(sizeof(*rej), GFP_KERNEL); @@ -2564,8 +2617,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, PRINT_ERROR("Translating pkey %#x failed (%d) - using index 0", be16_to_cpu(param->primary_path->pkey), ret); } - memcpy(ch->i_port_id, req->initiator_port_id, 16); - memcpy(ch->t_port_id, req->target_port_id, 16); + ch->nexus = nexus; ch->sport = sport; ch->srpt_tgt = srpt_tgt; ch->cm_id = cm_id; @@ -2627,7 +2679,7 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, "0x%016llx%016llx", be64_to_cpu(*(__be64 *) &sdev->port[param->port - 1].gid.raw[8]), - be64_to_cpu(*(__be64 *)(ch->i_port_id + 8))); + be64_to_cpu(*(__be64 *)(nexus->i_port_id + 8))); } else { /* * Default behavior: use the initiator port identifier as the @@ -2635,16 +2687,16 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, */ snprintf(ch->sess_name, sizeof(ch->sess_name), "0x%016llx%016llx", - be64_to_cpu(*(__be64 *)ch->i_port_id), - be64_to_cpu(*(__be64 *)(ch->i_port_id + 8))); + be64_to_cpu(*(__be64 *)nexus->i_port_id), + be64_to_cpu(*(__be64 *)(nexus->i_port_id + 8))); } TRACE_DBG("registering session %s", ch->sess_name); BUG_ON(!srpt_tgt->scst_tgt); ret = -ENOMEM; - ch->scst_sess = scst_register_session(srpt_tgt->scst_tgt, 0, ch->sess_name, - ch, NULL, NULL); + ch->scst_sess = scst_register_session(srpt_tgt->scst_tgt, 0, + ch->sess_name, ch, NULL, NULL); if (!ch->scst_sess) { rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); TRACE_DBG("Failed to create SCST session"); @@ -2667,28 +2719,19 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_NO_CHAN; restart: - list_for_each_entry(ch2, &srpt_tgt->rch_list, list) { - if (!memcmp(ch2->i_port_id, req->initiator_port_id, 16) - && param->port == ch2->sport->port - && param->listen_id == ch2->sport->sdev->cm_id) { - if (!__srpt_close_ch(ch2)) - continue; - - PRINT_INFO("Relogin - closed existing channel" - " %s; cm_id = %p", ch2->sess_name, - ch2->cm_id); - - rsp->rsp_flags = - SRP_LOGIN_RSP_MULTICHAN_TERMINATED; - - goto restart; - } + list_for_each_entry(ch2, &nexus->ch_list, list) { + if (!__srpt_close_ch(ch2)) + continue; + PRINT_INFO("Relogin - closed existing channel %s", + ch2->sess_name); + rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_TERMINATED; + goto restart; } } else { rsp->rsp_flags = SRP_LOGIN_RSP_MULTICHAN_MAINTAINED; } - list_add_tail(&ch->list, &srpt_tgt->rch_list); + list_add_tail(&ch->list, &nexus->ch_list); ch->thread = thread; if (!srpt_tgt->enabled) { @@ -3496,7 +3539,8 @@ static int srpt_get_initiator_port_transport_id(struct scst_tgt *tgt, res = 0; tr_id->protocol_identifier = SCSI_TRANSPORTID_PROTOCOLID_SRP; - memcpy(tr_id->i_port_id, ch->i_port_id, sizeof(ch->i_port_id)); + memcpy(tr_id->i_port_id, ch->nexus->i_port_id, + sizeof(tr_id->i_port_id)); *transport_id = (uint8_t *)tr_id; @@ -3560,12 +3604,15 @@ static int srpt_close_session(struct scst_session *sess) return 0; } -static int srpt_ch_list_empty(struct srpt_tgt *srpt_tgt) +static bool srpt_ch_list_empty(struct srpt_tgt *srpt_tgt) { - int res; + struct srpt_nexus *nexus; + bool res = true; spin_lock_irq(&srpt_tgt->spinlock); - res = list_empty(&srpt_tgt->rch_list); + list_for_each_entry(nexus, &srpt_tgt->nexus_list, entry) + if (!list_empty(&nexus->ch_list)) + res = false; spin_unlock_irq(&srpt_tgt->spinlock); return res; @@ -3576,6 +3623,7 @@ static int srpt_ch_list_empty(struct srpt_tgt *srpt_tgt) */ static int srpt_release_sport(struct srpt_tgt *srpt_tgt) { + struct srpt_nexus *nexus, *next_n; struct srpt_rdma_ch *ch; TRACE_ENTRY(); @@ -3594,14 +3642,24 @@ static int srpt_release_sport(struct srpt_tgt *srpt_tgt) PRINT_INFO("%s: waiting for session unregistration ...", srpt_tgt->scst_tgt->tgt_name); spin_lock_irq(&srpt_tgt->spinlock); - list_for_each_entry(ch, &srpt_tgt->rch_list, list) { - PRINT_INFO("%s: state %s; %d commands in progress", - ch->sess_name, get_ch_state_name(ch->state), + list_for_each_entry(nexus, &srpt_tgt->nexus_list, entry) { + list_for_each_entry(ch, &nexus->ch_list, list) { + PRINT_INFO("%s: state %s; %d commands in" + " progress", ch->sess_name, + get_ch_state_name(ch->state), atomic_read(&ch->scst_sess->sess_cmd_count)); + } } spin_unlock_irq(&srpt_tgt->spinlock); } + spin_lock_irq(&srpt_tgt->spinlock); + list_for_each_entry_safe(nexus, next_n, &srpt_tgt->nexus_list, entry) { + list_del(&nexus->entry); + kfree(nexus); + } + spin_unlock_irq(&srpt_tgt->spinlock); + TRACE_EXIT(); return 0; } @@ -3845,7 +3903,7 @@ static struct scst_proc_data srpt_log_proc_data = { /* Note: the caller must have zero-initialized *@srpt_tgt. */ static void srpt_init_tgt(struct srpt_tgt *srpt_tgt) { - INIT_LIST_HEAD(&srpt_tgt->rch_list); + INIT_LIST_HEAD(&srpt_tgt->nexus_list); init_waitqueue_head(&srpt_tgt->ch_releaseQ); spin_lock_init(&srpt_tgt->spinlock); } diff --git a/srpt/src/ib_srpt.h b/srpt/src/ib_srpt.h index 710153e85..68ce897ed 100644 --- a/srpt/src/ib_srpt.h +++ b/srpt/src/ib_srpt.h @@ -56,6 +56,7 @@ */ #define SRP_SERVICE_NAME_PREFIX "SRP.T10:" +struct srpt_nexus; struct srpt_tgt; enum { @@ -294,6 +295,7 @@ enum rdma_ch_state { * struct srpt_rdma_ch - RDMA channel. * @thread: Kernel thread that processes the IB queues associated with * the channel. + * @nexus: I_T nexus this channel is associated with. * @cm_id: IB CM ID associated with the channel. * @qp: IB queue pair used for communicating over this channel. * @cq: IB completion queue for this channel. @@ -305,8 +307,6 @@ enum rdma_ch_state { * @sport: pointer to the information of the HCA port used by this * channel. * @srpt_tgt: Target port used by this channel. - * @i_port_id: 128-bit initiator port identifier copied from SRP_LOGIN_REQ. - * @t_port_id: 128-bit target port identifier copied from SRP_LOGIN_REQ. * @max_ti_iu_len: maximum target-to-initiator information unit length. * @req_lim: request limit: maximum number of requests that may be sent * by the initiator without having received a response. @@ -321,7 +321,7 @@ enum rdma_ch_state { * @processing_wait_list: Whether or not cmd_wait_list is being processed. * @dreq_received: Whether an IB CM DREQ event has been received. * @last_wqe_received: Whether the Last WQE QP event has been received. - * @list: node for insertion in the srpt_device.rch_list list. + * @list: Entry in srpt_nexus.ch_list; * @cmd_wait_list: list of SCST commands that arrived before the RTU event. This * list contains struct srpt_ioctx elements and is protected * against concurrent modification by the cm_id spinlock. @@ -331,6 +331,7 @@ enum rdma_ch_state { */ struct srpt_rdma_ch { struct task_struct *thread; + struct srpt_nexus *nexus; struct ib_cm_id *cm_id; struct ib_qp *qp; struct ib_cq *cq; @@ -341,8 +342,6 @@ struct srpt_rdma_ch { int sq_wr_avail; struct srpt_port *sport; struct srpt_tgt *srpt_tgt; - u8 i_port_id[16]; - u8 t_port_id[16]; int max_ti_iu_len; int req_lim; int req_lim_delta; @@ -362,18 +361,32 @@ struct srpt_rdma_ch { u8 sess_name[40]; }; +/** + * struct srpt_nexus - I_T nexus + * @entry: srpt_tgt.nexus_list list node. + * @ch_list: struct srpt_rdma_ch list. Protected by srpt_tgt.spinlock + * @i_port_id: 128-bit initiator port identifier copied from SRP_LOGIN_REQ. + * @t_port_id: 128-bit target port identifier copied from SRP_LOGIN_REQ. + */ +struct srpt_nexus { + struct list_head entry; + struct list_head ch_list; + u8 i_port_id[16]; + u8 t_port_id[16]; +}; + /** * struct srpt_tgt - * @ch_releaseQ: Enables waiting for removal from rch_list. - * @spinlock: Protects rch_list. - * @rch_list: Per-device channel list -- see also srpt_rdma_ch.list. - * @scst_tgt: SCST target information associated with this HCA. - * @enabled: Whether or not this SCST target is enabled. + * @ch_releaseQ: Enables waiting for removal from nexus_list. + * @spinlock: Protects nexus_list. + * @nexus_list: Per-device I_T nexus list. + * @scst_tgt: SCST target information associated with this HCA. + * @enabled: Whether or not this SCST target is enabled. */ struct srpt_tgt { wait_queue_head_t ch_releaseQ; spinlock_t spinlock; - struct list_head rch_list; + struct list_head nexus_list; struct scst_tgt *scst_tgt; bool enabled; };