IB/srp: Add multichannel support
Subsystems (4)
Bart Van Assche
maintainerv3 cover IB/srp: Add multichannel support
Although the SRP protocol supports multichannel operation, although since considerable time RDMA HCA's are available that support multiple completion vectors and although multichannel operation yields better performance than using a single channel, the Linux SRP initiator does not yet support multichannel operation. Hence this patch series that adds multichannel support to the SRP initiator driver.
Changes between v2 and v3:
* Eliminated the new function blk_mq_build_unique_tag() from patch 1.
* Elaborated the nr_hw_queues documentation in patch 2 as requested by Martin.
* Merged patches v2/10 and v2/11 into a single patch (v3/9).
* Removed a debug statement from the patch that adds multichannel support, and added another new debug statement (WARN_ON_ONCE(scmnd->request->tag < 0) in srp_queuecommand()).
* Added a new patch (v3/11) that fixes a recently reported race condition. Although that patch is unrelated to adding multichannel support, that patch has been added to this series to avoid merge conflicts by submitting patches for the same driver to different maintainers.
Changes between v1 and v2:
* Added a function to the block layer that allows SCSI LLDs to query the blk-mq hardware context index chosen by the block layer. Removed the mq_queuecommand callback again.
* Added support for multiple hardware queues in the TCQ functions in the SCSI core.
* Split a few patches and elaborated the patch descriptions to make it easier to review this patch series.
* Added two new patches: one patch that makes the SRP initiator always use block layer tags and another patch that realizes a micro- optimization, namely elimination of the free requests list.
The patches in this series are:
0001-blk-mq-Add-blk_mq_unique_tag.patch 0002-scsi-mq-Add-support-for-multiple-hardware-queues.patch 0003-scsi_tcq.h-Add-support-for-multiple-hardware-queues.patch 0004-IB-srp-Move-ib_destroy_cm_id-call-into-srp_free_ch_i.patch 0005-IB-srp-Remove-stale-connection-retry-mechanism.patch 0006-IB-srp-Avoid-that-I-O-hangs-due-to-a-cable-pull-duri.patch 0007-IB-srp-Introduce-two-new-srp_target_port-member-vari.patch 0008-IB-srp-Separate-target-and-channel-variables.patch 0009-IB-srp-Use-block-layer-tags.patch 0010-IB-srp-Add-multichannel-support.patch 0011-IB-srp-Fix-a-race-condition-triggered-by-destroying-.patch
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH v3 1/11 blk-mq: Add blk_mq_unique_tag()
The queuecommand() callback functions in SCSI low-level drivers need to know which hardware context has been selected by the block layer. Since this information is not available in the request structure, and since passing the hctx pointer directly to the queuecommand callback function would require modification of all SCSI LLDs, add a function to the block layer that allows to query the hardware context index.
--- block/blk-mq-tag.c | 28 ++++++++++++++++++++++++++++ block/blk-mq.c | 2 ++ include/linux/blk-mq.h | 17 +++++++++++++++++ 3 files changed, 47 insertions(+)
block/blk-mq-tag.c +28 -0
@@ -584,6 +584,34 @@ int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int tdepth)return 0 ; } +/** +* blk_mq_unique_tag() - return a tag that is unique queue-wide +* @rq: request for which to compute a unique tag +* +* The tag field in struct request is unique per hardware queue but not over +* all hardware queues. Hence this function that returns a tag with the +* hardware context index in the upper bits and the per hardware queue tag in +* the lower bits. +* +* Note: When called for a request that is queued on a non-multiqueue request +* queue, the hardware context index is set to zero. +*/ +u32 blk_mq_unique_tag (struct request *rq) +{ +struct request_queue *q = rq->q; +struct blk_mq_hw_ctx *hctx; +int hwq =0 ; + +if (q->mq_ops) { + hctx = q->mq_ops->map_queue (q, rq->mq_ctx->cpu); + hwq = hctx->queue_num; + } + +return (hwq <<BLK_MQ_UNIQUE_TAG_BITS ) | + (rq->tag &BLK_MQ_UNIQUE_TAG_MASK ); +} +EXPORT_SYMBOL (blk_mq_unique_tag); +ssize_t blk_mq_tag_sysfs_show (struct blk_mq_tags *tags,char *page) {char *orig_page = page;
block/blk-mq.c +2 -0
@@ -2024,6 +2024,8 @@ static int blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)*/ int blk_mq_alloc_tag_set (struct blk_mq_tag_set *set) { +BUILD_BUG_ON (BLK_MQ_MAX_DEPTH >1 <<BLK_MQ_UNIQUE_TAG_BITS ); +if (!set->nr_hw_queues)return -EINVAL ;if (!set->queue_depth)
include/linux/blk-mq.h +17 -0
@@ -167,6 +167,23 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp, bool reserved);struct request *blk_mq_tag_to_rq (struct blk_mq_tags *tags,unsigned int tag); +enum { +BLK_MQ_UNIQUE_TAG_BITS =16 , +BLK_MQ_UNIQUE_TAG_MASK = (1 <<BLK_MQ_UNIQUE_TAG_BITS ) -1 , +}; + +u32 blk_mq_unique_tag (struct request *rq); + +static inline u16 blk_mq_unique_tag_to_hwq (u32 unique_tag) +{ +return unique_tag >>BLK_MQ_UNIQUE_TAG_BITS ; +} + +static inline u16 blk_mq_unique_tag_to_tag (u32 unique_tag) +{ +return unique_tag &BLK_MQ_UNIQUE_TAG_MASK ; +} +struct blk_mq_hw_ctx *blk_mq_map_queue (struct request_queue *,const int ctx_index);struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue (struct blk_mq_tag_set *,unsigned int ,int );
Signature · 6 lines
1.8.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 01/11] blk-mq: Add blk_mq_unique_tag()
I've applied patches 1-3 to the core-for-3.19 branch. Various srp patches, including the first one fail to apply for me. Can you regenerate them against the drivers-for-3.19 branch? Thanks!
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH v3 01/11] blk-mq: Add blk_mq_unique_tag()
Quoted 3 lines · Christoph Hellwig
I've applied patches 1-3 to the core-for-3.19 branch. Various srp patches, including the first one fail to apply for me. Can you regenerate them against the drivers-for-3.19 branch? Thanks!
Hello Christoph,
That's strange. I have compared the patches that are already in your tree with the patches I had posted myself with a diff tool. These patches look identical to what I had posted except for one CC tag that has been left out. If I try to apply the three patches that have not yet been included in your tree (9/11..11/11) on top the drivers-for-3.19 branch then these patches apply fine. Anyway, I have rebased my tree on top of your drivers-for-3.19 branch, added a few other patches (including one block layer patch that has not yet been posted) and retested the SRP initiator driver against the traditional SCSI core and also against the scsi-mq core. The result can be found here: https://github.com/bvanassche/linux/commits/srp-multiple-hwq-v4. Can you please retry to apply patches 9/11..11/11 apply on top of the drivers-for-3.19 branch ?
Thanks,
Bart.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH v3 01/11] blk-mq: Add blk_mq_unique_tag()
Quoted 4 lines · Bart Van Assche
That's strange. I have compared the patches that are already in your tree with the patches I had posted myself with a diff tool. These patches look identical to what I had posted except for one CC tag that has been left out. If I try to apply the three patches that have not yet been included in your
Quoted 8 lines
tree (9/11..11/11) on top the drivers-for-3.19 branch then these patches apply fine. Anyway, I have rebased my tree on top of your drivers-for-3.19 branch, added a few other patches (including one block layer patch that has not yet been posted) and retested the SRP initiator driver against the traditional SCSI core and also against the scsi-mq core. The result can be found here: https://github.com/bvanassche/linux/commits/srp-multiple-hwq-v4.
Can you please retry to apply patches 9/11..11/11 apply on top of the drivers-for-3.19 branch ?
I've pulled in the three remaining patches from the series from that tree. If you want me to pull in the remaining trivial srp patch as well please give me a Reviewed-by: and I'll also pull it in.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Bart Van Assche
maintainerRe: [PATCH v3 01/11] blk-mq: Add blk_mq_unique_tag()
Quoted 14 lines · Christoph Hellwig
Quoted 4 lines · Bart Van Assche
That's strange. I have compared the patches that are already in your tree with the patches I had posted myself with a diff tool. These patches look identical to what I had posted except for one CC tag that has been left out. If I try to apply the three patches that have not yet been included in your
Quoted 8 lines
tree (9/11..11/11) on top the drivers-for-3.19 branch then these patches apply fine. Anyway, I have rebased my tree on top of your drivers-for-3.19 branch, added a few other patches (including one block layer patch that has not yet been posted) and retested the SRP initiator driver against the traditional SCSI core and also against the scsi-mq core. The result can be found here: https://github.com/bvanassche/linux/commits/srp-multiple-hwq-v4.
Can you please retry to apply patches 9/11..11/11 apply on top of the drivers-for-3.19 branch ?
Quoted 3 lines
I've pulled in the three remaining patches from the series from that tree. If you want me to pull in the remaining trivial srp patch as well please give me a Reviewed-by: and I'll also pull it in.
Thanks !
Regarding the remaining SRP patch: Roland has already been asked to pull that patch (see also http://thread.gmane.org/gmane.linux.drivers.rdma/22018).
Bart.
PATCH v3 7/11 IB/srp: Introduce two new srp_target_port member variables
In reply to a message not in the archiveIntroduce the srp_target_port member variables 'sgid' and 'pkey'. Change the type of 'orig_dgid' from __be16[8] into union ib_gid. This patch does not change any functionality but makes the "Separate target and channel variables" patch easier to verify.
--- drivers/infiniband/ulp/srp/ib_srp.c | 39 ++++++++++++++++++++++--------------- drivers/infiniband/ulp/srp/ib_srp.h | 4 +++- 2 files changed, 26 insertions(+), 17 deletions(-)
drivers/infiniband/ulp/srp/ib_srp.c +23 -16
@@ -262,7 +262,7 @@ static int srp_init_qp(struct srp_target_port *target, ret =ib_find_pkey (target->srp_host->srp_dev->dev, target->srp_host->port, -be16_to_cpu (target->path.pkey), +be16_to_cpu (target->pkey), &attr->pkey_index);if (ret) goto out;
@@ -295,6 +295,10 @@ static int srp_new_cm_id(struct srp_target_port *target)if (target->cm_id)ib_destroy_cm_id (target->cm_id); target->cm_id = new_cm_id; + target->path.sgid = target->sgid; + target->path.dgid = target->orig_dgid; + target->path.pkey = target->pkey; + target->path.service_id = target->service_id;return 0 ; }
@@ -689,7 +693,7 @@ static int srp_send_req(struct srp_target_port *target)*/ if (target->io_class ==SRP_REV10_IB_IO_CLASS ) {memcpy (req->priv.initiator_port_id, - &target->path.sgid.global.interface_id,8 ); + &target->sgid.global.interface_id,8 );memcpy (req->priv.initiator_port_id +8 , &target->initiator_ext,8 );memcpy (req->priv.target_port_id, &target->ioc_guid,8 );
@@ -698,7 +702,7 @@ static int srp_send_req(struct srp_target_port *target)memcpy (req->priv.initiator_port_id, &target->initiator_ext,8 );memcpy (req->priv.initiator_port_id +8 , - &target->path.sgid.global.interface_id,8 ); + &target->sgid.global.interface_id,8 );memcpy (req->priv.target_port_id, &target->id_ext,8 );memcpy (req->priv.target_port_id +8 , &target->ioc_guid,8 ); }
@@ -2175,8 +2179,8 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,else shost_printk (KERN_WARNING , shost,PFX "SRP LOGIN from %pI6 to %pI6 REJECTED, reason 0x%08x\n" , - target->path.sgid.raw, - target->orig_dgid, reason); + target->sgid.raw, + target->orig_dgid.raw, reason); }else shost_printk (KERN_WARNING , shost, " REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
@@ -2464,7 +2468,7 @@ static ssize_t show_pkey(struct device *dev, struct device_attribute *attr, {struct srp_target_port *target =host_to_target (class_to_shost (dev)); -return sprintf (buf,"0x%04x\n" ,be16_to_cpu (target->path.pkey)); +return sprintf (buf,"0x%04x\n" ,be16_to_cpu (target->pkey)); } static ssize_t show_sgid(struct device *dev, struct device_attribute *attr,
@@ -2472,7 +2476,7 @@ static ssize_t show_sgid(struct device *dev, struct device_attribute *attr, {struct srp_target_port *target =host_to_target (class_to_shost (dev)); -return sprintf (buf,"%pI6\n" , target->path.sgid.raw); +return sprintf (buf,"%pI6\n" , target->sgid.raw); } static ssize_t show_dgid(struct device *dev, struct device_attribute *attr,
@@ -2488,7 +2492,7 @@ static ssize_t show_orig_dgid(struct device *dev, {struct srp_target_port *target =host_to_target (class_to_shost (dev)); -return sprintf (buf,"%pI6\n" , target->orig_dgid); +return sprintf (buf,"%pI6\n" , target->orig_dgid.raw); } static ssize_t show_req_lim(struct device *dev,
@@ -2826,11 +2830,15 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) }for (i =0 ; i <16 ; ++i) { -strlcpy (dgid, p + i *2 ,3 ); - target->path.dgid.raw[i] =simple_strtoul (dgid,NULL ,16 ); +strlcpy (dgid, p + i *2 ,sizeof (dgid)); +if (sscanf (dgid,"%hhx" , + &target->orig_dgid.raw[i]) <1 ) { + ret = -EINVAL ; +kfree (p); + goto out; + } }kfree (p); -memcpy (target->orig_dgid, target->path.dgid.raw,16 );break ;case SRP_OPT_PKEY :
@@ -2838,7 +2846,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)pr_warn ("bad P_Key parameter '%s'\n" , p); goto out; } - target->path.pkey =cpu_to_be16 (token); + target->pkey =cpu_to_be16 (token);break ;case SRP_OPT_SERVICE_ID :
@@ -2848,7 +2856,6 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) goto out; } target->service_id =cpu_to_be64 (simple_strtoull (p,NULL ,16 )); - target->path.service_id = target->service_id;kfree (p);break ;
@@ -3058,7 +3065,7 @@ static ssize_t srp_create_target(struct device *dev,if (ret) goto err_free_mem; - ret =ib_query_gid (ibdev, host->port,0 , &target->path.sgid); + ret =ib_query_gid (ibdev, host->port,0 , &target->sgid);if (ret) goto err_free_mem;
@@ -3086,9 +3093,9 @@ static ssize_t srp_create_target(struct device *dev,"new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n" ,be64_to_cpu (target->id_ext),be64_to_cpu (target->ioc_guid), -be16_to_cpu (target->path.pkey), +be16_to_cpu (target->pkey),be64_to_cpu (target->service_id), - target->path.sgid.raw, target->orig_dgid); + target->sgid.raw, target->orig_dgid.raw); } ret = count;
drivers/infiniband/ulp/srp/ib_srp.h +3 -1
@@ -157,6 +157,7 @@ struct srp_target_port {* command processing. Try to keep them packed into cachelines. */ +union ib_gid sgid;__be64 id_ext;__be64 ioc_guid;__be64 service_id;
@@ -173,8 +174,9 @@ struct srp_target_port {int comp_vector;int tl_retry_count; +union ib_gid orig_dgid; +__be16 pkey;struct ib_sa_path_rec path; -__be16 orig_dgid[8 ];struct ib_sa_query *path_query;int path_query_id;
Signature · 6 lines
1.8.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v3 9/11 IB/srp: Use block layer tags
In reply to a message not in the archiveSince the block layer already contains functionality to assign a tag to each request, use that functionality instead of reimplementing that functionality in the SRP initiator driver. This change makes the free_reqs list superfluous. Hence remove that list.
--- drivers/infiniband/ulp/srp/ib_srp.c | 55 +++++++++++++++++++++++-------------- drivers/infiniband/ulp/srp/ib_srp.h | 3 -- 2 files changed, 35 insertions(+), 23 deletions(-)
drivers/infiniband/ulp/srp/ib_srp.c +35 -20
@@ -821,8 +821,6 @@ static int srp_alloc_req_data(struct srp_rdma_ch *ch)dma_addr_t dma_addr;int i, ret = -ENOMEM ; -INIT_LIST_HEAD (&ch->free_reqs); - ch->req_ring =kcalloc (target->req_ring_size,sizeof (*ch->req_ring),GFP_KERNEL );if (!ch->req_ring)
@@ -853,8 +851,6 @@ static int srp_alloc_req_data(struct srp_rdma_ch *ch) goto out; req->indirect_dma_addr = dma_addr; - req->index = i; -list_add_tail (&req->list, &ch->free_reqs); } ret =0 ;
@@ -1076,7 +1072,6 @@ static void srp_free_req(struct srp_rdma_ch *ch, struct srp_request *req,spin_lock_irqsave (&ch->lock, flags); ch->req_lim += req_lim_delta; -list_add_tail (&req->list, &ch->free_reqs);spin_unlock_irqrestore (&ch->lock, flags); }
@@ -1648,8 +1643,11 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) ch->tsk_mgmt_status = rsp->data[3 ];complete (&ch->tsk_mgmt_done); }else { - req = &ch->req_ring[rsp->tag]; - scmnd =srp_claim_req (ch, req,NULL ,NULL ); + scmnd =scsi_host_find_tag (target->scsi_host, rsp->tag); +if (scmnd) { + req = (void *)scmnd->host_scribble; + scmnd =srp_claim_req (ch, req,NULL , scmnd); + }if (!scmnd) { shost_printk(KERN_ERR, target->scsi_host, "Null scmnd for RSP w/tag %016llx\n",
@@ -1889,6 +1887,8 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)struct srp_cmd *cmd;struct ib_device *dev;unsigned long flags; +u32 tag; +u16 idx;int len, ret;const bool in_scsi_eh = !in_interrupt () && current == shost->ehandler;
@@ -1905,17 +1905,22 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)if (unlikely (scmnd->result)) goto err; +WARN_ON_ONCE (scmnd->request->tag <0 ); + tag =blk_mq_unique_tag (scmnd->request); ch = &target->ch; + idx =blk_mq_unique_tag_to_tag (tag); +WARN_ONCE (idx >= target->req_ring_size,"%s: tag %#x: idx %d >= %d\n" , +dev_name (&shost->shost_gendev), tag, idx, + target->req_ring_size);spin_lock_irqsave (&ch->lock, flags); iu =__srp_get_tx_iu (ch,SRP_IU_CMD ); -if (!iu) - goto err_unlock; - - req = list_first_entry(&ch->free_reqs, struct srp_request, list); -list_del (&req->list);spin_unlock_irqrestore (&ch->lock, flags); +if (!iu) + goto err; + + req = &ch->req_ring[idx]; dev = target->srp_host->srp_dev->dev;ib_dma_sync_single_for_cpu (dev, iu->dma, target->max_iu_len,DMA_TO_DEVICE );
@@ -1927,7 +1932,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) cmd->opcode =SRP_CMD ; cmd->lun =cpu_to_be64 ((u64 ) scmnd->device->lun <<48 ); - cmd->tag = req->index; + cmd->tag = tag;memcpy (cmd->cdb, scmnd->cmnd, scmnd->cmd_len); req->scmnd = scmnd;
@@ -1976,12 +1981,6 @@ err_iu:*/ req->scmnd =NULL ; -spin_lock_irqsave (&ch->lock, flags); -list_add (&req->list, &ch->free_reqs); - -err_unlock: -spin_unlock_irqrestore (&ch->lock, flags); - err:if (scmnd->result) { scmnd->scsi_done (scmnd);
@@ -2409,6 +2408,7 @@ static int srp_abort(struct scsi_cmnd *scmnd) {struct srp_target_port *target =host_to_target (scmnd->device->host);struct srp_request *req = (struct srp_request *) scmnd->host_scribble; +u32 tag;struct srp_rdma_ch *ch;int ret;
@@ -2417,7 +2417,8 @@ static int srp_abort(struct scsi_cmnd *scmnd) ch = &target->ch;if (!req || !srp_claim_req (ch, req,NULL , scmnd))return SUCCESS ; -if (srp_send_tsk_mgmt (ch, req->index, scmnd->device->lun, + tag =blk_mq_unique_tag (scmnd->request); +if (srp_send_tsk_mgmt (ch, tag, scmnd->device->lun,SRP_TSK_ABORT_TASK ) ==0 ) ret =SUCCESS ;else if (target->rport->state ==SRP_RPORT_LOST )
@@ -2463,6 +2464,15 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)return srp_reconnect_rport (target->rport) ==0 ?SUCCESS :FAILED ; } +static int srp_slave_alloc (struct scsi_device *sdev) +{ + sdev->tagged_supported =1 ; + +scsi_activate_tcq (sdev, sdev->queue_depth); + +return 0 ; +} +static int srp_slave_configure (struct scsi_device *sdev) {struct Scsi_Host *shost = sdev->host;
@@ -2641,6 +2651,7 @@ static struct scsi_host_template srp_template = { .module = THIS_MODULE, .name = "InfiniBand SRP initiator", .proc_name = DRV_NAME, + .slave_alloc = srp_slave_alloc, .slave_configure = srp_slave_configure, .info = srp_target_info, .queuecommand = srp_queuecommand,
@@ -3076,6 +3087,10 @@ static ssize_t srp_create_target(struct device *dev,if (ret) goto err; + ret =scsi_init_shared_tag_map (target_host, target_host->can_queue); +if (ret) + goto err; + target->req_ring_size = target->queue_size -SRP_TSK_MGMT_SQ_SIZE ;if (!srp_conn_unique (target->srp_host, target)) {
drivers/infiniband/ulp/srp/ib_srp.h +0 -3
@@ -116,7 +116,6 @@ struct srp_host { };struct srp_request { -struct list_head list;struct scsi_cmnd *scmnd;struct srp_iu *cmd;union {
@@ -127,7 +126,6 @@ struct srp_request {struct srp_direct_buf *indirect_desc;dma_addr_t indirect_dma_addr;short nmdesc; -short index; };/**
@@ -137,7 +135,6 @@ struct srp_request {struct srp_rdma_ch {/* These are RW in the hot path, and commonly used together */ struct list_head free_tx; -struct list_head free_reqs;spinlock_t lock;s32 req_lim;
Signature · 6 lines
1.8.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 09/11] IB/srp: Use block layer tags
Quoted 192 lines · Bart Van Assche
Since the block layer already contains functionality to assign a tag to each request, use that functionality instead of reimplementing that functionality in the SRP initiator driver. This change makes the
free_reqslist superfluous. Hence remove that list.Signed-off-by Bart Van Assche <[email protected]>Cc Sagi Grimberg <[email protected]>Cc Sebastian Parschauer <[email protected]>--- drivers/infiniband/ulp/srp/ib_srp.c | 55 +++++++++++++++++++++++-------------- drivers/infiniband/ulp/srp/ib_srp.h | 3 -- 2 files changed, 35 insertions(+), 23 deletions(-)drivers/infiniband/ulp/srp/ib_srp.c +35
-20@@ -821,8 +821,6 @@ static int srp_alloc_req_data(struct srp_rdma_ch *ch)dma_addr_t dma_addr;int i, ret = -ENOMEM ; -INIT_LIST_HEAD (&ch->free_reqs); - ch->req_ring =kcalloc (target->req_ring_size,sizeof (*ch->req_ring),GFP_KERNEL );if (!ch->req_ring)@@ -853,8 +851,6 @@ static int srp_alloc_req_data(struct srp_rdma_ch *ch) goto out; req->indirect_dma_addr = dma_addr; - req->index = i; -list_add_tail (&req->list, &ch->free_reqs); } ret =0 ;@@ -1076,7 +1072,6 @@ static void srp_free_req(struct srp_rdma_ch *ch, struct srp_request *req,spin_lock_irqsave (&ch->lock, flags); ch->req_lim += req_lim_delta; -list_add_tail (&req->list, &ch->free_reqs);spin_unlock_irqrestore (&ch->lock, flags); }@@ -1648,8 +1643,11 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) ch->tsk_mgmt_status = rsp->data[3 ];complete (&ch->tsk_mgmt_done); }else { - req = &ch->req_ring[rsp->tag]; - scmnd =srp_claim_req (ch, req,NULL ,NULL ); + scmnd =scsi_host_find_tag (target->scsi_host, rsp->tag); +if (scmnd) { + req = (void *)scmnd->host_scribble; + scmnd =srp_claim_req (ch, req,NULL , scmnd); + }if (!scmnd) { shost_printk(KERN_ERR, target->scsi_host, "Null scmnd for RSP w/tag %016llx\n",@@ -1889,6 +1887,8 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)struct srp_cmd *cmd;struct ib_device *dev;unsigned long flags; +u32 tag; +u16 idx;int len, ret;const bool in_scsi_eh = !in_interrupt () && current == shost->ehandler;@@ -1905,17 +1905,22 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)if (unlikely (scmnd->result)) goto err; +WARN_ON_ONCE (scmnd->request->tag <0 ); + tag =blk_mq_unique_tag (scmnd->request); ch = &target->ch; + idx =blk_mq_unique_tag_to_tag (tag); +WARN_ONCE (idx >= target->req_ring_size,"%s: tag %#x: idx %d >= %d\n" , +dev_name (&shost->shost_gendev), tag, idx, + target->req_ring_size);spin_lock_irqsave (&ch->lock, flags); iu =__srp_get_tx_iu (ch,SRP_IU_CMD ); -if (!iu) - goto err_unlock; - - req = list_first_entry(&ch->free_reqs, struct srp_request, list); -list_del (&req->list);spin_unlock_irqrestore (&ch->lock, flags); +if (!iu) + goto err; + + req = &ch->req_ring[idx]; dev = target->srp_host->srp_dev->dev;ib_dma_sync_single_for_cpu (dev, iu->dma, target->max_iu_len,DMA_TO_DEVICE );@@ -1927,7 +1932,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) cmd->opcode =SRP_CMD ; cmd->lun =cpu_to_be64 ((u64 ) scmnd->device->lun <<48 ); - cmd->tag = req->index; + cmd->tag = tag;memcpy (cmd->cdb, scmnd->cmnd, scmnd->cmd_len); req->scmnd = scmnd;@@ -1976,12 +1981,6 @@ err_iu:*/ req->scmnd =NULL ; -spin_lock_irqsave (&ch->lock, flags); -list_add (&req->list, &ch->free_reqs); - -err_unlock: -spin_unlock_irqrestore (&ch->lock, flags); - err:if (scmnd->result) { scmnd->scsi_done (scmnd);@@ -2409,6 +2408,7 @@ static int srp_abort(struct scsi_cmnd *scmnd) {struct srp_target_port *target =host_to_target (scmnd->device->host);struct srp_request *req = (struct srp_request *) scmnd->host_scribble; +u32 tag;struct srp_rdma_ch *ch;int ret;@@ -2417,7 +2417,8 @@ static int srp_abort(struct scsi_cmnd *scmnd) ch = &target->ch;if (!req || !srp_claim_req (ch, req,NULL , scmnd))return SUCCESS ; -if (srp_send_tsk_mgmt (ch, req->index, scmnd->device->lun, + tag =blk_mq_unique_tag (scmnd->request); +if (srp_send_tsk_mgmt (ch, tag, scmnd->device->lun,SRP_TSK_ABORT_TASK ) ==0 ) ret =SUCCESS ;else if (target->rport->state ==SRP_RPORT_LOST )@@ -2463,6 +2464,15 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)return srp_reconnect_rport (target->rport) ==0 ?SUCCESS :FAILED ; } +static int srp_slave_alloc (struct scsi_device *sdev) +{ + sdev->tagged_supported =1 ; + +scsi_activate_tcq (sdev, sdev->queue_depth); + +return 0 ; +} +static int srp_slave_configure (struct scsi_device *sdev) {struct Scsi_Host *shost = sdev->host;@@ -2641,6 +2651,7 @@ static struct scsi_host_template srp_template = { .module = THIS_MODULE, .name = "InfiniBand SRP initiator", .proc_name = DRV_NAME, + .slave_alloc = srp_slave_alloc, .slave_configure = srp_slave_configure, .info = srp_target_info, .queuecommand = srp_queuecommand,@@ -3076,6 +3087,10 @@ static ssize_t srp_create_target(struct device *dev,if (ret) goto err; + ret =scsi_init_shared_tag_map (target_host, target_host->can_queue); +if (ret) + goto err; + target->req_ring_size = target->queue_size -SRP_TSK_MGMT_SQ_SIZE ;if (!srp_conn_unique (target->srp_host, target)) {drivers/infiniband/ulp/srp/ib_srp.h +0
-2@@ -116,7 +116,6 @@ struct srp_host { };struct srp_request { -struct list_head list;struct scsi_cmnd *scmnd;struct srp_iu *cmd;union {@@ -127,7 +126,6 @@ struct srp_request {struct srp_direct_buf *indirect_desc;dma_addr_t indirect_dma_addr;short nmdesc; -short index; };/**
drivers/infiniband/ulp/srp/ib_srp.h struct srp_request { · line 140
Quoted 7 lines
drivers/infiniband/ulp/srp/ib_srp.h +0
-1@@ -137,7 +135,6 @@ struct srp_request {struct srp_rdma_ch {/* These are RW in the hot path, and commonly used together */ struct list_head free_tx; -struct list_head free_reqs;spinlock_t lock;s32 req_lim;
This looks good to me.
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH v3 09/11] IB/srp: Use block layer tags
FYI, I've updated this to use .use_blk_tags = 1 isntead of scsi_activate_tcq now that I've rebased the drivers-for-3.19 branch over the tcq rework. Please verify that it's workign as intented.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH v3 09/11] IB/srp: Use block layer tags
Quoted 3 lines · Christoph Hellwig
FYI, I've updated this to use .use_blk_tags = 1 isntead of
scsi_activate_tcqnow that I've rebased the drivers-for-3.19 branch over the tcq rework. Please verify that it's workign as intented.
[ just arrived home from traveling ]
Hello Christoph,
The SRP initiator passes the same tests as before. I have checked with ibdump and Wireshark that the SRP tags are still assigned properly. These tests have been run with and without blk-mq (use_blk_mq=Y versus N). The code I have tested is branch drivers-for-3.19 / commit 18f87a67e6d681d1c6f8b3c47985f21b25959a77.
Bart.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v3 10/11 IB/srp: Add multichannel support
In reply to a message not in the archiveImprove performance by using multiple RDMA/RC channels per SCSI host for communication with an SRP target. About the implementation:
- Introduce a loop over all channels in the code that uses target->ch.
- Set the SRP_MULTICHAN_MULTI flag during login for the creation of the second and subsequent channels.
- RDMA completion vectors are chosen such that RDMA completion interrupts are handled by the CPU socket that submitted the I/O request. As one can see in this patch it has been assumed if a system contains n CPU sockets and m RDMA completion vectors have been assigned to an RDMA HCA that IRQ affinity has been configured such that completion vectors [i*m/n..(i+1)*m/n) are bound to CPU socket i with 0 <= i < n.
- Modify srp_free_ch_ib() and srp_free_req_data() such that it becomes safe to invoke these functions after the corresponding allocation function failed.
- Add a ch_count sysfs attribute per target port.
--- Documentation/ABI/stable/sysfs-driver-ib_srp | 25 ++- drivers/infiniband/ulp/srp/ib_srp.c | 288 ++++++++++++++++++++------- drivers/infiniband/ulp/srp/ib_srp.h | 3 +- 3 files changed, 235 insertions(+), 81 deletions(-)
Documentation/ABI/stable/sysfs-driver-ib_srp +19 -6
@@ -55,12 +55,12 @@ Description: Interface for making ib_srp connect to a new target. only safe with partial memory descriptor list support enabled (allow_ext_sg=1). * comp_vector, a number in the range 0..n-1 specifying the - MSI-X completion vector. Some HCA's allocate multiple (n) - MSI-X vectors per HCA port. If the IRQ affinity masks of - these interrupts have been configured such that each MSI-X - interrupt is handled by a different CPU then the comp_vector - parameter can be used to spread the SRP completion workload - over multiple CPU's. + MSI-X completion vector of the first RDMA channel. Some + HCA's allocate multiple (n) MSI-X vectors per HCA port. If + the IRQ affinity masks of these interrupts have been + configured such that each MSI-X interrupt is handled by a + different CPU then the comp_vector parameter can be used to + spread the SRP completion workload over multiple CPU's. * tl_retry_count, a number in the range 2..7 specifying the IB RC retry count. * queue_size, the maximum number of commands that the
@@ -88,6 +88,13 @@ Description: Whether ib_srp is allowed to include a partial memory descriptor list in an SRP_CMD when communicating with an SRP target. +What: /sys/class/scsi_host/host<n>/ch_count +Date: April 1, 2015 +KernelVersion: 3.19 +Contact: [email protected] +Description: Number of RDMA channels used for communication with the SRP + target. + What: /sys/class/scsi_host/host<n>/cmd_sg_entries Date: May 19, 2011 KernelVersion: 2.6.39
@@ -95,6 +102,12 @@ Contact: [email protected] Description: Maximum number of data buffer descriptors that may be sent to the target in a single SRP_CMD request. +What: /sys/class/scsi_host/host<n>/comp_vector +Date: September 2, 2013 +KernelVersion: 3.11 +Contact: [email protected] +Description: Completion vector used for the first RDMA channel. + What: /sys/class/scsi_host/host<n>/dgid Date: June 17, 2006 KernelVersion: 2.6.17
drivers/infiniband/ulp/srp/ib_srp.c +214 -74
498 lines not on this page · raw message
drivers/infiniband/ulp/srp/ib_srp.h +2 -1
@@ -179,8 +179,9 @@ struct srp_target_port {/* read and written in the hot path */ spinlock_t lock; -struct srp_rdma_ch ch;/* read only in the hot path */ +struct srp_rdma_ch *ch; +u32 ch_count;u32 lkey;u32 rkey;enum srp_target_state state;
Signature · 6 lines
1.8.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Bart Van Assche
maintainerPATCH v3 2/11 scsi-mq: Add support for multiple hardware queues
In reply to Bart Van AsscheAllow a SCSI LLD to declare how many hardware queues it supports by setting Scsi_Host.nr_hw_queues before calling scsi_add_host().
--- drivers/scsi/scsi_lib.c | 2 +- include/scsi/scsi_host.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
drivers/scsi/scsi_lib.c +1 -1
@@ -2086,7 +2086,7 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)memset (&shost->tag_set,0 ,sizeof (shost->tag_set)); shost->tag_set.ops = &scsi_mq_ops; - shost->tag_set.nr_hw_queues =1 ; + shost->tag_set.nr_hw_queues = shost->nr_hw_queues ? :1 ; shost->tag_set.queue_depth = shost->can_queue; shost->tag_set.cmd_size = cmd_size; shost->tag_set.numa_node =NUMA_NO_NODE ;
include/scsi/scsi_host.h +8 -0
@@ -638,6 +638,14 @@ struct Scsi_Host {short unsigned int sg_prot_tablesize;unsigned int max_sectors;unsigned long dma_boundary; +/* +* In scsi-mq mode, the number of hardware queues supported by the LLD. +* +* Note: it is assumed that each hardware queue has a queue depth of +* can_queue. In other words, the total queue depth per host +* is nr_hw_queues * can_queue. +*/ +unsigned nr_hw_queues;/* * Used to assign serial numbers to the cmds. * Protected by the host lock.
Signature · 1 line
1.8.4.5
Bart Van Assche
maintainerPATCH v3 3/11 scsi_tcq.h: Add support for multiple hardware queues
In reply to Bart Van AsscheModify scsi_find_tag() and scsi_host_find_tag() such that these functions can translate a tag generated by blk_mq_unique_tag().
--- include/scsi/scsi_tcq.h | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
include/scsi/scsi_tcq.h +11 -8
@@ -111,18 +111,21 @@ static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg) }static inline struct scsi_cmnd *scsi_mq_find_tag (struct Scsi_Host *shost, -unsigned int hw_ctx,int tag) +int unique_tag) { -struct request *req; +u16 hwq =blk_mq_unique_tag_to_hwq (unique_tag); +struct request *req =NULL ; - req =blk_mq_tag_to_rq (shost->tag_set.tags[hw_ctx], tag); +if (hwq < shost->tag_set.nr_hw_queues) + req =blk_mq_tag_to_rq (shost->tag_set.tags[hwq], +blk_mq_unique_tag_to_tag (unique_tag));return req ? (struct scsi_cmnd *)req->special :NULL ; }/** * scsi_find_tag - find a tagged command by device * @SDpnt: pointer to the ScSI device -* @tag: the tag number +* @tag: tag generated by blk_mq_unique_tag() * * Notes: * Only works with tags allocated by the generic blk layer.
@@ -133,9 +136,9 @@ static inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag)if (tag !=SCSI_NO_TAG ) {if (shost_use_blk_mq (sdev->host)) -return scsi_mq_find_tag (sdev->host,0 , tag); +return scsi_mq_find_tag (sdev->host, tag); - req =blk_queue_find_tag (sdev->request_queue, tag); + req =blk_queue_find_tag (sdev->request_queue, tag);return req ? (struct scsi_cmnd *)req->special :NULL ; }
@@ -174,7 +177,7 @@ static inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth)/** * scsi_host_find_tag - find the tagged command by host * @shost: pointer to scsi_host -* @tag: tag of the scsi_cmnd +* @tag: tag generated by blk_mq_unique_tag() * * Notes: * Only works with tags allocated by the generic blk layer.
@@ -186,7 +189,7 @@ static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,if (tag !=SCSI_NO_TAG ) {if (shost_use_blk_mq (shost)) -return scsi_mq_find_tag (shost,0 , tag); +return scsi_mq_find_tag (shost, tag); req =blk_map_queue_find_tag (shost->bqt, tag);return req ? (struct scsi_cmnd *)req->special :NULL ; }
Signature · 1 line
1.8.4.5
Bart Van Assche
maintainerPATCH v3 4/11 IB/srp: Move ib_destroy_cm_id() call into srp_free_ch_ib()
In reply to Bart Van AsscheThe patch that adds multichannel support into the SRP initiator driver introduces an additional call to srp_free_ch_ib(). This patch helps to keep that later patch simple.
--- drivers/infiniband/ulp/srp/ib_srp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
drivers/infiniband/ulp/srp/ib_srp.c +6 -5
@@ -555,6 +555,11 @@ static void srp_free_target_ib(struct srp_target_port *target)struct srp_device *dev = target->srp_host->srp_dev;int i; +if (target->cm_id) { +ib_destroy_cm_id (target->cm_id); + target->cm_id =NULL ; + } +if (dev->use_fast_reg) {if (target->fr_pool)srp_destroy_fr_pool (target->fr_pool);
@@ -868,7 +873,6 @@ static void srp_remove_target(struct srp_target_port *target)scsi_remove_host (target->scsi_host);srp_stop_rport_timers (target->rport);srp_disconnect_target (target); -ib_destroy_cm_id (target->cm_id);srp_free_target_ib (target);cancel_work_sync (&target->tl_err_work);srp_rport_put (target->rport);
@@ -3043,7 +3047,7 @@ static ssize_t srp_create_target(struct device *dev,if (ret) {shost_printk (KERN_ERR , target->scsi_host,PFX "Connection failed\n" ); - goto err_cm_id; + goto err_free_ib; } ret =srp_add_target (host, target);
@@ -3067,9 +3071,6 @@ out: err_disconnect:srp_disconnect_target (target); -err_cm_id: -ib_destroy_cm_id (target->cm_id); - err_free_ib:srp_free_target_ib (target);
Signature · 1 line
1.8.4.5
Bart Van Assche
maintainerPATCH v3 5/11 IB/srp: Remove stale connection retry mechanism
In reply to Bart Van AsscheAttempting to connect three times may be insufficient after an initiator system tries to relogin, especially if the relogin attempt occurs before the SRP target service ID has been registered. Since the srp_daemon retries a failed login attempt anyway, remove the stale connection retry mechanism.
--- drivers/infiniband/ulp/srp/ib_srp.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-)
drivers/infiniband/ulp/srp/ib_srp.c +3 -13
@@ -904,7 +904,6 @@ static void srp_rport_delete(struct srp_rport *rport)static int srp_connect_target (struct srp_target_port *target) { -int retries =3 ;int ret;WARN_ON_ONCE (target->connected);
@@ -945,19 +944,10 @@ static int srp_connect_target(struct srp_target_port *target)break ;case SRP_STALE_CONN : -/* Our current CM id was stale, and is now in timewait. -* Try to reconnect with a new one. -*/ -if (!retries-- ||srp_new_cm_id (target)) { -shost_printk (KERN_ERR , target->scsi_host,PFX -"giving up on stale connection\n" ); - target->status = -ECONNRESET ; -return target->status; - } -shost_printk (KERN_ERR , target->scsi_host,PFX -"retrying stale connection\n" ); -break ; +"giving up on stale connection\n" ); + target->status = -ECONNRESET ; +return target->status;default :return target->status;
Signature · 1 line
1.8.4.5
Bart Van Assche
maintainerPATCH v3 6/11 IB/srp: Avoid that I/O hangs due to a cable pull during LUN scanning
In reply to Bart Van AsscheIf a cable is pulled during LUN scanning it can happen that the SRP rport and the SCSI host have been created but no LUNs have been added to the SCSI host. Since multipathd only sends SCSI commands to a SCSI target if one or more SCSI devices are present and since there is no keepalive mechanism for IB queue pairs this means that after a LUN scan failed and after a reconnect has succeeded no data will be sent over the QP and hence that a subsequent cable pull will not be detected. Avoid this by not creating an rport or SCSI host if a cable is pulled during a SCSI LUN scan.
Note: so far the above behavior has only been observed with the kernel module parameter ch_count set to a value >= 2.
--- drivers/infiniband/ulp/srp/ib_srp.c | 60 +++++++++++++++++++++++++++++++------ drivers/infiniband/ulp/srp/ib_srp.h | 1 + 2 files changed, 52 insertions(+), 9 deletions(-)
drivers/infiniband/ulp/srp/ib_srp.c +51 -9
@@ -1111,6 +1111,10 @@ static int srp_rport_reconnect(struct srp_rport *rport)int i, ret;srp_disconnect_target (target); + +if (target->state ==SRP_TARGET_SCANNING ) +return -ENODEV ; +/* * Now get a new local CM ID so that we avoid confusing the target in * case things are really fouled up. Doing so also ensures that all CM
@@ -2607,11 +2611,23 @@ static struct scsi_host_template srp_template = { .shost_attrs = srp_host_attrs }; +static int srp_sdev_count (struct Scsi_Host *host) +{ +struct scsi_device *sdev; +int c =0 ; + +shost_for_each_device (sdev, host) + c++; + +return c; +} +static int srp_add_target (struct srp_host *host,struct srp_target_port *target) {struct srp_rport_identifiers ids;struct srp_rport *rport; + target->state =SRP_TARGET_SCANNING ;sprintf (target->target_name,"SRP.T10:%016llX" , (unsigned long long )be64_to_cpu (target->id_ext));
@@ -2634,11 +2650,26 @@ static int srp_add_target(struct srp_host *host, struct srp_target_port *target)list_add_tail (&target->list, &host->target_list);spin_unlock (&host->target_lock); - target->state =SRP_TARGET_LIVE ; -scsi_scan_target (&target->scsi_host->shost_gendev,0 , target->scsi_id,SCAN_WILD_CARD ,0 ); +if (!target->connected || target->qp_in_error) { +shost_printk (KERN_INFO , target->scsi_host, +PFX "SCSI scan failed - removing SCSI host\n" ); +srp_queue_remove_work (target); + goto out; + } + +pr_debug (PFX "%s: SCSI scan succeeded - detected %d LUNs\n" , +dev_name (&target->scsi_host->shost_gendev), +srp_sdev_count (target->scsi_host)); + +spin_lock_irq (&target->lock); +if (target->state ==SRP_TARGET_SCANNING ) + target->state =SRP_TARGET_LIVE ; +spin_unlock_irq (&target->lock); + +out:return 0 ; }
@@ -2982,6 +3013,12 @@ static ssize_t srp_create_target(struct device *dev, target->tl_retry_count =7 ; target->queue_size =SRP_DEFAULT_QUEUE_SIZE ; +/* +* Avoid that the SCSI host can be removed by srp_remove_target() +* before this function returns. +*/ +scsi_host_get (target->scsi_host); +mutex_lock (&host->add_target_mutex); ret =srp_parse_options (buf, target);
@@ -3044,18 +3081,23 @@ static ssize_t srp_create_target(struct device *dev,if (ret) goto err_disconnect; -shost_printk (KERN_DEBUG , target->scsi_host,PFX -"new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n" , -be64_to_cpu (target->id_ext), -be64_to_cpu (target->ioc_guid), -be16_to_cpu (target->path.pkey), -be64_to_cpu (target->service_id), - target->path.sgid.raw, target->path.dgid.raw); +if (target->state !=SRP_TARGET_REMOVED ) { +shost_printk (KERN_DEBUG , target->scsi_host,PFX +"new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n" , +be64_to_cpu (target->id_ext), +be64_to_cpu (target->ioc_guid), +be16_to_cpu (target->path.pkey), +be64_to_cpu (target->service_id), + target->path.sgid.raw, target->orig_dgid); + } ret = count; out:mutex_unlock (&host->add_target_mutex); + +scsi_host_put (target->scsi_host); +return ret; err_disconnect:
drivers/infiniband/ulp/srp/ib_srp.h +1 -0
@@ -73,6 +73,7 @@ enum { };enum srp_target_state { +SRP_TARGET_SCANNING ,SRP_TARGET_LIVE ,SRP_TARGET_REMOVED , };
Signature · 1 line
1.8.4.5
A message that is not in the archive (sent off-list or not yet received): [email protected]
Sagi Grimberg
Reviewed-byRe: [PATCH v3 06/11] IB/srp: Avoid that I/O hangs due to a cable pull during LUN scanning
Quoted 139 lines · Bart Van Assche
If a cable is pulled during LUN scanning it can happen that the SRP rport and the SCSI host have been created but no LUNs have been added to the SCSI host. Since multipathd only sends SCSI commands to a SCSI target if one or more SCSI devices are present and since there is no keepalive mechanism for IB queue pairs this means that after a LUN scan failed and after a reconnect has succeeded no data will be sent over the QP and hence that a subsequent cable pull will not be detected. Avoid this by not creating an rport or SCSI host if a cable is pulled during a SCSI LUN scan.
Note: so far the above behavior has only been observed with the kernel module parameter
ch_countset to a value >= 2.Signed-off-by Bart Van Assche <[email protected]>Cc Sagi Grimberg <sagig-VPRAkNaXOzVWk0Htik3J/[email protected]>Cc Sebastian Parschauer <[email protected]>--- drivers/infiniband/ulp/srp/ib_srp.c | 60 +++++++++++++++++++++++++++++++------ drivers/infiniband/ulp/srp/ib_srp.h | 1 + 2 files changed, 52 insertions(+), 9 deletions(-)drivers/infiniband/ulp/srp/ib_srp.c +51
-9@@ -1111,6 +1111,10 @@ static int srp_rport_reconnect(struct srp_rport *rport)int i, ret;srp_disconnect_target (target); + +if (target->state ==SRP_TARGET_SCANNING ) +return -ENODEV ; +/* * Now get a new local CM ID so that we avoid confusing the target in * case things are really fouled up. Doing so also ensures that all CM @@ -2607,11 +2611,23 @@ static struct scsi_host_template srp_template = { .shost_attrs = srp_host_attrs }; +static int srp_sdev_count (struct Scsi_Host *host) +{ +struct scsi_device *sdev; +int c =0 ; + +shost_for_each_device (sdev, host) + c++; + +return c; +} +static int srp_add_target (struct srp_host *host,struct srp_target_port *target) {struct srp_rport_identifiers ids;struct srp_rport *rport; + target->state =SRP_TARGET_SCANNING ;sprintf (target->target_name,"SRP.T10:%016llX" , (unsigned long long )be64_to_cpu (target->id_ext));@@ -2634,11 +2650,26 @@ static int srp_add_target(struct srp_host *host, struct srp_target_port *target)list_add_tail (&target->list, &host->target_list);spin_unlock (&host->target_lock); - target->state =SRP_TARGET_LIVE ; -scsi_scan_target (&target->scsi_host->shost_gendev,0 , target->scsi_id,SCAN_WILD_CARD ,0 ); +if (!target->connected || target->qp_in_error) { +shost_printk (KERN_INFO , target->scsi_host, +PFX "SCSI scan failed - removing SCSI host\n" ); +srp_queue_remove_work (target); + goto out; + } + +pr_debug (PFX "%s: SCSI scan succeeded - detected %d LUNs\n" , +dev_name (&target->scsi_host->shost_gendev), +srp_sdev_count (target->scsi_host)); + +spin_lock_irq (&target->lock); +if (target->state ==SRP_TARGET_SCANNING ) + target->state =SRP_TARGET_LIVE ; +spin_unlock_irq (&target->lock); + +out:return 0 ; }@@ -2982,6 +3013,12 @@ static ssize_t srp_create_target(struct device *dev, target->tl_retry_count =7 ; target->queue_size =SRP_DEFAULT_QUEUE_SIZE ; +/* +* Avoid that the SCSI host can be removed by srp_remove_target() +* before this function returns. +*/ +scsi_host_get (target->scsi_host); +mutex_lock (&host->add_target_mutex); ret =srp_parse_options (buf, target);@@ -3044,18 +3081,23 @@ static ssize_t srp_create_target(struct device *dev,if (ret) goto err_disconnect; -shost_printk (KERN_DEBUG , target->scsi_host,PFX -"new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n" , -be64_to_cpu (target->id_ext), -be64_to_cpu (target->ioc_guid), -be16_to_cpu (target->path.pkey), -be64_to_cpu (target->service_id), - target->path.sgid.raw, target->path.dgid.raw); +if (target->state !=SRP_TARGET_REMOVED ) { +shost_printk (KERN_DEBUG , target->scsi_host,PFX +"new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n" , +be64_to_cpu (target->id_ext), +be64_to_cpu (target->ioc_guid), +be16_to_cpu (target->path.pkey), +be64_to_cpu (target->service_id), + target->path.sgid.raw, target->orig_dgid); + } ret = count; out:mutex_unlock (&host->add_target_mutex); + +scsi_host_put (target->scsi_host); +return ret; err_disconnect:drivers/infiniband/ulp/srp/ib_srp.h +0
-0
drivers/infiniband/ulp/srp/ib_srp.h enum { · line 79
Quoted 7 lines
drivers/infiniband/ulp/srp/ib_srp.h +1
-0@@ -73,6 +73,7 @@ enum { };enum srp_target_state { +SRP_TARGET_SCANNING ,SRP_TARGET_LIVE ,SRP_TARGET_REMOVED , };
This looks OK to me.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Bart Van Assche
maintainerPATCH v3 8/11 IB/srp: Separate target and channel variables
In reply to Bart Van AsscheChanges in this patch:
- Move channel variables into a new structure (struct srp_rdma_ch).
- Add an srp_target_port pointer, 'lock' and 'comp_vector' members in struct srp_rdma_ch.
- Add code to initialize these three new member variables.
- Many boring "target->" into "ch->" changes.
- The cm_id and completion handler context pointers are now of type srp_rdma_ch * instead of srp_target_port *.
- Three kzalloc(a * b, f) calls have been changed into kcalloc(a, b, f) to avoid that this patch would trigger a checkpatch warning.
- Two casts from u64 into unsigned long long have been left out because these are superfluous. Since considerable time u64 is defined as unsigned long long for all architectures supported by the Linux kernel.
--- drivers/infiniband/ulp/srp/ib_srp.c | 674 +++++++++++++++++++----------------- drivers/infiniband/ulp/srp/ib_srp.h | 64 ++-- 2 files changed, 403 insertions(+), 335 deletions(-)
drivers/infiniband/ulp/srp/ib_srp.c +361 -313
@@ -125,8 +125,8 @@ MODULE_PARM_DESC(dev_loss_tmo,static void srp_add_one (struct ib_device *device);static void srp_remove_one (struct ib_device *device); -static void srp_recv_completion (struct ib_cq *cq,void *target_ptr); -static void srp_send_completion (struct ib_cq *cq,void *target_ptr); +static void srp_recv_completion (struct ib_cq *cq,void *ch_ptr); +static void srp_send_completion (struct ib_cq *cq,void *ch_ptr);static int srp_cm_handler (struct ib_cm_id *cm_id,struct ib_cm_event *event);static struct scsi_transport_template *ib_srp_transport_template;
@@ -283,22 +283,23 @@ out:return ret; } -static int srp_new_cm_id (struct srp_target_port *target) +static int srp_new_cm_id (struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;struct ib_cm_id *new_cm_id; new_cm_id =ib_create_cm_id (target->srp_host->srp_dev->dev, - srp_cm_handler, target); + srp_cm_handler, ch);if (IS_ERR (new_cm_id))return PTR_ERR (new_cm_id); -if (target->cm_id) -ib_destroy_cm_id (target->cm_id); - target->cm_id = new_cm_id; - target->path.sgid = target->sgid; - target->path.dgid = target->orig_dgid; - target->path.pkey = target->pkey; - target->path.service_id = target->service_id; +if (ch->cm_id) +ib_destroy_cm_id (ch->cm_id); + ch->cm_id = new_cm_id; + ch->path.sgid = target->sgid; + ch->path.dgid = target->orig_dgid; + ch->path.pkey = target->pkey; + ch->path.service_id = target->service_id;return 0 ; }
@@ -447,8 +448,9 @@ static struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target) dev->max_pages_per_mr); } -static int srp_create_target_ib (struct srp_target_port *target) +static int srp_create_ch_ib (struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;struct srp_device *dev = target->srp_host->srp_dev;struct ib_qp_init_attr *init_attr;struct ib_cq *recv_cq, *send_cq;
@@ -462,15 +464,15 @@ static int srp_create_target_ib(struct srp_target_port *target)if (!init_attr)return -ENOMEM ; - recv_cq =ib_create_cq (dev->dev, srp_recv_completion,NULL , target, - target->queue_size, target->comp_vector); + recv_cq =ib_create_cq (dev->dev, srp_recv_completion,NULL , ch, + target->queue_size, ch->comp_vector);if (IS_ERR (recv_cq)) { ret =PTR_ERR (recv_cq); goto err; } - send_cq =ib_create_cq (dev->dev, srp_send_completion,NULL , target, - m * target->queue_size, target->comp_vector); + send_cq =ib_create_cq (dev->dev, srp_send_completion,NULL , ch, + m * target->queue_size, ch->comp_vector);if (IS_ERR (send_cq)) { ret =PTR_ERR (send_cq); goto err_recv_cq;
@@ -506,9 +508,9 @@ static int srp_create_target_ib(struct srp_target_port *target) "FR pool allocation failed (%d)\n", ret); goto err_qp; } -if (target->fr_pool) -srp_destroy_fr_pool (target->fr_pool); - target->fr_pool = fr_pool; +if (ch->fr_pool) +srp_destroy_fr_pool (ch->fr_pool); + ch->fr_pool = fr_pool; }else if (!dev->use_fast_reg && dev->has_fmr) { fmr_pool =srp_alloc_fmr_pool (target);if (IS_ERR (fmr_pool)) {
@@ -517,21 +519,21 @@ static int srp_create_target_ib(struct srp_target_port *target) "FMR pool allocation failed (%d)\n", ret); goto err_qp; } -if (target->fmr_pool) -ib_destroy_fmr_pool (target->fmr_pool); - target->fmr_pool = fmr_pool; +if (ch->fmr_pool) +ib_destroy_fmr_pool (ch->fmr_pool); + ch->fmr_pool = fmr_pool; } -if (target->qp) -ib_destroy_qp (target->qp); -if (target->recv_cq) -ib_destroy_cq (target->recv_cq); -if (target->send_cq) -ib_destroy_cq (target->send_cq); +if (ch->qp) +ib_destroy_qp (ch->qp); +if (ch->recv_cq) +ib_destroy_cq (ch->recv_cq); +if (ch->send_cq) +ib_destroy_cq (ch->send_cq); - target->qp = qp; - target->recv_cq = recv_cq; - target->send_cq = send_cq; + ch->qp = qp; + ch->recv_cq = recv_cq; + ch->send_cq = send_cq;kfree (init_attr);return 0 ;
@@ -552,98 +554,102 @@ err:/* * Note: this function may be called without srp_alloc_iu_bufs() having been -* invoked. Hence the target->[rt]x_ring checks. +* invoked. Hence the ch->[rt]x_ring checks. */ -static void srp_free_target_ib (struct srp_target_port *target) +static void srp_free_ch_ib (struct srp_target_port *target, +struct srp_rdma_ch *ch) {struct srp_device *dev = target->srp_host->srp_dev;int i; -if (target->cm_id) { -ib_destroy_cm_id (target->cm_id); - target->cm_id =NULL ; +if (ch->cm_id) { +ib_destroy_cm_id (ch->cm_id); + ch->cm_id =NULL ; }if (dev->use_fast_reg) { -if (target->fr_pool) -srp_destroy_fr_pool (target->fr_pool); +if (ch->fr_pool) +srp_destroy_fr_pool (ch->fr_pool); }else { -if (target->fmr_pool) -ib_destroy_fmr_pool (target->fmr_pool); +if (ch->fmr_pool) +ib_destroy_fmr_pool (ch->fmr_pool); } -ib_destroy_qp (target->qp); -ib_destroy_cq (target->send_cq); -ib_destroy_cq (target->recv_cq); +ib_destroy_qp (ch->qp); +ib_destroy_cq (ch->send_cq); +ib_destroy_cq (ch->recv_cq); - target->qp =NULL ; - target->send_cq = target->recv_cq =NULL ; + ch->qp =NULL ; + ch->send_cq = ch->recv_cq =NULL ; -if (target->rx_ring) { +if (ch->rx_ring) {for (i =0 ; i < target->queue_size; ++i) -srp_free_iu (target->srp_host, target->rx_ring[i]); -kfree (target->rx_ring); - target->rx_ring =NULL ; +srp_free_iu (target->srp_host, ch->rx_ring[i]); +kfree (ch->rx_ring); + ch->rx_ring =NULL ; } -if (target->tx_ring) { +if (ch->tx_ring) {for (i =0 ; i < target->queue_size; ++i) -srp_free_iu (target->srp_host, target->tx_ring[i]); -kfree (target->tx_ring); - target->tx_ring =NULL ; +srp_free_iu (target->srp_host, ch->tx_ring[i]); +kfree (ch->tx_ring); + ch->tx_ring =NULL ; } }static void srp_path_rec_completion (int status,struct ib_sa_path_rec *pathrec, -void *target_ptr) +void *ch_ptr) { -struct srp_target_port *target = target_ptr; +struct srp_rdma_ch *ch = ch_ptr; +struct srp_target_port *target = ch->target; - target->status = status; + ch->status = status;if (status)shost_printk (KERN_ERR , target->scsi_host,PFX "Got failed path rec status %d\n" , status);else - target->path = *pathrec; -complete (&target->done); + ch->path = *pathrec; +complete (&ch->done); } -static int srp_lookup_path (struct srp_target_port *target) +static int srp_lookup_path (struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;int ret; - target->path.numb_path =1 ; - -init_completion (&target->done); - - target->path_query_id =ib_sa_path_rec_get (&srp_sa_client, - target->srp_host->srp_dev->dev, - target->srp_host->port, - &target->path, -IB_SA_PATH_REC_SERVICE_ID | -IB_SA_PATH_REC_DGID | -IB_SA_PATH_REC_SGID | -IB_SA_PATH_REC_NUMB_PATH | -IB_SA_PATH_REC_PKEY , -SRP_PATH_REC_TIMEOUT_MS , -GFP_KERNEL , - srp_path_rec_completion, - target, &target->path_query); -if (target->path_query_id <0 ) -return target->path_query_id; - - ret =wait_for_completion_interruptible (&target->done); + ch->path.numb_path =1 ; + +init_completion (&ch->done); + + ch->path_query_id =ib_sa_path_rec_get (&srp_sa_client, + target->srp_host->srp_dev->dev, + target->srp_host->port, + &ch->path, +IB_SA_PATH_REC_SERVICE_ID | +IB_SA_PATH_REC_DGID | +IB_SA_PATH_REC_SGID | +IB_SA_PATH_REC_NUMB_PATH | +IB_SA_PATH_REC_PKEY , +SRP_PATH_REC_TIMEOUT_MS , +GFP_KERNEL , + srp_path_rec_completion, + ch, &ch->path_query); +if (ch->path_query_id <0 ) +return ch->path_query_id; + + ret =wait_for_completion_interruptible (&ch->done);if (ret <0 )return ret; -if (target->status <0 ) +if (ch->status <0 )shost_printk (KERN_WARNING , target->scsi_host,PFX "Path record query failed\n" ); -return target->status; +return ch->status; } -static int srp_send_req (struct srp_target_port *target) +static int srp_send_req (struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;struct {struct ib_cm_req_param param;struct srp_login_req priv;
@@ -654,11 +660,11 @@ static int srp_send_req(struct srp_target_port *target)if (!req)return -ENOMEM ; - req->param.primary_path = &target->path; + req->param.primary_path = &ch->path; req->param.alternate_path =NULL ; req->param.service_id = target->service_id; - req->param.qp_num = target->qp->qp_num; - req->param.qp_type = target->qp->qp_type; + req->param.qp_num = ch->qp->qp_num; + req->param.qp_type = ch->qp->qp_type; req->param.private_data = &req->priv; req->param.private_data_len =sizeof req->priv; req->param.flow_control =1 ;
@@ -722,7 +728,7 @@ static int srp_send_req(struct srp_target_port *target) &target->srp_host->srp_dev->dev->node_guid, 8); } - status =ib_send_cm_req (target->cm_id, &req->param); + status =ib_send_cm_req (ch->cm_id, &req->param);kfree (req);
@@ -763,28 +769,31 @@ static bool srp_change_conn_state(struct srp_target_port *target,static void srp_disconnect_target (struct srp_target_port *target) { +struct srp_rdma_ch *ch = &target->ch; +if (srp_change_conn_state (target, false)) {/* XXX should send SRP_I_LOGOUT request */ -if (ib_send_cm_dreq (target->cm_id,NULL ,0 )) { +if (ib_send_cm_dreq (ch->cm_id,NULL ,0 )) {shost_printk (KERN_DEBUG , target->scsi_host,PFX "Sending CM DREQ failed\n" ); } } } -static void srp_free_req_data (struct srp_target_port *target) +static void srp_free_req_data (struct srp_target_port *target, +struct srp_rdma_ch *ch) {struct srp_device *dev = target->srp_host->srp_dev;struct ib_device *ibdev = dev->dev;struct srp_request *req;int i; -if (!target->req_ring) +if (!ch->req_ring)return ;for (i =0 ; i < target->req_ring_size; ++i) { - req = &target->req_ring[i]; + req = &ch->req_ring[i];if (dev->use_fast_reg)kfree (req->fr_list);else
@@ -798,12 +807,13 @@ static void srp_free_req_data(struct srp_target_port *target)kfree (req->indirect_desc); } -kfree (target->req_ring); - target->req_ring =NULL ; +kfree (ch->req_ring); + ch->req_ring =NULL ; } -static int srp_alloc_req_data (struct srp_target_port *target) +static int srp_alloc_req_data (struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;struct srp_device *srp_dev = target->srp_host->srp_dev;struct ib_device *ibdev = srp_dev->dev;struct srp_request *req;
@@ -811,15 +821,15 @@ static int srp_alloc_req_data(struct srp_target_port *target)dma_addr_t dma_addr;int i, ret = -ENOMEM ; -INIT_LIST_HEAD (&target->free_reqs); +INIT_LIST_HEAD (&ch->free_reqs); - target->req_ring =kzalloc (target->req_ring_size * -sizeof (*target->req_ring),GFP_KERNEL ); -if (!target->req_ring) + ch->req_ring =kcalloc (target->req_ring_size,sizeof (*ch->req_ring), +GFP_KERNEL ); +if (!ch->req_ring) goto out;for (i =0 ; i < target->req_ring_size; ++i) { - req = &target->req_ring[i]; + req = &ch->req_ring[i]; mr_list =kmalloc (target->cmd_sg_cnt *sizeof (void *),GFP_KERNEL );if (!mr_list)
@@ -844,7 +854,7 @@ static int srp_alloc_req_data(struct srp_target_port *target) req->indirect_dma_addr = dma_addr; req->index = i; -list_add_tail (&req->list, &target->free_reqs); +list_add_tail (&req->list, &ch->free_reqs); } ret =0 ;
@@ -869,6 +879,8 @@ static void srp_del_scsi_host_attr(struct Scsi_Host *shost)static void srp_remove_target (struct srp_target_port *target) { +struct srp_rdma_ch *ch = &target->ch; +WARN_ON_ONCE (target->state !=SRP_TARGET_REMOVED );srp_del_scsi_host_attr (target->scsi_host);
@@ -877,10 +889,10 @@ static void srp_remove_target(struct srp_target_port *target)scsi_remove_host (target->scsi_host);srp_stop_rport_timers (target->rport);srp_disconnect_target (target); -srp_free_target_ib (target); +srp_free_ch_ib (target, ch);cancel_work_sync (&target->tl_err_work);srp_rport_put (target->rport); -srp_free_req_data (target); +srp_free_req_data (target, ch);spin_lock (&target->srp_host->target_lock);list_del (&target->list);
@@ -906,24 +918,25 @@ static void srp_rport_delete(struct srp_rport *rport)srp_queue_remove_work (target); } -static int srp_connect_target (struct srp_target_port *target) +static int srp_connect_ch (struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;int ret;WARN_ON_ONCE (target->connected); target->qp_in_error = false; - ret =srp_lookup_path (target); + ret =srp_lookup_path (ch);if (ret)return ret;while (1 ) { -init_completion (&target->done); - ret =srp_send_req (target); +init_completion (&ch->done); + ret =srp_send_req (ch);if (ret)return ret; - ret =wait_for_completion_interruptible (&target->done); + ret =wait_for_completion_interruptible (&ch->done);if (ret <0 )return ret;
@@ -933,13 +946,13 @@ static int srp_connect_target(struct srp_target_port *target)* back, or SRP_DLID_REDIRECT if we get a lid/qp * redirect REJ back. */ -switch (target->status) { +switch (ch->status) {case 0 :srp_change_conn_state (target, true);return 0 ;case SRP_PORT_REDIRECT : - ret =srp_lookup_path (target); + ret =srp_lookup_path (ch);if (ret)return ret;break ;
@@ -950,16 +963,16 @@ static int srp_connect_target(struct srp_target_port *target)case SRP_STALE_CONN :shost_printk (KERN_ERR , target->scsi_host,PFX "giving up on stale connection\n" ); - target->status = -ECONNRESET ; -return target->status; + ch->status = -ECONNRESET ; +return ch->status;default : -return target->status; +return ch->status; } } } -static int srp_inv_rkey (struct srp_target_port *target,u32 rkey) +static int srp_inv_rkey (struct srp_rdma_ch *ch,u32 rkey) {struct ib_send_wr *bad_wr;struct ib_send_wr wr = {
@@ -971,13 +984,14 @@ static int srp_inv_rkey(struct srp_target_port *target, u32 rkey) .ex.invalidate_rkey = rkey, }; -return ib_post_send (target->qp, &wr, &bad_wr); +return ib_post_send (ch->qp, &wr, &bad_wr); }static void srp_unmap_data (struct scsi_cmnd *scmnd, -struct srp_target_port *target, +struct srp_rdma_ch *ch,struct srp_request *req) { +struct srp_target_port *target = ch->target;struct srp_device *dev = target->srp_host->srp_dev;struct ib_device *ibdev = dev->dev;int i, res;
@@ -991,7 +1005,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,struct srp_fr_desc **pfr;for (i = req->nmdesc, pfr = req->fr_list; i >0 ; i--, pfr++) { - res =srp_inv_rkey (target, (*pfr)->mr->rkey); + res =srp_inv_rkey (ch, (*pfr)->mr->rkey);if (res <0 ) { shost_printk(KERN_ERR, target->scsi_host, PFX "Queueing INV WR for rkey %#x failed (%d)\n",
@@ -1001,7 +1015,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, } }if (req->nmdesc) -srp_fr_pool_put (target->fr_pool, req->fr_list, +srp_fr_pool_put (ch->fr_pool, req->fr_list, req->nmdesc); }else {struct ib_pool_fmr **pfmr;
@@ -1016,7 +1030,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,/** * srp_claim_req - Take ownership of the scmnd associated with a request. -* @target: SRP target port. +* @ch: SRP RDMA channel. * @req: SRP request. * @sdev: If not NULL, only take ownership for this SCSI device. * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take
@@ -1025,14 +1039,14 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,* Return value: * Either NULL or a pointer to the SCSI command the caller became owner of. */ -static struct scsi_cmnd *srp_claim_req (struct srp_target_port *target, +static struct scsi_cmnd *srp_claim_req (struct srp_rdma_ch *ch,struct srp_request *req,struct scsi_device *sdev,struct scsi_cmnd *scmnd) {unsigned long flags; -spin_lock_irqsave (&target->lock, flags); +spin_lock_irqsave (&ch->lock, flags);if (req->scmnd && (!sdev || req->scmnd->device == sdev) && (!scmnd || req->scmnd == scmnd)) {
@@ -1041,40 +1055,38 @@ static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target, }else { scmnd =NULL ; } -spin_unlock_irqrestore (&target->lock, flags); +spin_unlock_irqrestore (&ch->lock, flags);return scmnd; }/** * srp_free_req() - Unmap data and add request to the free request list. -* @target: SRP target port. +* @ch: SRP RDMA channel. * @req: Request to be freed. * @scmnd: SCSI command associated with @req. * @req_lim_delta: Amount to be added to @target->req_lim. */ -static void srp_free_req (struct srp_target_port *target, -struct srp_request *req,struct scsi_cmnd *scmnd, -s32 req_lim_delta) +static void srp_free_req (struct srp_rdma_ch *ch,struct srp_request *req, +struct scsi_cmnd *scmnd,s32 req_lim_delta) {unsigned long flags; -srp_unmap_data (scmnd, target, req); +srp_unmap_data (scmnd, ch, req); -spin_lock_irqsave (&target->lock, flags); - target->req_lim += req_lim_delta; -list_add_tail (&req->list, &target->free_reqs); -spin_unlock_irqrestore (&target->lock, flags); +spin_lock_irqsave (&ch->lock, flags); + ch->req_lim += req_lim_delta; +list_add_tail (&req->list, &ch->free_reqs); +spin_unlock_irqrestore (&ch->lock, flags); } -static void srp_finish_req (struct srp_target_port *target, -struct srp_request *req,struct scsi_device *sdev, -int result) +static void srp_finish_req (struct srp_rdma_ch *ch,struct srp_request *req, +struct scsi_device *sdev,int result) { -struct scsi_cmnd *scmnd =srp_claim_req (target, req, sdev,NULL ); +struct scsi_cmnd *scmnd =srp_claim_req (ch, req, sdev,NULL );if (scmnd) { -srp_free_req (target, req, scmnd,0 ); +srp_free_req (ch, req, scmnd,0 ); scmnd->result = result; scmnd->scsi_done (scmnd); }
@@ -1083,6 +1095,7 @@ static void srp_finish_req(struct srp_target_port *target,static void srp_terminate_io (struct srp_rport *rport) {struct srp_target_port *target = rport->lld_data; +struct srp_rdma_ch *ch = &target->ch;struct Scsi_Host *shost = target->scsi_host;struct scsi_device *sdev;int i;
@@ -1095,8 +1108,9 @@ static void srp_terminate_io(struct srp_rport *rport)WARN_ON_ONCE (sdev->request_queue->request_fn_active);for (i =0 ; i < target->req_ring_size; ++i) { -struct srp_request *req = &target->req_ring[i]; -srp_finish_req (target, req,NULL ,DID_TRANSPORT_FAILFAST <<16 ); +struct srp_request *req = &ch->req_ring[i]; + +srp_finish_req (ch, req,NULL ,DID_TRANSPORT_FAILFAST <<16 ); } }
@@ -1112,6 +1126,7 @@ static void srp_terminate_io(struct srp_rport *rport)static int srp_rport_reconnect (struct srp_rport *rport) {struct srp_target_port *target = rport->lld_data; +struct srp_rdma_ch *ch = &target->ch;int i, ret;srp_disconnect_target (target);
@@ -1124,11 +1139,12 @@ static int srp_rport_reconnect(struct srp_rport *rport)* case things are really fouled up. Doing so also ensures that all CM * callbacks will have finished before a new QP is allocated. */ - ret =srp_new_cm_id (target); + ret =srp_new_cm_id (ch);for (i =0 ; i < target->req_ring_size; ++i) { -struct srp_request *req = &target->req_ring[i]; -srp_finish_req (target, req,NULL ,DID_RESET <<16 ); +struct srp_request *req = &ch->req_ring[i]; + +srp_finish_req (ch, req,NULL ,DID_RESET <<16 ); }/*
@@ -1136,14 +1152,14 @@ static int srp_rport_reconnect(struct srp_rport *rport)* QP. This guarantees that all callback functions for the old QP have * finished before any send requests are posted on the new QP. */ - ret +=srp_create_target_ib (target); + ret +=srp_create_ch_ib (ch); -INIT_LIST_HEAD (&target->free_tx); +INIT_LIST_HEAD (&ch->free_tx);for (i =0 ; i < target->queue_size; ++i) -list_add (&target->tx_ring[i]->list, &target->free_tx); +list_add (&ch->tx_ring[i]->list, &ch->free_tx);if (ret ==0 ) - ret =srp_connect_target (target); + ret =srp_connect_ch (ch);if (ret ==0 ) shost_printk(KERN_INFO, target->scsi_host,
@@ -1167,12 +1183,12 @@ static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr, }static int srp_map_finish_fmr (struct srp_map_state *state, -struct srp_target_port *target) +struct srp_rdma_ch *ch) {struct ib_pool_fmr *fmr;u64 io_addr =0 ; - fmr =ib_fmr_pool_map_phys (target->fmr_pool, state->pages, + fmr =ib_fmr_pool_map_phys (ch->fmr_pool, state->pages, state->npages, io_addr);if (IS_ERR (fmr))return PTR_ERR (fmr);
@@ -1186,15 +1202,16 @@ static int srp_map_finish_fmr(struct srp_map_state *state, }static int srp_map_finish_fr (struct srp_map_state *state, -struct srp_target_port *target) +struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;struct srp_device *dev = target->srp_host->srp_dev;struct ib_send_wr *bad_wr;struct ib_send_wr wr;struct srp_fr_desc *desc;u32 rkey; - desc =srp_fr_pool_get (target->fr_pool); + desc =srp_fr_pool_get (ch->fr_pool);if (!desc)return -ENOMEM ;
@@ -1223,12 +1240,13 @@ static int srp_map_finish_fr(struct srp_map_state *state,srp_map_desc (state, state->base_dma_addr, state->dma_len, desc->mr->rkey); -return ib_post_send (target->qp, &wr, &bad_wr); +return ib_post_send (ch->qp, &wr, &bad_wr); }static int srp_finish_mapping (struct srp_map_state *state, -struct srp_target_port *target) +struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;int ret =0 ;if (state->npages ==0 )
@@ -1239,8 +1257,8 @@ static int srp_finish_mapping(struct srp_map_state *state, target->rkey); else ret = target->srp_host->srp_dev->use_fast_reg ? -srp_map_finish_fr (state, target) : -srp_map_finish_fmr (state, target); +srp_map_finish_fr (state, ch) : +srp_map_finish_fmr (state, ch);if (ret ==0 ) { state->npages =0 ;
@@ -1260,10 +1278,11 @@ static void srp_map_update_start(struct srp_map_state *state, }static int srp_map_sg_entry (struct srp_map_state *state, -struct srp_target_port *target, +struct srp_rdma_ch *ch,struct scatterlist *sg,int sg_index,bool use_mr) { +struct srp_target_port *target = ch->target;struct srp_device *dev = target->srp_host->srp_dev;struct ib_device *ibdev = dev->dev;dma_addr_t dma_addr =ib_sg_dma_address (ibdev, sg);
@@ -1292,7 +1311,7 @@ static int srp_map_sg_entry(struct srp_map_state *state,*/ if ((!dev->use_fast_reg && dma_addr & ~dev->mr_page_mask) || dma_len > dev->mr_max_size) { - ret =srp_finish_mapping (state, target); + ret =srp_finish_mapping (state, ch);if (ret)return ret;
@@ -1313,7 +1332,7 @@ static int srp_map_sg_entry(struct srp_map_state *state,while (dma_len) {unsigned offset = dma_addr & ~dev->mr_page_mask;if (state->npages == dev->max_pages_per_mr || offset !=0 ) { - ret =srp_finish_mapping (state, target); + ret =srp_finish_mapping (state, ch);if (ret)return ret;
@@ -1337,17 +1356,18 @@ static int srp_map_sg_entry(struct srp_map_state *state,*/ ret =0 ;if (len != dev->mr_page_size) { - ret =srp_finish_mapping (state, target); + ret =srp_finish_mapping (state, ch);if (!ret)srp_map_update_start (state,NULL ,0 ,0 ); }return ret; } -static int srp_map_sg (struct srp_map_state *state, -struct srp_target_port *target,struct srp_request *req, -struct scatterlist *scat,int count) +static int srp_map_sg (struct srp_map_state *state,struct srp_rdma_ch *ch, +struct srp_request *req,struct scatterlist *scat, +int count) { +struct srp_target_port *target = ch->target;struct srp_device *dev = target->srp_host->srp_dev;struct ib_device *ibdev = dev->dev;struct scatterlist *sg;
@@ -1358,14 +1378,14 @@ static int srp_map_sg(struct srp_map_state *state, state->pages = req->map_page;if (dev->use_fast_reg) { state->next_fr = req->fr_list; - use_mr = !!target->fr_pool; + use_mr = !!ch->fr_pool; }else { state->next_fmr = req->fmr_list; - use_mr = !!target->fmr_pool; + use_mr = !!ch->fmr_pool; }for_each_sg (scat, sg, count, i) { -if (srp_map_sg_entry (state, target, sg, i, use_mr)) { +if (srp_map_sg_entry (state, ch, sg, i, use_mr)) {/* * Memory registration failed, so backtrack to the * first unmapped entry and continue on without using
@@ -1387,7 +1407,7 @@ backtrack: } } -if (use_mr &&srp_finish_mapping (state, target)) +if (use_mr &&srp_finish_mapping (state, ch)) goto backtrack; req->nmdesc = state->nmdesc;
@@ -1395,9 +1415,10 @@ backtrack:return 0 ; } -static int srp_map_data (struct scsi_cmnd *scmnd,struct srp_target_port *target, +static int srp_map_data (struct scsi_cmnd *scmnd,struct srp_rdma_ch *ch,struct srp_request *req) { +struct srp_target_port *target = ch->target;struct scatterlist *scat;struct srp_cmd *cmd = req->cmd->buf;int len, nents, count;
@@ -1459,7 +1480,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, target->indirect_size, DMA_TO_DEVICE);memset (&state,0 ,sizeof (state)); -srp_map_sg (&state, target, req, scat, count); +srp_map_sg (&state, ch, req, scat, count);/* We've mapped the request, now pull as much of the indirect * descriptor table as we can into the command buffer. If this
@@ -1520,20 +1541,20 @@ map_complete:/* * Return an IU and possible credit to the free pool */ -static void srp_put_tx_iu (struct srp_target_port *target,struct srp_iu *iu, +static void srp_put_tx_iu (struct srp_rdma_ch *ch,struct srp_iu *iu,enum srp_iu_type iu_type) {unsigned long flags; -spin_lock_irqsave (&target->lock, flags); -list_add (&iu->list, &target->free_tx); +spin_lock_irqsave (&ch->lock, flags); +list_add (&iu->list, &ch->free_tx);if (iu_type !=SRP_IU_RSP ) - ++target->req_lim; -spin_unlock_irqrestore (&target->lock, flags); + ++ch->req_lim; +spin_unlock_irqrestore (&ch->lock, flags); }/* -* Must be called with target->lock held to protect req_lim and free_tx. +* Must be called with ch->lock held to protect req_lim and free_tx. * If IU is not sent, it must be returned using srp_put_tx_iu(). * * Note:
@@ -1545,35 +1566,36 @@ static void srp_put_tx_iu(struct srp_target_port *target, struct srp_iu *iu,* - SRP_IU_RSP: 1, since a conforming SRP target never sends more than * one unanswered SRP request to an initiator. */ -static struct srp_iu *__srp_get_tx_iu (struct srp_target_port *target, +static struct srp_iu *__srp_get_tx_iu (struct srp_rdma_ch *ch,enum srp_iu_type iu_type) { +struct srp_target_port *target = ch->target;s32 rsv = (iu_type ==SRP_IU_TSK_MGMT ) ?0 :SRP_TSK_MGMT_SQ_SIZE ;struct srp_iu *iu; -srp_send_completion (target->send_cq, target); +srp_send_completion (ch->send_cq, ch); -if (list_empty (&target->free_tx)) +if (list_empty (&ch->free_tx))return NULL ;/* Initiator responses to target requests do not consume credits */ if (iu_type !=SRP_IU_RSP ) { -if (target->req_lim <= rsv) { +if (ch->req_lim <= rsv) { ++target->zero_req_lim;return NULL ; } - --target->req_lim; + --ch->req_lim; } - iu = list_first_entry(&target->free_tx, struct srp_iu, list); + iu = list_first_entry(&ch->free_tx, struct srp_iu, list);list_del (&iu->list);return iu; } -static int srp_post_send (struct srp_target_port *target, -struct srp_iu *iu,int len) +static int srp_post_send (struct srp_rdma_ch *ch,struct srp_iu *iu,int len) { +struct srp_target_port *target = ch->target;struct ib_sge list;struct ib_send_wr wr, *bad_wr;
@@ -1588,11 +1610,12 @@ static int srp_post_send(struct srp_target_port *target, wr.opcode =IB_WR_SEND ; wr.send_flags =IB_SEND_SIGNALED ; -return ib_post_send (target->qp, &wr, &bad_wr); +return ib_post_send (ch->qp, &wr, &bad_wr); } -static int srp_post_recv (struct srp_target_port *target,struct srp_iu *iu) +static int srp_post_recv (struct srp_rdma_ch *ch,struct srp_iu *iu) { +struct srp_target_port *target = ch->target;struct ib_recv_wr wr, *bad_wr;struct ib_sge list;
@@ -1605,35 +1628,36 @@ static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu) wr.sg_list = &list; wr.num_sge =1 ; -return ib_post_recv (target->qp, &wr, &bad_wr); +return ib_post_recv (ch->qp, &wr, &bad_wr); } -static void srp_process_rsp (struct srp_target_port *target,struct srp_rsp *rsp) +static void srp_process_rsp (struct srp_rdma_ch *ch,struct srp_rsp *rsp) { +struct srp_target_port *target = ch->target;struct srp_request *req;struct scsi_cmnd *scmnd;unsigned long flags;if (unlikely (rsp->tag &SRP_TAG_TSK_MGMT )) { -spin_lock_irqsave (&target->lock, flags); - target->req_lim +=be32_to_cpu (rsp->req_lim_delta); -spin_unlock_irqrestore (&target->lock, flags); +spin_lock_irqsave (&ch->lock, flags); + ch->req_lim +=be32_to_cpu (rsp->req_lim_delta); +spin_unlock_irqrestore (&ch->lock, flags); - target->tsk_mgmt_status =-1 ; + ch->tsk_mgmt_status =-1 ;if (be32_to_cpu (rsp->resp_data_len) >=4 ) - target->tsk_mgmt_status = rsp->data[3 ]; -complete (&target->tsk_mgmt_done); + ch->tsk_mgmt_status = rsp->data[3 ]; +complete (&ch->tsk_mgmt_done); }else { - req = &target->req_ring[rsp->tag]; - scmnd =srp_claim_req (target, req,NULL ,NULL ); + req = &ch->req_ring[rsp->tag]; + scmnd =srp_claim_req (ch, req,NULL ,NULL );if (!scmnd) {shost_printk (KERN_ERR , target->scsi_host,"Null scmnd for RSP w/tag %016llx\n" , (unsigned long long ) rsp->tag); -spin_lock_irqsave (&target->lock, flags); - target->req_lim +=be32_to_cpu (rsp->req_lim_delta); -spin_unlock_irqrestore (&target->lock, flags); +spin_lock_irqsave (&ch->lock, flags); + ch->req_lim +=be32_to_cpu (rsp->req_lim_delta); +spin_unlock_irqrestore (&ch->lock, flags);return ; }
@@ -1655,7 +1679,7 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)else if (unlikely (rsp->flags &SRP_RSP_FLAG_DOOVER ))scsi_set_resid (scmnd, -be32_to_cpu (rsp->data_out_res_cnt)); -srp_free_req (target, req, scmnd, +srp_free_req (ch, req, scmnd,be32_to_cpu (rsp->req_lim_delta)); scmnd->host_scribble =NULL ;
@@ -1663,18 +1687,19 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) } } -static int srp_response_common (struct srp_target_port *target,s32 req_delta, +static int srp_response_common (struct srp_rdma_ch *ch,s32 req_delta,void *rsp,int len) { +struct srp_target_port *target = ch->target;struct ib_device *dev = target->srp_host->srp_dev->dev;unsigned long flags;struct srp_iu *iu;int err; -spin_lock_irqsave (&target->lock, flags); - target->req_lim += req_delta; - iu =__srp_get_tx_iu (target,SRP_IU_RSP ); -spin_unlock_irqrestore (&target->lock, flags); +spin_lock_irqsave (&ch->lock, flags); + ch->req_lim += req_delta; + iu =__srp_get_tx_iu (ch,SRP_IU_RSP ); +spin_unlock_irqrestore (&ch->lock, flags);if (!iu) { shost_printk(KERN_ERR, target->scsi_host, PFX
@@ -1686,17 +1711,17 @@ static int srp_response_common(struct srp_target_port *target, s32 req_delta,memcpy (iu->buf, rsp, len);ib_dma_sync_single_for_device (dev, iu->dma, len,DMA_TO_DEVICE ); - err =srp_post_send (target, iu, len); + err =srp_post_send (ch, iu, len);if (err) {shost_printk (KERN_ERR , target->scsi_host,PFX "unable to post response: %d\n" , err); -srp_put_tx_iu (target, iu,SRP_IU_RSP ); +srp_put_tx_iu (ch, iu,SRP_IU_RSP ); }return err; } -static void srp_process_cred_req (struct srp_target_port *target, +static void srp_process_cred_req (struct srp_rdma_ch *ch,struct srp_cred_req *req) {struct srp_cred_rsp rsp = {
@@ -1705,14 +1730,15 @@ static void srp_process_cred_req(struct srp_target_port *target, };s32 delta =be32_to_cpu (req->req_lim_delta); -if (srp_response_common (target, delta, &rsp,sizeof rsp)) -shost_printk (KERN_ERR , target->scsi_host,PFX +if (srp_response_common (ch, delta, &rsp,sizeof (rsp))) +shost_printk (KERN_ERR , ch->target->scsi_host,PFX "problems processing SRP_CRED_REQ\n" ); } -static void srp_process_aer_req (struct srp_target_port *target, +static void srp_process_aer_req (struct srp_rdma_ch *ch,struct srp_aer_req *req) { +struct srp_target_port *target = ch->target;struct srp_aer_rsp rsp = { .opcode =SRP_AER_RSP , .tag = req->tag,
@@ -1722,19 +1748,20 @@ static void srp_process_aer_req(struct srp_target_port *target,shost_printk (KERN_ERR , target->scsi_host,PFX "ignoring AER for LUN %llu\n" ,be64_to_cpu (req->lun)); -if (srp_response_common (target, delta, &rsp,sizeof rsp)) +if (srp_response_common (ch, delta, &rsp,sizeof (rsp)))shost_printk (KERN_ERR , target->scsi_host,PFX "problems processing SRP_AER_REQ\n" ); } -static void srp_handle_recv (struct srp_target_port *target,struct ib_wc *wc) +static void srp_handle_recv (struct srp_rdma_ch *ch,struct ib_wc *wc) { +struct srp_target_port *target = ch->target;struct ib_device *dev = target->srp_host->srp_dev->dev;struct srp_iu *iu = (struct srp_iu *) (uintptr_t ) wc->wr_id;int res;u8 opcode; -ib_dma_sync_single_for_cpu (dev, iu->dma, target->max_ti_iu_len, +ib_dma_sync_single_for_cpu (dev, iu->dma, ch->max_ti_iu_len,DMA_FROM_DEVICE ); opcode = *(u8 *) iu->buf;
@@ -1748,15 +1775,15 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)switch (opcode) {case SRP_RSP : -srp_process_rsp (target, iu->buf); +srp_process_rsp (ch, iu->buf);break ;case SRP_CRED_REQ : -srp_process_cred_req (target, iu->buf); +srp_process_cred_req (ch, iu->buf);break ;case SRP_AER_REQ : -srp_process_aer_req (target, iu->buf); +srp_process_aer_req (ch, iu->buf);break ;case SRP_T_LOGOUT :
@@ -1771,10 +1798,10 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)break ; } -ib_dma_sync_single_for_device (dev, iu->dma, target->max_ti_iu_len, +ib_dma_sync_single_for_device (dev, iu->dma, ch->max_ti_iu_len,DMA_FROM_DEVICE ); - res =srp_post_recv (target, iu); + res =srp_post_recv (ch, iu);if (res !=0 )shost_printk (KERN_ERR , target->scsi_host,PFX "Recv failed with error code %d\n" , res);
@@ -1819,33 +1846,35 @@ static void srp_handle_qp_err(u64 wr_id, enum ib_wc_status wc_status, target->qp_in_error = true; } -static void srp_recv_completion (struct ib_cq *cq,void *target_ptr) +static void srp_recv_completion (struct ib_cq *cq,void *ch_ptr) { -struct srp_target_port *target = target_ptr; +struct srp_rdma_ch *ch = ch_ptr;struct ib_wc wc;ib_req_notify_cq (cq,IB_CQ_NEXT_COMP );while (ib_poll_cq (cq,1 , &wc) >0 ) {if (likely (wc.status ==IB_WC_SUCCESS )) { -srp_handle_recv (target, &wc); +srp_handle_recv (ch, &wc); }else { -srp_handle_qp_err (wc.wr_id, wc.status, false, target); +srp_handle_qp_err (wc.wr_id, wc.status, false, + ch->target); } } } -static void srp_send_completion (struct ib_cq *cq,void *target_ptr) +static void srp_send_completion (struct ib_cq *cq,void *ch_ptr) { -struct srp_target_port *target = target_ptr; +struct srp_rdma_ch *ch = ch_ptr;struct ib_wc wc;struct srp_iu *iu;while (ib_poll_cq (cq,1 , &wc) >0 ) {if (likely (wc.status ==IB_WC_SUCCESS )) { iu = (struct srp_iu *) (uintptr_t ) wc.wr_id; -list_add (&iu->list, &target->free_tx); +list_add (&iu->list, &ch->free_tx); }else { -srp_handle_qp_err (wc.wr_id, wc.status, true, target); +srp_handle_qp_err (wc.wr_id, wc.status, true, + ch->target); } } }
@@ -1854,6 +1883,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) {struct srp_target_port *target =host_to_target (shost);struct srp_rport *rport = target->rport; +struct srp_rdma_ch *ch;struct srp_request *req;struct srp_iu *iu;struct srp_cmd *cmd;
@@ -1875,14 +1905,16 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)if (unlikely (scmnd->result)) goto err; -spin_lock_irqsave (&target->lock, flags); - iu =__srp_get_tx_iu (target,SRP_IU_CMD ); + ch = &target->ch; + +spin_lock_irqsave (&ch->lock, flags); + iu =__srp_get_tx_iu (ch,SRP_IU_CMD );if (!iu) goto err_unlock; - req = list_first_entry(&target->free_reqs, struct srp_request, list); + req = list_first_entry(&ch->free_reqs, struct srp_request, list);list_del (&req->list); -spin_unlock_irqrestore (&target->lock, flags); +spin_unlock_irqrestore (&ch->lock, flags); dev = target->srp_host->srp_dev->dev; ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_iu_len,
@@ -1901,7 +1933,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) req->scmnd = scmnd; req->cmd = iu; - len =srp_map_data (scmnd, target, req); + len =srp_map_data (scmnd, ch, req);if (len <0 ) {shost_printk (KERN_ERR , target->scsi_host,PFX "Failed to map data (%d)\n" , len);
@@ -1919,7 +1951,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)ib_dma_sync_single_for_device (dev, iu->dma, target->max_iu_len,DMA_TO_DEVICE ); -if (srp_post_send (target, iu, len)) { +if (srp_post_send (ch, iu, len)) {shost_printk (KERN_ERR , target->scsi_host,PFX "Send failed\n" ); goto err_unmap; }
@@ -1933,10 +1965,10 @@ unlock_rport:return ret; err_unmap: -srp_unmap_data (scmnd, target, req); +srp_unmap_data (scmnd, ch, req); err_iu: -srp_put_tx_iu (target, iu,SRP_IU_CMD ); +srp_put_tx_iu (ch, iu,SRP_IU_CMD );/* * Avoid that the loops that iterate over the request ring can
@@ -1944,11 +1976,11 @@ err_iu:*/ req->scmnd =NULL ; -spin_lock_irqsave (&target->lock, flags); -list_add (&req->list, &target->free_reqs); +spin_lock_irqsave (&ch->lock, flags); +list_add (&req->list, &ch->free_reqs); err_unlock: -spin_unlock_irqrestore (&target->lock, flags); +spin_unlock_irqrestore (&ch->lock, flags); err:if (scmnd->result) {
@@ -1963,53 +1995,54 @@ err:/* * Note: the resources allocated in this function are freed in -* srp_free_target_ib(). +* srp_free_ch_ib(). */ -static int srp_alloc_iu_bufs (struct srp_target_port *target) +static int srp_alloc_iu_bufs (struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;int i; - target->rx_ring =kzalloc (target->queue_size *sizeof (*target->rx_ring), -GFP_KERNEL ); -if (!target->rx_ring) + ch->rx_ring =kcalloc (target->queue_size,sizeof (*ch->rx_ring), +GFP_KERNEL ); +if (!ch->rx_ring) goto err_no_ring; - target->tx_ring =kzalloc (target->queue_size *sizeof (*target->tx_ring), -GFP_KERNEL ); -if (!target->tx_ring) + ch->tx_ring =kcalloc (target->queue_size,sizeof (*ch->tx_ring), +GFP_KERNEL ); +if (!ch->tx_ring) goto err_no_ring;for (i =0 ; i < target->queue_size; ++i) { - target->rx_ring[i] =srp_alloc_iu (target->srp_host, - target->max_ti_iu_len, -GFP_KERNEL ,DMA_FROM_DEVICE ); -if (!target->rx_ring[i]) + ch->rx_ring[i] =srp_alloc_iu (target->srp_host, + ch->max_ti_iu_len, +GFP_KERNEL ,DMA_FROM_DEVICE ); +if (!ch->rx_ring[i]) goto err; }for (i =0 ; i < target->queue_size; ++i) { - target->tx_ring[i] =srp_alloc_iu (target->srp_host, - target->max_iu_len, -GFP_KERNEL ,DMA_TO_DEVICE ); -if (!target->tx_ring[i]) + ch->tx_ring[i] =srp_alloc_iu (target->srp_host, + target->max_iu_len, +GFP_KERNEL ,DMA_TO_DEVICE ); +if (!ch->tx_ring[i]) goto err; -list_add (&target->tx_ring[i]->list, &target->free_tx); +list_add (&ch->tx_ring[i]->list, &ch->free_tx); }return 0 ; err:for (i =0 ; i < target->queue_size; ++i) { -srp_free_iu (target->srp_host, target->rx_ring[i]); -srp_free_iu (target->srp_host, target->tx_ring[i]); +srp_free_iu (target->srp_host, ch->rx_ring[i]); +srp_free_iu (target->srp_host, ch->tx_ring[i]); } err_no_ring: -kfree (target->tx_ring); - target->tx_ring =NULL ; -kfree (target->rx_ring); - target->rx_ring =NULL ; +kfree (ch->tx_ring); + ch->tx_ring =NULL ; +kfree (ch->rx_ring); + ch->rx_ring =NULL ;return -ENOMEM ; }
@@ -2043,23 +2076,24 @@ static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask)static void srp_cm_rep_handler (struct ib_cm_id *cm_id,struct srp_login_rsp *lrsp, -struct srp_target_port *target) +struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;struct ib_qp_attr *qp_attr =NULL ;int attr_mask =0 ;int ret;int i;if (lrsp->opcode ==SRP_LOGIN_RSP ) { - target->max_ti_iu_len =be32_to_cpu (lrsp->max_ti_iu_len); - target->req_lim =be32_to_cpu (lrsp->req_lim_delta); + ch->max_ti_iu_len =be32_to_cpu (lrsp->max_ti_iu_len); + ch->req_lim =be32_to_cpu (lrsp->req_lim_delta);/* * Reserve credits for task management so we don't * bounce requests back to the SCSI mid-layer. */ target->scsi_host->can_queue - =min (target->req_lim -SRP_TSK_MGMT_SQ_SIZE , + =min (ch->req_lim -SRP_TSK_MGMT_SQ_SIZE , target->scsi_host->can_queue); target->scsi_host->cmd_per_lun = min_t(int, target->scsi_host->can_queue,
@@ -2071,8 +2105,8 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id, goto error; } -if (!target->rx_ring) { - ret =srp_alloc_iu_bufs (target); +if (!ch->rx_ring) { + ret =srp_alloc_iu_bufs (ch);if (ret) goto error; }
@@ -2087,13 +2121,14 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,if (ret) goto error_free; - ret =ib_modify_qp (target->qp, qp_attr, attr_mask); + ret =ib_modify_qp (ch->qp, qp_attr, attr_mask);if (ret) goto error_free;for (i =0 ; i < target->queue_size; i++) { -struct srp_iu *iu = target->rx_ring[i]; - ret =srp_post_recv (target, iu); +struct srp_iu *iu = ch->rx_ring[i]; + + ret =srp_post_recv (ch, iu);if (ret) goto error_free; }
@@ -2105,7 +2140,7 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id, target->rq_tmo_jiffies =srp_compute_rq_tmo (qp_attr, attr_mask); - ret =ib_modify_qp (target->qp, qp_attr, attr_mask); + ret =ib_modify_qp (ch->qp, qp_attr, attr_mask);if (ret) goto error_free;
@@ -2115,13 +2150,14 @@ error_free:kfree (qp_attr); error: - target->status = ret; + ch->status = ret; }static void srp_cm_rej_handler (struct ib_cm_id *cm_id,struct ib_cm_event *event, -struct srp_target_port *target) +struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target;struct Scsi_Host *shost = target->scsi_host;struct ib_class_port_info *cpi;int opcode;
@@ -2129,12 +2165,12 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,switch (event->param.rej_rcvd.reason) {case IB_CM_REJ_PORT_CM_REDIRECT : cpi = event->param.rej_rcvd.ari; - target->path.dlid = cpi->redirect_lid; - target->path.pkey = cpi->redirect_pkey; + ch->path.dlid = cpi->redirect_lid; + ch->path.pkey = cpi->redirect_pkey; cm_id->remote_cm_qpn =be32_to_cpu (cpi->redirect_qp) &0x00ffffff ; -memcpy (target->path.dgid.raw, cpi->redirect_gid,16 ); +memcpy (ch->path.dgid.raw, cpi->redirect_gid,16 ); - target->status = target->path.dlid ? + ch->status = ch->path.dlid ?SRP_DLID_REDIRECT :SRP_PORT_REDIRECT ;break ;
@@ -2145,26 +2181,26 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,* reject reason code 25 when they mean 24 * (port redirect). */ -memcpy (target->path.dgid.raw, +memcpy (ch->path.dgid.raw, event->param.rej_rcvd.ari,16 );shost_printk (KERN_DEBUG , shost,PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n" , - (unsigned long long )be64_to_cpu (target->path.dgid.global.subnet_prefix), - (unsigned long long )be64_to_cpu (target->path.dgid.global.interface_id)); +be64_to_cpu (ch->path.dgid.global.subnet_prefix), +be64_to_cpu (ch->path.dgid.global.interface_id)); - target->status =SRP_PORT_REDIRECT ; + ch->status =SRP_PORT_REDIRECT ; }else {shost_printk (KERN_WARNING , shost," REJ reason: IB_CM_REJ_PORT_REDIRECT\n" ); - target->status = -ECONNRESET ; + ch->status = -ECONNRESET ; }break ;case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID :shost_printk (KERN_WARNING , shost," REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n" ); - target->status = -ECONNRESET ; + ch->status = -ECONNRESET ;break ;case IB_CM_REJ_CONSUMER_DEFINED :
@@ -2185,24 +2221,25 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,shost_printk (KERN_WARNING , shost," REJ reason: IB_CM_REJ_CONSUMER_DEFINED," " opcode 0x%02x\n" , opcode); - target->status = -ECONNRESET ; + ch->status = -ECONNRESET ;break ;case IB_CM_REJ_STALE_CONN :shost_printk (KERN_WARNING , shost," REJ reason: stale connection\n" ); - target->status =SRP_STALE_CONN ; + ch->status =SRP_STALE_CONN ;break ;default :shost_printk (KERN_WARNING , shost," REJ reason 0x%x\n" , event->param.rej_rcvd.reason); - target->status = -ECONNRESET ; + ch->status = -ECONNRESET ; } }static int srp_cm_handler (struct ib_cm_id *cm_id,struct ib_cm_event *event) { -struct srp_target_port *target = cm_id->context; +struct srp_rdma_ch *ch = cm_id->context; +struct srp_target_port *target = ch->target;int comp =0 ;switch (event->event) {
@@ -2210,19 +2247,19 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)shost_printk (KERN_DEBUG , target->scsi_host,PFX "Sending CM REQ failed\n" ); comp =1 ; - target->status = -ECONNRESET ; + ch->status = -ECONNRESET ;break ;case IB_CM_REP_RECEIVED : comp =1 ; -srp_cm_rep_handler (cm_id, event->private_data, target); +srp_cm_rep_handler (cm_id, event->private_data, ch);break ;case IB_CM_REJ_RECEIVED :shost_printk (KERN_DEBUG , target->scsi_host,PFX "REJ received\n" ); comp =1 ; -srp_cm_rej_handler (cm_id, event, target); +srp_cm_rej_handler (cm_id, event, ch);break ;case IB_CM_DREQ_RECEIVED :
@@ -2240,7 +2277,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) PFX "connection closed\n"); comp =1 ; - target->status =0 ; + ch->status =0 ;break ;case IB_CM_MRA_RECEIVED :
@@ -2255,7 +2292,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) }if (comp) -complete (&target->done); +complete (&ch->done);return 0 ; }
@@ -2311,9 +2348,10 @@ srp_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)return sdev->queue_depth; } -static int srp_send_tsk_mgmt (struct srp_target_port *target, -u64 req_tag,unsigned int lun,u8 func) +static int srp_send_tsk_mgmt (struct srp_rdma_ch *ch,u64 req_tag, +unsigned int lun,u8 func) { +struct srp_target_port *target = ch->target;struct srp_rport *rport = target->rport;struct ib_device *dev = target->srp_host->srp_dev->dev;struct srp_iu *iu;
@@ -2322,16 +2360,16 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,if (!target->connected || target->qp_in_error)return -1 ; -init_completion (&target->tsk_mgmt_done); +init_completion (&ch->tsk_mgmt_done);/* -* Lock the rport mutex to avoid that srp_create_target_ib() is +* Lock the rport mutex to avoid that srp_create_ch_ib() is * invoked while a task management function is being sent. */ mutex_lock (&rport->mutex); -spin_lock_irq (&target->lock); - iu =__srp_get_tx_iu (target,SRP_IU_TSK_MGMT ); -spin_unlock_irq (&target->lock); +spin_lock_irq (&ch->lock); + iu =__srp_get_tx_iu (ch,SRP_IU_TSK_MGMT ); +spin_unlock_irq (&ch->lock);if (!iu) {mutex_unlock (&rport->mutex);
@@ -2352,15 +2390,15 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,ib_dma_sync_single_for_device (dev, iu->dma,sizeof *tsk_mgmt,DMA_TO_DEVICE ); -if (srp_post_send (target, iu,sizeof *tsk_mgmt)) { -srp_put_tx_iu (target, iu,SRP_IU_TSK_MGMT ); +if (srp_post_send (ch, iu,sizeof (*tsk_mgmt))) { +srp_put_tx_iu (ch, iu,SRP_IU_TSK_MGMT );mutex_unlock (&rport->mutex);return -1 ; }mutex_unlock (&rport->mutex); -if (!wait_for_completion_timeout (&target->tsk_mgmt_done, +if (!wait_for_completion_timeout (&ch->tsk_mgmt_done,msecs_to_jiffies (SRP_ABORT_TIMEOUT_MS )))return -1 ;
@@ -2371,20 +2409,22 @@ static int srp_abort(struct scsi_cmnd *scmnd) {struct srp_target_port *target =host_to_target (scmnd->device->host);struct srp_request *req = (struct srp_request *) scmnd->host_scribble; +struct srp_rdma_ch *ch;int ret;shost_printk (KERN_ERR , target->scsi_host,"SRP abort called\n" ); -if (!req || !srp_claim_req (target, req,NULL , scmnd)) + ch = &target->ch; +if (!req || !srp_claim_req (ch, req,NULL , scmnd))return SUCCESS ; -if (srp_send_tsk_mgmt (target, req->index, scmnd->device->lun, +if (srp_send_tsk_mgmt (ch, req->index, scmnd->device->lun,SRP_TSK_ABORT_TASK ) ==0 ) ret =SUCCESS ;else if (target->rport->state ==SRP_RPORT_LOST ) ret =FAST_IO_FAIL ;else ret =FAILED ; -srp_free_req (target, req, scmnd,0 ); +srp_free_req (ch, req, scmnd,0 ); scmnd->result =DID_ABORT <<16 ; scmnd->scsi_done (scmnd);
@@ -2394,19 +2434,21 @@ static int srp_abort(struct scsi_cmnd *scmnd)static int srp_reset_device (struct scsi_cmnd *scmnd) {struct srp_target_port *target =host_to_target (scmnd->device->host); +struct srp_rdma_ch *ch = &target->ch;int i;shost_printk (KERN_ERR , target->scsi_host,"SRP reset_device called\n" ); -if (srp_send_tsk_mgmt (target,SRP_TAG_NO_REQ , scmnd->device->lun, +if (srp_send_tsk_mgmt (ch,SRP_TAG_NO_REQ , scmnd->device->lun,SRP_TSK_LUN_RESET ))return FAILED ; -if (target->tsk_mgmt_status) +if (ch->tsk_mgmt_status)return FAILED ;for (i =0 ; i < target->req_ring_size; ++i) { -struct srp_request *req = &target->req_ring[i]; -srp_finish_req (target, req, scmnd->device,DID_RESET <<16 ); +struct srp_request *req = &ch->req_ring[i]; + +srp_finish_req (ch, req, scmnd->device,DID_RESET <<16 ); }return SUCCESS ;
@@ -2483,8 +2525,9 @@ static ssize_t show_dgid(struct device *dev, struct device_attribute *attr, char *buf) {struct srp_target_port *target =host_to_target (class_to_shost (dev)); +struct srp_rdma_ch *ch = &target->ch; -return sprintf (buf,"%pI6\n" , target->path.dgid.raw); +return sprintf (buf,"%pI6\n" , ch->path.dgid.raw); } static ssize_t show_orig_dgid(struct device *dev,
@@ -2500,7 +2543,7 @@ static ssize_t show_req_lim(struct device *dev, {struct srp_target_port *target =host_to_target (class_to_shost (dev)); -return sprintf (buf,"%d\n" , target->req_lim); +return sprintf (buf,"%d\n" , target->ch.req_lim); } static ssize_t show_zero_req_lim(struct device *dev,
@@ -2992,6 +3035,7 @@ static ssize_t srp_create_target(struct device *dev, container_of(dev, struct srp_host, dev);struct Scsi_Host *target_host;struct srp_target_port *target; +struct srp_rdma_ch *ch;struct srp_device *srp_dev = host->srp_dev;struct ib_device *ibdev = srp_dev->dev;int ret;
@@ -3060,8 +3104,12 @@ static ssize_t srp_create_target(struct device *dev,INIT_WORK (&target->tl_err_work, srp_tl_err_work);INIT_WORK (&target->remove_work, srp_remove_work);spin_lock_init (&target->lock); -INIT_LIST_HEAD (&target->free_tx); - ret =srp_alloc_req_data (target); + ch = &target->ch; + ch->target = target; + ch->comp_vector = target->comp_vector; +spin_lock_init (&ch->lock); +INIT_LIST_HEAD (&ch->free_tx); + ret =srp_alloc_req_data (ch);if (ret) goto err_free_mem;
@@ -3069,15 +3117,15 @@ static ssize_t srp_create_target(struct device *dev,if (ret) goto err_free_mem; - ret =srp_create_target_ib (target); + ret =srp_create_ch_ib (ch);if (ret) goto err_free_mem; - ret =srp_new_cm_id (target); + ret =srp_new_cm_id (ch);if (ret) goto err_free_ib; - ret =srp_connect_target (target); + ret =srp_connect_ch (ch);if (ret) {shost_printk (KERN_ERR , target->scsi_host,PFX "Connection failed\n" );
@@ -3111,10 +3159,10 @@ err_disconnect:srp_disconnect_target (target); err_free_ib: -srp_free_target_ib (target); +srp_free_ch_ib (target, ch); err_free_mem: -srp_free_req_data (target); +srp_free_req_data (target, ch); err:scsi_host_put (target_host);
drivers/infiniband/ulp/srp/ib_srp.h +42 -22
105 lines not on this page · raw message
Signature · 1 line
1.8.4.5
Bart Van Assche
maintainerPATCH v3 11/11 IB/srp: Fix a race condition triggered by destroying a queue pair
In reply to Bart Van AsscheAt least LID reassignment can trigger a race condition in the SRP initiator driver, namely the receive completion handler trying to post a request on a QP during or after QP destruction and before the CQ's have been destroyed. Avoid this race by modifying a QP into the error state and by waiting until all receive completions have been processed before destroying a QP.
--- drivers/infiniband/ulp/srp/ib_srp.c | 59 +++++++++++++++++++++++++++++++------ drivers/infiniband/ulp/srp/ib_srp.h | 2 ++ 2 files changed, 52 insertions(+), 9 deletions(-)
drivers/infiniband/ulp/srp/ib_srp.c +50 -9
@@ -453,6 +453,41 @@ static struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target) dev->max_pages_per_mr); } +/** +* srp_destroy_qp() - destroy an RDMA queue pair +* @ch: SRP RDMA channel. +* +* Change a queue pair into the error state and wait until all receive +* completions have been processed before destroying it. This avoids that +* the receive completion handler can access the queue pair while it is +* being destroyed. +*/ +static void srp_destroy_qp (struct srp_rdma_ch *ch) +{ +struct srp_target_port *target = ch->target; +static struct ib_qp_attr attr = { .qp_state =IB_QPS_ERR }; +static struct ib_recv_wr wr = { .wr_id =SRP_LAST_WR_ID }; +struct ib_recv_wr *bad_wr; +int ret; + +/* Destroying a QP and reusing ch->done is only safe if not connected */ +WARN_ON_ONCE (target->connected); + + ret =ib_modify_qp (ch->qp, &attr,IB_QP_STATE ); +WARN_ONCE (ret,"ib_cm_init_qp_attr() returned %d\n" , ret); +if (ret) + goto out; + +init_completion (&ch->done); + ret =ib_post_recv (ch->qp, &wr, &bad_wr); +WARN_ONCE (ret,"ib_post_recv() returned %d\n" , ret); +if (ret ==0 ) +wait_for_completion (&ch->done); + +out: +ib_destroy_qp (ch->qp); +} +static int srp_create_ch_ib (struct srp_rdma_ch *ch) {struct srp_target_port *target = ch->target;
@@ -469,8 +504,9 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch)if (!init_attr)return -ENOMEM ; +/* + 1 for SRP_LAST_WR_ID */ recv_cq =ib_create_cq (dev->dev, srp_recv_completion,NULL , ch, - target->queue_size, ch->comp_vector); + target->queue_size +1 , ch->comp_vector);if (IS_ERR (recv_cq)) { ret =PTR_ERR (recv_cq); goto err;
@@ -487,7 +523,7 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) init_attr->event_handler = srp_qp_event; init_attr->cap.max_send_wr = m * target->queue_size; - init_attr->cap.max_recv_wr = target->queue_size; + init_attr->cap.max_recv_wr = target->queue_size +1 ; init_attr->cap.max_recv_sge =1 ; init_attr->cap.max_send_sge =1 ; init_attr->sq_sig_type =IB_SIGNAL_REQ_WR ;
@@ -530,7 +566,7 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) }if (ch->qp) -ib_destroy_qp (ch->qp); +srp_destroy_qp (ch);if (ch->recv_cq)ib_destroy_cq (ch->recv_cq);if (ch->send_cq)
@@ -586,7 +622,7 @@ static void srp_free_ch_ib(struct srp_target_port *target,if (ch->fmr_pool)ib_destroy_fmr_pool (ch->fmr_pool); } -ib_destroy_qp (ch->qp); +srp_destroy_qp (ch);ib_destroy_cq (ch->send_cq);ib_destroy_cq (ch->recv_cq);
@@ -1883,8 +1919,15 @@ static void srp_tl_err_work(struct work_struct *work) }static void srp_handle_qp_err (u64 wr_id,enum ib_wc_status wc_status, -bool send_err,struct srp_target_port *target) +bool send_err,struct srp_rdma_ch *ch) { +struct srp_target_port *target = ch->target; + +if (wr_id ==SRP_LAST_WR_ID ) { +complete (&ch->done); +return ; + } +if (target->connected && !target->qp_in_error) {if (wr_id &LOCAL_INV_WR_ID_MASK ) { shost_printk(KERN_ERR, target->scsi_host, PFX
@@ -1915,8 +1958,7 @@ static void srp_recv_completion(struct ib_cq *cq, void *ch_ptr)if (likely (wc.status ==IB_WC_SUCCESS )) {srp_handle_recv (ch, &wc); }else { -srp_handle_qp_err (wc.wr_id, wc.status, false, - ch->target); +srp_handle_qp_err (wc.wr_id, wc.status, false, ch); } } }
@@ -1932,8 +1974,7 @@ static void srp_send_completion(struct ib_cq *cq, void *ch_ptr) iu = (struct srp_iu *) (uintptr_t ) wc.wr_id;list_add (&iu->list, &ch->free_tx); }else { -srp_handle_qp_err (wc.wr_id, wc.status, true, - ch->target); +srp_handle_qp_err (wc.wr_id, wc.status, true, ch); } } }
drivers/infiniband/ulp/srp/ib_srp.h +2 -0
@@ -70,6 +70,8 @@ enum {LOCAL_INV_WR_ID_MASK =1 ,FAST_REG_WR_ID_MASK =2 , + + SRP_LAST_WR_ID = 0xfffffffcU, }; enum srp_target_state {
Signature · 1 line
1.8.4.5
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH v3 11/11] IB/srp: Fix a race condition triggered by destroying a queue pair
Quoted 32 lines · Bart Van Assche
At least LID reassignment can trigger a race condition in the SRP initiator driver, namely the receive completion handler trying to post a request on a QP during or after QP destruction and before the CQ's have been destroyed. Avoid this race by modifying a QP into the error state and by waiting until all receive completions have been processed before destroying a QP.
Signed-off-by Bart Van Assche <[email protected]>--- drivers/infiniband/ulp/srp/ib_srp.c | 59 +++++++++++++++++++++++++++++++------ drivers/infiniband/ulp/srp/ib_srp.h | 2 ++ 2 files changed, 52 insertions(+), 9 deletions(-)drivers/infiniband/ulp/srp/ib_srp.c +9
-0@@ -453,6 +453,41 @@ static struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target) dev->max_pages_per_mr); } +/** +* srp_destroy_qp() - destroy an RDMA queue pair +* @ch: SRP RDMA channel. +* +* Change a queue pair into the error state and wait until all receive +* completions have been processed before destroying it. This avoids that +* the receive completion handler can access the queue pair while it is +* being destroyed. +*/
drivers/infiniband/ulp/srp/ib_srp.c static struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target) · line 474
Quoted 10 lines
drivers/infiniband/ulp/srp/ib_srp.c +10
-0+static void srp_destroy_qp (struct srp_rdma_ch *ch) +{ +struct srp_target_port *target = ch->target; +static struct ib_qp_attr attr = { .qp_state =IB_QPS_ERR }; +static struct ib_recv_wr wr = { .wr_id =SRP_LAST_WR_ID }; +struct ib_recv_wr *bad_wr; +int ret; + +/* Destroying a QP and reusing ch->done is only safe if not connected */ +WARN_ON_ONCE (target->connected);
I thought we agreed that cannot happen. I guess I don't mind keeping it... BTW, were you able to reproduce this race as well?
Sagi.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 54524A7B.3060708-LDSdmyG8hGV8YrgS2mwiifqBs+8SCbDb@public.gmane.org
Re: [PATCH v3 11/11] IB/srp: Fix a race condition triggered by destroying a queue pair
Quoted 7 lines · Sagi Grimberg
Quoted 3 lines · Bart Van Assche
+ /* Destroying a QP and reusing
ch->doneis only safe if not
connected */
+WARN_ON_ONCE(target->connected);I thought we agreed that cannot happen. I guess I don't mind keeping it... BTW, were you able to reproduce this race as well?
Hello Sagi,
Agreed that it is possible to conclude from the ib_srp source code that the above "WARN_ON_ONCE(target->connected)" statement will never be triggered. The reason I added that statement is to have an explicit check of that condition. Such statements can be helpful in case anyone would like to modify the SRP initiator driver.
I have not yet been able to reproduce the crash addressed by this patch. But the code added via this patch has been triggered in my tests. Since this code is e.g. called from srp_free_ch_ib(), unloading the ib_srp kernel module after login succeeded is sufficient to trigger this code.
Bart.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 11/11] IB/srp: Fix a race condition triggered by destroying a queue pair
Quoted 9 lines · Bart Van Assche
Quoted 7 lines · Sagi Grimberg
Quoted 3 lines · Bart Van Assche
+ /* Destroying a QP and reusing
ch->doneis only safe if not
connected */
+WARN_ON_ONCE(target->connected);I thought we agreed that cannot happen. I guess I don't mind keeping it... BTW, were you able to reproduce this race as well?
Quoted 8 lines
Hello Sagi,
Agreed that it is possible to conclude from the
ib_srpsource code that the above "WARN_ON_ONCE(target->connected)" statement will never be triggered. The reason I added that statement is to have an explicit check of that condition. Such statements can be helpful in case anyone would like to modify the SRP initiator driver.
Yea, OK.
Quoted 4 lines
I have not yet been able to reproduce the crash addressed by this patch. But the code added via this patch has been triggered in my tests. Since this code is e.g. called from
srp_free_ch_ib(), unloading theib_srpkernel module after login succeeded is sufficient to trigger this code.
Yes of course, was just curious to know if you got this crash as well...
Sagi.