1*f1c3b0fcSJames Smart /******************************************************************* 2*f1c3b0fcSJames Smart * This file is part of the Emulex Linux Device Driver for * 3*f1c3b0fcSJames Smart * Fibre Channel Host Bus Adapters. * 4*f1c3b0fcSJames Smart * Copyright (C) 2009 Emulex. All rights reserved. * 5*f1c3b0fcSJames Smart * EMULEX and SLI are trademarks of Emulex. * 6*f1c3b0fcSJames Smart * www.emulex.com * 7*f1c3b0fcSJames Smart * * 8*f1c3b0fcSJames Smart * This program is free software; you can redistribute it and/or * 9*f1c3b0fcSJames Smart * modify it under the terms of version 2 of the GNU General * 10*f1c3b0fcSJames Smart * Public License as published by the Free Software Foundation. * 11*f1c3b0fcSJames Smart * This program is distributed in the hope that it will be useful. * 12*f1c3b0fcSJames Smart * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * 13*f1c3b0fcSJames Smart * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * 14*f1c3b0fcSJames Smart * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * 15*f1c3b0fcSJames Smart * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * 16*f1c3b0fcSJames Smart * TO BE LEGALLY INVALID. See the GNU General Public License for * 17*f1c3b0fcSJames Smart * more details, a copy of which can be found in the file COPYING * 18*f1c3b0fcSJames Smart * included with this package. * 19*f1c3b0fcSJames Smart *******************************************************************/ 20*f1c3b0fcSJames Smart 21*f1c3b0fcSJames Smart #include <linux/interrupt.h> 22*f1c3b0fcSJames Smart #include <linux/mempool.h> 23*f1c3b0fcSJames Smart #include <linux/pci.h> 24*f1c3b0fcSJames Smart 25*f1c3b0fcSJames Smart #include <scsi/scsi.h> 26*f1c3b0fcSJames Smart #include <scsi/scsi_host.h> 27*f1c3b0fcSJames Smart #include <scsi/scsi_transport_fc.h> 28*f1c3b0fcSJames Smart #include <scsi/scsi_bsg_fc.h> 29*f1c3b0fcSJames Smart 30*f1c3b0fcSJames Smart #include "lpfc_hw4.h" 31*f1c3b0fcSJames Smart #include "lpfc_hw.h" 32*f1c3b0fcSJames Smart #include "lpfc_sli.h" 33*f1c3b0fcSJames Smart #include "lpfc_sli4.h" 34*f1c3b0fcSJames Smart #include "lpfc_nl.h" 35*f1c3b0fcSJames Smart #include "lpfc_disc.h" 36*f1c3b0fcSJames Smart #include "lpfc_scsi.h" 37*f1c3b0fcSJames Smart #include "lpfc.h" 38*f1c3b0fcSJames Smart #include "lpfc_logmsg.h" 39*f1c3b0fcSJames Smart #include "lpfc_crtn.h" 40*f1c3b0fcSJames Smart #include "lpfc_vport.h" 41*f1c3b0fcSJames Smart #include "lpfc_version.h" 42*f1c3b0fcSJames Smart 43*f1c3b0fcSJames Smart /** 44*f1c3b0fcSJames Smart * lpfc_bsg_rport_ct - send a CT command from a bsg request 45*f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 46*f1c3b0fcSJames Smart */ 47*f1c3b0fcSJames Smart static int 48*f1c3b0fcSJames Smart lpfc_bsg_rport_ct(struct fc_bsg_job *job) 49*f1c3b0fcSJames Smart { 50*f1c3b0fcSJames Smart struct Scsi_Host *shost = job->shost; 51*f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 52*f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 53*f1c3b0fcSJames Smart struct lpfc_rport_data *rdata = job->rport->dd_data; 54*f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 55*f1c3b0fcSJames Smart struct ulp_bde64 *bpl = NULL; 56*f1c3b0fcSJames Smart uint32_t timeout; 57*f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq = NULL; 58*f1c3b0fcSJames Smart struct lpfc_iocbq *rspiocbq = NULL; 59*f1c3b0fcSJames Smart IOCB_t *cmd; 60*f1c3b0fcSJames Smart IOCB_t *rsp; 61*f1c3b0fcSJames Smart struct lpfc_dmabuf *bmp = NULL; 62*f1c3b0fcSJames Smart int request_nseg; 63*f1c3b0fcSJames Smart int reply_nseg; 64*f1c3b0fcSJames Smart struct scatterlist *sgel = NULL; 65*f1c3b0fcSJames Smart int numbde; 66*f1c3b0fcSJames Smart dma_addr_t busaddr; 67*f1c3b0fcSJames Smart int rc = 0; 68*f1c3b0fcSJames Smart 69*f1c3b0fcSJames Smart /* in case no data is transferred */ 70*f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 71*f1c3b0fcSJames Smart 72*f1c3b0fcSJames Smart if (!lpfc_nlp_get(ndlp)) { 73*f1c3b0fcSJames Smart job->reply->result = -ENODEV; 74*f1c3b0fcSJames Smart return 0; 75*f1c3b0fcSJames Smart } 76*f1c3b0fcSJames Smart 77*f1c3b0fcSJames Smart if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { 78*f1c3b0fcSJames Smart rc = -ENODEV; 79*f1c3b0fcSJames Smart goto free_ndlp_exit; 80*f1c3b0fcSJames Smart } 81*f1c3b0fcSJames Smart 82*f1c3b0fcSJames Smart spin_lock_irq(shost->host_lock); 83*f1c3b0fcSJames Smart cmdiocbq = lpfc_sli_get_iocbq(phba); 84*f1c3b0fcSJames Smart if (!cmdiocbq) { 85*f1c3b0fcSJames Smart rc = -ENOMEM; 86*f1c3b0fcSJames Smart spin_unlock_irq(shost->host_lock); 87*f1c3b0fcSJames Smart goto free_ndlp_exit; 88*f1c3b0fcSJames Smart } 89*f1c3b0fcSJames Smart cmd = &cmdiocbq->iocb; 90*f1c3b0fcSJames Smart 91*f1c3b0fcSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 92*f1c3b0fcSJames Smart if (!rspiocbq) { 93*f1c3b0fcSJames Smart rc = -ENOMEM; 94*f1c3b0fcSJames Smart goto free_cmdiocbq; 95*f1c3b0fcSJames Smart } 96*f1c3b0fcSJames Smart spin_unlock_irq(shost->host_lock); 97*f1c3b0fcSJames Smart 98*f1c3b0fcSJames Smart rsp = &rspiocbq->iocb; 99*f1c3b0fcSJames Smart 100*f1c3b0fcSJames Smart bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); 101*f1c3b0fcSJames Smart if (!bmp) { 102*f1c3b0fcSJames Smart rc = -ENOMEM; 103*f1c3b0fcSJames Smart spin_lock_irq(shost->host_lock); 104*f1c3b0fcSJames Smart goto free_rspiocbq; 105*f1c3b0fcSJames Smart } 106*f1c3b0fcSJames Smart 107*f1c3b0fcSJames Smart spin_lock_irq(shost->host_lock); 108*f1c3b0fcSJames Smart bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); 109*f1c3b0fcSJames Smart if (!bmp->virt) { 110*f1c3b0fcSJames Smart rc = -ENOMEM; 111*f1c3b0fcSJames Smart goto free_bmp; 112*f1c3b0fcSJames Smart } 113*f1c3b0fcSJames Smart spin_unlock_irq(shost->host_lock); 114*f1c3b0fcSJames Smart 115*f1c3b0fcSJames Smart INIT_LIST_HEAD(&bmp->list); 116*f1c3b0fcSJames Smart bpl = (struct ulp_bde64 *) bmp->virt; 117*f1c3b0fcSJames Smart 118*f1c3b0fcSJames Smart request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, 119*f1c3b0fcSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 120*f1c3b0fcSJames Smart for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { 121*f1c3b0fcSJames Smart busaddr = sg_dma_address(sgel); 122*f1c3b0fcSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; 123*f1c3b0fcSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 124*f1c3b0fcSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 125*f1c3b0fcSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 126*f1c3b0fcSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 127*f1c3b0fcSJames Smart bpl++; 128*f1c3b0fcSJames Smart } 129*f1c3b0fcSJames Smart 130*f1c3b0fcSJames Smart reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list, 131*f1c3b0fcSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 132*f1c3b0fcSJames Smart for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) { 133*f1c3b0fcSJames Smart busaddr = sg_dma_address(sgel); 134*f1c3b0fcSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 135*f1c3b0fcSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 136*f1c3b0fcSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 137*f1c3b0fcSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 138*f1c3b0fcSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 139*f1c3b0fcSJames Smart bpl++; 140*f1c3b0fcSJames Smart } 141*f1c3b0fcSJames Smart 142*f1c3b0fcSJames Smart cmd->un.genreq64.bdl.ulpIoTag32 = 0; 143*f1c3b0fcSJames Smart cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); 144*f1c3b0fcSJames Smart cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); 145*f1c3b0fcSJames Smart cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; 146*f1c3b0fcSJames Smart cmd->un.genreq64.bdl.bdeSize = 147*f1c3b0fcSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 148*f1c3b0fcSJames Smart cmd->ulpCommand = CMD_GEN_REQUEST64_CR; 149*f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); 150*f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Dfctl = 0; 151*f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL; 152*f1c3b0fcSJames Smart cmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; 153*f1c3b0fcSJames Smart cmd->ulpBdeCount = 1; 154*f1c3b0fcSJames Smart cmd->ulpLe = 1; 155*f1c3b0fcSJames Smart cmd->ulpClass = CLASS3; 156*f1c3b0fcSJames Smart cmd->ulpContext = ndlp->nlp_rpi; 157*f1c3b0fcSJames Smart cmd->ulpOwner = OWN_CHIP; 158*f1c3b0fcSJames Smart cmdiocbq->vport = phba->pport; 159*f1c3b0fcSJames Smart cmdiocbq->context1 = NULL; 160*f1c3b0fcSJames Smart cmdiocbq->context2 = NULL; 161*f1c3b0fcSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 162*f1c3b0fcSJames Smart 163*f1c3b0fcSJames Smart timeout = phba->fc_ratov * 2; 164*f1c3b0fcSJames Smart job->dd_data = cmdiocbq; 165*f1c3b0fcSJames Smart 166*f1c3b0fcSJames Smart rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, 167*f1c3b0fcSJames Smart timeout + LPFC_DRVR_TIMEOUT); 168*f1c3b0fcSJames Smart 169*f1c3b0fcSJames Smart if (rc != IOCB_TIMEDOUT) { 170*f1c3b0fcSJames Smart pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, 171*f1c3b0fcSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 172*f1c3b0fcSJames Smart pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, 173*f1c3b0fcSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 174*f1c3b0fcSJames Smart } 175*f1c3b0fcSJames Smart 176*f1c3b0fcSJames Smart if (rc == IOCB_TIMEDOUT) { 177*f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 178*f1c3b0fcSJames Smart rc = -EACCES; 179*f1c3b0fcSJames Smart goto free_ndlp_exit; 180*f1c3b0fcSJames Smart } 181*f1c3b0fcSJames Smart 182*f1c3b0fcSJames Smart if (rc != IOCB_SUCCESS) { 183*f1c3b0fcSJames Smart rc = -EACCES; 184*f1c3b0fcSJames Smart goto free_outdmp; 185*f1c3b0fcSJames Smart } 186*f1c3b0fcSJames Smart 187*f1c3b0fcSJames Smart if (rsp->ulpStatus) { 188*f1c3b0fcSJames Smart if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { 189*f1c3b0fcSJames Smart switch (rsp->un.ulpWord[4] & 0xff) { 190*f1c3b0fcSJames Smart case IOERR_SEQUENCE_TIMEOUT: 191*f1c3b0fcSJames Smart rc = -ETIMEDOUT; 192*f1c3b0fcSJames Smart break; 193*f1c3b0fcSJames Smart case IOERR_INVALID_RPI: 194*f1c3b0fcSJames Smart rc = -EFAULT; 195*f1c3b0fcSJames Smart break; 196*f1c3b0fcSJames Smart default: 197*f1c3b0fcSJames Smart rc = -EACCES; 198*f1c3b0fcSJames Smart break; 199*f1c3b0fcSJames Smart } 200*f1c3b0fcSJames Smart goto free_outdmp; 201*f1c3b0fcSJames Smart } 202*f1c3b0fcSJames Smart } else 203*f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 204*f1c3b0fcSJames Smart rsp->un.genreq64.bdl.bdeSize; 205*f1c3b0fcSJames Smart 206*f1c3b0fcSJames Smart free_outdmp: 207*f1c3b0fcSJames Smart spin_lock_irq(shost->host_lock); 208*f1c3b0fcSJames Smart lpfc_mbuf_free(phba, bmp->virt, bmp->phys); 209*f1c3b0fcSJames Smart free_bmp: 210*f1c3b0fcSJames Smart kfree(bmp); 211*f1c3b0fcSJames Smart free_rspiocbq: 212*f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 213*f1c3b0fcSJames Smart free_cmdiocbq: 214*f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, cmdiocbq); 215*f1c3b0fcSJames Smart spin_unlock_irq(shost->host_lock); 216*f1c3b0fcSJames Smart free_ndlp_exit: 217*f1c3b0fcSJames Smart lpfc_nlp_put(ndlp); 218*f1c3b0fcSJames Smart 219*f1c3b0fcSJames Smart /* make error code available to userspace */ 220*f1c3b0fcSJames Smart job->reply->result = rc; 221*f1c3b0fcSJames Smart /* complete the job back to userspace */ 222*f1c3b0fcSJames Smart job->job_done(job); 223*f1c3b0fcSJames Smart 224*f1c3b0fcSJames Smart return 0; 225*f1c3b0fcSJames Smart } 226*f1c3b0fcSJames Smart 227*f1c3b0fcSJames Smart /** 228*f1c3b0fcSJames Smart * lpfc_bsg_rport_els - send an ELS command from a bsg request 229*f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 230*f1c3b0fcSJames Smart */ 231*f1c3b0fcSJames Smart static int 232*f1c3b0fcSJames Smart lpfc_bsg_rport_els(struct fc_bsg_job *job) 233*f1c3b0fcSJames Smart { 234*f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 235*f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 236*f1c3b0fcSJames Smart struct lpfc_rport_data *rdata = job->rport->dd_data; 237*f1c3b0fcSJames Smart struct lpfc_nodelist *ndlp = rdata->pnode; 238*f1c3b0fcSJames Smart 239*f1c3b0fcSJames Smart uint32_t elscmd; 240*f1c3b0fcSJames Smart uint32_t cmdsize; 241*f1c3b0fcSJames Smart uint32_t rspsize; 242*f1c3b0fcSJames Smart struct lpfc_iocbq *rspiocbq; 243*f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocbq; 244*f1c3b0fcSJames Smart IOCB_t *rsp; 245*f1c3b0fcSJames Smart uint16_t rpi = 0; 246*f1c3b0fcSJames Smart struct lpfc_dmabuf *pcmd; 247*f1c3b0fcSJames Smart struct lpfc_dmabuf *prsp; 248*f1c3b0fcSJames Smart struct lpfc_dmabuf *pbuflist = NULL; 249*f1c3b0fcSJames Smart struct ulp_bde64 *bpl; 250*f1c3b0fcSJames Smart int iocb_status; 251*f1c3b0fcSJames Smart int request_nseg; 252*f1c3b0fcSJames Smart int reply_nseg; 253*f1c3b0fcSJames Smart struct scatterlist *sgel = NULL; 254*f1c3b0fcSJames Smart int numbde; 255*f1c3b0fcSJames Smart dma_addr_t busaddr; 256*f1c3b0fcSJames Smart int rc = 0; 257*f1c3b0fcSJames Smart 258*f1c3b0fcSJames Smart /* in case no data is transferred */ 259*f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 260*f1c3b0fcSJames Smart 261*f1c3b0fcSJames Smart if (!lpfc_nlp_get(ndlp)) { 262*f1c3b0fcSJames Smart rc = -ENODEV; 263*f1c3b0fcSJames Smart goto out; 264*f1c3b0fcSJames Smart } 265*f1c3b0fcSJames Smart 266*f1c3b0fcSJames Smart elscmd = job->request->rqst_data.r_els.els_code; 267*f1c3b0fcSJames Smart cmdsize = job->request_payload.payload_len; 268*f1c3b0fcSJames Smart rspsize = job->reply_payload.payload_len; 269*f1c3b0fcSJames Smart rspiocbq = lpfc_sli_get_iocbq(phba); 270*f1c3b0fcSJames Smart if (!rspiocbq) { 271*f1c3b0fcSJames Smart lpfc_nlp_put(ndlp); 272*f1c3b0fcSJames Smart rc = -ENOMEM; 273*f1c3b0fcSJames Smart goto out; 274*f1c3b0fcSJames Smart } 275*f1c3b0fcSJames Smart 276*f1c3b0fcSJames Smart rsp = &rspiocbq->iocb; 277*f1c3b0fcSJames Smart rpi = ndlp->nlp_rpi; 278*f1c3b0fcSJames Smart 279*f1c3b0fcSJames Smart cmdiocbq = lpfc_prep_els_iocb(phba->pport, 1, cmdsize, 0, ndlp, 280*f1c3b0fcSJames Smart ndlp->nlp_DID, elscmd); 281*f1c3b0fcSJames Smart 282*f1c3b0fcSJames Smart if (!cmdiocbq) { 283*f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 284*f1c3b0fcSJames Smart return -EIO; 285*f1c3b0fcSJames Smart } 286*f1c3b0fcSJames Smart 287*f1c3b0fcSJames Smart job->dd_data = cmdiocbq; 288*f1c3b0fcSJames Smart pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; 289*f1c3b0fcSJames Smart prsp = (struct lpfc_dmabuf *) pcmd->list.next; 290*f1c3b0fcSJames Smart 291*f1c3b0fcSJames Smart lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); 292*f1c3b0fcSJames Smart kfree(pcmd); 293*f1c3b0fcSJames Smart lpfc_mbuf_free(phba, prsp->virt, prsp->phys); 294*f1c3b0fcSJames Smart kfree(prsp); 295*f1c3b0fcSJames Smart cmdiocbq->context2 = NULL; 296*f1c3b0fcSJames Smart 297*f1c3b0fcSJames Smart pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3; 298*f1c3b0fcSJames Smart bpl = (struct ulp_bde64 *) pbuflist->virt; 299*f1c3b0fcSJames Smart 300*f1c3b0fcSJames Smart request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, 301*f1c3b0fcSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 302*f1c3b0fcSJames Smart 303*f1c3b0fcSJames Smart for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { 304*f1c3b0fcSJames Smart busaddr = sg_dma_address(sgel); 305*f1c3b0fcSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; 306*f1c3b0fcSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 307*f1c3b0fcSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 308*f1c3b0fcSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 309*f1c3b0fcSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 310*f1c3b0fcSJames Smart bpl++; 311*f1c3b0fcSJames Smart } 312*f1c3b0fcSJames Smart 313*f1c3b0fcSJames Smart reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list, 314*f1c3b0fcSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 315*f1c3b0fcSJames Smart for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) { 316*f1c3b0fcSJames Smart busaddr = sg_dma_address(sgel); 317*f1c3b0fcSJames Smart bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; 318*f1c3b0fcSJames Smart bpl->tus.f.bdeSize = sg_dma_len(sgel); 319*f1c3b0fcSJames Smart bpl->tus.w = cpu_to_le32(bpl->tus.w); 320*f1c3b0fcSJames Smart bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); 321*f1c3b0fcSJames Smart bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); 322*f1c3b0fcSJames Smart bpl++; 323*f1c3b0fcSJames Smart } 324*f1c3b0fcSJames Smart 325*f1c3b0fcSJames Smart cmdiocbq->iocb.un.elsreq64.bdl.bdeSize = 326*f1c3b0fcSJames Smart (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); 327*f1c3b0fcSJames Smart cmdiocbq->iocb.ulpContext = rpi; 328*f1c3b0fcSJames Smart cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; 329*f1c3b0fcSJames Smart cmdiocbq->context1 = NULL; 330*f1c3b0fcSJames Smart cmdiocbq->context2 = NULL; 331*f1c3b0fcSJames Smart 332*f1c3b0fcSJames Smart iocb_status = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, 333*f1c3b0fcSJames Smart rspiocbq, (phba->fc_ratov * 2) 334*f1c3b0fcSJames Smart + LPFC_DRVR_TIMEOUT); 335*f1c3b0fcSJames Smart 336*f1c3b0fcSJames Smart /* release the new ndlp once the iocb completes */ 337*f1c3b0fcSJames Smart lpfc_nlp_put(ndlp); 338*f1c3b0fcSJames Smart if (iocb_status != IOCB_TIMEDOUT) { 339*f1c3b0fcSJames Smart pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, 340*f1c3b0fcSJames Smart job->request_payload.sg_cnt, DMA_TO_DEVICE); 341*f1c3b0fcSJames Smart pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, 342*f1c3b0fcSJames Smart job->reply_payload.sg_cnt, DMA_FROM_DEVICE); 343*f1c3b0fcSJames Smart } 344*f1c3b0fcSJames Smart 345*f1c3b0fcSJames Smart if (iocb_status == IOCB_SUCCESS) { 346*f1c3b0fcSJames Smart if (rsp->ulpStatus == IOSTAT_SUCCESS) { 347*f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 348*f1c3b0fcSJames Smart rsp->un.elsreq64.bdl.bdeSize; 349*f1c3b0fcSJames Smart rc = 0; 350*f1c3b0fcSJames Smart } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { 351*f1c3b0fcSJames Smart struct fc_bsg_ctels_reply *els_reply; 352*f1c3b0fcSJames Smart /* LS_RJT data returned in word 4 */ 353*f1c3b0fcSJames Smart uint8_t *rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; 354*f1c3b0fcSJames Smart 355*f1c3b0fcSJames Smart els_reply = &job->reply->reply_data.ctels_reply; 356*f1c3b0fcSJames Smart job->reply->result = 0; 357*f1c3b0fcSJames Smart els_reply->status = FC_CTELS_STATUS_REJECT; 358*f1c3b0fcSJames Smart els_reply->rjt_data.action = rjt_data[0]; 359*f1c3b0fcSJames Smart els_reply->rjt_data.reason_code = rjt_data[1]; 360*f1c3b0fcSJames Smart els_reply->rjt_data.reason_explanation = rjt_data[2]; 361*f1c3b0fcSJames Smart els_reply->rjt_data.vendor_unique = rjt_data[3]; 362*f1c3b0fcSJames Smart } else 363*f1c3b0fcSJames Smart rc = -EIO; 364*f1c3b0fcSJames Smart } else 365*f1c3b0fcSJames Smart rc = -EIO; 366*f1c3b0fcSJames Smart 367*f1c3b0fcSJames Smart if (iocb_status != IOCB_TIMEDOUT) 368*f1c3b0fcSJames Smart lpfc_els_free_iocb(phba, cmdiocbq); 369*f1c3b0fcSJames Smart 370*f1c3b0fcSJames Smart lpfc_sli_release_iocbq(phba, rspiocbq); 371*f1c3b0fcSJames Smart 372*f1c3b0fcSJames Smart out: 373*f1c3b0fcSJames Smart /* make error code available to userspace */ 374*f1c3b0fcSJames Smart job->reply->result = rc; 375*f1c3b0fcSJames Smart /* complete the job back to userspace */ 376*f1c3b0fcSJames Smart job->job_done(job); 377*f1c3b0fcSJames Smart 378*f1c3b0fcSJames Smart return 0; 379*f1c3b0fcSJames Smart } 380*f1c3b0fcSJames Smart 381*f1c3b0fcSJames Smart struct lpfc_ct_event { 382*f1c3b0fcSJames Smart struct list_head node; 383*f1c3b0fcSJames Smart int ref; 384*f1c3b0fcSJames Smart wait_queue_head_t wq; 385*f1c3b0fcSJames Smart 386*f1c3b0fcSJames Smart /* Event type and waiter identifiers */ 387*f1c3b0fcSJames Smart uint32_t type_mask; 388*f1c3b0fcSJames Smart uint32_t req_id; 389*f1c3b0fcSJames Smart uint32_t reg_id; 390*f1c3b0fcSJames Smart 391*f1c3b0fcSJames Smart /* next two flags are here for the auto-delete logic */ 392*f1c3b0fcSJames Smart unsigned long wait_time_stamp; 393*f1c3b0fcSJames Smart int waiting; 394*f1c3b0fcSJames Smart 395*f1c3b0fcSJames Smart /* seen and not seen events */ 396*f1c3b0fcSJames Smart struct list_head events_to_get; 397*f1c3b0fcSJames Smart struct list_head events_to_see; 398*f1c3b0fcSJames Smart }; 399*f1c3b0fcSJames Smart 400*f1c3b0fcSJames Smart struct event_data { 401*f1c3b0fcSJames Smart struct list_head node; 402*f1c3b0fcSJames Smart uint32_t type; 403*f1c3b0fcSJames Smart uint32_t immed_dat; 404*f1c3b0fcSJames Smart void *data; 405*f1c3b0fcSJames Smart uint32_t len; 406*f1c3b0fcSJames Smart }; 407*f1c3b0fcSJames Smart 408*f1c3b0fcSJames Smart static struct lpfc_ct_event * 409*f1c3b0fcSJames Smart lpfc_ct_event_new(int ev_reg_id, uint32_t ev_req_id) 410*f1c3b0fcSJames Smart { 411*f1c3b0fcSJames Smart struct lpfc_ct_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); 412*f1c3b0fcSJames Smart if (!evt) 413*f1c3b0fcSJames Smart return NULL; 414*f1c3b0fcSJames Smart 415*f1c3b0fcSJames Smart INIT_LIST_HEAD(&evt->events_to_get); 416*f1c3b0fcSJames Smart INIT_LIST_HEAD(&evt->events_to_see); 417*f1c3b0fcSJames Smart evt->req_id = ev_req_id; 418*f1c3b0fcSJames Smart evt->reg_id = ev_reg_id; 419*f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 420*f1c3b0fcSJames Smart init_waitqueue_head(&evt->wq); 421*f1c3b0fcSJames Smart 422*f1c3b0fcSJames Smart return evt; 423*f1c3b0fcSJames Smart } 424*f1c3b0fcSJames Smart 425*f1c3b0fcSJames Smart static void 426*f1c3b0fcSJames Smart lpfc_ct_event_free(struct lpfc_ct_event *evt) 427*f1c3b0fcSJames Smart { 428*f1c3b0fcSJames Smart struct event_data *ed; 429*f1c3b0fcSJames Smart 430*f1c3b0fcSJames Smart list_del(&evt->node); 431*f1c3b0fcSJames Smart 432*f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_get)) { 433*f1c3b0fcSJames Smart ed = list_entry(evt->events_to_get.next, typeof(*ed), node); 434*f1c3b0fcSJames Smart list_del(&ed->node); 435*f1c3b0fcSJames Smart kfree(ed->data); 436*f1c3b0fcSJames Smart kfree(ed); 437*f1c3b0fcSJames Smart } 438*f1c3b0fcSJames Smart 439*f1c3b0fcSJames Smart while (!list_empty(&evt->events_to_see)) { 440*f1c3b0fcSJames Smart ed = list_entry(evt->events_to_see.next, typeof(*ed), node); 441*f1c3b0fcSJames Smart list_del(&ed->node); 442*f1c3b0fcSJames Smart kfree(ed->data); 443*f1c3b0fcSJames Smart kfree(ed); 444*f1c3b0fcSJames Smart } 445*f1c3b0fcSJames Smart 446*f1c3b0fcSJames Smart kfree(evt); 447*f1c3b0fcSJames Smart } 448*f1c3b0fcSJames Smart 449*f1c3b0fcSJames Smart static inline void 450*f1c3b0fcSJames Smart lpfc_ct_event_ref(struct lpfc_ct_event *evt) 451*f1c3b0fcSJames Smart { 452*f1c3b0fcSJames Smart evt->ref++; 453*f1c3b0fcSJames Smart } 454*f1c3b0fcSJames Smart 455*f1c3b0fcSJames Smart static inline void 456*f1c3b0fcSJames Smart lpfc_ct_event_unref(struct lpfc_ct_event *evt) 457*f1c3b0fcSJames Smart { 458*f1c3b0fcSJames Smart if (--evt->ref < 0) 459*f1c3b0fcSJames Smart lpfc_ct_event_free(evt); 460*f1c3b0fcSJames Smart } 461*f1c3b0fcSJames Smart 462*f1c3b0fcSJames Smart #define SLI_CT_ELX_LOOPBACK 0x10 463*f1c3b0fcSJames Smart 464*f1c3b0fcSJames Smart enum ELX_LOOPBACK_CMD { 465*f1c3b0fcSJames Smart ELX_LOOPBACK_XRI_SETUP, 466*f1c3b0fcSJames Smart ELX_LOOPBACK_DATA, 467*f1c3b0fcSJames Smart }; 468*f1c3b0fcSJames Smart 469*f1c3b0fcSJames Smart /** 470*f1c3b0fcSJames Smart * lpfc_bsg_ct_unsol_event - process an unsolicited CT command 471*f1c3b0fcSJames Smart * @phba: 472*f1c3b0fcSJames Smart * @pring: 473*f1c3b0fcSJames Smart * @piocbq: 474*f1c3b0fcSJames Smart * 475*f1c3b0fcSJames Smart * This function is called when an unsolicited CT command is received. It 476*f1c3b0fcSJames Smart * forwards the event to any processes registerd to receive CT events. 477*f1c3b0fcSJames Smart */ 478*f1c3b0fcSJames Smart void 479*f1c3b0fcSJames Smart lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, 480*f1c3b0fcSJames Smart struct lpfc_iocbq *piocbq) 481*f1c3b0fcSJames Smart { 482*f1c3b0fcSJames Smart uint32_t evt_req_id = 0; 483*f1c3b0fcSJames Smart uint32_t cmd; 484*f1c3b0fcSJames Smart uint32_t len; 485*f1c3b0fcSJames Smart struct lpfc_dmabuf *dmabuf = NULL; 486*f1c3b0fcSJames Smart struct lpfc_ct_event *evt; 487*f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 488*f1c3b0fcSJames Smart struct lpfc_iocbq *iocbq; 489*f1c3b0fcSJames Smart size_t offset = 0; 490*f1c3b0fcSJames Smart struct list_head head; 491*f1c3b0fcSJames Smart struct ulp_bde64 *bde; 492*f1c3b0fcSJames Smart dma_addr_t dma_addr; 493*f1c3b0fcSJames Smart int i; 494*f1c3b0fcSJames Smart struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; 495*f1c3b0fcSJames Smart struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; 496*f1c3b0fcSJames Smart struct lpfc_hbq_entry *hbqe; 497*f1c3b0fcSJames Smart struct lpfc_sli_ct_request *ct_req; 498*f1c3b0fcSJames Smart 499*f1c3b0fcSJames Smart INIT_LIST_HEAD(&head); 500*f1c3b0fcSJames Smart list_add_tail(&head, &piocbq->list); 501*f1c3b0fcSJames Smart 502*f1c3b0fcSJames Smart if (piocbq->iocb.ulpBdeCount == 0 || 503*f1c3b0fcSJames Smart piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) 504*f1c3b0fcSJames Smart goto error_ct_unsol_exit; 505*f1c3b0fcSJames Smart 506*f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) 507*f1c3b0fcSJames Smart dmabuf = bdeBuf1; 508*f1c3b0fcSJames Smart else { 509*f1c3b0fcSJames Smart dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, 510*f1c3b0fcSJames Smart piocbq->iocb.un.cont64[0].addrLow); 511*f1c3b0fcSJames Smart dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); 512*f1c3b0fcSJames Smart } 513*f1c3b0fcSJames Smart 514*f1c3b0fcSJames Smart ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; 515*f1c3b0fcSJames Smart evt_req_id = ct_req->FsType; 516*f1c3b0fcSJames Smart cmd = ct_req->CommandResponse.bits.CmdRsp; 517*f1c3b0fcSJames Smart len = ct_req->CommandResponse.bits.Size; 518*f1c3b0fcSJames Smart if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) 519*f1c3b0fcSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); 520*f1c3b0fcSJames Smart 521*f1c3b0fcSJames Smart mutex_lock(&phba->ct_event_mutex); 522*f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 523*f1c3b0fcSJames Smart if (evt->req_id != evt_req_id) 524*f1c3b0fcSJames Smart continue; 525*f1c3b0fcSJames Smart 526*f1c3b0fcSJames Smart lpfc_ct_event_ref(evt); 527*f1c3b0fcSJames Smart 528*f1c3b0fcSJames Smart evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); 529*f1c3b0fcSJames Smart if (!evt_dat) { 530*f1c3b0fcSJames Smart lpfc_ct_event_unref(evt); 531*f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 532*f1c3b0fcSJames Smart "2614 Memory allocation failed for " 533*f1c3b0fcSJames Smart "CT event\n"); 534*f1c3b0fcSJames Smart break; 535*f1c3b0fcSJames Smart } 536*f1c3b0fcSJames Smart 537*f1c3b0fcSJames Smart mutex_unlock(&phba->ct_event_mutex); 538*f1c3b0fcSJames Smart 539*f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 540*f1c3b0fcSJames Smart /* take accumulated byte count from the last iocbq */ 541*f1c3b0fcSJames Smart iocbq = list_entry(head.prev, typeof(*iocbq), list); 542*f1c3b0fcSJames Smart evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; 543*f1c3b0fcSJames Smart } else { 544*f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 545*f1c3b0fcSJames Smart for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) 546*f1c3b0fcSJames Smart evt_dat->len += 547*f1c3b0fcSJames Smart iocbq->iocb.un.cont64[i].tus.f.bdeSize; 548*f1c3b0fcSJames Smart } 549*f1c3b0fcSJames Smart } 550*f1c3b0fcSJames Smart 551*f1c3b0fcSJames Smart evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); 552*f1c3b0fcSJames Smart if (!evt_dat->data) { 553*f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 554*f1c3b0fcSJames Smart "2615 Memory allocation failed for " 555*f1c3b0fcSJames Smart "CT event data, size %d\n", 556*f1c3b0fcSJames Smart evt_dat->len); 557*f1c3b0fcSJames Smart kfree(evt_dat); 558*f1c3b0fcSJames Smart mutex_lock(&phba->ct_event_mutex); 559*f1c3b0fcSJames Smart lpfc_ct_event_unref(evt); 560*f1c3b0fcSJames Smart mutex_unlock(&phba->ct_event_mutex); 561*f1c3b0fcSJames Smart goto error_ct_unsol_exit; 562*f1c3b0fcSJames Smart } 563*f1c3b0fcSJames Smart 564*f1c3b0fcSJames Smart list_for_each_entry(iocbq, &head, list) { 565*f1c3b0fcSJames Smart if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { 566*f1c3b0fcSJames Smart bdeBuf1 = iocbq->context2; 567*f1c3b0fcSJames Smart bdeBuf2 = iocbq->context3; 568*f1c3b0fcSJames Smart } 569*f1c3b0fcSJames Smart for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { 570*f1c3b0fcSJames Smart int size = 0; 571*f1c3b0fcSJames Smart if (phba->sli3_options & 572*f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED) { 573*f1c3b0fcSJames Smart if (i == 0) { 574*f1c3b0fcSJames Smart hbqe = (struct lpfc_hbq_entry *) 575*f1c3b0fcSJames Smart &iocbq->iocb.un.ulpWord[0]; 576*f1c3b0fcSJames Smart size = hbqe->bde.tus.f.bdeSize; 577*f1c3b0fcSJames Smart dmabuf = bdeBuf1; 578*f1c3b0fcSJames Smart } else if (i == 1) { 579*f1c3b0fcSJames Smart hbqe = (struct lpfc_hbq_entry *) 580*f1c3b0fcSJames Smart &iocbq->iocb.unsli3. 581*f1c3b0fcSJames Smart sli3Words[4]; 582*f1c3b0fcSJames Smart size = hbqe->bde.tus.f.bdeSize; 583*f1c3b0fcSJames Smart dmabuf = bdeBuf2; 584*f1c3b0fcSJames Smart } 585*f1c3b0fcSJames Smart if ((offset + size) > evt_dat->len) 586*f1c3b0fcSJames Smart size = evt_dat->len - offset; 587*f1c3b0fcSJames Smart } else { 588*f1c3b0fcSJames Smart size = iocbq->iocb.un.cont64[i]. 589*f1c3b0fcSJames Smart tus.f.bdeSize; 590*f1c3b0fcSJames Smart bde = &iocbq->iocb.un.cont64[i]; 591*f1c3b0fcSJames Smart dma_addr = getPaddr(bde->addrHigh, 592*f1c3b0fcSJames Smart bde->addrLow); 593*f1c3b0fcSJames Smart dmabuf = lpfc_sli_ringpostbuf_get(phba, 594*f1c3b0fcSJames Smart pring, dma_addr); 595*f1c3b0fcSJames Smart } 596*f1c3b0fcSJames Smart if (!dmabuf) { 597*f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_ERR, 598*f1c3b0fcSJames Smart LOG_LIBDFC, "2616 No dmabuf " 599*f1c3b0fcSJames Smart "found for iocbq 0x%p\n", 600*f1c3b0fcSJames Smart iocbq); 601*f1c3b0fcSJames Smart kfree(evt_dat->data); 602*f1c3b0fcSJames Smart kfree(evt_dat); 603*f1c3b0fcSJames Smart mutex_lock(&phba->ct_event_mutex); 604*f1c3b0fcSJames Smart lpfc_ct_event_unref(evt); 605*f1c3b0fcSJames Smart mutex_unlock(&phba->ct_event_mutex); 606*f1c3b0fcSJames Smart goto error_ct_unsol_exit; 607*f1c3b0fcSJames Smart } 608*f1c3b0fcSJames Smart memcpy((char *)(evt_dat->data) + offset, 609*f1c3b0fcSJames Smart dmabuf->virt, size); 610*f1c3b0fcSJames Smart offset += size; 611*f1c3b0fcSJames Smart if (evt_req_id != SLI_CT_ELX_LOOPBACK && 612*f1c3b0fcSJames Smart !(phba->sli3_options & 613*f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) { 614*f1c3b0fcSJames Smart lpfc_sli_ringpostbuf_put(phba, pring, 615*f1c3b0fcSJames Smart dmabuf); 616*f1c3b0fcSJames Smart } else { 617*f1c3b0fcSJames Smart switch (cmd) { 618*f1c3b0fcSJames Smart case ELX_LOOPBACK_XRI_SETUP: 619*f1c3b0fcSJames Smart if (!(phba->sli3_options & 620*f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) 621*f1c3b0fcSJames Smart lpfc_post_buffer(phba, 622*f1c3b0fcSJames Smart pring, 623*f1c3b0fcSJames Smart 1); 624*f1c3b0fcSJames Smart else 625*f1c3b0fcSJames Smart lpfc_in_buf_free(phba, 626*f1c3b0fcSJames Smart dmabuf); 627*f1c3b0fcSJames Smart break; 628*f1c3b0fcSJames Smart default: 629*f1c3b0fcSJames Smart if (!(phba->sli3_options & 630*f1c3b0fcSJames Smart LPFC_SLI3_HBQ_ENABLED)) 631*f1c3b0fcSJames Smart lpfc_post_buffer(phba, 632*f1c3b0fcSJames Smart pring, 633*f1c3b0fcSJames Smart 1); 634*f1c3b0fcSJames Smart break; 635*f1c3b0fcSJames Smart } 636*f1c3b0fcSJames Smart } 637*f1c3b0fcSJames Smart } 638*f1c3b0fcSJames Smart } 639*f1c3b0fcSJames Smart 640*f1c3b0fcSJames Smart mutex_lock(&phba->ct_event_mutex); 641*f1c3b0fcSJames Smart if (phba->sli_rev == LPFC_SLI_REV4) { 642*f1c3b0fcSJames Smart evt_dat->immed_dat = phba->ctx_idx; 643*f1c3b0fcSJames Smart phba->ctx_idx = (phba->ctx_idx + 1) % 64; 644*f1c3b0fcSJames Smart phba->ct_ctx[evt_dat->immed_dat].oxid = 645*f1c3b0fcSJames Smart piocbq->iocb.ulpContext; 646*f1c3b0fcSJames Smart phba->ct_ctx[evt_dat->immed_dat].SID = 647*f1c3b0fcSJames Smart piocbq->iocb.un.rcvels.remoteID; 648*f1c3b0fcSJames Smart } else 649*f1c3b0fcSJames Smart evt_dat->immed_dat = piocbq->iocb.ulpContext; 650*f1c3b0fcSJames Smart 651*f1c3b0fcSJames Smart evt_dat->type = FC_REG_CT_EVENT; 652*f1c3b0fcSJames Smart list_add(&evt_dat->node, &evt->events_to_see); 653*f1c3b0fcSJames Smart wake_up_interruptible(&evt->wq); 654*f1c3b0fcSJames Smart lpfc_ct_event_unref(evt); 655*f1c3b0fcSJames Smart if (evt_req_id == SLI_CT_ELX_LOOPBACK) 656*f1c3b0fcSJames Smart break; 657*f1c3b0fcSJames Smart } 658*f1c3b0fcSJames Smart mutex_unlock(&phba->ct_event_mutex); 659*f1c3b0fcSJames Smart 660*f1c3b0fcSJames Smart error_ct_unsol_exit: 661*f1c3b0fcSJames Smart if (!list_empty(&head)) 662*f1c3b0fcSJames Smart list_del(&head); 663*f1c3b0fcSJames Smart 664*f1c3b0fcSJames Smart return; 665*f1c3b0fcSJames Smart } 666*f1c3b0fcSJames Smart 667*f1c3b0fcSJames Smart /** 668*f1c3b0fcSJames Smart * lpfc_bsg_set_event - process a SET_EVENT bsg vendor command 669*f1c3b0fcSJames Smart * @job: SET_EVENT fc_bsg_job 670*f1c3b0fcSJames Smart */ 671*f1c3b0fcSJames Smart static int 672*f1c3b0fcSJames Smart lpfc_bsg_set_event(struct fc_bsg_job *job) 673*f1c3b0fcSJames Smart { 674*f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 675*f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 676*f1c3b0fcSJames Smart struct set_ct_event *event_req; 677*f1c3b0fcSJames Smart struct lpfc_ct_event *evt; 678*f1c3b0fcSJames Smart int rc = 0; 679*f1c3b0fcSJames Smart 680*f1c3b0fcSJames Smart if (job->request_len < 681*f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { 682*f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 683*f1c3b0fcSJames Smart "2612 Received SET_CT_EVENT below minimum " 684*f1c3b0fcSJames Smart "size\n"); 685*f1c3b0fcSJames Smart return -EINVAL; 686*f1c3b0fcSJames Smart } 687*f1c3b0fcSJames Smart 688*f1c3b0fcSJames Smart event_req = (struct set_ct_event *) 689*f1c3b0fcSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 690*f1c3b0fcSJames Smart 691*f1c3b0fcSJames Smart mutex_lock(&phba->ct_event_mutex); 692*f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 693*f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 694*f1c3b0fcSJames Smart lpfc_ct_event_ref(evt); 695*f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 696*f1c3b0fcSJames Smart break; 697*f1c3b0fcSJames Smart } 698*f1c3b0fcSJames Smart } 699*f1c3b0fcSJames Smart mutex_unlock(&phba->ct_event_mutex); 700*f1c3b0fcSJames Smart 701*f1c3b0fcSJames Smart if (&evt->node == &phba->ct_ev_waiters) { 702*f1c3b0fcSJames Smart /* no event waiting struct yet - first call */ 703*f1c3b0fcSJames Smart evt = lpfc_ct_event_new(event_req->ev_reg_id, 704*f1c3b0fcSJames Smart event_req->ev_req_id); 705*f1c3b0fcSJames Smart if (!evt) { 706*f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 707*f1c3b0fcSJames Smart "2617 Failed allocation of event " 708*f1c3b0fcSJames Smart "waiter\n"); 709*f1c3b0fcSJames Smart return -ENOMEM; 710*f1c3b0fcSJames Smart } 711*f1c3b0fcSJames Smart 712*f1c3b0fcSJames Smart mutex_lock(&phba->ct_event_mutex); 713*f1c3b0fcSJames Smart list_add(&evt->node, &phba->ct_ev_waiters); 714*f1c3b0fcSJames Smart lpfc_ct_event_ref(evt); 715*f1c3b0fcSJames Smart mutex_unlock(&phba->ct_event_mutex); 716*f1c3b0fcSJames Smart } 717*f1c3b0fcSJames Smart 718*f1c3b0fcSJames Smart evt->waiting = 1; 719*f1c3b0fcSJames Smart if (wait_event_interruptible(evt->wq, 720*f1c3b0fcSJames Smart !list_empty(&evt->events_to_see))) { 721*f1c3b0fcSJames Smart mutex_lock(&phba->ct_event_mutex); 722*f1c3b0fcSJames Smart lpfc_ct_event_unref(evt); /* release ref */ 723*f1c3b0fcSJames Smart lpfc_ct_event_unref(evt); /* delete */ 724*f1c3b0fcSJames Smart mutex_unlock(&phba->ct_event_mutex); 725*f1c3b0fcSJames Smart rc = -EINTR; 726*f1c3b0fcSJames Smart goto set_event_out; 727*f1c3b0fcSJames Smart } 728*f1c3b0fcSJames Smart 729*f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 730*f1c3b0fcSJames Smart evt->waiting = 0; 731*f1c3b0fcSJames Smart 732*f1c3b0fcSJames Smart mutex_lock(&phba->ct_event_mutex); 733*f1c3b0fcSJames Smart list_move(evt->events_to_see.prev, &evt->events_to_get); 734*f1c3b0fcSJames Smart lpfc_ct_event_unref(evt); /* release ref */ 735*f1c3b0fcSJames Smart mutex_unlock(&phba->ct_event_mutex); 736*f1c3b0fcSJames Smart 737*f1c3b0fcSJames Smart set_event_out: 738*f1c3b0fcSJames Smart /* set_event carries no reply payload */ 739*f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 740*f1c3b0fcSJames Smart /* make error code available to userspace */ 741*f1c3b0fcSJames Smart job->reply->result = rc; 742*f1c3b0fcSJames Smart /* complete the job back to userspace */ 743*f1c3b0fcSJames Smart job->job_done(job); 744*f1c3b0fcSJames Smart 745*f1c3b0fcSJames Smart return 0; 746*f1c3b0fcSJames Smart } 747*f1c3b0fcSJames Smart 748*f1c3b0fcSJames Smart /** 749*f1c3b0fcSJames Smart * lpfc_bsg_get_event - process a GET_EVENT bsg vendor command 750*f1c3b0fcSJames Smart * @job: GET_EVENT fc_bsg_job 751*f1c3b0fcSJames Smart */ 752*f1c3b0fcSJames Smart static int 753*f1c3b0fcSJames Smart lpfc_bsg_get_event(struct fc_bsg_job *job) 754*f1c3b0fcSJames Smart { 755*f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 756*f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 757*f1c3b0fcSJames Smart struct get_ct_event *event_req; 758*f1c3b0fcSJames Smart struct get_ct_event_reply *event_reply; 759*f1c3b0fcSJames Smart struct lpfc_ct_event *evt; 760*f1c3b0fcSJames Smart struct event_data *evt_dat = NULL; 761*f1c3b0fcSJames Smart int rc = 0; 762*f1c3b0fcSJames Smart 763*f1c3b0fcSJames Smart if (job->request_len < 764*f1c3b0fcSJames Smart sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { 765*f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 766*f1c3b0fcSJames Smart "2613 Received GET_CT_EVENT request below " 767*f1c3b0fcSJames Smart "minimum size\n"); 768*f1c3b0fcSJames Smart return -EINVAL; 769*f1c3b0fcSJames Smart } 770*f1c3b0fcSJames Smart 771*f1c3b0fcSJames Smart event_req = (struct get_ct_event *) 772*f1c3b0fcSJames Smart job->request->rqst_data.h_vendor.vendor_cmd; 773*f1c3b0fcSJames Smart 774*f1c3b0fcSJames Smart event_reply = (struct get_ct_event_reply *) 775*f1c3b0fcSJames Smart job->reply->reply_data.vendor_reply.vendor_rsp; 776*f1c3b0fcSJames Smart 777*f1c3b0fcSJames Smart mutex_lock(&phba->ct_event_mutex); 778*f1c3b0fcSJames Smart list_for_each_entry(evt, &phba->ct_ev_waiters, node) { 779*f1c3b0fcSJames Smart if (evt->reg_id == event_req->ev_reg_id) { 780*f1c3b0fcSJames Smart if (list_empty(&evt->events_to_get)) 781*f1c3b0fcSJames Smart break; 782*f1c3b0fcSJames Smart lpfc_ct_event_ref(evt); 783*f1c3b0fcSJames Smart evt->wait_time_stamp = jiffies; 784*f1c3b0fcSJames Smart evt_dat = list_entry(evt->events_to_get.prev, 785*f1c3b0fcSJames Smart struct event_data, node); 786*f1c3b0fcSJames Smart list_del(&evt_dat->node); 787*f1c3b0fcSJames Smart break; 788*f1c3b0fcSJames Smart } 789*f1c3b0fcSJames Smart } 790*f1c3b0fcSJames Smart mutex_unlock(&phba->ct_event_mutex); 791*f1c3b0fcSJames Smart 792*f1c3b0fcSJames Smart if (!evt_dat) { 793*f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 794*f1c3b0fcSJames Smart rc = -ENOENT; 795*f1c3b0fcSJames Smart goto error_get_event_exit; 796*f1c3b0fcSJames Smart } 797*f1c3b0fcSJames Smart 798*f1c3b0fcSJames Smart if (evt_dat->len > job->reply_payload.payload_len) { 799*f1c3b0fcSJames Smart evt_dat->len = job->reply_payload.payload_len; 800*f1c3b0fcSJames Smart lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, 801*f1c3b0fcSJames Smart "2618 Truncated event data at %d " 802*f1c3b0fcSJames Smart "bytes\n", 803*f1c3b0fcSJames Smart job->reply_payload.payload_len); 804*f1c3b0fcSJames Smart } 805*f1c3b0fcSJames Smart 806*f1c3b0fcSJames Smart event_reply->immed_data = evt_dat->immed_dat; 807*f1c3b0fcSJames Smart 808*f1c3b0fcSJames Smart if (evt_dat->len > 0) 809*f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 810*f1c3b0fcSJames Smart sg_copy_from_buffer(job->reply_payload.sg_list, 811*f1c3b0fcSJames Smart job->reply_payload.sg_cnt, 812*f1c3b0fcSJames Smart evt_dat->data, evt_dat->len); 813*f1c3b0fcSJames Smart else 814*f1c3b0fcSJames Smart job->reply->reply_payload_rcv_len = 0; 815*f1c3b0fcSJames Smart rc = 0; 816*f1c3b0fcSJames Smart 817*f1c3b0fcSJames Smart if (evt_dat) 818*f1c3b0fcSJames Smart kfree(evt_dat->data); 819*f1c3b0fcSJames Smart kfree(evt_dat); 820*f1c3b0fcSJames Smart mutex_lock(&phba->ct_event_mutex); 821*f1c3b0fcSJames Smart lpfc_ct_event_unref(evt); 822*f1c3b0fcSJames Smart mutex_unlock(&phba->ct_event_mutex); 823*f1c3b0fcSJames Smart 824*f1c3b0fcSJames Smart error_get_event_exit: 825*f1c3b0fcSJames Smart /* make error code available to userspace */ 826*f1c3b0fcSJames Smart job->reply->result = rc; 827*f1c3b0fcSJames Smart /* complete the job back to userspace */ 828*f1c3b0fcSJames Smart job->job_done(job); 829*f1c3b0fcSJames Smart 830*f1c3b0fcSJames Smart return rc; 831*f1c3b0fcSJames Smart } 832*f1c3b0fcSJames Smart 833*f1c3b0fcSJames Smart /** 834*f1c3b0fcSJames Smart * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job 835*f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 836*f1c3b0fcSJames Smart */ 837*f1c3b0fcSJames Smart static int 838*f1c3b0fcSJames Smart lpfc_bsg_hst_vendor(struct fc_bsg_job *job) 839*f1c3b0fcSJames Smart { 840*f1c3b0fcSJames Smart int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; 841*f1c3b0fcSJames Smart 842*f1c3b0fcSJames Smart switch (command) { 843*f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_SET_CT_EVENT: 844*f1c3b0fcSJames Smart return lpfc_bsg_set_event(job); 845*f1c3b0fcSJames Smart break; 846*f1c3b0fcSJames Smart 847*f1c3b0fcSJames Smart case LPFC_BSG_VENDOR_GET_CT_EVENT: 848*f1c3b0fcSJames Smart return lpfc_bsg_get_event(job); 849*f1c3b0fcSJames Smart break; 850*f1c3b0fcSJames Smart 851*f1c3b0fcSJames Smart default: 852*f1c3b0fcSJames Smart return -EINVAL; 853*f1c3b0fcSJames Smart } 854*f1c3b0fcSJames Smart } 855*f1c3b0fcSJames Smart 856*f1c3b0fcSJames Smart /** 857*f1c3b0fcSJames Smart * lpfc_bsg_request - handle a bsg request from the FC transport 858*f1c3b0fcSJames Smart * @job: fc_bsg_job to handle 859*f1c3b0fcSJames Smart */ 860*f1c3b0fcSJames Smart int 861*f1c3b0fcSJames Smart lpfc_bsg_request(struct fc_bsg_job *job) 862*f1c3b0fcSJames Smart { 863*f1c3b0fcSJames Smart uint32_t msgcode; 864*f1c3b0fcSJames Smart int rc = -EINVAL; 865*f1c3b0fcSJames Smart 866*f1c3b0fcSJames Smart msgcode = job->request->msgcode; 867*f1c3b0fcSJames Smart 868*f1c3b0fcSJames Smart switch (msgcode) { 869*f1c3b0fcSJames Smart case FC_BSG_HST_VENDOR: 870*f1c3b0fcSJames Smart rc = lpfc_bsg_hst_vendor(job); 871*f1c3b0fcSJames Smart break; 872*f1c3b0fcSJames Smart case FC_BSG_RPT_ELS: 873*f1c3b0fcSJames Smart rc = lpfc_bsg_rport_els(job); 874*f1c3b0fcSJames Smart break; 875*f1c3b0fcSJames Smart case FC_BSG_RPT_CT: 876*f1c3b0fcSJames Smart rc = lpfc_bsg_rport_ct(job); 877*f1c3b0fcSJames Smart break; 878*f1c3b0fcSJames Smart default: 879*f1c3b0fcSJames Smart break; 880*f1c3b0fcSJames Smart } 881*f1c3b0fcSJames Smart 882*f1c3b0fcSJames Smart return rc; 883*f1c3b0fcSJames Smart } 884*f1c3b0fcSJames Smart 885*f1c3b0fcSJames Smart /** 886*f1c3b0fcSJames Smart * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport 887*f1c3b0fcSJames Smart * @job: fc_bsg_job that has timed out 888*f1c3b0fcSJames Smart * 889*f1c3b0fcSJames Smart * This function just aborts the job's IOCB. The aborted IOCB will return to 890*f1c3b0fcSJames Smart * the waiting function which will handle passing the error back to userspace 891*f1c3b0fcSJames Smart */ 892*f1c3b0fcSJames Smart int 893*f1c3b0fcSJames Smart lpfc_bsg_timeout(struct fc_bsg_job *job) 894*f1c3b0fcSJames Smart { 895*f1c3b0fcSJames Smart struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; 896*f1c3b0fcSJames Smart struct lpfc_hba *phba = vport->phba; 897*f1c3b0fcSJames Smart struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)job->dd_data; 898*f1c3b0fcSJames Smart struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; 899*f1c3b0fcSJames Smart 900*f1c3b0fcSJames Smart if (cmdiocb) 901*f1c3b0fcSJames Smart lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); 902*f1c3b0fcSJames Smart 903*f1c3b0fcSJames Smart return 0; 904*f1c3b0fcSJames Smart } 905