Commit 72b81768 authored by Martin K. Petersen's avatar Martin K. Petersen
Browse files

Merge patch series: "qla2xxx driver bug fixes"

Nilesh Javali <njavali@marvell.com> says:

Martin,

Please apply the qla2xxx driver bug fixes to the scsi tree at your
earliest convenience.

Link: https://lore.kernel.org/r/20230714070104.40052-1-njavali@marvell.com


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parents d417a6ff a31a596a
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -466,6 +466,7 @@ static inline be_id_t port_id_to_be_id(port_id_t port_id)
}

struct tmf_arg {
	struct list_head tmf_elem;
	struct qla_qpair *qpair;
	struct fc_port *fcport;
	struct scsi_qla_host *vha;
@@ -2541,7 +2542,6 @@ enum rscn_addr_format {
typedef struct fc_port {
	struct list_head list;
	struct scsi_qla_host *vha;
	struct list_head tmf_pending;

	unsigned int conf_compl_supported:1;
	unsigned int deleted:2;
@@ -2562,9 +2562,6 @@ typedef struct fc_port {
	unsigned int do_prli_nvme:1;

	uint8_t nvme_flag;
	uint8_t active_tmf;
#define MAX_ACTIVE_TMF 8

	uint8_t node_name[WWN_SIZE];
	uint8_t port_name[WWN_SIZE];
	port_id_t d_id;
@@ -4657,6 +4654,8 @@ struct qla_hw_data {
		uint32_t	flt_region_aux_img_status_sec;
	};
	uint8_t         active_image;
	uint8_t active_tmf;
#define MAX_ACTIVE_TMF 8

	/* Needed for BEACON */
	uint16_t        beacon_blink_led;
@@ -4671,6 +4670,8 @@ struct qla_hw_data {

	struct qla_msix_entry *msix_entries;

	struct list_head tmf_pending;
	struct list_head tmf_active;
	struct list_head        vp_list;        /* list of VP */
	unsigned long   vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) /
			sizeof(unsigned long)];
+1 −0
Original line number Diff line number Diff line
@@ -143,6 +143,7 @@ void qla_edif_sess_down(struct scsi_qla_host *vha, struct fc_port *sess);
void qla_edif_clear_appdata(struct scsi_qla_host *vha,
			    struct fc_port *fcport);
const char *sc_to_str(uint16_t cmd);
void qla_adjust_iocb_limit(scsi_qla_host_t *vha);

/*
 * Global Data in qla_os.c source file.
+135 −82
Original line number Diff line number Diff line
@@ -508,6 +508,7 @@ static
void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea)
{
	struct fc_port *fcport = ea->fcport;
	unsigned long flags;

	ql_dbg(ql_dbg_disc, vha, 0x20d2,
	    "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n",
@@ -522,9 +523,15 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea)
		ql_dbg(ql_dbg_disc, vha, 0x2066,
		    "%s %8phC: adisc fail: post delete\n",
		    __func__, ea->fcport->port_name);

		spin_lock_irqsave(&vha->work_lock, flags);
		/* deleted = 0 & logout_on_delete = force fw cleanup */
		if (fcport->deleted == QLA_SESS_DELETED)
			fcport->deleted = 0;

		fcport->logout_on_delete = 1;
		spin_unlock_irqrestore(&vha->work_lock, flags);

		qlt_schedule_sess_for_deletion(ea->fcport);
		return;
	}
@@ -1134,7 +1141,7 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport)
	u16 *mb;

	if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT))
		return rval;
		goto done;

	ql_dbg(ql_dbg_disc, vha, 0x20d9,
	    "Async-gnlist WWPN %8phC \n", fcport->port_name);
@@ -1188,8 +1195,9 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport)
done_free_sp:
	/* ref: INIT */
	kref_put(&sp->cmd_kref, qla2x00_sp_release);
	fcport->flags &= ~(FCF_ASYNC_SENT);
done:
	fcport->flags &= ~(FCF_ASYNC_ACTIVE | FCF_ASYNC_SENT);
	fcport->flags &= ~(FCF_ASYNC_ACTIVE);
	return rval;
}

