Commit c3d98b12 authored by Quinn Tran's avatar Quinn Tran Committed by Martin K. Petersen

scsi: qla2xxx: Unable to act on RSCN for port online

The device does not come online when the target port is online. There were
multiple RSCNs indicating multiple devices were affected. Driver is in the
process of finishing a fabric scan. A new RSCN (device up) arrived at the
tail end of the last fabric scan. Driver mistakenly thinks the new RSCN is
being taken care of by the previous fabric scan, where this notification is
cleared and not acted on. The laser needs to be blinked again to get the
device to show up.

To prevent driver from accidentally clearing the RSCN notification, each
RSCN is given a generation value.  A fabric scan will scan for that
generation(s).  Any new RSCN arrive after the scan start will have a new
generation value. This will trigger another scan to get latest data. The
RSCN notification flag will be cleared when the scan is associate to that
generation.
Reported-by: default avatarkernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202406210538.w875N70K-lkp@intel.com/
Fixes: bb2ca6b3 ("scsi: qla2xxx: Relogin during fabric disturbance")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarQuinn Tran <qutran@marvell.com>
Signed-off-by: default avatarNilesh Javali <njavali@marvell.com>
Link: https://lore.kernel.org/r/20240710171057.35066-2-njavali@marvell.comReviewed-by: default avatarHimanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 1613e604
......@@ -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,11 @@ 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 (val >= start && val <= end)
return true;
else
return false;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment