OSDN Git Service

scsi: qla2xxx: Changes to support N2N logins
authorDuane Grigsby <duane.grigsby@cavium.com>
Fri, 13 Oct 2017 16:34:06 +0000 (09:34 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 17 Oct 2017 03:02:20 +0000 (23:02 -0400)
If we discovered a topology that is N2N then we will issue a login to
the target. If our WWPN is bigger than the target's WWPN then we will
initiate login, otherwise we will just wait for the target to initiate
login.

[mkp: many whitespace errors]

Signed-off-by: Duane Grigsby <duane.grigsby@cavium.com>
Signed-off-by: Michael Hernandez <michael.hernandez@cavium.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Tested-by: Ewan D. Milne <emilne@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c

index f712c0c..01a9b89 100644 (file)
@@ -323,6 +323,12 @@ struct els_logo_payload {
        uint8_t wwpn[WWN_SIZE];
 };
 
+struct els_plogi_payload {
+       uint8_t opcode;
+       uint8_t rsvd[3];
+       uint8_t data[112];
+};
+
 struct ct_arg {
        void            *iocb;
        u16             nport_handle;
@@ -358,6 +364,19 @@ struct srb_iocb {
                        dma_addr_t els_logo_pyld_dma;
                } els_logo;
                struct {
+#define ELS_DCMD_PLOGI 0x3
+                       uint32_t flags;
+                       uint32_t els_cmd;
+                       struct completion comp;
+                       struct els_plogi_payload *els_plogi_pyld;
+                       struct els_plogi_payload *els_resp_pyld;
+                       dma_addr_t els_plogi_pyld_dma;
+                       dma_addr_t els_resp_pyld_dma;
+                       uint32_t        fw_status[3];
+                       __le16  comp_status;
+                       __le16  len;
+               } els_plogi;
+               struct {
                        /*
                         * Values for flags field below are as
                         * defined in tsk_mgmt_entry struct
@@ -2349,6 +2368,7 @@ typedef struct fc_port {
        uint8_t fc4_type;
        uint8_t fc4f_nvme;
        uint8_t scan_state;
+       uint8_t n2n_flag;
 
        unsigned long last_queue_full;
        unsigned long last_ramp_up;
@@ -2372,6 +2392,7 @@ typedef struct fc_port {
        u8 iocb[IOCB_SIZE];
        u8 current_login_state;
        u8 last_login_state;
+       struct completion n2n_done;
 } fc_port_t;
 
 #define QLA_FCPORT_SCAN                1
@@ -4228,6 +4249,9 @@ typedef struct scsi_qla_host {
        wait_queue_head_t fcport_waitQ;
        wait_queue_head_t vref_waitq;
        uint8_t min_link_speed_feat;
+       uint8_t n2n_node_name[WWN_SIZE];
+       uint8_t n2n_port_name[WWN_SIZE];
+       uint16_t        n2n_id;
 } scsi_qla_host_t;
 
 struct qla27xx_image_status {
index bec641a..d5cef07 100644 (file)
@@ -753,9 +753,7 @@ struct els_entry_24xx {
        uint8_t reserved_2;
 
        uint8_t port_id[3];
-       uint8_t reserved_3;
-
-       uint16_t reserved_4;
+       uint8_t s_id[3];
 
        uint16_t control_flags;         /* Control flags. */
 #define ECF_PAYLOAD_DESCR_MASK (BIT_15|BIT_14|BIT_13)
index 46c7822..0a23af5 100644 (file)
@@ -45,6 +45,8 @@ extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
 extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
 
 extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t);
+extern int qla24xx_els_dcmd2_iocb(scsi_qla_host_t *, int, fc_port_t *,
+                                 port_id_t);
 
 extern void qla2x00_update_fcports(scsi_qla_host_t *);
 
@@ -487,6 +489,8 @@ int qla24xx_gidlist_wait(struct scsi_qla_host *, void *, dma_addr_t,
     uint16_t *);
 int __qla24xx_parse_gpdb(struct scsi_qla_host *, fc_port_t *,
        struct port_database_24xx *);
+int qla24xx_get_port_login_templ(scsi_qla_host_t *, dma_addr_t,
+                                void *, uint16_t);
 
 extern int qla27xx_get_zio_threshold(scsi_qla_host_t *, uint16_t *);
 extern int qla27xx_set_zio_threshold(scsi_qla_host_t *, uint16_t);
index 4c53199..1c53c07 100644 (file)
@@ -1433,6 +1433,14 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
                qla24xx_post_gpdb_work(vha, ea->fcport, 0);
                break;
        default:
+               if (ea->fcport->n2n_flag) {
+                       ql_dbg(ql_dbg_disc, vha, 0x2118,
+                               "%s %d %8phC post fc4 prli\n",
+                               __func__, __LINE__, ea->fcport->port_name);
+                       ea->fcport->fc4f_nvme = 0;
+                       ea->fcport->n2n_flag = 0;
+                       qla24xx_post_prli_work(vha, ea->fcport);
+               }
                ql_dbg(ql_dbg_disc, vha, 0x2119,
                    "%s %d %8phC unhandle event of %x\n",
                    __func__, __LINE__, ea->fcport->port_name, ea->data[0]);
@@ -4366,7 +4374,109 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
        return (rval);
 }
 
+/*
+ * N2N Login
+ *     Updates Fibre Channel Device Database with local loop devices.
+ *
+ * Input:
+ *     ha = adapter block pointer.
+ *
+ * Returns:
+ */
+static int qla24xx_n2n_handle_login(struct scsi_qla_host *vha,
+                                   fc_port_t *fcport)
+{
+       struct qla_hw_data *ha = vha->hw;
+       int     res = QLA_SUCCESS, rval;
+       int     greater_wwpn = 0;
+       int     logged_in = 0;
+
+       if (ha->current_topology != ISP_CFG_N)
+               return res;
+
+       if (wwn_to_u64(vha->port_name) >
+           wwn_to_u64(vha->n2n_port_name)) {
+               ql_dbg(ql_dbg_disc, vha, 0x2002,
+                   "HBA WWPN is greater %llx > target %llx\n",
+                   wwn_to_u64(vha->port_name),
+                   wwn_to_u64(vha->n2n_port_name));
+               greater_wwpn = 1;
+               fcport->d_id.b24 = vha->n2n_id;
+       }
+
+       fcport->loop_id = vha->loop_id;
+       fcport->fc4f_nvme = 0;
+       fcport->query = 1;
+
+       ql_dbg(ql_dbg_disc, vha, 0x4001,
+           "Initiate N2N login handler: HBA port_id=%06x loopid=%d\n",
+           fcport->d_id.b24, vha->loop_id);
+
+       /* Fill in member data. */
+       if (!greater_wwpn) {
+               rval = qla2x00_get_port_database(vha, fcport, 0);
+               ql_dbg(ql_dbg_disc, vha, 0x1051,
+                   "Remote login-state (%x/%x) port_id=%06x loop_id=%x, rval=%d\n",
+                   fcport->current_login_state, fcport->last_login_state,
+                   fcport->d_id.b24, fcport->loop_id, rval);
+
+               if (((fcport->current_login_state & 0xf) == 0x4) ||
+                   ((fcport->current_login_state & 0xf) == 0x6))
+                       logged_in = 1;
+       }
+
+       if (logged_in || greater_wwpn) {
+               if (!vha->nvme_local_port && vha->flags.nvme_enabled)
+                       qla_nvme_register_hba(vha);
+
+               /* Set connected N_Port d_id */
+               if (vha->flags.nvme_enabled)
+                       fcport->fc4f_nvme = 1;
+
+               fcport->scan_state = QLA_FCPORT_FOUND;
+               fcport->fw_login_state = DSC_LS_PORT_UNAVAIL;
+               fcport->disc_state = DSC_GNL;
+               fcport->n2n_flag = 1;
+               fcport->flags = 3;
+               vha->hw->flags.gpsc_supported = 0;
+
+               if (greater_wwpn) {
+                       ql_dbg(ql_dbg_disc, vha, 0x20e5,
+                           "%s %d PLOGI ELS %8phC\n",
+                           __func__, __LINE__, fcport->port_name);
+
+                       res = qla24xx_els_dcmd2_iocb(vha, ELS_DCMD_PLOGI,
+                           fcport, fcport->d_id);
+               }
+
+               if (res != QLA_SUCCESS) {
+                       ql_log(ql_log_info, vha, 0xd04d,
+                           "PLOGI Failed: portid=%06x - retrying\n",
+                           fcport->d_id.b24);
+                       res = QLA_SUCCESS;
+               } else {
+                       /* State 0x6 means FCP PRLI complete */
+                       if ((fcport->current_login_state & 0xf) == 0x6) {
+                               ql_dbg(ql_dbg_disc, vha, 0x2118,
+                                   "%s %d %8phC post GPDB work\n",
+                                   __func__, __LINE__, fcport->port_name);
+                               fcport->chip_reset =
+                                   vha->hw->base_qpair->chip_reset;
+                               qla24xx_post_gpdb_work(vha, fcport, 0);
+                       } else {
+                               ql_dbg(ql_dbg_disc, vha, 0x2118,
+                                   "%s %d %8phC post NVMe PRLI\n",
+                                   __func__, __LINE__, fcport->port_name);
+                               qla24xx_post_prli_work(vha, fcport);
+                       }
+               }
+       } else {
+               /* Wait for next database change */
+               set_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags);
+       }
 
+       return res;
+}
 
 /*
  * qla2x00_configure_local_loop
@@ -4437,6 +4547,14 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
                }
        }
 
+       /* Inititae N2N login. */
+       if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) {
+               rval = qla24xx_n2n_handle_login(vha, new_fcport);
+               if (rval != QLA_SUCCESS)
+                       goto cleanup_allocation;
+               return QLA_SUCCESS;
+       }
+
        /* Add devices to port list. */
        id_iter = (char *)ha->gid_list;
        for (index = 0; index < entries; index++) {
@@ -4478,10 +4596,13 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha)
                            "Failed to retrieve fcport information "
                            "-- get_port_database=%x, loop_id=0x%04x.\n",
                            rval2, new_fcport->loop_id);
