]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
scsi: qla2xxx: Add switch command to simplify fabric discovery
authorQuinn Tran <quinn.tran@cavium.com>
Thu, 28 Dec 2017 20:33:26 +0000 (12:33 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 4 Jan 2018 04:41:06 +0000 (23:41 -0500)
- add "async" gpn_ft, gnn_ft, gfpn_id, gnn_id switch commands.
- For 8G and newer adapters, use async commands when it comes to
fabric scan to reduce bottle neck.

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>
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h

index 9ce28c4f9812b6a4890fd909ae3fec8f6b39bd0c..b360df9936ffb0ef4ae48673775a5ce7f02a5ee4 100644 (file)
@@ -2170,6 +2170,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
        dma_free_coherent(&ha->pdev->dev, vha->gnl.size, vha->gnl.l,
            vha->gnl.ldma);
 
+       vfree(vha->scan.l);
+
        if (vha->qpair && vha->qpair->vp_idx == vha->vp_idx) {
                if (qla2xxx_delete_qpair(vha, vha->qpair) != QLA_SUCCESS)
                        ql_log(ql_log_warn, vha, 0x7087,
index bf50b4fbe64866c669a4ace803a00a66be126b03..240767c862e6fa326595d5eeffdf8c1a5aafae78 100644 (file)
@@ -2270,11 +2270,13 @@ struct ct_sns_desc {
 
 enum discovery_state {
        DSC_DELETED,
+       DSC_GNN_ID,
        DSC_GID_PN,
        DSC_GNL,
        DSC_LOGIN_PEND,
        DSC_LOGIN_FAILED,
        DSC_GPDB,
+       DSC_GFPN_ID,
        DSC_GPSC,
        DSC_UPD_FCPORT,
        DSC_LOGIN_COMPLETE,
@@ -2304,8 +2306,9 @@ enum fcport_mgt_event {
        FCME_GPDB_DONE,
        FCME_GPNID_DONE,
        FCME_GFFID_DONE,
-       FCME_DELETE_DONE,
        FCME_ADISC_DONE,
+       FCME_GNNID_DONE,
+       FCME_GFPNID_DONE,
 };
 
 enum rscn_addr_format {
@@ -2338,6 +2341,7 @@ typedef struct fc_port {
        unsigned int login_pause:1;
        unsigned int login_succ:1;
        unsigned int query:1;
+       unsigned int id_changed:1;
 
        struct work_struct nvme_del_work;
        struct completion nvme_del_done;
@@ -2485,6 +2489,11 @@ static const char * const port_state_str[] = {
 #define        GA_NXT_REQ_SIZE (16 + 4)
 #define        GA_NXT_RSP_SIZE (16 + 620)
 
+#define        GPN_FT_CMD      0x172
+#define        GPN_FT_REQ_SIZE (16 + 4)
+#define        GNN_FT_CMD      0x173
+#define        GNN_FT_REQ_SIZE (16 + 4)
+
 #define        GID_PT_CMD      0x1A1
 #define        GID_PT_REQ_SIZE (16 + 4)
 
@@ -2739,6 +2748,13 @@ struct ct_sns_req {
                        uint8_t port_id[3];
                } port_id;
 
+               struct {
+                       uint8_t reserved;
+                       uint8_t domain;
+                       uint8_t area;
+                       uint8_t port_type;
+               } gpn_ft;
+
                struct {
                        uint8_t port_type;
                        uint8_t domain;
@@ -2852,6 +2868,27 @@ struct ct_sns_gid_pt_data {
        uint8_t port_id[3];
 };
 
+/* It's the same for both GPN_FT and GNN_FT */
+struct ct_sns_gpnft_rsp {
+       struct {
+               struct ct_cmd_hdr header;
+               uint16_t response;
+               uint16_t residual;
+               uint8_t fragment_id;
+               uint8_t reason_code;
+               uint8_t explanation_code;
+               uint8_t vendor_unique;
+       };
+       /* Assume the largest number of targets for the union */
+       struct ct_sns_gpn_ft_data {
+               u8 control_byte;
+               u8 port_id[3];
+               u32 reserved;
+               u8 port_name[8];
+       } entries[1];
+};
+
+/* CT command response */
 struct ct_sns_rsp {
        struct ct_rsp_hdr header;
 
@@ -2927,6 +2964,24 @@ struct ct_sns_pkt {
        } p;
 };
 
+struct ct_sns_gpnft_pkt {
+       union {
+               struct ct_sns_req req;
+               struct ct_sns_gpnft_rsp rsp;
+       } p;
+};
+
+struct fab_scan_rp {
+       port_id_t id;
+       u8 port_name[8];
+       u8 node_name[8];
+};
+
+struct fab_scan {
+       struct fab_scan_rp *l;
+       u32 size;
+};
+
 /*
  * SNS command structures -- for 2200 compatibility.
  */
@@ -3143,6 +3198,11 @@ enum qla_work_type {
        QLA_EVT_RELOGIN,
        QLA_EVT_ASYNC_PRLO,
        QLA_EVT_ASYNC_PRLO_DONE,
+       QLA_EVT_GPNFT,
+       QLA_EVT_GPNFT_DONE,
+       QLA_EVT_GNNFT_DONE,
+       QLA_EVT_GNNID,
+       QLA_EVT_GFPNID,
 };
 
 
@@ -3184,7 +3244,9 @@ struct qla_work_evt {
                struct {
                        port_id_t id;
                        u8 port_name[8];
+                       u8 node_name[8];
                        void *pla;
+                       u8 fc4_type;
                } new_sess;
                struct { /*Get PDB, Get Speed, update fcport, gnl, gidpn */
                        fc_port_t *fcport;
@@ -3195,6 +3257,9 @@ struct qla_work_evt {
                        u8 iocb[IOCB_SIZE];
                        int type;
                } nack;
+               struct {
+                       u8 fc4_type;
+               } gpnft;
         } u;
 };
 
@@ -3729,6 +3794,8 @@ struct qla_hw_data {
        (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
 #define IS_EXLOGIN_OFFLD_CAPABLE(ha) \
        (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha))
+#define USE_ASYNC_SCAN(ha) (IS_QLA25XX(ha) || IS_QLA81XX(ha) ||\
+       IS_QLA83XX(ha) || IS_QLA27XX(ha))
 
        /* HBA serial number */
        uint8_t         serial0;
@@ -3811,7 +3878,7 @@ struct qla_hw_data {
        int             exchoffld_size;
        int             exchoffld_count;
 
-       void            *swl;
+       void            *swl;
 
        /* These are used by mailbox operations. */
        uint16_t mailbox_out[MAILBOX_REGISTER_COUNT];
@@ -4271,6 +4338,7 @@ typedef struct scsi_qla_host {
        uint8_t n2n_port_name[WWN_SIZE];
        uint16_t        n2n_id;
        struct list_head gpnid_list;
+       struct fab_scan scan;
 } scsi_qla_host_t;
 
 struct qla27xx_image_status {
index 9d7b66abfc10e5cbaa4cde41f019f4f71532bdfa..4e504e5e7586f72afa2cfb8c92c35ec848f350cf 100644 (file)
@@ -105,8 +105,8 @@ 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 *,
-    void *);
+int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, u8*,
+    void *, u8);
 int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *);
 int qla24xx_detect_sfp(scsi_qla_host_t *vha);
 int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8);
@@ -655,9 +655,20 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *, struct event_arg *);
 
 int qla24xx_post_gpsc_work(struct scsi_qla_host *, fc_port_t *);
 int qla24xx_async_gpsc(scsi_qla_host_t *, fc_port_t *);
+void qla24xx_handle_gpsc_event(scsi_qla_host_t *, struct event_arg *);
 int qla2x00_mgmt_svr_login(scsi_qla_host_t *);
 void qla24xx_handle_gffid_event(scsi_qla_host_t *vha, struct event_arg *ea);
 int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport);
+int qla24xx_async_gpnft(scsi_qla_host_t *, u8);
+void qla24xx_async_gpnft_done(scsi_qla_host_t *, srb_t *);
+void qla24xx_async_gnnft_done(scsi_qla_host_t *, srb_t *);
+int qla24xx_async_gnnid(scsi_qla_host_t *, fc_port_t *);
+void qla24xx_handle_gnnid_event(scsi_qla_host_t *, struct event_arg *);
+int qla24xx_post_gnnid_work(struct scsi_qla_host *, fc_port_t *);
+int qla24xx_post_gfpnid_work(struct scsi_qla_host *, fc_port_t *);
+int qla24xx_async_gfpnid(scsi_qla_host_t *, fc_port_t *);
+void qla24xx_handle_gfpnid_event(scsi_qla_host_t *, struct event_arg *);
+
 /*
  * Global Function Prototypes in qla_attr.c source file.
  */
index bb96219ce5255b2fdab275796b9d77c51f3552c9..2132c7ad8044f055b070e4fc75fde701fb8bcd3e 100644 (file)
@@ -2796,6 +2796,9 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea)
            "%s %8phC login state %d\n",
            __func__, fcport->port_name, fcport->fw_login_state);
 
+       if (fcport->disc_state == DSC_DELETE_PEND)
+               return;
+
        if (ea->sp->gen2 != fcport->login_gen) {
                /* PLOGI/PRLI/LOGO came in while cmd was out.*/
                ql_dbg(ql_dbg_disc, vha, 0x201e,
@@ -2814,7 +2817,21 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea)
                                /* cable plugged into the same place */
                                switch (vha->host->active_mode) {
                                case MODE_TARGET:
-                                       /* NOOP. let the other guy login to us.*/
+                                       if (fcport->fw_login_state ==
+                                           DSC_LS_PRLI_COMP) {
+                                               u16 data[2];
+                                               /*
+                                                * Late RSCN was delivered.
+                                                * Remote port already login'ed.
+                                                */
+                                               ql_dbg(ql_dbg_disc, vha, 0x201f,
+                                                   "%s %d %8phC post adisc\n",
+                                                   __func__, __LINE__,
+                                                   fcport->port_name);
+                                               data[0] = data[1] = 0;
+                                               qla2x00_post_async_adisc_work(
+                                                   vha, fcport, data);
+                                       }
                                        break;
                                case MODE_INITIATOR:
                                case MODE_DUAL:
@@ -2840,6 +2857,7 @@ void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea)
                                }
                        } else { /* fcport->d_id.b24 != ea->id.b24 */
                                fcport->d_id.b24 = ea->id.b24;
+                               fcport->id_changed = 1;
                                if (fcport->deleted != QLA_SESS_DELETED) {
                                        ql_dbg(ql_dbg_disc, vha, 0x2021,
                                            "%s %d %8phC post del sess\n",
@@ -3009,6 +3027,38 @@ int qla24xx_post_gpsc_work(struct scsi_qla_host *vha, fc_port_t *fcport)
        return qla2x00_post_work(vha, e);
 }
 
+void qla24xx_handle_gpsc_event(scsi_qla_host_t *vha, struct event_arg *ea)
+{
+       struct fc_port *fcport = ea->fcport;
+
+       ql_dbg(ql_dbg_disc, vha, 0x20d8,
+           "%s %8phC DS %d LS %d rscn %d|%d login %d|%d lid %d\n",
+           __func__, fcport->port_name, fcport->disc_state,
+           fcport->fw_login_state, fcport->last_rscn_gen, fcport->rscn_gen,
+           fcport->last_login_gen, fcport->login_gen,
+           fcport->loop_id);
+
+       if (fcport->disc_state == DSC_DELETE_PEND)
+               return;
+
+       if (ea->sp->gen2 != fcport->login_gen) {
+               /* target side must have changed it. */
+               ql_dbg(ql_dbg_disc, vha, 0x20d3,
+                   "%s %8phC generation changed rscn %d|%d login %d|%d\n",
+                   __func__, fcport->port_name, fcport->last_rscn_gen,
+                   fcport->rscn_gen, fcport->last_login_gen,
+                   fcport->login_gen);
+               return;
+       } else if (ea->sp->gen1 != fcport->rscn_gen) {
+               ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",
+                   __func__, __LINE__, fcport->port_name);
+               qla24xx_post_gidpn_work(vha, fcport);
+               return;
+       }
+
+       qla24xx_post_upd_fcport_work(vha, ea->fcport);
+}
+
 static void qla24xx_async_gpsc_sp_done(void *s, int res)
 {
        struct srb *sp = s;
@@ -3075,6 +3125,7 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res)
        ea.event = FCME_GPSC_DONE;
        ea.rc = res;
        ea.fcport = fcport;
+       ea.sp = sp;
        qla2x00_fcport_event_handler(vha, &ea);
 
        sp->free(sp);
@@ -3305,7 +3356,7 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
                            "%s %d %8phC post new sess\n",
                            __func__, __LINE__, ea->port_name);
                        qla24xx_post_newsess_work(vha, &ea->id,
-                           ea->port_name, NULL);
+                           ea->port_name, NULL, NULL, FC4_TYPE_UNKNOWN);
                }
        }
 }
