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

Commit 48acad09 authored by Quinn Tran's avatar Quinn Tran Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Fix N2N link re-connect



In case of N2N connect, sg_reset for bus/device/host was causing driver and
firmware state to go out of sync.  This patch fixes this link instablity
when reconnect is attempted after link flap.

Signed-off-by: default avatarQuinn Tran <quinn.tran@cavium.com>
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 4ae5716b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -377,6 +377,7 @@ struct srb_iocb {
#define SRB_LOGIN_COND_PLOGI	BIT_1
#define SRB_LOGIN_SKIP_PRLI	BIT_2
#define SRB_LOGIN_NVME_PRLI	BIT_3
#define SRB_LOGIN_PRLI_ONLY	BIT_4
			uint16_t data[2];
			u32 iop[2];
		} logio;
@@ -4236,7 +4237,7 @@ typedef struct scsi_qla_host {
#define FCOE_CTX_RESET_NEEDED	18	/* Initiate FCoE context reset */
#define MPI_RESET_NEEDED	19	/* Initiate MPI FW reset */
#define ISP_QUIESCE_NEEDED	20	/* Driver need some quiescence */
#define FREE_BIT 21
#define N2N_LINK_RESET		21
#define PORT_UPDATE_NEEDED	22
#define FX00_RESET_RECOVERY	23
#define FX00_TARGET_SCAN	24
+150 −77
Original line number Diff line number Diff line
@@ -160,6 +160,22 @@ qla2x00_async_login_sp_done(void *ptr, int res)
	sp->free(sp);
}

static inline bool
fcport_is_smaller(fc_port_t *fcport)
{
	if (wwn_to_u64(fcport->port_name) <
	    wwn_to_u64(fcport->vha->port_name))
		return true;
	else
		return false;
}

static inline bool
fcport_is_bigger(fc_port_t *fcport)
{
	return !fcport_is_smaller(fcport);
}

int
qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
    uint16_t *data)
