[PATCH 5/7] nvme-fabrics: Add host FC transport support
Johannes Thumshirn
jthumshirn at suse.de
Tue Oct 4 02:32:50 PDT 2016
Hi James,
Some minor nits below in case you'll have to re-send
On Mon, Oct 03, 2016 at 11:27:01PM -0700, James Smart wrote:
>
> Add nvme-fabrics host FC transport support
>
> Implements the FC-NVME T11 definition of how nvme fabric capsules are
> performed on an FC fabric. Utilizes a lower-layer API to FC host adapters
> to send/receive FC-4 LS operations and FCP operations that comprise NVME
> over FC operation.
>
> The T11 definitions for FC-4 Link Services are implemented which create
> NVMeOF connections. Implements the hooks with blk-mq to then submit admin
> and io requests to the different connections.
>
> The changes made since the prior patch:
> - Remove todo on Association LS: pull values from opts struct
> - Slight restructure of nvme_fc_create_io_queues() and
> nvme_fc_init_io_queues() for their return values
> - Checked and corrected BLK_MQ_xx return values in nvme_fc_start_fcp_op()
> - Remove the todo's around dma_map_page(). No need to use dma_map_page()
> - Reworked teardown paths with ref counting
> - Teardown now invokes callbackes on completion of unregister functions
> - set sqid in fcp request structs
> - Add blk poll support.
> - Remove map_queue from templates
> - Removal of fabric name for nport qualifier. Not necessary in T11.
> - LS's moved to controller linked list rather than remoteport
>
> Signed-off-by: James Smart <james.smart at broadcom.com>
> ---
[...]
> +/**
> + * nvme_fc_unregister_localport - transport entry point called by an
> + * LLDD to deregister/remove a previously
> + * registered a NVME host FC port.
> + * @localport: pointer to the (registered) local port that is to be
> + * deregistered.
> + *
> + * Returns:
> + * a completion status. Must be 0 upon success; a negative errno
> + * (ex: -ENXIO) upon failure.
> + */
> +int
> +nvme_fc_unregister_localport(struct nvme_fc_local_port *portptr)
> +{
> + struct nvme_fc_lport *lport =
> + container_of(portptr, struct nvme_fc_lport, localport);
This below could really benifit from a port_to_lport() and port_to_rport().
Same in:
* nvme_fc_register_remoteport()
* nvme_fc_free_rport()
* nvme_fc_unregister_remoteport()
> + unsigned long flags;
> + u32 lnum;
> +
> + if (!portptr)
> + return -EINVAL;
> +
> + lnum = portptr->port_num;
> +
> + spin_lock_irqsave(&nvme_fc_lock, flags);
> +
> + if (portptr->port_state != FC_OBJSTATE_ONLINE) {
> + spin_unlock_irqrestore(&nvme_fc_lock, flags);
> + return -EINVAL;
> + }
> + portptr->port_state = FC_OBJSTATE_DELETED;
> +
> + spin_unlock_irqrestore(&nvme_fc_lock, flags);
> +
> + nvme_fc_lport_put(lport);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(nvme_fc_unregister_localport);
[...]
> +enum blk_eh_timer_return
> +nvme_fc_timeout(struct request *rq, bool reserved)
> +{
> + struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
> + struct nvme_fc_ctrl *ctrl = op->ctrl;
> + int ret;
> +
> + if (reserved)
> + return BLK_EH_RESET_TIMER;
> +
> + ret = __nvme_fc_abort_op(ctrl, op);
> + if (ret)
> + /* io wasn't active to abort consider it done */
> + return BLK_EH_HANDLED;
> +
> + /* fail with DNR on cmd timeout */
> + rq->errors = NVME_SC_ABORT_REQ | NVME_SC_DNR;
> +
> + wait_for_completion(&op->abort_done);
> +
> + /* TODO: force a controller reset */
> +
> + init_completion(&op->abort_done);
Shouldn't a reinit_completion() be sufficient here?
> +
> + return BLK_EH_HANDLED;
> +}
> +
> +static int
> +nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
> + struct nvme_fc_fcp_op *op)
> +{
> + struct nvmefc_fcp_req *freq = &op->fcp_req;
> + u32 map_len = nvme_map_len(rq);
> + int ret;
> +
> + freq->sg_cnt = 0;
> +
> + if (!map_len)
> + return 0;
> +
> + freq->sg_table.sgl = freq->first_sgl;
> + ret = sg_alloc_table_chained(&freq->sg_table, rq->nr_phys_segments,
> + freq->sg_table.sgl);
> + if (ret)
> + return -ENOMEM;
> +
> + op->nents = blk_rq_map_sg(rq->q, rq, freq->sg_table.sgl);
> + WARN_ON(op->nents > rq->nr_phys_segments);
> + freq->sg_cnt = dma_map_sg(ctrl->lport->dev, freq->sg_table.sgl,
> + op->nents, ((rq_data_dir(rq) == WRITE) ?
> + DMA_TO_DEVICE : DMA_FROM_DEVICE));
Care to add a
enum dma_data_direction dir;
dir = (rq_data_dir(rq) == WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
so we're not getting too many linebreaks? (Just have this one as an example).
> + if (unlikely(freq->sg_cnt <= 0)) {
> + sg_free_table_chained(&freq->sg_table, true);
> + freq->sg_cnt = 0;
> + return -EFAULT;
> + }
> +
> + /*
> + * TODO: blk_integrity_rq(rq) for DIX
> + */
Just out of interest, do you plan to get DIX done in this cycle?
> + return 0;
> +}
[...]
> +
> +/*
> + * Called to terminate an association.
> + * Maybe called with association fully in place or partially in place.
> + */
> +static void
> +nvme_fc_shutdown_ctrl(struct nvme_fc_ctrl *ctrl)
> +{
> + nvme_stop_keep_alive(&ctrl->ctrl);
The keepalive should have already been stopped in __nvme_fc_remove_ctrl(),
shouldn't it?
> +
> + if (ctrl->queue_count > 1) {
> + nvme_stop_queues(&ctrl->ctrl);
> + blk_mq_tagset_busy_iter(&ctrl->tag_set,
> + nvme_fc_kill_request, &ctrl->ctrl);
> + }
> +
> + if (ctrl->ctrl.state == NVME_CTRL_LIVE)
> + nvme_shutdown_ctrl(&ctrl->ctrl);
> +
> + blk_mq_stop_hw_queues(ctrl->ctrl.admin_q);
> + blk_mq_tagset_busy_iter(&ctrl->admin_tag_set,
> + nvme_fc_kill_request, &ctrl->ctrl);
> +}
> +
> +
> +static void
> +__nvme_fc_remove_ctrl(struct nvme_fc_ctrl *ctrl)
> +{
> + nvme_stop_keep_alive(&ctrl->ctrl);
> + nvme_uninit_ctrl(&ctrl->ctrl);
> + nvme_fc_shutdown_ctrl(ctrl);
> + nvme_put_ctrl(&ctrl->ctrl);
> +}
[...]
> +static struct nvme_ctrl *
> +nvme_fc_create_ctrl(struct device *dev, struct nvmf_ctrl_options *opts)
> +{
> + struct nvme_fc_lport *lport;
> + struct nvme_fc_rport *rport;
> + struct nvmet_fc_traddr laddr = { 0L, 0L };
> + struct nvmet_fc_traddr raddr = { 0L, 0L };
> + unsigned long flags;
> + int ret;
> +
> + ret = nvme_fc_parse_address(&raddr, opts->traddr);
> + if ((ret) || !raddr.nn || !raddr.pn)
^ I don't think the parenthesis around ret are needed here
> + return ERR_PTR(-EINVAL);
> +
> + ret = nvme_fc_parse_address(&laddr, opts->host_traddr);
> + if ((ret) || !laddr.nn || !laddr.pn)
Same as above
--
Johannes Thumshirn Storage
jthumshirn at suse.de +49 911 74053 689
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
Key fingerprint = EC38 9CAB C2C4 F25D 8600 D0D0 0393 969D 2D76 0850
More information about the Linux-nvme
mailing list