Merge tag 'media/v5.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[linux-2.6-microblaze.git] / drivers / scsi / lpfc / lpfc_ct.c
index 3bbefa2..610b6da 100644 (file)
@@ -75,6 +75,9 @@
 
 
 static char *lpfc_release_version = LPFC_DRIVER_VERSION;
+static void
+lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                     struct lpfc_iocbq *rspiocb);
 
 static void
 lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
@@ -587,7 +590,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
             struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
             void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
                     struct lpfc_iocbq *),
-            struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry,
+            struct lpfc_nodelist *ndlp, uint32_t event_tag, uint32_t num_entry,
             uint32_t tmo, uint8_t retry)
 {
        struct lpfc_hba  *phba = vport->phba;
@@ -608,15 +611,14 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
        icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
        icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64));
 
-       if (usr_flg)
-               geniocb->context3 = NULL;
-       else
-               geniocb->context3 = (uint8_t *) bmp;
+       geniocb->context3 = (uint8_t *) bmp;
 
        /* Save for completion so we can release these resources */
        geniocb->context1 = (uint8_t *) inp;
        geniocb->context2 = (uint8_t *) outp;
 
+       geniocb->event_tag = event_tag;
+
        /* Fill in payload, bp points to frame payload */
        icmd->ulpCommand = CMD_GEN_REQUEST64_CR;
 
@@ -707,8 +709,8 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
         * lpfc_alloc_ct_rsp.
         */
        cnt += 1;
-       status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0,
-                             cnt, 0, retry);
+       status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp,
+                       phba->fc_eventTag, cnt, 0, retry);
        if (status) {
                lpfc_free_ct_rsp(phba, outmp);
                return -ENOMEM;
@@ -957,6 +959,13 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                 "GID_FT cmpl:     status:x%x/x%x rtry:%d",
                irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry);
 
+       /* Ignore response if link flipped after this request was made */
+       if (cmdiocb->event_tag != phba->fc_eventTag) {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "9043 Event tag mismatch. Ignoring NS rsp\n");
+               goto out;
+       }
+
        /* Don't bother processing response if vport is being torn down. */
        if (vport->load_flag & FC_UNLOADING) {
                if (vport->fc_flag & FC_RSCN_MODE)
@@ -1167,6 +1176,13 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                              irsp->ulpStatus, irsp->un.ulpWord[4],
                              vport->fc_ns_retry);
 
+       /* Ignore response if link flipped after this request was made */
+       if (cmdiocb->event_tag != phba->fc_eventTag) {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "9044 Event tag mismatch. Ignoring NS rsp\n");
+               goto out;
+       }
+
        /* Don't bother processing response if vport is being torn down. */
        if (vport->load_flag & FC_UNLOADING) {
                if (vport->fc_flag & FC_RSCN_MODE)
@@ -1366,6 +1382,13 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                "GFF_ID cmpl:     status:x%x/x%x did:x%x",
                irsp->ulpStatus, irsp->un.ulpWord[4], did);
 
+       /* Ignore response if link flipped after this request was made */
+       if (cmdiocb->event_tag != phba->fc_eventTag) {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "9045 Event tag mismatch. Ignoring NS rsp\n");
+               goto iocb_free;
+       }
+
        if (irsp->ulpStatus == IOSTAT_SUCCESS) {
                /* Good status, continue checking */
                CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
@@ -1479,6 +1502,7 @@ out:
                lpfc_disc_start(vport);
        }
 
+iocb_free:
        free_ndlp = cmdiocb->context_un.ndlp;
        lpfc_ct_free_iocb(phba, cmdiocb);
        lpfc_nlp_put(free_ndlp);
@@ -1506,6 +1530,13 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                              "GFT_ID cmpl: status:x%x/x%x did:x%x",
                              irsp->ulpStatus, irsp->un.ulpWord[4], did);
 
+       /* Ignore response if link flipped after this request was made */
+       if ((uint32_t) cmdiocb->event_tag != phba->fc_eventTag) {
+               lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                                "9046 Event tag mismatch. Ignoring NS rsp\n");
+               goto out;
+       }
+
        /* Preserve the nameserver node to release the reference. */
        ns_ndlp = cmdiocb->context_un.ndlp;
 
@@ -1572,6 +1603,7 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
                                 "3065 GFT_ID failed x%08x\n", irsp->ulpStatus);
 
+out:
        lpfc_ct_free_iocb(phba, cmdiocb);
        lpfc_nlp_put(ns_ndlp);
 }
@@ -3748,3 +3780,255 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
        }
        return;
 }