-                       ql_dbg(ql_dbg_disc, vha, 0x2105,
-                           "Scheduling resync.\n");
-                       set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
-                       continue;
+                       /* Skip retry if N2N */
+                       if (ha->current_topology != ISP_CFG_N) {
+                               ql_dbg(ql_dbg_disc, vha, 0x2105,
+                                   "Scheduling resync.\n");
+                               set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+                               continue;
+                       }
                }
 
                spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
@@ -7554,6 +7675,12 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
        if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha))
                icb->firmware_options_3 |= BIT_0;
 
+       if (IS_QLA27XX(ha)) {
+               icb->firmware_options_3 |= BIT_8;
+               ql_dbg(ql_log_info, vha, 0x0075,
+                   "Enabling direct connection.\n");
+       }
+
        if (rval) {
                ql_log(ql_log_warn, vha, 0x0076,
                    "NVRAM configuration failed.\n");
index 2f94159..d810a44 100644 (file)
@@ -2518,6 +2518,7 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
 {
        scsi_qla_host_t *vha = sp->vha;
        struct srb_iocb *elsio = &sp->u.iocb_cmd;
+       uint32_t        dsd_len = 24;
 
        els_iocb->entry_type = ELS_IOCB_TYPE;
        els_iocb->entry_count = 1;
@@ -2534,24 +2535,198 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
        els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
        els_iocb->port_id[1] = sp->fcport->d_id.b.area;
        els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+       els_iocb->s_id[0] = vha->d_id.b.al_pa;
+       els_iocb->s_id[1] = vha->d_id.b.area;
+       els_iocb->s_id[2] = vha->d_id.b.domain;
        els_iocb->control_flags = 0;
 
-       els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
-       els_iocb->tx_address[0] =
-           cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
-       els_iocb->tx_address[1] =
-           cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
-       els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
+       if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) {
+               els_iocb->tx_byte_count = sizeof(struct els_plogi_payload);
+               els_iocb->tx_address[0] =
+                       cpu_to_le32(LSD(elsio->u.els_plogi.els_plogi_pyld_dma));
+               els_iocb->tx_address[1] =
+                       cpu_to_le32(MSD(elsio->u.els_plogi.els_plogi_pyld_dma));
+               els_iocb->tx_len = dsd_len;
+
+               els_iocb->rx_dsd_count = 1;
+               els_iocb->rx_byte_count = sizeof(struct els_plogi_payload);
+               els_iocb->rx_address[0] =
+                       cpu_to_le32(LSD(elsio->u.els_plogi.els_resp_pyld_dma));
+               els_iocb->rx_address[1] =
+                       cpu_to_le32(MSD(elsio->u.els_plogi.els_resp_pyld_dma));
+               els_iocb->rx_len = dsd_len;
+               ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073,
+                   "PLOGI ELS IOCB:\n");
+               ql_dump_buffer(ql_log_info, vha, 0x0109,
+                   (uint8_t *)els_iocb, 0x70);
+       } else {
+               els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
+               els_iocb->tx_address[0] =
+                   cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
+               els_iocb->tx_address[1] =
+                   cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
+               els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
 
-       els_iocb->rx_byte_count = 0;
-       els_iocb->rx_address[0] = 0;
-       els_iocb->rx_address[1] = 0;
-       els_iocb->rx_len = 0;
+               els_iocb->rx_byte_count = 0;
+               els_iocb->rx_address[0] = 0;
+               els_iocb->rx_address[1] = 0;
+               els_iocb->rx_len = 0;
+       }
 
        sp->vha->qla_stats.control_requests++;
 }
 
 static void
