scsi: qla2xxx: Fix Async GPN_FT for FCP and FC-NVMe scan
authorQuinn Tran <quinn.tran@cavium.com>
Wed, 21 Mar 2018 06:09:40 +0000 (23:09 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 21 Mar 2018 22:38:55 +0000 (18:38 -0400)
This patch combines FCP and FC-NVMe scan into single scan when
driver detects FC-NVMe capability on same port.

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_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_os.c

index 6aae126add0ca6ff10797a4b7c60837e83226790..54625eb2904f3300935c1d2638c0f40cc9980d11 100644 (file)
@@ -2217,6 +2217,7 @@ typedef struct {
 
 /* FCP-4 types */
 #define FC4_TYPE_FCP_SCSI      0x08
+#define FC4_TYPE_NVME          0x28
 #define FC4_TYPE_OTHER         0x0
 #define FC4_TYPE_UNKNOWN       0xff
 
@@ -2982,8 +2983,14 @@ enum scan_flags_t {
        SF_QUEUED = BIT_1,
 };
 
+enum fc4type_t {
+       FS_FC4TYPE_FCP  = BIT_0,
+       FS_FC4TYPE_NVME = BIT_1,
+};
+
 struct fab_scan_rp {
        port_id_t id;
+       enum fc4type_t fc4type;
        u8 port_name[8];
        u8 node_name[8];
 };
@@ -3275,6 +3282,7 @@ struct qla_work_evt {
                } nack;
                struct {
                        u8 fc4_type;
+                       srb_t *sp;
                } gpnft;
         } u;
 };
index 19f44e12926b2ba2fc91c084549f2cafb2ef6cbb..3c4c84ed0f0fa63a726936dff5b79d30ebcc5fef 100644 (file)
@@ -658,7 +658,7 @@ 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);
+int qla24xx_async_gpnft(scsi_qla_host_t *, u8, srb_t *);
 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 *);
index e4d404c2450690122dce166e6fa002e77352ea9c..39dd62b8c6496640d5b808e09242b4da31db08d8 100644 (file)
@@ -3858,7 +3858,6 @@ 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;
        unsigned long flags;
 
@@ -3931,7 +3930,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp)
                            "%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);
+                           rp->node_name, NULL, rp->fc4type);
                }
        }
 
@@ -3971,19 +3970,112 @@ out:
        spin_unlock_irqrestore(&vha->work_lock, flags);
 }
 
