mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-19 13:46:25 +00:00
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
This commit is contained in:
+101
-43
@@ -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);
|
||||
}
|
||||
|
||||
+24
-11
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user