Commit a5d42f4c authored by Duane Grigsby's avatar Duane Grigsby Committed by Martin K. Petersen

scsi: qla2xxx: Add FC-NVMe port discovery and PRLI handling

Added logic to change the login process into an optional PRIL step for
FC-NVMe ports as a separate operation, such that we can change type to
0x28 (NVMe).

Currently, the driver performs the PLOGI/PRLI together as one operation,
but if the discovered port is an NVMe port then we first issue the PLOGI
and then we issue the PRLI. Also, the fabric discovery logic was changed
to mark each discovered FC NVMe port, so that we can register them with
the FC-NVMe transport later.
Signed-off-by: default avatarDarren Trapp <darren.trapp@cavium.com>
Signed-off-by: default avatarDuane Grigsby <duane.grigsby@cavium.com>
Signed-off-by: default avatarAnil Gurumurthy <anil.gurumurhty@cavium.com>
Signed-off-by: default avatarGiridhar Malavali <giridhar.malavali@cavium.com>
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@cavium.com>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 34e0badd
......@@ -15,9 +15,10 @@
* | | | 0x015b-0x0160 |
* | | | 0x016e |
* | Mailbox commands | 0x1199 | 0x1193 |
* | Device Discovery | 0x2004 | 0x2016 |
* | | | 0x2011-0x2012, |
* | | | 0x2099-0x20a4 |
* | Device Discovery | 0x2131 | 0x210e-0x2116 |
* | | | 0x211a |
* | | | 0x211c-0x2128 |
* | | | 0x212a-0x2130 |
* | Queue Command and IO tracing | 0x3074 | 0x300b |
* | | | 0x3027-0x3028 |
* | | | 0x303d-0x3041 |
......@@ -59,7 +60,7 @@
* | | | 0xb13c-0xb140 |
* | | | 0xb149 |
* | MultiQ | 0xc010 | |
* | Misc | 0xd301 | 0xd031-0xd0ff |
* | Misc | 0xd302 | 0xd031-0xd0ff |
* | | | 0xd101-0xd1fe |
* | | | 0xd214-0xd2fe |
* | Target Mode | 0xe081 | |
......
......@@ -343,6 +343,7 @@ struct srb_iocb {
#define SRB_LOGIN_RETRIED BIT_0
#define SRB_LOGIN_COND_PLOGI BIT_1
#define SRB_LOGIN_SKIP_PRLI BIT_2
#define SRB_LOGIN_NVME_PRLI BIT_3
uint16_t data[2];
u32 iop[2];
} logio;
......@@ -436,6 +437,7 @@ struct srb_iocb {
#define SRB_NACK_PLOGI 16
#define SRB_NACK_PRLI 17
#define SRB_NACK_LOGO 18
#define SRB_PRLI_CMD 21
enum {
TYPE_SRB,
......@@ -1088,6 +1090,7 @@ struct mbx_cmd_32 {
#define MBX_1 BIT_1
#define MBX_0 BIT_0
#define RNID_TYPE_PORT_LOGIN 0x7
#define RNID_TYPE_SET_VERSION 0x9
#define RNID_TYPE_ASIC_TEMP 0xC
......@@ -2152,6 +2155,7 @@ typedef struct {
uint8_t fabric_port_name[WWN_SIZE];
uint16_t fp_speed;
uint8_t fc4_type;
uint8_t fc4f_nvme; /* nvme fc4 feature bits */
} sw_info_t;
/* FCP-4 types */
......@@ -2180,7 +2184,8 @@ typedef enum {
FCT_SWITCH,
FCT_BROADCAST,
FCT_INITIATOR,
FCT_TARGET
FCT_TARGET,
FCT_NVME
} fc_port_type_t;
enum qla_sess_deletion {
......@@ -2237,10 +2242,12 @@ enum fcport_mgt_event {
FCME_RSCN,
FCME_GIDPN_DONE,
FCME_PLOGI_DONE, /* Initiator side sent LLIOCB */
FCME_PRLI_DONE,
FCME_GNL_DONE,
FCME_GPSC_DONE,
FCME_GPDB_DONE,
FCME_GPNID_DONE,
FCME_GFFID_DONE,
FCME_DELETE_DONE,
};
......@@ -2274,6 +2281,16 @@ typedef struct fc_port {
unsigned int login_pause:1;
unsigned int login_succ:1;
struct work_struct nvme_del_work;
atomic_t nvme_ref_count;
uint32_t nvme_prli_service_param;
#define NVME_PRLI_SP_CONF BIT_7
#define NVME_PRLI_SP_INITIATOR BIT_5
#define NVME_PRLI_SP_TARGET BIT_4
#define NVME_PRLI_SP_DISCOVERY BIT_3
uint8_t nvme_flag;
#define NVME_FLAG_REGISTERED 4
struct fc_port *conflict;
unsigned char logout_completed;
int generation;
......@@ -2306,6 +2323,7 @@ typedef struct fc_port {
u32 supported_classes;
uint8_t fc4_type;
uint8_t fc4f_nvme;
uint8_t scan_state;
unsigned long last_queue_full;
......@@ -2313,6 +2331,8 @@ typedef struct fc_port {
uint16_t port_id;
struct nvme_fc_remote_port *nvme_remote_port;
unsigned long retry_delay_timestamp;
struct qla_tgt_sess *tgt_session;
struct ct_sns_desc ct_desc;
......@@ -2745,7 +2765,7 @@ struct ct_sns_req {
struct {
uint8_t reserved;
uint8_t port_name[3];
uint8_t port_id[3];
} gff_id;
struct {
......@@ -3052,6 +3072,7 @@ enum qla_work_type {
QLA_EVT_GPNID_DONE,
QLA_EVT_NEW_SESS,
QLA_EVT_GPDB,
QLA_EVT_PRLI,
QLA_EVT_GPSC,
QLA_EVT_UPD_FCPORT,
QLA_EVT_GNL,
......@@ -4007,6 +4028,7 @@ typedef struct scsi_qla_host {
uint32_t qpairs_available:1;
uint32_t qpairs_req_created:1;
uint32_t qpairs_rsp_created:1;
uint32_t nvme_enabled:1;
} flags;
atomic_t loop_state;
......@@ -4085,6 +4107,10 @@ typedef struct scsi_qla_host {
uint8_t port_name[WWN_SIZE];
uint8_t fabric_node_name[WWN_SIZE];
struct nvme_fc_local_port *nvme_local_port;
atomic_t nvme_ref_count;
struct list_head nvme_rport_list;
uint16_t fcoe_vlan_id;
uint16_t fcoe_fcf_idx;
uint8_t fcoe_vn_port_mac[6];
......
......@@ -37,6 +37,12 @@ struct port_database_24xx {
#define PDF_CLASS_2 BIT_4
#define PDF_HARD_ADDR BIT_1
/*
* for NVMe, the login_state field has been
* split into nibbles.
* The lower nibble is for FCP.
* The upper nibble is for NVMe.
*/
uint8_t current_login_state;
uint8_t last_login_state;
#define PDS_PLOGI_PENDING 0x03
......@@ -69,7 +75,11 @@ struct port_database_24xx {
uint8_t port_name[WWN_SIZE];
uint8_t node_name[WWN_SIZE];
uint8_t reserved_3[24];
uint8_t reserved_3[4];
uint16_t prli_nvme_svc_param_word_0; /* Bits 15-0 of word 0 */
uint16_t prli_nvme_svc_param_word_3; /* Bits 15-0 of word 3 */
uint16_t nvme_first_burst_size;
uint8_t reserved_4[14];
};
/*
......@@ -819,6 +829,7 @@ struct logio_entry_24xx {
#define LCF_CLASS_2 BIT_8 /* Enable class 2 during PLOGI. */
#define LCF_FREE_NPORT BIT_7 /* Release NPORT handle after LOGO. */
#define LCF_EXPL_LOGO BIT_6 /* Perform an explicit LOGO. */
#define LCF_NVME_PRLI BIT_6 /* Perform NVME FC4 PRLI */
#define LCF_SKIP_PRLI BIT_5 /* Skip PRLI after PLOGI. */
#define LCF_IMPL_LOGO_ALL BIT_5 /* Implicit LOGO to all ports. */
#define LCF_COND_PLOGI BIT_4 /* PLOGI only if not logged-in. */
......
......@@ -99,6 +99,7 @@ extern struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *,
extern int qla2xxx_delete_qpair(struct scsi_qla_host *, struct qla_qpair *);
void qla2x00_fcport_event_handler(scsi_qla_host_t *, struct event_arg *);
int qla24xx_async_gpdb(struct scsi_qla_host *, fc_port_t *, u8);
int qla24xx_async_prli(struct scsi_qla_host *, fc_port_t *);
int qla24xx_async_notify_ack(scsi_qla_host_t *, fc_port_t *,
struct imm_ntfy_from_isp *, int);
int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *,
......
......@@ -37,8 +37,11 @@ static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
static int qla84xx_init_chip(scsi_qla_host_t *);
static int qla25xx_init_queues(struct qla_hw_data *);
static int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8);
static int qla24xx_post_prli_work(struct scsi_qla_host*, fc_port_t *);
static void qla24xx_handle_plogi_done_event(struct scsi_qla_host *,
struct event_arg *);
static void qla24xx_handle_prli_done_event(struct scsi_qla_host *,
struct event_arg *);
/* SRB Extensions ---------------------------------------------------------- */
......@@ -191,6 +194,10 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
lio->timeout = qla2x00_async_iocb_timeout;
sp->done = qla2x00_async_login_sp_done;
lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
if (fcport->fc4f_nvme)
lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI;
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
lio->u.logio.flags |= SRB_LOGIN_RETRIED;
rval = qla2x00_start_sp(sp);
......@@ -327,7 +334,7 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
u16 i, n, found = 0, loop_id;
port_id_t id;
u64 wwn;
u8 opt = 0;
u8 opt = 0, current_login_state;
fcport = ea->fcport;
......@@ -414,7 +421,12 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
fcport->login_pause = 1;
}
switch (e->current_login_state) {
if (fcport->fc4f_nvme)
current_login_state = e->current_login_state >> 4;
else
current_login_state = e->current_login_state & 0xf;
switch (current_login_state) {
case DSC_LS_PRLI_COMP:
ql_dbg(ql_dbg_disc, vha, 0x20e4,
"%s %d %8phC post gpdb\n",
......@@ -422,7 +434,6 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
opt = PDO_FORCE_ADISC;
qla24xx_post_gpdb_work(vha, fcport, opt);
break;
case DSC_LS_PORT_UNAVAIL:
default:
if (fcport->loop_id == FC_NO_LOOP_ID) {
......@@ -665,6 +676,104 @@ void qla24xx_async_gpdb_sp_done(void *s, int res)
sp->free(sp);
}
static int qla24xx_post_prli_work(struct scsi_qla_host *vha, fc_port_t *fcport)
{
struct qla_work_evt *e;
e = qla2x00_alloc_work(vha, QLA_EVT_PRLI);
if (!e)
return QLA_FUNCTION_FAILED;
e->u.fcport.fcport = fcport;
return qla2x00_post_work(vha, e);
}
static void
qla2x00_async_prli_sp_done(void *ptr, int res)
{
srb_t *sp = ptr;
struct scsi_qla_host *vha = sp->vha;
struct srb_iocb *lio = &sp->u.iocb_cmd;
struct event_arg ea;
ql_dbg(ql_dbg_disc, vha, 0x2129,
"%s %8phC res %d \n", __func__,
sp->fcport->port_name, res);
sp->fcport->flags &= ~FCF_ASYNC_SENT;
if (!test_bit(UNLOADING, &vha->dpc_flags)) {
memset(&ea, 0, sizeof(ea));
ea.event = FCME_PRLI_DONE;
ea.fcport = sp->fcport;
ea.data[0] = lio->u.logio.data[0];
ea.data[1] = lio->u.logio.data[1];
ea.iop[0] = lio->u.logio.iop[0];
ea.iop[1] = lio->u.logio.iop[1];
ea.sp = sp;
qla2x00_fcport_event_handler(vha, &ea);
}
sp->free(sp);
}
int
qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport)
{
srb_t *sp;
struct srb_iocb *lio;
int rval = QLA_FUNCTION_FAILED;
if (!vha->flags.online)
return rval;
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)
return rval;
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
if (!sp)
return rval;
fcport->flags |= FCF_ASYNC_SENT;
fcport->logout_completed = 0;
sp->type = SRB_PRLI_CMD;
sp->name = "prli";
qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
lio = &sp->u.iocb_cmd;
lio->timeout = qla2x00_async_iocb_timeout;
sp->done = qla2x00_async_prli_sp_done;
lio->u.logio.flags = 0;
if (fcport->fc4f_nvme)
lio->u.logio.flags |= SRB_LOGIN_NVME_PRLI;
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS) {
fcport->flags &= ~FCF_ASYNC_SENT;
fcport->flags |= FCF_LOGIN_NEEDED;
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
goto done_free_sp;
}
ql_dbg(ql_dbg_disc, vha, 0x211b,
"Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d.\n",
fcport->port_name, sp->handle, fcport->loop_id,
fcport->d_id.b24, fcport->login_retry);
return rval;
done_free_sp:
sp->free(sp);
fcport->flags &= ~FCF_ASYNC_SENT;
return rval;
}
static int qla24xx_post_gpdb_work(struct scsi_qla_host *vha, fc_port_t *fcport,
u8 opt)
{
......@@ -1126,6 +1235,9 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
case FCME_PLOGI_DONE: /* Initiator side sent LLIOCB */
qla24xx_handle_plogi_done_event(vha, ea);
break;
case FCME_PRLI_DONE:
qla24xx_handle_prli_done_event(vha, ea);
break;
case FCME_GPDB_DONE:
qla24xx_handle_gpdb_event(vha, ea);
break;
......@@ -1307,6 +1419,27 @@ qla24xx_async_abort_command(srb_t *sp)
return qla24xx_async_abort_cmd(sp);
}
static void
qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
{
switch (ea->data[0]) {
case MBS_COMMAND_COMPLETE:
ql_dbg(ql_dbg_disc, vha, 0x2118,
"%s %d %8phC post gpdb\n",
__func__, __LINE__, ea->fcport->port_name);
ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset;
ea->fcport->logout_on_delete = 1;
qla24xx_post_gpdb_work(vha, ea->fcport, 0);
break;
default:
ql_dbg(ql_dbg_disc, vha, 0x2119,
"%s %d %8phC unhandle event of %x\n",
__func__, __LINE__, ea->fcport->port_name, ea->data[0]);
break;
}
}
static void
qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
{
......@@ -1319,12 +1452,19 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
* force a relogin attempt via implicit LOGO, PLOGI, and PRLI
* requests.
*/
ql_dbg(ql_dbg_disc, vha, 0x20ea,
"%s %d %8phC post gpdb\n",
__func__, __LINE__, ea->fcport->port_name);
ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset;
ea->fcport->logout_on_delete = 1;
qla24xx_post_gpdb_work(vha, ea->fcport, 0);
if (ea->fcport->fc4f_nvme) {
ql_dbg(ql_dbg_disc, vha, 0x2117,
"%s %d %8phC post prli\n",
__func__, __LINE__, ea->fcport->port_name);
qla24xx_post_prli_work(vha, ea->fcport);
} else {
ql_dbg(ql_dbg_disc, vha, 0x20ea,
"%s %d %8phC post gpdb\n",
__func__, __LINE__, ea->fcport->port_name);
ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset;
ea->fcport->logout_on_delete = 1;
qla24xx_post_gpdb_work(vha, ea->fcport, 0);
}
break;
case MBS_COMMAND_ERROR:
ql_dbg(ql_dbg_disc, vha, 0x20eb, "%s %d %8phC cmd error %x\n",
......@@ -4646,6 +4786,16 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha)
new_fcport->fp_speed = swl[swl_idx].fp_speed;
new_fcport->fc4_type = swl[swl_idx].fc4_type;
new_fcport->nvme_flag = 0;
if (vha->flags.nvme_enabled &&
swl[swl_idx].fc4f_nvme) {
new_fcport->fc4f_nvme =
swl[swl_idx].fc4f_nvme;
ql_log(ql_log_info, vha, 0x2131,
"FOUND: NVME port %8phC as FC Type 28h\n",
new_fcport->port_name);
}
if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
last_dev = 1;
}
......
......@@ -2210,6 +2210,23 @@ qla2x00_alloc_iocbs(struct scsi_qla_host *vha, srb_t *sp)
return __qla2x00_alloc_iocbs(vha->hw->base_qpair, sp);
}
static void
qla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio)
{
struct srb_iocb *lio = &sp->u.iocb_cmd;
logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI);
if (lio->u.logio.flags & SRB_LOGIN_NVME_PRLI)
logio->control_flags |= LCF_NVME_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;
logio->port_id[2] = sp->fcport->d_id.b.domain;
logio->vp_index = sp->vha->vp_idx;
}
static void
qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
{
......@@ -2217,6 +2234,7 @@ qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
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)
......@@ -3162,6 +3180,9 @@ qla2x00_start_sp(srb_t *sp)
qla24xx_login_iocb(sp, pkt) :
qla2x00_login_iocb(sp, pkt);
break;
case SRB_PRLI_CMD:
qla24xx_prli_iocb(sp, pkt);
break;
case SRB_LOGOUT_CMD:
IS_FWI2_CAPABLE(ha) ?
qla24xx_logout_iocb(sp, pkt) :
......
......@@ -5968,14 +5968,22 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport,
{
int rval = QLA_SUCCESS;
uint64_t zero = 0;
u8 current_login_state, last_login_state;
if (fcport->fc4f_nvme) {
current_login_state = pd->current_login_state >> 4;
last_login_state = pd->last_login_state >> 4;
} else {
current_login_state = pd->current_login_state & 0xf;
last_login_state = pd->last_login_state & 0xf;
}
/* Check for logged in state. */
if (pd->current_login_state != PDS_PRLI_COMPLETE &&
pd->last_login_state != PDS_PRLI_COMPLETE) {
if (current_login_state != PDS_PRLI_COMPLETE &&
last_login_state != PDS_PRLI_COMPLETE) {
ql_dbg(ql_dbg_mbx, vha, 0x119a,
"Unable to verify login-state (%x/%x) for loop_id %x.\n",
pd->current_login_state, pd->last_login_state,
fcport->loop_id);
current_login_state, last_login_state, fcport->loop_id);
rval = QLA_FUNCTION_FAILED;
goto gpd_error_out;
}
......@@ -5998,12 +6006,17 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport,
fcport->d_id.b.al_pa = pd->port_id[2];
fcport->d_id.b.rsvd_1 = 0;
/* If not target must be initiator or unknown type. */
if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0)
fcport->port_type = FCT_INITIATOR;
else
fcport->port_type = FCT_TARGET;
if (fcport->fc4f_nvme) {
fcport->nvme_prli_service_param =
pd->prli_nvme_svc_param_word_3;
fcport->port_type = FCT_NVME;
} else {
/* If not target must be initiator or unknown type. */
if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0)
fcport->port_type = FCT_INITIATOR;
else
fcport->port_type = FCT_TARGET;
}
/* Passback COS information. */
fcport->supported_classes = (pd->flags & PDF_CLASS_2) ?
FC_COS_CLASS2 : FC_COS_CLASS3;
......
......@@ -4428,6 +4428,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
INIT_LIST_HEAD(&vha->plogi_ack_list);
INIT_LIST_HEAD(&vha->qp_list);
INIT_LIST_HEAD(&vha->gnl.fcports);
INIT_LIST_HEAD(&vha->nvme_rport_list);
spin_lock_init(&vha->work_lock);
spin_lock_init(&vha->cmd_list_lock);
......@@ -4717,6 +4718,9 @@ qla2x00_do_work(struct scsi_qla_host *vha)
qla24xx_async_gpdb(vha, e->u.fcport.fcport,
e->u.fcport.opt);
break;
case QLA_EVT_PRLI:
qla24xx_async_prli(vha, e->u.fcport.fcport);
break;
case QLA_EVT_GPSC:
qla24xx_async_gpsc(vha, e->u.fcport.fcport);
break;
......
......@@ -963,7 +963,6 @@ static void qlt_free_session_done(struct work_struct *work)
sess->logout_on_delete, sess->keep_nport_handle,
sess->send_els_logo);
if (!IS_SW_RESV_ADDR(sess->d_id)) {
if (sess->send_els_logo) {
qlt_port_logo_t logo;
......@@ -1118,6 +1117,9 @@ void qlt_unreg_sess(struct fc_port *sess)
sess->last_rscn_gen = sess->rscn_gen;
sess->last_login_gen = sess->login_gen;
if (sess->nvme_flag & NVME_FLAG_REGISTERED)
schedule_work(&sess->nvme_del_work);
INIT_WORK(&sess->free_work, qlt_free_session_done);
schedule_work(&sess->free_work);
}
......
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