@@ -3595,3 +3646,659 @@ int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport)
        fcport->flags &= ~FCF_ASYNC_SENT;
        return rval;
 }
+
+/* GPN_FT + GNN_FT*/
+static int qla2x00_is_a_vp(scsi_qla_host_t *vha, u64 wwn)
+{
+       struct qla_hw_data *ha = vha->hw;
+       scsi_qla_host_t *vp;
+       unsigned long flags;
+       u64 twwn;
+       int rc = 0;
+
+       if (!ha->num_vhosts)
+               return 0;
+
+       spin_lock_irqsave(&ha->vport_slock, flags);
+       list_for_each_entry(vp, &ha->vp_list, list) {
+               twwn = wwn_to_u64(vp->port_name);
+               if (wwn == twwn) {
+                       rc = 1;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&ha->vport_slock, flags);
+
+       return rc;
+}
+
+void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
+{
+       fc_port_t *fcport;
+       u32 i, rc;
+       bool found;
+       u8 fc4type = sp->gen2;
+       struct fab_scan_rp *rp;
+
+       ql_dbg(ql_dbg_disc, vha, 0xffff,
+           "%s enter\n", __func__);
+
+       if (sp->gen1 != vha->hw->base_qpair->chip_reset) {
+               ql_dbg(ql_dbg_disc, vha, 0xffff,
+                   "%s scan stop due to chip reset %x/%x\n",
+                   sp->name, sp->gen1, vha->hw->base_qpair->chip_reset);
+               goto out;
+       }
+
+       rc = sp->rc;
+       if (rc) {
+               ql_dbg(ql_dbg_disc, vha, 0xffff,
+                   "GPNFT failed. FC4type %x. Rescanning.\n",
+                   fc4type);
+               set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+               goto out;
+       }
+
+       list_for_each_entry(fcport, &vha->vp_fcports, list)
+               fcport->scan_state = QLA_FCPORT_SCAN;
+
+       for (i = 0; i < vha->hw->max_fibre_devices; i++) {
+               u64 wwn;
+
+               rp = &vha->scan.l[i];
+               found = false;
+
+               wwn = wwn_to_u64(rp->port_name);
+               if (wwn == 0)
+                       continue;
+
+               if (!memcmp(rp->port_name, vha->port_name, WWN_SIZE))
+                       continue;
+
+               /* Bypass reserved domain fields. */
+               if ((rp->id.b.domain & 0xf0) == 0xf0)
+                       continue;
+
+               /* Bypass virtual ports of the same host. */
+               if (qla2x00_is_a_vp(vha, wwn))
+                       continue;
+
+               list_for_each_entry(fcport, &vha->vp_fcports, list) {
+                       if (memcmp(rp->port_name, fcport->port_name, WWN_SIZE))
+                               continue;
+                       fcport->scan_state = QLA_FCPORT_FOUND;
+                       fcport->d_id.b24 = rp->id.b24;
+                       found = true;
+                       /*
+                        * If device was not a fabric device before.
+                        */
+                       if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
+                               qla2x00_clear_loop_id(fcport);
+                               fcport->flags |= FCF_FABRIC_DEVICE;
+                       }
+                       break;
+               }
+
+               if (!found) {
+                       ql_dbg(ql_dbg_disc, vha, 0xffff,
+                           "%s %d %8phC post new sess\n",
+                           __func__, __LINE__, rp->port_name);
+                       qla24xx_post_newsess_work(vha, &rp->id, rp->port_name,
+                           rp->node_name, NULL, fc4type);
+               }
+       }
+
+       /*
+        * Logout all previous fabric dev marked lost, except FCP2 devices.
+        */
+       list_for_each_entry(fcport, &vha->vp_fcports, list) {
+               if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
+                       continue;
+
+               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);
+       }
+
+out:
+       /* re-use gpnid_done to free resource */
+       qla24xx_async_gpnid_done(vha, sp);
+}
+
+static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res)
+{
+       struct srb *sp = s;
+       struct scsi_qla_host *vha = sp->vha;
+       struct qla_work_evt *e;
+       struct ct_sns_req *ct_req =
+               (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req;
+       struct ct_sns_gpnft_rsp *ct_rsp =
+               (struct ct_sns_gpnft_rsp *)sp->u.iocb_cmd.u.ctarg.rsp;
+       struct ct_sns_gpn_ft_data *d = &ct_rsp->entries[0];
+       struct fab_scan_rp *rp;
+       int i, j, k;
+       u16 cmd = be16_to_cpu(ct_req->command);
+
+       /* gen2 field is holding the fc4type */
+       ql_dbg(ql_dbg_disc, vha, 0xffff,
+           "Async done-%s res %x FC4Type %x\n",
+           sp->name, res, sp->gen2);
+
+       if (!res) {
+               port_id_t id;
+               u64 wwn;
+
+               j = 0;
+               for (i = 0; i < vha->hw->max_fibre_devices; i++) {
+                       d  = &ct_rsp->entries[i];
+
+                       id.b.rsvd_1 = 0;
+                       id.b.domain = d->port_id[0];
+                       id.b.area   = d->port_id[1];
+                       id.b.al_pa  = d->port_id[2];
+                       wwn = wwn_to_u64(d->port_name);
+
+                       if (id.b24 == 0 || wwn == 0)
+                               continue;
+
+                       if (cmd == GPN_FT_CMD) {
+                               rp = &vha->scan.l[j];
+                               rp->id = id;
+                               memcpy(rp->port_name, d->port_name, 8);
+                               j++;
+                       } else {/* GNN_FT_CMD */
+                               for (k = 0; k < vha->hw->max_fibre_devices;
+                                   k++) {
+                                       rp = &vha->scan.l[k];
+                                       if (id.b24 == rp->id.b24) {
+                                               memcpy(rp->node_name,
+                                                   d->port_name, 8);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if (cmd == GPN_FT_CMD)
+               e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT_DONE);
+       else
+               e = qla2x00_alloc_work(vha, QLA_EVT_GNNFT_DONE);
+       if (!e) {
+               /* please ignore kernel warning. Otherwise, we have mem leak. */
+               if (sp->u.iocb_cmd.u.ctarg.req) {
+                       dma_free_coherent(&vha->hw->pdev->dev,
+                           sizeof(struct ct_sns_pkt),
+                           sp->u.iocb_cmd.u.ctarg.req,
+                           sp->u.iocb_cmd.u.ctarg.req_dma);
+                       sp->u.iocb_cmd.u.ctarg.req = NULL;
+               }
+               if (sp->u.iocb_cmd.u.ctarg.rsp) {
+                       dma_free_coherent(&vha->hw->pdev->dev,
+                           sizeof(struct ct_sns_pkt),
+                           sp->u.iocb_cmd.u.ctarg.rsp,
+                           sp->u.iocb_cmd.u.ctarg.rsp_dma);
+                       sp->u.iocb_cmd.u.ctarg.rsp = NULL;
+               }
+
+               ql_dbg(ql_dbg_disc, vha, 0xffff,
+                   "Async done-%s unable to alloc work element\n",
+                   sp->name);
+               sp->free(sp);
+               set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+               return;
+       }
+
+       sp->rc = res;
+       e->u.iosb.sp = sp;
+
+       qla2x00_post_work(vha, e);
+}
+
+/*
+ * Get WWNN list for fc4_type
+ *
+ * It is assumed the same SRB is re-used from GPNFT to avoid
+ * mem free & re-alloc
+ */
+static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp,
+    u8 fc4_type)
+{
+       int rval = QLA_FUNCTION_FAILED;
+       struct ct_sns_req *ct_req;
+       struct ct_sns_pkt *ct_sns;
+
+       if (!vha->flags.online)
+               goto done_free_sp;
+
+       if (!sp->u.iocb_cmd.u.ctarg.req || !sp->u.iocb_cmd.u.ctarg.rsp) {
+               ql_log(ql_log_warn, vha, 0xffff,
+                   "%s: req %p rsp %p are not setup\n",
+                   __func__, sp->u.iocb_cmd.u.ctarg.req,
+                   sp->u.iocb_cmd.u.ctarg.rsp);
+               WARN_ON(1);
+               goto done_free_sp;
+       }
+       sp->type = SRB_CT_PTHRU_CMD;
+       sp->name = "gnnft";
+       sp->gen1 = vha->hw->base_qpair->chip_reset;
+       sp->gen2 = fc4_type;
+       qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
+
+       memset(sp->u.iocb_cmd.u.ctarg.rsp, 0, sp->u.iocb_cmd.u.ctarg.rsp_size);
+       memset(sp->u.iocb_cmd.u.ctarg.req, 0, sp->u.iocb_cmd.u.ctarg.req_size);
+
+       ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req;
+       /* CT_IU preamble  */
+       ct_req = qla2x00_prep_ct_req(ct_sns, GNN_FT_CMD,
+           sp->u.iocb_cmd.u.ctarg.rsp_size);
+
+       /* GPN_FT req */
+       ct_req->req.gpn_ft.port_type = fc4_type;
+
+       sp->u.iocb_cmd.u.ctarg.req_size = GNN_FT_REQ_SIZE;
+       sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS;
+
+       sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout;
+       sp->done = qla2x00_async_gpnft_gnnft_sp_done;
+
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+
+       ql_dbg(ql_dbg_disc, vha, 0xffff,
+           "Async-%s hdl=%x FC4Type %x.\n", sp->name,
+           sp->handle, ct_req->req.gpn_ft.port_type);
+       return rval;
+
+done_free_sp:
+       if (sp->u.iocb_cmd.u.ctarg.req) {
+               dma_free_coherent(&vha->hw->pdev->dev,
+                   sizeof(struct ct_sns_pkt),
+                   sp->u.iocb_cmd.u.ctarg.req,
+                   sp->u.iocb_cmd.u.ctarg.req_dma);
+               sp->u.iocb_cmd.u.ctarg.req = NULL;
+       }
+       if (sp->u.iocb_cmd.u.ctarg.rsp) {
+               dma_free_coherent(&vha->hw->pdev->dev,
+                   sizeof(struct ct_sns_pkt),
+                   sp->u.iocb_cmd.u.ctarg.rsp,
+                   sp->u.iocb_cmd.u.ctarg.rsp_dma);
+               sp->u.iocb_cmd.u.ctarg.rsp = NULL;
+       }
+
+       sp->free(sp);
+
+       return rval;
+} /* GNNFT */
+
+void qla24xx_async_gpnft_done(scsi_qla_host_t *vha, srb_t *sp)
+{
+       ql_dbg(ql_dbg_disc, vha, 0xffff,
+           "%s enter\n", __func__);
+       del_timer(&sp->u.iocb_cmd.timer);
+       qla24xx_async_gnnft(vha, sp, sp->gen2);
+}
+
+/* Get WWPN list for certain fc4_type */
+int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
+{
+       int rval = QLA_FUNCTION_FAILED;
+       struct ct_sns_req       *ct_req;
+       srb_t *sp;
+       struct ct_sns_pkt *ct_sns;
+       u32 rspsz;
+
+       if (!vha->flags.online)
+               return rval;
+
+       sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
+       if (!sp)
+               return rval;
+
+
+       sp->type = SRB_CT_PTHRU_CMD;
+       sp->name = "gpnft";
+       sp->gen1 = vha->hw->base_qpair->chip_reset;
+       sp->gen2 = fc4_type;
+       qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
+
+       sp->u.iocb_cmd.u.ctarg.req = dma_zalloc_coherent(&vha->hw->pdev->dev,
+           sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma,
+           GFP_KERNEL);
+       if (!sp->u.iocb_cmd.u.ctarg.req) {
+               ql_log(ql_log_warn, vha, 0xffff,
+                   "Failed to allocate ct_sns request.\n");
+               goto done_free_sp;
+       }
+
+       rspsz = sizeof(struct ct_sns_gpnft_rsp) +
+               ((vha->hw->max_fibre_devices - 1) *
+                   sizeof(struct ct_sns_gpn_ft_data));
+
+       sp->u.iocb_cmd.u.ctarg.rsp = dma_zalloc_coherent(&vha->hw->pdev->dev,
+           rspsz, &sp->u.iocb_cmd.u.ctarg.rsp_dma, GFP_KERNEL);
+       if (!sp->u.iocb_cmd.u.ctarg.rsp) {
+               ql_log(ql_log_warn, vha, 0xffff,
+                   "Failed to allocate ct_sns request.\n");
+               goto done_free_sp;
+       }
+
+       memset(vha->scan.l, 0, vha->scan.size);
+
+       ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req;
+       /* CT_IU preamble  */
+       ct_req = qla2x00_prep_ct_req(ct_sns, GPN_FT_CMD, rspsz);
+
+       /* GPN_FT req */
+       ct_req->req.gpn_ft.port_type = fc4_type;
+
+       sp->u.iocb_cmd.u.ctarg.req_size = GPN_FT_REQ_SIZE;
+       sp->u.iocb_cmd.u.ctarg.rsp_size = rspsz;
+       sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS;
+
+       sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout;
+       sp->done = qla2x00_async_gpnft_gnnft_sp_done;
+
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+
+       ql_dbg(ql_dbg_disc, vha, 0xffff,
+           "Async-%s hdl=%x FC4Type %x.\n", sp->name,
+           sp->handle, ct_req->req.gpn_ft.port_type);
+       return rval;
+
+done_free_sp:
+       if (sp->u.iocb_cmd.u.ctarg.req) {
+               dma_free_coherent(&vha->hw->pdev->dev,
+                   sizeof(struct ct_sns_pkt),
+                   sp->u.iocb_cmd.u.ctarg.req,
+                   sp->u.iocb_cmd.u.ctarg.req_dma);
+               sp->u.iocb_cmd.u.ctarg.req = NULL;
+       }
+       if (sp->u.iocb_cmd.u.ctarg.rsp) {
+               dma_free_coherent(&vha->hw->pdev->dev,
+                   sizeof(struct ct_sns_pkt),
+                   sp->u.iocb_cmd.u.ctarg.rsp,
+                   sp->u.iocb_cmd.u.ctarg.rsp_dma);
+               sp->u.iocb_cmd.u.ctarg.rsp = NULL;
+       }
+
+       sp->free(sp);
+
+       return rval;
+}
+
+/* GNN_ID */
+void qla24xx_handle_gnnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
+{
+       qla24xx_post_gnl_work(vha, ea->fcport);
+}
+
+static void qla2x00_async_gnnid_sp_done(void *s, int res)
+{
+       struct srb *sp = s;
+       struct scsi_qla_host *vha = sp->vha;
+       fc_port_t *fcport = sp->fcport;
+       u8 *node_name = fcport->ct_desc.ct_sns->p.rsp.rsp.gnn_id.node_name;
+       struct event_arg ea;
+       u64 wwnn;
+
+       fcport->flags &= ~FCF_ASYNC_SENT;
+       wwnn = wwn_to_u64(node_name);
+       if (wwnn)
+               memcpy(fcport->node_name, node_name, WWN_SIZE);
+
+       memset(&ea, 0, sizeof(ea));
+       ea.fcport = fcport;
+       ea.sp = sp;
+       ea.rc = res;
+       ea.event = FCME_GNNID_DONE;
+
+       ql_dbg(ql_dbg_disc, vha, 0x204f,
+           "Async done-%s res %x, WWPN %8phC %8phC\n",
+           sp->name, res, fcport->port_name, fcport->node_name);
+
+       qla2x00_fcport_event_handler(vha, &ea);
+
+       sp->free(sp);
+}
+
+int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport)
+{
+       int rval = QLA_FUNCTION_FAILED;
+       struct ct_sns_req       *ct_req;
+       srb_t *sp;
+
+       if (!vha->flags.online)
+               goto done;
+
+       fcport->flags |= FCF_ASYNC_SENT;
+       fcport->disc_state = DSC_GNN_ID;
+       sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
+       if (!sp)
+               goto done;
+
+       sp->type = SRB_CT_PTHRU_CMD;
+       sp->name = "gnnid";
+       sp->gen1 = fcport->rscn_gen;
+       sp->gen2 = fcport->login_gen;
+
+       qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
+
+       /* CT_IU preamble  */
+       ct_req = qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GNN_ID_CMD,
+           GNN_ID_RSP_SIZE);
+
+       /* GNN_ID req */
+       ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain;
+       ct_req->req.port_id.port_id[1] = fcport->d_id.b.area;
+       ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa;
+
+
+       /* req & rsp use the same buffer */
+       sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns;
+       sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma;
+       sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns;
+       sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma;
+       sp->u.iocb_cmd.u.ctarg.req_size = GNN_ID_REQ_SIZE;
+       sp->u.iocb_cmd.u.ctarg.rsp_size = GNN_ID_RSP_SIZE;
+       sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS;
+
+       sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout;
+       sp->done = qla2x00_async_gnnid_sp_done;
+
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+       ql_dbg(ql_dbg_disc, vha, 0xffff,
+           "Async-%s - %8phC hdl=%x loopid=%x portid %06x.\n",
+           sp->name, fcport->port_name,
+           sp->handle, fcport->loop_id, fcport->d_id.b24);
+       return rval;
+
+done_free_sp:
+       sp->free(sp);
+done:
+       fcport->flags &= ~FCF_ASYNC_SENT;
+       return rval;
+}
+
+int qla24xx_post_gnnid_work(struct scsi_qla_host *vha, fc_port_t *fcport)
+{
+       struct qla_work_evt *e;
+       int ls;
+
+       ls = atomic_read(&vha->loop_state);
+       if (((ls != LOOP_READY) && (ls != LOOP_UP)) ||
+               test_bit(UNLOADING, &vha->dpc_flags))
+               return 0;
+
+       e = qla2x00_alloc_work(vha, QLA_EVT_GNNID);
+       if (!e)
+               return QLA_FUNCTION_FAILED;
+
+       e->u.fcport.fcport = fcport;
+       return qla2x00_post_work(vha, e);
+}
+
+/* GPFN_ID */
+void qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
+{
+       fc_port_t *fcport = ea->fcport;
+
+       ql_dbg(ql_dbg_disc, vha, 0xffff,
+           "%s %d %8phC post gpsc fcp_cnt %d\n",
+           __func__, __LINE__, fcport->port_name,
+           vha->fcport_count);
+
+       if (fcport->disc_state == DSC_DELETE_PEND)
+               return;
+
+       if (ea->sp->gen2 != fcport->login_gen) {
+               /* target side must have changed it. */
+               ql_dbg(ql_dbg_disc, vha, 0x20d3,
+                   "%s %8phC generation changed rscn %d|%d login %d|%d\n",
+                   __func__, fcport->port_name, fcport->last_rscn_gen,
+                   fcport->rscn_gen, fcport->last_login_gen,
+                   fcport->login_gen);
+               return;
+       } else if (ea->sp->gen1 != fcport->rscn_gen) {
+               ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",
+                   __func__, __LINE__, fcport->port_name);
+               qla24xx_post_gidpn_work(vha, fcport);
+               return;
+       }
+
+       qla24xx_post_gpsc_work(vha, fcport);
+}
+
+static void qla2x00_async_gfpnid_sp_done(void *s, int res)
+{
+       struct srb *sp = s;
+       struct scsi_qla_host *vha = sp->vha;
+       fc_port_t *fcport = sp->fcport;
+       u8 *fpn = fcport->ct_desc.ct_sns->p.rsp.rsp.gfpn_id.port_name;
+       struct event_arg ea;
+       u64 wwn;
+
+       fcport->flags &= ~FCF_ASYNC_SENT;
+       wwn = wwn_to_u64(fpn);
+       if (wwn)
+               memcpy(fcport->fabric_port_name, fpn, WWN_SIZE);
+
+       memset(&ea, 0, sizeof(ea));
+       ea.fcport = fcport;
+       ea.sp = sp;
+       ea.rc = res;
+       ea.event = FCME_GFPNID_DONE;
+
+       ql_dbg(ql_dbg_disc, vha, 0x204f,
+           "Async done-%s res %x, WWPN %8phC %8phC\n",
+           sp->name, res, fcport->port_name, fcport->fabric_port_name);
+
+       qla2x00_fcport_event_handler(vha, &ea);
+
+       sp->free(sp);
+}
+
+int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport)
+{
+       int rval = QLA_FUNCTION_FAILED;
+       struct ct_sns_req       *ct_req;
+       srb_t *sp;
+
+       if (!vha->flags.online)
+               goto done;
+
+       fcport->flags |= FCF_ASYNC_SENT;
+       fcport->disc_state = DSC_GFPN_ID;
+       sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
+       if (!sp)
+               goto done;
+
+       sp->type = SRB_CT_PTHRU_CMD;
+       sp->name = "gfpnid";
+       sp->gen1 = fcport->rscn_gen;
+       sp->gen2 = fcport->login_gen;
+
+       qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
+
+       /* CT_IU preamble  */
+       ct_req = qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GFPN_ID_CMD,
+           GFPN_ID_RSP_SIZE);
+
+       /* GFPN_ID req */
+       ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain;
+       ct_req->req.port_id.port_id[1] = fcport->d_id.b.area;
+       ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa;
+
+
+       /* req & rsp use the same buffer */
+       sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns;
+       sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma;
+       sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns;
+       sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma;
+       sp->u.iocb_cmd.u.ctarg.req_size = GFPN_ID_REQ_SIZE;
+       sp->u.iocb_cmd.u.ctarg.rsp_size = GFPN_ID_RSP_SIZE;
+       sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS;
+
+       sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout;
+       sp->done = qla2x00_async_gfpnid_sp_done;
+
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+
+       ql_dbg(ql_dbg_disc, vha, 0xffff,
+           "Async-%s - %8phC hdl=%x loopid=%x portid %06x.\n",
+           sp->name, fcport->port_name,
+           sp->handle, fcport->loop_id, fcport->d_id.b24);
+       return rval;
+
+done_free_sp:
+       sp->free(sp);
+done:
+       fcport->flags &= ~FCF_ASYNC_SENT;
+       return rval;
+}
+
+int qla24xx_post_gfpnid_work(struct scsi_qla_host *vha, fc_port_t *fcport)
+{
+       struct qla_work_evt *e;
+       int ls;
+
+       ls = atomic_read(&vha->loop_state);
+       if (((ls != LOOP_READY) && (ls != LOOP_UP)) ||
+               test_bit(UNLOADING, &vha->dpc_flags))
+               return 0;
+
+       e = qla2x00_alloc_work(vha, QLA_EVT_GFPNID);
+       if (!e)
+               return QLA_FUNCTION_FAILED;
+
+       e->u.fcport.fcport = fcport;
+       return qla2x00_post_work(vha, e);
+}
index c671852131ef45c0f362e82e271294adfdd8196d..f26acb7ce3153519950b822111f3f960e0facd37 100644 (file)
@@ -41,7 +41,7 @@ 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 *);
-static void qla24xx_handle_gpdb_event(scsi_qla_host_t *, struct event_arg *);
+static void __qla24xx_handle_gpdb_event(scsi_qla_host_t *, struct event_arg *);
 
 /* SRB Extensions ---------------------------------------------------------- */
 
