@@ -3312,6 +3312,8 @@ struct fab_scan_rp {
struct fab_scan {
struct fab_scan_rp *l;
u32 size;
+ u32 rscn_gen_start;
+ u32 rscn_gen_end;
u16 scan_retry;
#define MAX_SCAN_RETRIES 5
enum scan_flags_t scan_flags;
@@ -5030,6 +5032,7 @@ typedef struct scsi_qla_host {
/* Counter to detect races between ELS and RSCN events */
atomic_t generation_tick;
+ atomic_t rscn_gen;
/* Time when global fcport update has been scheduled */
int total_fcport_update_gen;
/* List of pending LOGOs, protected by tgt_mutex */
@@ -3168,6 +3168,29 @@ static int qla2x00_is_a_vp(scsi_qla_host_t *vha, u64 wwn)
return rc;
}
+static bool qla_ok_to_clear_rscn(scsi_qla_host_t *vha, fc_port_t *fcport)
+{
+ u32 rscn_gen;
+
+ rscn_gen = atomic_read(&vha->rscn_gen);
+ ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x2017,
+ "%s %d %8phC rscn_gen %x start %x end %x current %x\n",
+ __func__, __LINE__, fcport->port_name, fcport->rscn_gen,
+ vha->scan.rscn_gen_start, vha->scan.rscn_gen_end, rscn_gen);
+
+ if (val_is_in_range(fcport->rscn_gen, vha->scan.rscn_gen_start,
+ vha->scan.rscn_gen_end))
+ /* rscn came in before fabric scan */
+ return true;
+
+ if (val_is_in_range(fcport->rscn_gen, vha->scan.rscn_gen_end, rscn_gen))
+ /* rscn came in after fabric scan */
+ return false;
+
+ /* rare: fcport's scan_needed + rscn_gen must be stale */
+ return true;
+}
+
void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
{
fc_port_t *fcport;
@@ -3281,10 +3304,10 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
(fcport->scan_needed &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_NVME_INITIATOR)) {
+ fcport->scan_needed = 0;
qlt_schedule_sess_for_deletion(fcport);
}
fcport->d_id.b24 = rp->id.b24;
- fcport->scan_needed = 0;
break;
}
@@ -3325,7 +3348,9 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
do_delete = true;
}
- fcport->scan_needed = 0;
+ if (qla_ok_to_clear_rscn(vha, fcport))
+ fcport->scan_needed = 0;
+
if (((qla_dual_mode_enabled(vha) ||
qla_ini_mode_enabled(vha)) &&
atomic_read(&fcport->state) == FCS_ONLINE) ||
@@ -3355,7 +3380,9 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
fcport->port_name, fcport->loop_id,
fcport->login_retry);
}
- fcport->scan_needed = 0;
+
+ if (qla_ok_to_clear_rscn(vha, fcport))
+ fcport->scan_needed = 0;
qla24xx_fcport_handle_login(vha, fcport);
}
}
@@ -1842,10 +1842,18 @@ int qla24xx_post_newsess_work(struct scsi_qla_host *vha, port_id_t *id,
return qla2x00_post_work(vha, e);
}
+static void qla_rscn_gen_tick(scsi_qla_host_t *vha, u32 *ret_rscn_gen)
+{
+ *ret_rscn_gen = atomic_inc_return(&vha->rscn_gen);
+ /* memory barrier */
+ wmb();
+}
+
void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea)
{
fc_port_t *fcport;
unsigned long flags;
+ u32 rscn_gen;
switch (ea->id.b.rsvd_1) {
case RSCN_PORT_ADDR:
@@ -1875,15 +1883,16 @@ void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea)
* Otherwise we're already in the middle of a relogin
*/
fcport->scan_needed = 1;
- fcport->rscn_gen++;
+ qla_rscn_gen_tick(vha, &fcport->rscn_gen);
}
} else {
fcport->scan_needed = 1;
- fcport->rscn_gen++;
+ qla_rscn_gen_tick(vha, &fcport->rscn_gen);
}
}
break;
case RSCN_AREA_ADDR:
+ qla_rscn_gen_tick(vha, &rscn_gen);
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->flags & FCF_FCP2_DEVICE &&
atomic_read(&fcport->state) == FCS_ONLINE)
@@ -1891,11 +1900,12 @@ void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea)
if ((ea->id.b24 & 0xffff00) == (fcport->d_id.b24 & 0xffff00)) {
fcport->scan_needed = 1;
- fcport->rscn_gen++;
+ fcport->rscn_gen = rscn_gen;
}
}
break;
case RSCN_DOM_ADDR:
+ qla_rscn_gen_tick(vha, &rscn_gen);
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->flags & FCF_FCP2_DEVICE &&
atomic_read(&fcport->state) == FCS_ONLINE)
@@ -1903,19 +1913,20 @@ void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea)
if ((ea->id.b24 & 0xff0000) == (fcport->d_id.b24 & 0xff0000)) {
fcport->scan_needed = 1;
- fcport->rscn_gen++;
+ fcport->rscn_gen = rscn_gen;
}
}
break;
case RSCN_FAB_ADDR:
default:
+ qla_rscn_gen_tick(vha, &rscn_gen);
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->flags & FCF_FCP2_DEVICE &&
atomic_read(&fcport->state) == FCS_ONLINE)
continue;
fcport->scan_needed = 1;
- fcport->rscn_gen++;
+ fcport->rscn_gen = rscn_gen;
}
break;
}
@@ -1924,6 +1935,7 @@ void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea)
if (vha->scan.scan_flags == 0) {
ql_dbg(ql_dbg_disc, vha, 0xffff, "%s: schedule\n", __func__);
vha->scan.scan_flags |= SF_QUEUED;
+ vha->scan.rscn_gen_start = atomic_read(&vha->rscn_gen);
schedule_delayed_work(&vha->scan.scan_work, 5);
}
spin_unlock_irqrestore(&vha->work_lock, flags);
@@ -6393,6 +6405,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
qlt_do_generation_tick(vha, &discovery_gen);
if (USE_ASYNC_SCAN(ha)) {
+ /* start of scan begins here */
+ vha->scan.rscn_gen_end = atomic_read(&vha->rscn_gen);
rval = qla24xx_async_gpnft(vha, FC4_TYPE_FCP_SCSI,
NULL);
if (rval)
@@ -631,3 +631,21 @@ static inline int qla_mapq_alloc_qp_cpu_map(struct qla_hw_data *ha)
}
return 0;
}
+
+static inline bool val_is_in_range(u32 val, u32 start, u32 end)
+{
+ if (start < end) {
+ if (val >= start && val <= end)
+ return true;
+ else
+ return false;
+ }
+
+ /* @end has wrapped */
+ if (val >= start && val <= 0xffffffffu)
+ return true;
+ if (val <= end)
+ return true;
+ else
+ return false;
+}