#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;
 #define SRB_NACK_PLOGI 16
 #define SRB_NACK_PRLI  17
 #define SRB_NACK_LOGO  18
+#define SRB_PRLI_CMD   21
 
 enum {
        TYPE_SRB,
 #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
 
        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 */
        FCT_SWITCH,
        FCT_BROADCAST,
        FCT_INITIATOR,
-       FCT_TARGET
+       FCT_TARGET,
+       FCT_NVME
 } fc_port_type_t;
 
 enum qla_sess_deletion {
        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,
 };
 
        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;
        u32 supported_classes;
 
        uint8_t fc4_type;
+       uint8_t fc4f_nvme;
        uint8_t scan_state;
 
        unsigned long last_queue_full;
 
        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;
 
                struct {
                        uint8_t reserved;
-                       uint8_t port_name[3];
+                       uint8_t port_id[3];
                } gff_id;
 
                struct {
        QLA_EVT_GPNID_DONE,
        QLA_EVT_NEW_SESS,
        QLA_EVT_GPDB,
+       QLA_EVT_PRLI,
        QLA_EVT_GPSC,
        QLA_EVT_UPD_FCPORT,
        QLA_EVT_GNL,
                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;
        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];
 
 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 ---------------------------------------------------------- */
 
        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);
        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;
 
                        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",
                        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) {
        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)
 {
        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;
        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)
 {
                 * 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",
                                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;
                                }
 
 {
        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;
        }
        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;