@@ -188,8 +188,11 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
        fcport->flags |= FCF_ASYNC_SENT;
        fcport->logout_completed = 0;
 
+       fcport->disc_state = DSC_LOGIN_PEND;
        sp->type = SRB_LOGIN_CMD;
        sp->name = "login";
+       sp->gen1 = fcport->rscn_gen;
+       sp->gen2 = fcport->login_gen;
        qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
 
        lio = &sp->u.iocb_cmd;
@@ -336,7 +339,36 @@ qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport)
 static
 void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea)
 {
-       qla24xx_handle_gpdb_event(vha, ea);
+       if (ea->rc) {
+               ql_dbg(ql_dbg_disc, vha, 0x2066,
+                   "%s %8phC: adisc fail: post delete\n",
+                   __func__, ea->fcport->port_name);
+               qlt_schedule_sess_for_deletion(ea->fcport, 1);
+               return;
+       }
+       ql_dbg(ql_dbg_disc, vha, 0x20d2,
+           "%s %8phC DS %d LS %d\n", __func__, ea->fcport->port_name,
+           ea->fcport->disc_state, ea->fcport->fw_login_state);
+
+       if (ea->fcport->disc_state == DSC_DELETE_PEND)
+               return;
+
+       if (ea->sp->gen2 != ea->fcport->login_gen) {
+               /* target side must have changed it. */
+               ql_dbg(ql_dbg_disc, vha, 0x20d3,
+                   "%s %8phC generation changed rscn %d|%d login %d|%d\n",
+                   __func__, ea->fcport->port_name, ea->fcport->last_rscn_gen,
+                   ea->fcport->rscn_gen, ea->fcport->last_login_gen,
+                   ea->fcport->login_gen);
+               return;
+       } else if (ea->sp->gen1 != ea->fcport->rscn_gen) {
+               ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",
+                   __func__, __LINE__, ea->fcport->port_name);
+               qla24xx_post_gidpn_work(vha, ea->fcport);
+               return;
+       }
+
+       __qla24xx_handle_gpdb_event(vha, ea);
 }
 
 static void