+qla2x00_els_dcmd2_sp_free(void *data)
+{
+       srb_t *sp = data;
+       struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+       if (elsio->u.els_plogi.els_plogi_pyld)
+               dma_free_coherent(&sp->vha->hw->pdev->dev, DMA_POOL_SIZE,
+                   elsio->u.els_plogi.els_plogi_pyld,
+                   elsio->u.els_plogi.els_plogi_pyld_dma);
+
+       if (elsio->u.els_plogi.els_resp_pyld)
+               dma_free_coherent(&sp->vha->hw->pdev->dev, DMA_POOL_SIZE,
+                   elsio->u.els_plogi.els_resp_pyld,
+                   elsio->u.els_plogi.els_resp_pyld_dma);
+
+       del_timer(&elsio->timer);
+       qla2x00_rel_sp(sp);
+}
+
+static void
+qla2x00_els_dcmd2_iocb_timeout(void *data)
+{
+       srb_t *sp = data;
+       fc_port_t *fcport = sp->fcport;
+       struct scsi_qla_host *vha = sp->vha;
+       struct qla_hw_data *ha = vha->hw;
+       struct srb_iocb *lio = &sp->u.iocb_cmd;
+       unsigned long flags = 0;
+       int res;
+
+       ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3069,
+           "%s hdl=%x ELS Timeout, %8phC portid=%06x\n",
+           sp->name, sp->handle, fcport->port_name, fcport->d_id.b24);
+
+       /* Abort the exchange */
+       spin_lock_irqsave(&ha->hardware_lock, flags);
+       res = ha->isp_ops->abort_command(sp);
+       ql_dbg(ql_dbg_io, vha, 0x3070,
+           "mbx abort_command %s\n",
+           (res == QLA_SUCCESS) ? "successful" : "failed");
+       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+       complete(&lio->u.els_plogi.comp);
+}
+
+static void
+qla2x00_els_dcmd2_sp_done(void *ptr, int res)
+{
+       srb_t *sp = ptr;
+       fc_port_t *fcport = sp->fcport;
+       struct srb_iocb *lio = &sp->u.iocb_cmd;
+       struct scsi_qla_host *vha = sp->vha;
+
+       ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3072,
+           "%s ELS hdl=%x, portid=%06x done %8pC\n",
+           sp->name, sp->handle, fcport->d_id.b24, fcport->port_name);
+
+       complete(&lio->u.els_plogi.comp);
+}
+
+int
+qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
+                      fc_port_t *fcport, port_id_t remote_did)
+{
+       srb_t *sp;
+       struct srb_iocb *elsio = NULL;
+       struct qla_hw_data *ha = vha->hw;
+       int rval = QLA_SUCCESS;
+       void    *ptr, *resp_ptr;
+       dma_addr_t ptr_dma;
+
+       /* Alloc SRB structure */
+       sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+       if (!sp) {
+               ql_log(ql_log_info, vha, 0x70e6,
+                "SRB allocation failed\n");
+               return -ENOMEM;
+       }
+
+       elsio = &sp->u.iocb_cmd;
+       fcport->d_id.b.domain = remote_did.b.domain;
+       fcport->d_id.b.area = remote_did.b.area;
+       fcport->d_id.b.al_pa = remote_did.b.al_pa;
+
+       ql_dbg(ql_dbg_io, vha, 0x3073,
+           "Enter: PLOGI portid=%06x\n", fcport->d_id.b24);
+
+       sp->type = SRB_ELS_DCMD;
+       sp->name = "ELS_DCMD";
+       sp->fcport = fcport;
+       qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT);
+       elsio->timeout = qla2x00_els_dcmd2_iocb_timeout;
+       sp->done = qla2x00_els_dcmd2_sp_done;
+       sp->free = qla2x00_els_dcmd2_sp_free;
+
+       ptr = elsio->u.els_plogi.els_plogi_pyld =
+           dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
+               &elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL);
+       ptr_dma = elsio->u.els_plogi.els_plogi_pyld_dma;
+
+       if (!elsio->u.els_plogi.els_plogi_pyld) {
+               rval = QLA_FUNCTION_FAILED;
+               goto out;
+       }
+
+       resp_ptr = elsio->u.els_plogi.els_resp_pyld =
+           dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
+               &elsio->u.els_plogi.els_resp_pyld_dma, GFP_KERNEL);
+
+       if (!elsio->u.els_plogi.els_resp_pyld) {
+               rval = QLA_FUNCTION_FAILED;
+               goto out;
+       }
+
+       ql_dbg(ql_dbg_io, vha, 0x3073, "PLOGI %p %p\n", ptr, resp_ptr);
+
+       memset(ptr, 0, sizeof(struct els_plogi_payload));
+       memset(resp_ptr, 0, sizeof(struct els_plogi_payload));
+       elsio->u.els_plogi.els_cmd = els_opcode;
+       elsio->u.els_plogi.els_plogi_pyld->opcode = els_opcode;
+       qla24xx_get_port_login_templ(vha, ptr_dma + 4,
+               &elsio->u.els_plogi.els_plogi_pyld->data[0],
+               sizeof(struct els_plogi_payload));
+
+       ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073, "PLOGI buffer:\n");
+       ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x0109,
+           (uint8_t *)elsio->u.els_plogi.els_plogi_pyld, 0x70);
+
+       init_completion(&elsio->u.els_plogi.comp);
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS) {
+               rval = QLA_FUNCTION_FAILED;
+               goto out;
+       }
+
+       ql_dbg(ql_dbg_io, vha, 0x3074,
+           "%s PLOGI sent, hdl=%x, loopid=%x, portid=%06x\n",
+           sp->name, sp->handle, fcport->loop_id, fcport->d_id.b24);
+
+       wait_for_completion(&elsio->u.els_plogi.comp);
+
+       if (elsio->u.els_plogi.comp_status != CS_COMPLETE)
+               rval = QLA_FUNCTION_FAILED;
+
+out:
+       sp->free(sp);
+       return rval;
+}
+
+static void
 qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
 {
        struct bsg_job *bsg_job = sp->u.bsg_job;
index ab97fb0..c7878be 100644 (file)
@@ -1041,6 +1041,7 @@ global_port_update:
                 */
                atomic_set(&vha->loop_down_timer, 0);
                if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
+                       !ha->flags.n2n_ae  &&
                    atomic_read(&vha->loop_state) != LOOP_DEAD) {
                        ql_dbg(ql_dbg_async, vha, 0x5011,
                            "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
@@ -1545,6 +1546,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
        uint32_t fw_status[3];
        uint8_t* fw_sts_ptr;
        int res;
+       struct srb_iocb *els;
 
        sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
        if (!sp)
@@ -1561,10 +1563,14 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                break;
        case SRB_ELS_DCMD:
                type = "Driver ELS logo";
-               ql_dbg(ql_dbg_user, vha, 0x5047,
-                   "Completing %s: (%p) type=%d.\n", type, sp, sp->type);
-               sp->done(sp, 0);
-               return;
+               if (iocb_type != ELS_IOCB_TYPE) {
+                       ql_dbg(ql_dbg_user, vha, 0x5047,
+                           "Completing %s: (%p) type=%d.\n",
+                           type, sp, sp->type);
+                       sp->done(sp, 0);
+                       return;
+               }
+               break;
        case SRB_CT_PTHRU_CMD:
                /* borrowing sts_entry_24xx.comp_status.
                   same location as ct_entry_24xx.comp_status
@@ -1584,6 +1590,33 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
        fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1);
        fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2);
 
+       if (iocb_type == ELS_IOCB_TYPE) {
+               els = &sp->u.iocb_cmd;
+               els->u.els_plogi.fw_status[0] = fw_status[0];
+               els->u.els_plogi.fw_status[1] = fw_status[1];
+               els->u.els_plogi.fw_status[2] = fw_status[2];
+               els->u.els_plogi.comp_status = fw_status[0];
+               if (comp_status == CS_COMPLETE) {
+                       res =  DID_OK << 16;
+               } else {
+                       if (comp_status == CS_DATA_UNDERRUN) {
+                               res =  DID_OK << 16;
+                               els->u.els_plogi.len =
+                               le16_to_cpu(((struct els_sts_entry_24xx *)
+                                       pkt)->total_byte_count);
+                       } else {
+                               els->u.els_plogi.len = 0;
+                               res = DID_ERROR << 16;
+                       }
+               }
+               ql_log(ql_log_info, vha, 0x503f,
+                   "ELS IOCB Done -%s error hdl=%x comp_status=0x%x error subcode 1=0x%x error subcode 2=0x%x total_byte=0x%x\n",
+                   type, sp->handle, comp_status, fw_status[1], fw_status[2],
+                   le16_to_cpu(((struct els_sts_entry_24xx *)
+                       pkt)->total_byte_count));
+               goto els_ct_done;
+       }
+
        /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
         * fc payload  to the caller
         */
@@ -1631,6 +1664,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
                bsg_reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
                bsg_job->reply_len = 0;
        }
+els_ct_done:
 
        sp->done(sp, res);
 }