@@ -189,6 +205,9 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
	qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);

	sp->done = qla2x00_async_login_sp_done;
	if (N2N_TOPO(fcport->vha->hw) && fcport_is_bigger(fcport)) {
		lio->u.logio.flags |= SRB_LOGIN_PRLI_ONLY;
	} else {
		lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;

		if (fcport->fc4f_nvme)
@@ -196,6 +215,8 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,

		if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
			lio->u.logio.flags |= SRB_LOGIN_RETRIED;
	}

	rval = qla2x00_start_sp(sp);
	if (rval != QLA_SUCCESS) {
		fcport->flags |= FCF_LOGIN_NEEDED;
@@ -497,15 +518,18 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
	for (i = 0; i < n; i++) {
		e = &vha->gnl.l[i];
		wwn = wwn_to_u64(e->port_name);
		id.b.domain = e->port_id[2];
		id.b.area = e->port_id[1];
		id.b.al_pa = e->port_id[0];
		id.b.rsvd_1 = 0;

		if (memcmp((u8 *)&wwn, fcport->port_name, WWN_SIZE))
			continue;

		if (IS_SW_RESV_ADDR(id))
			continue;

		found = 1;
		id.b.domain = e->port_id[2];
		id.b.area = e->port_id[1];
		id.b.al_pa = e->port_id[0];
		id.b.rsvd_1 = 0;

		loop_id = le16_to_cpu(e->nport_handle);
		loop_id = (loop_id & 0x7fff);
@@ -518,15 +542,19 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
		    fcport->d_id.b.domain, fcport->d_id.b.area,
		    fcport->d_id.b.al_pa, loop_id, fcport->loop_id);

		switch (fcport->disc_state) {
		case DSC_DELETE_PEND:
		case DSC_DELETED:
			break;
		default:
			if ((id.b24 != fcport->d_id.b24) ||
			    ((fcport->loop_id != FC_NO_LOOP_ID) &&
				(fcport->loop_id != loop_id))) {
			ql_dbg(ql_dbg_disc, vha, 0x20e3,
			    "%s %d %8phC post del sess\n",
			    __func__, __LINE__, fcport->port_name);
				qlt_schedule_sess_for_deletion(fcport);
				return;
			}
			break;
		}

		fcport->loop_id = loop_id;

@@ -549,36 +577,77 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
		else
			current_login_state = e->current_login_state & 0xf;

		switch (vha->hw->current_topology) {
		default:
			switch (current_login_state) {
			case DSC_LS_PRLI_COMP:
			ql_dbg(ql_dbg_disc, vha, 0x20e4,
			    "%s %d %8phC post gpdb\n",
				ql_dbg(ql_dbg_disc + ql_dbg_verbose,
				    vha, 0x20e4, "%s %d %8phC post gpdb\n",
				    __func__, __LINE__, fcport->port_name);

				if ((e->prli_svc_param_word_3[0] & BIT_4) == 0)
					fcport->port_type = FCT_INITIATOR;
				else
					fcport->port_type = FCT_TARGET;

				data[0] = data[1] = 0;
			qla2x00_post_async_adisc_work(vha, fcport, data);
				qla2x00_post_async_adisc_work(vha, fcport,
				    data);
				break;
			case DSC_LS_PORT_UNAVAIL:
			default:
			if (fcport->loop_id == FC_NO_LOOP_ID) {
				qla2x00_find_new_loop_id(vha, fcport);
				if (fcport->loop_id != FC_NO_LOOP_ID)
					qla2x00_clear_loop_id(fcport);

				fcport->loop_id = loop_id;
				fcport->fw_login_state = DSC_LS_PORT_UNAVAIL;
			}
			ql_dbg(ql_dbg_disc, vha, 0x20e5,
			    "%s %d %8phC\n",
			    __func__, __LINE__, fcport->port_name);
				qla24xx_fcport_handle_login(vha, fcport);
				break;
			}
			break;
		case ISP_CFG_N:
			switch (current_login_state) {
			case DSC_LS_PRLI_COMP:
				if ((e->prli_svc_param_word_3[0] & BIT_4) == 0)
					fcport->port_type = FCT_INITIATOR;
				else
					fcport->port_type = FCT_TARGET;

				data[0] = data[1] = 0;
				qla2x00_post_async_adisc_work(vha, fcport,
				    data);
				break;
			case DSC_LS_PLOGI_COMP:
				if (fcport_is_bigger(fcport)) {
					/* local adapter is smaller */
					if (fcport->loop_id != FC_NO_LOOP_ID)
						qla2x00_clear_loop_id(fcport);

					fcport->loop_id = loop_id;
					qla24xx_fcport_handle_login(vha,
					    fcport);
					break;
				}
				/* drop through */
			default:
				if (fcport_is_smaller(fcport)) {
					/* local adapter is bigger */
					if (fcport->loop_id != FC_NO_LOOP_ID)
						qla2x00_clear_loop_id(fcport);

					fcport->loop_id = loop_id;
					qla24xx_fcport_handle_login(vha,
					    fcport);
				}
				break;
			}
			break;
		} /* switch (ha->current_topology) */
	}

	if (!found) {
		/* fw has no record of this port */
		switch (vha->hw->current_topology) {
		case ISP_CFG_F:
		case ISP_CFG_FL:
			for (i = 0; i < n; i++) {
				e = &vha->gnl.l[i];
				id.b.domain = e->port_id[0];
@@ -591,19 +660,34 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
					conflict_fcport =
					    qla2x00_find_fcport_by_wwpn(vha,
						e->port_name, 0);
				ql_dbg(ql_dbg_disc, vha, 0x20e6,
					ql_dbg(ql_dbg_disc + ql_dbg_verbose,
					    vha, 0x20e5,
					    "%s %d %8phC post del sess\n",
					    __func__, __LINE__,
					    conflict_fcport->port_name);
					qlt_schedule_sess_for_deletion
						(conflict_fcport);
				}

			/* FW already picked this loop id for another fcport */
				/*
				 * FW already picked this loop id for
				 * another fcport
				 */
				if (fcport->loop_id == loop_id)
					fcport->loop_id = FC_NO_LOOP_ID;
			}
			qla24xx_fcport_handle_login(vha, fcport);
			break;
		case ISP_CFG_N:
			/*
			 * FW handles the initial login for n2n.
			 * Do link reinit to trigger this auto login.
			 */
			set_bit(N2N_LINK_RESET, &vha->dpc_flags);
			qla2xxx_wake_dpc(vha);
			break;
		default:
			break;
		}
	}
} /* gnl_event */