@@ -409,10 +441,14 @@ 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, current_login_state;
+       u16 data[2];
+       u8 current_login_state;
 
        fcport = ea->fcport;
 
+       if (fcport->disc_state == DSC_DELETE_PEND)
+               return;
+
        if (ea->rc) { /* rval */
                if (fcport->login_retry == 0) {
                        fcport->login_retry = vha->hw->login_retry_count;
@@ -506,8 +542,14 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
                        ql_dbg(ql_dbg_disc, vha, 0x20e4,
                            "%s %d %8phC post gpdb\n",
                            __func__, __LINE__, fcport->port_name);
-                       opt = PDO_FORCE_ADISC;
-                       qla24xx_post_gpdb_work(vha, fcport, opt);
+
+                       if ((e->prli_svc_param_word_3[0] & BIT_4) == 0)
+                               fcport->port_type = FCT_INITIATOR;
+                       else
+                               fcport->port_type = FCT_TARGET;
+
+                       data[0] = data[1] = 0;
+                       qla2x00_post_async_adisc_work(vha, fcport, data);
                        break;
                case DSC_LS_PORT_UNAVAIL:
                default:
@@ -572,6 +614,7 @@ qla24xx_async_gnl_sp_done(void *s, int res)
        struct get_name_list_extended *e;
        u64 wwn;
        struct list_head h;
+       bool found = false;
 
        ql_dbg(ql_dbg_disc, vha, 0x20e7,
            "Async done-%s res %x mb[1]=%x mb[2]=%x \n",
@@ -621,6 +664,38 @@ qla24xx_async_gnl_sp_done(void *s, int res)
                qla2x00_fcport_event_handler(vha, &ea);
        }
 
+       /* create new fcport if fw has knowledge of new sessions */
+       for (i = 0; i < n; i++) {
+               port_id_t id;
+               u64 wwnn;
+
+               e = &vha->gnl.l[i];
+               wwn = wwn_to_u64(e->port_name);
+
+               found = false;
+               list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
+                       if (!memcmp((u8 *)&wwn, fcport->port_name,
+                           WWN_SIZE)) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               id.b.domain = e->port_id[0];
+               id.b.area = e->port_id[1];
+               id.b.al_pa = e->port_id[2];
+               id.b.rsvd_1 = 0;
+
+               if (!found && wwn && !IS_SW_RESV_ADDR(id)) {
+                       ql_dbg(ql_dbg_disc, vha, 0x2065,
+                           "%s %d %8phC post new sess\n",
+                           __func__, __LINE__, (u8 *)&wwn);
+                       wwnn = wwn_to_u64(e->node_name);
+                       qla24xx_post_newsess_work(vha, &id, (u8 *)&wwn,
+                           (u8 *)&wwnn, NULL, FC4_TYPE_UNKNOWN);
+               }
+       }
+
        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 
        sp->free(sp);
@@ -715,10 +790,8 @@ void qla24xx_async_gpdb_sp_done(void *s, int res)
        struct srb *sp = s;
        struct scsi_qla_host *vha = sp->vha;
        struct qla_hw_data *ha = vha->hw;
-       struct port_database_24xx *pd;
        fc_port_t *fcport = sp->fcport;
        u16 *mb = sp->u.iocb_cmd.u.mbx.in_mb;
-       int rval = QLA_SUCCESS;
        struct event_arg ea;
 
        ql_dbg(ql_dbg_disc, vha, 0x20db,
@@ -727,19 +800,8 @@ void qla24xx_async_gpdb_sp_done(void *s, int res)
 
        fcport->flags &= ~FCF_ASYNC_SENT;
 
-       if (res) {
-               rval = res;
-               goto gpd_error_out;
-       }
-
-       pd = (struct port_database_24xx *)sp->u.iocb_cmd.u.mbx.in;
-
-       rval = __qla24xx_parse_gpdb(vha, fcport, pd);
-
-gpd_error_out:
        memset(&ea, 0, sizeof(ea));
        ea.event = FCME_GPDB_DONE;
-       ea.rc = rval;
        ea.fcport = fcport;
        ea.sp = sp;
 
@@ -934,41 +996,10 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt)
 }
 
 static
-void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
+void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
 {
-       int rval = ea->rc;
-       fc_port_t *fcport = ea->fcport;
        unsigned long flags;
 
-       fcport->flags &= ~FCF_ASYNC_SENT;
-
-       ql_dbg(ql_dbg_disc, vha, 0x20d2,
-           "%s %8phC DS %d LS %d rval %d\n", __func__, fcport->port_name,
-           fcport->disc_state, fcport->fw_login_state, rval);
-
-       if (ea->sp->gen2 != fcport->login_gen) {
-               /* target side must have changed it. */
-               ql_dbg(ql_dbg_disc, vha, 0x20d3,
-                   "%s %8phC generation changed rscn %d|%d login %d|%d \n",
-                   __func__, fcport->port_name, fcport->last_rscn_gen,
-                   fcport->rscn_gen, fcport->last_login_gen,
-                   fcport->login_gen);
-               set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
-               return;
-       } else if (ea->sp->gen1 != fcport->rscn_gen) {
-               ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",
-                   __func__, __LINE__, fcport->port_name);
-               qla24xx_post_gidpn_work(vha, fcport);
-               return;
-       }
-
-       if (rval != QLA_SUCCESS) {
-               ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC post del sess\n",
-                   __func__, __LINE__, fcport->port_name);
-               qlt_schedule_sess_for_deletion_lock(fcport);
-               return;
-       }
-
        spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
        ea->fcport->login_gen++;
        ea->fcport->deleted = 0;
