diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-26 19:55:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-26 19:55:27 -0500 |
commit | 654451748b779b28077d9058442d0f354251870d (patch) | |
tree | ff889a2f6226e16b1121789f809927666a9ccf13 /drivers/scsi/lpfc/lpfc_bsg.c | |
parent | 64d497f55379b1e320a08ec2426468d96f5642ec (diff) | |
parent | 77c9cfc51b0d732b2524799810fb30018074fd60 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (158 commits)
[SCSI] Fix printing of failed 32-byte commands
[SCSI] Fix printing of variable length commands
[SCSI] libsrp: fix bug in ADDITIONAL CDB LENGTH interpretation
[SCSI] scsi_dh_alua: Add IBM Power Virtual SCSI ALUA device to dev list
[SCSI] scsi_dh_alua: add netapp to dev list
[SCSI] qla2xxx: Update version number to 8.03.02-k1.
[SCSI] qla2xxx: EEH: Restore PCI saved state during pci slot reset.
[SCSI] qla2xxx: Add firmware ETS burst support.
[SCSI] qla2xxx: Correct loop-resync issues during SNS scans.
[SCSI] qla2xxx: Correct use-after-free issue in terminate_rport_io callback.
[SCSI] qla2xxx: Correct EH bus-reset handling.
[SCSI] qla2xxx: Proper clean-up of BSG requests when request times out.
[SCSI] qla2xxx: Initialize payload receive length in failure path of vendor commands
[SCSI] fix duplicate removal on error path in scsi_sysfs_add_sdev
[SCSI] fix refcounting bug in scsi_get_host_dev
[SCSI] fix memory leak in scsi_report_lun_scan
[SCSI] lpfc: correct PPC build failure
[SCSI] raid_class: add raid1e
[SCSI] mpt2sas: Do not call sas_is_tlr_enabled for RAID volumes.
[SCSI] zfcp: Introduce header file for qdio structs and inline functions
...
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_bsg.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 2473 |
1 files changed, 2178 insertions, 295 deletions
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index a5d9048235d9..f3f1bf1a0a71 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************* | 1 | /******************************************************************* |
2 | * This file is part of the Emulex Linux Device Driver for * | 2 | * This file is part of the Emulex Linux Device Driver for * |
3 | * Fibre Channel Host Bus Adapters. * | 3 | * Fibre Channel Host Bus Adapters. * |
4 | * Copyright (C) 2009 Emulex. All rights reserved. * | 4 | * Copyright (C) 2009-2010 Emulex. All rights reserved. * |
5 | * EMULEX and SLI are trademarks of Emulex. * | 5 | * EMULEX and SLI are trademarks of Emulex. * |
6 | * www.emulex.com * | 6 | * www.emulex.com * |
7 | * * | 7 | * * |
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/mempool.h> | 22 | #include <linux/mempool.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/delay.h> | ||
24 | 25 | ||
25 | #include <scsi/scsi.h> | 26 | #include <scsi/scsi.h> |
26 | #include <scsi/scsi_host.h> | 27 | #include <scsi/scsi_host.h> |
@@ -33,6 +34,7 @@ | |||
33 | #include "lpfc_sli.h" | 34 | #include "lpfc_sli.h" |
34 | #include "lpfc_sli4.h" | 35 | #include "lpfc_sli4.h" |
35 | #include "lpfc_nl.h" | 36 | #include "lpfc_nl.h" |
37 | #include "lpfc_bsg.h" | ||
36 | #include "lpfc_disc.h" | 38 | #include "lpfc_disc.h" |
37 | #include "lpfc_scsi.h" | 39 | #include "lpfc_scsi.h" |
38 | #include "lpfc.h" | 40 | #include "lpfc.h" |
@@ -41,14 +43,183 @@ | |||
41 | #include "lpfc_vport.h" | 43 | #include "lpfc_vport.h" |
42 | #include "lpfc_version.h" | 44 | #include "lpfc_version.h" |
43 | 45 | ||
46 | struct lpfc_bsg_event { | ||
47 | struct list_head node; | ||
48 | struct kref kref; | ||
49 | wait_queue_head_t wq; | ||
50 | |||
51 | /* Event type and waiter identifiers */ | ||
52 | uint32_t type_mask; | ||
53 | uint32_t req_id; | ||
54 | uint32_t reg_id; | ||
55 | |||
56 | /* next two flags are here for the auto-delete logic */ | ||
57 | unsigned long wait_time_stamp; | ||
58 | int waiting; | ||
59 | |||
60 | /* seen and not seen events */ | ||
61 | struct list_head events_to_get; | ||
62 | struct list_head events_to_see; | ||
63 | |||
64 | /* job waiting for this event to finish */ | ||
65 | struct fc_bsg_job *set_job; | ||
66 | }; | ||
67 | |||
68 | struct lpfc_bsg_iocb { | ||
69 | struct lpfc_iocbq *cmdiocbq; | ||
70 | struct lpfc_iocbq *rspiocbq; | ||
71 | struct lpfc_dmabuf *bmp; | ||
72 | struct lpfc_nodelist *ndlp; | ||
73 | |||
74 | /* job waiting for this iocb to finish */ | ||
75 | struct fc_bsg_job *set_job; | ||
76 | }; | ||
77 | |||
78 | struct lpfc_bsg_mbox { | ||
79 | LPFC_MBOXQ_t *pmboxq; | ||
80 | MAILBOX_t *mb; | ||
81 | |||
82 | /* job waiting for this mbox command to finish */ | ||
83 | struct fc_bsg_job *set_job; | ||
84 | }; | ||
85 | |||
86 | #define TYPE_EVT 1 | ||
87 | #define TYPE_IOCB 2 | ||
88 | #define TYPE_MBOX 3 | ||
89 | struct bsg_job_data { | ||
90 | uint32_t type; | ||
91 | union { | ||
92 | struct lpfc_bsg_event *evt; | ||
93 | struct lpfc_bsg_iocb iocb; | ||
94 | struct lpfc_bsg_mbox mbox; | ||
95 | } context_un; | ||
96 | }; | ||
97 | |||
98 | struct event_data { | ||
99 | struct list_head node; | ||
100 | uint32_t type; | ||
101 | uint32_t immed_dat; | ||
102 | void *data; | ||
103 | uint32_t len; | ||
104 | }; | ||
105 | |||
106 | #define BUF_SZ_4K 4096 | ||
107 | #define SLI_CT_ELX_LOOPBACK 0x10 | ||
108 | |||
109 | enum ELX_LOOPBACK_CMD { | ||
110 | ELX_LOOPBACK_XRI_SETUP, | ||
111 | ELX_LOOPBACK_DATA, | ||
112 | }; | ||
113 | |||
114 | #define ELX_LOOPBACK_HEADER_SZ \ | ||
115 | (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un) | ||
116 | |||
117 | struct lpfc_dmabufext { | ||
118 | struct lpfc_dmabuf dma; | ||
119 | uint32_t size; | ||
120 | uint32_t flag; | ||
121 | }; | ||
122 | |||
123 | /** | ||
124 | * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler | ||
125 | * @phba: Pointer to HBA context object. | ||
126 | * @cmdiocbq: Pointer to command iocb. | ||
127 | * @rspiocbq: Pointer to response iocb. | ||
128 | * | ||
129 | * This function is the completion handler for iocbs issued using | ||
130 | * lpfc_bsg_send_mgmt_cmd function. This function is called by the | ||
131 | * ring event handler function without any lock held. This function | ||
132 | * can be called from both worker thread context and interrupt | ||
133 | * context. This function also can be called from another thread which | ||
134 | * cleans up the SLI layer objects. | ||
135 | * This function copies the contents of the response iocb to the | ||
136 | * response iocb memory object provided by the caller of | ||
137 | * lpfc_sli_issue_iocb_wait and then wakes up the thread which | ||
138 | * sleeps for the iocb completion. | ||
139 | **/ | ||
140 | static void | ||
141 | lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, | ||
142 | struct lpfc_iocbq *cmdiocbq, | ||
143 | struct lpfc_iocbq *rspiocbq) | ||
144 | { | ||
145 | unsigned long iflags; | ||
146 | struct bsg_job_data *dd_data; | ||
147 | struct fc_bsg_job *job; | ||
148 | IOCB_t *rsp; | ||
149 | struct lpfc_dmabuf *bmp; | ||
150 | struct lpfc_nodelist *ndlp; | ||
151 | struct lpfc_bsg_iocb *iocb; | ||
152 | unsigned long flags; | ||
153 | int rc = 0; | ||
154 | |||
155 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
156 | dd_data = cmdiocbq->context1; | ||
157 | if (!dd_data) { | ||
158 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
159 | return; | ||
160 | } | ||
161 | |||
162 | iocb = &dd_data->context_un.iocb; | ||
163 | job = iocb->set_job; | ||
164 | job->dd_data = NULL; /* so timeout handler does not reply */ | ||
165 | |||
166 | spin_lock_irqsave(&phba->hbalock, iflags); | ||
167 | cmdiocbq->iocb_flag |= LPFC_IO_WAKE; | ||
168 | if (cmdiocbq->context2 && rspiocbq) | ||
169 | memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, | ||
170 | &rspiocbq->iocb, sizeof(IOCB_t)); | ||
171 | spin_unlock_irqrestore(&phba->hbalock, iflags); | ||
172 | |||
173 | bmp = iocb->bmp; | ||
174 | rspiocbq = iocb->rspiocbq; | ||
175 | rsp = &rspiocbq->iocb; | ||
176 | ndlp = iocb->ndlp; | ||
177 | |||
178 | pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, | ||
179 | job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
180 | pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, | ||
181 | job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
182 | |||
183 | if (rsp->ulpStatus) { | ||
184 | if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { | ||
185 | switch (rsp->un.ulpWord[4] & 0xff) { | ||
186 | case IOERR_SEQUENCE_TIMEOUT: | ||
187 | rc = -ETIMEDOUT; | ||
188 | break; | ||
189 | case IOERR_INVALID_RPI: | ||
190 | rc = -EFAULT; | ||
191 | break; | ||
192 | default: | ||
193 | rc = -EACCES; | ||
194 | break; | ||
195 | } | ||
196 | } else | ||
197 | rc = -EACCES; | ||
198 | } else | ||
199 | job->reply->reply_payload_rcv_len = | ||
200 | rsp->un.genreq64.bdl.bdeSize; | ||
201 | |||
202 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||
203 | lpfc_sli_release_iocbq(phba, rspiocbq); | ||
204 | lpfc_sli_release_iocbq(phba, cmdiocbq); | ||
205 | lpfc_nlp_put(ndlp); | ||
206 | kfree(bmp); | ||
207 | kfree(dd_data); | ||
208 | /* make error code available to userspace */ | ||
209 | job->reply->result = rc; | ||
210 | /* complete the job back to userspace */ | ||
211 | job->job_done(job); | ||
212 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
213 | return; | ||
214 | } | ||
215 | |||
44 | /** | 216 | /** |
45 | * lpfc_bsg_rport_ct - send a CT command from a bsg request | 217 | * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request |
46 | * @job: fc_bsg_job to handle | 218 | * @job: fc_bsg_job to handle |
47 | */ | 219 | **/ |
48 | static int | 220 | static int |
49 | lpfc_bsg_rport_ct(struct fc_bsg_job *job) | 221 | lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) |
50 | { | 222 | { |
51 | struct Scsi_Host *shost = job->shost; | ||
52 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; | 223 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; |
53 | struct lpfc_hba *phba = vport->phba; | 224 | struct lpfc_hba *phba = vport->phba; |
54 | struct lpfc_rport_data *rdata = job->rport->dd_data; | 225 | struct lpfc_rport_data *rdata = job->rport->dd_data; |
@@ -65,57 +236,60 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job) | |||
65 | struct scatterlist *sgel = NULL; | 236 | struct scatterlist *sgel = NULL; |
66 | int numbde; | 237 | int numbde; |
67 | dma_addr_t busaddr; | 238 | dma_addr_t busaddr; |
239 | struct bsg_job_data *dd_data; | ||
240 | uint32_t creg_val; | ||
68 | int rc = 0; | 241 | int rc = 0; |
69 | 242 | ||
70 | /* in case no data is transferred */ | 243 | /* in case no data is transferred */ |
71 | job->reply->reply_payload_rcv_len = 0; | 244 | job->reply->reply_payload_rcv_len = 0; |
72 | 245 | ||
246 | /* allocate our bsg tracking structure */ | ||
247 | dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); | ||
248 | if (!dd_data) { | ||
249 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
250 | "2733 Failed allocation of dd_data\n"); | ||
251 | rc = -ENOMEM; | ||
252 | goto no_dd_data; | ||
253 | } | ||
254 | |||
73 | if (!lpfc_nlp_get(ndlp)) { | 255 | if (!lpfc_nlp_get(ndlp)) { |
74 | job->reply->result = -ENODEV; | 256 | rc = -ENODEV; |
75 | return 0; | 257 | goto no_ndlp; |
258 | } | ||
259 | |||
260 | bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); | ||
261 | if (!bmp) { | ||
262 | rc = -ENOMEM; | ||
263 | goto free_ndlp; | ||
76 | } | 264 | } |
77 | 265 | ||
78 | if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { | 266 | if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { |
79 | rc = -ENODEV; | 267 | rc = -ENODEV; |
80 | goto free_ndlp_exit; | 268 | goto free_bmp; |
81 | } | 269 | } |
82 | 270 | ||
83 | spin_lock_irq(shost->host_lock); | ||
84 | cmdiocbq = lpfc_sli_get_iocbq(phba); | 271 | cmdiocbq = lpfc_sli_get_iocbq(phba); |
85 | if (!cmdiocbq) { | 272 | if (!cmdiocbq) { |
86 | rc = -ENOMEM; | 273 | rc = -ENOMEM; |
87 | spin_unlock_irq(shost->host_lock); | 274 | goto free_bmp; |
88 | goto free_ndlp_exit; | ||
89 | } | 275 | } |
90 | cmd = &cmdiocbq->iocb; | ||
91 | 276 | ||
277 | cmd = &cmdiocbq->iocb; | ||
92 | rspiocbq = lpfc_sli_get_iocbq(phba); | 278 | rspiocbq = lpfc_sli_get_iocbq(phba); |
93 | if (!rspiocbq) { | 279 | if (!rspiocbq) { |
94 | rc = -ENOMEM; | 280 | rc = -ENOMEM; |
95 | goto free_cmdiocbq; | 281 | goto free_cmdiocbq; |
96 | } | 282 | } |
97 | spin_unlock_irq(shost->host_lock); | ||
98 | 283 | ||
99 | rsp = &rspiocbq->iocb; | 284 | rsp = &rspiocbq->iocb; |
100 | |||
101 | bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); | ||
102 | if (!bmp) { | ||
103 | rc = -ENOMEM; | ||
104 | spin_lock_irq(shost->host_lock); | ||
105 | goto free_rspiocbq; | ||
106 | } | ||
107 | |||
108 | spin_lock_irq(shost->host_lock); | ||
109 | bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); | 285 | bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); |
110 | if (!bmp->virt) { | 286 | if (!bmp->virt) { |
111 | rc = -ENOMEM; | 287 | rc = -ENOMEM; |
112 | goto free_bmp; | 288 | goto free_rspiocbq; |
113 | } | 289 | } |
114 | spin_unlock_irq(shost->host_lock); | ||
115 | 290 | ||
116 | INIT_LIST_HEAD(&bmp->list); | 291 | INIT_LIST_HEAD(&bmp->list); |
117 | bpl = (struct ulp_bde64 *) bmp->virt; | 292 | bpl = (struct ulp_bde64 *) bmp->virt; |
118 | |||
119 | request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, | 293 | request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, |
120 | job->request_payload.sg_cnt, DMA_TO_DEVICE); | 294 | job->request_payload.sg_cnt, DMA_TO_DEVICE); |
121 | for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { | 295 | for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { |
@@ -157,78 +331,152 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job) | |||
157 | cmd->ulpContext = ndlp->nlp_rpi; | 331 | cmd->ulpContext = ndlp->nlp_rpi; |
158 | cmd->ulpOwner = OWN_CHIP; | 332 | cmd->ulpOwner = OWN_CHIP; |
159 | cmdiocbq->vport = phba->pport; | 333 | cmdiocbq->vport = phba->pport; |
160 | cmdiocbq->context1 = NULL; | 334 | cmdiocbq->context3 = bmp; |
161 | cmdiocbq->context2 = NULL; | ||
162 | cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; | 335 | cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; |
163 | |||
164 | timeout = phba->fc_ratov * 2; | 336 | timeout = phba->fc_ratov * 2; |
165 | job->dd_data = cmdiocbq; | 337 | cmd->ulpTimeout = timeout; |
166 | 338 | ||
167 | rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, | 339 | cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; |
168 | timeout + LPFC_DRVR_TIMEOUT); | 340 | cmdiocbq->context1 = dd_data; |
169 | 341 | cmdiocbq->context2 = rspiocbq; | |
170 | if (rc != IOCB_TIMEDOUT) { | 342 | dd_data->type = TYPE_IOCB; |
171 | pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, | 343 | dd_data->context_un.iocb.cmdiocbq = cmdiocbq; |
172 | job->request_payload.sg_cnt, DMA_TO_DEVICE); | 344 | dd_data->context_un.iocb.rspiocbq = rspiocbq; |
173 | pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, | 345 | dd_data->context_un.iocb.set_job = job; |
174 | job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | 346 | dd_data->context_un.iocb.bmp = bmp; |
347 | dd_data->context_un.iocb.ndlp = ndlp; | ||
348 | |||
349 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { | ||
350 | creg_val = readl(phba->HCregaddr); | ||
351 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); | ||
352 | writel(creg_val, phba->HCregaddr); | ||
353 | readl(phba->HCregaddr); /* flush */ | ||
175 | } | 354 | } |
176 | 355 | ||
177 | if (rc == IOCB_TIMEDOUT) { | 356 | rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); |
178 | lpfc_sli_release_iocbq(phba, rspiocbq); | ||
179 | rc = -EACCES; | ||
180 | goto free_ndlp_exit; | ||
181 | } | ||
182 | 357 | ||
183 | if (rc != IOCB_SUCCESS) { | 358 | if (rc == IOCB_SUCCESS) |
184 | rc = -EACCES; | 359 | return 0; /* done for now */ |
185 | goto free_outdmp; | ||
186 | } | ||
187 | 360 | ||
188 | if (rsp->ulpStatus) { | 361 | /* iocb failed so cleanup */ |
189 | if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { | 362 | pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, |
190 | switch (rsp->un.ulpWord[4] & 0xff) { | 363 | job->request_payload.sg_cnt, DMA_TO_DEVICE); |
191 | case IOERR_SEQUENCE_TIMEOUT: | 364 | pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, |
192 | rc = -ETIMEDOUT; | 365 | job->reply_payload.sg_cnt, DMA_FROM_DEVICE); |
193 | break; | ||
194 | case IOERR_INVALID_RPI: | ||
195 | rc = -EFAULT; | ||
196 | break; | ||
197 | default: | ||
198 | rc = -EACCES; | ||
199 | break; | ||
200 | } | ||
201 | goto free_outdmp; | ||
202 | } | ||
203 | } else | ||
204 | job->reply->reply_payload_rcv_len = | ||
205 | rsp->un.genreq64.bdl.bdeSize; | ||
206 | 366 | ||
207 | free_outdmp: | ||
208 | spin_lock_irq(shost->host_lock); | ||
209 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | 367 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); |
210 | free_bmp: | 368 | |
211 | kfree(bmp); | ||
212 | free_rspiocbq: | 369 | free_rspiocbq: |
213 | lpfc_sli_release_iocbq(phba, rspiocbq); | 370 | lpfc_sli_release_iocbq(phba, rspiocbq); |
214 | free_cmdiocbq: | 371 | free_cmdiocbq: |
215 | lpfc_sli_release_iocbq(phba, cmdiocbq); | 372 | lpfc_sli_release_iocbq(phba, cmdiocbq); |
216 | spin_unlock_irq(shost->host_lock); | 373 | free_bmp: |
217 | free_ndlp_exit: | 374 | kfree(bmp); |
375 | free_ndlp: | ||
218 | lpfc_nlp_put(ndlp); | 376 | lpfc_nlp_put(ndlp); |
377 | no_ndlp: | ||
378 | kfree(dd_data); | ||
379 | no_dd_data: | ||
380 | /* make error code available to userspace */ | ||
381 | job->reply->result = rc; | ||
382 | job->dd_data = NULL; | ||
383 | return rc; | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler | ||
388 | * @phba: Pointer to HBA context object. | ||
389 | * @cmdiocbq: Pointer to command iocb. | ||
390 | * @rspiocbq: Pointer to response iocb. | ||
391 | * | ||
392 | * This function is the completion handler for iocbs issued using | ||
393 | * lpfc_bsg_rport_els_cmp function. This function is called by the | ||
394 | * ring event handler function without any lock held. This function | ||
395 | * can be called from both worker thread context and interrupt | ||
396 | * context. This function also can be called from other thread which | ||
397 | * cleans up the SLI layer objects. | ||
398 | * This function copies the contents of the response iocb to the | ||
399 | * response iocb memory object provided by the caller of | ||
400 | * lpfc_sli_issue_iocb_wait and then wakes up the thread which | ||
401 | * sleeps for the iocb completion. | ||
402 | **/ | ||
403 | static void | ||
404 | lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, | ||
405 | struct lpfc_iocbq *cmdiocbq, | ||
406 | struct lpfc_iocbq *rspiocbq) | ||
407 | { | ||
408 | struct bsg_job_data *dd_data; | ||
409 | struct fc_bsg_job *job; | ||
410 | IOCB_t *rsp; | ||
411 | struct lpfc_nodelist *ndlp; | ||
412 | struct lpfc_dmabuf *pbuflist = NULL; | ||
413 | struct fc_bsg_ctels_reply *els_reply; | ||
414 | uint8_t *rjt_data; | ||
415 | unsigned long flags; | ||
416 | int rc = 0; | ||
417 | |||
418 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
419 | dd_data = cmdiocbq->context1; | ||
420 | /* normal completion and timeout crossed paths, already done */ | ||
421 | if (!dd_data) { | ||
422 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
423 | return; | ||
424 | } | ||
425 | |||
426 | cmdiocbq->iocb_flag |= LPFC_IO_WAKE; | ||
427 | if (cmdiocbq->context2 && rspiocbq) | ||
428 | memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, | ||
429 | &rspiocbq->iocb, sizeof(IOCB_t)); | ||
430 | |||
431 | job = dd_data->context_un.iocb.set_job; | ||
432 | cmdiocbq = dd_data->context_un.iocb.cmdiocbq; | ||
433 | rspiocbq = dd_data->context_un.iocb.rspiocbq; | ||
434 | rsp = &rspiocbq->iocb; | ||
435 | ndlp = dd_data->context_un.iocb.ndlp; | ||
436 | |||
437 | pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, | ||
438 | job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
439 | pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, | ||
440 | job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | ||
219 | 441 | ||
442 | if (job->reply->result == -EAGAIN) | ||
443 | rc = -EAGAIN; | ||
444 | else if (rsp->ulpStatus == IOSTAT_SUCCESS) | ||
445 | job->reply->reply_payload_rcv_len = | ||
446 | rsp->un.elsreq64.bdl.bdeSize; | ||
447 | else if (rsp->ulpStatus == IOSTAT_LS_RJT) { | ||
448 | job->reply->reply_payload_rcv_len = | ||
449 | sizeof(struct fc_bsg_ctels_reply); | ||
450 | /* LS_RJT data returned in word 4 */ | ||
451 | rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; | ||
452 | els_reply = &job->reply->reply_data.ctels_reply; | ||
453 | els_reply->status = FC_CTELS_STATUS_REJECT; | ||
454 | els_reply->rjt_data.action = rjt_data[3]; | ||
455 | els_reply->rjt_data.reason_code = rjt_data[2]; | ||
456 | els_reply->rjt_data.reason_explanation = rjt_data[1]; | ||
457 | els_reply->rjt_data.vendor_unique = rjt_data[0]; | ||
458 | } else | ||
459 | rc = -EIO; | ||
460 | |||
461 | pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3; | ||
462 | lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys); | ||
463 | lpfc_sli_release_iocbq(phba, rspiocbq); | ||
464 | lpfc_sli_release_iocbq(phba, cmdiocbq); | ||
465 | lpfc_nlp_put(ndlp); | ||
466 | kfree(dd_data); | ||
220 | /* make error code available to userspace */ | 467 | /* make error code available to userspace */ |
221 | job->reply->result = rc; | 468 | job->reply->result = rc; |
469 | job->dd_data = NULL; | ||
222 | /* complete the job back to userspace */ | 470 | /* complete the job back to userspace */ |
223 | job->job_done(job); | 471 | job->job_done(job); |
224 | 472 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | |
225 | return 0; | 473 | return; |
226 | } | 474 | } |
227 | 475 | ||
228 | /** | 476 | /** |
229 | * lpfc_bsg_rport_els - send an ELS command from a bsg request | 477 | * lpfc_bsg_rport_els - send an ELS command from a bsg request |
230 | * @job: fc_bsg_job to handle | 478 | * @job: fc_bsg_job to handle |
231 | */ | 479 | **/ |
232 | static int | 480 | static int |
233 | lpfc_bsg_rport_els(struct fc_bsg_job *job) | 481 | lpfc_bsg_rport_els(struct fc_bsg_job *job) |
234 | { | 482 | { |
@@ -236,7 +484,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) | |||
236 | struct lpfc_hba *phba = vport->phba; | 484 | struct lpfc_hba *phba = vport->phba; |
237 | struct lpfc_rport_data *rdata = job->rport->dd_data; | 485 | struct lpfc_rport_data *rdata = job->rport->dd_data; |
238 | struct lpfc_nodelist *ndlp = rdata->pnode; | 486 | struct lpfc_nodelist *ndlp = rdata->pnode; |
239 | |||
240 | uint32_t elscmd; | 487 | uint32_t elscmd; |
241 | uint32_t cmdsize; | 488 | uint32_t cmdsize; |
242 | uint32_t rspsize; | 489 | uint32_t rspsize; |
@@ -248,20 +495,30 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) | |||
248 | struct lpfc_dmabuf *prsp; | 495 | struct lpfc_dmabuf *prsp; |
249 | struct lpfc_dmabuf *pbuflist = NULL; | 496 | struct lpfc_dmabuf *pbuflist = NULL; |
250 | struct ulp_bde64 *bpl; | 497 | struct ulp_bde64 *bpl; |
251 | int iocb_status; | ||
252 | int request_nseg; | 498 | int request_nseg; |
253 | int reply_nseg; | 499 | int reply_nseg; |
254 | struct scatterlist *sgel = NULL; | 500 | struct scatterlist *sgel = NULL; |
255 | int numbde; | 501 | int numbde; |
256 | dma_addr_t busaddr; | 502 | dma_addr_t busaddr; |
503 | struct bsg_job_data *dd_data; | ||
504 | uint32_t creg_val; | ||
257 | int rc = 0; | 505 | int rc = 0; |
258 | 506 | ||
259 | /* in case no data is transferred */ | 507 | /* in case no data is transferred */ |
260 | job->reply->reply_payload_rcv_len = 0; | 508 | job->reply->reply_payload_rcv_len = 0; |
261 | 509 | ||
510 | /* allocate our bsg tracking structure */ | ||
511 | dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); | ||
512 | if (!dd_data) { | ||
513 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
514 | "2735 Failed allocation of dd_data\n"); | ||
515 | rc = -ENOMEM; | ||
516 | goto no_dd_data; | ||
517 | } | ||
518 | |||
262 | if (!lpfc_nlp_get(ndlp)) { | 519 | if (!lpfc_nlp_get(ndlp)) { |
263 | rc = -ENODEV; | 520 | rc = -ENODEV; |
264 | goto out; | 521 | goto free_dd_data; |
265 | } | 522 | } |
266 | 523 | ||
267 | elscmd = job->request->rqst_data.r_els.els_code; | 524 | elscmd = job->request->rqst_data.r_els.els_code; |
@@ -271,24 +528,24 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) | |||
271 | if (!rspiocbq) { | 528 | if (!rspiocbq) { |
272 | lpfc_nlp_put(ndlp); | 529 | lpfc_nlp_put(ndlp); |
273 | rc = -ENOMEM; | 530 | rc = -ENOMEM; |
274 | goto out; | 531 | goto free_dd_data; |
275 | } | 532 | } |
276 | 533 | ||
277 | rsp = &rspiocbq->iocb; | 534 | rsp = &rspiocbq->iocb; |
278 | rpi = ndlp->nlp_rpi; | 535 | rpi = ndlp->nlp_rpi; |
279 | 536 | ||
280 | cmdiocbq = lpfc_prep_els_iocb(phba->pport, 1, cmdsize, 0, ndlp, | 537 | cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, |
281 | ndlp->nlp_DID, elscmd); | 538 | ndlp->nlp_DID, elscmd); |
282 | |||
283 | if (!cmdiocbq) { | 539 | if (!cmdiocbq) { |
284 | lpfc_sli_release_iocbq(phba, rspiocbq); | 540 | rc = -EIO; |
285 | return -EIO; | 541 | goto free_rspiocbq; |
286 | } | 542 | } |
287 | 543 | ||
288 | job->dd_data = cmdiocbq; | 544 | /* prep els iocb set context1 to the ndlp, context2 to the command |
545 | * dmabuf, context3 holds the data dmabuf | ||
546 | */ | ||
289 | pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; | 547 | pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; |
290 | prsp = (struct lpfc_dmabuf *) pcmd->list.next; | 548 | prsp = (struct lpfc_dmabuf *) pcmd->list.next; |
291 | |||
292 | lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); | 549 | lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); |
293 | kfree(pcmd); | 550 | kfree(pcmd); |
294 | lpfc_mbuf_free(phba, prsp->virt, prsp->phys); | 551 | lpfc_mbuf_free(phba, prsp->virt, prsp->phys); |
@@ -300,7 +557,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) | |||
300 | 557 | ||
301 | request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, | 558 | request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, |
302 | job->request_payload.sg_cnt, DMA_TO_DEVICE); | 559 | job->request_payload.sg_cnt, DMA_TO_DEVICE); |
303 | |||
304 | for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { | 560 | for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { |
305 | busaddr = sg_dma_address(sgel); | 561 | busaddr = sg_dma_address(sgel); |
306 | bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; | 562 | bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; |
@@ -322,7 +578,6 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) | |||
322 | bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); | 578 | bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); |
323 | bpl++; | 579 | bpl++; |
324 | } | 580 | } |
325 | |||
326 | cmdiocbq->iocb.un.elsreq64.bdl.bdeSize = | 581 | cmdiocbq->iocb.un.elsreq64.bdl.bdeSize = |
327 | (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); | 582 | (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); |
328 | cmdiocbq->iocb.ulpContext = rpi; | 583 | cmdiocbq->iocb.ulpContext = rpi; |
@@ -330,102 +585,62 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) | |||
330 | cmdiocbq->context1 = NULL; | 585 | cmdiocbq->context1 = NULL; |
331 | cmdiocbq->context2 = NULL; | 586 | cmdiocbq->context2 = NULL; |
332 | 587 | ||
333 | iocb_status = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, | 588 | cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; |
334 | rspiocbq, (phba->fc_ratov * 2) | 589 | cmdiocbq->context1 = dd_data; |
335 | + LPFC_DRVR_TIMEOUT); | 590 | cmdiocbq->context2 = rspiocbq; |
336 | 591 | dd_data->type = TYPE_IOCB; | |
337 | /* release the new ndlp once the iocb completes */ | 592 | dd_data->context_un.iocb.cmdiocbq = cmdiocbq; |
338 | lpfc_nlp_put(ndlp); | 593 | dd_data->context_un.iocb.rspiocbq = rspiocbq; |
339 | if (iocb_status != IOCB_TIMEDOUT) { | 594 | dd_data->context_un.iocb.set_job = job; |
340 | pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, | 595 | dd_data->context_un.iocb.bmp = NULL;; |
341 | job->request_payload.sg_cnt, DMA_TO_DEVICE); | 596 | dd_data->context_un.iocb.ndlp = ndlp; |
342 | pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, | 597 | |
343 | job->reply_payload.sg_cnt, DMA_FROM_DEVICE); | 598 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { |
599 | creg_val = readl(phba->HCregaddr); | ||
600 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); | ||
601 | writel(creg_val, phba->HCregaddr); | ||
602 | readl(phba->HCregaddr); /* flush */ | ||
344 | } | 603 | } |
604 | rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); | ||
605 | lpfc_nlp_put(ndlp); | ||
606 | if (rc == IOCB_SUCCESS) | ||
607 | return 0; /* done for now */ | ||
345 | 608 | ||
346 | if (iocb_status == IOCB_SUCCESS) { | 609 | pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, |
347 | if (rsp->ulpStatus == IOSTAT_SUCCESS) { | 610 | job->request_payload.sg_cnt, DMA_TO_DEVICE); |
348 | job->reply->reply_payload_rcv_len = | 611 | pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, |
349 | rsp->un.elsreq64.bdl.bdeSize; | 612 | job->reply_payload.sg_cnt, DMA_FROM_DEVICE); |
350 | rc = 0; | 613 | |
351 | } else if (rsp->ulpStatus == IOSTAT_LS_RJT) { | 614 | lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys); |
352 | struct fc_bsg_ctels_reply *els_reply; | ||
353 | /* LS_RJT data returned in word 4 */ | ||
354 | uint8_t *rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; | ||
355 | |||
356 | els_reply = &job->reply->reply_data.ctels_reply; | ||
357 | job->reply->result = 0; | ||
358 | els_reply->status = FC_CTELS_STATUS_REJECT; | ||
359 | els_reply->rjt_data.action = rjt_data[0]; | ||
360 | els_reply->rjt_data.reason_code = rjt_data[1]; | ||
361 | els_reply->rjt_data.reason_explanation = rjt_data[2]; | ||
362 | els_reply->rjt_data.vendor_unique = rjt_data[3]; | ||
363 | } else | ||
364 | rc = -EIO; | ||
365 | } else | ||
366 | rc = -EIO; | ||
367 | 615 | ||
368 | if (iocb_status != IOCB_TIMEDOUT) | 616 | lpfc_sli_release_iocbq(phba, cmdiocbq); |
369 | lpfc_els_free_iocb(phba, cmdiocbq); | ||
370 | 617 | ||
618 | free_rspiocbq: | ||
371 | lpfc_sli_release_iocbq(phba, rspiocbq); | 619 | lpfc_sli_release_iocbq(phba, rspiocbq); |
372 | 620 | ||
373 | out: | 621 | free_dd_data: |
622 | kfree(dd_data); | ||
623 | |||
624 | no_dd_data: | ||
374 | /* make error code available to userspace */ | 625 | /* make error code available to userspace */ |
375 | job->reply->result = rc; | 626 | job->reply->result = rc; |
376 | /* complete the job back to userspace */ | 627 | job->dd_data = NULL; |
377 | job->job_done(job); | 628 | return rc; |
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | struct lpfc_ct_event { | ||
383 | struct list_head node; | ||
384 | int ref; | ||
385 | wait_queue_head_t wq; | ||
386 | |||
387 | /* Event type and waiter identifiers */ | ||
388 | uint32_t type_mask; | ||
389 | uint32_t req_id; | ||
390 | uint32_t reg_id; | ||
391 | |||
392 | /* next two flags are here for the auto-delete logic */ | ||
393 | unsigned long wait_time_stamp; | ||
394 | int waiting; | ||
395 | |||
396 | /* seen and not seen events */ | ||
397 | struct list_head events_to_get; | ||
398 | struct list_head events_to_see; | ||
399 | }; | ||
400 | |||
401 | struct event_data { | ||
402 | struct list_head node; | ||
403 | uint32_t type; | ||
404 | uint32_t immed_dat; | ||
405 | void *data; | ||
406 | uint32_t len; | ||
407 | }; | ||
408 | |||
409 | static struct lpfc_ct_event * | ||
410 | lpfc_ct_event_new(int ev_reg_id, uint32_t ev_req_id) | ||
411 | { | ||
412 | struct lpfc_ct_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); | ||
413 | if (!evt) | ||
414 | return NULL; | ||
415 | |||
416 | INIT_LIST_HEAD(&evt->events_to_get); | ||
417 | INIT_LIST_HEAD(&evt->events_to_see); | ||
418 | evt->req_id = ev_req_id; | ||
419 | evt->reg_id = ev_reg_id; | ||
420 | evt->wait_time_stamp = jiffies; | ||
421 | init_waitqueue_head(&evt->wq); | ||
422 | |||
423 | return evt; | ||
424 | } | 629 | } |
425 | 630 | ||
631 | /** | ||
632 | * lpfc_bsg_event_free - frees an allocated event structure | ||
633 | * @kref: Pointer to a kref. | ||
634 | * | ||
635 | * Called from kref_put. Back cast the kref into an event structure address. | ||
636 | * Free any events to get, delete associated nodes, free any events to see, | ||
637 | * free any data then free the event itself. | ||
638 | **/ | ||
426 | static void | 639 | static void |
427 | lpfc_ct_event_free(struct lpfc_ct_event *evt) | 640 | lpfc_bsg_event_free(struct kref *kref) |
428 | { | 641 | { |
642 | struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event, | ||
643 | kref); | ||
429 | struct event_data *ed; | 644 | struct event_data *ed; |
430 | 645 | ||
431 | list_del(&evt->node); | 646 | list_del(&evt->node); |
@@ -447,25 +662,82 @@ lpfc_ct_event_free(struct lpfc_ct_event *evt) | |||
447 | kfree(evt); | 662 | kfree(evt); |
448 | } | 663 | } |
449 | 664 | ||
665 | /** | ||
666 | * lpfc_bsg_event_ref - increments the kref for an event | ||
667 | * @evt: Pointer to an event structure. | ||
668 | **/ | ||
450 | static inline void | 669 | static inline void |
451 | lpfc_ct_event_ref(struct lpfc_ct_event *evt) | 670 | lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) |
452 | { | 671 | { |
453 | evt->ref++; | 672 | kref_get(&evt->kref); |
454 | } | 673 | } |
455 | 674 | ||
675 | /** | ||
676 | * lpfc_bsg_event_unref - Uses kref_put to free an event structure | ||
677 | * @evt: Pointer to an event structure. | ||
678 | **/ | ||
456 | static inline void | 679 | static inline void |
457 | lpfc_ct_event_unref(struct lpfc_ct_event *evt) | 680 | lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) |
458 | { | 681 | { |
459 | if (--evt->ref < 0) | 682 | kref_put(&evt->kref, lpfc_bsg_event_free); |
460 | lpfc_ct_event_free(evt); | ||
461 | } | 683 | } |
462 | 684 | ||
463 | #define SLI_CT_ELX_LOOPBACK 0x10 | 685 | /** |
686 | * lpfc_bsg_event_new - allocate and initialize a event structure | ||
687 | * @ev_mask: Mask of events. | ||
688 | * @ev_reg_id: Event reg id. | ||
689 | * @ev_req_id: Event request id. | ||
690 | **/ | ||
691 | static struct lpfc_bsg_event * | ||
692 | lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) | ||
693 | { | ||
694 | struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); | ||
464 | 695 | ||
465 | enum ELX_LOOPBACK_CMD { | 696 | if (!evt) |
466 | ELX_LOOPBACK_XRI_SETUP, | 697 | return NULL; |
467 | ELX_LOOPBACK_DATA, | 698 | |
468 | }; | 699 | INIT_LIST_HEAD(&evt->events_to_get); |
700 | INIT_LIST_HEAD(&evt->events_to_see); | ||
701 | evt->type_mask = ev_mask; | ||
702 | evt->req_id = ev_req_id; | ||
703 | evt->reg_id = ev_reg_id; | ||
704 | evt->wait_time_stamp = jiffies; | ||
705 | init_waitqueue_head(&evt->wq); | ||
706 | kref_init(&evt->kref); | ||
707 | return evt; | ||
708 | } | ||
709 | |||
710 | /** | ||
711 | * diag_cmd_data_free - Frees an lpfc dma buffer extension | ||
712 | * @phba: Pointer to HBA context object. | ||
713 | * @mlist: Pointer to an lpfc dma buffer extension. | ||
714 | **/ | ||
715 | static int | ||
716 | diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) | ||
717 | { | ||
718 | struct lpfc_dmabufext *mlast; | ||
719 | struct pci_dev *pcidev; | ||
720 | struct list_head head, *curr, *next; | ||
721 | |||
722 | if ((!mlist) || (!lpfc_is_link_up(phba) && | ||
723 | (phba->link_flag & LS_LOOPBACK_MODE))) { | ||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | pcidev = phba->pcidev; | ||
728 | list_add_tail(&head, &mlist->dma.list); | ||
729 | |||
730 | list_for_each_safe(curr, next, &head) { | ||
731 | mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); | ||
732 | if (mlast->dma.virt) | ||
733 | dma_free_coherent(&pcidev->dev, | ||
734 | mlast->size, | ||
735 | mlast->dma.virt, | ||
736 | mlast->dma.phys); | ||
737 | kfree(mlast); | ||
738 | } | ||
739 | return 0; | ||
740 | } | ||
469 | 741 | ||
470 | /** | 742 | /** |
471 | * lpfc_bsg_ct_unsol_event - process an unsolicited CT command | 743 | * lpfc_bsg_ct_unsol_event - process an unsolicited CT command |
@@ -474,9 +746,9 @@ enum ELX_LOOPBACK_CMD { | |||
474 | * @piocbq: | 746 | * @piocbq: |
475 | * | 747 | * |
476 | * This function is called when an unsolicited CT command is received. It | 748 | * This function is called when an unsolicited CT command is received. It |
477 | * forwards the event to any processes registerd to receive CT events. | 749 | * forwards the event to any processes registered to receive CT events. |
478 | */ | 750 | **/ |
479 | void | 751 | int |
480 | lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | 752 | lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, |
481 | struct lpfc_iocbq *piocbq) | 753 | struct lpfc_iocbq *piocbq) |
482 | { | 754 | { |
@@ -484,7 +756,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
484 | uint32_t cmd; | 756 | uint32_t cmd; |
485 | uint32_t len; | 757 | uint32_t len; |
486 | struct lpfc_dmabuf *dmabuf = NULL; | 758 | struct lpfc_dmabuf *dmabuf = NULL; |
487 | struct lpfc_ct_event *evt; | 759 | struct lpfc_bsg_event *evt; |
488 | struct event_data *evt_dat = NULL; | 760 | struct event_data *evt_dat = NULL; |
489 | struct lpfc_iocbq *iocbq; | 761 | struct lpfc_iocbq *iocbq; |
490 | size_t offset = 0; | 762 | size_t offset = 0; |
@@ -496,6 +768,9 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
496 | struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; | 768 | struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; |
497 | struct lpfc_hbq_entry *hbqe; | 769 | struct lpfc_hbq_entry *hbqe; |
498 | struct lpfc_sli_ct_request *ct_req; | 770 | struct lpfc_sli_ct_request *ct_req; |
771 | struct fc_bsg_job *job = NULL; | ||
772 | unsigned long flags; | ||
773 | int size = 0; | ||
499 | 774 | ||
500 | INIT_LIST_HEAD(&head); | 775 | INIT_LIST_HEAD(&head); |
501 | list_add_tail(&head, &piocbq->list); | 776 | list_add_tail(&head, &piocbq->list); |
@@ -504,6 +779,10 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
504 | piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) | 779 | piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) |
505 | goto error_ct_unsol_exit; | 780 | goto error_ct_unsol_exit; |
506 | 781 | ||
782 | if (phba->link_state == LPFC_HBA_ERROR || | ||
783 | (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) | ||
784 | goto error_ct_unsol_exit; | ||
785 | |||
507 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) | 786 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) |
508 | dmabuf = bdeBuf1; | 787 | dmabuf = bdeBuf1; |
509 | else { | 788 | else { |
@@ -511,7 +790,8 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
511 | piocbq->iocb.un.cont64[0].addrLow); | 790 | piocbq->iocb.un.cont64[0].addrLow); |
512 | dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); | 791 | dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); |
513 | } | 792 | } |
514 | 793 | if (dmabuf == NULL) | |
794 | goto error_ct_unsol_exit; | ||
515 | ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; | 795 | ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; |
516 | evt_req_id = ct_req->FsType; | 796 | evt_req_id = ct_req->FsType; |
517 | cmd = ct_req->CommandResponse.bits.CmdRsp; | 797 | cmd = ct_req->CommandResponse.bits.CmdRsp; |
@@ -519,24 +799,24 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
519 | if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) | 799 | if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) |
520 | lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); | 800 | lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); |
521 | 801 | ||
522 | mutex_lock(&phba->ct_event_mutex); | 802 | spin_lock_irqsave(&phba->ct_ev_lock, flags); |
523 | list_for_each_entry(evt, &phba->ct_ev_waiters, node) { | 803 | list_for_each_entry(evt, &phba->ct_ev_waiters, node) { |
524 | if (evt->req_id != evt_req_id) | 804 | if (!(evt->type_mask & FC_REG_CT_EVENT) || |
805 | evt->req_id != evt_req_id) | ||
525 | continue; | 806 | continue; |
526 | 807 | ||
527 | lpfc_ct_event_ref(evt); | 808 | lpfc_bsg_event_ref(evt); |
528 | 809 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | |
529 | evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); | 810 | evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); |
530 | if (!evt_dat) { | 811 | if (evt_dat == NULL) { |
531 | lpfc_ct_event_unref(evt); | 812 | spin_lock_irqsave(&phba->ct_ev_lock, flags); |
813 | lpfc_bsg_event_unref(evt); | ||
532 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | 814 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, |
533 | "2614 Memory allocation failed for " | 815 | "2614 Memory allocation failed for " |
534 | "CT event\n"); | 816 | "CT event\n"); |
535 | break; | 817 | break; |
536 | } | 818 | } |
537 | 819 | ||
538 | mutex_unlock(&phba->ct_event_mutex); | ||
539 | |||
540 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { | 820 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { |
541 | /* take accumulated byte count from the last iocbq */ | 821 | /* take accumulated byte count from the last iocbq */ |
542 | iocbq = list_entry(head.prev, typeof(*iocbq), list); | 822 | iocbq = list_entry(head.prev, typeof(*iocbq), list); |
@@ -550,25 +830,25 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
550 | } | 830 | } |
551 | 831 | ||
552 | evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); | 832 | evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); |
553 | if (!evt_dat->data) { | 833 | if (evt_dat->data == NULL) { |
554 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | 834 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, |
555 | "2615 Memory allocation failed for " | 835 | "2615 Memory allocation failed for " |
556 | "CT event data, size %d\n", | 836 | "CT event data, size %d\n", |
557 | evt_dat->len); | 837 | evt_dat->len); |
558 | kfree(evt_dat); | 838 | kfree(evt_dat); |
559 | mutex_lock(&phba->ct_event_mutex); | 839 | spin_lock_irqsave(&phba->ct_ev_lock, flags); |
560 | lpfc_ct_event_unref(evt); | 840 | lpfc_bsg_event_unref(evt); |
561 | mutex_unlock(&phba->ct_event_mutex); | 841 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
562 | goto error_ct_unsol_exit; | 842 | goto error_ct_unsol_exit; |
563 | } | 843 | } |
564 | 844 | ||
565 | list_for_each_entry(iocbq, &head, list) { | 845 | list_for_each_entry(iocbq, &head, list) { |
846 | size = 0; | ||
566 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { | 847 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { |
567 | bdeBuf1 = iocbq->context2; | 848 | bdeBuf1 = iocbq->context2; |
568 | bdeBuf2 = iocbq->context3; | 849 | bdeBuf2 = iocbq->context3; |
569 | } | 850 | } |
570 | for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { | 851 | for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { |
571 | int size = 0; | ||
572 | if (phba->sli3_options & | 852 | if (phba->sli3_options & |
573 | LPFC_SLI3_HBQ_ENABLED) { | 853 | LPFC_SLI3_HBQ_ENABLED) { |
574 | if (i == 0) { | 854 | if (i == 0) { |
@@ -601,9 +881,11 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
601 | iocbq); | 881 | iocbq); |
602 | kfree(evt_dat->data); | 882 | kfree(evt_dat->data); |
603 | kfree(evt_dat); | 883 | kfree(evt_dat); |
604 | mutex_lock(&phba->ct_event_mutex); | 884 | spin_lock_irqsave(&phba->ct_ev_lock, |
605 | lpfc_ct_event_unref(evt); | 885 | flags); |
606 | mutex_unlock(&phba->ct_event_mutex); | 886 | lpfc_bsg_event_unref(evt); |
887 | spin_unlock_irqrestore( | ||
888 | &phba->ct_ev_lock, flags); | ||
607 | goto error_ct_unsol_exit; | 889 | goto error_ct_unsol_exit; |
608 | } | 890 | } |
609 | memcpy((char *)(evt_dat->data) + offset, | 891 | memcpy((char *)(evt_dat->data) + offset, |
@@ -616,15 +898,24 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
616 | dmabuf); | 898 | dmabuf); |
617 | } else { | 899 | } else { |
618 | switch (cmd) { | 900 | switch (cmd) { |
901 | case ELX_LOOPBACK_DATA: | ||
902 | diag_cmd_data_free(phba, | ||
903 | (struct lpfc_dmabufext *) | ||
904 | dmabuf); | ||
905 | break; | ||
619 | case ELX_LOOPBACK_XRI_SETUP: | 906 | case ELX_LOOPBACK_XRI_SETUP: |
620 | if (!(phba->sli3_options & | 907 | if ((phba->sli_rev == |
621 | LPFC_SLI3_HBQ_ENABLED)) | 908 | LPFC_SLI_REV2) || |
909 | (phba->sli3_options & | ||
910 | LPFC_SLI3_HBQ_ENABLED | ||
911 | )) { | ||
912 | lpfc_in_buf_free(phba, | ||
913 | dmabuf); | ||
914 | } else { | ||
622 | lpfc_post_buffer(phba, | 915 | lpfc_post_buffer(phba, |
623 | pring, | 916 | pring, |
624 | 1); | 917 | 1); |
625 | else | 918 | } |
626 | lpfc_in_buf_free(phba, | ||
627 | dmabuf); | ||
628 | break; | 919 | break; |
629 | default: | 920 | default: |
630 | if (!(phba->sli3_options & | 921 | if (!(phba->sli3_options & |
@@ -638,7 +929,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
638 | } | 929 | } |
639 | } | 930 | } |
640 | 931 | ||
641 | mutex_lock(&phba->ct_event_mutex); | 932 | spin_lock_irqsave(&phba->ct_ev_lock, flags); |
642 | if (phba->sli_rev == LPFC_SLI_REV4) { | 933 | if (phba->sli_rev == LPFC_SLI_REV4) { |
643 | evt_dat->immed_dat = phba->ctx_idx; | 934 | evt_dat->immed_dat = phba->ctx_idx; |
644 | phba->ctx_idx = (phba->ctx_idx + 1) % 64; | 935 | phba->ctx_idx = (phba->ctx_idx + 1) % 64; |
@@ -651,122 +942,144 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
651 | 942 | ||
652 | evt_dat->type = FC_REG_CT_EVENT; | 943 | evt_dat->type = FC_REG_CT_EVENT; |
653 | list_add(&evt_dat->node, &evt->events_to_see); | 944 | list_add(&evt_dat->node, &evt->events_to_see); |
654 | wake_up_interruptible(&evt->wq); | 945 | if (evt_req_id == SLI_CT_ELX_LOOPBACK) { |
655 | lpfc_ct_event_unref(evt); | 946 | wake_up_interruptible(&evt->wq); |
656 | if (evt_req_id == SLI_CT_ELX_LOOPBACK) | 947 | lpfc_bsg_event_unref(evt); |
657 | break; | 948 | break; |
949 | } | ||
950 | |||
951 | list_move(evt->events_to_see.prev, &evt->events_to_get); | ||
952 | lpfc_bsg_event_unref(evt); | ||
953 | |||
954 | job = evt->set_job; | ||
955 | evt->set_job = NULL; | ||
956 | if (job) { | ||
957 | job->reply->reply_payload_rcv_len = size; | ||
958 | /* make error code available to userspace */ | ||
959 | job->reply->result = 0; | ||
960 | job->dd_data = NULL; | ||
961 | /* complete the job back to userspace */ | ||
962 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
963 | job->job_done(job); | ||
964 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
965 | } | ||
658 | } | 966 | } |
659 | mutex_unlock(&phba->ct_event_mutex); | 967 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
660 | 968 | ||
661 | error_ct_unsol_exit: | 969 | error_ct_unsol_exit: |
662 | if (!list_empty(&head)) | 970 | if (!list_empty(&head)) |
663 | list_del(&head); | 971 | list_del(&head); |
664 | 972 | if (evt_req_id == SLI_CT_ELX_LOOPBACK) | |
665 | return; | 973 | return 0; |
974 | return 1; | ||
666 | } | 975 | } |
667 | 976 | ||
668 | /** | 977 | /** |
669 | * lpfc_bsg_set_event - process a SET_EVENT bsg vendor command | 978 | * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command |
670 | * @job: SET_EVENT fc_bsg_job | 979 | * @job: SET_EVENT fc_bsg_job |
671 | */ | 980 | **/ |
672 | static int | 981 | static int |
673 | lpfc_bsg_set_event(struct fc_bsg_job *job) | 982 | lpfc_bsg_hba_set_event(struct fc_bsg_job *job) |
674 | { | 983 | { |
675 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; | 984 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; |
676 | struct lpfc_hba *phba = vport->phba; | 985 | struct lpfc_hba *phba = vport->phba; |
677 | struct set_ct_event *event_req; | 986 | struct set_ct_event *event_req; |
678 | struct lpfc_ct_event *evt; | 987 | struct lpfc_bsg_event *evt; |
679 | int rc = 0; | 988 | int rc = 0; |
989 | struct bsg_job_data *dd_data = NULL; | ||
990 | uint32_t ev_mask; | ||
991 | unsigned long flags; | ||
680 | 992 | ||
681 | if (job->request_len < | 993 | if (job->request_len < |
682 | sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { | 994 | sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { |
683 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | 995 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, |
684 | "2612 Received SET_CT_EVENT below minimum " | 996 | "2612 Received SET_CT_EVENT below minimum " |
685 | "size\n"); | 997 | "size\n"); |
686 | return -EINVAL; | 998 | rc = -EINVAL; |
999 | goto job_error; | ||
1000 | } | ||
1001 | |||
1002 | dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); | ||
1003 | if (dd_data == NULL) { | ||
1004 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
1005 | "2734 Failed allocation of dd_data\n"); | ||
1006 | rc = -ENOMEM; | ||
1007 | goto job_error; | ||
687 | } | 1008 | } |
688 | 1009 | ||
689 | event_req = (struct set_ct_event *) | 1010 | event_req = (struct set_ct_event *) |
690 | job->request->rqst_data.h_vendor.vendor_cmd; | 1011 | job->request->rqst_data.h_vendor.vendor_cmd; |
691 | 1012 | ev_mask = ((uint32_t)(unsigned long)event_req->type_mask & | |
692 | mutex_lock(&phba->ct_event_mutex); | 1013 | FC_REG_EVENT_MASK); |
1014 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
693 | list_for_each_entry(evt, &phba->ct_ev_waiters, node) { | 1015 | list_for_each_entry(evt, &phba->ct_ev_waiters, node) { |
694 | if (evt->reg_id == event_req->ev_reg_id) { | 1016 | if (evt->reg_id == event_req->ev_reg_id) { |
695 | lpfc_ct_event_ref(evt); | 1017 | lpfc_bsg_event_ref(evt); |
696 | evt->wait_time_stamp = jiffies; | 1018 | evt->wait_time_stamp = jiffies; |
697 | break; | 1019 | break; |
698 | } | 1020 | } |
699 | } | 1021 | } |
700 | mutex_unlock(&phba->ct_event_mutex); | 1022 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
701 | 1023 | ||
702 | if (&evt->node == &phba->ct_ev_waiters) { | 1024 | if (&evt->node == &phba->ct_ev_waiters) { |
703 | /* no event waiting struct yet - first call */ | 1025 | /* no event waiting struct yet - first call */ |
704 | evt = lpfc_ct_event_new(event_req->ev_reg_id, | 1026 | evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id, |
705 | event_req->ev_req_id); | 1027 | event_req->ev_req_id); |
706 | if (!evt) { | 1028 | if (!evt) { |
707 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | 1029 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, |
708 | "2617 Failed allocation of event " | 1030 | "2617 Failed allocation of event " |
709 | "waiter\n"); | 1031 | "waiter\n"); |
710 | return -ENOMEM; | 1032 | rc = -ENOMEM; |
1033 | goto job_error; | ||
711 | } | 1034 | } |
712 | 1035 | ||
713 | mutex_lock(&phba->ct_event_mutex); | 1036 | spin_lock_irqsave(&phba->ct_ev_lock, flags); |
714 | list_add(&evt->node, &phba->ct_ev_waiters); | 1037 | list_add(&evt->node, &phba->ct_ev_waiters); |
715 | lpfc_ct_event_ref(evt); | 1038 | lpfc_bsg_event_ref(evt); |
716 | mutex_unlock(&phba->ct_event_mutex); | 1039 | evt->wait_time_stamp = jiffies; |
1040 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
717 | } | 1041 | } |
718 | 1042 | ||
1043 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
719 | evt->waiting = 1; | 1044 | evt->waiting = 1; |
720 | if (wait_event_interruptible(evt->wq, | 1045 | dd_data->type = TYPE_EVT; |
721 | !list_empty(&evt->events_to_see))) { | 1046 | dd_data->context_un.evt = evt; |
722 | mutex_lock(&phba->ct_event_mutex); | 1047 | evt->set_job = job; /* for unsolicited command */ |
723 | lpfc_ct_event_unref(evt); /* release ref */ | 1048 | job->dd_data = dd_data; /* for fc transport timeout callback*/ |
724 | lpfc_ct_event_unref(evt); /* delete */ | 1049 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
725 | mutex_unlock(&phba->ct_event_mutex); | 1050 | return 0; /* call job done later */ |
726 | rc = -EINTR; | 1051 | |
727 | goto set_event_out; | 1052 | job_error: |
728 | } | 1053 | if (dd_data != NULL) |
729 | 1054 | kfree(dd_data); | |
730 | evt->wait_time_stamp = jiffies; | 1055 | |
731 | evt->waiting = 0; | 1056 | job->dd_data = NULL; |
732 | 1057 | return rc; | |
733 | mutex_lock(&phba->ct_event_mutex); | ||
734 | list_move(evt->events_to_see.prev, &evt->events_to_get); | ||
735 | lpfc_ct_event_unref(evt); /* release ref */ | ||
736 | mutex_unlock(&phba->ct_event_mutex); | ||
737 | |||
738 | set_event_out: | ||
739 | /* set_event carries no reply payload */ | ||
740 | job->reply->reply_payload_rcv_len = 0; | ||
741 | /* make error code available to userspace */ | ||
742 | job->reply->result = rc; | ||
743 | /* complete the job back to userspace */ | ||
744 | job->job_done(job); | ||
745 | |||
746 | return 0; | ||
747 | } | 1058 | } |
748 | 1059 | ||
749 | /** | 1060 | /** |
750 | * lpfc_bsg_get_event - process a GET_EVENT bsg vendor command | 1061 | * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command |
751 | * @job: GET_EVENT fc_bsg_job | 1062 | * @job: GET_EVENT fc_bsg_job |
752 | */ | 1063 | **/ |
753 | static int | 1064 | static int |
754 | lpfc_bsg_get_event(struct fc_bsg_job *job) | 1065 | lpfc_bsg_hba_get_event(struct fc_bsg_job *job) |
755 | { | 1066 | { |
756 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; | 1067 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; |
757 | struct lpfc_hba *phba = vport->phba; | 1068 | struct lpfc_hba *phba = vport->phba; |
758 | struct get_ct_event *event_req; | 1069 | struct get_ct_event *event_req; |
759 | struct get_ct_event_reply *event_reply; | 1070 | struct get_ct_event_reply *event_reply; |
760 | struct lpfc_ct_event *evt; | 1071 | struct lpfc_bsg_event *evt; |
761 | struct event_data *evt_dat = NULL; | 1072 | struct event_data *evt_dat = NULL; |
762 | int rc = 0; | 1073 | unsigned long flags; |
1074 | uint32_t rc = 0; | ||
763 | 1075 | ||
764 | if (job->request_len < | 1076 | if (job->request_len < |
765 | sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { | 1077 | sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { |
766 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | 1078 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, |
767 | "2613 Received GET_CT_EVENT request below " | 1079 | "2613 Received GET_CT_EVENT request below " |
768 | "minimum size\n"); | 1080 | "minimum size\n"); |
769 | return -EINVAL; | 1081 | rc = -EINVAL; |
1082 | goto job_error; | ||
770 | } | 1083 | } |
771 | 1084 | ||
772 | event_req = (struct get_ct_event *) | 1085 | event_req = (struct get_ct_event *) |
@@ -774,13 +1087,12 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) | |||
774 | 1087 | ||
775 | event_reply = (struct get_ct_event_reply *) | 1088 | event_reply = (struct get_ct_event_reply *) |
776 | job->reply->reply_data.vendor_reply.vendor_rsp; | 1089 | job->reply->reply_data.vendor_reply.vendor_rsp; |
777 | 1090 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | |
778 | mutex_lock(&phba->ct_event_mutex); | ||
779 | list_for_each_entry(evt, &phba->ct_ev_waiters, node) { | 1091 | list_for_each_entry(evt, &phba->ct_ev_waiters, node) { |
780 | if (evt->reg_id == event_req->ev_reg_id) { | 1092 | if (evt->reg_id == event_req->ev_reg_id) { |
781 | if (list_empty(&evt->events_to_get)) | 1093 | if (list_empty(&evt->events_to_get)) |
782 | break; | 1094 | break; |
783 | lpfc_ct_event_ref(evt); | 1095 | lpfc_bsg_event_ref(evt); |
784 | evt->wait_time_stamp = jiffies; | 1096 | evt->wait_time_stamp = jiffies; |
785 | evt_dat = list_entry(evt->events_to_get.prev, | 1097 | evt_dat = list_entry(evt->events_to_get.prev, |
786 | struct event_data, node); | 1098 | struct event_data, node); |
@@ -788,45 +1100,1539 @@ lpfc_bsg_get_event(struct fc_bsg_job *job) | |||
788 | break; | 1100 | break; |
789 | } | 1101 | } |
790 | } | 1102 | } |
791 | mutex_unlock(&phba->ct_event_mutex); | 1103 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); |
792 | 1104 | ||
793 | if (!evt_dat) { | 1105 | /* The app may continue to ask for event data until it gets |
1106 | * an error indicating that there isn't anymore | ||
1107 | */ | ||
1108 | if (evt_dat == NULL) { | ||
794 | job->reply->reply_payload_rcv_len = 0; | 1109 | job->reply->reply_payload_rcv_len = 0; |
795 | rc = -ENOENT; | 1110 | rc = -ENOENT; |
796 | goto error_get_event_exit; | 1111 | goto job_error; |
797 | } | 1112 | } |
798 | 1113 | ||
799 | if (evt_dat->len > job->reply_payload.payload_len) { | 1114 | if (evt_dat->len > job->request_payload.payload_len) { |
800 | evt_dat->len = job->reply_payload.payload_len; | 1115 | evt_dat->len = job->request_payload.payload_len; |
801 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | 1116 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, |
802 | "2618 Truncated event data at %d " | 1117 | "2618 Truncated event data at %d " |
803 | "bytes\n", | 1118 | "bytes\n", |
804 | job->reply_payload.payload_len); | 1119 | job->request_payload.payload_len); |
805 | } | 1120 | } |
806 | 1121 | ||
1122 | event_reply->type = evt_dat->type; | ||
807 | event_reply->immed_data = evt_dat->immed_dat; | 1123 | event_reply->immed_data = evt_dat->immed_dat; |
808 | |||
809 | if (evt_dat->len > 0) | 1124 | if (evt_dat->len > 0) |
810 | job->reply->reply_payload_rcv_len = | 1125 | job->reply->reply_payload_rcv_len = |
811 | sg_copy_from_buffer(job->reply_payload.sg_list, | 1126 | sg_copy_from_buffer(job->request_payload.sg_list, |
812 | job->reply_payload.sg_cnt, | 1127 | job->request_payload.sg_cnt, |
813 | evt_dat->data, evt_dat->len); | 1128 | evt_dat->data, evt_dat->len); |
814 | else | 1129 | else |
815 | job->reply->reply_payload_rcv_len = 0; | 1130 | job->reply->reply_payload_rcv_len = 0; |
816 | rc = 0; | ||
817 | 1131 | ||
818 | if (evt_dat) | 1132 | if (evt_dat) { |
819 | kfree(evt_dat->data); | 1133 | kfree(evt_dat->data); |
820 | kfree(evt_dat); | 1134 | kfree(evt_dat); |
821 | mutex_lock(&phba->ct_event_mutex); | 1135 | } |
822 | lpfc_ct_event_unref(evt); | 1136 | |
823 | mutex_unlock(&phba->ct_event_mutex); | 1137 | spin_lock_irqsave(&phba->ct_ev_lock, flags); |
1138 | lpfc_bsg_event_unref(evt); | ||
1139 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
1140 | job->dd_data = NULL; | ||
1141 | job->reply->result = 0; | ||
1142 | job->job_done(job); | ||
1143 | return 0; | ||
1144 | |||
1145 | job_error: | ||
1146 | job->dd_data = NULL; | ||
1147 | job->reply->result = rc; | ||
1148 | return rc; | ||
1149 | } | ||
1150 | |||
1151 | /** | ||
1152 | * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler | ||
1153 | * @phba: Pointer to HBA context object. | ||
1154 | * @cmdiocbq: Pointer to command iocb. | ||
1155 | * @rspiocbq: Pointer to response iocb. | ||
1156 | * | ||
1157 | * This function is the completion handler for iocbs issued using | ||
1158 | * lpfc_issue_ct_rsp_cmp function. This function is called by the | ||
1159 | * ring event handler function without any lock held. This function | ||
1160 | * can be called from both worker thread context and interrupt | ||
1161 | * context. This function also can be called from other thread which | ||
1162 | * cleans up the SLI layer objects. | ||
1163 | * This function copy the contents of the response iocb to the | ||
1164 | * response iocb memory object provided by the caller of | ||
1165 | * lpfc_sli_issue_iocb_wait and then wakes up the thread which | ||
1166 | * sleeps for the iocb completion. | ||
1167 | **/ | ||
1168 | static void | ||
1169 | lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, | ||
1170 | struct lpfc_iocbq *cmdiocbq, | ||
1171 | struct lpfc_iocbq *rspiocbq) | ||
1172 | { | ||
1173 | struct bsg_job_data *dd_data; | ||
1174 | struct fc_bsg_job *job; | ||
1175 | IOCB_t *rsp; | ||
1176 | struct lpfc_dmabuf *bmp; | ||
1177 | struct lpfc_nodelist *ndlp; | ||
1178 | unsigned long flags; | ||
1179 | int rc = 0; | ||
1180 | |||
1181 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
1182 | dd_data = cmdiocbq->context1; | ||
1183 | /* normal completion and timeout crossed paths, already done */ | ||
1184 | if (!dd_data) { | ||
1185 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
1186 | return; | ||
1187 | } | ||
824 | 1188 | ||
825 | error_get_event_exit: | 1189 | job = dd_data->context_un.iocb.set_job; |
1190 | bmp = dd_data->context_un.iocb.bmp; | ||
1191 | rsp = &rspiocbq->iocb; | ||
1192 | ndlp = dd_data->context_un.iocb.ndlp; | ||
1193 | |||
1194 | pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, | ||
1195 | job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
1196 | |||
1197 | if (rsp->ulpStatus) { | ||
1198 | if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { | ||
1199 | switch (rsp->un.ulpWord[4] & 0xff) { | ||
1200 | case IOERR_SEQUENCE_TIMEOUT: | ||
1201 | rc = -ETIMEDOUT; | ||
1202 | break; | ||
1203 | case IOERR_INVALID_RPI: | ||
1204 | rc = -EFAULT; | ||
1205 | break; | ||
1206 | default: | ||
1207 | rc = -EACCES; | ||
1208 | break; | ||
1209 | } | ||
1210 | } else | ||
1211 | rc = -EACCES; | ||
1212 | } else | ||
1213 | job->reply->reply_payload_rcv_len = | ||
1214 | rsp->un.genreq64.bdl.bdeSize; | ||
1215 | |||
1216 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||
1217 | lpfc_sli_release_iocbq(phba, cmdiocbq); | ||
1218 | lpfc_nlp_put(ndlp); | ||
1219 | kfree(bmp); | ||
1220 | kfree(dd_data); | ||
826 | /* make error code available to userspace */ | 1221 | /* make error code available to userspace */ |
827 | job->reply->result = rc; | 1222 | job->reply->result = rc; |
1223 | job->dd_data = NULL; | ||
828 | /* complete the job back to userspace */ | 1224 | /* complete the job back to userspace */ |
829 | job->job_done(job); | 1225 | job->job_done(job); |
1226 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
1227 | return; | ||
1228 | } | ||
1229 | |||
1230 | /** | ||
1231 | * lpfc_issue_ct_rsp - issue a ct response | ||
1232 | * @phba: Pointer to HBA context object. | ||
1233 | * @job: Pointer to the job object. | ||
1234 | * @tag: tag index value into the ports context exchange array. | ||
1235 | * @bmp: Pointer to a dma buffer descriptor. | ||
1236 | * @num_entry: Number of enties in the bde. | ||
1237 | **/ | ||
1238 | static int | ||
1239 | lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag, | ||
1240 | struct lpfc_dmabuf *bmp, int num_entry) | ||
1241 | { | ||
1242 | IOCB_t *icmd; | ||
1243 | struct lpfc_iocbq *ctiocb = NULL; | ||
1244 | int rc = 0; | ||
1245 | struct lpfc_nodelist *ndlp = NULL; | ||
1246 | struct bsg_job_data *dd_data; | ||
1247 | uint32_t creg_val; | ||
1248 | |||
1249 | /* allocate our bsg tracking structure */ | ||
1250 | dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); | ||
1251 | if (!dd_data) { | ||
1252 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
1253 | "2736 Failed allocation of dd_data\n"); | ||
1254 | rc = -ENOMEM; | ||
1255 | goto no_dd_data; | ||
1256 | } | ||
1257 | |||
1258 | /* Allocate buffer for command iocb */ | ||
1259 | ctiocb = lpfc_sli_get_iocbq(phba); | ||
1260 | if (!ctiocb) { | ||
1261 | rc = ENOMEM; | ||
1262 | goto no_ctiocb; | ||
1263 | } | ||
1264 | |||
1265 | icmd = &ctiocb->iocb; | ||
1266 | icmd->un.xseq64.bdl.ulpIoTag32 = 0; | ||
1267 | icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); | ||
1268 | icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); | ||
1269 | icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; | ||
1270 | icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); | ||
1271 | icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); | ||
1272 | icmd->un.xseq64.w5.hcsw.Dfctl = 0; | ||
1273 | icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; | ||
1274 | icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; | ||
1275 | |||
1276 | /* Fill in rest of iocb */ | ||
1277 | icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; | ||
1278 | icmd->ulpBdeCount = 1; | ||
1279 | icmd->ulpLe = 1; | ||
1280 | icmd->ulpClass = CLASS3; | ||
1281 | if (phba->sli_rev == LPFC_SLI_REV4) { | ||
1282 | /* Do not issue unsol response if oxid not marked as valid */ | ||
1283 | if (!(phba->ct_ctx[tag].flags & UNSOL_VALID)) { | ||
1284 | rc = IOCB_ERROR; | ||
1285 | goto issue_ct_rsp_exit; | ||
1286 | } | ||
1287 | icmd->ulpContext = phba->ct_ctx[tag].oxid; | ||
1288 | ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); | ||
1289 | if (!ndlp) { | ||
1290 | lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, | ||
1291 | "2721 ndlp null for oxid %x SID %x\n", | ||
1292 | icmd->ulpContext, | ||
1293 | phba->ct_ctx[tag].SID); | ||
1294 | rc = IOCB_ERROR; | ||
1295 | goto issue_ct_rsp_exit; | ||
1296 | } | ||
1297 | icmd->un.ulpWord[3] = ndlp->nlp_rpi; | ||
1298 | /* The exchange is done, mark the entry as invalid */ | ||
1299 | phba->ct_ctx[tag].flags &= ~UNSOL_VALID; | ||
1300 | } else | ||
1301 | icmd->ulpContext = (ushort) tag; | ||
1302 | |||
1303 | icmd->ulpTimeout = phba->fc_ratov * 2; | ||
1304 | |||
1305 | /* Xmit CT response on exchange <xid> */ | ||
1306 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
1307 | "2722 Xmit CT response on exchange x%x Data: x%x x%x\n", | ||
1308 | icmd->ulpContext, icmd->ulpIoTag, phba->link_state); | ||
1309 | |||
1310 | ctiocb->iocb_cmpl = NULL; | ||
1311 | ctiocb->iocb_flag |= LPFC_IO_LIBDFC; | ||
1312 | ctiocb->vport = phba->pport; | ||
1313 | ctiocb->context3 = bmp; | ||
1314 | |||
1315 | ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp; | ||
1316 | ctiocb->context1 = dd_data; | ||
1317 | ctiocb->context2 = NULL; | ||
1318 | dd_data->type = TYPE_IOCB; | ||
1319 | dd_data->context_un.iocb.cmdiocbq = ctiocb; | ||
1320 | dd_data->context_un.iocb.rspiocbq = NULL; | ||
1321 | dd_data->context_un.iocb.set_job = job; | ||
1322 | dd_data->context_un.iocb.bmp = bmp; | ||
1323 | dd_data->context_un.iocb.ndlp = ndlp; | ||
1324 | |||
1325 | if (phba->cfg_poll & DISABLE_FCP_RING_INT) { | ||
1326 | creg_val = readl(phba->HCregaddr); | ||
1327 | creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); | ||
1328 | writel(creg_val, phba->HCregaddr); | ||
1329 | readl(phba->HCregaddr); /* flush */ | ||
1330 | } | ||
1331 | |||
1332 | rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); | ||
1333 | |||
1334 | if (rc == IOCB_SUCCESS) | ||
1335 | return 0; /* done for now */ | ||
1336 | |||
1337 | issue_ct_rsp_exit: | ||
1338 | lpfc_sli_release_iocbq(phba, ctiocb); | ||
1339 | no_ctiocb: | ||
1340 | kfree(dd_data); | ||
1341 | no_dd_data: | ||
1342 | return rc; | ||
1343 | } | ||
1344 | |||
1345 | /** | ||
1346 | * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command | ||
1347 | * @job: SEND_MGMT_RESP fc_bsg_job | ||
1348 | **/ | ||
1349 | static int | ||
1350 | lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job) | ||
1351 | { | ||
1352 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; | ||
1353 | struct lpfc_hba *phba = vport->phba; | ||
1354 | struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *) | ||
1355 | job->request->rqst_data.h_vendor.vendor_cmd; | ||
1356 | struct ulp_bde64 *bpl; | ||
1357 | struct lpfc_dmabuf *bmp = NULL; | ||
1358 | struct scatterlist *sgel = NULL; | ||
1359 | int request_nseg; | ||
1360 | int numbde; | ||
1361 | dma_addr_t busaddr; | ||
1362 | uint32_t tag = mgmt_resp->tag; | ||
1363 | unsigned long reqbfrcnt = | ||
1364 | (unsigned long)job->request_payload.payload_len; | ||
1365 | int rc = 0; | ||
1366 | |||
1367 | /* in case no data is transferred */ | ||
1368 | job->reply->reply_payload_rcv_len = 0; | ||
1369 | |||
1370 | if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) { | ||
1371 | rc = -ERANGE; | ||
1372 | goto send_mgmt_rsp_exit; | ||
1373 | } | ||
1374 | |||
1375 | bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); | ||
1376 | if (!bmp) { | ||
1377 | rc = -ENOMEM; | ||
1378 | goto send_mgmt_rsp_exit; | ||
1379 | } | ||
1380 | |||
1381 | bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); | ||
1382 | if (!bmp->virt) { | ||
1383 | rc = -ENOMEM; | ||
1384 | goto send_mgmt_rsp_free_bmp; | ||
1385 | } | ||
1386 | |||
1387 | INIT_LIST_HEAD(&bmp->list); | ||
1388 | bpl = (struct ulp_bde64 *) bmp->virt; | ||
1389 | request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, | ||
1390 | job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
1391 | for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { | ||
1392 | busaddr = sg_dma_address(sgel); | ||
1393 | bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; | ||
1394 | bpl->tus.f.bdeSize = sg_dma_len(sgel); | ||
1395 | bpl->tus.w = cpu_to_le32(bpl->tus.w); | ||
1396 | bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); | ||
1397 | bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); | ||
1398 | bpl++; | ||
1399 | } | ||
1400 | |||
1401 | rc = lpfc_issue_ct_rsp(phba, job, tag, bmp, request_nseg); | ||
1402 | |||
1403 | if (rc == IOCB_SUCCESS) | ||
1404 | return 0; /* done for now */ | ||
1405 | |||
1406 | /* TBD need to handle a timeout */ | ||
1407 | pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, | ||
1408 | job->request_payload.sg_cnt, DMA_TO_DEVICE); | ||
1409 | rc = -EACCES; | ||
1410 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||
1411 | |||
1412 | send_mgmt_rsp_free_bmp: | ||
1413 | kfree(bmp); | ||
1414 | send_mgmt_rsp_exit: | ||
1415 | /* make error code available to userspace */ | ||
1416 | job->reply->result = rc; | ||
1417 | job->dd_data = NULL; | ||
1418 | return rc; | ||
1419 | } | ||
1420 | |||
1421 | /** | ||
1422 | * lpfc_bsg_diag_mode - process a LPFC_BSG_VENDOR_DIAG_MODE bsg vendor command | ||
1423 | * @job: LPFC_BSG_VENDOR_DIAG_MODE | ||
1424 | * | ||
1425 | * This function is responsible for placing a port into diagnostic loopback | ||
1426 | * mode in order to perform a diagnostic loopback test. | ||
1427 | * All new scsi requests are blocked, a small delay is used to allow the | ||
1428 | * scsi requests to complete then the link is brought down. If the link is | ||
1429 | * is placed in loopback mode then scsi requests are again allowed | ||
1430 | * so the scsi mid-layer doesn't give up on the port. | ||
1431 | * All of this is done in-line. | ||
1432 | */ | ||
1433 | static int | ||
1434 | lpfc_bsg_diag_mode(struct fc_bsg_job *job) | ||
1435 | { | ||
1436 | struct Scsi_Host *shost = job->shost; | ||
1437 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; | ||
1438 | struct lpfc_hba *phba = vport->phba; | ||
1439 | struct diag_mode_set *loopback_mode; | ||
1440 | struct lpfc_sli *psli = &phba->sli; | ||
1441 | struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING]; | ||
1442 | uint32_t link_flags; | ||
1443 | uint32_t timeout; | ||
1444 | struct lpfc_vport **vports; | ||
1445 | LPFC_MBOXQ_t *pmboxq; | ||
1446 | int mbxstatus; | ||
1447 | int i = 0; | ||
1448 | int rc = 0; | ||
1449 | |||
1450 | /* no data to return just the return code */ | ||
1451 | job->reply->reply_payload_rcv_len = 0; | ||
1452 | |||
1453 | if (job->request_len < | ||
1454 | sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_set)) { | ||
1455 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
1456 | "2738 Received DIAG MODE request below minimum " | ||
1457 | "size\n"); | ||
1458 | rc = -EINVAL; | ||
1459 | goto job_error; | ||
1460 | } | ||
1461 | |||
1462 | loopback_mode = (struct diag_mode_set *) | ||
1463 | job->request->rqst_data.h_vendor.vendor_cmd; | ||
1464 | link_flags = loopback_mode->type; | ||
1465 | timeout = loopback_mode->timeout; | ||
1466 | |||
1467 | if ((phba->link_state == LPFC_HBA_ERROR) || | ||
1468 | (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || | ||
1469 | (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { | ||
1470 | rc = -EACCES; | ||
1471 | goto job_error; | ||
1472 | } | ||
1473 | |||
1474 | pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
1475 | if (!pmboxq) { | ||
1476 | rc = -ENOMEM; | ||
1477 | goto job_error; | ||
1478 | } | ||
1479 | |||
1480 | vports = lpfc_create_vport_work_array(phba); | ||
1481 | if (vports) { | ||
1482 | for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { | ||
1483 | shost = lpfc_shost_from_vport(vports[i]); | ||
1484 | scsi_block_requests(shost); | ||
1485 | } | ||
1486 | |||
1487 | lpfc_destroy_vport_work_array(phba, vports); | ||
1488 | } else { | ||
1489 | shost = lpfc_shost_from_vport(phba->pport); | ||
1490 | scsi_block_requests(shost); | ||
1491 | } | ||
1492 | |||
1493 | while (pring->txcmplq_cnt) { | ||
1494 | if (i++ > 500) /* wait up to 5 seconds */ | ||
1495 | break; | ||
1496 | |||
1497 | msleep(10); | ||
1498 | } | ||
1499 | |||
1500 | memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); | ||
1501 | pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; | ||
1502 | pmboxq->u.mb.mbxOwner = OWN_HOST; | ||
1503 | |||
1504 | mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); | ||
1505 | |||
1506 | if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) { | ||
1507 | /* wait for link down before proceeding */ | ||
1508 | i = 0; | ||
1509 | while (phba->link_state != LPFC_LINK_DOWN) { | ||
1510 | if (i++ > timeout) { | ||
1511 | rc = -ETIMEDOUT; | ||
1512 | goto loopback_mode_exit; | ||
1513 | } | ||
1514 | |||
1515 | msleep(10); | ||
1516 | } | ||
1517 | |||
1518 | memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); | ||
1519 | if (link_flags == INTERNAL_LOOP_BACK) | ||
1520 | pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB; | ||
1521 | else | ||
1522 | pmboxq->u.mb.un.varInitLnk.link_flags = | ||
1523 | FLAGS_TOPOLOGY_MODE_LOOP; | ||
1524 | |||
1525 | pmboxq->u.mb.mbxCommand = MBX_INIT_LINK; | ||
1526 | pmboxq->u.mb.mbxOwner = OWN_HOST; | ||
1527 | |||
1528 | mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, | ||
1529 | LPFC_MBOX_TMO); | ||
1530 | |||
1531 | if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) | ||
1532 | rc = -ENODEV; | ||
1533 | else { | ||
1534 | phba->link_flag |= LS_LOOPBACK_MODE; | ||
1535 | /* wait for the link attention interrupt */ | ||
1536 | msleep(100); | ||
1537 | |||
1538 | i = 0; | ||
1539 | while (phba->link_state != LPFC_HBA_READY) { | ||
1540 | if (i++ > timeout) { | ||
1541 | rc = -ETIMEDOUT; | ||
1542 | break; | ||
1543 | } | ||
1544 | |||
1545 | msleep(10); | ||
1546 | } | ||
1547 | } | ||
1548 | |||
1549 | } else | ||
1550 | rc = -ENODEV; | ||
1551 | |||
1552 | loopback_mode_exit: | ||
1553 | vports = lpfc_create_vport_work_array(phba); | ||
1554 | if (vports) { | ||
1555 | for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { | ||
1556 | shost = lpfc_shost_from_vport(vports[i]); | ||
1557 | scsi_unblock_requests(shost); | ||
1558 | } | ||
1559 | lpfc_destroy_vport_work_array(phba, vports); | ||
1560 | } else { | ||
1561 | shost = lpfc_shost_from_vport(phba->pport); | ||
1562 | scsi_unblock_requests(shost); | ||
1563 | } | ||
1564 | |||
1565 | /* | ||
1566 | * Let SLI layer release mboxq if mbox command completed after timeout. | ||
1567 | */ | ||
1568 | if (mbxstatus != MBX_TIMEOUT) | ||
1569 | mempool_free(pmboxq, phba->mbox_mem_pool); | ||
1570 | |||
1571 | job_error: | ||
1572 | /* make error code available to userspace */ | ||
1573 | job->reply->result = rc; | ||
1574 | /* complete the job back to userspace if no error */ | ||
1575 | if (rc == 0) | ||
1576 | job->job_done(job); | ||
1577 | return rc; | ||
1578 | } | ||
1579 | |||
1580 | /** | ||
1581 | * lpfcdiag_loop_self_reg - obtains a remote port login id | ||
1582 | * @phba: Pointer to HBA context object | ||
1583 | * @rpi: Pointer to a remote port login id | ||
1584 | * | ||
1585 | * This function obtains a remote port login id so the diag loopback test | ||
1586 | * can send and receive its own unsolicited CT command. | ||
1587 | **/ | ||
1588 | static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t * rpi) | ||
1589 | { | ||
1590 | LPFC_MBOXQ_t *mbox; | ||
1591 | struct lpfc_dmabuf *dmabuff; | ||
1592 | int status; | ||
1593 | |||
1594 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
1595 | if (!mbox) | ||
1596 | return ENOMEM; | ||
1597 | |||
1598 | status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, | ||
1599 | (uint8_t *)&phba->pport->fc_sparam, mbox, 0); | ||
1600 | if (status) { | ||
1601 | mempool_free(mbox, phba->mbox_mem_pool); | ||
1602 | return ENOMEM; | ||
1603 | } | ||
1604 | |||
1605 | dmabuff = (struct lpfc_dmabuf *) mbox->context1; | ||
1606 | mbox->context1 = NULL; | ||
1607 | status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); | ||
1608 | |||
1609 | if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { | ||
1610 | lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); | ||
1611 | kfree(dmabuff); | ||
1612 | if (status != MBX_TIMEOUT) | ||
1613 | mempool_free(mbox, phba->mbox_mem_pool); | ||
1614 | return ENODEV; | ||
1615 | } | ||
1616 | |||
1617 | *rpi = mbox->u.mb.un.varWords[0]; | ||
1618 | |||
1619 | lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); | ||
1620 | kfree(dmabuff); | ||
1621 | mempool_free(mbox, phba->mbox_mem_pool); | ||
1622 | return 0; | ||
1623 | } | ||
1624 | |||
1625 | /** | ||
1626 | * lpfcdiag_loop_self_unreg - unregs from the rpi | ||
1627 | * @phba: Pointer to HBA context object | ||
1628 | * @rpi: Remote port login id | ||
1629 | * | ||
1630 | * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg | ||
1631 | **/ | ||
1632 | static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) | ||
1633 | { | ||
1634 | LPFC_MBOXQ_t *mbox; | ||
1635 | int status; | ||
1636 | |||
1637 | /* Allocate mboxq structure */ | ||
1638 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
1639 | if (mbox == NULL) | ||
1640 | return ENOMEM; | ||
1641 | |||
1642 | lpfc_unreg_login(phba, 0, rpi, mbox); | ||
1643 | status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); | ||
1644 | |||
1645 | if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { | ||
1646 | if (status != MBX_TIMEOUT) | ||
1647 | mempool_free(mbox, phba->mbox_mem_pool); | ||
1648 | return EIO; | ||
1649 | } | ||
1650 | |||
1651 | mempool_free(mbox, phba->mbox_mem_pool); | ||
1652 | return 0; | ||
1653 | } | ||
1654 | |||
1655 | /** | ||
1656 | * lpfcdiag_loop_get_xri - obtains the transmit and receive ids | ||
1657 | * @phba: Pointer to HBA context object | ||
1658 | * @rpi: Remote port login id | ||
1659 | * @txxri: Pointer to transmit exchange id | ||
1660 | * @rxxri: Pointer to response exchabge id | ||
1661 | * | ||
1662 | * This function obtains the transmit and receive ids required to send | ||
1663 | * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp | ||
1664 | * flags are used to the unsolicted response handler is able to process | ||
1665 | * the ct command sent on the same port. | ||
1666 | **/ | ||
1667 | static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, | ||
1668 | uint16_t *txxri, uint16_t * rxxri) | ||
1669 | { | ||
1670 | struct lpfc_bsg_event *evt; | ||
1671 | struct lpfc_iocbq *cmdiocbq, *rspiocbq; | ||
1672 | IOCB_t *cmd, *rsp; | ||
1673 | struct lpfc_dmabuf *dmabuf; | ||
1674 | struct ulp_bde64 *bpl = NULL; | ||
1675 | struct lpfc_sli_ct_request *ctreq = NULL; | ||
1676 | int ret_val = 0; | ||
1677 | unsigned long flags; | ||
1678 | |||
1679 | *txxri = 0; | ||
1680 | *rxxri = 0; | ||
1681 | evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, | ||
1682 | SLI_CT_ELX_LOOPBACK); | ||
1683 | if (!evt) | ||
1684 | return ENOMEM; | ||
1685 | |||
1686 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
1687 | list_add(&evt->node, &phba->ct_ev_waiters); | ||
1688 | lpfc_bsg_event_ref(evt); | ||
1689 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
1690 | |||
1691 | cmdiocbq = lpfc_sli_get_iocbq(phba); | ||
1692 | rspiocbq = lpfc_sli_get_iocbq(phba); | ||
1693 | |||
1694 | dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); | ||
1695 | if (dmabuf) { | ||
1696 | dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); | ||
1697 | INIT_LIST_HEAD(&dmabuf->list); | ||
1698 | bpl = (struct ulp_bde64 *) dmabuf->virt; | ||
1699 | memset(bpl, 0, sizeof(*bpl)); | ||
1700 | ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); | ||
1701 | bpl->addrHigh = | ||
1702 | le32_to_cpu(putPaddrHigh(dmabuf->phys + sizeof(*bpl))); | ||
1703 | bpl->addrLow = | ||
1704 | le32_to_cpu(putPaddrLow(dmabuf->phys + sizeof(*bpl))); | ||
1705 | bpl->tus.f.bdeFlags = 0; | ||
1706 | bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; | ||
1707 | bpl->tus.w = le32_to_cpu(bpl->tus.w); | ||
1708 | } | ||
1709 | |||
1710 | if (cmdiocbq == NULL || rspiocbq == NULL || | ||
1711 | dmabuf == NULL || bpl == NULL || ctreq == NULL) { | ||
1712 | ret_val = ENOMEM; | ||
1713 | goto err_get_xri_exit; | ||
1714 | } | ||
1715 | |||
1716 | cmd = &cmdiocbq->iocb; | ||
1717 | rsp = &rspiocbq->iocb; | ||
1718 | |||
1719 | memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); | ||
1720 | |||
1721 | ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; | ||
1722 | ctreq->RevisionId.bits.InId = 0; | ||
1723 | ctreq->FsType = SLI_CT_ELX_LOOPBACK; | ||
1724 | ctreq->FsSubType = 0; | ||
1725 | ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; | ||
1726 | ctreq->CommandResponse.bits.Size = 0; | ||
1727 | |||
1728 | |||
1729 | cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys); | ||
1730 | cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys); | ||
1731 | cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; | ||
1732 | cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl); | ||
1733 | |||
1734 | cmd->un.xseq64.w5.hcsw.Fctl = LA; | ||
1735 | cmd->un.xseq64.w5.hcsw.Dfctl = 0; | ||
1736 | cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; | ||
1737 | cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; | ||
1738 | |||
1739 | cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; | ||
1740 | cmd->ulpBdeCount = 1; | ||
1741 | cmd->ulpLe = 1; | ||
1742 | cmd->ulpClass = CLASS3; | ||
1743 | cmd->ulpContext = rpi; | ||
1744 | |||
1745 | cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; | ||
1746 | cmdiocbq->vport = phba->pport; | ||
1747 | |||
1748 | ret_val = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, | ||
1749 | rspiocbq, | ||
1750 | (phba->fc_ratov * 2) | ||
1751 | + LPFC_DRVR_TIMEOUT); | ||
1752 | if (ret_val) | ||
1753 | goto err_get_xri_exit; | ||
1754 | |||
1755 | *txxri = rsp->ulpContext; | ||
1756 | |||
1757 | evt->waiting = 1; | ||
1758 | evt->wait_time_stamp = jiffies; | ||
1759 | ret_val = wait_event_interruptible_timeout( | ||
1760 | evt->wq, !list_empty(&evt->events_to_see), | ||
1761 | ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); | ||
1762 | if (list_empty(&evt->events_to_see)) | ||
1763 | ret_val = (ret_val) ? EINTR : ETIMEDOUT; | ||
1764 | else { | ||
1765 | ret_val = IOCB_SUCCESS; | ||
1766 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
1767 | list_move(evt->events_to_see.prev, &evt->events_to_get); | ||
1768 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
1769 | *rxxri = (list_entry(evt->events_to_get.prev, | ||
1770 | typeof(struct event_data), | ||
1771 | node))->immed_dat; | ||
1772 | } | ||
1773 | evt->waiting = 0; | ||
1774 | |||
1775 | err_get_xri_exit: | ||
1776 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
1777 | lpfc_bsg_event_unref(evt); /* release ref */ | ||
1778 | lpfc_bsg_event_unref(evt); /* delete */ | ||
1779 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
1780 | |||
1781 | if (dmabuf) { | ||
1782 | if (dmabuf->virt) | ||
1783 | lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); | ||
1784 | kfree(dmabuf); | ||
1785 | } | ||
1786 | |||
1787 | if (cmdiocbq && (ret_val != IOCB_TIMEDOUT)) | ||
1788 | lpfc_sli_release_iocbq(phba, cmdiocbq); | ||
1789 | if (rspiocbq) | ||
1790 | lpfc_sli_release_iocbq(phba, rspiocbq); | ||
1791 | return ret_val; | ||
1792 | } | ||
1793 | |||
1794 | /** | ||
1795 | * diag_cmd_data_alloc - fills in a bde struct with dma buffers | ||
1796 | * @phba: Pointer to HBA context object | ||
1797 | * @bpl: Pointer to 64 bit bde structure | ||
1798 | * @size: Number of bytes to process | ||
1799 | * @nocopydata: Flag to copy user data into the allocated buffer | ||
1800 | * | ||
1801 | * This function allocates page size buffers and populates an lpfc_dmabufext. | ||
1802 | * If allowed the user data pointed to with indataptr is copied into the kernel | ||
1803 | * memory. The chained list of page size buffers is returned. | ||
1804 | **/ | ||
1805 | static struct lpfc_dmabufext * | ||
1806 | diag_cmd_data_alloc(struct lpfc_hba *phba, | ||
1807 | struct ulp_bde64 *bpl, uint32_t size, | ||
1808 | int nocopydata) | ||
1809 | { | ||
1810 | struct lpfc_dmabufext *mlist = NULL; | ||
1811 | struct lpfc_dmabufext *dmp; | ||
1812 | int cnt, offset = 0, i = 0; | ||
1813 | struct pci_dev *pcidev; | ||
1814 | |||
1815 | pcidev = phba->pcidev; | ||
1816 | |||
1817 | while (size) { | ||
1818 | /* We get chunks of 4K */ | ||
1819 | if (size > BUF_SZ_4K) | ||
1820 | cnt = BUF_SZ_4K; | ||
1821 | else | ||
1822 | cnt = size; | ||
1823 | |||
1824 | /* allocate struct lpfc_dmabufext buffer header */ | ||
1825 | dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL); | ||
1826 | if (!dmp) | ||
1827 | goto out; | ||
1828 | |||
1829 | INIT_LIST_HEAD(&dmp->dma.list); | ||
1830 | |||
1831 | /* Queue it to a linked list */ | ||
1832 | if (mlist) | ||
1833 | list_add_tail(&dmp->dma.list, &mlist->dma.list); | ||
1834 | else | ||
1835 | mlist = dmp; | ||
1836 | |||
1837 | /* allocate buffer */ | ||
1838 | dmp->dma.virt = dma_alloc_coherent(&pcidev->dev, | ||
1839 | cnt, | ||
1840 | &(dmp->dma.phys), | ||
1841 | GFP_KERNEL); | ||
1842 | |||
1843 | if (!dmp->dma.virt) | ||
1844 | goto out; | ||
1845 | |||
1846 | dmp->size = cnt; | ||
1847 | |||
1848 | if (nocopydata) { | ||
1849 | bpl->tus.f.bdeFlags = 0; | ||
1850 | pci_dma_sync_single_for_device(phba->pcidev, | ||
1851 | dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); | ||
1852 | |||
1853 | } else { | ||
1854 | memset((uint8_t *)dmp->dma.virt, 0, cnt); | ||
1855 | bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; | ||
1856 | } | ||
1857 | |||
1858 | /* build buffer ptr list for IOCB */ | ||
1859 | bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); | ||
1860 | bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); | ||
1861 | bpl->tus.f.bdeSize = (ushort) cnt; | ||
1862 | bpl->tus.w = le32_to_cpu(bpl->tus.w); | ||
1863 | bpl++; | ||
1864 | |||
1865 | i++; | ||
1866 | offset += cnt; | ||
1867 | size -= cnt; | ||
1868 | } | ||
1869 | |||
1870 | mlist->flag = i; | ||
1871 | return mlist; | ||
1872 | out: | ||
1873 | diag_cmd_data_free(phba, mlist); | ||
1874 | return NULL; | ||
1875 | } | ||
1876 | |||
1877 | /** | ||
1878 | * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd | ||
1879 | * @phba: Pointer to HBA context object | ||
1880 | * @rxxri: Receive exchange id | ||
1881 | * @len: Number of data bytes | ||
1882 | * | ||
1883 | * This function allocates and posts a data buffer of sufficient size to recieve | ||
1884 | * an unsolicted CT command. | ||
1885 | **/ | ||
1886 | static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, | ||
1887 | size_t len) | ||
1888 | { | ||
1889 | struct lpfc_sli *psli = &phba->sli; | ||
1890 | struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; | ||
1891 | struct lpfc_iocbq *cmdiocbq; | ||
1892 | IOCB_t *cmd = NULL; | ||
1893 | struct list_head head, *curr, *next; | ||
1894 | struct lpfc_dmabuf *rxbmp; | ||
1895 | struct lpfc_dmabuf *dmp; | ||
1896 | struct lpfc_dmabuf *mp[2] = {NULL, NULL}; | ||
1897 | struct ulp_bde64 *rxbpl = NULL; | ||
1898 | uint32_t num_bde; | ||
1899 | struct lpfc_dmabufext *rxbuffer = NULL; | ||
1900 | int ret_val = 0; | ||
1901 | int i = 0; | ||
1902 | |||
1903 | cmdiocbq = lpfc_sli_get_iocbq(phba); | ||
1904 | rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); | ||
1905 | if (rxbmp != NULL) { | ||
1906 | rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); | ||
1907 | INIT_LIST_HEAD(&rxbmp->list); | ||
1908 | rxbpl = (struct ulp_bde64 *) rxbmp->virt; | ||
1909 | rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); | ||
1910 | } | ||
1911 | |||
1912 | if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) { | ||
1913 | ret_val = ENOMEM; | ||
1914 | goto err_post_rxbufs_exit; | ||
1915 | } | ||
1916 | |||
1917 | /* Queue buffers for the receive exchange */ | ||
1918 | num_bde = (uint32_t)rxbuffer->flag; | ||
1919 | dmp = &rxbuffer->dma; | ||
1920 | |||
1921 | cmd = &cmdiocbq->iocb; | ||
1922 | i = 0; | ||
1923 | |||
1924 | INIT_LIST_HEAD(&head); | ||
1925 | list_add_tail(&head, &dmp->list); | ||
1926 | list_for_each_safe(curr, next, &head) { | ||
1927 | mp[i] = list_entry(curr, struct lpfc_dmabuf, list); | ||
1928 | list_del(curr); | ||
1929 | |||
1930 | if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { | ||
1931 | mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); | ||
1932 | cmd->un.quexri64cx.buff.bde.addrHigh = | ||
1933 | putPaddrHigh(mp[i]->phys); | ||
1934 | cmd->un.quexri64cx.buff.bde.addrLow = | ||
1935 | putPaddrLow(mp[i]->phys); | ||
1936 | cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = | ||
1937 | ((struct lpfc_dmabufext *)mp[i])->size; | ||
1938 | cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; | ||
1939 | cmd->ulpCommand = CMD_QUE_XRI64_CX; | ||
1940 | cmd->ulpPU = 0; | ||
1941 | cmd->ulpLe = 1; | ||
1942 | cmd->ulpBdeCount = 1; | ||
1943 | cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; | ||
1944 | |||
1945 | } else { | ||
1946 | cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); | ||
1947 | cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); | ||
1948 | cmd->un.cont64[i].tus.f.bdeSize = | ||
1949 | ((struct lpfc_dmabufext *)mp[i])->size; | ||
1950 | cmd->ulpBdeCount = ++i; | ||
1951 | |||
1952 | if ((--num_bde > 0) && (i < 2)) | ||
1953 | continue; | ||
1954 | |||
1955 | cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; | ||
1956 | cmd->ulpLe = 1; | ||
1957 | } | ||
1958 | |||
1959 | cmd->ulpClass = CLASS3; | ||
1960 | cmd->ulpContext = rxxri; | ||
1961 | |||
1962 | ret_val = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); | ||
1963 | |||
1964 | if (ret_val == IOCB_ERROR) { | ||
1965 | diag_cmd_data_free(phba, | ||
1966 | (struct lpfc_dmabufext *)mp[0]); | ||
1967 | if (mp[1]) | ||
1968 | diag_cmd_data_free(phba, | ||
1969 | (struct lpfc_dmabufext *)mp[1]); | ||
1970 | dmp = list_entry(next, struct lpfc_dmabuf, list); | ||
1971 | ret_val = EIO; | ||
1972 | goto err_post_rxbufs_exit; | ||
1973 | } | ||
1974 | |||
1975 | lpfc_sli_ringpostbuf_put(phba, pring, mp[0]); | ||
1976 | if (mp[1]) { | ||
1977 | lpfc_sli_ringpostbuf_put(phba, pring, mp[1]); | ||
1978 | mp[1] = NULL; | ||
1979 | } | ||
1980 | |||
1981 | /* The iocb was freed by lpfc_sli_issue_iocb */ | ||
1982 | cmdiocbq = lpfc_sli_get_iocbq(phba); | ||
1983 | if (!cmdiocbq) { | ||
1984 | dmp = list_entry(next, struct lpfc_dmabuf, list); | ||
1985 | ret_val = EIO; | ||
1986 | goto err_post_rxbufs_exit; | ||
1987 | } | ||
1988 | |||
1989 | cmd = &cmdiocbq->iocb; | ||
1990 | i = 0; | ||
1991 | } | ||
1992 | list_del(&head); | ||
1993 | |||
1994 | err_post_rxbufs_exit: | ||
1995 | |||
1996 | if (rxbmp) { | ||
1997 | if (rxbmp->virt) | ||
1998 | lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); | ||
1999 | kfree(rxbmp); | ||
2000 | } | ||
2001 | |||
2002 | if (cmdiocbq) | ||
2003 | lpfc_sli_release_iocbq(phba, cmdiocbq); | ||
2004 | return ret_val; | ||
2005 | } | ||
2006 | |||
2007 | /** | ||
2008 | * lpfc_bsg_diag_test - with a port in loopback issues a Ct cmd to itself | ||
2009 | * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job | ||
2010 | * | ||
2011 | * This function receives a user data buffer to be transmitted and received on | ||
2012 | * the same port, the link must be up and in loopback mode prior | ||
2013 | * to being called. | ||
2014 | * 1. A kernel buffer is allocated to copy the user data into. | ||
2015 | * 2. The port registers with "itself". | ||
2016 | * 3. The transmit and receive exchange ids are obtained. | ||
2017 | * 4. The receive exchange id is posted. | ||
2018 | * 5. A new els loopback event is created. | ||
2019 | * 6. The command and response iocbs are allocated. | ||
2020 | * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback. | ||
2021 | * | ||
2022 | * This function is meant to be called n times while the port is in loopback | ||
2023 | * so it is the apps responsibility to issue a reset to take the port out | ||
2024 | * of loopback mode. | ||
2025 | **/ | ||
2026 | static int | ||
2027 | lpfc_bsg_diag_test(struct fc_bsg_job *job) | ||
2028 | { | ||
2029 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; | ||
2030 | struct lpfc_hba *phba = vport->phba; | ||
2031 | struct diag_mode_test *diag_mode; | ||
2032 | struct lpfc_bsg_event *evt; | ||
2033 | struct event_data *evdat; | ||
2034 | struct lpfc_sli *psli = &phba->sli; | ||
2035 | uint32_t size; | ||
2036 | uint32_t full_size; | ||
2037 | size_t segment_len = 0, segment_offset = 0, current_offset = 0; | ||
2038 | uint16_t rpi; | ||
2039 | struct lpfc_iocbq *cmdiocbq, *rspiocbq; | ||
2040 | IOCB_t *cmd, *rsp; | ||
2041 | struct lpfc_sli_ct_request *ctreq; | ||
2042 | struct lpfc_dmabuf *txbmp; | ||
2043 | struct ulp_bde64 *txbpl = NULL; | ||
2044 | struct lpfc_dmabufext *txbuffer = NULL; | ||
2045 | struct list_head head; | ||
2046 | struct lpfc_dmabuf *curr; | ||
2047 | uint16_t txxri, rxxri; | ||
2048 | uint32_t num_bde; | ||
2049 | uint8_t *ptr = NULL, *rx_databuf = NULL; | ||
2050 | int rc = 0; | ||
2051 | unsigned long flags; | ||
2052 | void *dataout = NULL; | ||
2053 | uint32_t total_mem; | ||
2054 | |||
2055 | /* in case no data is returned return just the return code */ | ||
2056 | job->reply->reply_payload_rcv_len = 0; | ||
2057 | |||
2058 | if (job->request_len < | ||
2059 | sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) { | ||
2060 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
2061 | "2739 Received DIAG TEST request below minimum " | ||
2062 | "size\n"); | ||
2063 | rc = -EINVAL; | ||
2064 | goto loopback_test_exit; | ||
2065 | } | ||
2066 | |||
2067 | if (job->request_payload.payload_len != | ||
2068 | job->reply_payload.payload_len) { | ||
2069 | rc = -EINVAL; | ||
2070 | goto loopback_test_exit; | ||
2071 | } | ||
2072 | |||
2073 | diag_mode = (struct diag_mode_test *) | ||
2074 | job->request->rqst_data.h_vendor.vendor_cmd; | ||
2075 | |||
2076 | if ((phba->link_state == LPFC_HBA_ERROR) || | ||
2077 | (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || | ||
2078 | (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { | ||
2079 | rc = -EACCES; | ||
2080 | goto loopback_test_exit; | ||
2081 | } | ||
2082 | |||
2083 | if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) { | ||
2084 | rc = -EACCES; | ||
2085 | goto loopback_test_exit; | ||
2086 | } | ||
2087 | |||
2088 | size = job->request_payload.payload_len; | ||
2089 | full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */ | ||
2090 | |||
2091 | if ((size == 0) || (size > 80 * BUF_SZ_4K)) { | ||
2092 | rc = -ERANGE; | ||
2093 | goto loopback_test_exit; | ||
2094 | } | ||
2095 | |||
2096 | if (size >= BUF_SZ_4K) { | ||
2097 | /* | ||
2098 | * Allocate memory for ioctl data. If buffer is bigger than 64k, | ||
2099 | * then we allocate 64k and re-use that buffer over and over to | ||
2100 | * xfer the whole block. This is because Linux kernel has a | ||
2101 | * problem allocating more than 120k of kernel space memory. Saw | ||
2102 | * problem with GET_FCPTARGETMAPPING... | ||
2103 | */ | ||
2104 | if (size <= (64 * 1024)) | ||
2105 | total_mem = size; | ||
2106 | else | ||
2107 | total_mem = 64 * 1024; | ||
2108 | } else | ||
2109 | /* Allocate memory for ioctl data */ | ||
2110 | total_mem = BUF_SZ_4K; | ||
2111 | |||
2112 | dataout = kmalloc(total_mem, GFP_KERNEL); | ||
2113 | if (dataout == NULL) { | ||
2114 | rc = -ENOMEM; | ||
2115 | goto loopback_test_exit; | ||
2116 | } | ||
2117 | |||
2118 | ptr = dataout; | ||
2119 | ptr += ELX_LOOPBACK_HEADER_SZ; | ||
2120 | sg_copy_to_buffer(job->request_payload.sg_list, | ||
2121 | job->request_payload.sg_cnt, | ||
2122 | ptr, size); | ||
2123 | |||
2124 | rc = lpfcdiag_loop_self_reg(phba, &rpi); | ||
2125 | if (rc) { | ||
2126 | rc = -ENOMEM; | ||
2127 | goto loopback_test_exit; | ||
2128 | } | ||
2129 | |||
2130 | rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); | ||
2131 | if (rc) { | ||
2132 | lpfcdiag_loop_self_unreg(phba, rpi); | ||
2133 | rc = -ENOMEM; | ||
2134 | goto loopback_test_exit; | ||
2135 | } | ||
2136 | |||
2137 | rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); | ||
2138 | if (rc) { | ||
2139 | lpfcdiag_loop_self_unreg(phba, rpi); | ||
2140 | rc = -ENOMEM; | ||
2141 | goto loopback_test_exit; | ||
2142 | } | ||
2143 | |||
2144 | evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, | ||
2145 | SLI_CT_ELX_LOOPBACK); | ||
2146 | if (!evt) { | ||
2147 | lpfcdiag_loop_self_unreg(phba, rpi); | ||
2148 | rc = -ENOMEM; | ||
2149 | goto loopback_test_exit; | ||
2150 | } | ||
2151 | |||
2152 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
2153 | list_add(&evt->node, &phba->ct_ev_waiters); | ||
2154 | lpfc_bsg_event_ref(evt); | ||
2155 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2156 | |||
2157 | cmdiocbq = lpfc_sli_get_iocbq(phba); | ||
2158 | rspiocbq = lpfc_sli_get_iocbq(phba); | ||
2159 | txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); | ||
2160 | |||
2161 | if (txbmp) { | ||
2162 | txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); | ||
2163 | INIT_LIST_HEAD(&txbmp->list); | ||
2164 | txbpl = (struct ulp_bde64 *) txbmp->virt; | ||
2165 | if (txbpl) | ||
2166 | txbuffer = diag_cmd_data_alloc(phba, | ||
2167 | txbpl, full_size, 0); | ||
2168 | } | ||
2169 | |||
2170 | if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer) { | ||
2171 | rc = -ENOMEM; | ||
2172 | goto err_loopback_test_exit; | ||
2173 | } | ||
2174 | |||
2175 | cmd = &cmdiocbq->iocb; | ||
2176 | rsp = &rspiocbq->iocb; | ||
2177 | |||
2178 | INIT_LIST_HEAD(&head); | ||
2179 | list_add_tail(&head, &txbuffer->dma.list); | ||
2180 | list_for_each_entry(curr, &head, list) { | ||
2181 | segment_len = ((struct lpfc_dmabufext *)curr)->size; | ||
2182 | if (current_offset == 0) { | ||
2183 | ctreq = curr->virt; | ||
2184 | memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); | ||
2185 | ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; | ||
2186 | ctreq->RevisionId.bits.InId = 0; | ||
2187 | ctreq->FsType = SLI_CT_ELX_LOOPBACK; | ||
2188 | ctreq->FsSubType = 0; | ||
2189 | ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA; | ||
2190 | ctreq->CommandResponse.bits.Size = size; | ||
2191 | segment_offset = ELX_LOOPBACK_HEADER_SZ; | ||
2192 | } else | ||
2193 | segment_offset = 0; | ||
2194 | |||
2195 | BUG_ON(segment_offset >= segment_len); | ||
2196 | memcpy(curr->virt + segment_offset, | ||
2197 | ptr + current_offset, | ||
2198 | segment_len - segment_offset); | ||
2199 | |||
2200 | current_offset += segment_len - segment_offset; | ||
2201 | BUG_ON(current_offset > size); | ||
2202 | } | ||
2203 | list_del(&head); | ||
2204 | |||
2205 | /* Build the XMIT_SEQUENCE iocb */ | ||
2206 | |||
2207 | num_bde = (uint32_t)txbuffer->flag; | ||
2208 | |||
2209 | cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); | ||
2210 | cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys); | ||
2211 | cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; | ||
2212 | cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64)); | ||
2213 | |||
2214 | cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); | ||
2215 | cmd->un.xseq64.w5.hcsw.Dfctl = 0; | ||
2216 | cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; | ||
2217 | cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; | ||
2218 | |||
2219 | cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; | ||
2220 | cmd->ulpBdeCount = 1; | ||
2221 | cmd->ulpLe = 1; | ||
2222 | cmd->ulpClass = CLASS3; | ||
2223 | cmd->ulpContext = txxri; | ||
2224 | |||
2225 | cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; | ||
2226 | cmdiocbq->vport = phba->pport; | ||
2227 | |||
2228 | rc = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, rspiocbq, | ||
2229 | (phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT); | ||
2230 | |||
2231 | if ((rc != IOCB_SUCCESS) || (rsp->ulpStatus != IOCB_SUCCESS)) { | ||
2232 | rc = -EIO; | ||
2233 | goto err_loopback_test_exit; | ||
2234 | } | ||
2235 | |||
2236 | evt->waiting = 1; | ||
2237 | rc = wait_event_interruptible_timeout( | ||
2238 | evt->wq, !list_empty(&evt->events_to_see), | ||
2239 | ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); | ||
2240 | evt->waiting = 0; | ||
2241 | if (list_empty(&evt->events_to_see)) | ||
2242 | rc = (rc) ? -EINTR : -ETIMEDOUT; | ||
2243 | else { | ||
2244 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
2245 | list_move(evt->events_to_see.prev, &evt->events_to_get); | ||
2246 | evdat = list_entry(evt->events_to_get.prev, | ||
2247 | typeof(*evdat), node); | ||
2248 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2249 | rx_databuf = evdat->data; | ||
2250 | if (evdat->len != full_size) { | ||
2251 | lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, | ||
2252 | "1603 Loopback test did not receive expected " | ||
2253 | "data length. actual length 0x%x expected " | ||
2254 | "length 0x%x\n", | ||
2255 | evdat->len, full_size); | ||
2256 | rc = -EIO; | ||
2257 | } else if (rx_databuf == NULL) | ||
2258 | rc = -EIO; | ||
2259 | else { | ||
2260 | rc = IOCB_SUCCESS; | ||
2261 | /* skip over elx loopback header */ | ||
2262 | rx_databuf += ELX_LOOPBACK_HEADER_SZ; | ||
2263 | job->reply->reply_payload_rcv_len = | ||
2264 | sg_copy_from_buffer(job->reply_payload.sg_list, | ||
2265 | job->reply_payload.sg_cnt, | ||
2266 | rx_databuf, size); | ||
2267 | job->reply->reply_payload_rcv_len = size; | ||
2268 | } | ||
2269 | } | ||
2270 | |||
2271 | err_loopback_test_exit: | ||
2272 | lpfcdiag_loop_self_unreg(phba, rpi); | ||
2273 | |||
2274 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
2275 | lpfc_bsg_event_unref(evt); /* release ref */ | ||
2276 | lpfc_bsg_event_unref(evt); /* delete */ | ||
2277 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2278 | |||
2279 | if (cmdiocbq != NULL) | ||
2280 | lpfc_sli_release_iocbq(phba, cmdiocbq); | ||
2281 | |||
2282 | if (rspiocbq != NULL) | ||
2283 | lpfc_sli_release_iocbq(phba, rspiocbq); | ||
2284 | |||
2285 | if (txbmp != NULL) { | ||
2286 | if (txbpl != NULL) { | ||
2287 | if (txbuffer != NULL) | ||
2288 | diag_cmd_data_free(phba, txbuffer); | ||
2289 | lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys); | ||
2290 | } | ||
2291 | kfree(txbmp); | ||
2292 | } | ||
2293 | |||
2294 | loopback_test_exit: | ||
2295 | kfree(dataout); | ||
2296 | /* make error code available to userspace */ | ||
2297 | job->reply->result = rc; | ||
2298 | job->dd_data = NULL; | ||
2299 | /* complete the job back to userspace if no error */ | ||
2300 | if (rc == 0) | ||
2301 | job->job_done(job); | ||
2302 | return rc; | ||
2303 | } | ||
2304 | |||
2305 | /** | ||
2306 | * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command | ||
2307 | * @job: GET_DFC_REV fc_bsg_job | ||
2308 | **/ | ||
2309 | static int | ||
2310 | lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job) | ||
2311 | { | ||
2312 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; | ||
2313 | struct lpfc_hba *phba = vport->phba; | ||
2314 | struct get_mgmt_rev *event_req; | ||
2315 | struct get_mgmt_rev_reply *event_reply; | ||
2316 | int rc = 0; | ||
2317 | |||
2318 | if (job->request_len < | ||
2319 | sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) { | ||
2320 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
2321 | "2740 Received GET_DFC_REV request below " | ||
2322 | "minimum size\n"); | ||
2323 | rc = -EINVAL; | ||
2324 | goto job_error; | ||
2325 | } | ||
2326 | |||
2327 | event_req = (struct get_mgmt_rev *) | ||
2328 | job->request->rqst_data.h_vendor.vendor_cmd; | ||
2329 | |||
2330 | event_reply = (struct get_mgmt_rev_reply *) | ||
2331 | job->reply->reply_data.vendor_reply.vendor_rsp; | ||
2332 | |||
2333 | if (job->reply_len < | ||
2334 | sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) { | ||
2335 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
2336 | "2741 Received GET_DFC_REV reply below " | ||
2337 | "minimum size\n"); | ||
2338 | rc = -EINVAL; | ||
2339 | goto job_error; | ||
2340 | } | ||
2341 | |||
2342 | event_reply->info.a_Major = MANAGEMENT_MAJOR_REV; | ||
2343 | event_reply->info.a_Minor = MANAGEMENT_MINOR_REV; | ||
2344 | job_error: | ||
2345 | job->reply->result = rc; | ||
2346 | if (rc == 0) | ||
2347 | job->job_done(job); | ||
2348 | return rc; | ||
2349 | } | ||
2350 | |||
2351 | /** | ||
2352 | * lpfc_bsg_wake_mbox_wait - lpfc_bsg_issue_mbox mbox completion handler | ||
2353 | * @phba: Pointer to HBA context object. | ||
2354 | * @pmboxq: Pointer to mailbox command. | ||
2355 | * | ||
2356 | * This is completion handler function for mailbox commands issued from | ||
2357 | * lpfc_bsg_issue_mbox function. This function is called by the | ||
2358 | * mailbox event handler function with no lock held. This function | ||
2359 | * will wake up thread waiting on the wait queue pointed by context1 | ||
2360 | * of the mailbox. | ||
2361 | **/ | ||
2362 | void | ||
2363 | lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) | ||
2364 | { | ||
2365 | struct bsg_job_data *dd_data; | ||
2366 | MAILBOX_t *pmb; | ||
2367 | MAILBOX_t *mb; | ||
2368 | struct fc_bsg_job *job; | ||
2369 | uint32_t size; | ||
2370 | unsigned long flags; | ||
2371 | |||
2372 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
2373 | dd_data = pmboxq->context1; | ||
2374 | if (!dd_data) { | ||
2375 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2376 | return; | ||
2377 | } | ||
2378 | |||
2379 | pmb = &dd_data->context_un.mbox.pmboxq->u.mb; | ||
2380 | mb = dd_data->context_un.mbox.mb; | ||
2381 | job = dd_data->context_un.mbox.set_job; | ||
2382 | memcpy(mb, pmb, sizeof(*pmb)); | ||
2383 | size = job->request_payload.payload_len; | ||
2384 | job->reply->reply_payload_rcv_len = | ||
2385 | sg_copy_from_buffer(job->reply_payload.sg_list, | ||
2386 | job->reply_payload.sg_cnt, | ||
2387 | mb, size); | ||
2388 | job->reply->result = 0; | ||
2389 | dd_data->context_un.mbox.set_job = NULL; | ||
2390 | job->dd_data = NULL; | ||
2391 | job->job_done(job); | ||
2392 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2393 | mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); | ||
2394 | kfree(mb); | ||
2395 | kfree(dd_data); | ||
2396 | return; | ||
2397 | } | ||
2398 | |||
2399 | /** | ||
2400 | * lpfc_bsg_check_cmd_access - test for a supported mailbox command | ||
2401 | * @phba: Pointer to HBA context object. | ||
2402 | * @mb: Pointer to a mailbox object. | ||
2403 | * @vport: Pointer to a vport object. | ||
2404 | * | ||
2405 | * Some commands require the port to be offline, some may not be called from | ||
2406 | * the application. | ||
2407 | **/ | ||
2408 | static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, | ||
2409 | MAILBOX_t *mb, struct lpfc_vport *vport) | ||
2410 | { | ||
2411 | /* return negative error values for bsg job */ | ||
2412 | switch (mb->mbxCommand) { | ||
2413 | /* Offline only */ | ||
2414 | case MBX_INIT_LINK: | ||
2415 | case MBX_DOWN_LINK: | ||
2416 | case MBX_CONFIG_LINK: | ||
2417 | case MBX_CONFIG_RING: | ||
2418 | case MBX_RESET_RING: | ||
2419 | case MBX_UNREG_LOGIN: | ||
2420 | case MBX_CLEAR_LA: | ||
2421 | case MBX_DUMP_CONTEXT: | ||
2422 | case MBX_RUN_DIAGS: | ||
2423 | case MBX_RESTART: | ||
2424 | case MBX_SET_MASK: | ||
2425 | if (!(vport->fc_flag & FC_OFFLINE_MODE)) { | ||
2426 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
2427 | "2743 Command 0x%x is illegal in on-line " | ||
2428 | "state\n", | ||
2429 | mb->mbxCommand); | ||
2430 | return -EPERM; | ||
2431 | } | ||
2432 | case MBX_WRITE_NV: | ||
2433 | case MBX_WRITE_VPARMS: | ||
2434 | case MBX_LOAD_SM: | ||
2435 | case MBX_READ_NV: | ||
2436 | case MBX_READ_CONFIG: | ||
2437 | case MBX_READ_RCONFIG: | ||
2438 | case MBX_READ_STATUS: | ||
2439 | case MBX_READ_XRI: | ||
2440 | case MBX_READ_REV: | ||
2441 | case MBX_READ_LNK_STAT: | ||
2442 | case MBX_DUMP_MEMORY: | ||
2443 | case MBX_DOWN_LOAD: | ||
2444 | case MBX_UPDATE_CFG: | ||
2445 | case MBX_KILL_BOARD: | ||
2446 | case MBX_LOAD_AREA: | ||
2447 | case MBX_LOAD_EXP_ROM: | ||
2448 | case MBX_BEACON: | ||
2449 | case MBX_DEL_LD_ENTRY: | ||
2450 | case MBX_SET_DEBUG: | ||
2451 | case MBX_WRITE_WWN: | ||
2452 | case MBX_SLI4_CONFIG: | ||
2453 | case MBX_READ_EVENT_LOG_STATUS: | ||
2454 | case MBX_WRITE_EVENT_LOG: | ||
2455 | case MBX_PORT_CAPABILITIES: | ||
2456 | case MBX_PORT_IOV_CONTROL: | ||
2457 | break; | ||
2458 | case MBX_SET_VARIABLE: | ||
2459 | case MBX_RUN_BIU_DIAG64: | ||
2460 | case MBX_READ_EVENT_LOG: | ||
2461 | case MBX_READ_SPARM64: | ||
2462 | case MBX_READ_LA: | ||
2463 | case MBX_READ_LA64: | ||
2464 | case MBX_REG_LOGIN: | ||
2465 | case MBX_REG_LOGIN64: | ||
2466 | case MBX_CONFIG_PORT: | ||
2467 | case MBX_RUN_BIU_DIAG: | ||
2468 | default: | ||
2469 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
2470 | "2742 Unknown Command 0x%x\n", | ||
2471 | mb->mbxCommand); | ||
2472 | return -EPERM; | ||
2473 | } | ||
2474 | |||
2475 | return 0; /* ok */ | ||
2476 | } | ||
2477 | |||
2478 | /** | ||
2479 | * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app | ||
2480 | * @phba: Pointer to HBA context object. | ||
2481 | * @mb: Pointer to a mailbox object. | ||
2482 | * @vport: Pointer to a vport object. | ||
2483 | * | ||
2484 | * Allocate a tracking object, mailbox command memory, get a mailbox | ||
2485 | * from the mailbox pool, copy the caller mailbox command. | ||
2486 | * | ||
2487 | * If offline and the sli is active we need to poll for the command (port is | ||
2488 | * being reset) and com-plete the job, otherwise issue the mailbox command and | ||
2489 | * let our completion handler finish the command. | ||
2490 | **/ | ||
2491 | static uint32_t | ||
2492 | lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, | ||
2493 | struct lpfc_vport *vport) | ||
2494 | { | ||
2495 | LPFC_MBOXQ_t *pmboxq; | ||
2496 | MAILBOX_t *pmb; | ||
2497 | MAILBOX_t *mb; | ||
2498 | struct bsg_job_data *dd_data; | ||
2499 | uint32_t size; | ||
2500 | int rc = 0; | ||
2501 | |||
2502 | /* allocate our bsg tracking structure */ | ||
2503 | dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); | ||
2504 | if (!dd_data) { | ||
2505 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
2506 | "2727 Failed allocation of dd_data\n"); | ||
2507 | return -ENOMEM; | ||
2508 | } | ||
2509 | |||
2510 | mb = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
2511 | if (!mb) { | ||
2512 | kfree(dd_data); | ||
2513 | return -ENOMEM; | ||
2514 | } | ||
2515 | |||
2516 | pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
2517 | if (!pmboxq) { | ||
2518 | kfree(dd_data); | ||
2519 | kfree(mb); | ||
2520 | return -ENOMEM; | ||
2521 | } | ||
2522 | |||
2523 | size = job->request_payload.payload_len; | ||
2524 | job->reply->reply_payload_rcv_len = | ||
2525 | sg_copy_to_buffer(job->request_payload.sg_list, | ||
2526 | job->request_payload.sg_cnt, | ||
2527 | mb, size); | ||
2528 | |||
2529 | rc = lpfc_bsg_check_cmd_access(phba, mb, vport); | ||
2530 | if (rc != 0) { | ||
2531 | kfree(dd_data); | ||
2532 | kfree(mb); | ||
2533 | mempool_free(pmboxq, phba->mbox_mem_pool); | ||
2534 | return rc; /* must be negative */ | ||
2535 | } | ||
2536 | |||
2537 | memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); | ||
2538 | pmb = &pmboxq->u.mb; | ||
2539 | memcpy(pmb, mb, sizeof(*pmb)); | ||
2540 | pmb->mbxOwner = OWN_HOST; | ||
2541 | pmboxq->context1 = NULL; | ||
2542 | pmboxq->vport = vport; | ||
2543 | |||
2544 | if ((vport->fc_flag & FC_OFFLINE_MODE) || | ||
2545 | (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { | ||
2546 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); | ||
2547 | if (rc != MBX_SUCCESS) { | ||
2548 | if (rc != MBX_TIMEOUT) { | ||
2549 | kfree(dd_data); | ||
2550 | kfree(mb); | ||
2551 | mempool_free(pmboxq, phba->mbox_mem_pool); | ||
2552 | } | ||
2553 | return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; | ||
2554 | } | ||
2555 | |||
2556 | memcpy(mb, pmb, sizeof(*pmb)); | ||
2557 | job->reply->reply_payload_rcv_len = | ||
2558 | sg_copy_from_buffer(job->reply_payload.sg_list, | ||
2559 | job->reply_payload.sg_cnt, | ||
2560 | mb, size); | ||
2561 | kfree(dd_data); | ||
2562 | kfree(mb); | ||
2563 | mempool_free(pmboxq, phba->mbox_mem_pool); | ||
2564 | /* not waiting mbox already done */ | ||
2565 | return 0; | ||
2566 | } | ||
2567 | |||
2568 | /* setup wake call as IOCB callback */ | ||
2569 | pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait; | ||
2570 | /* setup context field to pass wait_queue pointer to wake function */ | ||
2571 | pmboxq->context1 = dd_data; | ||
2572 | dd_data->type = TYPE_MBOX; | ||
2573 | dd_data->context_un.mbox.pmboxq = pmboxq; | ||
2574 | dd_data->context_un.mbox.mb = mb; | ||
2575 | dd_data->context_un.mbox.set_job = job; | ||
2576 | job->dd_data = dd_data; | ||
2577 | rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); | ||
2578 | if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { | ||
2579 | kfree(dd_data); | ||
2580 | kfree(mb); | ||
2581 | mempool_free(pmboxq, phba->mbox_mem_pool); | ||
2582 | return -EIO; | ||
2583 | } | ||
2584 | |||
2585 | return 1; | ||
2586 | } | ||
2587 | |||
2588 | /** | ||
2589 | * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command | ||
2590 | * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX. | ||
2591 | **/ | ||
2592 | static int | ||
2593 | lpfc_bsg_mbox_cmd(struct fc_bsg_job *job) | ||
2594 | { | ||
2595 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; | ||
2596 | struct lpfc_hba *phba = vport->phba; | ||
2597 | int rc = 0; | ||
2598 | |||
2599 | /* in case no data is transferred */ | ||
2600 | job->reply->reply_payload_rcv_len = 0; | ||
2601 | if (job->request_len < | ||
2602 | sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) { | ||
2603 | lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, | ||
2604 | "2737 Received MBOX_REQ request below " | ||
2605 | "minimum size\n"); | ||
2606 | rc = -EINVAL; | ||
2607 | goto job_error; | ||
2608 | } | ||
2609 | |||
2610 | if (job->request_payload.payload_len != PAGE_SIZE) { | ||
2611 | rc = -EINVAL; | ||
2612 | goto job_error; | ||
2613 | } | ||
2614 | |||
2615 | if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { | ||
2616 | rc = -EAGAIN; | ||
2617 | goto job_error; | ||
2618 | } | ||
2619 | |||
2620 | rc = lpfc_bsg_issue_mbox(phba, job, vport); | ||
2621 | |||
2622 | job_error: | ||
2623 | if (rc == 0) { | ||
2624 | /* job done */ | ||
2625 | job->reply->result = 0; | ||
2626 | job->dd_data = NULL; | ||
2627 | job->job_done(job); | ||
2628 | } else if (rc == 1) | ||
2629 | /* job submitted, will complete later*/ | ||
2630 | rc = 0; /* return zero, no error */ | ||
2631 | else { | ||
2632 | /* some error occurred */ | ||
2633 | job->reply->result = rc; | ||
2634 | job->dd_data = NULL; | ||
2635 | } | ||
830 | 2636 | ||
831 | return rc; | 2637 | return rc; |
832 | } | 2638 | } |
@@ -834,38 +2640,57 @@ error_get_event_exit: | |||
834 | /** | 2640 | /** |
835 | * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job | 2641 | * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job |
836 | * @job: fc_bsg_job to handle | 2642 | * @job: fc_bsg_job to handle |
837 | */ | 2643 | **/ |
838 | static int | 2644 | static int |
839 | lpfc_bsg_hst_vendor(struct fc_bsg_job *job) | 2645 | lpfc_bsg_hst_vendor(struct fc_bsg_job *job) |
840 | { | 2646 | { |
841 | int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; | 2647 | int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; |
2648 | int rc; | ||
842 | 2649 | ||
843 | switch (command) { | 2650 | switch (command) { |
844 | case LPFC_BSG_VENDOR_SET_CT_EVENT: | 2651 | case LPFC_BSG_VENDOR_SET_CT_EVENT: |
845 | return lpfc_bsg_set_event(job); | 2652 | rc = lpfc_bsg_hba_set_event(job); |
846 | break; | 2653 | break; |
847 | |||
848 | case LPFC_BSG_VENDOR_GET_CT_EVENT: | 2654 | case LPFC_BSG_VENDOR_GET_CT_EVENT: |
849 | return lpfc_bsg_get_event(job); | 2655 | rc = lpfc_bsg_hba_get_event(job); |
2656 | break; | ||
2657 | case LPFC_BSG_VENDOR_SEND_MGMT_RESP: | ||
2658 | rc = lpfc_bsg_send_mgmt_rsp(job); | ||
2659 | break; | ||
2660 | case LPFC_BSG_VENDOR_DIAG_MODE: | ||
2661 | rc = lpfc_bsg_diag_mode(job); | ||
2662 | break; | ||
2663 | case LPFC_BSG_VENDOR_DIAG_TEST: | ||
2664 | rc = lpfc_bsg_diag_test(job); | ||
2665 | break; | ||
2666 | case LPFC_BSG_VENDOR_GET_MGMT_REV: | ||
2667 | rc = lpfc_bsg_get_dfc_rev(job); | ||
2668 | break; | ||
2669 | case LPFC_BSG_VENDOR_MBOX: | ||
2670 | rc = lpfc_bsg_mbox_cmd(job); | ||
850 | break; | 2671 | break; |
851 | |||
852 | default: | 2672 | default: |
853 | return -EINVAL; | 2673 | rc = -EINVAL; |
2674 | job->reply->reply_payload_rcv_len = 0; | ||
2675 | /* make error code available to userspace */ | ||
2676 | job->reply->result = rc; | ||
2677 | break; | ||
854 | } | 2678 | } |
2679 | |||
2680 | return rc; | ||
855 | } | 2681 | } |
856 | 2682 | ||
857 | /** | 2683 | /** |
858 | * lpfc_bsg_request - handle a bsg request from the FC transport | 2684 | * lpfc_bsg_request - handle a bsg request from the FC transport |
859 | * @job: fc_bsg_job to handle | 2685 | * @job: fc_bsg_job to handle |
860 | */ | 2686 | **/ |
861 | int | 2687 | int |
862 | lpfc_bsg_request(struct fc_bsg_job *job) | 2688 | lpfc_bsg_request(struct fc_bsg_job *job) |
863 | { | 2689 | { |
864 | uint32_t msgcode; | 2690 | uint32_t msgcode; |
865 | int rc = -EINVAL; | 2691 | int rc; |
866 | 2692 | ||
867 | msgcode = job->request->msgcode; | 2693 | msgcode = job->request->msgcode; |
868 | |||
869 | switch (msgcode) { | 2694 | switch (msgcode) { |
870 | case FC_BSG_HST_VENDOR: | 2695 | case FC_BSG_HST_VENDOR: |
871 | rc = lpfc_bsg_hst_vendor(job); | 2696 | rc = lpfc_bsg_hst_vendor(job); |
@@ -874,9 +2699,13 @@ lpfc_bsg_request(struct fc_bsg_job *job) | |||
874 | rc = lpfc_bsg_rport_els(job); | 2699 | rc = lpfc_bsg_rport_els(job); |
875 | break; | 2700 | break; |
876 | case FC_BSG_RPT_CT: | 2701 | case FC_BSG_RPT_CT: |
877 | rc = lpfc_bsg_rport_ct(job); | 2702 | rc = lpfc_bsg_send_mgmt_cmd(job); |
878 | break; | 2703 | break; |
879 | default: | 2704 | default: |
2705 | rc = -EINVAL; | ||
2706 | job->reply->reply_payload_rcv_len = 0; | ||
2707 | /* make error code available to userspace */ | ||
2708 | job->reply->result = rc; | ||
880 | break; | 2709 | break; |
881 | } | 2710 | } |
882 | 2711 | ||
@@ -889,17 +2718,71 @@ lpfc_bsg_request(struct fc_bsg_job *job) | |||
889 | * | 2718 | * |
890 | * This function just aborts the job's IOCB. The aborted IOCB will return to | 2719 | * This function just aborts the job's IOCB. The aborted IOCB will return to |
891 | * the waiting function which will handle passing the error back to userspace | 2720 | * the waiting function which will handle passing the error back to userspace |
892 | */ | 2721 | **/ |
893 | int | 2722 | int |
894 | lpfc_bsg_timeout(struct fc_bsg_job *job) | 2723 | lpfc_bsg_timeout(struct fc_bsg_job *job) |
895 | { | 2724 | { |
896 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; | 2725 | struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; |
897 | struct lpfc_hba *phba = vport->phba; | 2726 | struct lpfc_hba *phba = vport->phba; |
898 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)job->dd_data; | 2727 | struct lpfc_iocbq *cmdiocb; |
2728 | struct lpfc_bsg_event *evt; | ||
2729 | struct lpfc_bsg_iocb *iocb; | ||
2730 | struct lpfc_bsg_mbox *mbox; | ||
899 | struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; | 2731 | struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; |
2732 | struct bsg_job_data *dd_data; | ||
2733 | unsigned long flags; | ||
2734 | |||
2735 | spin_lock_irqsave(&phba->ct_ev_lock, flags); | ||
2736 | dd_data = (struct bsg_job_data *)job->dd_data; | ||
2737 | /* timeout and completion crossed paths if no dd_data */ | ||
2738 | if (!dd_data) { | ||
2739 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2740 | return 0; | ||
2741 | } | ||
900 | 2742 | ||
901 | if (cmdiocb) | 2743 | switch (dd_data->type) { |
2744 | case TYPE_IOCB: | ||
2745 | iocb = &dd_data->context_un.iocb; | ||
2746 | cmdiocb = iocb->cmdiocbq; | ||
2747 | /* hint to completion handler that the job timed out */ | ||
2748 | job->reply->result = -EAGAIN; | ||
2749 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2750 | /* this will call our completion handler */ | ||
2751 | spin_lock_irq(&phba->hbalock); | ||
902 | lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); | 2752 | lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); |
2753 | spin_unlock_irq(&phba->hbalock); | ||
2754 | break; | ||
2755 | case TYPE_EVT: | ||
2756 | evt = dd_data->context_un.evt; | ||
2757 | /* this event has no job anymore */ | ||
2758 | evt->set_job = NULL; | ||
2759 | job->dd_data = NULL; | ||
2760 | job->reply->reply_payload_rcv_len = 0; | ||
2761 | /* Return -EAGAIN which is our way of signallying the | ||
2762 | * app to retry. | ||
2763 | */ | ||
2764 | job->reply->result = -EAGAIN; | ||
2765 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2766 | job->job_done(job); | ||
2767 | break; | ||
2768 | case TYPE_MBOX: | ||
2769 | mbox = &dd_data->context_un.mbox; | ||
2770 | /* this mbox has no job anymore */ | ||
2771 | mbox->set_job = NULL; | ||
2772 | job->dd_data = NULL; | ||
2773 | job->reply->reply_payload_rcv_len = 0; | ||
2774 | job->reply->result = -EAGAIN; | ||
2775 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2776 | job->job_done(job); | ||
2777 | break; | ||
2778 | default: | ||
2779 | spin_unlock_irqrestore(&phba->ct_ev_lock, flags); | ||
2780 | break; | ||
2781 | } | ||
903 | 2782 | ||
2783 | /* scsi transport fc fc_bsg_job_timeout expects a zero return code, | ||
2784 | * otherwise an error message will be displayed on the console | ||
2785 | * so always return success (zero) | ||
2786 | */ | ||
904 | return 0; | 2787 | return 0; |
905 | } | 2788 | } |