scsi: qla2xxx: Add ability to use GPNFT/GNNFT for RSCN handling

add ability to use gpnft/gnnft to handle RSCN.

Signed-off-by: Quinn Tran <quinn.tran@cavium.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index fff12d7..963ebcb 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -2976,8 +2976,10 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea)
 	fc_port_t *fcport = ea->fcport;
 
 	ql_dbg(ql_dbg_disc, vha, 0x201d,
-	    "%s %8phC login state %d\n",
-	    __func__, fcport->port_name, fcport->fw_login_state);
+	    "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n",
+	    __func__, fcport->port_name, fcport->disc_state,
+	    fcport->fw_login_state, ea->rc, fcport->login_gen, ea->sp->gen2,
+	    fcport->rscn_gen, ea->sp->gen1, fcport->loop_id);
 
 	if (fcport->disc_state == DSC_DELETE_PEND)
 		return;
@@ -2985,9 +2987,9 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea)
 	if (ea->sp->gen2 != fcport->login_gen) {
 		/* PLOGI/PRLI/LOGO came in while cmd was out.*/
 		ql_dbg(ql_dbg_disc, vha, 0x201e,
-		    "%s %8phC generation changed rscn %d|%d login %d|%d \n",
+		    "%s %8phC generation changed rscn %d|%d n",
 		    __func__, fcport->port_name, fcport->last_rscn_gen,
-		    fcport->rscn_gen, fcport->last_login_gen, fcport->login_gen);
+		    fcport->rscn_gen);
 		return;
 	}
 
@@ -3215,11 +3217,10 @@ void qla24xx_handle_gpsc_event(scsi_qla_host_t *vha, struct event_arg *ea)
 	struct fc_port *fcport = ea->fcport;
 
 	ql_dbg(ql_dbg_disc, vha, 0x20d8,
-	    "%s %8phC DS %d LS %d rscn %d|%d login %d|%d lid %d\n",
+	    "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n",
 	    __func__, fcport->port_name, fcport->disc_state,
-	    fcport->fw_login_state, fcport->last_rscn_gen, fcport->rscn_gen,
-	    fcport->last_login_gen, fcport->login_gen,
-	    fcport->loop_id);
+	    fcport->fw_login_state, ea->rc, ea->sp->gen2, fcport->login_gen,
+	    ea->sp->gen2, fcport->rscn_gen|ea->sp->gen1, fcport->loop_id);
 
 	if (fcport->disc_state == DSC_DELETE_PEND)
 		return;
@@ -3227,10 +3228,8 @@ void qla24xx_handle_gpsc_event(scsi_qla_host_t *vha, struct event_arg *ea)
 	if (ea->sp->gen2 != fcport->login_gen) {
 		/* target side must have changed it. */
 		ql_dbg(ql_dbg_disc, vha, 0x20d3,
-		    "%s %8phC generation changed rscn %d|%d login %d|%d\n",
-		    __func__, fcport->port_name, fcport->last_rscn_gen,
-		    fcport->rscn_gen, fcport->last_login_gen,
-		    fcport->login_gen);
+		    "%s %8phC generation changed\n",
+		    __func__, fcport->port_name);
 		return;
 	} else if (ea->sp->gen1 != fcport->rscn_gen) {
 		ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",
@@ -3862,6 +3861,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
 	bool found;
 	u8 fc4type = sp->gen2;
 	struct fab_scan_rp *rp;
+	unsigned long flags;
 
 	ql_dbg(ql_dbg_disc, vha, 0xffff,
 	    "%s enter\n", __func__);
@@ -3939,16 +3939,15 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
 		if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
 			continue;
 
-		if (fcport->scan_state == QLA_FCPORT_SCAN) {
+		if (fcport->scan_state != QLA_FCPORT_FOUND) {
 			if ((qla_dual_mode_enabled(vha) ||
 				qla_ini_mode_enabled(vha)) &&
 			    atomic_read(&fcport->state) == FCS_ONLINE) {
 				qla2x00_mark_device_lost(vha, fcport,
 				    ql2xplogiabsentdevice, 0);
+
 				if (fcport->loop_id != FC_NO_LOOP_ID &&
-				    (fcport->flags & FCF_FCP2_DEVICE) == 0 &&
-				    fcport->port_type != FCT_INITIATOR &&
-				    fcport->port_type != FCT_BROADCAST) {
+				    (fcport->flags & FCF_FCP2_DEVICE) == 0) {
 					ql_dbg(ql_dbg_disc, vha, 0x20f0,
 					    "%s %d %8phC post del sess\n",
 					    __func__, __LINE__,
@@ -3959,14 +3958,16 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
 					continue;
 				}
 			}
-		}
-
-		if (fcport->scan_state == QLA_FCPORT_FOUND)
+		} else
 			qla24xx_fcport_handle_login(vha, fcport);
 	}
 
 out:
 	qla24xx_sp_unmap(vha, sp);
+
+	spin_lock_irqsave(&vha->work_lock, flags);
+	vha->scan.scan_flags &= ~SF_SCANNING;
+	spin_unlock_irqrestore(&vha->work_lock, flags);
 }
 
 static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res)
@@ -3995,6 +3996,9 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res)
 		    "Async done-%s timed out.\n",
 		    sp->name);
 		sp->free(sp);
+		spin_lock_irqsave(&vha->work_lock, flags);
+		vha->scan.scan_flags &= ~SF_SCANNING;
+		spin_unlock_irqrestore(&vha->work_lock, flags);
 		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
 		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
 		qla2xxx_wake_dpc(vha);