@@ -982,32 +1013,81 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
                    !vha->hw->flags.gpsc_supported) {
                        ql_dbg(ql_dbg_disc, vha, 0x20d6,
                            "%s %d %8phC post upd_fcport fcp_cnt %d\n",
-                           __func__, __LINE__, fcport->port_name,
+                           __func__, __LINE__,  ea->fcport->port_name,
                            vha->fcport_count);
 
-                       qla24xx_post_upd_fcport_work(vha, fcport);
+                       qla24xx_post_upd_fcport_work(vha, ea->fcport);
                } else {
-                       ql_dbg(ql_dbg_disc, vha, 0x20d7,
-                           "%s %d %8phC post gpsc fcp_cnt %d\n",
-                           __func__, __LINE__, fcport->port_name,
-                           vha->fcport_count);
-
-                       qla24xx_post_gpsc_work(vha, fcport);
+                       if (ea->fcport->id_changed) {
+                               ea->fcport->id_changed = 0;
+                               ql_dbg(ql_dbg_disc, vha, 0x20d7,
+                                   "%s %d %8phC post gfpnid fcp_cnt %d\n",
+                                   __func__, __LINE__, ea->fcport->port_name,
+                                   vha->fcport_count);
+                               qla24xx_post_gfpnid_work(vha, ea->fcport);
+                       } else {
+                               ql_dbg(ql_dbg_disc, vha, 0x20d7,
+                                   "%s %d %8phC post gpsc fcp_cnt %d\n",
+                                   __func__, __LINE__, ea->fcport->port_name,
+                                   vha->fcport_count);
+                               qla24xx_post_gpsc_work(vha, ea->fcport);
+                       }
                }
        } else if (ea->fcport->login_succ) {
                /*
                 * We have an existing session. A late RSCN delivery
                 * must have triggered the session to be re-validate.
-                * session is still valid.
+                * Session is still valid.
                 */
                ql_dbg(ql_dbg_disc, vha, 0x20d6,
                    "%s %d %8phC session revalidate success\n",
-                   __func__, __LINE__, fcport->port_name);
-               fcport->disc_state = DSC_LOGIN_COMPLETE;
+                   __func__, __LINE__, ea->fcport->port_name);
+                ea->fcport->disc_state = DSC_LOGIN_COMPLETE;
        }
        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
