scsi: qla2xxx: Add changes for devloss timeout in driver
authorDarren Trapp <darren.trapp@cavium.com>
Wed, 21 Mar 2018 06:09:32 +0000 (23:09 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 21 Mar 2018 22:38:54 +0000 (18:38 -0400)
Add support for error recovery within devloss timeout, now that
FC-NVMe transport support devloss timeout.

Signed-off-by: Darren Trapp <darren.trapp@cavium.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_nvme.c
drivers/scsi/qla2xxx/qla_nvme.h
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h

index be7d682..56f78dc 100644 (file)
@@ -2355,6 +2355,7 @@ typedef struct fc_port {
 #define NVME_PRLI_SP_DISCOVERY  BIT_3
        uint8_t nvme_flag;
 #define NVME_FLAG_REGISTERED 4
+#define NVME_FLAG_DELETING 2
 
        struct fc_port *conflict;
        unsigned char logout_completed;
index 1878a6f..7f8bfa0 100644 (file)
@@ -5517,6 +5517,14 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
                        break;
                }
 
+               if (fcport->fc4f_nvme) {
+                       if (fcport->disc_state == DSC_DELETE_PEND) {
+                               fcport->disc_state = DSC_GNL;
+                               vha->fcport_count--;
+                               fcport->login_succ = 0;
+                       }
+               }
+
                if (found) {
                        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
                        continue;
index 16c43bd..93f2f1d 100644 (file)
@@ -1910,7 +1910,7 @@ qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
        } else  {
                switch (le16_to_cpu(sts->comp_status)) {
                        case CS_COMPLETE:
-                               ret = 0;
+                               ret = QLA_SUCCESS;
                        break;
 
                        case CS_ABORTED:
@@ -1922,7 +1922,8 @@ qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
                                "NVME-%s ERR Handling - hdl=%x completion status(%x) resid=%x  ox_id=%x\n",
                                sp->name, sp->handle, sts->comp_status,
                                le32_to_cpu(sts->residual_len), sts->ox_id);
-                               fd->transferred_length = fd->payload_length;
+                               fd->transferred_length = 0;
+                               iocb->u.nvme.rsp_pyld_len = 0;
                                ret = QLA_ABORTED;
                        break;
 
index 91f8b3c..5ee4476 100644 (file)
@@ -16,15 +16,13 @@ static void qla_nvme_unregister_remote_port(struct work_struct *);
 
 int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
 {
-       struct nvme_rport *rport;
+       struct qla_nvme_rport *rport;
+       struct nvme_fc_port_info req;
        int ret;
 
        if (!IS_ENABLED(CONFIG_NVME_FC))
                return 0;
 
-       if (fcport->nvme_flag & NVME_FLAG_REGISTERED)
-               return 0;
-
        if (!vha->flags.nvme_enabled) {
                ql_log(ql_log_info, vha, 0x2100,
                    "%s: Not registering target since Host NVME is not enabled\n",
@@ -33,38 +31,35 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
        }
 
        if (!(fcport->nvme_prli_service_param &
-           (NVME_PRLI_SP_TARGET | NVME_PRLI_SP_DISCOVERY)))
+           (NVME_PRLI_SP_TARGET | NVME_PRLI_SP_DISCOVERY)) ||
+               (fcport->nvme_flag & NVME_FLAG_REGISTERED))
                return 0;
 
        INIT_WORK(&fcport->nvme_del_work, qla_nvme_unregister_remote_port);
-       rport = kzalloc(sizeof(*rport), GFP_KERNEL);
-       if (!rport) {
-               ql_log(ql_log_warn, vha, 0x2101,
-                   "%s: unable to alloc memory\n", __func__);
-               return -ENOMEM;
-       }
 
-       rport->req.port_name = wwn_to_u64(fcport->port_name);
-       rport->req.node_name = wwn_to_u64(fcport->node_name);
-       rport->req.port_role = 0;
+       memset(&req, 0, sizeof(struct nvme_fc_port_info));
+       req.port_name = wwn_to_u64(fcport->port_name);
+       req.node_name = wwn_to_u64(fcport->node_name);
+       req.port_role = 0;
+       req.dev_loss_tmo = NVME_FC_DEV_LOSS_TMO;
 
        if (fcport->nvme_prli_service_param & NVME_PRLI_SP_INITIATOR)
-               rport->req.port_role = FC_PORT_ROLE_NVME_INITIATOR;
+               req.port_role = FC_PORT_ROLE_NVME_INITIATOR;
 
        if (fcport->nvme_prli_service_param & NVME_PRLI_SP_TARGET)
-               rport->req.port_role |= FC_PORT_ROLE_NVME_TARGET;
+               req.port_role |= FC_PORT_ROLE_NVME_TARGET;
 
        if (fcport->nvme_prli_service_param & NVME_PRLI_SP_DISCOVERY)
-               rport->req.port_role |= FC_PORT_ROLE_NVME_DISCOVERY;
+               req.port_role |= FC_PORT_ROLE_NVME_DISCOVERY;
 
-       rport->req.port_id = fcport->d_id.b24;
+       req.port_id = fcport->d_id.b24;
 
        ql_log(ql_log_info, vha, 0x2102,
            "%s: traddr=nn-0x%016llx:pn-0x%016llx PortID:%06x\n",
-           __func__, rport->req.node_name, rport->req.port_name,
-           rport->req.port_id);
+           __func__, req.node_name, req.port_name,
+           req.port_id);
 
-       ret = nvme_fc_register_remoteport(vha->nvme_local_port, &rport->req,
+       ret = nvme_fc_register_remoteport(vha->nvme_local_port, &req,
            &fcport->nvme_remote_port);
        if (ret) {
                ql_log(ql_log_warn, vha, 0x212e,
@@ -73,10 +68,11 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport)
                return ret;
        }
 
-       fcport->nvme_remote_port->private = fcport;
-       fcport->nvme_flag |= NVME_FLAG_REGISTERED;
+       rport = fcport->nvme_remote_port->private;
        rport->fcport = fcport;
        list_add_tail(&rport->list, &vha->nvme_rport_list);
+
+       fcport->nvme_flag |= NVME_FLAG_REGISTERED;
        return 0;
 }
 
@@ -174,26 +170,23 @@ static void qla_nvme_sp_done(void *ptr, int res)
        if (!atomic_dec_and_test(&sp->ref_count))
                return;
 
-       if (!(sp->fcport->nvme_flag & NVME_FLAG_REGISTERED))
-               goto rel;
-
-       if (unlikely(res == QLA_FUNCTION_FAILED))
-               fd->status = NVME_SC_INTERNAL;
-       else
+       if (res == QLA_SUCCESS)
                fd->status = 0;
+       else
+               fd->status = NVME_SC_INTERNAL;
 
        fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len;
        list_add_tail(&nvme->u.nvme.entry, &sp->qpair->nvme_done_list);
+
        return;
-rel:
-       qla2xxx_rel_qpair_sp(sp->qpair, sp);
 }
 
 static 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;