@@ -1446,7 +1454,6 @@ void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)

	spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
	ea->fcport->login_gen++;
	ea->fcport->deleted = 0;
	ea->fcport->logout_on_delete = 1;

	if (!ea->fcport->login_succ && !IS_SW_RESV_ADDR(ea->fcport->d_id)) {
@@ -1996,12 +2003,11 @@ qla2x00_tmf_iocb_timeout(void *data)
	int rc, h;
	unsigned long flags;

	if (sp->type == SRB_MARKER) {
		complete(&tmf->u.tmf.comp);
		return;
	}

	if (sp->type == SRB_MARKER)
		rc = QLA_FUNCTION_FAILED;
	else
		rc = qla24xx_async_abort_cmd(sp, false);

	if (rc) {
		spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
		for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) {
@@ -2032,10 +2038,14 @@ static void qla_marker_sp_done(srb_t *sp, int res)
	complete(&tmf->u.tmf.comp);
}

#define  START_SP_W_RETRIES(_sp, _rval) \
#define  START_SP_W_RETRIES(_sp, _rval, _chip_gen, _login_gen) \
{\
	int cnt = 5; \
	do { \
		if (_chip_gen != sp->vha->hw->chip_reset || _login_gen != sp->fcport->login_gen) {\
			_rval = EINVAL; \
			break; \
		} \
		_rval = qla2x00_start_sp(_sp); \
		if (_rval == EAGAIN) \
			msleep(1); \
@@ -2058,6 +2068,7 @@ qla26xx_marker(struct tmf_arg *arg)
	srb_t *sp;
	int rval = QLA_FUNCTION_FAILED;
	fc_port_t *fcport = arg->fcport;
	u32 chip_gen, login_gen;

	if (TMF_NOT_READY(arg->fcport)) {
		ql_dbg(ql_dbg_taskm, vha, 0x8039,
@@ -2067,6 +2078,9 @@ qla26xx_marker(struct tmf_arg *arg)
		return QLA_SUSPENDED;
	}

	chip_gen = vha->hw->chip_reset;
	login_gen = fcport->login_gen;

	/* ref: INIT */
	sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
	if (!sp)
@@ -2084,7 +2098,7 @@ qla26xx_marker(struct tmf_arg *arg)
	tm_iocb->u.tmf.loop_id = fcport->loop_id;
	tm_iocb->u.tmf.vp_index = vha->vp_idx;

	START_SP_W_RETRIES(sp, rval);
	START_SP_W_RETRIES(sp, rval, chip_gen, login_gen);

	ql_dbg(ql_dbg_taskm, vha, 0x8006,
	    "Async-marker hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
@@ -2123,6 +2137,17 @@ static void qla2x00_tmf_sp_done(srb_t *sp, int res)
	complete(&tmf->u.tmf.comp);
}

static int qla_tmf_wait(struct tmf_arg *arg)
{
	/* there are only 2 types of error handling that reaches here, lun or target reset */
	if (arg->flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET | TCF_CLEAR_TASK_SET))
		return qla2x00_eh_wait_for_pending_commands(arg->vha,
		    arg->fcport->d_id.b24, arg->lun, WAIT_LUN);
	else
		return qla2x00_eh_wait_for_pending_commands(arg->vha,
		    arg->fcport->d_id.b24, arg->lun, WAIT_TARGET);
}

static int
__qla2x00_async_tm_cmd(struct tmf_arg *arg)
{
@@ -2130,8 +2155,9 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
	struct srb_iocb *tm_iocb;
	srb_t *sp;
	int rval = QLA_FUNCTION_FAILED;

	fc_port_t *fcport = arg->fcport;
	u32 chip_gen, login_gen;
	u64 jif;

	if (TMF_NOT_READY(arg->fcport)) {
		ql_dbg(ql_dbg_taskm, vha, 0x8032,
@@ -2141,6 +2167,9 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
		return QLA_SUSPENDED;
	}

	chip_gen = vha->hw->chip_reset;
	login_gen = fcport->login_gen;

	/* ref: INIT */
	sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
	if (!sp)
@@ -2158,7 +2187,7 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
	tm_iocb->u.tmf.flags = arg->flags;
	tm_iocb->u.tmf.lun = arg->lun;

	START_SP_W_RETRIES(sp, rval);
	START_SP_W_RETRIES(sp, rval, chip_gen, login_gen);

	ql_dbg(ql_dbg_taskm, vha, 0x802f,
	    "Async-tmf hdl=%x loop-id=%x portid=%06x ctrl=%x lun=%lld qp=%d rval=%x.\n",
@@ -2176,8 +2205,24 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
		    "TM IOCB failed (%x).\n", rval);
	}

	if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw))
	if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
		jif = jiffies;
		if (qla_tmf_wait(arg)) {
			ql_log(ql_log_info, vha, 0x803e,
			       "Waited %u ms Nexus=%ld:%06x:%llu.\n",
			       jiffies_to_msecs(jiffies - jif), vha->host_no,
			       fcport->d_id.b24, arg->lun);
		}

		if (chip_gen == vha->hw->chip_reset && login_gen == fcport->login_gen) {
			rval = qla26xx_marker(arg);
		} else {
			ql_log(ql_log_info, vha, 0x803e,
			       "Skip Marker due to disruption. Nexus=%ld:%06x:%llu.\n",
			       vha->host_no, fcport->d_id.b24, arg->lun);
			rval = QLA_FUNCTION_FAILED;
		}
	}

done_free_sp:
	/* ref: INIT */
@@ -2186,30 +2231,42 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
	return rval;
}

