Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9dd9686b authored by Darren Trapp's avatar Darren Trapp Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Add changes for devloss timeout in driver



Add support for error recovery within devloss timeout, now that
FC-NVMe transport support devloss timeout.

Signed-off-by: default avatarDarren Trapp <darren.trapp@cavium.com>
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@cavium.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent dbe18018
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+8 −0
Original line number Diff line number Diff line
@@ -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;
+3 −2
Original line number Diff line number Diff line
@@ -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;

+62 −80
Original line number Diff line number Diff line
@@ -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);
		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",
			"unregister localport=%p\n",
			vha->nvme_local_port);
		else
		nv_ret = nvme_fc_unregister_localport(vha->nvme_local_port);
		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);
	}
}

+4 −2
Original line number Diff line number Diff line
@@ -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;
};
Loading