-static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res)
+static void qla2x00_find_free_fcp_nvme_slot(struct scsi_qla_host *vha,
+       struct srb *sp)
 {
-       struct srb *sp = s;
-       struct scsi_qla_host *vha = sp->vha;
-       struct qla_work_evt *e;
+       struct qla_hw_data *ha = vha->hw;
+       int num_fibre_dev = ha->max_fibre_devices;
        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;
        struct fab_scan_rp *rp;
+       u16 cmd = be16_to_cpu(ct_req->command);
+       u8 fc4_type = sp->gen2;
        int i, j, k;
+       port_id_t id;
+       u8 found;
+       u64 wwn;
+
+       j = 0;
+       for (i = 0; i < num_fibre_dev; 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 (fc4_type == FC4_TYPE_FCP_SCSI) {
+                       if (cmd == GPN_FT_CMD) {
+                               rp = &vha->scan.l[j];
+                               rp->id = id;
+                               memcpy(rp->port_name, d->port_name, 8);
+                               j++;
+                               rp->fc4type = FS_FC4TYPE_FCP;
+                       } else {
+                               for (k = 0; k < num_fibre_dev; k++) {
+                                       rp = &vha->scan.l[k];
+                                       if (id.b24 == rp->id.b24) {
+                                               memcpy(rp->node_name,
+                                                   d->port_name, 8);
+                                               break;
+                                       }
+                               }
+                       }
+               } else {
+                       /* Search if the fibre device supports FC4_TYPE_NVME */
+                       if (cmd == GPN_FT_CMD) {
+                               found = 0;
+
+                               for (k = 0; k < num_fibre_dev; k++) {
+                                       rp = &vha->scan.l[k];
+                                       if (!memcmp(rp->port_name,
+                                           d->port_name, 8)) {
+                                               /*
+                                                * Supports FC-NVMe & FCP
+                                                */
+                                               rp->fc4type |= FS_FC4TYPE_NVME;
+                                               found = 1;
+                                               break;
+                                       }
+                               }
+
+                               /* We found new FC-NVMe only port */
+                               if (!found) {
+                                       for (k = 0; k < num_fibre_dev; k++) {
+                                               rp = &vha->scan.l[k];
+                                               if (wwn_to_u64(rp->port_name)) {
+                                                       continue;
+                                               } else {
+                                                       rp->id = id;
+                                                       memcpy(rp->port_name,
+                                                           d->port_name, 8);
+                                                       rp->fc4type =
+                                                           FS_FC4TYPE_NVME;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       } else {
+                               for (k = 0; k < num_fibre_dev; k++) {
+                                       rp = &vha->scan.l[k];
+                                       if (id.b24 == rp->id.b24) {
+                                               memcpy(rp->node_name,
+                                                   d->port_name, 8);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+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;
        u16 cmd = be16_to_cpu(ct_req->command);
+       u8 fc4_type = sp->gen2;
+       unsigned long flags;
 
        /* gen2 field is holding the fc4type */
        ql_dbg(ql_dbg_disc, vha, 0xffff,
@@ -4011,40 +4103,51 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res)
                return;
        }
 
-       if (!res) {
-               port_id_t id;
-               u64 wwn;
+       if (!res)
+               qla2x00_find_free_fcp_nvme_slot(vha, sp);
 
-               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 ((fc4_type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled &&
+           cmd == GNN_FT_CMD) {
+               del_timer(&sp->u.iocb_cmd.timer);
+               spin_lock_irqsave(&vha->work_lock, flags);
+               vha->scan.scan_flags &= ~SF_SCANNING;
+               spin_unlock_irqrestore(&vha->work_lock, flags);
 
-                       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;
-                                       }
-                               }
+               e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT);
+               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(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
+                       set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+                       return;
                }
+               e->u.gpnft.fc4_type = FC4_TYPE_NVME;
+               sp->rc = res;
+               e->u.gpnft.sp = sp;
+
+               qla2x00_post_work(vha, e);
+               return;
        }
 
        if (cmd == GPN_FT_CMD)
@@ -4095,9 +4198,12 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp,
        int rval = QLA_FUNCTION_FAILED;
        struct ct_sns_req *ct_req;
        struct ct_sns_pkt *ct_sns;
+       unsigned long flags;
 
        if (!vha->flags.online) {
+               spin_lock_irqsave(&vha->work_lock, flags);
                vha->scan.scan_flags &= ~SF_SCANNING;
+               spin_unlock_irqrestore(&vha->work_lock, flags);
                goto done_free_sp;
        }
 
@@ -4106,10 +4212,18 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp,
                    "%s: req %p rsp %p are not setup\n",
                    __func__, sp->u.iocb_cmd.u.ctarg.req,
                    sp->u.iocb_cmd.u.ctarg.rsp);
+               spin_lock_irqsave(&vha->work_lock, flags);
                vha->scan.scan_flags &= ~SF_SCANNING;
+               spin_unlock_irqrestore(&vha->work_lock, flags);
                WARN_ON(1);
                goto done_free_sp;
        }
+
+       ql_dbg(ql_dbg_disc, vha, 0xfffff,
+           "%s: FC4Type %x, CT-PASSTRHU %s command ctarg rsp size %d, ctarg req size %d\n",
+           __func__, fc4_type, sp->name, sp->u.iocb_cmd.u.ctarg.rsp_size,
+            sp->u.iocb_cmd.u.ctarg.req_size);
+
        sp->type = SRB_CT_PTHRU_CMD;
        sp->name = "gnnft";
        sp->gen1 = vha->hw->base_qpair->chip_reset;
@@ -4172,15 +4286,17 @@ void qla24xx_async_gpnft_done(scsi_qla_host_t *vha, srb_t *sp)
 }
 
 /* Get WWPN list for certain fc4_type */
-int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
+int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp)
 {
        int rval = QLA_FUNCTION_FAILED;
        struct ct_sns_req       *ct_req;
-       srb_t *sp;
        struct ct_sns_pkt *ct_sns;
        u32 rspsz;
        unsigned long flags;
 
+       ql_dbg(ql_dbg_disc, vha, 0xffff,
+           "%s enter\n", __func__);
+
        if (!vha->flags.online)
                return rval;
 
@@ -4193,9 +4309,58 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
        vha->scan.scan_flags |= SF_SCANNING;
        spin_unlock_irqrestore(&vha->work_lock, flags);
 
-       sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
-       if (!sp) {
-               vha->scan.scan_flags &= ~SF_SCANNING;
+       if (fc4_type == FC4_TYPE_FCP_SCSI) {
+               ql_dbg(ql_dbg_disc, vha, 0xffff,
+                   "%s: Performing FCP Scan\n", __func__);
+
+               if (sp)
+                       sp->free(sp); /* should not happen */
+
+               sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
+               if (!sp) {
+                       spin_lock_irqsave(&vha->work_lock, flags);
+                       vha->scan.scan_flags &= ~SF_SCANNING;
+                       spin_unlock_irqrestore(&vha->work_lock, flags);
+                       return rval;
+               }
+
+               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");
+                       spin_lock_irqsave(&vha->work_lock, flags);
+                       vha->scan.scan_flags &= ~SF_SCANNING;
+                       spin_unlock_irqrestore(&vha->work_lock, flags);
+                       goto done_free_sp;
+               }
+               sp->u.iocb_cmd.u.ctarg.req_size = GPN_FT_REQ_SIZE;
+
+               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");
+                       spin_lock_irqsave(&vha->work_lock, flags);
+                       vha->scan.scan_flags &= ~SF_SCANNING;
+                       spin_unlock_irqrestore(&vha->work_lock, flags);
+                       goto done_free_sp;
+               }
+               sp->u.iocb_cmd.u.ctarg.rsp_size = rspsz;
+
+               ql_dbg(ql_dbg_disc, vha, 0xffff,
+                   "%s scan list size %d\n", __func__, vha->scan.size);
+
+               memset(vha->scan.l, 0, vha->scan.size);
+       } else if (!sp) {
+               ql_dbg(ql_dbg_disc, vha, 0xffff,
+                   "NVME scan did not provide SP\n");
                return rval;
        }
 
@@ -4205,31 +4370,10 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
        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");
-               vha->scan.scan_flags &= ~SF_SCANNING;
-               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");
-               vha->scan.scan_flags &= ~SF_SCANNING;
-               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);
@@ -4237,8 +4381,6 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
        /* 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;
@@ -4246,7 +4388,9 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type)
 
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS) {
+               spin_lock_irqsave(&vha->work_lock, flags);
                vha->scan.scan_flags &= ~SF_SCANNING;
+               spin_unlock_irqrestore(&vha->work_lock, flags);
                goto done_free_sp;
        }
 
index 15a96dc205d00e2e99b9a746d38cc6e0fb2771d3..77c9177d0c25bd63ae0d28c2fe876bdca1706b60 100644 (file)
@@ -5036,9 +5036,9 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
                    fcport->port_name, rval, fcport->fp_speed, mb[0], mb[1]);
        } else {
                ql_dbg(ql_dbg_disc, vha, 0x2005,
-                   "iIDMA adjusted to %s GB/s on %8phN.\n",
+                   "iIDMA adjusted to %s GB/s (%X) on %8phN.\n",
                    qla2x00_get_link_speed_str(ha, fcport->fp_speed),
-                   fcport->port_name);
+                   fcport->fp_speed, fcport->port_name);
        }
 }
 
@@ -5264,8 +5264,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
                qlt_do_generation_tick(vha, &discovery_gen);
 
                if (USE_ASYNC_SCAN(ha)) {
-                       rval = QLA_SUCCESS;
-                       rval = qla24xx_async_gpnft(vha, FC4_TYPE_FCP_SCSI);
+                       rval = qla24xx_async_gpnft(vha, FC4_TYPE_FCP_SCSI,
+                           NULL);
                        if (rval)
                                set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
                } else  {
index 54f93f9cba480f37811bd005cd1e930779abe2d7..6fa2467e2a16983103a93d57caeffbe0fa64c011 100644 (file)
@@ -4803,9 +4803,14 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                        fcport->d_id = e->u.new_sess.id;
                        fcport->flags |= FCF_FABRIC_DEVICE;
                        fcport->fw_login_state = DSC_LS_PLOGI_PEND;
-                       if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI)
+                       if (e->u.new_sess.fc4_type & FS_FC4TYPE_FCP)
                                fcport->fc4_type = FC4_TYPE_FCP_SCSI;
 
+                       if (e->u.new_sess.fc4_type & FS_FC4TYPE_NVME) {
+                               fcport->fc4_type = FC4_TYPE_OTHER;
+                               fcport->fc4f_nvme = FC4_TYPE_NVME;
+                       }
+
                        memcpy(fcport->port_name, e->u.new_sess.port_name,
                            WWN_SIZE);
                } else {
@@ -5021,7 +5026,8 @@ qla2x00_do_work(struct scsi_qla_host *vha)
                            e->u.logio.data);
                        break;
                case QLA_EVT_GPNFT:
-                       qla24xx_async_gpnft(vha, e->u.gpnft.fc4_type);
+                       qla24xx_async_gpnft(vha, e->u.gpnft.fc4_type,
+                           e->u.gpnft.sp);
                        break;
                case QLA_EVT_GPNFT_DONE:
                        qla24xx_async_gpnft_done(vha, e->u.iosb.sp);