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: 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>
This commit is contained in:
Darren Trapp 2018-03-20 23:09:32 -07:00 committed by Martin K. Petersen
parent dbe18018e3
commit 9dd9686b14
7 changed files with 87 additions and 90 deletions

View File

@ -2355,6 +2355,7 @@ typedef struct fc_port {
#define NVME_PRLI_SP_DISCOVERY BIT_3 #define NVME_PRLI_SP_DISCOVERY BIT_3
uint8_t nvme_flag; uint8_t nvme_flag;
#define NVME_FLAG_REGISTERED 4 #define NVME_FLAG_REGISTERED 4
#define NVME_FLAG_DELETING 2
struct fc_port *conflict; struct fc_port *conflict;
unsigned char logout_completed; unsigned char logout_completed;

View File

@ -5517,6 +5517,14 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
break; 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) { if (found) {
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
continue; continue;

View File

@ -1910,7 +1910,7 @@ qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
} else { } else {
switch (le16_to_cpu(sts->comp_status)) { switch (le16_to_cpu(sts->comp_status)) {
case CS_COMPLETE: case CS_COMPLETE:
ret = 0; ret = QLA_SUCCESS;
break; break;
case CS_ABORTED: 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", "NVME-%s ERR Handling - hdl=%x completion status(%x) resid=%x ox_id=%x\n",
sp->name, sp->handle, sts->comp_status, sp->name, sp->handle, sts->comp_status,
le32_to_cpu(sts->residual_len), sts->ox_id); 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; ret = QLA_ABORTED;
break; break;

View 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) 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; int ret;
if (!IS_ENABLED(CONFIG_NVME_FC)) if (!IS_ENABLED(CONFIG_NVME_FC))
return 0; return 0;
if (fcport->nvme_flag & NVME_FLAG_REGISTERED)
return 0;
if (!vha->flags.nvme_enabled) { if (!vha->flags.nvme_enabled) {
ql_log(ql_log_info, vha, 0x2100, ql_log(ql_log_info, vha, 0x2100,
"%s: Not registering target since Host NVME is not enabled\n", "%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 & 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; return 0;
INIT_WORK(&fcport->nvme_del_work, qla_nvme_unregister_remote_port); 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); memset(&req, 0, sizeof(struct nvme_fc_port_info));
rport->req.node_name = wwn_to_u64(fcport->node_name); req.port_name = wwn_to_u64(fcport->port_name);
rport->req.port_role = 0; 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) 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) 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) 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, ql_log(ql_log_info, vha, 0x2102,
"%s: traddr=nn-0x%016llx:pn-0x%016llx PortID:%06x\n", "%s: traddr=nn-0x%016llx:pn-0x%016llx PortID:%06x\n",
__func__, rport->req.node_name, rport->req.port_name, __func__, req.node_name, req.port_name,
rport->req.port_id); 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); &fcport->nvme_remote_port);
if (ret) { if (ret) {
ql_log(ql_log_warn, vha, 0x212e, 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; return ret;
} }
fcport->nvme_remote_port->private = fcport; rport = fcport->nvme_remote_port->private;
fcport->nvme_flag |= NVME_FLAG_REGISTERED;
rport->fcport = fcport; rport->fcport = fcport;
list_add_tail(&rport->list, &vha->nvme_rport_list); list_add_tail(&rport->list, &vha->nvme_rport_list);
fcport->nvme_flag |= NVME_FLAG_REGISTERED;
return 0; return 0;
} }
@ -174,26 +170,23 @@ static void qla_nvme_sp_done(void *ptr, int res)
if (!atomic_dec_and_test(&sp->ref_count)) if (!atomic_dec_and_test(&sp->ref_count))
return; return;
if (!(sp->fcport->nvme_flag & NVME_FLAG_REGISTERED)) if (res == QLA_SUCCESS)
goto rel;
if (unlikely(res == QLA_FUNCTION_FAILED))
fd->status = NVME_SC_INTERNAL;
else
fd->status = 0; fd->status = 0;
else
fd->status = NVME_SC_INTERNAL;
fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len; fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len;
list_add_tail(&nvme->u.nvme.entry, &sp->qpair->nvme_done_list); list_add_tail(&nvme->u.nvme.entry, &sp->qpair->nvme_done_list);
return; return;
rel:
qla2xxx_rel_qpair_sp(sp->qpair, sp);
} }
static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport, 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_fc_remote_port *rport, struct nvmefc_ls_req *fd)
{ {
struct nvme_private *priv = fd->private; 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; srb_t *sp = priv->sp;
int rval; int rval;
struct qla_hw_data *ha = fcport->vha->hw; 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, static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) 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 srb_iocb *nvme;
struct nvme_private *priv = fd->private; struct nvme_private *priv = fd->private;
struct scsi_qla_host *vha; 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; struct qla_hw_data *ha;
srb_t *sp; srb_t *sp;
if (!(fcport->nvme_flag & NVME_FLAG_REGISTERED))
return rval;
vha = fcport->vha; vha = fcport->vha;
ha = vha->hw; ha = vha->hw;
/* Alloc SRB structure */ /* 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; struct nvme_private *priv = fd->private;
srb_t *sp = priv->sp; srb_t *sp = priv->sp;
int rval; 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; struct qla_hw_data *ha = fcport->vha->hw;
rval = ha->isp_ops->abort_command(sp); 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) 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; 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); spin_lock_irqsave(&qpair->qp_lock, flags);
qla24xx_process_response_queue(vha, qpair->rsp); qla24xx_process_response_queue(vha, qpair->rsp);
spin_unlock_irqrestore(&qpair->qp_lock, flags); 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; srb_t *sp;
struct qla_qpair *qpair = hw_queue_handle; struct qla_qpair *qpair = hw_queue_handle;
struct nvme_private *priv; struct nvme_private *priv;
struct qla_nvme_rport *qla_rport = rport->private;
if (!fd) { if (!fd) {
ql_log(ql_log_warn, NULL, 0x2134, "NO NVMe FCP request\n"); 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; priv = fd->private;
fcport = rport->private; fcport = qla_rport->fcport;
if (!fcport) { if (!fcport) {
ql_log(ql_log_warn, NULL, 0x210e, "No fcport ptr\n"); ql_log(ql_log_warn, NULL, 0x210e, "No fcport ptr\n");
return rval; return rval;
} }
vha = fcport->vha; vha = fcport->vha;
if ((!qpair) || (!(fcport->nvme_flag & NVME_FLAG_REGISTERED))) if (!qpair)
return -EBUSY; return -EBUSY;
/* Alloc SRB structure */ /* 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) static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
{ {
fc_port_t *fcport; 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_remote_port = NULL;
fcport->nvme_flag &= ~NVME_FLAG_REGISTERED; 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) { &fcport->vha->nvme_rport_list, list) {
if (r_port->fcport == fcport) { if (qla_rport->fcport == fcport) {
list_del(&r_port->list); list_del(&qla_rport->list);
break; break;
} }
} }
kfree(r_port);
complete(&fcport->nvme_del_done); 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, ql_log(ql_log_info, fcport->vha, 0x2110,
"remoteport_delete of %p completed.\n", fcport); "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, .max_dif_sgl_segments = 64,
.dma_boundary = 0xFFFFFFFF, .dma_boundary = 0xFFFFFFFF,
.local_priv_sz = 8, .local_priv_sz = 8,
.remote_priv_sz = 0, .remote_priv_sz = sizeof(struct qla_nvme_rport),
.lsrqst_priv_sz = sizeof(struct nvme_private), .lsrqst_priv_sz = sizeof(struct nvme_private),
.fcprqst_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; 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) void qla_nvme_abort(struct qla_hw_data *ha, struct srb *sp)
{ {
int rval; 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, struct fc_port *fcport = container_of(work, struct fc_port,
nvme_del_work); nvme_del_work);
struct nvme_rport *rport, *trport; struct qla_nvme_rport *qla_rport, *trport;
if (!IS_ENABLED(CONFIG_NVME_FC)) if (!IS_ENABLED(CONFIG_NVME_FC))
return; return;
@ -639,51 +620,52 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work)
ql_log(ql_log_warn, NULL, 0x2112, ql_log(ql_log_warn, NULL, 0x2112,
"%s: unregister remoteport on %p\n",__func__, fcport); "%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) { &fcport->vha->nvme_rport_list, list) {
if (rport->fcport == fcport) { if (qla_rport->fcport == fcport) {
ql_log(ql_log_info, fcport->vha, 0x2113, ql_log(ql_log_info, fcport->vha, 0x2113,
"%s: fcport=%p\n", __func__, fcport); "%s: fcport=%p\n", __func__, fcport);
init_completion(&fcport->nvme_del_done); init_completion(&fcport->nvme_del_done);
nvme_fc_unregister_remoteport( nvme_fc_unregister_remoteport(
fcport->nvme_remote_port); 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) 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; fc_port_t *fcport;
int nv_ret; int nv_ret;
if (!IS_ENABLED(CONFIG_NVME_FC)) if (!IS_ENABLED(CONFIG_NVME_FC))
return; return;
list_for_each_entry_safe(rport, trport, &vha->nvme_rport_list, list) { list_for_each_entry_safe(qla_rport, trport,
fcport = rport->fcport; &vha->nvme_rport_list, list) {
fcport = qla_rport->fcport;
ql_log(ql_log_info, fcport->vha, 0x2114, "%s: fcport=%p\n", ql_log(ql_log_info, fcport->vha, 0x2114, "%s: fcport=%p\n",
__func__, fcport); __func__, fcport);
init_completion(&fcport->nvme_del_done); init_completion(&fcport->nvme_del_done);
nvme_fc_unregister_remoteport(fcport->nvme_remote_port); 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) { if (vha->nvme_local_port) {
init_completion(&vha->nvme_del_done); 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); nv_ret = nvme_fc_unregister_localport(vha->nvme_local_port);
if (nv_ret == 0) if (nv_ret)
ql_log(ql_log_info, vha, 0x2116,
"unregistered localport=%p\n",
vha->nvme_local_port);
else
ql_log(ql_log_info, vha, 0x2115, ql_log(ql_log_info, vha, 0x2115,
"Unregister of localport failed\n"); "Unregister of localport failed\n");
wait_for_completion_timeout(&vha->nvme_del_done, else
msecs_to_jiffies(5000)); wait_for_completion(&vha->nvme_del_done);
} }
} }

View File

@ -14,6 +14,9 @@
#include "qla_def.h" #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_ATIO_CMD_OFF 32
#define NVME_FIRST_PACKET_CMDLEN (64 - NVME_ATIO_CMD_OFF) #define NVME_FIRST_PACKET_CMDLEN (64 - NVME_ATIO_CMD_OFF)
#define Q2T_NVME_NUM_TAGS 2048 #define Q2T_NVME_NUM_TAGS 2048
@ -31,8 +34,7 @@ struct nvme_private {
int comp_status; int comp_status;
}; };
struct nvme_rport { struct qla_nvme_rport {
struct nvme_fc_port_info req;
struct list_head list; struct list_head list;
struct fc_port *fcport; struct fc_port *fcport;
}; };

View File

@ -961,7 +961,7 @@ qlt_send_first_logo(struct scsi_qla_host *vha, qlt_port_logo_t *logo)
logo->cmd_count, res); 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, struct fc_port *sess = container_of(work, struct fc_port,
free_work); free_work);
@ -1169,11 +1169,14 @@ void qlt_unreg_sess(struct fc_port *sess)
sess->last_rscn_gen = sess->rscn_gen; sess->last_rscn_gen = sess->rscn_gen;
sess->last_login_gen = sess->login_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); schedule_work(&sess->nvme_del_work);
} else {
INIT_WORK(&sess->free_work, qlt_free_session_done); INIT_WORK(&sess->free_work, qlt_free_session_done);
schedule_work(&sess->free_work); schedule_work(&sess->free_work);
}
} }
EXPORT_SYMBOL(qlt_unreg_sess); EXPORT_SYMBOL(qlt_unreg_sess);

View 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 int __init qlt_init(void);
extern void qlt_exit(void); extern void qlt_exit(void);
extern void qlt_update_vp_map(struct scsi_qla_host *, int); 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 * This macro is used during early initializations when host->active_mode
* is not set. Right now, ha value is ignored. * is not set. Right now, ha value is ignored.