index 71e5687..cb717d4 100644 (file)
@@ -1786,6 +1786,7 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
        if (pd  == NULL) {
                ql_log(ql_log_warn, vha, 0x1050,
                    "Failed to allocate port database structure.\n");
+               fcport->query = 0;
                return QLA_MEMORY_ALLOC_FAILED;
        }
 
@@ -1926,6 +1927,7 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
 
 gpd_error_out:
        dma_pool_free(ha->s_dma_pool, pd, pd_dma);
+       fcport->query = 0;
 
        if (rval != QLA_SUCCESS) {
                ql_dbg(ql_dbg_mbx, vha, 0x1052,
@@ -3762,6 +3764,38 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
                        rptid_entry->vp_status,
                    rptid_entry->port_id[2], rptid_entry->port_id[1],
                    rptid_entry->port_id[0]);
+               ql_dbg(ql_dbg_async, vha, 0x5075,
+                  "Format 1: Remote WWPN %8phC.\n",
+                  rptid_entry->u.f1.port_name);
+
+               ql_dbg(ql_dbg_async, vha, 0x5075,
+                  "Format 1: WWPN %8phC.\n",
+                  vha->port_name);
+
+               /* N2N.  direct connect */
+               if (IS_QLA27XX(ha) &&
+                   ((rptid_entry->u.f1.flags>>1) & 0x7) == 2) {
+                       /* if our portname is higher then initiate N2N login */
+                       if (wwn_to_u64(vha->port_name) >
+                           wwn_to_u64(rptid_entry->u.f1.port_name)) {
+                               // ??? qlt_update_host_map(vha, id);
+                               vha->n2n_id = 0x1;
+                               ql_dbg(ql_dbg_async, vha, 0x5075,
+                                   "Format 1: Setting n2n_update_needed for id %d\n",
+                                   vha->n2n_id);
+                       } else {
+                               ql_dbg(ql_dbg_async, vha, 0x5075,
+                                   "Format 1: Remote login - Waiting for WWPN %8phC.\n",
+                                   rptid_entry->u.f1.port_name);
+                       }
+
+                       memcpy(vha->n2n_port_name, rptid_entry->u.f1.port_name,
+                           WWN_SIZE);
+                       set_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags);
+                       set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
+                       set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
+                       return;
+               }
 
                /* buffer to buffer credit flag */
                vha->flags.bbcr_enable = (rptid_entry->u.f1.bbcr & 0xf) != 0;