@@ -4086,14 +4090,17 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp,
 	struct ct_sns_req *ct_req;
 	struct ct_sns_pkt *ct_sns;
 
-	if (!vha->flags.online)
+	if (!vha->flags.online) {
+		vha->scan.scan_flags &= ~SF_SCANNING;
 		goto done_free_sp;
+	}
 
 	if (!sp->u.iocb_cmd.u.ctarg.req || !sp->u.iocb_cmd.u.ctarg.rsp) {
 		ql_log(ql_log_warn, vha, 0xffff,
 		    "%s: req %p rsp %p are not setup\n",
 		    __func__, sp->u.iocb_cmd.u.ctarg.req,
 		    sp->u.iocb_cmd.u.ctarg.rsp);
+		vha->scan.scan_flags &= ~SF_SCANNING;
 		WARN_ON(1);
 		goto done_free_sp;
 	}
@@ -4166,14 +4173,25 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
 	srb_t *sp;
 	struct ct_sns_pkt *ct_sns;
 	u32 rspsz;
+	unsigned long flags;
 
 	if (!vha->flags.online)
 		return rval;
 
-	sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
-	if (!sp)
+	spin_lock_irqsave(&vha->work_lock, flags);
+	if (vha->scan.scan_flags & SF_SCANNING) {
+		spin_unlock_irqrestore(&vha->work_lock, flags);
+		ql_dbg(ql_dbg_disc, vha, 0xffff, "scan active\n");
 		return rval;
+	}
+	vha->scan.scan_flags |= SF_SCANNING;
+	spin_unlock_irqrestore(&vha->work_lock, flags);
 
+	sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
+	if (!sp) {
+		vha->scan.scan_flags &= ~SF_SCANNING;
+		return rval;
+	}
 
 	sp->type = SRB_CT_PTHRU_CMD;
 	sp->name = "gpnft";
@@ -4187,6 +4205,7 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
 	if (!sp->u.iocb_cmd.u.ctarg.req) {
 		ql_log(ql_log_warn, vha, 0xffff,
 		    "Failed to allocate ct_sns request.\n");
+		vha->scan.scan_flags &= ~SF_SCANNING;
 		goto done_free_sp;
 	}
 
@@ -4199,6 +4218,7 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
 	if (!sp->u.iocb_cmd.u.ctarg.rsp) {
 		ql_log(ql_log_warn, vha, 0xffff,
 		    "Failed to allocate ct_sns request.\n");
+		vha->scan.scan_flags &= ~SF_SCANNING;
 		goto done_free_sp;
 	}
 
@@ -4219,8 +4239,10 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
 	sp->done = qla2x00_async_gpnft_gnnft_sp_done;
 
 	rval = qla2x00_start_sp(sp);
-	if (rval != QLA_SUCCESS)
+	if (rval != QLA_SUCCESS) {
+		vha->scan.scan_flags &= ~SF_SCANNING;
 		goto done_free_sp;
+	}
 
 	ql_dbg(ql_dbg_disc, vha, 0xffff,
 	    "Async-%s hdl=%x FC4Type %x.\n", sp->name,
@@ -4248,6 +4270,24 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
 	return rval;
 }
 
+void qla_scan_work_fn(struct work_struct *work)
+{
+	struct fab_scan *s = container_of(to_delayed_work(work),
+	    struct fab_scan, scan_work);
+	struct scsi_qla_host *vha = container_of(s, struct scsi_qla_host,
+	    scan);
+	unsigned long flags;
+
+	ql_dbg(ql_dbg_disc, vha, 0xffff,
+	    "%s: schedule loop resync\n", __func__);
+	set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
+	set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+	qla2xxx_wake_dpc(vha);
+	spin_lock_irqsave(&vha->work_lock, flags);
+	vha->scan.scan_flags &= ~SF_QUEUED;
+	spin_unlock_irqrestore(&vha->work_lock, flags);
+}
+
 /* GNN_ID */
 void qla24xx_handle_gnnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
 {
@@ -4367,9 +4407,10 @@ void qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
 	fc_port_t *fcport = ea->fcport;
 
 	ql_dbg(ql_dbg_disc, vha, 0xffff,
-	    "%s %d %8phC post gpsc fcp_cnt %d\n",
-	    __func__, __LINE__, fcport->port_name,
-	    vha->fcport_count);
+	    "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d fcpcnt %d\n",
+	    __func__, fcport->port_name, fcport->disc_state,
+	    fcport->fw_login_state, ea->rc, fcport->login_gen, ea->sp->gen2,
+	    fcport->rscn_gen, ea->sp->gen1, vha->fcport_count);
 
 	if (fcport->disc_state == DSC_DELETE_PEND)
 		return;
@@ -4377,10 +4418,8 @@ void qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
 	if (ea->sp->gen2 != fcport->login_gen) {
 		/* target side must have changed it. */
 		ql_dbg(ql_dbg_disc, vha, 0x20d3,
-		    "%s %8phC generation changed rscn %d|%d login %d|%d\n",
-		    __func__, fcport->port_name, fcport->last_rscn_gen,
-		    fcport->rscn_gen, fcport->last_login_gen,
-		    fcport->login_gen);
+		    "%s %8phC generation changed\n",
+		    __func__, fcport->port_name);
 		return;
 	} else if (ea->sp->gen1 != fcport->rscn_gen) {
 		ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",