> On Jun 19, 2017, at 3:01 AM, Johannes Thumshirn <[email protected]> wrote:
>
> On Fri, Jun 16, 2017 at 03:47:41PM -0700, Himanshu Madhani wrote:
> [...]
>> /*
>> + * Global functions prototype in qla_nvme.c source file.
>> + */
>> +extern void qla_nvme_register_hba(scsi_qla_host_t *);
>> +extern int qla_nvme_register_remote(scsi_qla_host_t *, fc_port_t *);
>> +extern void qla_nvme_delete(scsi_qla_host_t *);
>> +extern void qla_nvme_abort(struct qla_hw_data *, srb_t *sp);
>> +extern void qla_nvme_unregister_remote_port(struct work_struct *);
>> +extern int qla_nvme_wait_on_rport_del(fc_port_t *);
>> +extern void qla_nvme_abort_all(fc_port_t *);
>> +extern int qla_nvme_post_cmd(struct nvme_fc_local_port *,
>> + struct nvme_fc_remote_port *, void *, struct nvmefc_fcp_req *);
>> +extern int qla_nvme_alloc_queue(struct nvme_fc_local_port *, unsigned int,
>> + u16, void **);
>> +extern int qla_nvme_hba_scan(scsi_qla_host_t *);
>> +extern void qla_nvme_ls_abort(struct nvme_fc_local_port *,
>> + struct nvme_fc_remote_port *, struct nvmefc_ls_req *);
>> +extern int qla_nvme_ls_req(struct nvme_fc_local_port *,
>> + struct nvme_fc_remote_port *, struct nvmefc_ls_req *);
>> +extern void qla_nvme_poll(struct nvme_fc_local_port *, void *);
>> +extern int qla2x00_start_nvme_mq(srb_t *);
>> +extern void qla_nvme_fcp_abort(struct nvme_fc_local_port *,
>> + struct nvme_fc_remote_port *, void *, struct nvmefc_fcp_req *);
>> +extern void qla24xx_nvme_ls4_iocb(scsi_qla_host_t *, struct pt_ls4_request
>> *,
>> + struct req_que *);
>
> Can't these go into a header instead of using extern?
>
Sure.
> [...]
>
>> @@ -4662,6 +4667,9 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
>> break;
>> } while (0);
>>
>> + if ((!vha->nvme_local_port) && (vha->flags.nvme_enabled))
>
>
> [...]
>
>> + if ((ql2xnvmeenable) && IS_QLA27XX(ha))
>> + mcp->mb[4] |= NVME_ENABLE_FLAG;
>> +
>
> [...]
>
>> +
>> + /* bit 26 of fw_attributes */
>> + if ((ha->fw_attributes_h & 0x400) && (ql2xnvmeenable)) {
>
> Superfluous parenthesis.
>
Good catch. will fix in v2
> [...]
>
>> + vha->flags.nvme_enabled = 1;
>> + icb->firmware_options_2 &=
>> + cpu_to_le32(~(BIT_0 | BIT_1 | BIT_2 | BIT_3));
>
> 0xfffffff0 or maybe even ~0xf?
>
will fix in v2
> [...]
>
>> + ret = nvme_fc_register_remoteport(vha->nvme_local_port, &rport->req,
>> + &fcport->nvme_remote_port);
>> + if (ret) {
>> + ql_log(ql_log_warn, vha, 0x212e,
>> + "Failed to register remote port. Transport returned %d\n",
>> + ret);
>> + return ret;
>> + }
>> +
>> + fcport->nvme_remote_port->private = fcport;
>
> A FC-NVMe remote port can be in used right after a call to
> nvme_fc_register_remoteport(), if I'm not mistaken. So you should add the
> fcport to the nvme_remote_port->private _before_ calling
> nvme_fc_register_remoteport().
Will check this out.
>
>> + fcport->nvme_flag |= NVME_FLAG_REGISTERED;
>> + atomic_set(&fcport->nvme_ref_count, 1);
>> + rport->fcport = fcport;
>> + list_add_tail(&rport->list, &vha->nvme_rport_list);
>> +#endif
>> + return 0;
>> +}
>> +
>> +/*
>> + * Perform a scan and register those ports with FC-NVMe transport
>> + * input: HBA handle
>> + */
>> +int qla_nvme_hba_scan(scsi_qla_host_t *vha)
>
> This should be bool.
>
>> +{
>> +#if (IS_ENABLED(CONFIG_NVME_FC))
>> + fc_port_t *fcport;
>> + uint8_t not_found = 1;
>
> bool found = false;
>
>> +
>> + /*
>> + * We are using the first HBA found
>> + * Find matching fcport
>> + */
>> + list_for_each_entry(fcport, &vha->vp_fcports, list) {
>> + if ((fcport->fc4f_nvme) &&
>> + (!(fcport->nvme_flag & NVME_FLAG_REGISTERED))) {
>> + qla_nvme_register_remote(vha, fcport);
>> + not_found = 0;
>
> found = true;
>
>> + }
>> + }
>> +
>> + return not_found;
>
> return found;
>
>> +#else
>> + return 1;
>
> return false;
>
>> +#endif
>> +}
>
> And update the call-sites.
>
Ack.
> [...]
>
>> + if (unlikely((nvme->u.nvme.comp_status) || res))
>
> Parenthesis again.
>
Ack.
> [...]
>
>> +void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
>> + struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
>> +{
>> + struct nvme_private *priv = fd->private;
>> + fc_port_t *fcport = rport->private;
>> + srb_t *sp = priv->sp;
>> + int rval;
>> + struct qla_hw_data *ha;
>> +
>> + ql_log(ql_log_info, fcport->vha, 0x212b,
>> + "%s: aborting sp:%p on fcport:%p\n", __func__, sp, fcport);
>> +
>> + ha = fcport->vha->hw;
>> + rval = ha->isp_ops->abort_command(sp);
>> + if (rval != QLA_SUCCESS)
>> + ql_log(ql_log_warn, fcport->vha, 0x2125,
>> + "%s: failed to abort LS command for SP:%p rval=%x\n",
>> + __func__, sp, rval);
>> +}
>
> I think qla_nvme_ls_abort() is a bit too verbose, it nearly only consists of
> logging and thus hides the call to abort_command() from the reader.
>
Sure. will make it more readable.
>> +
>> +static void qla_nvme_ls_complete(struct work_struct *work)
>> +{
>> + struct nvme_private *priv =
>> + container_of(work, struct nvme_private, ls_work);
>> + struct nvmefc_ls_req *fd = priv->fd;
>> +
>> + (*fd->done)(fd, priv->comp_status);
>
> Can't we get the function pointer to done directly this LISP style doesn't
> really look too nice;
>
> done(fd, priv->comp_status);
> or maybe
> fd->done(fd, priv->comp_status);
>
Sure. will fix this for v2.
>> +
>> +int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
>> + struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd)
>> +{
>> + fc_port_t *fcport;
>> + struct srb_iocb *nvme;
>> + struct scsi_qla_host *vha;
>> + int rval = QLA_FUNCTION_FAILED;
>> + struct qla_hw_data *ha;
>> + srb_t *sp;
>> + struct nvme_private *priv;
>> +
>> + if (!fd) {
>> + ql_log(ql_log_warn, NULL, 0x2135, "NO NVMe FCP reqeust\n");
>> + return rval;
>> + }
>
> Just curious, how likely is this? I.e. have you hit the case in debugging?
>
Defensive coding. This can be removed.
>> +
>> + priv = fd->private;
>> + fcport = (fc_port_t *)rport->private;
>> + if (!fcport) {
>> + ql_log(ql_log_warn, NULL, 0x212c,
>> + "%s: No fcport ptr\n", __func__);
>> + return rval;
>> + }
>
> Same here.
>
> [...]
>
>> +
>> +void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
>> + struct nvme_fc_remote_port *rport, void *hw_queue_handle,
>> + struct nvmefc_fcp_req *fd)
>
> The comment from the other abort function above applies here as well.
>
Ack.
>> +void qla_nvme_poll(struct nvme_fc_local_port *lport, void *hw_queue_handle)
>> +{
>> + struct scsi_qla_host *vha = lport->private;
>> + unsigned long flags;
>> + struct qla_qpair *qpair = (struct qla_qpair *)hw_queue_handle;
>> +
>> + /* Acquire ring specific lock */
>> + spin_lock_irqsave(&qpair->qp_lock, flags);
>> + qla24xx_process_response_queue(vha, qpair->rsp);
>> + spin_unlock_irqrestore(&qpair->qp_lock, flags);
>
> Just a side note, I _think_ needing a spin_lock here is a design issue.
>
>> + /* Acquire qpair specific lock */
>> + spin_lock_irqsave(&qpair->qp_lock, flags);
>
> Same here. What is this lock protecting? I see qla_qpair does have a
> reference count (not kref backed btw), so if you're only protecting
> against the structure vanishing under your feet, you could change
> this to krefs. If you're protecting structure members the use of RCUs
> spring to mind. rwlocks as well, if the content that is protected is
> read-mostly. But please note, reworking this requires extensive testing. But a
> spin_lock_irqsave() in the I/O path raises a red-flag for me.
>
The lock here is protecting hardware queue resource of qla2xxx driver.
> [...]
>
>> +
>> +static void qla_nvme_localport_delete(struct nvme_fc_local_port *lport)
>> +{
>> + struct scsi_qla_host *vha = lport->private;
>> +
>> + ql_log(ql_log_info, vha, 0x210f,
>> + "localport delete of %p completed.\n", vha->nvme_local_port);
>> +
>> + vha->nvme_local_port = NULL;
>> + atomic_dec(&vha->nvme_ref_count);
>
> Nit, the debug message says completed, but you haven't "completed" the delete
> ;-).
>
:) good catch again
>> +}
>> +
>> +static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
>> +{
>> + fc_port_t *fcport;
>> + struct nvme_rport *r_port, *trport;
>> +
>> + fcport = (fc_port_t *)rport->private;
>> + fcport->nvme_remote_port = NULL;
>> + fcport->nvme_flag &= ~NVME_FLAG_REGISTERED;
>> + atomic_dec(&fcport->nvme_ref_count);
>> +
>> + ql_log(ql_log_info, fcport->vha, 0x2110,
>> + "remoteport_delete of %p completed.\n", fcport);
>> +
>> + list_for_each_entry_safe(r_port, trport,
>> + &fcport->vha->nvme_rport_list, list) {
>> + if (r_port->fcport == fcport) {
>> + list_del(&r_port->list);
>> + break;
>> + }
>> + }
>> + kfree(r_port);
>
> Ditto.
>
:) Ack
> [..]
>
>> +static int qla_nvme_wait_on_command(srb_t *sp)
>> +{
>> +#define NVME_ABORT_POLLING_PERIOD 1000
>> +#define NVME_ABORT_WAIT_ITER ((2 * 1000) /
>> (NVME_ABORT_POLLING_PERIOD))
>> + unsigned long wait_iter = NVME_ABORT_WAIT_ITER;
>> + int ret = QLA_SUCCESS;
>> +
>> + while ((atomic_read(&sp->ref_count) > 1) && wait_iter--)
>> + msleep(NVME_ABORT_POLLING_PERIOD);
>> +
>> + if (atomic_read(&sp->ref_count) > 1)
>> + ret = QLA_FUNCTION_FAILED;
>> +
>> + return ret;
>
> wait_event_timeout()?
>
will fix up in v2
>> +int qla_nvme_wait_on_rport_del(fc_port_t *fcport)
>> +{
>> + unsigned long wait_iter = NVME_ABORT_WAIT_ITER;
>> + int ret = QLA_SUCCESS;
>> +
>> + while (atomic_read(&fcport->nvme_ref_count) && wait_iter--)
>> + msleep(NVME_ABORT_POLLING_PERIOD);
>
> Ditto.
>
Ack
> [...]
>
>> +void qla_nvme_abort(struct qla_hw_data *ha, srb_t *sp)
>> +{
>> + int rval;
>> +
>> + rval = ha->isp_ops->abort_command(sp);
>> + if (!rval) {
>
> if (!rval && !qla_nvme_wait_on_command(sp))
> ql_log(ql_log_warn, NULL, 0x2112,
> "nvme_wait_on_comand timed out waiting on sp=%p\n",
> sp);
>
> [...]
>
>
>
>
>> + fcport = rport->fcport;
>> + ql_log(ql_log_info, fcport->vha, 0x2114,
>> + "%s: fcport=%p\n", __func__, fcport);
>> + nvme_fc_unregister_remoteport(
>> + fcport->nvme_remote_port);
>> + qla_nvme_wait_on_rport_del(fcport);
>> + qla_nvme_abort_all(fcport);
>> + }
>> + }
>> +
>> + if (vha->nvme_local_port) {
>> + ql_log(ql_log_info, vha, 0x2115,
>> + "unregister localport = %p\n", vha->nvme_local_port);
>> + nvme_fc_unregister_localport(vha->nvme_local_port);
>> + }
>> +
>> + while (atomic_read(&vha->nvme_ref_count))
>> + schedule();
>
> Ugh..., no!
> wait_event()?
>
Ack. will fix up in v2
> [...]
>
>> +
>> + ret = nvme_fc_register_localport(&pinfo, tmpl,
>> + get_device(&ha->pdev->dev), &vha->nvme_local_port);
>
> [...]
>
>> + vha->nvme_local_port->private = vha;
>
> Please move above the nvme_fc_register_localport().
>
> [...]
>
>> +#if (IS_ENABLED(CONFIG_NVME_FC))
>> +int ql2xnvmeenable = 1;
>> +#else
>> +int ql2xnvmeenable;
>> +#endif
>> +module_param(ql2xnvmeenable, int, 0644);
>> +MODULE_PARM_DESC(ql2xnvmeenable,
>> + "Enables NVME support"
>> + "0 - no NVMe. Default is N");
>> +
>
> The message is a bit misleading. NVMe is enabled *IFF* CONFIG_NVME_FC is
> enabled.
>
Will fix up in v2.
> --
> Johannes Thumshirn Storage
> [email protected] +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
Thanks,
- Himanshu