Skip to content

Commit

Permalink
scsi: qla2xxx: Fix session cleanup for N2N
Browse files Browse the repository at this point in the history
When connection type is N_Port to N_Port (point-to-point), there
is a possibilty where initiator will not send PLOGI request and
will directly send PRLI. In N2N connection the port has higher
port name sends the PLOGI but not allow to send PRLI if is a
target mode. Only initiator is allowed to send PRLI.

Current driver code deletes old session when it receives PLOGI
request. If we will not receive PLOGI request then we will not
delete old session and create new session. Add check for N2N
with PRLI receive only and trigger cleanup. For this case, the
cleanup requires individual cmd abort instead of using implicit
logout as a broad stroke flush.

Signed-off-by: Krishna Kant <krishna.kant@purestorage.com>
Signed-off-by: Alexei Potashnik <alexei@purestorage.com>
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>
  • Loading branch information
Quinn Tran authored and Martin K. Petersen committed Jan 4, 2018
1 parent 94d83e3 commit 9cd883f
Show file tree
Hide file tree
Showing 7 changed files with 378 additions and 155 deletions.
11 changes: 11 additions & 0 deletions drivers/scsi/qla2xxx/qla_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -3508,6 +3508,7 @@ struct qla_hw_data {

uint32_t detected_lr_sfp:1;
uint32_t using_lr_setting:1;
uint32_t rida_fmt2:1;
} flags;

uint16_t max_exchg;
Expand Down Expand Up @@ -4529,6 +4530,16 @@ struct sff_8247_a0 {
#define USER_CTRL_IRQ(_ha) (ql2xuctrlirq && QLA_TGT_MODE_ENABLED() && \
(IS_QLA27XX(_ha) || IS_QLA83XX(_ha)))

#define SAVE_TOPO(_ha) { \
if (_ha->current_topology) \
_ha->prev_topology = _ha->current_topology; \
}

#define N2N_TOPO(ha) \
((ha->prev_topology == ISP_CFG_N && !ha->current_topology) || \
ha->current_topology == ISP_CFG_N || \
!ha->current_topology)

#include "qla_target.h"
#include "qla_gbl.h"
#include "qla_dbg.h"
Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/qla2xxx/qla_fw.h
Original file line number Diff line number Diff line change
Expand Up @@ -1392,7 +1392,7 @@ struct vp_rpt_id_entry_24xx {

uint8_t port_name[8];
uint8_t node_name[8];
uint32_t remote_nport_id;
uint8_t remote_nport_id[4];
uint32_t reserved_5;
} f2;
} u;
Expand Down
151 changes: 102 additions & 49 deletions drivers/scsi/qla2xxx/qla_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,6 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
if (!vha->flags.online)
goto done;

if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
(fcport->fw_login_state == DSC_LS_PLOGI_COMP) ||
(fcport->fw_login_state == DSC_LS_PRLI_PEND))
goto done;

sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
goto done;
Expand Down Expand Up @@ -1013,6 +1008,43 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
} /* gpdb event */


static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport)
{
u8 login = 0;

if (qla_tgt_mode_enabled(vha))
return;

if (qla_dual_mode_enabled(vha)) {
if (N2N_TOPO(vha->hw)) {
u64 mywwn, wwn;

mywwn = wwn_to_u64(vha->port_name);
wwn = wwn_to_u64(fcport->port_name);
if (mywwn > wwn)
login = 1;
else if ((fcport->fw_login_state == DSC_LS_PLOGI_COMP)
&& time_after_eq(jiffies,
fcport->plogi_nack_done_deadline))
login = 1;
} else {
login = 1;
}
} else {
/* initiator mode */
login = 1;
}

if (login) {
ql_dbg(ql_dbg_disc, vha, 0x20bf,
"%s %d %8phC post login\n",
__func__, __LINE__, fcport->port_name);
fcport->disc_state = DSC_LOGIN_PEND;
qla2x00_post_async_login_work(vha, fcport, NULL);
}
}

int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
{
u16 data[2];
Expand All @@ -1037,8 +1069,10 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
return 0;

if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) {
if (time_before_eq(jiffies, fcport->plogi_nack_done_deadline))
if (time_before_eq(jiffies, fcport->plogi_nack_done_deadline)) {
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
return 0;
}
}