-} /* gpdb event */
+}
+
+static
+void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
+{
+       int rval = ea->rc;
+       fc_port_t *fcport = ea->fcport;
+       struct port_database_24xx *pd;
+       struct srb *sp = ea->sp;
+
+       pd = (struct port_database_24xx *)sp->u.iocb_cmd.u.mbx.in;
+
+       fcport->flags &= ~FCF_ASYNC_SENT;
+
+       ql_dbg(ql_dbg_disc, vha, 0x20d2,
+           "%s %8phC DS %d LS %d rval %d\n", __func__, fcport->port_name,
+           fcport->disc_state, pd->current_login_state, rval);
+
+       if (fcport->disc_state == DSC_DELETE_PEND)
+               return;
 
+       switch (pd->current_login_state) {
+       case PDS_PRLI_COMPLETE:
+               __qla24xx_parse_gpdb(vha, fcport, pd);
+               break;
+       case PDS_PLOGI_PENDING:
+       case PDS_PLOGI_COMPLETE:
+       case PDS_PRLI_PENDING:
+       case PDS_PRLI2_PENDING:
+               ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC relogin needed\n",
+                   __func__, __LINE__, fcport->port_name);
+               set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
+               return;
+       case PDS_LOGO_PENDING:
+       case PDS_PORT_UNAVAILABLE:
+       default:
+               ql_dbg(ql_dbg_disc, vha, 0x20d5, "%s %d %8phC post del sess\n",
+                   __func__, __LINE__, fcport->port_name);
+               qlt_schedule_sess_for_deletion_lock(fcport);
+               return;
+       }
+       __qla24xx_handle_gpdb_event(vha, ea);
+} /* gpdb event */
 
 static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport)
 {
@@ -1048,21 +1128,21 @@ static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport)
 int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
 {
        u16 data[2];
-       if (fcport->login_retry == 0)
-               return 0;
-
-       if (fcport->scan_state != QLA_FCPORT_FOUND)
-               return 0;
+       u64 wwn;
 
        ql_dbg(ql_dbg_disc, vha, 0x20d8,
-           "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d|%d retry %d lid %d\n",
+           "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d|%d retry %d lid %d scan %d\n",
            __func__, fcport->port_name, fcport->disc_state,
            fcport->fw_login_state, fcport->login_pause, fcport->flags,
            fcport->conflict, fcport->last_rscn_gen, fcport->rscn_gen,
            fcport->last_login_gen, fcport->login_gen, fcport->login_retry,
-           fcport->loop_id);
+           fcport->loop_id, fcport->scan_state);
 