+
+static void
+lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                     struct lpfc_iocbq *rspiocb)
+{
+       struct lpfc_vport *vport = cmdiocb->vport;
+       struct lpfc_dmabuf *inp = cmdiocb->context1;
+       struct lpfc_dmabuf *outp = cmdiocb->context2;
+       struct lpfc_sli_ct_request *ctcmd = inp->virt;
+       struct lpfc_sli_ct_request *ctrsp = outp->virt;
+       u16 rsp = ctrsp->CommandResponse.bits.CmdRsp;
+       struct app_id_object *app;
+       u32 cmd, hash, bucket;
+       struct lpfc_vmid *vmp, *cur;
+       u8 *data = outp->virt;
+       int i;
+
+       cmd = be16_to_cpu(ctcmd->CommandResponse.bits.CmdRsp);
+       if (cmd == SLI_CTAS_DALLAPP_ID)
+               lpfc_ct_free_iocb(phba, cmdiocb);
+
+       if (lpfc_els_chk_latt(vport) || rspiocb->iocb.ulpStatus) {
+               if (cmd != SLI_CTAS_DALLAPP_ID)
+                       return;
+       }
+       /* Check for a CT LS_RJT response */
+       if (rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
+               if (cmd != SLI_CTAS_DALLAPP_ID)
+                       lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+                                        "3306 VMID FS_RJT Data: x%x x%x x%x\n",
+                                        cmd, ctrsp->ReasonCode,
+                                        ctrsp->Explanation);
+               if ((cmd != SLI_CTAS_DALLAPP_ID) ||
+                   (ctrsp->ReasonCode != SLI_CT_UNABLE_TO_PERFORM_REQ) ||
+                   (ctrsp->Explanation != SLI_CT_APP_ID_NOT_AVAILABLE)) {
+                       /* If DALLAPP_ID failed retry later */
+                       if (cmd == SLI_CTAS_DALLAPP_ID)
+                               vport->load_flag |= FC_DEREGISTER_ALL_APP_ID;
+                       return;
+               }
+       }
+
+       switch (cmd) {
+       case SLI_CTAS_RAPP_IDENT:
+               app = (struct app_id_object *)(RAPP_IDENT_OFFSET + data);
+               lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+                                "6712 RAPP_IDENT app id %d  port id x%x id "
+                                "len %d\n", be32_to_cpu(app->app_id),
+                                be32_to_cpu(app->port_id),
+                                app->obj.entity_id_len);
+
+               if (app->obj.entity_id_len == 0 || app->port_id == 0)
+                       return;
+
+               hash = lpfc_vmid_hash_fn(app->obj.entity_id,
+                                        app->obj.entity_id_len);
+               vmp = lpfc_get_vmid_from_hashtable(vport, hash,
+                                                 app->obj.entity_id);
+               if (vmp) {
+                       write_lock(&vport->vmid_lock);
+                       vmp->un.app_id = be32_to_cpu(app->app_id);
+                       vmp->flag |= LPFC_VMID_REGISTERED;
+                       vmp->flag &= ~LPFC_VMID_REQ_REGISTER;
+                       write_unlock(&vport->vmid_lock);
+                       /* Set IN USE flag */
+                       vport->vmid_flag |= LPFC_VMID_IN_USE;
+               } else {
+                       lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+                                        "6901 No entry found %s hash %d\n",
+                                        app->obj.entity_id, hash);
+               }
+               break;
+       case SLI_CTAS_DAPP_IDENT:
+               app = (struct app_id_object *)(DAPP_IDENT_OFFSET + data);
+               lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+                                "6713 DAPP_IDENT app id %d  port id x%x\n",
+                                be32_to_cpu(app->app_id),
+                                be32_to_cpu(app->port_id));
+               break;
+       case SLI_CTAS_DALLAPP_ID:
+               lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+                                "8856 Deregistered all app ids\n");
+               read_lock(&vport->vmid_lock);
+               for (i = 0; i < phba->cfg_max_vmid; i++) {
+                       vmp = &vport->vmid[i];
+                       if (vmp->flag != LPFC_VMID_SLOT_FREE)
+                               memset(vmp, 0, sizeof(struct lpfc_vmid));
+               }
+               read_unlock(&vport->vmid_lock);
+               /* for all elements in the hash table */
+               if (!hash_empty(vport->hash_table))
+                       hash_for_each(vport->hash_table, bucket, cur, hnode)
+                               hash_del(&cur->hnode);
+               vport->load_flag |= FC_ALLOW_VMID;
+               break;
+       default:
+               lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+                                "8857 Invalid command code\n");
+       }
+}
+
+/**
+ * lpfc_vmid_cmd - Build and send a FDMI cmd to the specified NPort
+ * @vport: pointer to a host virtual N_Port data structure.
+ * @ndlp: ndlp to send FDMI cmd to (if NULL use FDMI_DID)
+ * cmdcode: FDMI command to send
+ * mask: Mask of HBA or PORT Attributes to send
+ *
+ * Builds and sends a FDMI command using the CT subsystem.
+ */
+int
+lpfc_vmid_cmd(struct lpfc_vport *vport,
+             int cmdcode, struct lpfc_vmid *vmid)
+{
+       struct lpfc_hba *phba = vport->phba;
+       struct lpfc_dmabuf *mp, *bmp;
+       struct lpfc_sli_ct_request *ctreq;
+       struct ulp_bde64 *bpl;
+       u32 size;
+       u32 rsp_size;
+       u8 *data;
+       struct lpfc_vmid_rapp_ident_list *rap;
+       struct lpfc_vmid_dapp_ident_list *dap;
+       u8 retry = 0;
+       struct lpfc_nodelist *ndlp;
+
+       void (*cmpl)(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+                    struct lpfc_iocbq *rspiocb);
+
+       ndlp = lpfc_findnode_did(vport, FDMI_DID);
+       if (!ndlp || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
+               return 0;
+
+       cmpl = lpfc_cmpl_ct_cmd_vmid;
+
+       /* fill in BDEs for command */
+       /* Allocate buffer for command payload */
+       mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+       if (!mp)
+               goto vmid_free_mp_exit;
+
+       mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+       if (!mp->virt)
+               goto vmid_free_mp_virt_exit;
+
+       /* Allocate buffer for Buffer ptr list */
+       bmp = kmalloc(sizeof(*bmp), GFP_KERNEL);
+       if (!bmp)
+               goto vmid_free_bmp_exit;
+
+       bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
+       if (!bmp->virt)
+               goto vmid_free_bmp_virt_exit;
+
+       INIT_LIST_HEAD(&mp->list);
+       INIT_LIST_HEAD(&bmp->list);
+
+       lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+                        "3275 VMID Request Data: x%x x%x x%x\n",
+                        vport->fc_flag, vport->port_state, cmdcode);
+       ctreq = (struct lpfc_sli_ct_request *)mp->virt;
+       data = mp->virt;
+       /* First populate the CT_IU preamble */
+       memset(data, 0, LPFC_BPL_SIZE);
+       ctreq->RevisionId.bits.Revision = SLI_CT_REVISION;
+       ctreq->RevisionId.bits.InId = 0;
+
+       ctreq->FsType = SLI_CT_MANAGEMENT_SERVICE;
+       ctreq->FsSubType = SLI_CT_APP_SEV_Subtypes;
+
+       ctreq->CommandResponse.bits.CmdRsp = cpu_to_be16(cmdcode);
+       rsp_size = LPFC_BPL_SIZE;
+       size = 0;
+
+       switch (cmdcode) {
+       case SLI_CTAS_RAPP_IDENT:
+               lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+                                "1329 RAPP_IDENT for %s\n", vmid->host_vmid);
+               ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+               rap = (struct lpfc_vmid_rapp_ident_list *)
+                       (DAPP_IDENT_OFFSET + data);
+               rap->no_of_objects = cpu_to_be32(1);
+               rap->obj[0].entity_id_len = vmid->vmid_len;
+               memcpy(rap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
+               size = RAPP_IDENT_OFFSET +
+                       sizeof(struct lpfc_vmid_rapp_ident_list);
+               retry = 1;
+               break;
+
+       case SLI_CTAS_GALLAPPIA_ID:
+               ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+               size = GALLAPPIA_ID_SIZE;
+               break;
+
+       case SLI_CTAS_DAPP_IDENT:
+               lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+                                "1469 DAPP_IDENT for %s\n", vmid->host_vmid);
+               ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+               dap = (struct lpfc_vmid_dapp_ident_list *)
+                       (DAPP_IDENT_OFFSET + data);
+               dap->no_of_objects = cpu_to_be32(1);
+               dap->obj[0].entity_id_len = vmid->vmid_len;
+               memcpy(dap->obj[0].entity_id, vmid->host_vmid, vmid->vmid_len);
+               size = DAPP_IDENT_OFFSET +
+                       sizeof(struct lpfc_vmid_dapp_ident_list);
+               write_lock(&vport->vmid_lock);
+               vmid->flag &= ~LPFC_VMID_REGISTERED;
+               write_unlock(&vport->vmid_lock);
+               retry = 1;
+               break;
+
+       case SLI_CTAS_DALLAPP_ID:
+               ctreq->un.PortID = cpu_to_be32(vport->fc_myDID);
+               size = DALLAPP_ID_SIZE;
+               break;
+
+       default:
+               lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+                                "7062 VMID cmdcode x%x not supported\n",
+                                cmdcode);
+               goto vmid_free_all_mem;
+       }
+
+       ctreq->CommandResponse.bits.Size = cpu_to_be16(rsp_size);
+
+       bpl = (struct ulp_bde64 *)bmp->virt;
+       bpl->addrHigh = putPaddrHigh(mp->phys);
+       bpl->addrLow = putPaddrLow(mp->phys);
+       bpl->tus.f.bdeFlags = 0;
+       bpl->tus.f.bdeSize = size;
+
+       /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
+        * to hold ndlp reference for the corresponding callback function.
+        */
+       if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry))
+               return 0;
+
+ vmid_free_all_mem:
+       lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+ vmid_free_bmp_virt_exit:
+       kfree(bmp);
+ vmid_free_bmp_exit:
+       lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ vmid_free_mp_virt_exit:
+       kfree(mp);
+ vmid_free_mp_exit:
+
+       /* Issue CT request failed */
+       lpfc_printf_vlog(vport, KERN_DEBUG, LOG_DISCOVERY,
+                        "3276 VMID CT request failed Data: x%x\n", cmdcode);
+       return -EIO;
+}