static void qla_put_tmf(fc_port_t *fcport)
static void qla_put_tmf(struct tmf_arg *arg)
{
	struct scsi_qla_host *vha = fcport->vha;
	struct scsi_qla_host *vha = arg->vha;
	struct qla_hw_data *ha = vha->hw;
	unsigned long flags;

	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
	fcport->active_tmf--;
	ha->active_tmf--;
	list_del(&arg->tmf_elem);
	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
}

static
int qla_get_tmf(fc_port_t *fcport)
int qla_get_tmf(struct tmf_arg *arg)
{
	struct scsi_qla_host *vha = fcport->vha;
	struct scsi_qla_host *vha = arg->vha;
	struct qla_hw_data *ha = vha->hw;
	unsigned long flags;
	fc_port_t *fcport = arg->fcport;
	int rc = 0;
	LIST_HEAD(tmf_elem);
	struct tmf_arg *t;

	spin_lock_irqsave(&ha->tgt.sess_lock, flags);
	list_add_tail(&tmf_elem, &fcport->tmf_pending);
	list_for_each_entry(t, &ha->tmf_active, tmf_elem) {
		if (t->fcport == arg->fcport && t->lun == arg->lun) {
			/* reject duplicate TMF */
			ql_log(ql_log_warn, vha, 0x802c,
			       "found duplicate TMF.  Nexus=%ld:%06x:%llu.\n",
			       vha->host_no, fcport->d_id.b24, arg->lun);
			spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
			return -EINVAL;
		}
	}

	while (fcport->active_tmf >= MAX_ACTIVE_TMF) {
	list_add_tail(&arg->tmf_elem, &ha->tmf_pending);
	while (ha->active_tmf >= MAX_ACTIVE_TMF) {
		spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);

		msleep(1);
@@ -2221,15 +2278,17 @@ int qla_get_tmf(fc_port_t *fcport)
			rc = EIO;
			break;
		}
		if (fcport->active_tmf < MAX_ACTIVE_TMF &&
		    list_is_first(&tmf_elem, &fcport->tmf_pending))
		if (ha->active_tmf < MAX_ACTIVE_TMF &&
		    list_is_first(&arg->tmf_elem, &ha->tmf_pending))
			break;
	}

	list_del(&tmf_elem);
	list_del(&arg->tmf_elem);

	if (!rc)
		fcport->active_tmf++;
	if (!rc) {
		ha->active_tmf++;
		list_add_tail(&arg->tmf_elem, &ha->tmf_active);
	}

	spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);