-       fcport->login_retry--;
+       if (fcport->login_retry == 0)
+               return 0;
+
+       if (fcport->scan_state != QLA_FCPORT_FOUND)
+               return 0;
 
        if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
            (fcport->fw_login_state == DSC_LS_PRLI_PEND))
@@ -1084,9 +1164,17 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
                return 0;
        }
 
+       fcport->login_retry--;
+
        switch (fcport->disc_state) {
        case DSC_DELETED:
-               if (fcport->loop_id == FC_NO_LOOP_ID) {
+               wwn = wwn_to_u64(fcport->node_name);
+               if (wwn == 0) {
+                       ql_dbg(ql_dbg_disc, vha, 0xffff,
+                           "%s %d %8phC post GNNID\n",
+                           __func__, __LINE__, fcport->port_name);
+                       qla24xx_post_gnnid_work(vha, fcport);
+               } else if (fcport->loop_id == FC_NO_LOOP_ID) {
                        ql_dbg(ql_dbg_disc, vha, 0x20bd,
                            "%s %d %8phC post gnl\n",
                            __func__, __LINE__, fcport->port_name);
@@ -1157,7 +1245,7 @@ void qla24xx_handle_rscn_event(fc_port_t *fcport, struct event_arg *ea)
 }
 
 int qla24xx_post_newsess_work(struct scsi_qla_host *vha, port_id_t *id,
-       u8 *port_name, void *pla)
+    u8 *port_name, u8 *node_name, void *pla, u8 fc4_type)
 {
        struct qla_work_evt *e;
        e = qla2x00_alloc_work(vha, QLA_EVT_NEW_SESS);
@@ -1166,36 +1254,14 @@ int qla24xx_post_newsess_work(struct scsi_qla_host *vha, port_id_t *id,
 
        e->u.new_sess.id = *id;
        e->u.new_sess.pla = pla;
+       e->u.new_sess.fc4_type = fc4_type;
        memcpy(e->u.new_sess.port_name, port_name, WWN_SIZE);
+       if (node_name)
+               memcpy(e->u.new_sess.node_name, node_name, WWN_SIZE);
 
        return qla2x00_post_work(vha, e);
 }
 
-static
-int qla24xx_handle_delete_done_event(scsi_qla_host_t *vha,
-       struct event_arg *ea)
-{
-       fc_port_t *fcport = ea->fcport;
-
-       if (test_bit(UNLOADING, &vha->dpc_flags))
-               return 0;
-
-       switch (vha->host->active_mode) {
-       case MODE_INITIATOR:
-       case MODE_DUAL:
-               if (fcport->scan_state == QLA_FCPORT_FOUND)
-                       qla24xx_fcport_handle_login(vha, fcport);
-               break;
-
-       case MODE_TARGET:
-       default:
-               /* no-op */
-               break;
-       }
-
-       return 0;
-}
-
 static
 void qla24xx_handle_relogin_event(scsi_qla_host_t *vha,
        struct event_arg *ea)
@@ -1261,6 +1327,7 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
        case FCME_GIDPN_DONE:
        case FCME_GPSC_DONE:
        case FCME_GPNID_DONE:
+       case FCME_GNNID_DONE:
                if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) ||
                    test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))
                        return;
@@ -1337,7 +1404,7 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
                qla24xx_handle_gnl_done_event(vha, ea);
                break;
        case FCME_GPSC_DONE:
-               qla24xx_post_upd_fcport_work(vha, ea->fcport);
+               qla24xx_handle_gpsc_event(vha, ea);
                break;
        case FCME_PLOGI_DONE:   /* Initiator side sent LLIOCB */
                qla24xx_handle_plogi_done_event(vha, ea);
@@ -1354,12 +1421,15 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea)
        case FCME_GFFID_DONE:
                qla24xx_handle_gffid_event(vha, ea);
                break;
-       case FCME_DELETE_DONE:
-               qla24xx_handle_delete_done_event(vha, ea);
-               break;
        case FCME_ADISC_DONE:
                qla24xx_handle_adisc_event(vha, ea);
                break;
+       case FCME_GNNID_DONE:
+               qla24xx_handle_gnnid_event(vha, ea);
+               break;
+       case FCME_GFPNID_DONE:
+               qla24xx_handle_gfpnid_event(vha, ea);
+               break;
        default:
                BUG_ON(1);
                break;
@@ -1568,6 +1638,33 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
        u16 lid;
        struct fc_port *conflict_fcport;
        unsigned long flags;
+       struct fc_port *fcport = ea->fcport;
+
+       if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
+           (fcport->fw_login_state == DSC_LS_PRLI_PEND)) {
+               ql_dbg(ql_dbg_disc, vha, 0x20ea,
+                   "%s %d %8phC Remote is trying to login\n",
+                   __func__, __LINE__, fcport->port_name);
+               return;
+       }
+
+       if (fcport->disc_state == DSC_DELETE_PEND)
+               return;
+
+       if (ea->sp->gen2 != fcport->login_gen) {
+               /* target side must have changed it. */
+               ql_dbg(ql_dbg_disc, vha, 0x20d3,
+                   "%s %8phC generation changed rscn %d|%d login %d|%d\n",
+                   __func__, fcport->port_name, fcport->last_rscn_gen,
+                   fcport->rscn_gen, fcport->last_login_gen,
+                   fcport->login_gen);
+               return;
+       } else if (ea->sp->gen1 != fcport->rscn_gen) {
+               ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n",
+                   __func__, __LINE__, fcport->port_name);
+               qla24xx_post_gidpn_work(vha, fcport);
+               return;
+       }
 
        switch (ea->data[0]) {
        case MBS_COMMAND_COMPLETE:
@@ -5124,7 +5221,14 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                 * will be newer than discovery_gen. */
                qlt_do_generation_tick(vha, &discovery_gen);
 
-               rval = qla2x00_find_all_fabric_devs(vha);
+               if (USE_ASYNC_SCAN(ha)) {
+                       rval = QLA_SUCCESS;
+                       rval = qla24xx_async_gpnft(vha, FC4_TYPE_FCP_SCSI);
+                       if (rval)
+                               set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+               } else  {
+                       rval = qla2x00_find_all_fabric_devs(vha);
+               }
                if (rval != QLA_SUCCESS)
                        break;
        } while (0);
index 4c2f85b67ad18b3fa74015db84e79eee5b795a2e..8455058cd7243a0c8f586c52ad7d82514c3b93ec 100644 (file)
@@ -3904,7 +3904,10 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
                        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);
+                           rptid_entry->u.f2.port_name,
+                           rptid_entry->u.f2.node_name,
+                           NULL,
+                           FC4_TYPE_UNKNOWN);
                }
        }
 }
index 4c3527f54b74a4945e6a2ddfd871e2df220be911..5d909f4ab6c2ce789ed79d018628168b27870a11 100644 (file)
@@ -3639,6 +3639,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
        dma_free_coherent(&ha->pdev->dev,
                base_vha->gnl.size, base_vha->gnl.l, base_vha->gnl.ldma);
 
+       vfree(base_vha->scan.l);
+
        if (IS_QLAFX00(ha))
                qlafx00_driver_shutdown(base_vha, 20);
 
@@ -4587,6 +4589,18 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
                return NULL;
        }
 