+       struct qla_nvme_rport *qla_rport = rport->private;
+       fc_port_t *fcport = qla_rport->fcport;
        srb_t *sp = priv->sp;
        int rval;
        struct qla_hw_data *ha = fcport->vha->hw;
@@ -218,7 +211,8 @@ static void qla_nvme_ls_complete(struct work_struct *work)
 static 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 = rport->private;
+       struct qla_nvme_rport *qla_rport = rport->private;
+       fc_port_t *fcport = qla_rport->fcport;
        struct srb_iocb   *nvme;
        struct nvme_private *priv = fd->private;
        struct scsi_qla_host *vha;
@@ -226,9 +220,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
        struct qla_hw_data *ha;
        srb_t           *sp;
 
-       if (!(fcport->nvme_flag & NVME_FLAG_REGISTERED))
-               return rval;
-
        vha = fcport->vha;
        ha = vha->hw;
        /* Alloc SRB structure */
@@ -275,7 +266,8 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
        struct nvme_private *priv = fd->private;
        srb_t *sp = priv->sp;
        int rval;
-       fc_port_t *fcport = rport->private;
+       struct qla_nvme_rport *qla_rport = rport->private;
+       fc_port_t *fcport = qla_rport->fcport;
        struct qla_hw_data *ha = fcport->vha->hw;
 
        rval = ha->isp_ops->abort_command(sp);
@@ -288,11 +280,10 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
 
 static 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 = hw_queue_handle;
+       unsigned long flags;
+       struct scsi_qla_host *vha = lport->private;
 
