xref: /linux/drivers/scsi/lpfc/lpfc_bsg.c (revision f1c3b0fcbb8104dac92d65d5016500a09beea287)
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