@@ -2241,9 +2300,8 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
		     uint32_t tag)
{
	struct scsi_qla_host *vha = fcport->vha;
	struct qla_qpair *qpair;
	struct tmf_arg a;
	int i, rval = QLA_SUCCESS;
	int rval = QLA_SUCCESS;

	if (TMF_NOT_READY(fcport))
		return QLA_SUSPENDED;
@@ -2251,47 +2309,22 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
	a.vha = fcport->vha;
	a.fcport = fcport;
	a.lun = lun;
	a.flags = flags;
	INIT_LIST_HEAD(&a.tmf_elem);

	if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
		a.modifier = MK_SYNC_ID_LUN;

		if (qla_get_tmf(fcport))
			return QLA_FUNCTION_FAILED;
	} else {
		a.modifier = MK_SYNC_ID;
	}

	if (vha->hw->mqenable) {
		for (i = 0; i < vha->hw->num_qpairs; i++) {
			qpair = vha->hw->queue_pair_map[i];
			if (!qpair)
				continue;

			if (TMF_NOT_READY(fcport)) {
				ql_log(ql_log_warn, vha, 0x8026,
				    "Unable to send TM due to disruption.\n");
				rval = QLA_SUSPENDED;
				break;
			}

			a.qpair = qpair;
			a.flags = flags|TCF_NOTMCMD_TO_TARGET;
			rval = __qla2x00_async_tm_cmd(&a);
			if (rval)
				break;
		}
	}

	if (rval)
		goto bailout;
	if (qla_get_tmf(&a))
		return QLA_FUNCTION_FAILED;

	a.qpair = vha->hw->base_qpair;
	a.flags = flags;
	rval = __qla2x00_async_tm_cmd(&a);

bailout:
	if (a.modifier == MK_SYNC_ID_LUN)
		qla_put_tmf(fcport);

	qla_put_tmf(&a);
	return rval;
}

@@ -4147,41 +4180,55 @@ qla24xx_detect_sfp(scsi_qla_host_t *vha)
	return ha->flags.lr_detected;
}