-       /* 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);
@@ -490,6 +481,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
        srb_t *sp;
        struct qla_qpair *qpair = hw_queue_handle;
        struct nvme_private *priv;
+       struct qla_nvme_rport *qla_rport = rport->private;
 
        if (!fd) {
                ql_log(ql_log_warn, NULL, 0x2134, "NO NVMe FCP request\n");
@@ -497,14 +489,14 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
        }
 
        priv = fd->private;
-       fcport = rport->private;
+       fcport = qla_rport->fcport;
        if (!fcport) {
                ql_log(ql_log_warn, NULL, 0x210e, "No fcport ptr\n");
                return rval;
        }
 
        vha = fcport->vha;
-       if ((!qpair) || (!(fcport->nvme_flag & NVME_FLAG_REGISTERED)))
+       if (!qpair)
                return -EBUSY;
 
        /* Alloc SRB structure */
@@ -547,22 +539,27 @@ static void qla_nvme_localport_delete(struct nvme_fc_local_port *lport)
 static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
 {
        fc_port_t *fcport;
-       struct nvme_rport *r_port, *trport;
+       struct qla_nvme_rport *qla_rport = rport->private, *trport;
 
-       fcport = rport->private;
+       fcport = qla_rport->fcport;
        fcport->nvme_remote_port = NULL;
        fcport->nvme_flag &= ~NVME_FLAG_REGISTERED;
 
-       list_for_each_entry_safe(r_port, trport,
+       list_for_each_entry_safe(qla_rport, trport,
            &fcport->vha->nvme_rport_list, list) {
-               if (r_port->fcport == fcport) {
-                       list_del(&r_port->list);
+               if (qla_rport->fcport == fcport) {
+                       list_del(&qla_rport->list);
                        break;
                }
        }
-       kfree(r_port);
        complete(&fcport->nvme_del_done);
 
+       if (!test_bit(UNLOADING, &fcport->vha->dpc_flags)) {
+               INIT_WORK(&fcport->free_work, qlt_free_session_done);
+               schedule_work(&fcport->free_work);
+       }
+
+       fcport->nvme_flag &= ~(NVME_FLAG_REGISTERED | NVME_FLAG_DELETING);
        ql_log(ql_log_info, fcport->vha, 0x2110,
            "remoteport_delete of %p completed.\n", fcport);
 }
@@ -582,7 +579,7 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = {
        .max_dif_sgl_segments = 64,
        .dma_boundary = 0xFFFFFFFF,
        .local_priv_sz  = 8,
-       .remote_priv_sz = 0,
+       .remote_priv_sz = sizeof(struct qla_nvme_rport),
        .lsrqst_priv_sz = sizeof(struct nvme_private),
        .fcprqst_priv_sz = sizeof(struct nvme_private),
 };
@@ -601,22 +598,6 @@ static int qla_nvme_wait_on_command(srb_t *sp)
        return ret;
 }
 
-static int qla_nvme_wait_on_rport_del(fc_port_t *fcport)
-{
-       int ret = QLA_SUCCESS;
-       int timeout;
-
-       timeout = wait_for_completion_timeout(&fcport->nvme_del_done,
-           msecs_to_jiffies(2000));
-       if (!timeout) {
-               ret = QLA_FUNCTION_FAILED;
-               ql_log(ql_log_info, fcport->vha, 0x2111,
-                   "timed out waiting for fcport=%p to delete\n", fcport);
-       }
-
-       return ret;
-}
-
 void qla_nvme_abort(struct qla_hw_data *ha, struct srb *sp)
 {
        int rval;
@@ -631,7 +612,7 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work)
 {
        struct fc_port *fcport = container_of(work, struct fc_port,
            nvme_del_work);
-       struct nvme_rport *rport, *trport;
+       struct qla_nvme_rport *qla_rport, *trport;
 
        if (!IS_ENABLED(CONFIG_NVME_FC))
                return;
@@ -639,51 +620,52 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work)
        ql_log(ql_log_warn, NULL, 0x2112,
            "%s: unregister remoteport on %p\n",__func__, fcport);
 
-       list_for_each_entry_safe(rport, trport,
+       list_for_each_entry_safe(qla_rport, trport,
            &fcport->vha->nvme_rport_list, list) {
-               if (rport->fcport == fcport) {
+               if (qla_rport->fcport == fcport) {
                        ql_log(ql_log_info, fcport->vha, 0x2113,
                            "%s: fcport=%p\n", __func__, fcport);
                        init_completion(&fcport->nvme_del_done);
                        nvme_fc_unregister_remoteport(
                            fcport->nvme_remote_port);
-                       qla_nvme_wait_on_rport_del(fcport);
+                       wait_for_completion(&fcport->nvme_del_done);
+                       break;
                }
        }
 }
 
 void qla_nvme_delete(struct scsi_qla_host *vha)
 {
-       struct nvme_rport *rport, *trport;
+       struct qla_nvme_rport *qla_rport, *trport;
        fc_port_t *fcport;
        int nv_ret;
 
        if (!IS_ENABLED(CONFIG_NVME_FC))
                return;
 
-       list_for_each_entry_safe(rport, trport, &vha->nvme_rport_list, list) {
-               fcport = rport->fcport;
+       list_for_each_entry_safe(qla_rport, trport,
+           &vha->nvme_rport_list, list) {
+               fcport = qla_rport->fcport;
 
                ql_log(ql_log_info, fcport->vha, 0x2114, "%s: fcport=%p\n",
                    __func__, fcport);
 
                init_completion(&fcport->nvme_del_done);
                nvme_fc_unregister_remoteport(fcport->nvme_remote_port);
-               qla_nvme_wait_on_rport_del(fcport);
+               wait_for_completion(&fcport->nvme_del_done);
        }
 
        if (vha->nvme_local_port) {
                init_completion(&vha->nvme_del_done);
+               ql_log(ql_log_info, vha, 0x2116,
+                       "unregister localport=%p\n",
+                       vha->nvme_local_port);
                nv_ret = nvme_fc_unregister_localport(vha->nvme_local_port);
-               if (nv_ret == 0)
-                       ql_log(ql_log_info, vha, 0x2116,
-                           "unregistered localport=%p\n",
-                           vha->nvme_local_port);
-               else
+               if (nv_ret)
                        ql_log(ql_log_info, vha, 0x2115,
                            "Unregister of localport failed\n");
-               wait_for_completion_timeout(&vha->nvme_del_done,
-                   msecs_to_jiffies(5000));
+               else
+                       wait_for_completion(&vha->nvme_del_done);
        }
 }
 
index 7f05fa1..7becfc1 100644 (file)
@@ -14,6 +14,9 @@
 
 #include "qla_def.h"
 
+/* default dev loss time (seconds) before transport tears down ctrl */
+#define NVME_FC_DEV_LOSS_TMO  30
+
 #define NVME_ATIO_CMD_OFF 32
 #define NVME_FIRST_PACKET_CMDLEN (64 - NVME_ATIO_CMD_OFF)
 #define Q2T_NVME_NUM_TAGS 2048
@@ -31,8 +34,7 @@ struct nvme_private {
        int comp_status;
 };
 
-struct nvme_rport {
-       struct nvme_fc_port_info req;
+struct qla_nvme_rport {
        struct list_head list;
        struct fc_port *fcport;
 };
index 41863a0..ead6813 100644 (file)
@@ -961,7 +961,7 @@ qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo)
            logo->cmd_count, res);
 }
 
-static void qlt_free_session_done(struct work_struct *work)
+void qlt_free_session_done(struct work_struct *work)
 {
        struct fc_port *sess = container_of(work, struct fc_port,
            free_work);
@@ -1169,11 +1169,14 @@ void qlt_unreg_sess(struct fc_port *sess)
        sess->last_rscn_gen = sess->rscn_gen;
        sess->last_login_gen = sess->login_gen;
 
-       if (sess->nvme_flag & NVME_FLAG_REGISTERED)
+       if (sess->nvme_flag & NVME_FLAG_REGISTERED &&
+           !(sess->nvme_flag & NVME_FLAG_DELETING)) {
+               sess->nvme_flag |= NVME_FLAG_DELETING;
                schedule_work(&sess->nvme_del_work);
-
-       INIT_WORK(&sess->free_work, qlt_free_session_done);
-       schedule_work(&sess->free_work);
+       } else {
+               INIT_WORK(&sess->free_work, qlt_free_session_done);
+               schedule_work(&sess->free_work);
+       }
 }
 EXPORT_SYMBOL(qlt_unreg_sess);
 
index bb67b5a..728ce74 100644 (file)
@@ -1016,7 +1016,7 @@ extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *, int);
 extern int __init qlt_init(void);
 extern void qlt_exit(void);
 extern void qlt_update_vp_map(struct scsi_qla_host *, int);
-
+extern void qlt_free_session_done(struct work_struct *);
 /*
  * This macro is used during early initializations when host->active_mode
  * is not set. Right now, ha value is ignored.