/* for pure Target Mode. Login will not be initiated */
Expand All @@ -1058,11 +1092,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
__func__, __LINE__, fcport->port_name);
qla24xx_post_gnl_work(vha, fcport);
} else {
ql_dbg(ql_dbg_disc, vha, 0x20bf,
"%s %d %8phC post login\n",
__func__, __LINE__, fcport->port_name);
fcport->disc_state = DSC_LOGIN_PEND;
qla2x00_post_async_login_work(vha, fcport, NULL);
qla_chk_n2n_b4_login(vha, fcport);
}
break;

Expand All @@ -1074,19 +1104,17 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
break;
}

ql_dbg(ql_dbg_disc, vha, 0x20cf,
"%s %d %8phC post login\n",
__func__, __LINE__, fcport->port_name);
fcport->disc_state = DSC_LOGIN_PEND;
qla2x00_post_async_login_work(vha, fcport, NULL);
qla_chk_n2n_b4_login(vha, fcport);
break;

case DSC_LOGIN_FAILED:
ql_dbg(ql_dbg_disc, vha, 0x20d0,
"%s %d %8phC post gidpn\n",
__func__, __LINE__, fcport->port_name);

qla24xx_post_gidpn_work(vha, fcport);
if (N2N_TOPO(vha->hw))
qla_chk_n2n_b4_login(vha, fcport);
else
qla24xx_post_gidpn_work(vha, fcport);
break;

case DSC_LOGIN_COMPLETE:
Expand Down Expand Up @@ -1193,8 +1221,10 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha,
return;

if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) {
if (time_before_eq(jiffies, fcport->plogi_nack_done_deadline))
if (time_before_eq(jiffies, fcport->plogi_nack_done_deadline)) {
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
return;
}
}

if (fcport->flags & FCF_ASYNC_SENT) {
Expand Down Expand Up @@ -4434,6 +4464,21 @@ 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);
Expand Down Expand Up @@ -4662,6 +4707,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
(uint8_t *)ha->gid_list,
entries * sizeof(struct gid_list_info));

list_for_each_entry(fcport, &vha->vp_fcports, list) {
fcport->scan_state = QLA_FCPORT_SCAN;
}

/* Allocate temporary fcport for any new fcports discovered. */
new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
if (new_fcport == NULL) {
Expand All @@ -4672,22 +4721,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
}
new_fcport->flags &= ~FCF_FABRIC_DEVICE;

/*
* Mark local devices that were present with FCF_DEVICE_LOST for now.
*/
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (atomic_read(&fcport->state) == FCS_ONLINE &&
fcport->port_type != FCT_BROADCAST &&
(fcport->flags & FCF_FABRIC_DEVICE) == 0) {

ql_dbg(ql_dbg_disc, vha, 0x2096,
"Marking port lost loop_id=0x%04x.\n",
fcport->loop_id);

qla2x00_mark_device_lost(vha, fcport, 0, 0);
}
}

/* Inititae N2N login. */
if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) {
rval = qla24xx_n2n_handle_login(vha, new_fcport);
Expand Down Expand Up @@ -4730,6 +4763,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
new_fcport->d_id.b.area = area;
new_fcport->d_id.b.al_pa = al_pa;
new_fcport->loop_id = loop_id;
new_fcport->scan_state = QLA_FCPORT_FOUND;

rval2 = qla2x00_get_port_database(vha, new_fcport, 0);
if (rval2 != QLA_SUCCESS) {
Expand Down Expand Up @@ -4761,13 +4795,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
fcport->d_id.b24 = new_fcport->d_id.b24;
memcpy(fcport->node_name, new_fcport->node_name,
WWN_SIZE);

if (!fcport->login_succ) {
vha->fcport_count++;
fcport->login_succ = 1;
fcport->disc_state = DSC_LOGIN_COMPLETE;
}

fcport->scan_state = QLA_FCPORT_FOUND;
found++;
break;
}
Expand All @@ -4778,11 +4806,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)

