diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index ae6410018..d55f1c7ab 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -2133,12 +2133,12 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch) ch->rq_size + srpt_sq_size); #else ch->cq = ib_create_cq(sdev->device, srpt_completion, NULL, ch, - ch->rq_size + srpt_sq_size, 0); + ch->rq_size + srpt_sq_size, ch->comp_vector); #endif if (IS_ERR(ch->cq)) { ret = PTR_ERR(ch->cq); - PRINT_ERROR("failed to create CQ cqe= %d ret= %d", - ch->rq_size + srpt_sq_size, ret); + PRINT_ERROR("failed to create CQ: cqe %d; c.v. %d; ret %d", + ch->rq_size + srpt_sq_size, ch->comp_vector, ret); goto out; } @@ -2296,6 +2296,18 @@ static void __srpt_close_all_ch(struct srpt_tgt *srpt_tgt) } } +static struct srpt_device *srpt_convert_to_sdev(struct scst_tgt *scst_tgt) +{ + struct srpt_port *sport; + + if (one_target_per_port) { + sport = scst_tgt_get_tgt_priv(scst_tgt); + return sport ? sport->sdev : NULL; + } else { + return scst_tgt_get_tgt_priv(scst_tgt); + } +} + static struct srpt_tgt *srpt_convert_scst_tgt(struct scst_tgt *scst_tgt) { struct srpt_device *sdev; @@ -2394,6 +2406,26 @@ static bool srpt_is_target_enabled(struct scst_tgt *scst_tgt) } #endif +/* + * srpt_next_comp_vector() - Next completion vector >= srpt_tgt->comp_vector + */ +static u8 srpt_next_comp_vector(struct srpt_tgt *srpt_tgt) +{ + u8 comp_vector; + + mutex_lock(&srpt_tgt->mutex); + comp_vector = find_next_bit(srpt_tgt->comp_v_mask, COMP_V_MASK_SIZE, + srpt_tgt->comp_vector); + if (comp_vector >= COMP_V_MASK_SIZE) + comp_vector = find_next_bit(srpt_tgt->comp_v_mask, + COMP_V_MASK_SIZE, 0); + sBUG_ON(comp_vector >= COMP_V_MASK_SIZE); + srpt_tgt->comp_vector = comp_vector + 1; + mutex_unlock(&srpt_tgt->mutex); + + return comp_vector; +} + /** * srpt_cm_req_recv() - Process the event IB_CM_REQ_RECEIVED. * @@ -2556,6 +2588,8 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev, list_add_tail(&ch->ioctx_ring[i]->free_list, &ch->free_list); } + ch->comp_vector = srpt_next_comp_vector(srpt_tgt); + ret = srpt_create_ch_ib(ch); if (ret) { rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES); @@ -3782,6 +3816,57 @@ static uint16_t srpt_get_scsi_transport_version(struct scst_tgt *scst_tgt) } #if !defined(CONFIG_SCST_PROC) +static ssize_t show_comp_v_mask(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_tgt *scst_tgt = container_of(kobj, struct scst_tgt, + tgt_kobj); + struct srpt_tgt *srpt_tgt = srpt_convert_scst_tgt(scst_tgt); + int res = -E_TGT_PRIV_NOT_YET_SET; + + if (!srpt_tgt) + goto out; + res = sprintf(buf, "%#lx\n%s", srpt_tgt->comp_v_mask[0], + SCST_SYSFS_KEY_MARK "\n"); + +out: + return res; +} + +static ssize_t store_comp_v_mask(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + struct scst_tgt *scst_tgt = container_of(kobj, struct scst_tgt, + tgt_kobj); + struct srpt_tgt *srpt_tgt = srpt_convert_scst_tgt(scst_tgt); + struct srpt_device *sdev = srpt_convert_to_sdev(scst_tgt); + int res = -E_TGT_PRIV_NOT_YET_SET; + unsigned long mask; + + if (!srpt_tgt) + goto out; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) + res = kstrtoul(buf, 16, &mask); +#else + res = strict_strtoul(buf, 16, &mask); +#endif + if (res) + goto out; + res = -EINVAL; + if (mask == 0 || mask >= (1ULL << sdev->device->num_comp_vectors)) + goto out; + srpt_tgt->comp_v_mask[0] = mask; + res = count; + +out: + return res; +} + +static struct kobj_attribute srpt_show_comp_v_mask_attr = + __ATTR(comp_v_mask, S_IRUGO | S_IWUSR, show_comp_v_mask, + store_comp_v_mask); + static ssize_t srpt_show_device(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -3873,6 +3958,7 @@ static struct kobj_attribute srpt_show_login_info_attr = __ATTR(login_info, S_IRUGO, show_login_info, NULL); static const struct attribute *srpt_tgt_attrs[] = { + &srpt_show_comp_v_mask_attr.attr, &srpt_device_attr.attr, &srpt_show_login_info_attr.attr, NULL @@ -3917,17 +4003,37 @@ static ssize_t show_ch_state(struct kobject *kobj, struct kobj_attribute *attr, return sprintf(buf, "%s\n", get_ch_state_name(ch->state)); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) || defined(RHEL_RELEASE_CODE) +static ssize_t show_comp_vector(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_session *scst_sess; + struct srpt_rdma_ch *ch; + + scst_sess = container_of(kobj, struct scst_session, sess_kobj); + ch = scst_sess_get_tgt_priv(scst_sess); + return ch ? sprintf(buf, "%u\n", ch->comp_vector) : -ENOENT; +} +#endif + static const struct kobj_attribute srpt_req_lim_attr = __ATTR(req_lim, S_IRUGO, show_req_lim, NULL); static const struct kobj_attribute srpt_req_lim_delta_attr = __ATTR(req_lim_delta, S_IRUGO, show_req_lim_delta, NULL); static const struct kobj_attribute srpt_ch_state_attr = __ATTR(ch_state, S_IRUGO, show_ch_state, NULL); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) || defined(RHEL_RELEASE_CODE) +static const struct kobj_attribute srpt_comp_vector_attr = + __ATTR(comp_vector, S_IRUGO, show_comp_vector, NULL); +#endif static const struct attribute *srpt_sess_attrs[] = { &srpt_req_lim_attr.attr, &srpt_req_lim_delta_attr.attr, &srpt_ch_state_attr.attr, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) || defined(RHEL_RELEASE_CODE) + &srpt_comp_vector_attr.attr, +#endif NULL }; #endif @@ -3986,9 +4092,13 @@ 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) { + int i; + INIT_LIST_HEAD(&srpt_tgt->nexus_list); init_waitqueue_head(&srpt_tgt->ch_releaseQ); mutex_init(&srpt_tgt->mutex); + for (i = 0; i < COMP_V_MASK_SIZE; i++) + __set_bit(i, srpt_tgt->comp_v_mask); } /** diff --git a/srpt/src/ib_srpt.h b/srpt/src/ib_srpt.h index 0e30e16ea..49d2a9b9f 100644 --- a/srpt/src/ib_srpt.h +++ b/srpt/src/ib_srpt.h @@ -139,6 +139,8 @@ enum { DEFAULT_MAX_RDMA_SIZE = 65536, RDMA_COMPL_TIMEOUT_S = 80, + + COMP_V_MASK_SIZE = 64, }; #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) && \ @@ -334,6 +336,7 @@ enum rdma_ch_state { * list contains struct srpt_ioctx elements and is protected * against concurrent modification by the cm_id spinlock. * @pkey: P_Key of the IB partition for this SRP channel. + * @comp_vector: Completion vector assigned to the QP. * @scst_sess: SCST session information associated with this SRP channel. * @sess_name: SCST session name. */ @@ -368,6 +371,9 @@ struct srpt_rdma_ch { struct list_head list; struct list_head cmd_wait_list; uint16_t pkey; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) || defined(RHEL_RELEASE_CODE) + u8 comp_vector; +#endif bool using_rdma_cm; bool processing_wait_list; @@ -395,6 +401,8 @@ struct srpt_nexus { * @mutex: Protects @nexus_list and srpt_nexus.ch_list. * @nexus_list: Per-device I_T nexus list. * @scst_tgt: SCST target information associated with this HCA. + * @comp_v_mask: Bitmask with one bit per allowed completion vector. + * @comp_vector: Completion vector from where searching will start. * @enabled: Whether or not this SCST target is enabled. */ struct srpt_tgt { @@ -402,6 +410,8 @@ struct srpt_tgt { struct mutex mutex; struct list_head nexus_list; struct scst_tgt *scst_tgt; + DECLARE_BITMAP(comp_v_mask, COMP_V_MASK_SIZE); + u8 comp_vector; bool enabled; };