1f1c3b0fcSJames Smart /******************************************************************* 2f1c3b0fcSJames Smart * This file is part of the Emulex Linux Device Driver for * 3f1c3b0fcSJames Smart * Fibre Channel Host Bus Adapters. * 44fede78fSJames Smart * Copyright (C) 2009-2010 Emulex. All rights reserved. * 5f1c3b0fcSJames Smart * EMULEX and SLI are trademarks of Emulex. * 6f1c3b0fcSJames Smart * www.emulex.com * 7f1c3b0fcSJames Smart * * 8f1c3b0fcSJames Smart * This program is free software; you can redistribute it and/or * 9f1c3b0fcSJames Smart * modify it under the terms of version 2 of the GNU General * 10f1c3b0fcSJames Smart * Public License as published by the Free Software Foundation. * 11f1c3b0fcSJames Smart * This program is distributed in the hope that it will be useful. * 12f1c3b0fcSJames Smart * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * 13f1c3b0fcSJames Smart * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * 14f1c3b0fcSJames Smart * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * 15f1c3b0fcSJames Smart * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * 16f1c3b0fcSJames Smart * TO BE LEGALLY INVALID. See the GNU General Public License for * 17f1c3b0fcSJames Smart * more details, a copy of which can be found in the file COPYING * 18f1c3b0fcSJames Smart * included with this package. * 19f1c3b0fcSJames Smart *******************************************************************/ 20f1c3b0fcSJames Smart 21f1c3b0fcSJames Smart #include <linux/interrupt.h> 22f1c3b0fcSJames Smart #include <linux/mempool.h> 23f1c3b0fcSJames Smart #include <linux/pci.h> 245a0e3ad6STejun Heo #include <linux/slab.h> 25277e76f1SJames Smart #include <linux/delay.h> 26f1c3b0fcSJames Smart 27f1c3b0fcSJames Smart #include <scsi/scsi.h> 28f1c3b0fcSJames Smart #include <scsi/scsi_host.h> 29f1c3b0fcSJames Smart #include <scsi/scsi_transport_fc.h> 30f1c3b0fcSJames Smart #include <scsi/scsi_bsg_fc.h> 316a9c52cfSJames Smart #include <scsi/fc/fc_fs.h> 32f1c3b0fcSJames Smart 33f1c3b0fcSJames Smart #include "lpfc_hw4.h" 34f1c3b0fcSJames Smart #include "lpfc_hw.h" 35f1c3b0fcSJames Smart #include "lpfc_sli.h" 36f1c3b0fcSJames Smart #include "lpfc_sli4.h" 37f1c3b0fcSJames Smart #include "lpfc_nl.h" 384fede78fSJames Smart #include "lpfc_bsg.h" 39f1c3b0fcSJames Smart #include "lpfc_disc.h" 40f1c3b0fcSJames Smart #include "lpfc_scsi.h" 41f1c3b0fcSJames Smart #include "lpfc.h" 42f1c3b0fcSJames Smart #include "lpfc_logmsg.h" 43f1c3b0fcSJames Smart #include "lpfc_crtn.h" 44f1c3b0fcSJames Smart #include "lpfc_vport.h" 45f1c3b0fcSJames Smart #include "lpfc_version.h" 46f1c3b0fcSJames Smart 474cc0e56eSJames Smart struct lpfc_bsg_event { 484cc0e56eSJames Smart struct list_head node; 494cc0e56eSJames Smart struct kref kref; 504cc0e56eSJames Smart wait_queue_head_t wq; 514cc0e56eSJames Smart 524cc0e56eSJames Smart /* Event type and waiter identifiers */ 534cc0e56eSJames Smart uint32_t type_mask; 544cc0e56eSJames Smart uint32_t req_id; 554cc0e56eSJames Smart uint32_t reg_id; 564cc0e56eSJames Smart 574cc0e56eSJames Smart /* next two flags are here for the auto-delete logic */ 584cc0e56eSJames Smart unsigned long wait_time_stamp; 594cc0e56eSJames Smart int waiting; 604cc0e56eSJames Smart 614cc0e56eSJames Smart /* seen and not seen events */ 624cc0e56eSJames Smart struct list_head events_to_get; 634cc0e56eSJames Smart struct list_head events_to_see; 644cc0e56eSJames Smart 654cc0e56eSJames Smart /* job waiting for this event to finish */ 664cc0e56eSJames Smart struct fc_bsg_job *set_job; 674cc0e56eSJames Smart }; 684cc0e56eSJames Smart 694cc0e56eSJames Smart struct lpfc_bsg_iocb { 704cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq; 714cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq; 724cc0e56eSJames Smart struct lpfc_dmabuf *bmp; 734cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 744cc0e56eSJames Smart 754cc0e56eSJames Smart /* job waiting for this iocb to finish */ 764cc0e56eSJames Smart struct fc_bsg_job *set_job; 774cc0e56eSJames Smart }; 784cc0e56eSJames Smart 793b5dd52aSJames Smart struct lpfc_bsg_mbox { 803b5dd52aSJames Smart LPFC_MBOXQ_t *pmboxq; 813b5dd52aSJames Smart MAILBOX_t *mb; 827a470277SJames Smart struct lpfc_dmabuf *rxbmp; /* for BIU diags */ 837a470277SJames Smart struct lpfc_dmabufext *dmp; /* for BIU diags */ 847a470277SJames Smart uint8_t *ext; /* extended mailbox data */ 857a470277SJames Smart uint32_t mbOffset; /* from app */ 867a470277SJames Smart uint32_t inExtWLen; /* from app */ 87c7495937SJames Smart uint32_t outExtWLen; /* from app */ 883b5dd52aSJames Smart 893b5dd52aSJames Smart /* job waiting for this mbox command to finish */ 903b5dd52aSJames Smart struct fc_bsg_job *set_job; 913b5dd52aSJames Smart }; 923b5dd52aSJames Smart 93e2aed29fSJames Smart #define MENLO_DID 0x0000FC0E 94e2aed29fSJames Smart 95e2aed29fSJames Smart struct lpfc_bsg_menlo { 96e2aed29fSJames Smart struct lpfc_iocbq *cmdiocbq; 97e2aed29fSJames Smart struct lpfc_iocbq *rspiocbq; 98e2aed29fSJames Smart struct lpfc_dmabuf *bmp; 99e2aed29fSJames Smart 100e2aed29fSJames Smart /* job waiting for this iocb to finish */ 101e2aed29fSJames Smart struct fc_bsg_job *set_job; 102e2aed29fSJames Smart }; 103e2aed29fSJames Smart 1044cc0e56eSJames Smart #define TYPE_EVT 1 1054cc0e56eSJames Smart #define TYPE_IOCB 2 1063b5dd52aSJames Smart #define TYPE_MBOX 3 107e2aed29fSJames Smart #define TYPE_MENLO 4 1084cc0e56eSJames Smart struct bsg_job_data { 1094cc0e56eSJames Smart uint32_t type; 1104cc0e56eSJames Smart union { 1114cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1124cc0e56eSJames Smart struct lpfc_bsg_iocb iocb; 1133b5dd52aSJames Smart struct lpfc_bsg_mbox mbox; 114e2aed29fSJames Smart struct lpfc_bsg_menlo menlo; 1154cc0e56eSJames Smart } context_un; 1164cc0e56eSJames Smart }; 1174cc0e56eSJames Smart 1184cc0e56eSJames Smart struct event_data { 1194cc0e56eSJames Smart struct list_head node; 1204cc0e56eSJames Smart uint32_t type; 1214cc0e56eSJames Smart uint32_t immed_dat; 1224cc0e56eSJames Smart void *data; 1234cc0e56eSJames Smart uint32_t len; 1244cc0e56eSJames Smart }; 1254cc0e56eSJames Smart 1263b5dd52aSJames Smart #define BUF_SZ_4K 4096 1274cc0e56eSJames Smart #define SLI_CT_ELX_LOOPBACK 0x10 1284cc0e56eSJames Smart 1294cc0e56eSJames Smart enum ELX_LOOPBACK_CMD { 1304cc0e56eSJames Smart ELX_LOOPBACK_XRI_SETUP, 1314cc0e56eSJames Smart ELX_LOOPBACK_DATA, 1324cc0e56eSJames Smart }; 1334cc0e56eSJames Smart 1343b5dd52aSJames Smart #define ELX_LOOPBACK_HEADER_SZ \ 1353b5dd52aSJames Smart (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un) 1363b5dd52aSJames Smart 1374cc0e56eSJames Smart struct lpfc_dmabufext { 1384cc0e56eSJames Smart struct lpfc_dmabuf dma; 1394cc0e56eSJames Smart uint32_t size; 1404cc0e56eSJames Smart uint32_t flag; 1414cc0e56eSJames Smart }; 1424cc0e56eSJames Smart 143f1c3b0fcSJames Smart /** 1444cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler 1454cc0e56eSJames Smart * @phba: Pointer to HBA context object. 1464cc0e56eSJames Smart * @cmdiocbq: Pointer to command iocb. 1474cc0e56eSJames Smart * @rspiocbq: Pointer to response iocb. 1484cc0e56eSJames Smart * 1494cc0e56eSJames Smart * This function is the completion handler for iocbs issued using 1504cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd function. This function is called by the 1514cc0e56eSJames Smart * ring event handler function without any lock held. This function 1524cc0e56eSJames Smart * can be called from both worker thread context and interrupt 1534cc0e56eSJames Smart * context. This function also can be called from another thread which 1544cc0e56eSJames Smart * cleans up the SLI layer objects. 1554cc0e56eSJames Smart * This function copies the contents of the response iocb to the 1564cc0e56eSJames Smart * response iocb memory object provided by the caller of 1574cc0e56eSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 1584cc0e56eSJames Smart * sleeps for the iocb completion. 1594cc0e56eSJames Smart **/ 1604cc0e56eSJames Smart static void 1614cc0e56eSJames Smart lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, 1624cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq, 1634cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq) 1644cc0e56eSJames Smart { 1654cc0e56eSJames Smart struct bsg_job_data *dd_data; 1664cc0e56eSJames Smart struct fc_bsg_job *job; 1674cc0e56eSJames Smart IOCB_t *rsp; 1684cc0e56eSJames Smart struct lpfc_dmabuf *bmp; 1694cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 1704cc0e56eSJames Smart struct lpfc_bsg_iocb *iocb; 1714cc0e56eSJames Smart unsigned long flags; 1724cc0e56eSJames Smart int rc = 0; 1734cc0e56eSJames Smart 1744cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 175be858b65SJames Smart dd_data = cmdiocbq->context2; 1764cc0e56eSJames Smart if (!dd_data) { 1774cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 178be858b65SJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 1794cc0e56eSJames Smart return; 1804cc0e56eSJames Smart } 1814cc0e56eSJames Smart 1824cc0e56eSJames Smart iocb = &dd_data->context_un.iocb; 1834cc0e56eSJames Smart job = iocb->set_job; 1844cc0e56eSJames Smart job->dd_data = NULL; /* so timeout handler does not reply */ 1854cc0e56eSJames Smart 1864cc0e56eSJames Smart bmp = iocb->bmp; 1874cc0e56eSJames Smart rsp = &rspiocbq->iocb; 188be858b65SJames Smart ndlp = cmdiocbq->context1; 1894cc0e56eSJames Smart 1904cc0e56eSJames Smart pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, 1914cc0e56eSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 1924cc0e56eSJames Smart pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, 1934cc0e56eSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 1944cc0e56eSJames Smart 1954cc0e56eSJames Smart if (rsp->ulpStatus) { 1964cc0e56eSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 1974cc0e56eSJames Smart switch (rsp->un.ulpWord[4] & 0xff) { 1984cc0e56eSJames Smart case IOERR_SEQUENCE_TIMEOUT: 1994cc0e56eSJames Smart rc = -ETIMEDOUT; 2004cc0e56eSJames Smart break; 2014cc0e56eSJames Smart case IOERR_INVALID_RPI: 2024cc0e56eSJames Smart rc = -EFAULT; 2034cc0e56eSJames Smart break; 2044cc0e56eSJames Smart default: 2054cc0e56eSJames Smart rc = -EACCES; 2064cc0e56eSJames Smart break; 2074cc0e56eSJames Smart } 2084cc0e56eSJames Smart } else 2094cc0e56eSJames Smart rc = -EACCES; 2104cc0e56eSJames Smart } else 2114cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 2124cc0e56eSJames Smart rsp->un.genreq64.bdl.bdeSize; 2134cc0e56eSJames Smart 2144cc0e56eSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 2154cc0e56eSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 2164cc0e56eSJames Smart lpfc_nlp_put(ndlp); 2174cc0e56eSJames Smart kfree(bmp); 2184cc0e56eSJames Smart kfree(dd_data); 2194cc0e56eSJames Smart /* make error code available to userspace */ 2204cc0e56eSJames Smart job->reply->result = rc; 2214cc0e56eSJames Smart /* complete the job back to userspace */ 2224cc0e56eSJames Smart job->job_done(job); 2234cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 2244cc0e56eSJames Smart return; 2254cc0e56eSJames Smart } 2264cc0e56eSJames Smart 2274cc0e56eSJames Smart /** 2284cc0e56eSJames Smart * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request 229f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 2303b5dd52aSJames Smart **/ 231f1c3b0fcSJames Smart static int 2324cc0e56eSJames Smart lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) 233f1c3b0fcSJames Smart { 234f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 235f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 236f1c3b0fcSJames Smart struct lpfc_rport_data *rdata = job->rport->dd_data; 237f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 238f1c3b0fcSJames Smart struct ulp_bde64 *bpl = NULL; 239f1c3b0fcSJames Smart uint32_t timeout; 240f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq = NULL; 241f1c3b0fcSJames Smart IOCB_t *cmd; 242f1c3b0fcSJames Smart struct lpfc_dmabuf *bmp = NULL; 243f1c3b0fcSJames Smart int request_nseg; 244f1c3b0fcSJames Smart int reply_nseg; 245f1c3b0fcSJames Smart struct scatterlist *sgel = NULL; 246f1c3b0fcSJames Smart int numbde; 247f1c3b0fcSJames Smart dma_addr_t busaddr; 2484cc0e56eSJames Smart struct bsg_job_data *dd_data; 2494cc0e56eSJames Smart uint32_t creg_val; 250f1c3b0fcSJames Smart int rc = 0; 251d439d286SJames Smart int iocb_stat; 252f1c3b0fcSJames Smart 253f1c3b0fcSJames Smart /* in case no data is transferred */ 254f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 255f1c3b0fcSJames Smart 2564cc0e56eSJames Smart /* allocate our bsg tracking structure */ 2574cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 2584cc0e56eSJames Smart if (!dd_data) { 2594cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 2604cc0e56eSJames Smart "2733 Failed allocation of dd_data\n"); 2614cc0e56eSJames Smart rc = -ENOMEM; 2624cc0e56eSJames Smart goto no_dd_data; 2634cc0e56eSJames Smart } 2644cc0e56eSJames Smart 265f1c3b0fcSJames Smart if (!lpfc_nlp_get(ndlp)) { 2664cc0e56eSJames Smart rc = -ENODEV; 2674cc0e56eSJames Smart goto no_ndlp; 2684cc0e56eSJames Smart } 2694cc0e56eSJames Smart 2704cc0e56eSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 2714cc0e56eSJames Smart if (!bmp) { 2724cc0e56eSJames Smart rc = -ENOMEM; 2734cc0e56eSJames Smart goto free_ndlp; 274f1c3b0fcSJames Smart } 275f1c3b0fcSJames Smart 276f1c3b0fcSJames Smart if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { 277f1c3b0fcSJames Smart rc = -ENODEV; 2784cc0e56eSJames Smart goto free_bmp; 279f1c3b0fcSJames Smart } 280f1c3b0fcSJames Smart 281f1c3b0fcSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 282f1c3b0fcSJames Smart if (!cmdiocbq) { 283f1c3b0fcSJames Smart rc = -ENOMEM; 2844cc0e56eSJames Smart goto free_bmp; 285f1c3b0fcSJames Smart } 286f1c3b0fcSJames Smart 2874cc0e56eSJames Smart cmd = &cmdiocbq->iocb; 288f1c3b0fcSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 289f1c3b0fcSJames Smart if (!bmp->virt) { 290f1c3b0fcSJames Smart rc = -ENOMEM; 291be858b65SJames Smart goto free_cmdiocbq; 292f1c3b0fcSJames Smart } 293f1c3b0fcSJames Smart 294f1c3b0fcSJames Smart INIT_LIST_HEAD(&bmp->list); 295f1c3b0fcSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 296f1c3b0fcSJames Smart request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, 297f1c3b0fcSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 298f1c3b0fcSJames Smart for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { 299f1c3b0fcSJames Smart busaddr = sg_dma_address(sgel); 300f1c3b0fcSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; 301f1c3b0fcSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 302f1c3b0fcSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 303f1c3b0fcSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 304f1c3b0fcSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 305f1c3b0fcSJames Smart bpl++; 306f1c3b0fcSJames Smart } 307f1c3b0fcSJames Smart 308f1c3b0fcSJames Smart reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list, 309f1c3b0fcSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 310f1c3b0fcSJames Smart for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) { 311f1c3b0fcSJames Smart busaddr = sg_dma_address(sgel); 312f1c3b0fcSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 313f1c3b0fcSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 314f1c3b0fcSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 315f1c3b0fcSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 316f1c3b0fcSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 317f1c3b0fcSJames Smart bpl++; 318f1c3b0fcSJames Smart } 319f1c3b0fcSJames Smart 320f1c3b0fcSJames Smart cmd->un.genreq64.bdl.ulpIoTag32 = 0; 321f1c3b0fcSJames Smart cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 322f1c3b0fcSJames Smart cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); 323f1c3b0fcSJames Smart cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 324f1c3b0fcSJames Smart cmd->un.genreq64.bdl.bdeSize = 325f1c3b0fcSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 326f1c3b0fcSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CR; 327f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); 328f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Dfctl = 0; 3296a9c52cfSJames Smart cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 3306a9c52cfSJames Smart cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; 331f1c3b0fcSJames Smart cmd->ulpBdeCount = 1; 332f1c3b0fcSJames Smart cmd->ulpLe = 1; 333f1c3b0fcSJames Smart cmd->ulpClass = CLASS3; 334f1c3b0fcSJames Smart cmd->ulpContext = ndlp->nlp_rpi; 335f1c3b0fcSJames Smart cmd->ulpOwner = OWN_CHIP; 336f1c3b0fcSJames Smart cmdiocbq->vport = phba->pport; 3374cc0e56eSJames Smart cmdiocbq->context3 = bmp; 338f1c3b0fcSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 339f1c3b0fcSJames Smart timeout = phba->fc_ratov * 2; 3404cc0e56eSJames Smart cmd->ulpTimeout = timeout; 341f1c3b0fcSJames Smart 3424cc0e56eSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; 343be858b65SJames Smart cmdiocbq->context1 = ndlp; 344be858b65SJames Smart cmdiocbq->context2 = dd_data; 3454cc0e56eSJames Smart dd_data->type = TYPE_IOCB; 3464cc0e56eSJames Smart dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 3474cc0e56eSJames Smart dd_data->context_un.iocb.set_job = job; 3484cc0e56eSJames Smart dd_data->context_un.iocb.bmp = bmp; 349f1c3b0fcSJames Smart 3504cc0e56eSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 3514cc0e56eSJames Smart creg_val = readl(phba->HCregaddr); 3524cc0e56eSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 3534cc0e56eSJames Smart writel(creg_val, phba->HCregaddr); 3544cc0e56eSJames Smart readl(phba->HCregaddr); /* flush */ 3554cc0e56eSJames Smart } 3564cc0e56eSJames Smart 357d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 358d439d286SJames Smart if (iocb_stat == IOCB_SUCCESS) 3594cc0e56eSJames Smart return 0; /* done for now */ 360d439d286SJames Smart else if (iocb_stat == IOCB_BUSY) 361d439d286SJames Smart rc = -EAGAIN; 3622a9bf3d0SJames Smart else 363d439d286SJames Smart rc = -EIO; 3642a9bf3d0SJames Smart 3654cc0e56eSJames Smart 3664cc0e56eSJames Smart /* iocb failed so cleanup */ 367f1c3b0fcSJames Smart pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, 368f1c3b0fcSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 369f1c3b0fcSJames Smart pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, 370f1c3b0fcSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 371f1c3b0fcSJames Smart 372f1c3b0fcSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 3734cc0e56eSJames Smart 374f1c3b0fcSJames Smart free_cmdiocbq: 375f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 3764cc0e56eSJames Smart free_bmp: 3774cc0e56eSJames Smart kfree(bmp); 3784cc0e56eSJames Smart free_ndlp: 379f1c3b0fcSJames Smart lpfc_nlp_put(ndlp); 3804cc0e56eSJames Smart no_ndlp: 3814cc0e56eSJames Smart kfree(dd_data); 3824cc0e56eSJames Smart no_dd_data: 383f1c3b0fcSJames Smart /* make error code available to userspace */ 384f1c3b0fcSJames Smart job->reply->result = rc; 3854cc0e56eSJames Smart job->dd_data = NULL; 3864cc0e56eSJames Smart return rc; 3874cc0e56eSJames Smart } 3884cc0e56eSJames Smart 3894cc0e56eSJames Smart /** 3904cc0e56eSJames Smart * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler 3914cc0e56eSJames Smart * @phba: Pointer to HBA context object. 3924cc0e56eSJames Smart * @cmdiocbq: Pointer to command iocb. 3934cc0e56eSJames Smart * @rspiocbq: Pointer to response iocb. 3944cc0e56eSJames Smart * 3954cc0e56eSJames Smart * This function is the completion handler for iocbs issued using 3964cc0e56eSJames Smart * lpfc_bsg_rport_els_cmp function. This function is called by the 3974cc0e56eSJames Smart * ring event handler function without any lock held. This function 3984cc0e56eSJames Smart * can be called from both worker thread context and interrupt 3994cc0e56eSJames Smart * context. This function also can be called from other thread which 4004cc0e56eSJames Smart * cleans up the SLI layer objects. 4013b5dd52aSJames Smart * This function copies the contents of the response iocb to the 4024cc0e56eSJames Smart * response iocb memory object provided by the caller of 4034cc0e56eSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 4044cc0e56eSJames Smart * sleeps for the iocb completion. 4054cc0e56eSJames Smart **/ 4064cc0e56eSJames Smart static void 4074cc0e56eSJames Smart lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, 4084cc0e56eSJames Smart struct lpfc_iocbq *cmdiocbq, 4094cc0e56eSJames Smart struct lpfc_iocbq *rspiocbq) 4104cc0e56eSJames Smart { 4114cc0e56eSJames Smart struct bsg_job_data *dd_data; 4124cc0e56eSJames Smart struct fc_bsg_job *job; 4134cc0e56eSJames Smart IOCB_t *rsp; 4144cc0e56eSJames Smart struct lpfc_nodelist *ndlp; 4154cc0e56eSJames Smart struct lpfc_dmabuf *pbuflist = NULL; 4164cc0e56eSJames Smart struct fc_bsg_ctels_reply *els_reply; 4174cc0e56eSJames Smart uint8_t *rjt_data; 4184cc0e56eSJames Smart unsigned long flags; 4194cc0e56eSJames Smart int rc = 0; 4204cc0e56eSJames Smart 4214cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 4224cc0e56eSJames Smart dd_data = cmdiocbq->context1; 4234cc0e56eSJames Smart /* normal completion and timeout crossed paths, already done */ 4244cc0e56eSJames Smart if (!dd_data) { 42567221a42SJiri Slaby spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 4264cc0e56eSJames Smart return; 4274cc0e56eSJames Smart } 4284cc0e56eSJames Smart 4294cc0e56eSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_WAKE; 4304cc0e56eSJames Smart if (cmdiocbq->context2 && rspiocbq) 4314cc0e56eSJames Smart memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, 4324cc0e56eSJames Smart &rspiocbq->iocb, sizeof(IOCB_t)); 4334cc0e56eSJames Smart 4344cc0e56eSJames Smart job = dd_data->context_un.iocb.set_job; 4354cc0e56eSJames Smart cmdiocbq = dd_data->context_un.iocb.cmdiocbq; 4364cc0e56eSJames Smart rspiocbq = dd_data->context_un.iocb.rspiocbq; 4374cc0e56eSJames Smart rsp = &rspiocbq->iocb; 4384cc0e56eSJames Smart ndlp = dd_data->context_un.iocb.ndlp; 4394cc0e56eSJames Smart 4404cc0e56eSJames Smart pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, 4414cc0e56eSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 4424cc0e56eSJames Smart pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, 4434cc0e56eSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 4444cc0e56eSJames Smart 4454cc0e56eSJames Smart if (job->reply->result == -EAGAIN) 4464cc0e56eSJames Smart rc = -EAGAIN; 4474cc0e56eSJames Smart else if (rsp->ulpStatus == IOSTAT_SUCCESS) 4484cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 4494cc0e56eSJames Smart rsp->un.elsreq64.bdl.bdeSize; 4504cc0e56eSJames Smart else if (rsp->ulpStatus == IOSTAT_LS_RJT) { 4514cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 4524cc0e56eSJames Smart sizeof(struct fc_bsg_ctels_reply); 4534cc0e56eSJames Smart /* LS_RJT data returned in word 4 */ 4544cc0e56eSJames Smart rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; 4554cc0e56eSJames Smart els_reply = &job->reply->reply_data.ctels_reply; 4564cc0e56eSJames Smart els_reply->status = FC_CTELS_STATUS_REJECT; 4574cc0e56eSJames Smart els_reply->rjt_data.action = rjt_data[3]; 4584cc0e56eSJames Smart els_reply->rjt_data.reason_code = rjt_data[2]; 4594cc0e56eSJames Smart els_reply->rjt_data.reason_explanation = rjt_data[1]; 4604cc0e56eSJames Smart els_reply->rjt_data.vendor_unique = rjt_data[0]; 4614cc0e56eSJames Smart } else 4624cc0e56eSJames Smart rc = -EIO; 4634cc0e56eSJames Smart 4644cc0e56eSJames Smart pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3; 4654cc0e56eSJames Smart lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys); 4664cc0e56eSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 4674cc0e56eSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 4684cc0e56eSJames Smart lpfc_nlp_put(ndlp); 4694cc0e56eSJames Smart kfree(dd_data); 4704cc0e56eSJames Smart /* make error code available to userspace */ 4714cc0e56eSJames Smart job->reply->result = rc; 4724cc0e56eSJames Smart job->dd_data = NULL; 473f1c3b0fcSJames Smart /* complete the job back to userspace */ 474f1c3b0fcSJames Smart job->job_done(job); 4754cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 4764cc0e56eSJames Smart return; 477f1c3b0fcSJames Smart } 478f1c3b0fcSJames Smart 479f1c3b0fcSJames Smart /** 480f1c3b0fcSJames Smart * lpfc_bsg_rport_els - send an ELS command from a bsg request 481f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 4823b5dd52aSJames Smart **/ 483f1c3b0fcSJames Smart static int 484f1c3b0fcSJames Smart lpfc_bsg_rport_els(struct fc_bsg_job *job) 485f1c3b0fcSJames Smart { 486f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 487f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 488f1c3b0fcSJames Smart struct lpfc_rport_data *rdata = job->rport->dd_data; 489f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 490f1c3b0fcSJames Smart uint32_t elscmd; 491f1c3b0fcSJames Smart uint32_t cmdsize; 492f1c3b0fcSJames Smart uint32_t rspsize; 493f1c3b0fcSJames Smart struct lpfc_iocbq *rspiocbq; 494f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq; 495f1c3b0fcSJames Smart IOCB_t *rsp; 496f1c3b0fcSJames Smart uint16_t rpi = 0; 497f1c3b0fcSJames Smart struct lpfc_dmabuf *pcmd; 498f1c3b0fcSJames Smart struct lpfc_dmabuf *prsp; 499f1c3b0fcSJames Smart struct lpfc_dmabuf *pbuflist = NULL; 500f1c3b0fcSJames Smart struct ulp_bde64 *bpl; 501f1c3b0fcSJames Smart int request_nseg; 502f1c3b0fcSJames Smart int reply_nseg; 503f1c3b0fcSJames Smart struct scatterlist *sgel = NULL; 504f1c3b0fcSJames Smart int numbde; 505f1c3b0fcSJames Smart dma_addr_t busaddr; 5064cc0e56eSJames Smart struct bsg_job_data *dd_data; 5074cc0e56eSJames Smart uint32_t creg_val; 508f1c3b0fcSJames Smart int rc = 0; 509f1c3b0fcSJames Smart 510f1c3b0fcSJames Smart /* in case no data is transferred */ 511f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 512f1c3b0fcSJames Smart 5134cc0e56eSJames Smart /* allocate our bsg tracking structure */ 5144cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 5154cc0e56eSJames Smart if (!dd_data) { 5164cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 5174cc0e56eSJames Smart "2735 Failed allocation of dd_data\n"); 5184cc0e56eSJames Smart rc = -ENOMEM; 5194cc0e56eSJames Smart goto no_dd_data; 5204cc0e56eSJames Smart } 5214cc0e56eSJames Smart 522f1c3b0fcSJames Smart if (!lpfc_nlp_get(ndlp)) { 523f1c3b0fcSJames Smart rc = -ENODEV; 5244cc0e56eSJames Smart goto free_dd_data; 525f1c3b0fcSJames Smart } 526f1c3b0fcSJames Smart 527f1c3b0fcSJames Smart elscmd = job->request->rqst_data.r_els.els_code; 528f1c3b0fcSJames Smart cmdsize = job->request_payload.payload_len; 529f1c3b0fcSJames Smart rspsize = job->reply_payload.payload_len; 530f1c3b0fcSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 531f1c3b0fcSJames Smart if (!rspiocbq) { 532f1c3b0fcSJames Smart lpfc_nlp_put(ndlp); 533f1c3b0fcSJames Smart rc = -ENOMEM; 5344cc0e56eSJames Smart goto free_dd_data; 535f1c3b0fcSJames Smart } 536f1c3b0fcSJames Smart 537f1c3b0fcSJames Smart rsp = &rspiocbq->iocb; 538f1c3b0fcSJames Smart rpi = ndlp->nlp_rpi; 539f1c3b0fcSJames Smart 5404cc0e56eSJames Smart cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, 541f1c3b0fcSJames Smart ndlp->nlp_DID, elscmd); 542f1c3b0fcSJames Smart if (!cmdiocbq) { 5434cc0e56eSJames Smart rc = -EIO; 5444cc0e56eSJames Smart goto free_rspiocbq; 545f1c3b0fcSJames Smart } 546f1c3b0fcSJames Smart 5474cc0e56eSJames Smart /* prep els iocb set context1 to the ndlp, context2 to the command 5484cc0e56eSJames Smart * dmabuf, context3 holds the data dmabuf 5494cc0e56eSJames Smart */ 550f1c3b0fcSJames Smart pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; 551f1c3b0fcSJames Smart prsp = (struct lpfc_dmabuf *) pcmd->list.next; 552f1c3b0fcSJames Smart lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); 553f1c3b0fcSJames Smart kfree(pcmd); 554f1c3b0fcSJames Smart lpfc_mbuf_free(phba, prsp->virt, prsp->phys); 555f1c3b0fcSJames Smart kfree(prsp); 556f1c3b0fcSJames Smart cmdiocbq->context2 = NULL; 557f1c3b0fcSJames Smart 558f1c3b0fcSJames Smart pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3; 559f1c3b0fcSJames Smart bpl = (struct ulp_bde64 *) pbuflist->virt; 560f1c3b0fcSJames Smart 561f1c3b0fcSJames Smart request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, 562f1c3b0fcSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 563f1c3b0fcSJames Smart for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { 564f1c3b0fcSJames Smart busaddr = sg_dma_address(sgel); 565f1c3b0fcSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; 566f1c3b0fcSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 567f1c3b0fcSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 568f1c3b0fcSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 569f1c3b0fcSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 570f1c3b0fcSJames Smart bpl++; 571f1c3b0fcSJames Smart } 572f1c3b0fcSJames Smart 573f1c3b0fcSJames Smart reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list, 574f1c3b0fcSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 575f1c3b0fcSJames Smart for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) { 576f1c3b0fcSJames Smart busaddr = sg_dma_address(sgel); 577f1c3b0fcSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 578f1c3b0fcSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 579f1c3b0fcSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 580f1c3b0fcSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 581f1c3b0fcSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 582f1c3b0fcSJames Smart bpl++; 583f1c3b0fcSJames Smart } 584f1c3b0fcSJames Smart cmdiocbq->iocb.un.elsreq64.bdl.bdeSize = 585f1c3b0fcSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 586f1c3b0fcSJames Smart cmdiocbq->iocb.ulpContext = rpi; 587f1c3b0fcSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 588f1c3b0fcSJames Smart cmdiocbq->context1 = NULL; 589f1c3b0fcSJames Smart cmdiocbq->context2 = NULL; 590f1c3b0fcSJames Smart 5914cc0e56eSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; 5924cc0e56eSJames Smart cmdiocbq->context1 = dd_data; 5934cc0e56eSJames Smart cmdiocbq->context2 = rspiocbq; 5944cc0e56eSJames Smart dd_data->type = TYPE_IOCB; 5954cc0e56eSJames Smart dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 5964cc0e56eSJames Smart dd_data->context_un.iocb.rspiocbq = rspiocbq; 5974cc0e56eSJames Smart dd_data->context_un.iocb.set_job = job; 5984cc0e56eSJames Smart dd_data->context_un.iocb.bmp = NULL;; 5994cc0e56eSJames Smart dd_data->context_un.iocb.ndlp = ndlp; 600f1c3b0fcSJames Smart 6014cc0e56eSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 6024cc0e56eSJames Smart creg_val = readl(phba->HCregaddr); 6034cc0e56eSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 6044cc0e56eSJames Smart writel(creg_val, phba->HCregaddr); 6054cc0e56eSJames Smart readl(phba->HCregaddr); /* flush */ 6064cc0e56eSJames Smart } 6074cc0e56eSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); 608f1c3b0fcSJames Smart lpfc_nlp_put(ndlp); 6094cc0e56eSJames Smart if (rc == IOCB_SUCCESS) 6104cc0e56eSJames Smart return 0; /* done for now */ 6112a9bf3d0SJames Smart else if (rc == IOCB_BUSY) 612d439d286SJames Smart rc = -EAGAIN; 6132a9bf3d0SJames Smart else 614d439d286SJames Smart rc = -EIO; 6154cc0e56eSJames Smart 616f1c3b0fcSJames Smart pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, 617f1c3b0fcSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 618f1c3b0fcSJames Smart pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, 619f1c3b0fcSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 620f1c3b0fcSJames Smart 6214cc0e56eSJames Smart lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys); 622f1c3b0fcSJames Smart 6234cc0e56eSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 624f1c3b0fcSJames Smart 6254cc0e56eSJames Smart free_rspiocbq: 626f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 627f1c3b0fcSJames Smart 6284cc0e56eSJames Smart free_dd_data: 6294cc0e56eSJames Smart kfree(dd_data); 6304cc0e56eSJames Smart 6314cc0e56eSJames Smart no_dd_data: 632f1c3b0fcSJames Smart /* make error code available to userspace */ 633f1c3b0fcSJames Smart job->reply->result = rc; 6344cc0e56eSJames Smart job->dd_data = NULL; 6354cc0e56eSJames Smart return rc; 636f1c3b0fcSJames Smart } 637f1c3b0fcSJames Smart 6383b5dd52aSJames Smart /** 6393b5dd52aSJames Smart * lpfc_bsg_event_free - frees an allocated event structure 6403b5dd52aSJames Smart * @kref: Pointer to a kref. 6413b5dd52aSJames Smart * 6423b5dd52aSJames Smart * Called from kref_put. Back cast the kref into an event structure address. 6433b5dd52aSJames Smart * Free any events to get, delete associated nodes, free any events to see, 6443b5dd52aSJames Smart * free any data then free the event itself. 6453b5dd52aSJames Smart **/ 646f1c3b0fcSJames Smart static void 6474cc0e56eSJames Smart lpfc_bsg_event_free(struct kref *kref) 648f1c3b0fcSJames Smart { 6494cc0e56eSJames Smart struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event, 6504cc0e56eSJames Smart kref); 651f1c3b0fcSJames Smart struct event_data *ed; 652f1c3b0fcSJames Smart 653f1c3b0fcSJames Smart list_del(&evt->node); 654f1c3b0fcSJames Smart 655f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_get)) { 656f1c3b0fcSJames Smart ed = list_entry(evt->events_to_get.next, typeof(*ed), node); 657f1c3b0fcSJames Smart list_del(&ed->node); 658f1c3b0fcSJames Smart kfree(ed->data); 659f1c3b0fcSJames Smart kfree(ed); 660f1c3b0fcSJames Smart } 661f1c3b0fcSJames Smart 662f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_see)) { 663f1c3b0fcSJames Smart ed = list_entry(evt->events_to_see.next, typeof(*ed), node); 664f1c3b0fcSJames Smart list_del(&ed->node); 665f1c3b0fcSJames Smart kfree(ed->data); 666f1c3b0fcSJames Smart kfree(ed); 667f1c3b0fcSJames Smart } 668f1c3b0fcSJames Smart 669f1c3b0fcSJames Smart kfree(evt); 670f1c3b0fcSJames Smart } 671f1c3b0fcSJames Smart 6723b5dd52aSJames Smart /** 6733b5dd52aSJames Smart * lpfc_bsg_event_ref - increments the kref for an event 6743b5dd52aSJames Smart * @evt: Pointer to an event structure. 6753b5dd52aSJames Smart **/ 676f1c3b0fcSJames Smart static inline void 6774cc0e56eSJames Smart lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) 678f1c3b0fcSJames Smart { 6794cc0e56eSJames Smart kref_get(&evt->kref); 680f1c3b0fcSJames Smart } 681f1c3b0fcSJames Smart 6823b5dd52aSJames Smart /** 6833b5dd52aSJames Smart * lpfc_bsg_event_unref - Uses kref_put to free an event structure 6843b5dd52aSJames Smart * @evt: Pointer to an event structure. 6853b5dd52aSJames Smart **/ 686f1c3b0fcSJames Smart static inline void 6874cc0e56eSJames Smart lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) 688f1c3b0fcSJames Smart { 6894cc0e56eSJames Smart kref_put(&evt->kref, lpfc_bsg_event_free); 690f1c3b0fcSJames Smart } 691f1c3b0fcSJames Smart 6923b5dd52aSJames Smart /** 6933b5dd52aSJames Smart * lpfc_bsg_event_new - allocate and initialize a event structure 6943b5dd52aSJames Smart * @ev_mask: Mask of events. 6953b5dd52aSJames Smart * @ev_reg_id: Event reg id. 6963b5dd52aSJames Smart * @ev_req_id: Event request id. 6973b5dd52aSJames Smart **/ 6984cc0e56eSJames Smart static struct lpfc_bsg_event * 6994cc0e56eSJames Smart lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) 7004cc0e56eSJames Smart { 7014cc0e56eSJames Smart struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); 702f1c3b0fcSJames Smart 7034cc0e56eSJames Smart if (!evt) 7044cc0e56eSJames Smart return NULL; 7054cc0e56eSJames Smart 7064cc0e56eSJames Smart INIT_LIST_HEAD(&evt->events_to_get); 7074cc0e56eSJames Smart INIT_LIST_HEAD(&evt->events_to_see); 7084cc0e56eSJames Smart evt->type_mask = ev_mask; 7094cc0e56eSJames Smart evt->req_id = ev_req_id; 7104cc0e56eSJames Smart evt->reg_id = ev_reg_id; 7114cc0e56eSJames Smart evt->wait_time_stamp = jiffies; 7124cc0e56eSJames Smart init_waitqueue_head(&evt->wq); 7134cc0e56eSJames Smart kref_init(&evt->kref); 7144cc0e56eSJames Smart return evt; 7154cc0e56eSJames Smart } 7164cc0e56eSJames Smart 7173b5dd52aSJames Smart /** 7183b5dd52aSJames Smart * diag_cmd_data_free - Frees an lpfc dma buffer extension 7193b5dd52aSJames Smart * @phba: Pointer to HBA context object. 7203b5dd52aSJames Smart * @mlist: Pointer to an lpfc dma buffer extension. 7213b5dd52aSJames Smart **/ 7224cc0e56eSJames Smart static int 7233b5dd52aSJames Smart diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) 7244cc0e56eSJames Smart { 7254cc0e56eSJames Smart struct lpfc_dmabufext *mlast; 7264cc0e56eSJames Smart struct pci_dev *pcidev; 7274cc0e56eSJames Smart struct list_head head, *curr, *next; 7284cc0e56eSJames Smart 7294cc0e56eSJames Smart if ((!mlist) || (!lpfc_is_link_up(phba) && 7304cc0e56eSJames Smart (phba->link_flag & LS_LOOPBACK_MODE))) { 7314cc0e56eSJames Smart return 0; 7324cc0e56eSJames Smart } 7334cc0e56eSJames Smart 7344cc0e56eSJames Smart pcidev = phba->pcidev; 7354cc0e56eSJames Smart list_add_tail(&head, &mlist->dma.list); 7364cc0e56eSJames Smart 7374cc0e56eSJames Smart list_for_each_safe(curr, next, &head) { 7384cc0e56eSJames Smart mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); 7394cc0e56eSJames Smart if (mlast->dma.virt) 7404cc0e56eSJames Smart dma_free_coherent(&pcidev->dev, 7414cc0e56eSJames Smart mlast->size, 7424cc0e56eSJames Smart mlast->dma.virt, 7434cc0e56eSJames Smart mlast->dma.phys); 7444cc0e56eSJames Smart kfree(mlast); 7454cc0e56eSJames Smart } 7464cc0e56eSJames Smart return 0; 7474cc0e56eSJames Smart } 748f1c3b0fcSJames Smart 749f1c3b0fcSJames Smart /** 750f1c3b0fcSJames Smart * lpfc_bsg_ct_unsol_event - process an unsolicited CT command 751f1c3b0fcSJames Smart * @phba: 752f1c3b0fcSJames Smart * @pring: 753f1c3b0fcSJames Smart * @piocbq: 754f1c3b0fcSJames Smart * 755f1c3b0fcSJames Smart * This function is called when an unsolicited CT command is received. It 7564cc0e56eSJames Smart * forwards the event to any processes registered to receive CT events. 7573b5dd52aSJames Smart **/ 7584fede78fSJames Smart int 759f1c3b0fcSJames Smart lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, 760f1c3b0fcSJames Smart struct lpfc_iocbq *piocbq) 761f1c3b0fcSJames Smart { 762f1c3b0fcSJames Smart uint32_t evt_req_id = 0; 763f1c3b0fcSJames Smart uint32_t cmd; 764f1c3b0fcSJames Smart uint32_t len; 765f1c3b0fcSJames Smart struct lpfc_dmabuf *dmabuf = NULL; 7664cc0e56eSJames Smart struct lpfc_bsg_event *evt; 767f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 768f1c3b0fcSJames Smart struct lpfc_iocbq *iocbq; 769f1c3b0fcSJames Smart size_t offset = 0; 770f1c3b0fcSJames Smart struct list_head head; 771f1c3b0fcSJames Smart struct ulp_bde64 *bde; 772f1c3b0fcSJames Smart dma_addr_t dma_addr; 773f1c3b0fcSJames Smart int i; 774f1c3b0fcSJames Smart struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; 775f1c3b0fcSJames Smart struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; 776f1c3b0fcSJames Smart struct lpfc_hbq_entry *hbqe; 777f1c3b0fcSJames Smart struct lpfc_sli_ct_request *ct_req; 7784cc0e56eSJames Smart struct fc_bsg_job *job = NULL; 7794fede78fSJames Smart unsigned long flags; 7804cc0e56eSJames Smart int size = 0; 781f1c3b0fcSJames Smart 782f1c3b0fcSJames Smart INIT_LIST_HEAD(&head); 783f1c3b0fcSJames Smart list_add_tail(&head, &piocbq->list); 784f1c3b0fcSJames Smart 785f1c3b0fcSJames Smart if (piocbq->iocb.ulpBdeCount == 0 || 786f1c3b0fcSJames Smart piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) 787f1c3b0fcSJames Smart goto error_ct_unsol_exit; 788f1c3b0fcSJames Smart 7894cc0e56eSJames Smart if (phba->link_state == LPFC_HBA_ERROR || 7904cc0e56eSJames Smart (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) 7914cc0e56eSJames Smart goto error_ct_unsol_exit; 7924cc0e56eSJames Smart 793f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) 794f1c3b0fcSJames Smart dmabuf = bdeBuf1; 795f1c3b0fcSJames Smart else { 796f1c3b0fcSJames Smart dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, 797f1c3b0fcSJames Smart piocbq->iocb.un.cont64[0].addrLow); 798f1c3b0fcSJames Smart dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); 799f1c3b0fcSJames Smart } 8004cc0e56eSJames Smart if (dmabuf == NULL) 8014cc0e56eSJames Smart goto error_ct_unsol_exit; 802f1c3b0fcSJames Smart ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; 803f1c3b0fcSJames Smart evt_req_id = ct_req->FsType; 804f1c3b0fcSJames Smart cmd = ct_req->CommandResponse.bits.CmdRsp; 805f1c3b0fcSJames Smart len = ct_req->CommandResponse.bits.Size; 806f1c3b0fcSJames Smart if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) 807f1c3b0fcSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); 808f1c3b0fcSJames Smart 8094fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 810f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 8114cc0e56eSJames Smart if (!(evt->type_mask & FC_REG_CT_EVENT) || 8124cc0e56eSJames Smart evt->req_id != evt_req_id) 813f1c3b0fcSJames Smart continue; 814f1c3b0fcSJames Smart 8154cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 8164cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 817f1c3b0fcSJames Smart evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); 8184cc0e56eSJames Smart if (evt_dat == NULL) { 8194cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 8204cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 821f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 822f1c3b0fcSJames Smart "2614 Memory allocation failed for " 823f1c3b0fcSJames Smart "CT event\n"); 824f1c3b0fcSJames Smart break; 825f1c3b0fcSJames Smart } 826f1c3b0fcSJames Smart 827f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 828f1c3b0fcSJames Smart /* take accumulated byte count from the last iocbq */ 829f1c3b0fcSJames Smart iocbq = list_entry(head.prev, typeof(*iocbq), list); 830f1c3b0fcSJames Smart evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; 831f1c3b0fcSJames Smart } else { 832f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 833f1c3b0fcSJames Smart for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) 834f1c3b0fcSJames Smart evt_dat->len += 835f1c3b0fcSJames Smart iocbq->iocb.un.cont64[i].tus.f.bdeSize; 836f1c3b0fcSJames Smart } 837f1c3b0fcSJames Smart } 838f1c3b0fcSJames Smart 839f1c3b0fcSJames Smart evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); 8404cc0e56eSJames Smart if (evt_dat->data == NULL) { 841f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 842f1c3b0fcSJames Smart "2615 Memory allocation failed for " 843f1c3b0fcSJames Smart "CT event data, size %d\n", 844f1c3b0fcSJames Smart evt_dat->len); 845f1c3b0fcSJames Smart kfree(evt_dat); 8464fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 8474cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 8484fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 849f1c3b0fcSJames Smart goto error_ct_unsol_exit; 850f1c3b0fcSJames Smart } 851f1c3b0fcSJames Smart 852f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 8534cc0e56eSJames Smart size = 0; 854f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 855f1c3b0fcSJames Smart bdeBuf1 = iocbq->context2; 856f1c3b0fcSJames Smart bdeBuf2 = iocbq->context3; 857f1c3b0fcSJames Smart } 858f1c3b0fcSJames Smart for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { 859f1c3b0fcSJames Smart if (phba->sli3_options & 860f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED) { 861f1c3b0fcSJames Smart if (i == 0) { 862f1c3b0fcSJames Smart hbqe = (struct lpfc_hbq_entry *) 863f1c3b0fcSJames Smart &iocbq->iocb.un.ulpWord[0]; 864f1c3b0fcSJames Smart size = hbqe->bde.tus.f.bdeSize; 865f1c3b0fcSJames Smart dmabuf = bdeBuf1; 866f1c3b0fcSJames Smart } else if (i == 1) { 867f1c3b0fcSJames Smart hbqe = (struct lpfc_hbq_entry *) 868f1c3b0fcSJames Smart &iocbq->iocb.unsli3. 869f1c3b0fcSJames Smart sli3Words[4]; 870f1c3b0fcSJames Smart size = hbqe->bde.tus.f.bdeSize; 871f1c3b0fcSJames Smart dmabuf = bdeBuf2; 872f1c3b0fcSJames Smart } 873f1c3b0fcSJames Smart if ((offset + size) > evt_dat->len) 874f1c3b0fcSJames Smart size = evt_dat->len - offset; 875f1c3b0fcSJames Smart } else { 876f1c3b0fcSJames Smart size = iocbq->iocb.un.cont64[i]. 877f1c3b0fcSJames Smart tus.f.bdeSize; 878f1c3b0fcSJames Smart bde = &iocbq->iocb.un.cont64[i]; 879f1c3b0fcSJames Smart dma_addr = getPaddr(bde->addrHigh, 880f1c3b0fcSJames Smart bde->addrLow); 881f1c3b0fcSJames Smart dmabuf = lpfc_sli_ringpostbuf_get(phba, 882f1c3b0fcSJames Smart pring, dma_addr); 883f1c3b0fcSJames Smart } 884f1c3b0fcSJames Smart if (!dmabuf) { 885f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_ERR, 886f1c3b0fcSJames Smart LOG_LIBDFC, "2616 No dmabuf " 887f1c3b0fcSJames Smart "found for iocbq 0x%p\n", 888f1c3b0fcSJames Smart iocbq); 889f1c3b0fcSJames Smart kfree(evt_dat->data); 890f1c3b0fcSJames Smart kfree(evt_dat); 8914fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, 8924fede78fSJames Smart flags); 8934cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 8944fede78fSJames Smart spin_unlock_irqrestore( 8954fede78fSJames Smart &phba->ct_ev_lock, flags); 896f1c3b0fcSJames Smart goto error_ct_unsol_exit; 897f1c3b0fcSJames Smart } 898f1c3b0fcSJames Smart memcpy((char *)(evt_dat->data) + offset, 899f1c3b0fcSJames Smart dmabuf->virt, size); 900f1c3b0fcSJames Smart offset += size; 901f1c3b0fcSJames Smart if (evt_req_id != SLI_CT_ELX_LOOPBACK && 902f1c3b0fcSJames Smart !(phba->sli3_options & 903f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) { 904f1c3b0fcSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, 905f1c3b0fcSJames Smart dmabuf); 906f1c3b0fcSJames Smart } else { 907f1c3b0fcSJames Smart switch (cmd) { 9084cc0e56eSJames Smart case ELX_LOOPBACK_DATA: 9093b5dd52aSJames Smart diag_cmd_data_free(phba, 9104cc0e56eSJames Smart (struct lpfc_dmabufext *) 9114cc0e56eSJames Smart dmabuf); 9124cc0e56eSJames Smart break; 913f1c3b0fcSJames Smart case ELX_LOOPBACK_XRI_SETUP: 9144cc0e56eSJames Smart if ((phba->sli_rev == 9154cc0e56eSJames Smart LPFC_SLI_REV2) || 9164cc0e56eSJames Smart (phba->sli3_options & 9174cc0e56eSJames Smart LPFC_SLI3_HBQ_ENABLED 9184cc0e56eSJames Smart )) { 9194cc0e56eSJames Smart lpfc_in_buf_free(phba, 9204cc0e56eSJames Smart dmabuf); 9214cc0e56eSJames Smart } else { 922f1c3b0fcSJames Smart lpfc_post_buffer(phba, 923f1c3b0fcSJames Smart pring, 924f1c3b0fcSJames Smart 1); 9254cc0e56eSJames Smart } 926f1c3b0fcSJames Smart break; 927f1c3b0fcSJames Smart default: 928f1c3b0fcSJames Smart if (!(phba->sli3_options & 929f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) 930f1c3b0fcSJames Smart lpfc_post_buffer(phba, 931f1c3b0fcSJames Smart pring, 932f1c3b0fcSJames Smart 1); 933f1c3b0fcSJames Smart break; 934f1c3b0fcSJames Smart } 935f1c3b0fcSJames Smart } 936f1c3b0fcSJames Smart } 937f1c3b0fcSJames Smart } 938f1c3b0fcSJames Smart 9394fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 940f1c3b0fcSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 941f1c3b0fcSJames Smart evt_dat->immed_dat = phba->ctx_idx; 942f1c3b0fcSJames Smart phba->ctx_idx = (phba->ctx_idx + 1) % 64; 943589a52d6SJames Smart /* Provide warning for over-run of the ct_ctx array */ 944589a52d6SJames Smart if (phba->ct_ctx[evt_dat->immed_dat].flags & 945589a52d6SJames Smart UNSOL_VALID) 946589a52d6SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 947589a52d6SJames Smart "2717 CT context array entry " 948589a52d6SJames Smart "[%d] over-run: oxid:x%x, " 949589a52d6SJames Smart "sid:x%x\n", phba->ctx_idx, 950589a52d6SJames Smart phba->ct_ctx[ 951589a52d6SJames Smart evt_dat->immed_dat].oxid, 952589a52d6SJames Smart phba->ct_ctx[ 953589a52d6SJames Smart evt_dat->immed_dat].SID); 954f1c3b0fcSJames Smart phba->ct_ctx[evt_dat->immed_dat].oxid = 955f1c3b0fcSJames Smart piocbq->iocb.ulpContext; 956f1c3b0fcSJames Smart phba->ct_ctx[evt_dat->immed_dat].SID = 957f1c3b0fcSJames Smart piocbq->iocb.un.rcvels.remoteID; 958589a52d6SJames Smart phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID; 959f1c3b0fcSJames Smart } else 960f1c3b0fcSJames Smart evt_dat->immed_dat = piocbq->iocb.ulpContext; 961f1c3b0fcSJames Smart 962f1c3b0fcSJames Smart evt_dat->type = FC_REG_CT_EVENT; 963f1c3b0fcSJames Smart list_add(&evt_dat->node, &evt->events_to_see); 9644cc0e56eSJames Smart if (evt_req_id == SLI_CT_ELX_LOOPBACK) { 965f1c3b0fcSJames Smart wake_up_interruptible(&evt->wq); 9664cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 967f1c3b0fcSJames Smart break; 968f1c3b0fcSJames Smart } 9694cc0e56eSJames Smart 9704cc0e56eSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 9714cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 9724cc0e56eSJames Smart 9734cc0e56eSJames Smart job = evt->set_job; 9744cc0e56eSJames Smart evt->set_job = NULL; 9754cc0e56eSJames Smart if (job) { 9764cc0e56eSJames Smart job->reply->reply_payload_rcv_len = size; 9774cc0e56eSJames Smart /* make error code available to userspace */ 9784cc0e56eSJames Smart job->reply->result = 0; 9794cc0e56eSJames Smart job->dd_data = NULL; 9804cc0e56eSJames Smart /* complete the job back to userspace */ 9814cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 9824cc0e56eSJames Smart job->job_done(job); 9834cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 9844cc0e56eSJames Smart } 9854cc0e56eSJames Smart } 9864fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 987f1c3b0fcSJames Smart 988f1c3b0fcSJames Smart error_ct_unsol_exit: 989f1c3b0fcSJames Smart if (!list_empty(&head)) 990f1c3b0fcSJames Smart list_del(&head); 9914cc0e56eSJames Smart if (evt_req_id == SLI_CT_ELX_LOOPBACK) 9924cc0e56eSJames Smart return 0; 9934fede78fSJames Smart return 1; 994f1c3b0fcSJames Smart } 995f1c3b0fcSJames Smart 996f1c3b0fcSJames Smart /** 9974cc0e56eSJames Smart * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command 998f1c3b0fcSJames Smart * @job: SET_EVENT fc_bsg_job 9993b5dd52aSJames Smart **/ 1000f1c3b0fcSJames Smart static int 10014cc0e56eSJames Smart lpfc_bsg_hba_set_event(struct fc_bsg_job *job) 1002f1c3b0fcSJames Smart { 1003f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 1004f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 1005f1c3b0fcSJames Smart struct set_ct_event *event_req; 10064cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1007f1c3b0fcSJames Smart int rc = 0; 10084cc0e56eSJames Smart struct bsg_job_data *dd_data = NULL; 10094cc0e56eSJames Smart uint32_t ev_mask; 10104cc0e56eSJames Smart unsigned long flags; 1011f1c3b0fcSJames Smart 1012f1c3b0fcSJames Smart if (job->request_len < 1013f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { 1014f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1015f1c3b0fcSJames Smart "2612 Received SET_CT_EVENT below minimum " 1016f1c3b0fcSJames Smart "size\n"); 10174cc0e56eSJames Smart rc = -EINVAL; 10184cc0e56eSJames Smart goto job_error; 10194cc0e56eSJames Smart } 10204cc0e56eSJames Smart 10214cc0e56eSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 10224cc0e56eSJames Smart if (dd_data == NULL) { 10234cc0e56eSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 10244cc0e56eSJames Smart "2734 Failed allocation of dd_data\n"); 10254cc0e56eSJames Smart rc = -ENOMEM; 10264cc0e56eSJames Smart goto job_error; 1027f1c3b0fcSJames Smart } 1028f1c3b0fcSJames Smart 1029f1c3b0fcSJames Smart event_req = (struct set_ct_event *) 1030f1c3b0fcSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 10314cc0e56eSJames Smart ev_mask = ((uint32_t)(unsigned long)event_req->type_mask & 10324cc0e56eSJames Smart FC_REG_EVENT_MASK); 10334fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1034f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 1035f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 10364cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1037f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 1038f1c3b0fcSJames Smart break; 1039f1c3b0fcSJames Smart } 1040f1c3b0fcSJames Smart } 10414fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1042f1c3b0fcSJames Smart 1043f1c3b0fcSJames Smart if (&evt->node == &phba->ct_ev_waiters) { 1044f1c3b0fcSJames Smart /* no event waiting struct yet - first call */ 10454cc0e56eSJames Smart evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id, 1046f1c3b0fcSJames Smart event_req->ev_req_id); 1047f1c3b0fcSJames Smart if (!evt) { 1048f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1049f1c3b0fcSJames Smart "2617 Failed allocation of event " 1050f1c3b0fcSJames Smart "waiter\n"); 10514cc0e56eSJames Smart rc = -ENOMEM; 10524cc0e56eSJames Smart goto job_error; 1053f1c3b0fcSJames Smart } 1054f1c3b0fcSJames Smart 10554fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1056f1c3b0fcSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 10574cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1058f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 10594cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 10604cc0e56eSJames Smart } 1061f1c3b0fcSJames Smart 10624fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 10634cc0e56eSJames Smart evt->waiting = 1; 10644cc0e56eSJames Smart dd_data->type = TYPE_EVT; 10654cc0e56eSJames Smart dd_data->context_un.evt = evt; 10664cc0e56eSJames Smart evt->set_job = job; /* for unsolicited command */ 10674cc0e56eSJames Smart job->dd_data = dd_data; /* for fc transport timeout callback*/ 10684fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 10694cc0e56eSJames Smart return 0; /* call job done later */ 1070f1c3b0fcSJames Smart 10714cc0e56eSJames Smart job_error: 10724cc0e56eSJames Smart if (dd_data != NULL) 10734cc0e56eSJames Smart kfree(dd_data); 1074f1c3b0fcSJames Smart 10754cc0e56eSJames Smart job->dd_data = NULL; 10764cc0e56eSJames Smart return rc; 1077f1c3b0fcSJames Smart } 1078f1c3b0fcSJames Smart 1079f1c3b0fcSJames Smart /** 10804cc0e56eSJames Smart * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command 1081f1c3b0fcSJames Smart * @job: GET_EVENT fc_bsg_job 10823b5dd52aSJames Smart **/ 1083f1c3b0fcSJames Smart static int 10844cc0e56eSJames Smart lpfc_bsg_hba_get_event(struct fc_bsg_job *job) 1085f1c3b0fcSJames Smart { 1086f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 1087f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 1088f1c3b0fcSJames Smart struct get_ct_event *event_req; 1089f1c3b0fcSJames Smart struct get_ct_event_reply *event_reply; 10904cc0e56eSJames Smart struct lpfc_bsg_event *evt; 1091f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 10924fede78fSJames Smart unsigned long flags; 10934cc0e56eSJames Smart uint32_t rc = 0; 1094f1c3b0fcSJames Smart 1095f1c3b0fcSJames Smart if (job->request_len < 1096f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { 1097f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1098f1c3b0fcSJames Smart "2613 Received GET_CT_EVENT request below " 1099f1c3b0fcSJames Smart "minimum size\n"); 11004cc0e56eSJames Smart rc = -EINVAL; 11014cc0e56eSJames Smart goto job_error; 1102f1c3b0fcSJames Smart } 1103f1c3b0fcSJames Smart 1104f1c3b0fcSJames Smart event_req = (struct get_ct_event *) 1105f1c3b0fcSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 1106f1c3b0fcSJames Smart 1107f1c3b0fcSJames Smart event_reply = (struct get_ct_event_reply *) 1108f1c3b0fcSJames Smart job->reply->reply_data.vendor_reply.vendor_rsp; 11094fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1110f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 1111f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 1112f1c3b0fcSJames Smart if (list_empty(&evt->events_to_get)) 1113f1c3b0fcSJames Smart break; 11144cc0e56eSJames Smart lpfc_bsg_event_ref(evt); 1115f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 1116f1c3b0fcSJames Smart evt_dat = list_entry(evt->events_to_get.prev, 1117f1c3b0fcSJames Smart struct event_data, node); 1118f1c3b0fcSJames Smart list_del(&evt_dat->node); 1119f1c3b0fcSJames Smart break; 1120f1c3b0fcSJames Smart } 1121f1c3b0fcSJames Smart } 11224fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 1123f1c3b0fcSJames Smart 11244cc0e56eSJames Smart /* The app may continue to ask for event data until it gets 11254cc0e56eSJames Smart * an error indicating that there isn't anymore 11264cc0e56eSJames Smart */ 11274cc0e56eSJames Smart if (evt_dat == NULL) { 1128f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 1129f1c3b0fcSJames Smart rc = -ENOENT; 11304cc0e56eSJames Smart goto job_error; 1131f1c3b0fcSJames Smart } 1132f1c3b0fcSJames Smart 11334cc0e56eSJames Smart if (evt_dat->len > job->request_payload.payload_len) { 11344cc0e56eSJames Smart evt_dat->len = job->request_payload.payload_len; 1135f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 1136f1c3b0fcSJames Smart "2618 Truncated event data at %d " 1137f1c3b0fcSJames Smart "bytes\n", 11384cc0e56eSJames Smart job->request_payload.payload_len); 1139f1c3b0fcSJames Smart } 1140f1c3b0fcSJames Smart 11414cc0e56eSJames Smart event_reply->type = evt_dat->type; 1142f1c3b0fcSJames Smart event_reply->immed_data = evt_dat->immed_dat; 1143f1c3b0fcSJames Smart if (evt_dat->len > 0) 1144f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 11454cc0e56eSJames Smart sg_copy_from_buffer(job->request_payload.sg_list, 11464cc0e56eSJames Smart job->request_payload.sg_cnt, 1147f1c3b0fcSJames Smart evt_dat->data, evt_dat->len); 1148f1c3b0fcSJames Smart else 1149f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 1150f1c3b0fcSJames Smart 11514cc0e56eSJames Smart if (evt_dat) { 1152f1c3b0fcSJames Smart kfree(evt_dat->data); 1153f1c3b0fcSJames Smart kfree(evt_dat); 11544cc0e56eSJames Smart } 11554cc0e56eSJames Smart 11564fede78fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 11574cc0e56eSJames Smart lpfc_bsg_event_unref(evt); 11584fede78fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 11594cc0e56eSJames Smart job->dd_data = NULL; 11604cc0e56eSJames Smart job->reply->result = 0; 1161f1c3b0fcSJames Smart job->job_done(job); 11624cc0e56eSJames Smart return 0; 1163f1c3b0fcSJames Smart 11644cc0e56eSJames Smart job_error: 11654cc0e56eSJames Smart job->dd_data = NULL; 11664cc0e56eSJames Smart job->reply->result = rc; 1167f1c3b0fcSJames Smart return rc; 1168f1c3b0fcSJames Smart } 1169f1c3b0fcSJames Smart 1170f1c3b0fcSJames Smart /** 11713b5dd52aSJames Smart * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler 11723b5dd52aSJames Smart * @phba: Pointer to HBA context object. 11733b5dd52aSJames Smart * @cmdiocbq: Pointer to command iocb. 11743b5dd52aSJames Smart * @rspiocbq: Pointer to response iocb. 11753b5dd52aSJames Smart * 11763b5dd52aSJames Smart * This function is the completion handler for iocbs issued using 11773b5dd52aSJames Smart * lpfc_issue_ct_rsp_cmp function. This function is called by the 11783b5dd52aSJames Smart * ring event handler function without any lock held. This function 11793b5dd52aSJames Smart * can be called from both worker thread context and interrupt 11803b5dd52aSJames Smart * context. This function also can be called from other thread which 11813b5dd52aSJames Smart * cleans up the SLI layer objects. 11823b5dd52aSJames Smart * This function copy the contents of the response iocb to the 11833b5dd52aSJames Smart * response iocb memory object provided by the caller of 11843b5dd52aSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 11853b5dd52aSJames Smart * sleeps for the iocb completion. 11863b5dd52aSJames Smart **/ 11873b5dd52aSJames Smart static void 11883b5dd52aSJames Smart lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, 11893b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, 11903b5dd52aSJames Smart struct lpfc_iocbq *rspiocbq) 11913b5dd52aSJames Smart { 11923b5dd52aSJames Smart struct bsg_job_data *dd_data; 11933b5dd52aSJames Smart struct fc_bsg_job *job; 11943b5dd52aSJames Smart IOCB_t *rsp; 11953b5dd52aSJames Smart struct lpfc_dmabuf *bmp; 11963b5dd52aSJames Smart struct lpfc_nodelist *ndlp; 11973b5dd52aSJames Smart unsigned long flags; 11983b5dd52aSJames Smart int rc = 0; 11993b5dd52aSJames Smart 12003b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 1201be858b65SJames Smart dd_data = cmdiocbq->context2; 12023b5dd52aSJames Smart /* normal completion and timeout crossed paths, already done */ 12033b5dd52aSJames Smart if (!dd_data) { 120467221a42SJiri Slaby spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 12053b5dd52aSJames Smart return; 12063b5dd52aSJames Smart } 12073b5dd52aSJames Smart 12083b5dd52aSJames Smart job = dd_data->context_un.iocb.set_job; 12093b5dd52aSJames Smart bmp = dd_data->context_un.iocb.bmp; 12103b5dd52aSJames Smart rsp = &rspiocbq->iocb; 12113b5dd52aSJames Smart ndlp = dd_data->context_un.iocb.ndlp; 12123b5dd52aSJames Smart 12133b5dd52aSJames Smart pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, 12143b5dd52aSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 12153b5dd52aSJames Smart 12163b5dd52aSJames Smart if (rsp->ulpStatus) { 12173b5dd52aSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 12183b5dd52aSJames Smart switch (rsp->un.ulpWord[4] & 0xff) { 12193b5dd52aSJames Smart case IOERR_SEQUENCE_TIMEOUT: 12203b5dd52aSJames Smart rc = -ETIMEDOUT; 12213b5dd52aSJames Smart break; 12223b5dd52aSJames Smart case IOERR_INVALID_RPI: 12233b5dd52aSJames Smart rc = -EFAULT; 12243b5dd52aSJames Smart break; 12253b5dd52aSJames Smart default: 12263b5dd52aSJames Smart rc = -EACCES; 12273b5dd52aSJames Smart break; 12283b5dd52aSJames Smart } 12293b5dd52aSJames Smart } else 12303b5dd52aSJames Smart rc = -EACCES; 12313b5dd52aSJames Smart } else 12323b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 12333b5dd52aSJames Smart rsp->un.genreq64.bdl.bdeSize; 12343b5dd52aSJames Smart 12353b5dd52aSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 12363b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 12373b5dd52aSJames Smart lpfc_nlp_put(ndlp); 12383b5dd52aSJames Smart kfree(bmp); 12393b5dd52aSJames Smart kfree(dd_data); 12403b5dd52aSJames Smart /* make error code available to userspace */ 12413b5dd52aSJames Smart job->reply->result = rc; 12423b5dd52aSJames Smart job->dd_data = NULL; 12433b5dd52aSJames Smart /* complete the job back to userspace */ 12443b5dd52aSJames Smart job->job_done(job); 12453b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 12463b5dd52aSJames Smart return; 12473b5dd52aSJames Smart } 12483b5dd52aSJames Smart 12493b5dd52aSJames Smart /** 12503b5dd52aSJames Smart * lpfc_issue_ct_rsp - issue a ct response 12513b5dd52aSJames Smart * @phba: Pointer to HBA context object. 12523b5dd52aSJames Smart * @job: Pointer to the job object. 12533b5dd52aSJames Smart * @tag: tag index value into the ports context exchange array. 12543b5dd52aSJames Smart * @bmp: Pointer to a dma buffer descriptor. 12553b5dd52aSJames Smart * @num_entry: Number of enties in the bde. 12563b5dd52aSJames Smart **/ 12573b5dd52aSJames Smart static int 12583b5dd52aSJames Smart lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag, 12593b5dd52aSJames Smart struct lpfc_dmabuf *bmp, int num_entry) 12603b5dd52aSJames Smart { 12613b5dd52aSJames Smart IOCB_t *icmd; 12623b5dd52aSJames Smart struct lpfc_iocbq *ctiocb = NULL; 12633b5dd52aSJames Smart int rc = 0; 12643b5dd52aSJames Smart struct lpfc_nodelist *ndlp = NULL; 12653b5dd52aSJames Smart struct bsg_job_data *dd_data; 12663b5dd52aSJames Smart uint32_t creg_val; 12673b5dd52aSJames Smart 12683b5dd52aSJames Smart /* allocate our bsg tracking structure */ 12693b5dd52aSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 12703b5dd52aSJames Smart if (!dd_data) { 12713b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 12723b5dd52aSJames Smart "2736 Failed allocation of dd_data\n"); 12733b5dd52aSJames Smart rc = -ENOMEM; 12743b5dd52aSJames Smart goto no_dd_data; 12753b5dd52aSJames Smart } 12763b5dd52aSJames Smart 12773b5dd52aSJames Smart /* Allocate buffer for command iocb */ 12783b5dd52aSJames Smart ctiocb = lpfc_sli_get_iocbq(phba); 12793b5dd52aSJames Smart if (!ctiocb) { 1280d439d286SJames Smart rc = -ENOMEM; 12813b5dd52aSJames Smart goto no_ctiocb; 12823b5dd52aSJames Smart } 12833b5dd52aSJames Smart 12843b5dd52aSJames Smart icmd = &ctiocb->iocb; 12853b5dd52aSJames Smart icmd->un.xseq64.bdl.ulpIoTag32 = 0; 12863b5dd52aSJames Smart icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 12873b5dd52aSJames Smart icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); 12883b5dd52aSJames Smart icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 12893b5dd52aSJames Smart icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); 12903b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); 12913b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Dfctl = 0; 12923b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; 12933b5dd52aSJames Smart icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 12943b5dd52aSJames Smart 12953b5dd52aSJames Smart /* Fill in rest of iocb */ 12963b5dd52aSJames Smart icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; 12973b5dd52aSJames Smart icmd->ulpBdeCount = 1; 12983b5dd52aSJames Smart icmd->ulpLe = 1; 12993b5dd52aSJames Smart icmd->ulpClass = CLASS3; 13003b5dd52aSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 13013b5dd52aSJames Smart /* Do not issue unsol response if oxid not marked as valid */ 13023b5dd52aSJames Smart if (!(phba->ct_ctx[tag].flags & UNSOL_VALID)) { 13033b5dd52aSJames Smart rc = IOCB_ERROR; 13043b5dd52aSJames Smart goto issue_ct_rsp_exit; 13053b5dd52aSJames Smart } 13063b5dd52aSJames Smart icmd->ulpContext = phba->ct_ctx[tag].oxid; 13073b5dd52aSJames Smart ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); 13083b5dd52aSJames Smart if (!ndlp) { 13093b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, 13103b5dd52aSJames Smart "2721 ndlp null for oxid %x SID %x\n", 13113b5dd52aSJames Smart icmd->ulpContext, 13123b5dd52aSJames Smart phba->ct_ctx[tag].SID); 13133b5dd52aSJames Smart rc = IOCB_ERROR; 13143b5dd52aSJames Smart goto issue_ct_rsp_exit; 13153b5dd52aSJames Smart } 1316589a52d6SJames Smart 1317589a52d6SJames Smart /* Check if the ndlp is active */ 1318589a52d6SJames Smart if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { 1319589a52d6SJames Smart rc = -IOCB_ERROR; 1320589a52d6SJames Smart goto issue_ct_rsp_exit; 1321589a52d6SJames Smart } 1322589a52d6SJames Smart 1323589a52d6SJames Smart /* get a refernece count so the ndlp doesn't go away while 1324589a52d6SJames Smart * we respond 1325589a52d6SJames Smart */ 1326589a52d6SJames Smart if (!lpfc_nlp_get(ndlp)) { 1327589a52d6SJames Smart rc = -IOCB_ERROR; 1328589a52d6SJames Smart goto issue_ct_rsp_exit; 1329589a52d6SJames Smart } 1330589a52d6SJames Smart 13313b5dd52aSJames Smart icmd->un.ulpWord[3] = ndlp->nlp_rpi; 13323b5dd52aSJames Smart /* The exchange is done, mark the entry as invalid */ 13333b5dd52aSJames Smart phba->ct_ctx[tag].flags &= ~UNSOL_VALID; 13343b5dd52aSJames Smart } else 13353b5dd52aSJames Smart icmd->ulpContext = (ushort) tag; 13363b5dd52aSJames Smart 13373b5dd52aSJames Smart icmd->ulpTimeout = phba->fc_ratov * 2; 13383b5dd52aSJames Smart 13393b5dd52aSJames Smart /* Xmit CT response on exchange <xid> */ 13403b5dd52aSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_ELS, 13413b5dd52aSJames Smart "2722 Xmit CT response on exchange x%x Data: x%x x%x\n", 13423b5dd52aSJames Smart icmd->ulpContext, icmd->ulpIoTag, phba->link_state); 13433b5dd52aSJames Smart 13443b5dd52aSJames Smart ctiocb->iocb_cmpl = NULL; 13453b5dd52aSJames Smart ctiocb->iocb_flag |= LPFC_IO_LIBDFC; 13463b5dd52aSJames Smart ctiocb->vport = phba->pport; 13473b5dd52aSJames Smart ctiocb->context3 = bmp; 13483b5dd52aSJames Smart 13493b5dd52aSJames Smart ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp; 1350be858b65SJames Smart ctiocb->context2 = dd_data; 1351be858b65SJames Smart ctiocb->context1 = ndlp; 13523b5dd52aSJames Smart dd_data->type = TYPE_IOCB; 13533b5dd52aSJames Smart dd_data->context_un.iocb.cmdiocbq = ctiocb; 13543b5dd52aSJames Smart dd_data->context_un.iocb.rspiocbq = NULL; 13553b5dd52aSJames Smart dd_data->context_un.iocb.set_job = job; 13563b5dd52aSJames Smart dd_data->context_un.iocb.bmp = bmp; 13573b5dd52aSJames Smart dd_data->context_un.iocb.ndlp = ndlp; 13583b5dd52aSJames Smart 13593b5dd52aSJames Smart if (phba->cfg_poll & DISABLE_FCP_RING_INT) { 13603b5dd52aSJames Smart creg_val = readl(phba->HCregaddr); 13613b5dd52aSJames Smart creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); 13623b5dd52aSJames Smart writel(creg_val, phba->HCregaddr); 13633b5dd52aSJames Smart readl(phba->HCregaddr); /* flush */ 13643b5dd52aSJames Smart } 13653b5dd52aSJames Smart 13663b5dd52aSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); 13673b5dd52aSJames Smart 13683b5dd52aSJames Smart if (rc == IOCB_SUCCESS) 13693b5dd52aSJames Smart return 0; /* done for now */ 13703b5dd52aSJames Smart 13713b5dd52aSJames Smart issue_ct_rsp_exit: 13723b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, ctiocb); 13733b5dd52aSJames Smart no_ctiocb: 13743b5dd52aSJames Smart kfree(dd_data); 13753b5dd52aSJames Smart no_dd_data: 13763b5dd52aSJames Smart return rc; 13773b5dd52aSJames Smart } 13783b5dd52aSJames Smart 13793b5dd52aSJames Smart /** 13803b5dd52aSJames Smart * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command 13813b5dd52aSJames Smart * @job: SEND_MGMT_RESP fc_bsg_job 13823b5dd52aSJames Smart **/ 13833b5dd52aSJames Smart static int 13843b5dd52aSJames Smart lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job) 13853b5dd52aSJames Smart { 13863b5dd52aSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 13873b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 13883b5dd52aSJames Smart struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *) 13893b5dd52aSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 13903b5dd52aSJames Smart struct ulp_bde64 *bpl; 13913b5dd52aSJames Smart struct lpfc_dmabuf *bmp = NULL; 13923b5dd52aSJames Smart struct scatterlist *sgel = NULL; 13933b5dd52aSJames Smart int request_nseg; 13943b5dd52aSJames Smart int numbde; 13953b5dd52aSJames Smart dma_addr_t busaddr; 13963b5dd52aSJames Smart uint32_t tag = mgmt_resp->tag; 13973b5dd52aSJames Smart unsigned long reqbfrcnt = 13983b5dd52aSJames Smart (unsigned long)job->request_payload.payload_len; 13993b5dd52aSJames Smart int rc = 0; 14003b5dd52aSJames Smart 14013b5dd52aSJames Smart /* in case no data is transferred */ 14023b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 0; 14033b5dd52aSJames Smart 14043b5dd52aSJames Smart if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) { 14053b5dd52aSJames Smart rc = -ERANGE; 14063b5dd52aSJames Smart goto send_mgmt_rsp_exit; 14073b5dd52aSJames Smart } 14083b5dd52aSJames Smart 14093b5dd52aSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 14103b5dd52aSJames Smart if (!bmp) { 14113b5dd52aSJames Smart rc = -ENOMEM; 14123b5dd52aSJames Smart goto send_mgmt_rsp_exit; 14133b5dd52aSJames Smart } 14143b5dd52aSJames Smart 14153b5dd52aSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 14163b5dd52aSJames Smart if (!bmp->virt) { 14173b5dd52aSJames Smart rc = -ENOMEM; 14183b5dd52aSJames Smart goto send_mgmt_rsp_free_bmp; 14193b5dd52aSJames Smart } 14203b5dd52aSJames Smart 14213b5dd52aSJames Smart INIT_LIST_HEAD(&bmp->list); 14223b5dd52aSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 14233b5dd52aSJames Smart request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, 14243b5dd52aSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 14253b5dd52aSJames Smart for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { 14263b5dd52aSJames Smart busaddr = sg_dma_address(sgel); 14273b5dd52aSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; 14283b5dd52aSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 14293b5dd52aSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 14303b5dd52aSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 14313b5dd52aSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 14323b5dd52aSJames Smart bpl++; 14333b5dd52aSJames Smart } 14343b5dd52aSJames Smart 14353b5dd52aSJames Smart rc = lpfc_issue_ct_rsp(phba, job, tag, bmp, request_nseg); 14363b5dd52aSJames Smart 14373b5dd52aSJames Smart if (rc == IOCB_SUCCESS) 14383b5dd52aSJames Smart return 0; /* done for now */ 14393b5dd52aSJames Smart 14403b5dd52aSJames Smart /* TBD need to handle a timeout */ 14413b5dd52aSJames Smart pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, 14423b5dd52aSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 14433b5dd52aSJames Smart rc = -EACCES; 14443b5dd52aSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 14453b5dd52aSJames Smart 14463b5dd52aSJames Smart send_mgmt_rsp_free_bmp: 14473b5dd52aSJames Smart kfree(bmp); 14483b5dd52aSJames Smart send_mgmt_rsp_exit: 14493b5dd52aSJames Smart /* make error code available to userspace */ 14503b5dd52aSJames Smart job->reply->result = rc; 14513b5dd52aSJames Smart job->dd_data = NULL; 14523b5dd52aSJames Smart return rc; 14533b5dd52aSJames Smart } 14543b5dd52aSJames Smart 14553b5dd52aSJames Smart /** 14563b5dd52aSJames Smart * lpfc_bsg_diag_mode - process a LPFC_BSG_VENDOR_DIAG_MODE bsg vendor command 14573b5dd52aSJames Smart * @job: LPFC_BSG_VENDOR_DIAG_MODE 14583b5dd52aSJames Smart * 14593b5dd52aSJames Smart * This function is responsible for placing a port into diagnostic loopback 14603b5dd52aSJames Smart * mode in order to perform a diagnostic loopback test. 14613b5dd52aSJames Smart * All new scsi requests are blocked, a small delay is used to allow the 14623b5dd52aSJames Smart * scsi requests to complete then the link is brought down. If the link is 14633b5dd52aSJames Smart * is placed in loopback mode then scsi requests are again allowed 14643b5dd52aSJames Smart * so the scsi mid-layer doesn't give up on the port. 14653b5dd52aSJames Smart * All of this is done in-line. 14663b5dd52aSJames Smart */ 14673b5dd52aSJames Smart static int 14683b5dd52aSJames Smart lpfc_bsg_diag_mode(struct fc_bsg_job *job) 14693b5dd52aSJames Smart { 14703b5dd52aSJames Smart struct Scsi_Host *shost = job->shost; 14713b5dd52aSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 14723b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 14733b5dd52aSJames Smart struct diag_mode_set *loopback_mode; 14743b5dd52aSJames Smart struct lpfc_sli *psli = &phba->sli; 14753b5dd52aSJames Smart struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING]; 14763b5dd52aSJames Smart uint32_t link_flags; 14773b5dd52aSJames Smart uint32_t timeout; 14783b5dd52aSJames Smart struct lpfc_vport **vports; 14793b5dd52aSJames Smart LPFC_MBOXQ_t *pmboxq; 14803b5dd52aSJames Smart int mbxstatus; 14813b5dd52aSJames Smart int i = 0; 14823b5dd52aSJames Smart int rc = 0; 14833b5dd52aSJames Smart 14843b5dd52aSJames Smart /* no data to return just the return code */ 14853b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 0; 14863b5dd52aSJames Smart 14873b5dd52aSJames Smart if (job->request_len < 14883b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_set)) { 14893b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 14903b5dd52aSJames Smart "2738 Received DIAG MODE request below minimum " 14913b5dd52aSJames Smart "size\n"); 14923b5dd52aSJames Smart rc = -EINVAL; 14933b5dd52aSJames Smart goto job_error; 14943b5dd52aSJames Smart } 14953b5dd52aSJames Smart 14963b5dd52aSJames Smart loopback_mode = (struct diag_mode_set *) 14973b5dd52aSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 14983b5dd52aSJames Smart link_flags = loopback_mode->type; 1499515e0aa2SJames Smart timeout = loopback_mode->timeout * 100; 15003b5dd52aSJames Smart 15013b5dd52aSJames Smart if ((phba->link_state == LPFC_HBA_ERROR) || 15023b5dd52aSJames Smart (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || 15033b5dd52aSJames Smart (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { 15043b5dd52aSJames Smart rc = -EACCES; 15053b5dd52aSJames Smart goto job_error; 15063b5dd52aSJames Smart } 15073b5dd52aSJames Smart 15083b5dd52aSJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 15093b5dd52aSJames Smart if (!pmboxq) { 15103b5dd52aSJames Smart rc = -ENOMEM; 15113b5dd52aSJames Smart goto job_error; 15123b5dd52aSJames Smart } 15133b5dd52aSJames Smart 15143b5dd52aSJames Smart vports = lpfc_create_vport_work_array(phba); 15153b5dd52aSJames Smart if (vports) { 15163b5dd52aSJames Smart for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { 15173b5dd52aSJames Smart shost = lpfc_shost_from_vport(vports[i]); 15183b5dd52aSJames Smart scsi_block_requests(shost); 15193b5dd52aSJames Smart } 15203b5dd52aSJames Smart 15213b5dd52aSJames Smart lpfc_destroy_vport_work_array(phba, vports); 15223b5dd52aSJames Smart } else { 15233b5dd52aSJames Smart shost = lpfc_shost_from_vport(phba->pport); 15243b5dd52aSJames Smart scsi_block_requests(shost); 15253b5dd52aSJames Smart } 15263b5dd52aSJames Smart 15273b5dd52aSJames Smart while (pring->txcmplq_cnt) { 15283b5dd52aSJames Smart if (i++ > 500) /* wait up to 5 seconds */ 15293b5dd52aSJames Smart break; 15303b5dd52aSJames Smart 15313b5dd52aSJames Smart msleep(10); 15323b5dd52aSJames Smart } 15333b5dd52aSJames Smart 15343b5dd52aSJames Smart memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 15353b5dd52aSJames Smart pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; 15363b5dd52aSJames Smart pmboxq->u.mb.mbxOwner = OWN_HOST; 15373b5dd52aSJames Smart 15383b5dd52aSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); 15393b5dd52aSJames Smart 15403b5dd52aSJames Smart if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) { 15413b5dd52aSJames Smart /* wait for link down before proceeding */ 15423b5dd52aSJames Smart i = 0; 15433b5dd52aSJames Smart while (phba->link_state != LPFC_LINK_DOWN) { 15443b5dd52aSJames Smart if (i++ > timeout) { 15453b5dd52aSJames Smart rc = -ETIMEDOUT; 15463b5dd52aSJames Smart goto loopback_mode_exit; 15473b5dd52aSJames Smart } 15483b5dd52aSJames Smart 15493b5dd52aSJames Smart msleep(10); 15503b5dd52aSJames Smart } 15513b5dd52aSJames Smart 15523b5dd52aSJames Smart memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 15533b5dd52aSJames Smart if (link_flags == INTERNAL_LOOP_BACK) 15543b5dd52aSJames Smart pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB; 15553b5dd52aSJames Smart else 15563b5dd52aSJames Smart pmboxq->u.mb.un.varInitLnk.link_flags = 15573b5dd52aSJames Smart FLAGS_TOPOLOGY_MODE_LOOP; 15583b5dd52aSJames Smart 15593b5dd52aSJames Smart pmboxq->u.mb.mbxCommand = MBX_INIT_LINK; 15603b5dd52aSJames Smart pmboxq->u.mb.mbxOwner = OWN_HOST; 15613b5dd52aSJames Smart 15623b5dd52aSJames Smart mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, 15633b5dd52aSJames Smart LPFC_MBOX_TMO); 15643b5dd52aSJames Smart 15653b5dd52aSJames Smart if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) 15663b5dd52aSJames Smart rc = -ENODEV; 15673b5dd52aSJames Smart else { 15683b5dd52aSJames Smart phba->link_flag |= LS_LOOPBACK_MODE; 15693b5dd52aSJames Smart /* wait for the link attention interrupt */ 15703b5dd52aSJames Smart msleep(100); 15713b5dd52aSJames Smart 15723b5dd52aSJames Smart i = 0; 15733b5dd52aSJames Smart while (phba->link_state != LPFC_HBA_READY) { 15743b5dd52aSJames Smart if (i++ > timeout) { 15753b5dd52aSJames Smart rc = -ETIMEDOUT; 15763b5dd52aSJames Smart break; 15773b5dd52aSJames Smart } 15783b5dd52aSJames Smart 15793b5dd52aSJames Smart msleep(10); 15803b5dd52aSJames Smart } 15813b5dd52aSJames Smart } 15823b5dd52aSJames Smart 15833b5dd52aSJames Smart } else 15843b5dd52aSJames Smart rc = -ENODEV; 15853b5dd52aSJames Smart 15863b5dd52aSJames Smart loopback_mode_exit: 15873b5dd52aSJames Smart vports = lpfc_create_vport_work_array(phba); 15883b5dd52aSJames Smart if (vports) { 15893b5dd52aSJames Smart for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { 15903b5dd52aSJames Smart shost = lpfc_shost_from_vport(vports[i]); 15913b5dd52aSJames Smart scsi_unblock_requests(shost); 15923b5dd52aSJames Smart } 15933b5dd52aSJames Smart lpfc_destroy_vport_work_array(phba, vports); 15943b5dd52aSJames Smart } else { 15953b5dd52aSJames Smart shost = lpfc_shost_from_vport(phba->pport); 15963b5dd52aSJames Smart scsi_unblock_requests(shost); 15973b5dd52aSJames Smart } 15983b5dd52aSJames Smart 15993b5dd52aSJames Smart /* 16003b5dd52aSJames Smart * Let SLI layer release mboxq if mbox command completed after timeout. 16013b5dd52aSJames Smart */ 16023b5dd52aSJames Smart if (mbxstatus != MBX_TIMEOUT) 16033b5dd52aSJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 16043b5dd52aSJames Smart 16053b5dd52aSJames Smart job_error: 16063b5dd52aSJames Smart /* make error code available to userspace */ 16073b5dd52aSJames Smart job->reply->result = rc; 16083b5dd52aSJames Smart /* complete the job back to userspace if no error */ 16093b5dd52aSJames Smart if (rc == 0) 16103b5dd52aSJames Smart job->job_done(job); 16113b5dd52aSJames Smart return rc; 16123b5dd52aSJames Smart } 16133b5dd52aSJames Smart 16143b5dd52aSJames Smart /** 16153b5dd52aSJames Smart * lpfcdiag_loop_self_reg - obtains a remote port login id 16163b5dd52aSJames Smart * @phba: Pointer to HBA context object 16173b5dd52aSJames Smart * @rpi: Pointer to a remote port login id 16183b5dd52aSJames Smart * 16193b5dd52aSJames Smart * This function obtains a remote port login id so the diag loopback test 16203b5dd52aSJames Smart * can send and receive its own unsolicited CT command. 16213b5dd52aSJames Smart **/ 16223b5dd52aSJames Smart static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi) 16233b5dd52aSJames Smart { 16243b5dd52aSJames Smart LPFC_MBOXQ_t *mbox; 16253b5dd52aSJames Smart struct lpfc_dmabuf *dmabuff; 16263b5dd52aSJames Smart int status; 16273b5dd52aSJames Smart 16283b5dd52aSJames Smart mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 16293b5dd52aSJames Smart if (!mbox) 1630d439d286SJames Smart return -ENOMEM; 16313b5dd52aSJames Smart 16324042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 16334042629eSJames Smart *rpi = lpfc_sli4_alloc_rpi(phba); 16343b5dd52aSJames Smart status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, 16354042629eSJames Smart (uint8_t *)&phba->pport->fc_sparam, mbox, *rpi); 16363b5dd52aSJames Smart if (status) { 16373b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 16384042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 16394042629eSJames Smart lpfc_sli4_free_rpi(phba, *rpi); 1640d439d286SJames Smart return -ENOMEM; 16413b5dd52aSJames Smart } 16423b5dd52aSJames Smart 16433b5dd52aSJames Smart dmabuff = (struct lpfc_dmabuf *) mbox->context1; 16443b5dd52aSJames Smart mbox->context1 = NULL; 1645d439d286SJames Smart mbox->context2 = NULL; 16463b5dd52aSJames Smart status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 16473b5dd52aSJames Smart 16483b5dd52aSJames Smart if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { 16493b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); 16503b5dd52aSJames Smart kfree(dmabuff); 16513b5dd52aSJames Smart if (status != MBX_TIMEOUT) 16523b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 16534042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 16544042629eSJames Smart lpfc_sli4_free_rpi(phba, *rpi); 1655d439d286SJames Smart return -ENODEV; 16563b5dd52aSJames Smart } 16573b5dd52aSJames Smart 16583b5dd52aSJames Smart *rpi = mbox->u.mb.un.varWords[0]; 16593b5dd52aSJames Smart 16603b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); 16613b5dd52aSJames Smart kfree(dmabuff); 16623b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 16633b5dd52aSJames Smart return 0; 16643b5dd52aSJames Smart } 16653b5dd52aSJames Smart 16663b5dd52aSJames Smart /** 16673b5dd52aSJames Smart * lpfcdiag_loop_self_unreg - unregs from the rpi 16683b5dd52aSJames Smart * @phba: Pointer to HBA context object 16693b5dd52aSJames Smart * @rpi: Remote port login id 16703b5dd52aSJames Smart * 16713b5dd52aSJames Smart * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg 16723b5dd52aSJames Smart **/ 16733b5dd52aSJames Smart static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) 16743b5dd52aSJames Smart { 16753b5dd52aSJames Smart LPFC_MBOXQ_t *mbox; 16763b5dd52aSJames Smart int status; 16773b5dd52aSJames Smart 16783b5dd52aSJames Smart /* Allocate mboxq structure */ 16793b5dd52aSJames Smart mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 16803b5dd52aSJames Smart if (mbox == NULL) 1681d439d286SJames Smart return -ENOMEM; 16823b5dd52aSJames Smart 16833b5dd52aSJames Smart lpfc_unreg_login(phba, 0, rpi, mbox); 16843b5dd52aSJames Smart status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); 16853b5dd52aSJames Smart 16863b5dd52aSJames Smart if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { 16873b5dd52aSJames Smart if (status != MBX_TIMEOUT) 16883b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 1689d439d286SJames Smart return -EIO; 16903b5dd52aSJames Smart } 16913b5dd52aSJames Smart mempool_free(mbox, phba->mbox_mem_pool); 16924042629eSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) 16934042629eSJames Smart lpfc_sli4_free_rpi(phba, rpi); 16943b5dd52aSJames Smart return 0; 16953b5dd52aSJames Smart } 16963b5dd52aSJames Smart 16973b5dd52aSJames Smart /** 16983b5dd52aSJames Smart * lpfcdiag_loop_get_xri - obtains the transmit and receive ids 16993b5dd52aSJames Smart * @phba: Pointer to HBA context object 17003b5dd52aSJames Smart * @rpi: Remote port login id 17013b5dd52aSJames Smart * @txxri: Pointer to transmit exchange id 17023b5dd52aSJames Smart * @rxxri: Pointer to response exchabge id 17033b5dd52aSJames Smart * 17043b5dd52aSJames Smart * This function obtains the transmit and receive ids required to send 17053b5dd52aSJames Smart * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp 17063b5dd52aSJames Smart * flags are used to the unsolicted response handler is able to process 17073b5dd52aSJames Smart * the ct command sent on the same port. 17083b5dd52aSJames Smart **/ 17093b5dd52aSJames Smart static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, 17103b5dd52aSJames Smart uint16_t *txxri, uint16_t * rxxri) 17113b5dd52aSJames Smart { 17123b5dd52aSJames Smart struct lpfc_bsg_event *evt; 17133b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq; 17143b5dd52aSJames Smart IOCB_t *cmd, *rsp; 17153b5dd52aSJames Smart struct lpfc_dmabuf *dmabuf; 17163b5dd52aSJames Smart struct ulp_bde64 *bpl = NULL; 17173b5dd52aSJames Smart struct lpfc_sli_ct_request *ctreq = NULL; 17183b5dd52aSJames Smart int ret_val = 0; 1719d439d286SJames Smart int time_left; 1720515e0aa2SJames Smart int iocb_stat = 0; 17213b5dd52aSJames Smart unsigned long flags; 17223b5dd52aSJames Smart 17233b5dd52aSJames Smart *txxri = 0; 17243b5dd52aSJames Smart *rxxri = 0; 17253b5dd52aSJames Smart evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, 17263b5dd52aSJames Smart SLI_CT_ELX_LOOPBACK); 17273b5dd52aSJames Smart if (!evt) 1728d439d286SJames Smart return -ENOMEM; 17293b5dd52aSJames Smart 17303b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 17313b5dd52aSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 17323b5dd52aSJames Smart lpfc_bsg_event_ref(evt); 17333b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 17343b5dd52aSJames Smart 17353b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 17363b5dd52aSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 17373b5dd52aSJames Smart 17383b5dd52aSJames Smart dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 17393b5dd52aSJames Smart if (dmabuf) { 17403b5dd52aSJames Smart dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); 1741c7495937SJames Smart if (dmabuf->virt) { 17423b5dd52aSJames Smart INIT_LIST_HEAD(&dmabuf->list); 17433b5dd52aSJames Smart bpl = (struct ulp_bde64 *) dmabuf->virt; 17443b5dd52aSJames Smart memset(bpl, 0, sizeof(*bpl)); 17453b5dd52aSJames Smart ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); 17463b5dd52aSJames Smart bpl->addrHigh = 1747c7495937SJames Smart le32_to_cpu(putPaddrHigh(dmabuf->phys + 1748c7495937SJames Smart sizeof(*bpl))); 17493b5dd52aSJames Smart bpl->addrLow = 1750c7495937SJames Smart le32_to_cpu(putPaddrLow(dmabuf->phys + 1751c7495937SJames Smart sizeof(*bpl))); 17523b5dd52aSJames Smart bpl->tus.f.bdeFlags = 0; 17533b5dd52aSJames Smart bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; 17543b5dd52aSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 17553b5dd52aSJames Smart } 1756c7495937SJames Smart } 17573b5dd52aSJames Smart 17583b5dd52aSJames Smart if (cmdiocbq == NULL || rspiocbq == NULL || 1759c7495937SJames Smart dmabuf == NULL || bpl == NULL || ctreq == NULL || 1760c7495937SJames Smart dmabuf->virt == NULL) { 1761d439d286SJames Smart ret_val = -ENOMEM; 17623b5dd52aSJames Smart goto err_get_xri_exit; 17633b5dd52aSJames Smart } 17643b5dd52aSJames Smart 17653b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 17663b5dd52aSJames Smart rsp = &rspiocbq->iocb; 17673b5dd52aSJames Smart 17683b5dd52aSJames Smart memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); 17693b5dd52aSJames Smart 17703b5dd52aSJames Smart ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; 17713b5dd52aSJames Smart ctreq->RevisionId.bits.InId = 0; 17723b5dd52aSJames Smart ctreq->FsType = SLI_CT_ELX_LOOPBACK; 17733b5dd52aSJames Smart ctreq->FsSubType = 0; 17743b5dd52aSJames Smart ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; 17753b5dd52aSJames Smart ctreq->CommandResponse.bits.Size = 0; 17763b5dd52aSJames Smart 17773b5dd52aSJames Smart 17783b5dd52aSJames Smart cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys); 17793b5dd52aSJames Smart cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys); 17803b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 17813b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl); 17823b5dd52aSJames Smart 17833b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Fctl = LA; 17843b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Dfctl = 0; 17853b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 17863b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 17873b5dd52aSJames Smart 17883b5dd52aSJames Smart cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; 17893b5dd52aSJames Smart cmd->ulpBdeCount = 1; 17903b5dd52aSJames Smart cmd->ulpLe = 1; 17913b5dd52aSJames Smart cmd->ulpClass = CLASS3; 17923b5dd52aSJames Smart cmd->ulpContext = rpi; 17933b5dd52aSJames Smart 17943b5dd52aSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 17953b5dd52aSJames Smart cmdiocbq->vport = phba->pport; 17963b5dd52aSJames Smart 1797d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 17983b5dd52aSJames Smart rspiocbq, 17993b5dd52aSJames Smart (phba->fc_ratov * 2) 18003b5dd52aSJames Smart + LPFC_DRVR_TIMEOUT); 1801d439d286SJames Smart if (iocb_stat) { 1802d439d286SJames Smart ret_val = -EIO; 18033b5dd52aSJames Smart goto err_get_xri_exit; 1804d439d286SJames Smart } 18053b5dd52aSJames Smart *txxri = rsp->ulpContext; 18063b5dd52aSJames Smart 18073b5dd52aSJames Smart evt->waiting = 1; 18083b5dd52aSJames Smart evt->wait_time_stamp = jiffies; 1809d439d286SJames Smart time_left = wait_event_interruptible_timeout( 18103b5dd52aSJames Smart evt->wq, !list_empty(&evt->events_to_see), 18113b5dd52aSJames Smart ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); 18123b5dd52aSJames Smart if (list_empty(&evt->events_to_see)) 1813d439d286SJames Smart ret_val = (time_left) ? -EINTR : -ETIMEDOUT; 18143b5dd52aSJames Smart else { 18153b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 18163b5dd52aSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 18173b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 18183b5dd52aSJames Smart *rxxri = (list_entry(evt->events_to_get.prev, 18193b5dd52aSJames Smart typeof(struct event_data), 18203b5dd52aSJames Smart node))->immed_dat; 18213b5dd52aSJames Smart } 18223b5dd52aSJames Smart evt->waiting = 0; 18233b5dd52aSJames Smart 18243b5dd52aSJames Smart err_get_xri_exit: 18253b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 18263b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* release ref */ 18273b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* delete */ 18283b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 18293b5dd52aSJames Smart 18303b5dd52aSJames Smart if (dmabuf) { 18313b5dd52aSJames Smart if (dmabuf->virt) 18323b5dd52aSJames Smart lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); 18333b5dd52aSJames Smart kfree(dmabuf); 18343b5dd52aSJames Smart } 18353b5dd52aSJames Smart 1836d439d286SJames Smart if (cmdiocbq && (iocb_stat != IOCB_TIMEDOUT)) 18373b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 18383b5dd52aSJames Smart if (rspiocbq) 18393b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 18403b5dd52aSJames Smart return ret_val; 18413b5dd52aSJames Smart } 18423b5dd52aSJames Smart 18433b5dd52aSJames Smart /** 18443b5dd52aSJames Smart * diag_cmd_data_alloc - fills in a bde struct with dma buffers 18453b5dd52aSJames Smart * @phba: Pointer to HBA context object 18463b5dd52aSJames Smart * @bpl: Pointer to 64 bit bde structure 18473b5dd52aSJames Smart * @size: Number of bytes to process 18483b5dd52aSJames Smart * @nocopydata: Flag to copy user data into the allocated buffer 18493b5dd52aSJames Smart * 18503b5dd52aSJames Smart * This function allocates page size buffers and populates an lpfc_dmabufext. 18513b5dd52aSJames Smart * If allowed the user data pointed to with indataptr is copied into the kernel 18523b5dd52aSJames Smart * memory. The chained list of page size buffers is returned. 18533b5dd52aSJames Smart **/ 18543b5dd52aSJames Smart static struct lpfc_dmabufext * 18553b5dd52aSJames Smart diag_cmd_data_alloc(struct lpfc_hba *phba, 18563b5dd52aSJames Smart struct ulp_bde64 *bpl, uint32_t size, 18573b5dd52aSJames Smart int nocopydata) 18583b5dd52aSJames Smart { 18593b5dd52aSJames Smart struct lpfc_dmabufext *mlist = NULL; 18603b5dd52aSJames Smart struct lpfc_dmabufext *dmp; 18613b5dd52aSJames Smart int cnt, offset = 0, i = 0; 18623b5dd52aSJames Smart struct pci_dev *pcidev; 18633b5dd52aSJames Smart 18643b5dd52aSJames Smart pcidev = phba->pcidev; 18653b5dd52aSJames Smart 18663b5dd52aSJames Smart while (size) { 18673b5dd52aSJames Smart /* We get chunks of 4K */ 18683b5dd52aSJames Smart if (size > BUF_SZ_4K) 18693b5dd52aSJames Smart cnt = BUF_SZ_4K; 18703b5dd52aSJames Smart else 18713b5dd52aSJames Smart cnt = size; 18723b5dd52aSJames Smart 18733b5dd52aSJames Smart /* allocate struct lpfc_dmabufext buffer header */ 18743b5dd52aSJames Smart dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL); 18753b5dd52aSJames Smart if (!dmp) 18763b5dd52aSJames Smart goto out; 18773b5dd52aSJames Smart 18783b5dd52aSJames Smart INIT_LIST_HEAD(&dmp->dma.list); 18793b5dd52aSJames Smart 18803b5dd52aSJames Smart /* Queue it to a linked list */ 18813b5dd52aSJames Smart if (mlist) 18823b5dd52aSJames Smart list_add_tail(&dmp->dma.list, &mlist->dma.list); 18833b5dd52aSJames Smart else 18843b5dd52aSJames Smart mlist = dmp; 18853b5dd52aSJames Smart 18863b5dd52aSJames Smart /* allocate buffer */ 18873b5dd52aSJames Smart dmp->dma.virt = dma_alloc_coherent(&pcidev->dev, 18883b5dd52aSJames Smart cnt, 18893b5dd52aSJames Smart &(dmp->dma.phys), 18903b5dd52aSJames Smart GFP_KERNEL); 18913b5dd52aSJames Smart 18923b5dd52aSJames Smart if (!dmp->dma.virt) 18933b5dd52aSJames Smart goto out; 18943b5dd52aSJames Smart 18953b5dd52aSJames Smart dmp->size = cnt; 18963b5dd52aSJames Smart 18973b5dd52aSJames Smart if (nocopydata) { 18983b5dd52aSJames Smart bpl->tus.f.bdeFlags = 0; 18993b5dd52aSJames Smart pci_dma_sync_single_for_device(phba->pcidev, 19003b5dd52aSJames Smart dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); 19013b5dd52aSJames Smart 19023b5dd52aSJames Smart } else { 19033b5dd52aSJames Smart memset((uint8_t *)dmp->dma.virt, 0, cnt); 19043b5dd52aSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 19053b5dd52aSJames Smart } 19063b5dd52aSJames Smart 19073b5dd52aSJames Smart /* build buffer ptr list for IOCB */ 19083b5dd52aSJames Smart bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); 19093b5dd52aSJames Smart bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); 19103b5dd52aSJames Smart bpl->tus.f.bdeSize = (ushort) cnt; 19113b5dd52aSJames Smart bpl->tus.w = le32_to_cpu(bpl->tus.w); 19123b5dd52aSJames Smart bpl++; 19133b5dd52aSJames Smart 19143b5dd52aSJames Smart i++; 19153b5dd52aSJames Smart offset += cnt; 19163b5dd52aSJames Smart size -= cnt; 19173b5dd52aSJames Smart } 19183b5dd52aSJames Smart 19193b5dd52aSJames Smart mlist->flag = i; 19203b5dd52aSJames Smart return mlist; 19213b5dd52aSJames Smart out: 19223b5dd52aSJames Smart diag_cmd_data_free(phba, mlist); 19233b5dd52aSJames Smart return NULL; 19243b5dd52aSJames Smart } 19253b5dd52aSJames Smart 19263b5dd52aSJames Smart /** 19273b5dd52aSJames Smart * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd 19283b5dd52aSJames Smart * @phba: Pointer to HBA context object 19293b5dd52aSJames Smart * @rxxri: Receive exchange id 19303b5dd52aSJames Smart * @len: Number of data bytes 19313b5dd52aSJames Smart * 19323b5dd52aSJames Smart * This function allocates and posts a data buffer of sufficient size to recieve 19333b5dd52aSJames Smart * an unsolicted CT command. 19343b5dd52aSJames Smart **/ 19353b5dd52aSJames Smart static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, 19363b5dd52aSJames Smart size_t len) 19373b5dd52aSJames Smart { 19383b5dd52aSJames Smart struct lpfc_sli *psli = &phba->sli; 19393b5dd52aSJames Smart struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; 19403b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq; 19413b5dd52aSJames Smart IOCB_t *cmd = NULL; 19423b5dd52aSJames Smart struct list_head head, *curr, *next; 19433b5dd52aSJames Smart struct lpfc_dmabuf *rxbmp; 19443b5dd52aSJames Smart struct lpfc_dmabuf *dmp; 19453b5dd52aSJames Smart struct lpfc_dmabuf *mp[2] = {NULL, NULL}; 19463b5dd52aSJames Smart struct ulp_bde64 *rxbpl = NULL; 19473b5dd52aSJames Smart uint32_t num_bde; 19483b5dd52aSJames Smart struct lpfc_dmabufext *rxbuffer = NULL; 19493b5dd52aSJames Smart int ret_val = 0; 1950d439d286SJames Smart int iocb_stat; 19513b5dd52aSJames Smart int i = 0; 19523b5dd52aSJames Smart 19533b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 19543b5dd52aSJames Smart rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 19553b5dd52aSJames Smart if (rxbmp != NULL) { 19563b5dd52aSJames Smart rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); 1957c7495937SJames Smart if (rxbmp->virt) { 19583b5dd52aSJames Smart INIT_LIST_HEAD(&rxbmp->list); 19593b5dd52aSJames Smart rxbpl = (struct ulp_bde64 *) rxbmp->virt; 19603b5dd52aSJames Smart rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); 19613b5dd52aSJames Smart } 1962c7495937SJames Smart } 19633b5dd52aSJames Smart 19643b5dd52aSJames Smart if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) { 1965d439d286SJames Smart ret_val = -ENOMEM; 19663b5dd52aSJames Smart goto err_post_rxbufs_exit; 19673b5dd52aSJames Smart } 19683b5dd52aSJames Smart 19693b5dd52aSJames Smart /* Queue buffers for the receive exchange */ 19703b5dd52aSJames Smart num_bde = (uint32_t)rxbuffer->flag; 19713b5dd52aSJames Smart dmp = &rxbuffer->dma; 19723b5dd52aSJames Smart 19733b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 19743b5dd52aSJames Smart i = 0; 19753b5dd52aSJames Smart 19763b5dd52aSJames Smart INIT_LIST_HEAD(&head); 19773b5dd52aSJames Smart list_add_tail(&head, &dmp->list); 19783b5dd52aSJames Smart list_for_each_safe(curr, next, &head) { 19793b5dd52aSJames Smart mp[i] = list_entry(curr, struct lpfc_dmabuf, list); 19803b5dd52aSJames Smart list_del(curr); 19813b5dd52aSJames Smart 19823b5dd52aSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 19833b5dd52aSJames Smart mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); 19843b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.addrHigh = 19853b5dd52aSJames Smart putPaddrHigh(mp[i]->phys); 19863b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.addrLow = 19873b5dd52aSJames Smart putPaddrLow(mp[i]->phys); 19883b5dd52aSJames Smart cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = 19893b5dd52aSJames Smart ((struct lpfc_dmabufext *)mp[i])->size; 19903b5dd52aSJames Smart cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; 19913b5dd52aSJames Smart cmd->ulpCommand = CMD_QUE_XRI64_CX; 19923b5dd52aSJames Smart cmd->ulpPU = 0; 19933b5dd52aSJames Smart cmd->ulpLe = 1; 19943b5dd52aSJames Smart cmd->ulpBdeCount = 1; 19953b5dd52aSJames Smart cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; 19963b5dd52aSJames Smart 19973b5dd52aSJames Smart } else { 19983b5dd52aSJames Smart cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); 19993b5dd52aSJames Smart cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); 20003b5dd52aSJames Smart cmd->un.cont64[i].tus.f.bdeSize = 20013b5dd52aSJames Smart ((struct lpfc_dmabufext *)mp[i])->size; 20023b5dd52aSJames Smart cmd->ulpBdeCount = ++i; 20033b5dd52aSJames Smart 20043b5dd52aSJames Smart if ((--num_bde > 0) && (i < 2)) 20053b5dd52aSJames Smart continue; 20063b5dd52aSJames Smart 20073b5dd52aSJames Smart cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; 20083b5dd52aSJames Smart cmd->ulpLe = 1; 20093b5dd52aSJames Smart } 20103b5dd52aSJames Smart 20113b5dd52aSJames Smart cmd->ulpClass = CLASS3; 20123b5dd52aSJames Smart cmd->ulpContext = rxxri; 20133b5dd52aSJames Smart 2014d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 2015d439d286SJames Smart 0); 2016d439d286SJames Smart if (iocb_stat == IOCB_ERROR) { 20173b5dd52aSJames Smart diag_cmd_data_free(phba, 20183b5dd52aSJames Smart (struct lpfc_dmabufext *)mp[0]); 20193b5dd52aSJames Smart if (mp[1]) 20203b5dd52aSJames Smart diag_cmd_data_free(phba, 20213b5dd52aSJames Smart (struct lpfc_dmabufext *)mp[1]); 20223b5dd52aSJames Smart dmp = list_entry(next, struct lpfc_dmabuf, list); 2023d439d286SJames Smart ret_val = -EIO; 20243b5dd52aSJames Smart goto err_post_rxbufs_exit; 20253b5dd52aSJames Smart } 20263b5dd52aSJames Smart 20273b5dd52aSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, mp[0]); 20283b5dd52aSJames Smart if (mp[1]) { 20293b5dd52aSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, mp[1]); 20303b5dd52aSJames Smart mp[1] = NULL; 20313b5dd52aSJames Smart } 20323b5dd52aSJames Smart 20333b5dd52aSJames Smart /* The iocb was freed by lpfc_sli_issue_iocb */ 20343b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 20353b5dd52aSJames Smart if (!cmdiocbq) { 20363b5dd52aSJames Smart dmp = list_entry(next, struct lpfc_dmabuf, list); 2037d439d286SJames Smart ret_val = -EIO; 20383b5dd52aSJames Smart goto err_post_rxbufs_exit; 20393b5dd52aSJames Smart } 20403b5dd52aSJames Smart 20413b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 20423b5dd52aSJames Smart i = 0; 20433b5dd52aSJames Smart } 20443b5dd52aSJames Smart list_del(&head); 20453b5dd52aSJames Smart 20463b5dd52aSJames Smart err_post_rxbufs_exit: 20473b5dd52aSJames Smart 20483b5dd52aSJames Smart if (rxbmp) { 20493b5dd52aSJames Smart if (rxbmp->virt) 20503b5dd52aSJames Smart lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); 20513b5dd52aSJames Smart kfree(rxbmp); 20523b5dd52aSJames Smart } 20533b5dd52aSJames Smart 20543b5dd52aSJames Smart if (cmdiocbq) 20553b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 20563b5dd52aSJames Smart return ret_val; 20573b5dd52aSJames Smart } 20583b5dd52aSJames Smart 20593b5dd52aSJames Smart /** 20603b5dd52aSJames Smart * lpfc_bsg_diag_test - with a port in loopback issues a Ct cmd to itself 20613b5dd52aSJames Smart * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job 20623b5dd52aSJames Smart * 20633b5dd52aSJames Smart * This function receives a user data buffer to be transmitted and received on 20643b5dd52aSJames Smart * the same port, the link must be up and in loopback mode prior 20653b5dd52aSJames Smart * to being called. 20663b5dd52aSJames Smart * 1. A kernel buffer is allocated to copy the user data into. 20673b5dd52aSJames Smart * 2. The port registers with "itself". 20683b5dd52aSJames Smart * 3. The transmit and receive exchange ids are obtained. 20693b5dd52aSJames Smart * 4. The receive exchange id is posted. 20703b5dd52aSJames Smart * 5. A new els loopback event is created. 20713b5dd52aSJames Smart * 6. The command and response iocbs are allocated. 20723b5dd52aSJames Smart * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback. 20733b5dd52aSJames Smart * 20743b5dd52aSJames Smart * This function is meant to be called n times while the port is in loopback 20753b5dd52aSJames Smart * so it is the apps responsibility to issue a reset to take the port out 20763b5dd52aSJames Smart * of loopback mode. 20773b5dd52aSJames Smart **/ 20783b5dd52aSJames Smart static int 20793b5dd52aSJames Smart lpfc_bsg_diag_test(struct fc_bsg_job *job) 20803b5dd52aSJames Smart { 20813b5dd52aSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 20823b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 20833b5dd52aSJames Smart struct diag_mode_test *diag_mode; 20843b5dd52aSJames Smart struct lpfc_bsg_event *evt; 20853b5dd52aSJames Smart struct event_data *evdat; 20863b5dd52aSJames Smart struct lpfc_sli *psli = &phba->sli; 20873b5dd52aSJames Smart uint32_t size; 20883b5dd52aSJames Smart uint32_t full_size; 20893b5dd52aSJames Smart size_t segment_len = 0, segment_offset = 0, current_offset = 0; 20904042629eSJames Smart uint16_t rpi = 0; 20913b5dd52aSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq; 20923b5dd52aSJames Smart IOCB_t *cmd, *rsp; 20933b5dd52aSJames Smart struct lpfc_sli_ct_request *ctreq; 20943b5dd52aSJames Smart struct lpfc_dmabuf *txbmp; 20953b5dd52aSJames Smart struct ulp_bde64 *txbpl = NULL; 20963b5dd52aSJames Smart struct lpfc_dmabufext *txbuffer = NULL; 20973b5dd52aSJames Smart struct list_head head; 20983b5dd52aSJames Smart struct lpfc_dmabuf *curr; 20993b5dd52aSJames Smart uint16_t txxri, rxxri; 21003b5dd52aSJames Smart uint32_t num_bde; 21013b5dd52aSJames Smart uint8_t *ptr = NULL, *rx_databuf = NULL; 21023b5dd52aSJames Smart int rc = 0; 2103d439d286SJames Smart int time_left; 2104d439d286SJames Smart int iocb_stat; 21053b5dd52aSJames Smart unsigned long flags; 21063b5dd52aSJames Smart void *dataout = NULL; 21073b5dd52aSJames Smart uint32_t total_mem; 21083b5dd52aSJames Smart 21093b5dd52aSJames Smart /* in case no data is returned return just the return code */ 21103b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 0; 21113b5dd52aSJames Smart 21123b5dd52aSJames Smart if (job->request_len < 21133b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) { 21143b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 21153b5dd52aSJames Smart "2739 Received DIAG TEST request below minimum " 21163b5dd52aSJames Smart "size\n"); 21173b5dd52aSJames Smart rc = -EINVAL; 21183b5dd52aSJames Smart goto loopback_test_exit; 21193b5dd52aSJames Smart } 21203b5dd52aSJames Smart 21213b5dd52aSJames Smart if (job->request_payload.payload_len != 21223b5dd52aSJames Smart job->reply_payload.payload_len) { 21233b5dd52aSJames Smart rc = -EINVAL; 21243b5dd52aSJames Smart goto loopback_test_exit; 21253b5dd52aSJames Smart } 21263b5dd52aSJames Smart 21273b5dd52aSJames Smart diag_mode = (struct diag_mode_test *) 21283b5dd52aSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 21293b5dd52aSJames Smart 21303b5dd52aSJames Smart if ((phba->link_state == LPFC_HBA_ERROR) || 21313b5dd52aSJames Smart (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || 21323b5dd52aSJames Smart (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { 21333b5dd52aSJames Smart rc = -EACCES; 21343b5dd52aSJames Smart goto loopback_test_exit; 21353b5dd52aSJames Smart } 21363b5dd52aSJames Smart 21373b5dd52aSJames Smart if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) { 21383b5dd52aSJames Smart rc = -EACCES; 21393b5dd52aSJames Smart goto loopback_test_exit; 21403b5dd52aSJames Smart } 21413b5dd52aSJames Smart 21423b5dd52aSJames Smart size = job->request_payload.payload_len; 21433b5dd52aSJames Smart full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */ 21443b5dd52aSJames Smart 21453b5dd52aSJames Smart if ((size == 0) || (size > 80 * BUF_SZ_4K)) { 21463b5dd52aSJames Smart rc = -ERANGE; 21473b5dd52aSJames Smart goto loopback_test_exit; 21483b5dd52aSJames Smart } 21493b5dd52aSJames Smart 215063e801ceSJames Smart if (full_size >= BUF_SZ_4K) { 21513b5dd52aSJames Smart /* 21523b5dd52aSJames Smart * Allocate memory for ioctl data. If buffer is bigger than 64k, 21533b5dd52aSJames Smart * then we allocate 64k and re-use that buffer over and over to 21543b5dd52aSJames Smart * xfer the whole block. This is because Linux kernel has a 21553b5dd52aSJames Smart * problem allocating more than 120k of kernel space memory. Saw 21563b5dd52aSJames Smart * problem with GET_FCPTARGETMAPPING... 21573b5dd52aSJames Smart */ 21583b5dd52aSJames Smart if (size <= (64 * 1024)) 215963e801ceSJames Smart total_mem = full_size; 21603b5dd52aSJames Smart else 21613b5dd52aSJames Smart total_mem = 64 * 1024; 21623b5dd52aSJames Smart } else 21633b5dd52aSJames Smart /* Allocate memory for ioctl data */ 21643b5dd52aSJames Smart total_mem = BUF_SZ_4K; 21653b5dd52aSJames Smart 21663b5dd52aSJames Smart dataout = kmalloc(total_mem, GFP_KERNEL); 21673b5dd52aSJames Smart if (dataout == NULL) { 21683b5dd52aSJames Smart rc = -ENOMEM; 21693b5dd52aSJames Smart goto loopback_test_exit; 21703b5dd52aSJames Smart } 21713b5dd52aSJames Smart 21723b5dd52aSJames Smart ptr = dataout; 21733b5dd52aSJames Smart ptr += ELX_LOOPBACK_HEADER_SZ; 21743b5dd52aSJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 21753b5dd52aSJames Smart job->request_payload.sg_cnt, 21763b5dd52aSJames Smart ptr, size); 21773b5dd52aSJames Smart rc = lpfcdiag_loop_self_reg(phba, &rpi); 2178d439d286SJames Smart if (rc) 21793b5dd52aSJames Smart goto loopback_test_exit; 21803b5dd52aSJames Smart 21813b5dd52aSJames Smart rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); 21823b5dd52aSJames Smart if (rc) { 21833b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 21843b5dd52aSJames Smart goto loopback_test_exit; 21853b5dd52aSJames Smart } 21863b5dd52aSJames Smart 21873b5dd52aSJames Smart rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); 21883b5dd52aSJames Smart if (rc) { 21893b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 21903b5dd52aSJames Smart goto loopback_test_exit; 21913b5dd52aSJames Smart } 21923b5dd52aSJames Smart 21933b5dd52aSJames Smart evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, 21943b5dd52aSJames Smart SLI_CT_ELX_LOOPBACK); 21953b5dd52aSJames Smart if (!evt) { 21963b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 21973b5dd52aSJames Smart rc = -ENOMEM; 21983b5dd52aSJames Smart goto loopback_test_exit; 21993b5dd52aSJames Smart } 22003b5dd52aSJames Smart 22013b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 22023b5dd52aSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 22033b5dd52aSJames Smart lpfc_bsg_event_ref(evt); 22043b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 22053b5dd52aSJames Smart 22063b5dd52aSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 22073b5dd52aSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 22083b5dd52aSJames Smart txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 22093b5dd52aSJames Smart 22103b5dd52aSJames Smart if (txbmp) { 22113b5dd52aSJames Smart txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); 2212c7495937SJames Smart if (txbmp->virt) { 22133b5dd52aSJames Smart INIT_LIST_HEAD(&txbmp->list); 22143b5dd52aSJames Smart txbpl = (struct ulp_bde64 *) txbmp->virt; 22153b5dd52aSJames Smart txbuffer = diag_cmd_data_alloc(phba, 22163b5dd52aSJames Smart txbpl, full_size, 0); 22173b5dd52aSJames Smart } 2218c7495937SJames Smart } 22193b5dd52aSJames Smart 2220c7495937SJames Smart if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer || 2221c7495937SJames Smart !txbmp->virt) { 22223b5dd52aSJames Smart rc = -ENOMEM; 22233b5dd52aSJames Smart goto err_loopback_test_exit; 22243b5dd52aSJames Smart } 22253b5dd52aSJames Smart 22263b5dd52aSJames Smart cmd = &cmdiocbq->iocb; 22273b5dd52aSJames Smart rsp = &rspiocbq->iocb; 22283b5dd52aSJames Smart 22293b5dd52aSJames Smart INIT_LIST_HEAD(&head); 22303b5dd52aSJames Smart list_add_tail(&head, &txbuffer->dma.list); 22313b5dd52aSJames Smart list_for_each_entry(curr, &head, list) { 22323b5dd52aSJames Smart segment_len = ((struct lpfc_dmabufext *)curr)->size; 22333b5dd52aSJames Smart if (current_offset == 0) { 22343b5dd52aSJames Smart ctreq = curr->virt; 22353b5dd52aSJames Smart memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); 22363b5dd52aSJames Smart ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; 22373b5dd52aSJames Smart ctreq->RevisionId.bits.InId = 0; 22383b5dd52aSJames Smart ctreq->FsType = SLI_CT_ELX_LOOPBACK; 22393b5dd52aSJames Smart ctreq->FsSubType = 0; 22403b5dd52aSJames Smart ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA; 22413b5dd52aSJames Smart ctreq->CommandResponse.bits.Size = size; 22423b5dd52aSJames Smart segment_offset = ELX_LOOPBACK_HEADER_SZ; 22433b5dd52aSJames Smart } else 22443b5dd52aSJames Smart segment_offset = 0; 22453b5dd52aSJames Smart 22463b5dd52aSJames Smart BUG_ON(segment_offset >= segment_len); 22473b5dd52aSJames Smart memcpy(curr->virt + segment_offset, 22483b5dd52aSJames Smart ptr + current_offset, 22493b5dd52aSJames Smart segment_len - segment_offset); 22503b5dd52aSJames Smart 22513b5dd52aSJames Smart current_offset += segment_len - segment_offset; 22523b5dd52aSJames Smart BUG_ON(current_offset > size); 22533b5dd52aSJames Smart } 22543b5dd52aSJames Smart list_del(&head); 22553b5dd52aSJames Smart 22563b5dd52aSJames Smart /* Build the XMIT_SEQUENCE iocb */ 22573b5dd52aSJames Smart 22583b5dd52aSJames Smart num_bde = (uint32_t)txbuffer->flag; 22593b5dd52aSJames Smart 22603b5dd52aSJames Smart cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); 22613b5dd52aSJames Smart cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys); 22623b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 22633b5dd52aSJames Smart cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64)); 22643b5dd52aSJames Smart 22653b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); 22663b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Dfctl = 0; 22673b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; 22683b5dd52aSJames Smart cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; 22693b5dd52aSJames Smart 22703b5dd52aSJames Smart cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; 22713b5dd52aSJames Smart cmd->ulpBdeCount = 1; 22723b5dd52aSJames Smart cmd->ulpLe = 1; 22733b5dd52aSJames Smart cmd->ulpClass = CLASS3; 22743b5dd52aSJames Smart cmd->ulpContext = txxri; 22753b5dd52aSJames Smart 22763b5dd52aSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 22773b5dd52aSJames Smart cmdiocbq->vport = phba->pport; 22783b5dd52aSJames Smart 2279d439d286SJames Smart iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 2280d439d286SJames Smart rspiocbq, (phba->fc_ratov * 2) + 2281d439d286SJames Smart LPFC_DRVR_TIMEOUT); 22823b5dd52aSJames Smart 2283d439d286SJames Smart if ((iocb_stat != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) { 22843b5dd52aSJames Smart rc = -EIO; 22853b5dd52aSJames Smart goto err_loopback_test_exit; 22863b5dd52aSJames Smart } 22873b5dd52aSJames Smart 22883b5dd52aSJames Smart evt->waiting = 1; 2289d439d286SJames Smart time_left = wait_event_interruptible_timeout( 22903b5dd52aSJames Smart evt->wq, !list_empty(&evt->events_to_see), 22913b5dd52aSJames Smart ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); 22923b5dd52aSJames Smart evt->waiting = 0; 22933b5dd52aSJames Smart if (list_empty(&evt->events_to_see)) 2294d439d286SJames Smart rc = (time_left) ? -EINTR : -ETIMEDOUT; 22953b5dd52aSJames Smart else { 22963b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 22973b5dd52aSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 22983b5dd52aSJames Smart evdat = list_entry(evt->events_to_get.prev, 22993b5dd52aSJames Smart typeof(*evdat), node); 23003b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 23013b5dd52aSJames Smart rx_databuf = evdat->data; 23023b5dd52aSJames Smart if (evdat->len != full_size) { 23033b5dd52aSJames Smart lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, 23043b5dd52aSJames Smart "1603 Loopback test did not receive expected " 23053b5dd52aSJames Smart "data length. actual length 0x%x expected " 23063b5dd52aSJames Smart "length 0x%x\n", 23073b5dd52aSJames Smart evdat->len, full_size); 23083b5dd52aSJames Smart rc = -EIO; 23093b5dd52aSJames Smart } else if (rx_databuf == NULL) 23103b5dd52aSJames Smart rc = -EIO; 23113b5dd52aSJames Smart else { 23123b5dd52aSJames Smart rc = IOCB_SUCCESS; 23133b5dd52aSJames Smart /* skip over elx loopback header */ 23143b5dd52aSJames Smart rx_databuf += ELX_LOOPBACK_HEADER_SZ; 23153b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 23163b5dd52aSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 23173b5dd52aSJames Smart job->reply_payload.sg_cnt, 23183b5dd52aSJames Smart rx_databuf, size); 23193b5dd52aSJames Smart job->reply->reply_payload_rcv_len = size; 23203b5dd52aSJames Smart } 23213b5dd52aSJames Smart } 23223b5dd52aSJames Smart 23233b5dd52aSJames Smart err_loopback_test_exit: 23243b5dd52aSJames Smart lpfcdiag_loop_self_unreg(phba, rpi); 23253b5dd52aSJames Smart 23263b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 23273b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* release ref */ 23283b5dd52aSJames Smart lpfc_bsg_event_unref(evt); /* delete */ 23293b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 23303b5dd52aSJames Smart 23313b5dd52aSJames Smart if (cmdiocbq != NULL) 23323b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 23333b5dd52aSJames Smart 23343b5dd52aSJames Smart if (rspiocbq != NULL) 23353b5dd52aSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 23363b5dd52aSJames Smart 23373b5dd52aSJames Smart if (txbmp != NULL) { 23383b5dd52aSJames Smart if (txbpl != NULL) { 23393b5dd52aSJames Smart if (txbuffer != NULL) 23403b5dd52aSJames Smart diag_cmd_data_free(phba, txbuffer); 23413b5dd52aSJames Smart lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys); 23423b5dd52aSJames Smart } 23433b5dd52aSJames Smart kfree(txbmp); 23443b5dd52aSJames Smart } 23453b5dd52aSJames Smart 23463b5dd52aSJames Smart loopback_test_exit: 23473b5dd52aSJames Smart kfree(dataout); 23483b5dd52aSJames Smart /* make error code available to userspace */ 23493b5dd52aSJames Smart job->reply->result = rc; 23503b5dd52aSJames Smart job->dd_data = NULL; 23513b5dd52aSJames Smart /* complete the job back to userspace if no error */ 23523b5dd52aSJames Smart if (rc == 0) 23533b5dd52aSJames Smart job->job_done(job); 23543b5dd52aSJames Smart return rc; 23553b5dd52aSJames Smart } 23563b5dd52aSJames Smart 23573b5dd52aSJames Smart /** 23583b5dd52aSJames Smart * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command 23593b5dd52aSJames Smart * @job: GET_DFC_REV fc_bsg_job 23603b5dd52aSJames Smart **/ 23613b5dd52aSJames Smart static int 23623b5dd52aSJames Smart lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job) 23633b5dd52aSJames Smart { 23643b5dd52aSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 23653b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 23663b5dd52aSJames Smart struct get_mgmt_rev *event_req; 23673b5dd52aSJames Smart struct get_mgmt_rev_reply *event_reply; 23683b5dd52aSJames Smart int rc = 0; 23693b5dd52aSJames Smart 23703b5dd52aSJames Smart if (job->request_len < 23713b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) { 23723b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 23733b5dd52aSJames Smart "2740 Received GET_DFC_REV request below " 23743b5dd52aSJames Smart "minimum size\n"); 23753b5dd52aSJames Smart rc = -EINVAL; 23763b5dd52aSJames Smart goto job_error; 23773b5dd52aSJames Smart } 23783b5dd52aSJames Smart 23793b5dd52aSJames Smart event_req = (struct get_mgmt_rev *) 23803b5dd52aSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 23813b5dd52aSJames Smart 23823b5dd52aSJames Smart event_reply = (struct get_mgmt_rev_reply *) 23833b5dd52aSJames Smart job->reply->reply_data.vendor_reply.vendor_rsp; 23843b5dd52aSJames Smart 23853b5dd52aSJames Smart if (job->reply_len < 23863b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) { 23873b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 23883b5dd52aSJames Smart "2741 Received GET_DFC_REV reply below " 23893b5dd52aSJames Smart "minimum size\n"); 23903b5dd52aSJames Smart rc = -EINVAL; 23913b5dd52aSJames Smart goto job_error; 23923b5dd52aSJames Smart } 23933b5dd52aSJames Smart 23943b5dd52aSJames Smart event_reply->info.a_Major = MANAGEMENT_MAJOR_REV; 23953b5dd52aSJames Smart event_reply->info.a_Minor = MANAGEMENT_MINOR_REV; 23963b5dd52aSJames Smart job_error: 23973b5dd52aSJames Smart job->reply->result = rc; 23983b5dd52aSJames Smart if (rc == 0) 23993b5dd52aSJames Smart job->job_done(job); 24003b5dd52aSJames Smart return rc; 24013b5dd52aSJames Smart } 24023b5dd52aSJames Smart 24033b5dd52aSJames Smart /** 24043b5dd52aSJames Smart * lpfc_bsg_wake_mbox_wait - lpfc_bsg_issue_mbox mbox completion handler 24053b5dd52aSJames Smart * @phba: Pointer to HBA context object. 24063b5dd52aSJames Smart * @pmboxq: Pointer to mailbox command. 24073b5dd52aSJames Smart * 24083b5dd52aSJames Smart * This is completion handler function for mailbox commands issued from 24093b5dd52aSJames Smart * lpfc_bsg_issue_mbox function. This function is called by the 24103b5dd52aSJames Smart * mailbox event handler function with no lock held. This function 24113b5dd52aSJames Smart * will wake up thread waiting on the wait queue pointed by context1 24123b5dd52aSJames Smart * of the mailbox. 24133b5dd52aSJames Smart **/ 24143b5dd52aSJames Smart void 24153b5dd52aSJames Smart lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) 24163b5dd52aSJames Smart { 24173b5dd52aSJames Smart struct bsg_job_data *dd_data; 24183b5dd52aSJames Smart struct fc_bsg_job *job; 24193b5dd52aSJames Smart uint32_t size; 24203b5dd52aSJames Smart unsigned long flags; 24217a470277SJames Smart uint8_t *to; 24227a470277SJames Smart uint8_t *from; 24233b5dd52aSJames Smart 24243b5dd52aSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 24253b5dd52aSJames Smart dd_data = pmboxq->context1; 24267a470277SJames Smart /* job already timed out? */ 24273b5dd52aSJames Smart if (!dd_data) { 24283b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 24293b5dd52aSJames Smart return; 24303b5dd52aSJames Smart } 24313b5dd52aSJames Smart 24327a470277SJames Smart /* build the outgoing buffer to do an sg copy 24337a470277SJames Smart * the format is the response mailbox followed by any extended 24347a470277SJames Smart * mailbox data 24357a470277SJames Smart */ 24367a470277SJames Smart from = (uint8_t *)&pmboxq->u.mb; 24377a470277SJames Smart to = (uint8_t *)dd_data->context_un.mbox.mb; 24387a470277SJames Smart memcpy(to, from, sizeof(MAILBOX_t)); 2439c7495937SJames Smart if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS) { 24407a470277SJames Smart /* copy the extended data if any, count is in words */ 2441c7495937SJames Smart if (dd_data->context_un.mbox.outExtWLen) { 24427a470277SJames Smart from = (uint8_t *)dd_data->context_un.mbox.ext; 24437a470277SJames Smart to += sizeof(MAILBOX_t); 2444c7495937SJames Smart size = dd_data->context_un.mbox.outExtWLen * 2445c7495937SJames Smart sizeof(uint32_t); 2446c7495937SJames Smart memcpy(to, from, size); 2447c7495937SJames Smart } else if (pmboxq->u.mb.mbxCommand == MBX_RUN_BIU_DIAG64) { 2448c7495937SJames Smart from = (uint8_t *)dd_data->context_un.mbox. 2449c7495937SJames Smart dmp->dma.virt; 2450c7495937SJames Smart to += sizeof(MAILBOX_t); 2451c7495937SJames Smart size = dd_data->context_un.mbox.dmp->size; 2452c7495937SJames Smart memcpy(to, from, size); 2453c7495937SJames Smart } else if ((phba->sli_rev == LPFC_SLI_REV4) && 2454c7495937SJames Smart (pmboxq->u.mb.mbxCommand == MBX_DUMP_MEMORY)) { 2455c7495937SJames Smart from = (uint8_t *)dd_data->context_un.mbox.dmp->dma. 2456c7495937SJames Smart virt; 2457c7495937SJames Smart to += sizeof(MAILBOX_t); 2458c7495937SJames Smart size = pmboxq->u.mb.un.varWords[5]; 2459c7495937SJames Smart memcpy(to, from, size); 2460515e0aa2SJames Smart } else if ((phba->sli_rev == LPFC_SLI_REV4) && 2461515e0aa2SJames Smart (pmboxq->u.mb.mbxCommand == MBX_SLI4_CONFIG)) { 2462515e0aa2SJames Smart struct lpfc_mbx_nembed_cmd *nembed_sge = 2463515e0aa2SJames Smart (struct lpfc_mbx_nembed_cmd *) 2464515e0aa2SJames Smart &pmboxq->u.mb.un.varWords[0]; 2465515e0aa2SJames Smart 2466515e0aa2SJames Smart from = (uint8_t *)dd_data->context_un.mbox.dmp->dma. 2467515e0aa2SJames Smart virt; 2468515e0aa2SJames Smart to += sizeof(MAILBOX_t); 2469515e0aa2SJames Smart size = nembed_sge->sge[0].length; 2470515e0aa2SJames Smart memcpy(to, from, size); 2471c7495937SJames Smart } else if (pmboxq->u.mb.mbxCommand == MBX_READ_EVENT_LOG) { 2472c7495937SJames Smart from = (uint8_t *)dd_data->context_un. 2473c7495937SJames Smart mbox.dmp->dma.virt; 2474c7495937SJames Smart to += sizeof(MAILBOX_t); 2475c7495937SJames Smart size = dd_data->context_un.mbox.dmp->size; 2476c7495937SJames Smart memcpy(to, from, size); 2477c7495937SJames Smart } 24787a470277SJames Smart } 24797a470277SJames Smart 24807a470277SJames Smart from = (uint8_t *)dd_data->context_un.mbox.mb; 24813b5dd52aSJames Smart job = dd_data->context_un.mbox.set_job; 2482*5a6f133eSJames Smart if (job) { 24837a470277SJames Smart size = job->reply_payload.payload_len; 24843b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 24853b5dd52aSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 24863b5dd52aSJames Smart job->reply_payload.sg_cnt, 24877a470277SJames Smart from, size); 24883b5dd52aSJames Smart job->reply->result = 0; 24897a470277SJames Smart 24903b5dd52aSJames Smart job->dd_data = NULL; 24913b5dd52aSJames Smart job->job_done(job); 2492*5a6f133eSJames Smart } 2493*5a6f133eSJames Smart dd_data->context_un.mbox.set_job = NULL; 24947a470277SJames Smart /* need to hold the lock until we call job done to hold off 24957a470277SJames Smart * the timeout handler returning to the midlayer while 24967a470277SJames Smart * we are stillprocessing the job 24977a470277SJames Smart */ 24983b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 24997a470277SJames Smart 25007a470277SJames Smart kfree(dd_data->context_un.mbox.mb); 25013b5dd52aSJames Smart mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); 25027a470277SJames Smart kfree(dd_data->context_un.mbox.ext); 25037a470277SJames Smart if (dd_data->context_un.mbox.dmp) { 25047a470277SJames Smart dma_free_coherent(&phba->pcidev->dev, 25057a470277SJames Smart dd_data->context_un.mbox.dmp->size, 25067a470277SJames Smart dd_data->context_un.mbox.dmp->dma.virt, 25077a470277SJames Smart dd_data->context_un.mbox.dmp->dma.phys); 25087a470277SJames Smart kfree(dd_data->context_un.mbox.dmp); 25097a470277SJames Smart } 25107a470277SJames Smart if (dd_data->context_un.mbox.rxbmp) { 25117a470277SJames Smart lpfc_mbuf_free(phba, dd_data->context_un.mbox.rxbmp->virt, 25127a470277SJames Smart dd_data->context_un.mbox.rxbmp->phys); 25137a470277SJames Smart kfree(dd_data->context_un.mbox.rxbmp); 25147a470277SJames Smart } 25153b5dd52aSJames Smart kfree(dd_data); 25163b5dd52aSJames Smart return; 25173b5dd52aSJames Smart } 25183b5dd52aSJames Smart 25193b5dd52aSJames Smart /** 25203b5dd52aSJames Smart * lpfc_bsg_check_cmd_access - test for a supported mailbox command 25213b5dd52aSJames Smart * @phba: Pointer to HBA context object. 25223b5dd52aSJames Smart * @mb: Pointer to a mailbox object. 25233b5dd52aSJames Smart * @vport: Pointer to a vport object. 25243b5dd52aSJames Smart * 25253b5dd52aSJames Smart * Some commands require the port to be offline, some may not be called from 25263b5dd52aSJames Smart * the application. 25273b5dd52aSJames Smart **/ 25283b5dd52aSJames Smart static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, 25293b5dd52aSJames Smart MAILBOX_t *mb, struct lpfc_vport *vport) 25303b5dd52aSJames Smart { 25313b5dd52aSJames Smart /* return negative error values for bsg job */ 25323b5dd52aSJames Smart switch (mb->mbxCommand) { 25333b5dd52aSJames Smart /* Offline only */ 25343b5dd52aSJames Smart case MBX_INIT_LINK: 25353b5dd52aSJames Smart case MBX_DOWN_LINK: 25363b5dd52aSJames Smart case MBX_CONFIG_LINK: 25373b5dd52aSJames Smart case MBX_CONFIG_RING: 25383b5dd52aSJames Smart case MBX_RESET_RING: 25393b5dd52aSJames Smart case MBX_UNREG_LOGIN: 25403b5dd52aSJames Smart case MBX_CLEAR_LA: 25413b5dd52aSJames Smart case MBX_DUMP_CONTEXT: 25423b5dd52aSJames Smart case MBX_RUN_DIAGS: 25433b5dd52aSJames Smart case MBX_RESTART: 25443b5dd52aSJames Smart case MBX_SET_MASK: 25453b5dd52aSJames Smart if (!(vport->fc_flag & FC_OFFLINE_MODE)) { 25463b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 25473b5dd52aSJames Smart "2743 Command 0x%x is illegal in on-line " 25483b5dd52aSJames Smart "state\n", 25493b5dd52aSJames Smart mb->mbxCommand); 25503b5dd52aSJames Smart return -EPERM; 25513b5dd52aSJames Smart } 25523b5dd52aSJames Smart case MBX_WRITE_NV: 25533b5dd52aSJames Smart case MBX_WRITE_VPARMS: 25543b5dd52aSJames Smart case MBX_LOAD_SM: 25553b5dd52aSJames Smart case MBX_READ_NV: 25563b5dd52aSJames Smart case MBX_READ_CONFIG: 25573b5dd52aSJames Smart case MBX_READ_RCONFIG: 25583b5dd52aSJames Smart case MBX_READ_STATUS: 25593b5dd52aSJames Smart case MBX_READ_XRI: 25603b5dd52aSJames Smart case MBX_READ_REV: 25613b5dd52aSJames Smart case MBX_READ_LNK_STAT: 25623b5dd52aSJames Smart case MBX_DUMP_MEMORY: 25633b5dd52aSJames Smart case MBX_DOWN_LOAD: 25643b5dd52aSJames Smart case MBX_UPDATE_CFG: 25653b5dd52aSJames Smart case MBX_KILL_BOARD: 25663b5dd52aSJames Smart case MBX_LOAD_AREA: 25673b5dd52aSJames Smart case MBX_LOAD_EXP_ROM: 25683b5dd52aSJames Smart case MBX_BEACON: 25693b5dd52aSJames Smart case MBX_DEL_LD_ENTRY: 25703b5dd52aSJames Smart case MBX_SET_DEBUG: 25713b5dd52aSJames Smart case MBX_WRITE_WWN: 25723b5dd52aSJames Smart case MBX_SLI4_CONFIG: 2573c7495937SJames Smart case MBX_READ_EVENT_LOG: 25743b5dd52aSJames Smart case MBX_READ_EVENT_LOG_STATUS: 25753b5dd52aSJames Smart case MBX_WRITE_EVENT_LOG: 25763b5dd52aSJames Smart case MBX_PORT_CAPABILITIES: 25773b5dd52aSJames Smart case MBX_PORT_IOV_CONTROL: 25787a470277SJames Smart case MBX_RUN_BIU_DIAG64: 25793b5dd52aSJames Smart break; 25803b5dd52aSJames Smart case MBX_SET_VARIABLE: 2581e2aed29fSJames Smart lpfc_printf_log(phba, KERN_INFO, LOG_INIT, 2582e2aed29fSJames Smart "1226 mbox: set_variable 0x%x, 0x%x\n", 2583e2aed29fSJames Smart mb->un.varWords[0], 2584e2aed29fSJames Smart mb->un.varWords[1]); 2585e2aed29fSJames Smart if ((mb->un.varWords[0] == SETVAR_MLOMNT) 2586e2aed29fSJames Smart && (mb->un.varWords[1] == 1)) { 2587e2aed29fSJames Smart phba->wait_4_mlo_maint_flg = 1; 2588e2aed29fSJames Smart } else if (mb->un.varWords[0] == SETVAR_MLORST) { 2589e2aed29fSJames Smart phba->link_flag &= ~LS_LOOPBACK_MODE; 259076a95d75SJames Smart phba->fc_topology = LPFC_TOPOLOGY_PT_PT; 2591e2aed29fSJames Smart } 2592e2aed29fSJames Smart break; 25933b5dd52aSJames Smart case MBX_READ_SPARM64: 259476a95d75SJames Smart case MBX_READ_TOPOLOGY: 25953b5dd52aSJames Smart case MBX_REG_LOGIN: 25963b5dd52aSJames Smart case MBX_REG_LOGIN64: 25973b5dd52aSJames Smart case MBX_CONFIG_PORT: 25983b5dd52aSJames Smart case MBX_RUN_BIU_DIAG: 25993b5dd52aSJames Smart default: 26003b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 26013b5dd52aSJames Smart "2742 Unknown Command 0x%x\n", 26023b5dd52aSJames Smart mb->mbxCommand); 26033b5dd52aSJames Smart return -EPERM; 26043b5dd52aSJames Smart } 26053b5dd52aSJames Smart 26063b5dd52aSJames Smart return 0; /* ok */ 26073b5dd52aSJames Smart } 26083b5dd52aSJames Smart 26093b5dd52aSJames Smart /** 26103b5dd52aSJames Smart * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app 26113b5dd52aSJames Smart * @phba: Pointer to HBA context object. 26123b5dd52aSJames Smart * @mb: Pointer to a mailbox object. 26133b5dd52aSJames Smart * @vport: Pointer to a vport object. 26143b5dd52aSJames Smart * 26153b5dd52aSJames Smart * Allocate a tracking object, mailbox command memory, get a mailbox 26163b5dd52aSJames Smart * from the mailbox pool, copy the caller mailbox command. 26173b5dd52aSJames Smart * 26183b5dd52aSJames Smart * If offline and the sli is active we need to poll for the command (port is 26193b5dd52aSJames Smart * being reset) and com-plete the job, otherwise issue the mailbox command and 26203b5dd52aSJames Smart * let our completion handler finish the command. 26213b5dd52aSJames Smart **/ 26223b5dd52aSJames Smart static uint32_t 26233b5dd52aSJames Smart lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, 26243b5dd52aSJames Smart struct lpfc_vport *vport) 26253b5dd52aSJames Smart { 26267a470277SJames Smart LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */ 26277a470277SJames Smart MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */ 26287a470277SJames Smart /* a 4k buffer to hold the mb and extended data from/to the bsg */ 26297a470277SJames Smart MAILBOX_t *mb = NULL; 26307a470277SJames Smart struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */ 26313b5dd52aSJames Smart uint32_t size; 26327a470277SJames Smart struct lpfc_dmabuf *rxbmp = NULL; /* for biu diag */ 26337a470277SJames Smart struct lpfc_dmabufext *dmp = NULL; /* for biu diag */ 26347a470277SJames Smart struct ulp_bde64 *rxbpl = NULL; 26357a470277SJames Smart struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *) 26367a470277SJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 26377a470277SJames Smart uint8_t *ext = NULL; 26383b5dd52aSJames Smart int rc = 0; 26397a470277SJames Smart uint8_t *from; 26407a470277SJames Smart 26417a470277SJames Smart /* in case no data is transferred */ 26427a470277SJames Smart job->reply->reply_payload_rcv_len = 0; 26437a470277SJames Smart 26447a470277SJames Smart /* check if requested extended data lengths are valid */ 26457a470277SJames Smart if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) || 2646c7495937SJames Smart (mbox_req->outExtWLen > MAILBOX_EXT_SIZE)) { 26477a470277SJames Smart rc = -ERANGE; 26487a470277SJames Smart goto job_done; 26497a470277SJames Smart } 26503b5dd52aSJames Smart 26513b5dd52aSJames Smart /* allocate our bsg tracking structure */ 26523b5dd52aSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 26533b5dd52aSJames Smart if (!dd_data) { 26543b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 26553b5dd52aSJames Smart "2727 Failed allocation of dd_data\n"); 26567a470277SJames Smart rc = -ENOMEM; 26577a470277SJames Smart goto job_done; 26583b5dd52aSJames Smart } 26593b5dd52aSJames Smart 266049198b37SJames Smart mb = kzalloc(BSG_MBOX_SIZE, GFP_KERNEL); 26613b5dd52aSJames Smart if (!mb) { 26627a470277SJames Smart rc = -ENOMEM; 26637a470277SJames Smart goto job_done; 26643b5dd52aSJames Smart } 26653b5dd52aSJames Smart 26663b5dd52aSJames Smart pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); 26673b5dd52aSJames Smart if (!pmboxq) { 26687a470277SJames Smart rc = -ENOMEM; 26697a470277SJames Smart goto job_done; 26703b5dd52aSJames Smart } 26717a470277SJames Smart memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); 26723b5dd52aSJames Smart 26733b5dd52aSJames Smart size = job->request_payload.payload_len; 26743b5dd52aSJames Smart sg_copy_to_buffer(job->request_payload.sg_list, 26753b5dd52aSJames Smart job->request_payload.sg_cnt, 26763b5dd52aSJames Smart mb, size); 26773b5dd52aSJames Smart 26783b5dd52aSJames Smart rc = lpfc_bsg_check_cmd_access(phba, mb, vport); 26797a470277SJames Smart if (rc != 0) 26807a470277SJames Smart goto job_done; /* must be negative */ 26813b5dd52aSJames Smart 26823b5dd52aSJames Smart pmb = &pmboxq->u.mb; 26833b5dd52aSJames Smart memcpy(pmb, mb, sizeof(*pmb)); 26843b5dd52aSJames Smart pmb->mbxOwner = OWN_HOST; 26853b5dd52aSJames Smart pmboxq->vport = vport; 26863b5dd52aSJames Smart 2687c7495937SJames Smart /* If HBA encountered an error attention, allow only DUMP 2688c7495937SJames Smart * or RESTART mailbox commands until the HBA is restarted. 2689c7495937SJames Smart */ 2690c7495937SJames Smart if (phba->pport->stopped && 2691c7495937SJames Smart pmb->mbxCommand != MBX_DUMP_MEMORY && 2692c7495937SJames Smart pmb->mbxCommand != MBX_RESTART && 2693c7495937SJames Smart pmb->mbxCommand != MBX_WRITE_VPARMS && 2694c7495937SJames Smart pmb->mbxCommand != MBX_WRITE_WWN) 2695c7495937SJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, 2696c7495937SJames Smart "2797 mbox: Issued mailbox cmd " 2697c7495937SJames Smart "0x%x while in stopped state.\n", 2698c7495937SJames Smart pmb->mbxCommand); 2699c7495937SJames Smart 2700c7495937SJames Smart /* Don't allow mailbox commands to be sent when blocked 2701c7495937SJames Smart * or when in the middle of discovery 2702c7495937SJames Smart */ 2703c7495937SJames Smart if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { 2704c7495937SJames Smart rc = -EAGAIN; 2705c7495937SJames Smart goto job_done; 2706c7495937SJames Smart } 2707c7495937SJames Smart 27087a470277SJames Smart /* extended mailbox commands will need an extended buffer */ 2709c7495937SJames Smart if (mbox_req->inExtWLen || mbox_req->outExtWLen) { 27107a470277SJames Smart ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL); 27117a470277SJames Smart if (!ext) { 27127a470277SJames Smart rc = -ENOMEM; 27137a470277SJames Smart goto job_done; 27143b5dd52aSJames Smart } 27153b5dd52aSJames Smart 27167a470277SJames Smart /* any data for the device? */ 27177a470277SJames Smart if (mbox_req->inExtWLen) { 27187a470277SJames Smart from = (uint8_t *)mb; 27197a470277SJames Smart from += sizeof(MAILBOX_t); 27207a470277SJames Smart memcpy((uint8_t *)ext, from, 27217a470277SJames Smart mbox_req->inExtWLen * sizeof(uint32_t)); 27227a470277SJames Smart } 27237a470277SJames Smart 27247a470277SJames Smart pmboxq->context2 = ext; 27257a470277SJames Smart pmboxq->in_ext_byte_len = 27267a470277SJames Smart mbox_req->inExtWLen * sizeof(uint32_t); 27277a470277SJames Smart pmboxq->out_ext_byte_len = 2728c7495937SJames Smart mbox_req->outExtWLen * sizeof(uint32_t); 27297a470277SJames Smart pmboxq->mbox_offset_word = mbox_req->mbOffset; 27307a470277SJames Smart } 27317a470277SJames Smart 27327a470277SJames Smart /* biu diag will need a kernel buffer to transfer the data 27337a470277SJames Smart * allocate our own buffer and setup the mailbox command to 27347a470277SJames Smart * use ours 27357a470277SJames Smart */ 27367a470277SJames Smart if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { 2737c7495937SJames Smart uint32_t transmit_length = pmb->un.varWords[1]; 2738c7495937SJames Smart uint32_t receive_length = pmb->un.varWords[4]; 2739c7495937SJames Smart /* transmit length cannot be greater than receive length or 2740c7495937SJames Smart * mailbox extension size 2741c7495937SJames Smart */ 2742c7495937SJames Smart if ((transmit_length > receive_length) || 2743c7495937SJames Smart (transmit_length > MAILBOX_EXT_SIZE)) { 2744c7495937SJames Smart rc = -ERANGE; 2745c7495937SJames Smart goto job_done; 2746c7495937SJames Smart } 2747c7495937SJames Smart 27487a470277SJames Smart rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 27497a470277SJames Smart if (!rxbmp) { 27507a470277SJames Smart rc = -ENOMEM; 27517a470277SJames Smart goto job_done; 27527a470277SJames Smart } 27537a470277SJames Smart 27547a470277SJames Smart rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); 2755c7495937SJames Smart if (!rxbmp->virt) { 2756c7495937SJames Smart rc = -ENOMEM; 2757c7495937SJames Smart goto job_done; 2758c7495937SJames Smart } 2759c7495937SJames Smart 27607a470277SJames Smart INIT_LIST_HEAD(&rxbmp->list); 27617a470277SJames Smart rxbpl = (struct ulp_bde64 *) rxbmp->virt; 2762c7495937SJames Smart dmp = diag_cmd_data_alloc(phba, rxbpl, transmit_length, 0); 27637a470277SJames Smart if (!dmp) { 27647a470277SJames Smart rc = -ENOMEM; 27657a470277SJames Smart goto job_done; 27667a470277SJames Smart } 27677a470277SJames Smart 27687a470277SJames Smart INIT_LIST_HEAD(&dmp->dma.list); 27697a470277SJames Smart pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = 27707a470277SJames Smart putPaddrHigh(dmp->dma.phys); 27717a470277SJames Smart pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = 27727a470277SJames Smart putPaddrLow(dmp->dma.phys); 27737a470277SJames Smart 27747a470277SJames Smart pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = 27757a470277SJames Smart putPaddrHigh(dmp->dma.phys + 27767a470277SJames Smart pmb->un.varBIUdiag.un.s2. 27777a470277SJames Smart xmit_bde64.tus.f.bdeSize); 27787a470277SJames Smart pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = 27797a470277SJames Smart putPaddrLow(dmp->dma.phys + 27807a470277SJames Smart pmb->un.varBIUdiag.un.s2. 27817a470277SJames Smart xmit_bde64.tus.f.bdeSize); 2782c7495937SJames Smart 2783c7495937SJames Smart /* copy the transmit data found in the mailbox extension area */ 2784c7495937SJames Smart from = (uint8_t *)mb; 2785c7495937SJames Smart from += sizeof(MAILBOX_t); 2786c7495937SJames Smart memcpy((uint8_t *)dmp->dma.virt, from, transmit_length); 2787c7495937SJames Smart } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { 2788c7495937SJames Smart struct READ_EVENT_LOG_VAR *rdEventLog = 2789c7495937SJames Smart &pmb->un.varRdEventLog ; 2790c7495937SJames Smart uint32_t receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; 2791c7495937SJames Smart uint32_t mode = bf_get(lpfc_event_log, rdEventLog); 2792c7495937SJames Smart 2793c7495937SJames Smart /* receive length cannot be greater than mailbox 2794c7495937SJames Smart * extension size 2795c7495937SJames Smart */ 2796c7495937SJames Smart if (receive_length > MAILBOX_EXT_SIZE) { 2797c7495937SJames Smart rc = -ERANGE; 2798c7495937SJames Smart goto job_done; 2799c7495937SJames Smart } 2800c7495937SJames Smart 2801c7495937SJames Smart /* mode zero uses a bde like biu diags command */ 2802c7495937SJames Smart if (mode == 0) { 2803c7495937SJames Smart 2804c7495937SJames Smart /* rebuild the command for sli4 using our own buffers 2805c7495937SJames Smart * like we do for biu diags 2806c7495937SJames Smart */ 2807c7495937SJames Smart 2808c7495937SJames Smart rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 2809c7495937SJames Smart if (!rxbmp) { 2810c7495937SJames Smart rc = -ENOMEM; 2811c7495937SJames Smart goto job_done; 2812c7495937SJames Smart } 2813c7495937SJames Smart 2814c7495937SJames Smart rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); 2815c7495937SJames Smart rxbpl = (struct ulp_bde64 *) rxbmp->virt; 2816c7495937SJames Smart if (rxbpl) { 2817c7495937SJames Smart INIT_LIST_HEAD(&rxbmp->list); 2818c7495937SJames Smart dmp = diag_cmd_data_alloc(phba, rxbpl, 2819c7495937SJames Smart receive_length, 0); 2820c7495937SJames Smart } 2821c7495937SJames Smart 2822c7495937SJames Smart if (!dmp) { 2823c7495937SJames Smart rc = -ENOMEM; 2824c7495937SJames Smart goto job_done; 2825c7495937SJames Smart } 2826c7495937SJames Smart 2827c7495937SJames Smart INIT_LIST_HEAD(&dmp->dma.list); 2828c7495937SJames Smart pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys); 2829c7495937SJames Smart pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys); 2830c7495937SJames Smart } 2831c7495937SJames Smart } else if (phba->sli_rev == LPFC_SLI_REV4) { 2832c7495937SJames Smart if (pmb->mbxCommand == MBX_DUMP_MEMORY) { 2833c7495937SJames Smart /* rebuild the command for sli4 using our own buffers 2834c7495937SJames Smart * like we do for biu diags 2835c7495937SJames Smart */ 2836c7495937SJames Smart uint32_t receive_length = pmb->un.varWords[2]; 2837c7495937SJames Smart /* receive length cannot be greater than mailbox 2838c7495937SJames Smart * extension size 2839c7495937SJames Smart */ 2840c7495937SJames Smart if ((receive_length == 0) || 2841c7495937SJames Smart (receive_length > MAILBOX_EXT_SIZE)) { 2842c7495937SJames Smart rc = -ERANGE; 2843c7495937SJames Smart goto job_done; 2844c7495937SJames Smart } 2845c7495937SJames Smart 2846c7495937SJames Smart rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 2847c7495937SJames Smart if (!rxbmp) { 2848c7495937SJames Smart rc = -ENOMEM; 2849c7495937SJames Smart goto job_done; 2850c7495937SJames Smart } 2851c7495937SJames Smart 2852c7495937SJames Smart rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); 2853c7495937SJames Smart if (!rxbmp->virt) { 2854c7495937SJames Smart rc = -ENOMEM; 2855c7495937SJames Smart goto job_done; 2856c7495937SJames Smart } 2857c7495937SJames Smart 2858c7495937SJames Smart INIT_LIST_HEAD(&rxbmp->list); 2859c7495937SJames Smart rxbpl = (struct ulp_bde64 *) rxbmp->virt; 2860c7495937SJames Smart dmp = diag_cmd_data_alloc(phba, rxbpl, receive_length, 2861c7495937SJames Smart 0); 2862c7495937SJames Smart if (!dmp) { 2863c7495937SJames Smart rc = -ENOMEM; 2864c7495937SJames Smart goto job_done; 2865c7495937SJames Smart } 2866c7495937SJames Smart 2867c7495937SJames Smart INIT_LIST_HEAD(&dmp->dma.list); 2868c7495937SJames Smart pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys); 2869c7495937SJames Smart pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys); 2870c7495937SJames Smart } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && 2871c7495937SJames Smart pmb->un.varUpdateCfg.co) { 2872c7495937SJames Smart struct ulp_bde64 *bde = 2873c7495937SJames Smart (struct ulp_bde64 *)&pmb->un.varWords[4]; 2874c7495937SJames Smart 2875c7495937SJames Smart /* bde size cannot be greater than mailbox ext size */ 2876c7495937SJames Smart if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) { 2877c7495937SJames Smart rc = -ERANGE; 2878c7495937SJames Smart goto job_done; 2879c7495937SJames Smart } 2880c7495937SJames Smart 2881c7495937SJames Smart rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 2882c7495937SJames Smart if (!rxbmp) { 2883c7495937SJames Smart rc = -ENOMEM; 2884c7495937SJames Smart goto job_done; 2885c7495937SJames Smart } 2886c7495937SJames Smart 2887c7495937SJames Smart rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); 2888c7495937SJames Smart if (!rxbmp->virt) { 2889c7495937SJames Smart rc = -ENOMEM; 2890c7495937SJames Smart goto job_done; 2891c7495937SJames Smart } 2892c7495937SJames Smart 2893c7495937SJames Smart INIT_LIST_HEAD(&rxbmp->list); 2894c7495937SJames Smart rxbpl = (struct ulp_bde64 *) rxbmp->virt; 2895c7495937SJames Smart dmp = diag_cmd_data_alloc(phba, rxbpl, 2896c7495937SJames Smart bde->tus.f.bdeSize, 0); 2897c7495937SJames Smart if (!dmp) { 2898c7495937SJames Smart rc = -ENOMEM; 2899c7495937SJames Smart goto job_done; 2900c7495937SJames Smart } 2901c7495937SJames Smart 2902c7495937SJames Smart INIT_LIST_HEAD(&dmp->dma.list); 2903c7495937SJames Smart bde->addrHigh = putPaddrHigh(dmp->dma.phys); 2904c7495937SJames Smart bde->addrLow = putPaddrLow(dmp->dma.phys); 2905c7495937SJames Smart 2906c7495937SJames Smart /* copy the transmit data found in the mailbox 2907c7495937SJames Smart * extension area 2908c7495937SJames Smart */ 2909c7495937SJames Smart from = (uint8_t *)mb; 2910c7495937SJames Smart from += sizeof(MAILBOX_t); 2911c7495937SJames Smart memcpy((uint8_t *)dmp->dma.virt, from, 2912c7495937SJames Smart bde->tus.f.bdeSize); 2913515e0aa2SJames Smart } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { 2914515e0aa2SJames Smart struct lpfc_mbx_nembed_cmd *nembed_sge; 2915515e0aa2SJames Smart struct mbox_header *header; 2916515e0aa2SJames Smart uint32_t receive_length; 2917515e0aa2SJames Smart 2918515e0aa2SJames Smart /* rebuild the command for sli4 using our own buffers 2919515e0aa2SJames Smart * like we do for biu diags 2920515e0aa2SJames Smart */ 2921515e0aa2SJames Smart header = (struct mbox_header *)&pmb->un.varWords[0]; 2922515e0aa2SJames Smart nembed_sge = (struct lpfc_mbx_nembed_cmd *) 2923515e0aa2SJames Smart &pmb->un.varWords[0]; 2924515e0aa2SJames Smart receive_length = nembed_sge->sge[0].length; 2925515e0aa2SJames Smart 2926515e0aa2SJames Smart /* receive length cannot be greater than mailbox 2927515e0aa2SJames Smart * extension size 2928515e0aa2SJames Smart */ 2929515e0aa2SJames Smart if ((receive_length == 0) || 2930515e0aa2SJames Smart (receive_length > MAILBOX_EXT_SIZE)) { 2931515e0aa2SJames Smart rc = -ERANGE; 2932515e0aa2SJames Smart goto job_done; 2933515e0aa2SJames Smart } 2934515e0aa2SJames Smart 2935515e0aa2SJames Smart rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 2936515e0aa2SJames Smart if (!rxbmp) { 2937515e0aa2SJames Smart rc = -ENOMEM; 2938515e0aa2SJames Smart goto job_done; 2939515e0aa2SJames Smart } 2940515e0aa2SJames Smart 2941515e0aa2SJames Smart rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); 2942515e0aa2SJames Smart if (!rxbmp->virt) { 2943515e0aa2SJames Smart rc = -ENOMEM; 2944515e0aa2SJames Smart goto job_done; 2945515e0aa2SJames Smart } 2946515e0aa2SJames Smart 2947515e0aa2SJames Smart INIT_LIST_HEAD(&rxbmp->list); 2948515e0aa2SJames Smart rxbpl = (struct ulp_bde64 *) rxbmp->virt; 2949515e0aa2SJames Smart dmp = diag_cmd_data_alloc(phba, rxbpl, receive_length, 2950515e0aa2SJames Smart 0); 2951515e0aa2SJames Smart if (!dmp) { 2952515e0aa2SJames Smart rc = -ENOMEM; 2953515e0aa2SJames Smart goto job_done; 2954515e0aa2SJames Smart } 2955515e0aa2SJames Smart 2956515e0aa2SJames Smart INIT_LIST_HEAD(&dmp->dma.list); 2957515e0aa2SJames Smart nembed_sge->sge[0].pa_hi = putPaddrHigh(dmp->dma.phys); 2958515e0aa2SJames Smart nembed_sge->sge[0].pa_lo = putPaddrLow(dmp->dma.phys); 2959515e0aa2SJames Smart /* copy the transmit data found in the mailbox 2960515e0aa2SJames Smart * extension area 2961515e0aa2SJames Smart */ 2962515e0aa2SJames Smart from = (uint8_t *)mb; 2963515e0aa2SJames Smart from += sizeof(MAILBOX_t); 2964515e0aa2SJames Smart memcpy((uint8_t *)dmp->dma.virt, from, 2965515e0aa2SJames Smart header->cfg_mhdr.payload_length); 2966c7495937SJames Smart } 2967c7495937SJames Smart } 2968c7495937SJames Smart 29697a470277SJames Smart dd_data->context_un.mbox.rxbmp = rxbmp; 29707a470277SJames Smart dd_data->context_un.mbox.dmp = dmp; 29713b5dd52aSJames Smart 29723b5dd52aSJames Smart /* setup wake call as IOCB callback */ 29733b5dd52aSJames Smart pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait; 29747a470277SJames Smart 29753b5dd52aSJames Smart /* setup context field to pass wait_queue pointer to wake function */ 29763b5dd52aSJames Smart pmboxq->context1 = dd_data; 29773b5dd52aSJames Smart dd_data->type = TYPE_MBOX; 29783b5dd52aSJames Smart dd_data->context_un.mbox.pmboxq = pmboxq; 29793b5dd52aSJames Smart dd_data->context_un.mbox.mb = mb; 29803b5dd52aSJames Smart dd_data->context_un.mbox.set_job = job; 29817a470277SJames Smart dd_data->context_un.mbox.ext = ext; 29827a470277SJames Smart dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset; 29837a470277SJames Smart dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen; 2984c7495937SJames Smart dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen; 29853b5dd52aSJames Smart job->dd_data = dd_data; 29867a470277SJames Smart 29877a470277SJames Smart if ((vport->fc_flag & FC_OFFLINE_MODE) || 29887a470277SJames Smart (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { 29897a470277SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); 29907a470277SJames Smart if (rc != MBX_SUCCESS) { 29917a470277SJames Smart rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; 29927a470277SJames Smart goto job_done; 29933b5dd52aSJames Smart } 29943b5dd52aSJames Smart 29957a470277SJames Smart /* job finished, copy the data */ 29967a470277SJames Smart memcpy(mb, pmb, sizeof(*pmb)); 29977a470277SJames Smart job->reply->reply_payload_rcv_len = 29987a470277SJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 29997a470277SJames Smart job->reply_payload.sg_cnt, 30007a470277SJames Smart mb, size); 30017a470277SJames Smart /* not waiting mbox already done */ 30027a470277SJames Smart rc = 0; 30037a470277SJames Smart goto job_done; 30047a470277SJames Smart } 30057a470277SJames Smart 30067a470277SJames Smart rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); 30077a470277SJames Smart if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) 30087a470277SJames Smart return 1; /* job started */ 30097a470277SJames Smart 30107a470277SJames Smart job_done: 30117a470277SJames Smart /* common exit for error or job completed inline */ 30127a470277SJames Smart kfree(mb); 30137a470277SJames Smart if (pmboxq) 30147a470277SJames Smart mempool_free(pmboxq, phba->mbox_mem_pool); 30157a470277SJames Smart kfree(ext); 30167a470277SJames Smart if (dmp) { 30177a470277SJames Smart dma_free_coherent(&phba->pcidev->dev, 30187a470277SJames Smart dmp->size, dmp->dma.virt, 30197a470277SJames Smart dmp->dma.phys); 30207a470277SJames Smart kfree(dmp); 30217a470277SJames Smart } 30227a470277SJames Smart if (rxbmp) { 30237a470277SJames Smart lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); 30247a470277SJames Smart kfree(rxbmp); 30257a470277SJames Smart } 30267a470277SJames Smart kfree(dd_data); 30277a470277SJames Smart 30287a470277SJames Smart return rc; 30293b5dd52aSJames Smart } 30303b5dd52aSJames Smart 30313b5dd52aSJames Smart /** 30323b5dd52aSJames Smart * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command 30333b5dd52aSJames Smart * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX. 30343b5dd52aSJames Smart **/ 30353b5dd52aSJames Smart static int 30363b5dd52aSJames Smart lpfc_bsg_mbox_cmd(struct fc_bsg_job *job) 30373b5dd52aSJames Smart { 30383b5dd52aSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 30393b5dd52aSJames Smart struct lpfc_hba *phba = vport->phba; 30403b5dd52aSJames Smart int rc = 0; 30413b5dd52aSJames Smart 30423b5dd52aSJames Smart /* in case no data is transferred */ 30433b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 0; 30443b5dd52aSJames Smart if (job->request_len < 30453b5dd52aSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) { 30463b5dd52aSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 30473b5dd52aSJames Smart "2737 Received MBOX_REQ request below " 30483b5dd52aSJames Smart "minimum size\n"); 30493b5dd52aSJames Smart rc = -EINVAL; 30503b5dd52aSJames Smart goto job_error; 30513b5dd52aSJames Smart } 30523b5dd52aSJames Smart 305349198b37SJames Smart if (job->request_payload.payload_len != BSG_MBOX_SIZE) { 30543b5dd52aSJames Smart rc = -EINVAL; 30553b5dd52aSJames Smart goto job_error; 30563b5dd52aSJames Smart } 30573b5dd52aSJames Smart 305849198b37SJames Smart if (job->reply_payload.payload_len != BSG_MBOX_SIZE) { 30597a470277SJames Smart rc = -EINVAL; 30607a470277SJames Smart goto job_error; 30617a470277SJames Smart } 30627a470277SJames Smart 30633b5dd52aSJames Smart if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { 30643b5dd52aSJames Smart rc = -EAGAIN; 30653b5dd52aSJames Smart goto job_error; 30663b5dd52aSJames Smart } 30673b5dd52aSJames Smart 30683b5dd52aSJames Smart rc = lpfc_bsg_issue_mbox(phba, job, vport); 30693b5dd52aSJames Smart 30703b5dd52aSJames Smart job_error: 30713b5dd52aSJames Smart if (rc == 0) { 30723b5dd52aSJames Smart /* job done */ 30733b5dd52aSJames Smart job->reply->result = 0; 30743b5dd52aSJames Smart job->dd_data = NULL; 30753b5dd52aSJames Smart job->job_done(job); 30763b5dd52aSJames Smart } else if (rc == 1) 30773b5dd52aSJames Smart /* job submitted, will complete later*/ 30783b5dd52aSJames Smart rc = 0; /* return zero, no error */ 30793b5dd52aSJames Smart else { 30803b5dd52aSJames Smart /* some error occurred */ 30813b5dd52aSJames Smart job->reply->result = rc; 30823b5dd52aSJames Smart job->dd_data = NULL; 30833b5dd52aSJames Smart } 30843b5dd52aSJames Smart 30853b5dd52aSJames Smart return rc; 30863b5dd52aSJames Smart } 30873b5dd52aSJames Smart 30883b5dd52aSJames Smart /** 3089e2aed29fSJames Smart * lpfc_bsg_menlo_cmd_cmp - lpfc_menlo_cmd completion handler 3090e2aed29fSJames Smart * @phba: Pointer to HBA context object. 3091e2aed29fSJames Smart * @cmdiocbq: Pointer to command iocb. 3092e2aed29fSJames Smart * @rspiocbq: Pointer to response iocb. 3093e2aed29fSJames Smart * 3094e2aed29fSJames Smart * This function is the completion handler for iocbs issued using 3095e2aed29fSJames Smart * lpfc_menlo_cmd function. This function is called by the 3096e2aed29fSJames Smart * ring event handler function without any lock held. This function 3097e2aed29fSJames Smart * can be called from both worker thread context and interrupt 3098e2aed29fSJames Smart * context. This function also can be called from another thread which 3099e2aed29fSJames Smart * cleans up the SLI layer objects. 3100e2aed29fSJames Smart * This function copies the contents of the response iocb to the 3101e2aed29fSJames Smart * response iocb memory object provided by the caller of 3102e2aed29fSJames Smart * lpfc_sli_issue_iocb_wait and then wakes up the thread which 3103e2aed29fSJames Smart * sleeps for the iocb completion. 3104e2aed29fSJames Smart **/ 3105e2aed29fSJames Smart static void 3106e2aed29fSJames Smart lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba, 3107e2aed29fSJames Smart struct lpfc_iocbq *cmdiocbq, 3108e2aed29fSJames Smart struct lpfc_iocbq *rspiocbq) 3109e2aed29fSJames Smart { 3110e2aed29fSJames Smart struct bsg_job_data *dd_data; 3111e2aed29fSJames Smart struct fc_bsg_job *job; 3112e2aed29fSJames Smart IOCB_t *rsp; 3113e2aed29fSJames Smart struct lpfc_dmabuf *bmp; 3114e2aed29fSJames Smart struct lpfc_bsg_menlo *menlo; 3115e2aed29fSJames Smart unsigned long flags; 3116e2aed29fSJames Smart struct menlo_response *menlo_resp; 3117e2aed29fSJames Smart int rc = 0; 3118e2aed29fSJames Smart 3119e2aed29fSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 3120e2aed29fSJames Smart dd_data = cmdiocbq->context1; 3121e2aed29fSJames Smart if (!dd_data) { 3122e2aed29fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3123e2aed29fSJames Smart return; 3124e2aed29fSJames Smart } 3125e2aed29fSJames Smart 3126e2aed29fSJames Smart menlo = &dd_data->context_un.menlo; 3127e2aed29fSJames Smart job = menlo->set_job; 3128e2aed29fSJames Smart job->dd_data = NULL; /* so timeout handler does not reply */ 3129e2aed29fSJames Smart 31305989b8d4SJames Smart spin_lock(&phba->hbalock); 3131e2aed29fSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_WAKE; 3132e2aed29fSJames Smart if (cmdiocbq->context2 && rspiocbq) 3133e2aed29fSJames Smart memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, 3134e2aed29fSJames Smart &rspiocbq->iocb, sizeof(IOCB_t)); 31355989b8d4SJames Smart spin_unlock(&phba->hbalock); 3136e2aed29fSJames Smart 3137e2aed29fSJames Smart bmp = menlo->bmp; 3138e2aed29fSJames Smart rspiocbq = menlo->rspiocbq; 3139e2aed29fSJames Smart rsp = &rspiocbq->iocb; 3140e2aed29fSJames Smart 3141e2aed29fSJames Smart pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, 3142e2aed29fSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 3143e2aed29fSJames Smart pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, 3144e2aed29fSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 3145e2aed29fSJames Smart 3146e2aed29fSJames Smart /* always return the xri, this would be used in the case 3147e2aed29fSJames Smart * of a menlo download to allow the data to be sent as a continuation 3148e2aed29fSJames Smart * of the exchange. 3149e2aed29fSJames Smart */ 3150e2aed29fSJames Smart menlo_resp = (struct menlo_response *) 3151e2aed29fSJames Smart job->reply->reply_data.vendor_reply.vendor_rsp; 3152e2aed29fSJames Smart menlo_resp->xri = rsp->ulpContext; 3153e2aed29fSJames Smart if (rsp->ulpStatus) { 3154e2aed29fSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 3155e2aed29fSJames Smart switch (rsp->un.ulpWord[4] & 0xff) { 3156e2aed29fSJames Smart case IOERR_SEQUENCE_TIMEOUT: 3157e2aed29fSJames Smart rc = -ETIMEDOUT; 3158e2aed29fSJames Smart break; 3159e2aed29fSJames Smart case IOERR_INVALID_RPI: 3160e2aed29fSJames Smart rc = -EFAULT; 3161e2aed29fSJames Smart break; 3162e2aed29fSJames Smart default: 3163e2aed29fSJames Smart rc = -EACCES; 3164e2aed29fSJames Smart break; 3165e2aed29fSJames Smart } 3166e2aed29fSJames Smart } else 3167e2aed29fSJames Smart rc = -EACCES; 3168e2aed29fSJames Smart } else 3169e2aed29fSJames Smart job->reply->reply_payload_rcv_len = 3170e2aed29fSJames Smart rsp->un.genreq64.bdl.bdeSize; 3171e2aed29fSJames Smart 3172e2aed29fSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 3173e2aed29fSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 3174e2aed29fSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 3175e2aed29fSJames Smart kfree(bmp); 3176e2aed29fSJames Smart kfree(dd_data); 3177e2aed29fSJames Smart /* make error code available to userspace */ 3178e2aed29fSJames Smart job->reply->result = rc; 3179e2aed29fSJames Smart /* complete the job back to userspace */ 3180e2aed29fSJames Smart job->job_done(job); 3181e2aed29fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3182e2aed29fSJames Smart return; 3183e2aed29fSJames Smart } 3184e2aed29fSJames Smart 3185e2aed29fSJames Smart /** 3186e2aed29fSJames Smart * lpfc_menlo_cmd - send an ioctl for menlo hardware 3187e2aed29fSJames Smart * @job: fc_bsg_job to handle 3188e2aed29fSJames Smart * 3189e2aed29fSJames Smart * This function issues a gen request 64 CR ioctl for all menlo cmd requests, 3190e2aed29fSJames Smart * all the command completions will return the xri for the command. 3191e2aed29fSJames Smart * For menlo data requests a gen request 64 CX is used to continue the exchange 3192e2aed29fSJames Smart * supplied in the menlo request header xri field. 3193e2aed29fSJames Smart **/ 3194e2aed29fSJames Smart static int 3195e2aed29fSJames Smart lpfc_menlo_cmd(struct fc_bsg_job *job) 3196e2aed29fSJames Smart { 3197e2aed29fSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 3198e2aed29fSJames Smart struct lpfc_hba *phba = vport->phba; 3199e2aed29fSJames Smart struct lpfc_iocbq *cmdiocbq, *rspiocbq; 3200e2aed29fSJames Smart IOCB_t *cmd, *rsp; 3201e2aed29fSJames Smart int rc = 0; 3202e2aed29fSJames Smart struct menlo_command *menlo_cmd; 3203e2aed29fSJames Smart struct menlo_response *menlo_resp; 3204e2aed29fSJames Smart struct lpfc_dmabuf *bmp = NULL; 3205e2aed29fSJames Smart int request_nseg; 3206e2aed29fSJames Smart int reply_nseg; 3207e2aed29fSJames Smart struct scatterlist *sgel = NULL; 3208e2aed29fSJames Smart int numbde; 3209e2aed29fSJames Smart dma_addr_t busaddr; 3210e2aed29fSJames Smart struct bsg_job_data *dd_data; 3211e2aed29fSJames Smart struct ulp_bde64 *bpl = NULL; 3212e2aed29fSJames Smart 3213e2aed29fSJames Smart /* in case no data is returned return just the return code */ 3214e2aed29fSJames Smart job->reply->reply_payload_rcv_len = 0; 3215e2aed29fSJames Smart 3216e2aed29fSJames Smart if (job->request_len < 3217e2aed29fSJames Smart sizeof(struct fc_bsg_request) + 3218e2aed29fSJames Smart sizeof(struct menlo_command)) { 3219e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 3220e2aed29fSJames Smart "2784 Received MENLO_CMD request below " 3221e2aed29fSJames Smart "minimum size\n"); 3222e2aed29fSJames Smart rc = -ERANGE; 3223e2aed29fSJames Smart goto no_dd_data; 3224e2aed29fSJames Smart } 3225e2aed29fSJames Smart 3226e2aed29fSJames Smart if (job->reply_len < 3227e2aed29fSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct menlo_response)) { 3228e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 3229e2aed29fSJames Smart "2785 Received MENLO_CMD reply below " 3230e2aed29fSJames Smart "minimum size\n"); 3231e2aed29fSJames Smart rc = -ERANGE; 3232e2aed29fSJames Smart goto no_dd_data; 3233e2aed29fSJames Smart } 3234e2aed29fSJames Smart 3235e2aed29fSJames Smart if (!(phba->menlo_flag & HBA_MENLO_SUPPORT)) { 3236e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 3237e2aed29fSJames Smart "2786 Adapter does not support menlo " 3238e2aed29fSJames Smart "commands\n"); 3239e2aed29fSJames Smart rc = -EPERM; 3240e2aed29fSJames Smart goto no_dd_data; 3241e2aed29fSJames Smart } 3242e2aed29fSJames Smart 3243e2aed29fSJames Smart menlo_cmd = (struct menlo_command *) 3244e2aed29fSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 3245e2aed29fSJames Smart 3246e2aed29fSJames Smart menlo_resp = (struct menlo_response *) 3247e2aed29fSJames Smart job->reply->reply_data.vendor_reply.vendor_rsp; 3248e2aed29fSJames Smart 3249e2aed29fSJames Smart /* allocate our bsg tracking structure */ 3250e2aed29fSJames Smart dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); 3251e2aed29fSJames Smart if (!dd_data) { 3252e2aed29fSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 3253e2aed29fSJames Smart "2787 Failed allocation of dd_data\n"); 3254e2aed29fSJames Smart rc = -ENOMEM; 3255e2aed29fSJames Smart goto no_dd_data; 3256e2aed29fSJames Smart } 3257e2aed29fSJames Smart 3258e2aed29fSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 3259e2aed29fSJames Smart if (!bmp) { 3260e2aed29fSJames Smart rc = -ENOMEM; 3261e2aed29fSJames Smart goto free_dd; 3262e2aed29fSJames Smart } 3263e2aed29fSJames Smart 3264e2aed29fSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 3265e2aed29fSJames Smart if (!cmdiocbq) { 3266e2aed29fSJames Smart rc = -ENOMEM; 3267e2aed29fSJames Smart goto free_bmp; 3268e2aed29fSJames Smart } 3269e2aed29fSJames Smart 3270e2aed29fSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 3271e2aed29fSJames Smart if (!rspiocbq) { 3272e2aed29fSJames Smart rc = -ENOMEM; 3273e2aed29fSJames Smart goto free_cmdiocbq; 3274e2aed29fSJames Smart } 3275e2aed29fSJames Smart 3276e2aed29fSJames Smart rsp = &rspiocbq->iocb; 3277e2aed29fSJames Smart 3278e2aed29fSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 3279e2aed29fSJames Smart if (!bmp->virt) { 3280e2aed29fSJames Smart rc = -ENOMEM; 3281e2aed29fSJames Smart goto free_rspiocbq; 3282e2aed29fSJames Smart } 3283e2aed29fSJames Smart 3284e2aed29fSJames Smart INIT_LIST_HEAD(&bmp->list); 3285e2aed29fSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 3286e2aed29fSJames Smart request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, 3287e2aed29fSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 3288e2aed29fSJames Smart for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { 3289e2aed29fSJames Smart busaddr = sg_dma_address(sgel); 3290e2aed29fSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; 3291e2aed29fSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 3292e2aed29fSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 3293e2aed29fSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 3294e2aed29fSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 3295e2aed29fSJames Smart bpl++; 3296e2aed29fSJames Smart } 3297e2aed29fSJames Smart 3298e2aed29fSJames Smart reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list, 3299e2aed29fSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 3300e2aed29fSJames Smart for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) { 3301e2aed29fSJames Smart busaddr = sg_dma_address(sgel); 3302e2aed29fSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 3303e2aed29fSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 3304e2aed29fSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 3305e2aed29fSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 3306e2aed29fSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 3307e2aed29fSJames Smart bpl++; 3308e2aed29fSJames Smart } 3309e2aed29fSJames Smart 3310e2aed29fSJames Smart cmd = &cmdiocbq->iocb; 3311e2aed29fSJames Smart cmd->un.genreq64.bdl.ulpIoTag32 = 0; 3312e2aed29fSJames Smart cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 3313e2aed29fSJames Smart cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); 3314e2aed29fSJames Smart cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 3315e2aed29fSJames Smart cmd->un.genreq64.bdl.bdeSize = 3316e2aed29fSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 3317e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); 3318e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Dfctl = 0; 3319e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CMD; 3320e2aed29fSJames Smart cmd->un.genreq64.w5.hcsw.Type = MENLO_TRANSPORT_TYPE; /* 0xfe */ 3321e2aed29fSJames Smart cmd->ulpBdeCount = 1; 3322e2aed29fSJames Smart cmd->ulpClass = CLASS3; 3323e2aed29fSJames Smart cmd->ulpOwner = OWN_CHIP; 3324e2aed29fSJames Smart cmd->ulpLe = 1; /* Limited Edition */ 3325e2aed29fSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 3326e2aed29fSJames Smart cmdiocbq->vport = phba->pport; 3327e2aed29fSJames Smart /* We want the firmware to timeout before we do */ 3328e2aed29fSJames Smart cmd->ulpTimeout = MENLO_TIMEOUT - 5; 3329e2aed29fSJames Smart cmdiocbq->context3 = bmp; 3330e2aed29fSJames Smart cmdiocbq->context2 = rspiocbq; 3331e2aed29fSJames Smart cmdiocbq->iocb_cmpl = lpfc_bsg_menlo_cmd_cmp; 3332e2aed29fSJames Smart cmdiocbq->context1 = dd_data; 3333e2aed29fSJames Smart cmdiocbq->context2 = rspiocbq; 3334e2aed29fSJames Smart if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) { 3335e2aed29fSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CR; 3336e2aed29fSJames Smart cmd->ulpPU = MENLO_PU; /* 3 */ 3337e2aed29fSJames Smart cmd->un.ulpWord[4] = MENLO_DID; /* 0x0000FC0E */ 3338e2aed29fSJames Smart cmd->ulpContext = MENLO_CONTEXT; /* 0 */ 3339e2aed29fSJames Smart } else { 3340e2aed29fSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CX; 3341e2aed29fSJames Smart cmd->ulpPU = 1; 3342e2aed29fSJames Smart cmd->un.ulpWord[4] = 0; 3343e2aed29fSJames Smart cmd->ulpContext = menlo_cmd->xri; 3344e2aed29fSJames Smart } 3345e2aed29fSJames Smart 3346e2aed29fSJames Smart dd_data->type = TYPE_MENLO; 3347e2aed29fSJames Smart dd_data->context_un.menlo.cmdiocbq = cmdiocbq; 3348e2aed29fSJames Smart dd_data->context_un.menlo.rspiocbq = rspiocbq; 3349e2aed29fSJames Smart dd_data->context_un.menlo.set_job = job; 3350e2aed29fSJames Smart dd_data->context_un.menlo.bmp = bmp; 3351e2aed29fSJames Smart 3352e2aed29fSJames Smart rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 3353e2aed29fSJames Smart MENLO_TIMEOUT - 5); 3354e2aed29fSJames Smart if (rc == IOCB_SUCCESS) 3355e2aed29fSJames Smart return 0; /* done for now */ 3356e2aed29fSJames Smart 3357e2aed29fSJames Smart /* iocb failed so cleanup */ 3358e2aed29fSJames Smart pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, 3359e2aed29fSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 3360e2aed29fSJames Smart pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, 3361e2aed29fSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 3362e2aed29fSJames Smart 3363e2aed29fSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 3364e2aed29fSJames Smart 3365e2aed29fSJames Smart free_rspiocbq: 3366e2aed29fSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 3367e2aed29fSJames Smart free_cmdiocbq: 3368e2aed29fSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 3369e2aed29fSJames Smart free_bmp: 3370e2aed29fSJames Smart kfree(bmp); 3371e2aed29fSJames Smart free_dd: 3372e2aed29fSJames Smart kfree(dd_data); 3373e2aed29fSJames Smart no_dd_data: 3374e2aed29fSJames Smart /* make error code available to userspace */ 3375e2aed29fSJames Smart job->reply->result = rc; 3376e2aed29fSJames Smart job->dd_data = NULL; 3377e2aed29fSJames Smart return rc; 3378e2aed29fSJames Smart } 3379e2aed29fSJames Smart /** 3380f1c3b0fcSJames Smart * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job 3381f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 33823b5dd52aSJames Smart **/ 3383f1c3b0fcSJames Smart static int 3384f1c3b0fcSJames Smart lpfc_bsg_hst_vendor(struct fc_bsg_job *job) 3385f1c3b0fcSJames Smart { 3386f1c3b0fcSJames Smart int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; 33874cc0e56eSJames Smart int rc; 3388f1c3b0fcSJames Smart 3389f1c3b0fcSJames Smart switch (command) { 3390f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_SET_CT_EVENT: 33914cc0e56eSJames Smart rc = lpfc_bsg_hba_set_event(job); 3392f1c3b0fcSJames Smart break; 3393f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_GET_CT_EVENT: 33944cc0e56eSJames Smart rc = lpfc_bsg_hba_get_event(job); 3395f1c3b0fcSJames Smart break; 33963b5dd52aSJames Smart case LPFC_BSG_VENDOR_SEND_MGMT_RESP: 33973b5dd52aSJames Smart rc = lpfc_bsg_send_mgmt_rsp(job); 33983b5dd52aSJames Smart break; 33993b5dd52aSJames Smart case LPFC_BSG_VENDOR_DIAG_MODE: 34003b5dd52aSJames Smart rc = lpfc_bsg_diag_mode(job); 34013b5dd52aSJames Smart break; 34023b5dd52aSJames Smart case LPFC_BSG_VENDOR_DIAG_TEST: 34033b5dd52aSJames Smart rc = lpfc_bsg_diag_test(job); 34043b5dd52aSJames Smart break; 34053b5dd52aSJames Smart case LPFC_BSG_VENDOR_GET_MGMT_REV: 34063b5dd52aSJames Smart rc = lpfc_bsg_get_dfc_rev(job); 34073b5dd52aSJames Smart break; 34083b5dd52aSJames Smart case LPFC_BSG_VENDOR_MBOX: 34093b5dd52aSJames Smart rc = lpfc_bsg_mbox_cmd(job); 34103b5dd52aSJames Smart break; 3411e2aed29fSJames Smart case LPFC_BSG_VENDOR_MENLO_CMD: 3412e2aed29fSJames Smart case LPFC_BSG_VENDOR_MENLO_DATA: 3413e2aed29fSJames Smart rc = lpfc_menlo_cmd(job); 3414e2aed29fSJames Smart break; 3415f1c3b0fcSJames Smart default: 34164cc0e56eSJames Smart rc = -EINVAL; 34174cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 0; 34184cc0e56eSJames Smart /* make error code available to userspace */ 34194cc0e56eSJames Smart job->reply->result = rc; 34204cc0e56eSJames Smart break; 3421f1c3b0fcSJames Smart } 34224cc0e56eSJames Smart 34234cc0e56eSJames Smart return rc; 3424f1c3b0fcSJames Smart } 3425f1c3b0fcSJames Smart 3426f1c3b0fcSJames Smart /** 3427f1c3b0fcSJames Smart * lpfc_bsg_request - handle a bsg request from the FC transport 3428f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 34293b5dd52aSJames Smart **/ 3430f1c3b0fcSJames Smart int 3431f1c3b0fcSJames Smart lpfc_bsg_request(struct fc_bsg_job *job) 3432f1c3b0fcSJames Smart { 3433f1c3b0fcSJames Smart uint32_t msgcode; 34344cc0e56eSJames Smart int rc; 3435f1c3b0fcSJames Smart 3436f1c3b0fcSJames Smart msgcode = job->request->msgcode; 3437f1c3b0fcSJames Smart switch (msgcode) { 3438f1c3b0fcSJames Smart case FC_BSG_HST_VENDOR: 3439f1c3b0fcSJames Smart rc = lpfc_bsg_hst_vendor(job); 3440f1c3b0fcSJames Smart break; 3441f1c3b0fcSJames Smart case FC_BSG_RPT_ELS: 3442f1c3b0fcSJames Smart rc = lpfc_bsg_rport_els(job); 3443f1c3b0fcSJames Smart break; 3444f1c3b0fcSJames Smart case FC_BSG_RPT_CT: 34454cc0e56eSJames Smart rc = lpfc_bsg_send_mgmt_cmd(job); 3446f1c3b0fcSJames Smart break; 3447f1c3b0fcSJames Smart default: 34484cc0e56eSJames Smart rc = -EINVAL; 34494cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 0; 34504cc0e56eSJames Smart /* make error code available to userspace */ 34514cc0e56eSJames Smart job->reply->result = rc; 3452f1c3b0fcSJames Smart break; 3453f1c3b0fcSJames Smart } 3454f1c3b0fcSJames Smart 3455f1c3b0fcSJames Smart return rc; 3456f1c3b0fcSJames Smart } 3457f1c3b0fcSJames Smart 3458f1c3b0fcSJames Smart /** 3459f1c3b0fcSJames Smart * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport 3460f1c3b0fcSJames Smart * @job: fc_bsg_job that has timed out 3461f1c3b0fcSJames Smart * 3462f1c3b0fcSJames Smart * This function just aborts the job's IOCB. The aborted IOCB will return to 3463f1c3b0fcSJames Smart * the waiting function which will handle passing the error back to userspace 34643b5dd52aSJames Smart **/ 3465f1c3b0fcSJames Smart int 3466f1c3b0fcSJames Smart lpfc_bsg_timeout(struct fc_bsg_job *job) 3467f1c3b0fcSJames Smart { 3468f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 3469f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 34704cc0e56eSJames Smart struct lpfc_iocbq *cmdiocb; 34714cc0e56eSJames Smart struct lpfc_bsg_event *evt; 34724cc0e56eSJames Smart struct lpfc_bsg_iocb *iocb; 34733b5dd52aSJames Smart struct lpfc_bsg_mbox *mbox; 3474e2aed29fSJames Smart struct lpfc_bsg_menlo *menlo; 3475f1c3b0fcSJames Smart struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; 34764cc0e56eSJames Smart struct bsg_job_data *dd_data; 34774cc0e56eSJames Smart unsigned long flags; 3478f1c3b0fcSJames Smart 34794cc0e56eSJames Smart spin_lock_irqsave(&phba->ct_ev_lock, flags); 34804cc0e56eSJames Smart dd_data = (struct bsg_job_data *)job->dd_data; 34814cc0e56eSJames Smart /* timeout and completion crossed paths if no dd_data */ 34824cc0e56eSJames Smart if (!dd_data) { 34834cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 34844cc0e56eSJames Smart return 0; 34854cc0e56eSJames Smart } 34864cc0e56eSJames Smart 34874cc0e56eSJames Smart switch (dd_data->type) { 34884cc0e56eSJames Smart case TYPE_IOCB: 34894cc0e56eSJames Smart iocb = &dd_data->context_un.iocb; 34904cc0e56eSJames Smart cmdiocb = iocb->cmdiocbq; 34914cc0e56eSJames Smart /* hint to completion handler that the job timed out */ 34924cc0e56eSJames Smart job->reply->result = -EAGAIN; 34934cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 34944cc0e56eSJames Smart /* this will call our completion handler */ 34954cc0e56eSJames Smart spin_lock_irq(&phba->hbalock); 3496f1c3b0fcSJames Smart lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); 34974cc0e56eSJames Smart spin_unlock_irq(&phba->hbalock); 34984cc0e56eSJames Smart break; 34994cc0e56eSJames Smart case TYPE_EVT: 35004cc0e56eSJames Smart evt = dd_data->context_un.evt; 35014cc0e56eSJames Smart /* this event has no job anymore */ 35024cc0e56eSJames Smart evt->set_job = NULL; 35034cc0e56eSJames Smart job->dd_data = NULL; 35044cc0e56eSJames Smart job->reply->reply_payload_rcv_len = 0; 35054cc0e56eSJames Smart /* Return -EAGAIN which is our way of signallying the 35064cc0e56eSJames Smart * app to retry. 35074cc0e56eSJames Smart */ 35084cc0e56eSJames Smart job->reply->result = -EAGAIN; 35094cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 35104cc0e56eSJames Smart job->job_done(job); 35114cc0e56eSJames Smart break; 35123b5dd52aSJames Smart case TYPE_MBOX: 35133b5dd52aSJames Smart mbox = &dd_data->context_un.mbox; 35143b5dd52aSJames Smart /* this mbox has no job anymore */ 35153b5dd52aSJames Smart mbox->set_job = NULL; 35163b5dd52aSJames Smart job->dd_data = NULL; 35173b5dd52aSJames Smart job->reply->reply_payload_rcv_len = 0; 35183b5dd52aSJames Smart job->reply->result = -EAGAIN; 35197a470277SJames Smart /* the mbox completion handler can now be run */ 35203b5dd52aSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 35213b5dd52aSJames Smart job->job_done(job); 35223b5dd52aSJames Smart break; 3523e2aed29fSJames Smart case TYPE_MENLO: 3524e2aed29fSJames Smart menlo = &dd_data->context_un.menlo; 3525e2aed29fSJames Smart cmdiocb = menlo->cmdiocbq; 3526e2aed29fSJames Smart /* hint to completion handler that the job timed out */ 3527e2aed29fSJames Smart job->reply->result = -EAGAIN; 3528e2aed29fSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 3529e2aed29fSJames Smart /* this will call our completion handler */ 3530e2aed29fSJames Smart spin_lock_irq(&phba->hbalock); 3531e2aed29fSJames Smart lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); 3532e2aed29fSJames Smart spin_unlock_irq(&phba->hbalock); 3533e2aed29fSJames Smart break; 35344cc0e56eSJames Smart default: 35354cc0e56eSJames Smart spin_unlock_irqrestore(&phba->ct_ev_lock, flags); 35364cc0e56eSJames Smart break; 35374cc0e56eSJames Smart } 3538f1c3b0fcSJames Smart 35394cc0e56eSJames Smart /* scsi transport fc fc_bsg_job_timeout expects a zero return code, 35404cc0e56eSJames Smart * otherwise an error message will be displayed on the console 35414cc0e56eSJames Smart * so always return success (zero) 35424cc0e56eSJames Smart */ 3543f1c3b0fcSJames Smart return 0; 3544f1c3b0fcSJames Smart } 3545