/* Allocate a new replacement fcport. */
fcport = new_fcport;
if (!fcport->login_succ) {
vha->fcport_count++;
fcport->login_succ = 1;
fcport->disc_state = DSC_LOGIN_COMPLETE;
}

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

Expand All @@ -4803,11 +4826,39 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
/* Base iIDMA settings on HBA port speed. */
fcport->fp_speed = ha->link_data_rate;

qla2x00_update_fcport(vha, fcport);

found_devs++;
}

list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
break;

if (fcport->scan_state == QLA_FCPORT_SCAN) {
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) {
ql_dbg(ql_dbg_disc, vha, 0x20f0,
"%s %d %8phC post del sess\n",
__func__, __LINE__,
fcport->port_name);

qlt_schedule_sess_for_deletion_lock
(fcport);
continue;
}
}
}

if (fcport->scan_state == QLA_FCPORT_FOUND)
qla24xx_fcport_handle_login(vha, fcport);
}

cleanup_allocation:
kfree(new_fcport);

Expand Down Expand Up @@ -6115,6 +6166,8 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
if (!(IS_P3P_TYPE(ha)))
ha->isp_ops->reset_chip(vha);

SAVE_TOPO(ha);
ha->flags.rida_fmt2 = 0;
ha->flags.n2n_ae = 0;
ha->flags.lip_ae = 0;
ha->current_topology = 0;
Expand Down
4 changes: 1 addition & 3 deletions drivers/scsi/qla2xxx/qla_isr.c
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
break;

case MBA_LOOP_DOWN: /* Loop Down Event */
SAVE_TOPO(ha);
ha->flags.n2n_ae = 0;
ha->flags.lip_ae = 0;
ha->current_topology = 0;
Expand Down Expand Up @@ -922,7 +923,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);

ha->flags.gpsc_supported = 1;
vha->flags.management_server_logged_in = 0;
break;

Expand Down Expand Up @@ -1060,8 +1060,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
*/
atomic_set(&vha->loop_state, LOOP_UP);

qla2x00_mark_all_devices_lost(vha, 1);

set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
set_bit(VP_CONFIG_OK, &vha->vp_flags);
Expand Down
38 changes: 37 additions & 1 deletion drivers/scsi/qla2xxx/qla_mbx.c
Original file line number Diff line number Diff line change
Expand Up @@ -3732,6 +3732,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
unsigned long flags;
int found;
port_id_t id;
struct fc_port *fcport;

ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b6,
"Entered %s.\n", __func__);
Expand All @@ -3754,7 +3755,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
"Primary port id %02x%02x%02x.\n",
rptid_entry->port_id[2], rptid_entry->port_id[1],
rptid_entry->port_id[0]);

ha->current_topology = ISP_CFG_NL;
qlt_update_host_map(vha, id);

} else if (rptid_entry->format == 1) {
Expand Down Expand Up @@ -3798,6 +3799,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
return;
}

ha->flags.gpsc_supported = 1;
ha->current_topology = ISP_CFG_F;
/* buffer to buffer credit flag */
vha->flags.bbcr_enable = (rptid_entry->u.f1.bbcr & 0xf) != 0;

Expand Down Expand Up @@ -3863,13 +3866,46 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
rptid_entry->u.f2.port_name);

/* N2N. direct connect */
ha->current_topology = ISP_CFG_N;
ha->flags.rida_fmt2 = 1;
vha->d_id.b.domain = rptid_entry->port_id[2];
vha->d_id.b.area = rptid_entry->port_id[1];
vha->d_id.b.al_pa = rptid_entry->port_id[0];

spin_lock_irqsave(&ha->vport_slock, flags);
qlt_update_vp_map(vha, SET_AL_PA);
spin_unlock_irqrestore(&ha->vport_slock, flags);

list_for_each_entry(fcport, &vha->vp_fcports, list) {
fcport->scan_state = QLA_FCPORT_SCAN;
}

fcport = qla2x00_find_fcport_by_wwpn(vha,
rptid_entry->u.f2.port_name, 1);

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_lock(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, NULL);
}
}
}

Expand Down
Loading

0 comments on commit 9cd883f

Please sign in to comment.