void qla_init_iocb_limit(scsi_qla_host_t *vha)
static void __qla_adjust_iocb_limit(struct qla_qpair *qpair)
{
	u16 i, num_qps;
	u32 limit;
	struct qla_hw_data *ha = vha->hw;
	u8 num_qps;
	u16 limit;
	struct qla_hw_data *ha = qpair->vha->hw;

	num_qps = ha->num_qpairs + 1;
	limit = (ha->orig_fw_iocb_count * QLA_IOCB_PCT_LIMIT) / 100;

	ha->base_qpair->fwres.iocbs_total = ha->orig_fw_iocb_count;
	ha->base_qpair->fwres.iocbs_limit = limit;
	ha->base_qpair->fwres.iocbs_qp_limit = limit / num_qps;
	ha->base_qpair->fwres.iocbs_used = 0;
	qpair->fwres.iocbs_total = ha->orig_fw_iocb_count;
	qpair->fwres.iocbs_limit = limit;
	qpair->fwres.iocbs_qp_limit = limit / num_qps;

	ha->base_qpair->fwres.exch_total = ha->orig_fw_xcb_count;
	ha->base_qpair->fwres.exch_limit = (ha->orig_fw_xcb_count *
	qpair->fwres.exch_total = ha->orig_fw_xcb_count;
	qpair->fwres.exch_limit = (ha->orig_fw_xcb_count *
				   QLA_IOCB_PCT_LIMIT) / 100;
}

void qla_init_iocb_limit(scsi_qla_host_t *vha)
{
	u8 i;
	struct qla_hw_data *ha = vha->hw;

	 __qla_adjust_iocb_limit(ha->base_qpair);
	ha->base_qpair->fwres.iocbs_used = 0;
	ha->base_qpair->fwres.exch_used  = 0;

	for (i = 0; i < ha->max_qpairs; i++) {
		if (ha->queue_pair_map[i])  {
			ha->queue_pair_map[i]->fwres.iocbs_total =
				ha->orig_fw_iocb_count;
			ha->queue_pair_map[i]->fwres.iocbs_limit = limit;
			ha->queue_pair_map[i]->fwres.iocbs_qp_limit =
				limit / num_qps;
			__qla_adjust_iocb_limit(ha->queue_pair_map[i]);
			ha->queue_pair_map[i]->fwres.iocbs_used = 0;
			ha->queue_pair_map[i]->fwres.exch_total = ha->orig_fw_xcb_count;
			ha->queue_pair_map[i]->fwres.exch_limit =
				(ha->orig_fw_xcb_count * QLA_IOCB_PCT_LIMIT) / 100;
			ha->queue_pair_map[i]->fwres.exch_used = 0;
		}
	}
}

void qla_adjust_iocb_limit(scsi_qla_host_t *vha)
{
	u8 i;
	struct qla_hw_data *ha = vha->hw;

	__qla_adjust_iocb_limit(ha->base_qpair);

	for (i = 0; i < ha->max_qpairs; i++) {
		if (ha->queue_pair_map[i])
			__qla_adjust_iocb_limit(ha->queue_pair_map[i]);
	}
}

/**
 * qla2x00_setup_chip() - Load and start RISC firmware.
 * @vha: HA context
@@ -4777,15 +4824,16 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
	if (ha->flags.edif_enabled)
		mid_init_cb->init_cb.frame_payload_size = cpu_to_le16(ELS_MAX_PAYLOAD);

	QLA_FW_STARTED(ha);
	rval = qla2x00_init_firmware(vha, ha->init_cb_size);
next_check:
	if (rval) {
		QLA_FW_STOPPED(ha);
		ql_log(ql_log_fatal, vha, 0x00d2,
		    "Init Firmware **** FAILED ****.\n");
	} else {
		ql_dbg(ql_dbg_init, vha, 0x00d3,
		    "Init Firmware -- success.\n");
		QLA_FW_STARTED(ha);
		vha->u_ql2xexchoffld = vha->u_ql2xiniexchg = 0;
	}

@@ -5506,7 +5554,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
	INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
	INIT_LIST_HEAD(&fcport->gnl_entry);
	INIT_LIST_HEAD(&fcport->list);
	INIT_LIST_HEAD(&fcport->tmf_pending);

	INIT_LIST_HEAD(&fcport->sess_cmd_list);
	spin_lock_init(&fcport->sess_cmd_lock);
@@ -6090,6 +6137,8 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
void
qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
{
	unsigned long flags;

	if (IS_SW_RESV_ADDR(fcport->d_id))
		return;

@@ -6099,7 +6148,11 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
	qla2x00_set_fcport_disc_state(fcport, DSC_UPD_FCPORT);
	fcport->login_retry = vha->hw->login_retry_count;
	fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);

	spin_lock_irqsave(&vha->work_lock, flags);
	fcport->deleted = 0;
	spin_unlock_irqrestore(&vha->work_lock, flags);

	if (vha->hw->current_topology == ISP_CFG_NL)
		fcport->logout_on_delete = 0;
	else
+1 −0
Original line number Diff line number Diff line
@@ -3881,6 +3881,7 @@ qla_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk)
{
	mrk->entry_type = MARKER_TYPE;
	mrk->modifier = sp->u.iocb_cmd.u.tmf.modifier;
	mrk->handle = make_handle(sp->qpair->req->id, sp->handle);
	if (sp->u.iocb_cmd.u.tmf.modifier != MK_SYNC_ALL) {
		mrk->nport_handle = cpu_to_le16(sp->u.iocb_cmd.u.tmf.loop_id);
		int_to_scsilun(sp->u.iocb_cmd.u.tmf.lun, (struct scsi_lun *)&mrk->lun);
+5 −2
Original line number Diff line number Diff line
@@ -1121,8 +1121,12 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
	unsigned long	flags;
	fc_port_t	*fcport = NULL;

	if (!vha->hw->flags.fw_started)
	if (!vha->hw->flags.fw_started) {
		ql_log(ql_log_warn, vha, 0x50ff,
		    "Dropping AEN - %04x %04x %04x %04x.\n",
		    mb[0], mb[1], mb[2], mb[3]);
		return;
	}

	/* Setup to process RIO completion. */
	handle_cnt = 0;
@@ -2539,7 +2543,6 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
	case CS_PORT_BUSY:
	case CS_INCOMPLETE:
	case CS_PORT_UNAVAILABLE:
	case CS_TIMEOUT:
	case CS_RESET:
		if (atomic_read(&fcport->state) == FCS_ONLINE) {
			ql_dbg(ql_dbg_disc, fcport->vha, 0x3021,
Loading