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