@@ -4590,21 +4674,11 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)

	} else if (ha->current_topology == ISP_CFG_N) {
		clear_bit(RSCN_UPDATE, &flags);
		if (ha->flags.rida_fmt2) {
			/* With Rida Format 2, the login is already triggered.
			 * We know who is on the other side of the wire.
			 * No need to login to do login to find out or drop into
			 * qla2x00_configure_local_loop().
			 */
			clear_bit(LOCAL_LOOP_UPDATE, &flags);
			set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
		} else {
		if (qla_tgt_mode_enabled(vha)) {
			/* allow the other side to start the login */
			clear_bit(LOCAL_LOOP_UPDATE, &flags);
			set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
		}
		}
	} else if (ha->current_topology == ISP_CFG_NL) {
		clear_bit(RSCN_UPDATE, &flags);
		set_bit(LOCAL_LOOP_UPDATE, &flags);
@@ -7929,7 +8003,6 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
	}

	 /* enable RIDA Format2 */
	if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha))
	icb->firmware_options_3 |= BIT_0;

	if (IS_QLA27XX(ha)) {
+9 −6
Original line number Diff line number Diff line
@@ -2240,12 +2240,15 @@ qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
	struct srb_iocb *lio = &sp->u.iocb_cmd;

	logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
	if (lio->u.logio.flags & SRB_LOGIN_PRLI_ONLY) {
		logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI);
	} else {
		logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI);

		if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI)
			logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI);
		if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI)
			logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI);
	}
	logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
	logio->port_id[0] = sp->fcport->d_id.b.al_pa;
	logio->port_id[1] = sp->fcport->d_id.b.area;
+2 −1
Original line number Diff line number Diff line
@@ -908,6 +908,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
			if (!atomic_read(&vha->loop_down_timer))
				atomic_set(&vha->loop_down_timer,
				    LOOP_DOWN_TIME);
			if (!N2N_TOPO(ha))
				qla2x00_mark_all_devices_lost(vha, 1);
		}

+4 −23
Original line number Diff line number Diff line
@@ -2177,7 +2177,10 @@ qla2x00_lip_reset(scsi_qla_host_t *vha)
		mcp->out_mb = MBX_2|MBX_1|MBX_0;
	} else if (IS_FWI2_CAPABLE(vha->hw)) {
		mcp->mb[0] = MBC_LIP_FULL_LOGIN;
		mcp->mb[1] = BIT_6;
		if (N2N_TOPO(vha->hw))
			mcp->mb[1] = BIT_4; /* re-init */
		else
			mcp->mb[1] = BIT_6; /* LIP */
		mcp->mb[2] = 0;
		mcp->mb[3] = vha->hw->loop_reset_delay;
		mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -3911,28 +3914,6 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
		if (fcport) {
			fcport->plogi_nack_done_deadline = jiffies + HZ;
			fcport->scan_state = QLA_FCPORT_FOUND;
			switch (fcport->disc_state) {
			case DSC_DELETED:
				ql_dbg(ql_dbg_disc, vha, 0x210d,
				    "%s %d %8phC login\n",
				    __func__, __LINE__, fcport->port_name);
				qla24xx_fcport_handle_login(vha, fcport);
				break;
			case DSC_DELETE_PEND:
				break;
			default:
				qlt_schedule_sess_for_deletion(fcport);
				break;
			}
		} else {
			id.b.al_pa  = rptid_entry->u.f2.remote_nport_id[0];
			id.b.area   = rptid_entry->u.f2.remote_nport_id[1];
			id.b.domain = rptid_entry->u.f2.remote_nport_id[2];
			qla24xx_post_newsess_work(vha, &id,
			    rptid_entry->u.f2.port_name,
			    rptid_entry->u.f2.node_name,
			    NULL,
			    FC4_TYPE_UNKNOWN);
		}
	}
}
Loading