+       /* todo: what about ext login? */
+       vha->scan.size = ha->max_fibre_devices * sizeof(struct fab_scan_rp);
+       vha->scan.l = vmalloc(vha->scan.size);
+       if (!vha->scan.l) {
+               ql_log(ql_log_fatal, vha, 0xd04a,
+                   "Alloc failed for scan database.\n");
+               dma_free_coherent(&ha->pdev->dev, vha->gnl.size,
+                   vha->gnl.l, vha->gnl.ldma);
+               scsi_remove_host(vha->host);
+               return NULL;
+       }
+
        sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no);
        ql_dbg(ql_dbg_init, vha, 0x0041,
            "Allocated the host=%p hw=%p vha=%p dev_name=%s",
@@ -4760,6 +4774,7 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
        struct qlt_plogi_ack_t *pla =
            (struct qlt_plogi_ack_t *)e->u.new_sess.pla;
        uint8_t free_fcport = 0;
+       u64 wwn;
 
        ql_dbg(ql_dbg_disc, vha, 0xffff,
            "%s %d %8phC enter\n",
@@ -4785,9 +4800,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
                if (fcport) {
                        fcport->d_id = e->u.new_sess.id;
-                       fcport->scan_state = QLA_FCPORT_FOUND;
                        fcport->flags |= FCF_FABRIC_DEVICE;
                        fcport->fw_login_state = DSC_LS_PLOGI_PEND;
+                       if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI)
+                               fcport->fc4_type = FC4_TYPE_FCP_SCSI;
 
                        memcpy(fcport->port_name, e->u.new_sess.port_name,
                            WWN_SIZE);
@@ -4802,7 +4818,7 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                }
 
                spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
-               /* search again to make sure one else got ahead */
+               /* search again to make sure no one else got ahead */
                tfcp = qla2x00_find_fcport_by_wwpn(vha,
                    e->u.new_sess.port_name, 1);
                if (tfcp) {
@@ -4829,6 +4845,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                if (N2N_TOPO(vha->hw))
                        fcport->flags &= ~FCF_FABRIC_DEVICE;
 
+               fcport->id_changed = 1;
+               fcport->scan_state = QLA_FCPORT_FOUND;
+               memcpy(fcport->node_name, e->u.new_sess.node_name, WWN_SIZE);
+
                if (pla) {
                        if (pla->iocb.u.isp24.status_subcode == ELS_PRLI) {
                                u16 wd3_lo;
@@ -4881,7 +4901,13 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                                }
                        }
                        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
-                       qla24xx_async_gnl(vha, fcport);
+
+                       wwn = wwn_to_u64(fcport->node_name);
+
+                       if (!wwn)
+                               qla24xx_async_gnnid(vha, fcport);
+                       else
+                               qla24xx_async_gnl(vha, fcport);
                }
        }
 
@@ -4980,6 +5006,21 @@ qla2x00_do_work(struct scsi_qla_host *vha)
                        qla2x00_async_prlo_done(vha, e->u.logio.fcport,
                            e->u.logio.data);
                        break;
+               case QLA_EVT_GPNFT:
+                       qla24xx_async_gpnft(vha, e->u.gpnft.fc4_type);
+                       break;
+               case QLA_EVT_GPNFT_DONE:
+                       qla24xx_async_gpnft_done(vha, e->u.iosb.sp);
+                       break;
+               case QLA_EVT_GNNFT_DONE:
+                       qla24xx_async_gnnft_done(vha, e->u.iosb.sp);
+                       break;
+               case QLA_EVT_GNNID:
+                       qla24xx_async_gnnid(vha, e->u.fcport.fcport);
+                       break;
+               case QLA_EVT_GFPNID:
+                       qla24xx_async_gfpnid(vha, e->u.fcport.fcport);
+                       break;
                }
                if (e->flags & QLA_EVT_FLAG_FREE)
                        kfree(e);
index 3c25be73005d708ee439252a3c0b6abd83670c3c..d4ead404100ca88d01d58fc3e4430cefcbb4d30a 100644 (file)
@@ -969,7 +969,6 @@ static void qlt_free_session_done(struct work_struct *work)
        struct qla_hw_data *ha = vha->hw;
        unsigned long flags;
        bool logout_started = false;
-       struct event_arg ea;
        scsi_qla_host_t *base_vha;
        struct qlt_plogi_ack_t *own =
                sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN];
@@ -1121,11 +1120,18 @@ static void qlt_free_session_done(struct work_struct *work)
        if (test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags))
                return;
 
-       if (!tgt || !tgt->tgt_stop) {
-               memset(&ea, 0, sizeof(ea));
-               ea.event = FCME_DELETE_DONE;
-               ea.fcport = sess;
-               qla2x00_fcport_event_handler(vha, &ea);
+       if ((!tgt || !tgt->tgt_stop) && !LOOP_TRANSITION(vha)) {
+               switch (vha->host->active_mode) {
+               case MODE_INITIATOR:
+               case MODE_DUAL:
+                       set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
+                       qla2xxx_wake_dpc(vha);
+                       break;
+               case MODE_TARGET:
+               default:
+                       /* no-op */
+                       break;
+               }
        }
 }
 
@@ -4318,6 +4324,7 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
        struct fc_port *sess;
        struct qla_tgt_cmd *cmd;
        unsigned long flags;
+       port_id_t id;
 
        if (unlikely(tgt->tgt_stop)) {
                ql_dbg(ql_dbg_io, vha, 0x3061,
@@ -4325,6 +4332,12 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
                return -EFAULT;
        }
 
+       id.b.al_pa = atio->u.isp24.fcp_hdr.s_id[2];
+       id.b.area = atio->u.isp24.fcp_hdr.s_id[1];
+       id.b.domain = atio->u.isp24.fcp_hdr.s_id[0];
+       if (IS_SW_RESV_ADDR(id))
+               return -EBUSY;
+
        sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, atio->u.isp24.fcp_hdr.s_id);
        if (unlikely(!sess)) {
                struct qla_tgt_sess_op *op = kzalloc(sizeof(struct qla_tgt_sess_op),
@@ -4739,8 +4752,16 @@ static int qlt_handle_login(struct scsi_qla_host *vha,
                ql_dbg(ql_dbg_disc, vha, 0xffff,
                    "%s %d %8phC post new sess\n",
                    __func__, __LINE__, iocb->u.isp24.port_name);
-               qla24xx_post_newsess_work(vha, &port_id,
-                   iocb->u.isp24.port_name, pla);
+               if (iocb->u.isp24.status_subcode == ELS_PLOGI)
+                       qla24xx_post_newsess_work(vha, &port_id,
+                           iocb->u.isp24.port_name,
+                           iocb->u.isp24.u.plogi.node_name,
+                           pla, FC4_TYPE_UNKNOWN);
+               else
+                       qla24xx_post_newsess_work(vha, &port_id,
+                           iocb->u.isp24.port_name, NULL,
+                           pla, FC4_TYPE_UNKNOWN);
+
                goto out;
        }
 
@@ -4869,6 +4890,11 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
                        break;
                }
 
+               if (IS_SW_RESV_ADDR(port_id)) {
+                       res = 1;
+                       break;
+               }
+
                wd3_lo = le16_to_cpu(iocb->u.isp24.u.prli.wd3_lo);
 
                if (wwn) {
@@ -4896,12 +4922,32 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
                }
 
                if (sess != NULL) {
+                       bool delete = false;
                        spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
                        switch (sess->fw_login_state) {
+                       case DSC_LS_PLOGI_PEND:
                        case DSC_LS_PLOGI_COMP:
                        case DSC_LS_PRLI_COMP:
                                break;
                        default:
+                               delete = true;
+                               break;
+                       }
+
+                       switch (sess->disc_state) {
+                       case DSC_LOGIN_PEND:
+                       case DSC_GPDB:
+                       case DSC_GPSC:
+                       case DSC_UPD_FCPORT:
+                       case DSC_LOGIN_COMPLETE:
+                       case DSC_ADISC:
+                               delete = false;
+                               break;
+                       default:
+                               break;
+                       }
+
+                       if (delete) {
                                spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock,
                                    flags);
                                /*
index aba58d3848a6e7c99c264261f2680f425d7e10e6..8c04971a54542f09b1ce070dcb6bd5b624eec526 100644 (file)
@@ -993,7 +993,7 @@ struct qla_tgt_prm {
 
 /* Check for Switch reserved address */
 #define IS_SW_RESV_ADDR(_s_id) \
-       ((_s_id.b.domain == 0xff) && (_s_id.b.area == 0xfc))
+       ((_s_id.b.domain == 0xff) && ((_s_id.b.area & 0xf0) == 0xf0))
 
 #define QLA_TGT_XMIT_DATA              1
 #define QLA_TGT_XMIT_STATUS            2