@@ -4599,6 +4633,48 @@ qla25xx_set_driver_version(scsi_qla_host_t *vha, char *version)
        return rval;
 }
 
+int
+qla24xx_get_port_login_templ(scsi_qla_host_t *vha, dma_addr_t buf_dma,
+                            void *buf, uint16_t bufsiz)
+{
+       int rval, i;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+       uint32_t        *bp;
+
+       if (!IS_FWI2_CAPABLE(vha->hw))
+               return QLA_FUNCTION_FAILED;
+
+       ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1159,
+           "Entered %s.\n", __func__);
+
+       mcp->mb[0] = MBC_GET_RNID_PARAMS;
+       mcp->mb[1] = RNID_TYPE_PORT_LOGIN << 8;
+       mcp->mb[2] = MSW(buf_dma);
+       mcp->mb[3] = LSW(buf_dma);
+       mcp->mb[6] = MSW(MSD(buf_dma));
+       mcp->mb[7] = LSW(MSD(buf_dma));
+       mcp->mb[8] = bufsiz/4;
+       mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_1|MBX_0;
+       mcp->tov = MBX_TOV_SECONDS;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       if (rval != QLA_SUCCESS) {
+               ql_dbg(ql_dbg_mbx, vha, 0x115a,
+                   "Failed=%x mb[0]=%x,%x.\n", rval, mcp->mb[0], mcp->mb[1]);
+       } else {
+               ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x115b,
+                   "Done %s.\n", __func__);
+               bp = (uint32_t *) buf;
+               for (i = 0; i < (bufsiz-4)/4; i++, bp++)
+                       *bp = cpu_to_be32(*bp);
+       }
+
+       return rval;
+}
+
 static int
 qla2x00_read_asic_temperature(scsi_qla_host_t *vha, uint16_t *temp)
 {