diff options
author | <jejb@titanic.il.steeleye.com> | 2005-04-17 17:05:31 -0400 |
---|---|---|
committer | James Bottomley <jejb@titanic> | 2005-04-18 14:50:53 -0400 |
commit | dea3101e0a5c897d2c9351a7444e139db9f40247 (patch) | |
tree | 61de19e98eed08bb760703b362eab2038c34f261 /drivers/scsi/lpfc/lpfc_ct.c | |
parent | 8e8790415e91964096f862a58cacb55d2bc9a817 (diff) |
lpfc: add Emulex FC driver version 8.0.28
From: James.Smart@Emulex.Com
Modified for kernel import and
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_ct.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 1237 |
1 files changed, 1237 insertions, 0 deletions
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c new file mode 100644 index 000000000000..c40cb239c16d --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_ct.c | |||
@@ -0,0 +1,1237 @@ | |||
1 | /******************************************************************* | ||
2 | * This file is part of the Emulex Linux Device Driver for * | ||
3 | * Enterprise Fibre Channel Host Bus Adapters. * | ||
4 | * Refer to the README file included with this package for * | ||
5 | * driver version and adapter support. * | ||
6 | * Copyright (C) 2004 Emulex Corporation. * | ||
7 | * www.emulex.com * | ||
8 | * * | ||
9 | * This program is free software; you can redistribute it and/or * | ||
10 | * modify it under the terms of the GNU General Public License * | ||
11 | * as published by the Free Software Foundation; either version 2 * | ||
12 | * of the License, or (at your option) any later version. * | ||
13 | * * | ||
14 | * This program is distributed in the hope that it will be useful, * | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
17 | * GNU General Public License for more details, a copy of which * | ||
18 | * can be found in the file COPYING included with this package. * | ||
19 | *******************************************************************/ | ||
20 | |||
21 | /* | ||
22 | * $Id: lpfc_ct.c 1.161 2005/04/13 11:59:01EDT sf_support Exp $ | ||
23 | * | ||
24 | * Fibre Channel SCSI LAN Device Driver CT support | ||
25 | */ | ||
26 | |||
27 | #include <linux/blkdev.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/utsname.h> | ||
31 | |||
32 | #include <scsi/scsi_device.h> | ||
33 | #include <scsi/scsi_host.h> | ||
34 | |||
35 | #include "lpfc_hw.h" | ||
36 | #include "lpfc_sli.h" | ||
37 | #include "lpfc_disc.h" | ||
38 | #include "lpfc_scsi.h" | ||
39 | #include "lpfc.h" | ||
40 | #include "lpfc_logmsg.h" | ||
41 | #include "lpfc_crtn.h" | ||
42 | #include "lpfc_version.h" | ||
43 | |||
44 | #define HBA_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver | ||
45 | * incapable of reporting */ | ||
46 | #define HBA_PORTSPEED_1GBIT 1 /* 1 GBit/sec */ | ||
47 | #define HBA_PORTSPEED_2GBIT 2 /* 2 GBit/sec */ | ||
48 | #define HBA_PORTSPEED_4GBIT 8 /* 4 GBit/sec */ | ||
49 | #define HBA_PORTSPEED_8GBIT 16 /* 8 GBit/sec */ | ||
50 | #define HBA_PORTSPEED_10GBIT 4 /* 10 GBit/sec */ | ||
51 | #define HBA_PORTSPEED_NOT_NEGOTIATED 5 /* Speed not established */ | ||
52 | |||
53 | #define FOURBYTES 4 | ||
54 | |||
55 | |||
56 | static char *lpfc_release_version = LPFC_DRIVER_VERSION; | ||
57 | |||
58 | /* | ||
59 | * lpfc_ct_unsol_event | ||
60 | */ | ||
61 | void | ||
62 | lpfc_ct_unsol_event(struct lpfc_hba * phba, | ||
63 | struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocbq) | ||
64 | { | ||
65 | |||
66 | struct lpfc_iocbq *next_piocbq; | ||
67 | struct lpfc_dmabuf *pmbuf = NULL; | ||
68 | struct lpfc_dmabuf *matp, *next_matp; | ||
69 | uint32_t ctx = 0, size = 0, cnt = 0; | ||
70 | IOCB_t *icmd = &piocbq->iocb; | ||
71 | IOCB_t *save_icmd = icmd; | ||
72 | int i, go_exit = 0; | ||
73 | struct list_head head; | ||
74 | |||
75 | if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||
76 | ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { | ||
77 | /* Not enough posted buffers; Try posting more buffers */ | ||
78 | phba->fc_stat.NoRcvBuf++; | ||
79 | lpfc_post_buffer(phba, pring, 0, 1); | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | /* If there are no BDEs associated with this IOCB, | ||
84 | * there is nothing to do. | ||
85 | */ | ||
86 | if (icmd->ulpBdeCount == 0) | ||
87 | return; | ||
88 | |||
89 | INIT_LIST_HEAD(&head); | ||
90 | list_add_tail(&head, &piocbq->list); | ||
91 | |||
92 | list_for_each_entry_safe(piocbq, next_piocbq, &head, list) { | ||
93 | icmd = &piocbq->iocb; | ||
94 | if (ctx == 0) | ||
95 | ctx = (uint32_t) (icmd->ulpContext); | ||
96 | if (icmd->ulpBdeCount == 0) | ||
97 | continue; | ||
98 | |||
99 | for (i = 0; i < icmd->ulpBdeCount; i++) { | ||
100 | matp = lpfc_sli_ringpostbuf_get(phba, pring, | ||
101 | getPaddr(icmd->un. | ||
102 | cont64[i]. | ||
103 | addrHigh, | ||
104 | icmd->un. | ||
105 | cont64[i]. | ||
106 | addrLow)); | ||
107 | if (!matp) { | ||
108 | /* Insert lpfc log message here */ | ||
109 | lpfc_post_buffer(phba, pring, cnt, 1); | ||
110 | go_exit = 1; | ||
111 | goto ct_unsol_event_exit_piocbq; | ||
112 | } | ||
113 | |||
114 | /* Typically for Unsolicited CT requests */ | ||
115 | if (!pmbuf) { | ||
116 | pmbuf = matp; | ||
117 | INIT_LIST_HEAD(&pmbuf->list); | ||
118 | } else | ||
119 | list_add_tail(&matp->list, &pmbuf->list); | ||
120 | |||
121 | size += icmd->un.cont64[i].tus.f.bdeSize; | ||
122 | cnt++; | ||
123 | } | ||
124 | |||
125 | icmd->ulpBdeCount = 0; | ||
126 | } | ||
127 | |||
128 | lpfc_post_buffer(phba, pring, cnt, 1); | ||
129 | if (save_icmd->ulpStatus) { | ||
130 | go_exit = 1; | ||
131 | } | ||
132 | |||
133 | ct_unsol_event_exit_piocbq: | ||
134 | if (pmbuf) { | ||
135 | list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) { | ||
136 | lpfc_mbuf_free(phba, matp->virt, matp->phys); | ||
137 | list_del(&matp->list); | ||
138 | kfree(matp); | ||
139 | } | ||
140 | lpfc_mbuf_free(phba, pmbuf->virt, pmbuf->phys); | ||
141 | kfree(pmbuf); | ||
142 | } | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | static void | ||
147 | lpfc_free_ct_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mlist) | ||
148 | { | ||
149 | struct lpfc_dmabuf *mlast, *next_mlast; | ||
150 | |||
151 | list_for_each_entry_safe(mlast, next_mlast, &mlist->list, list) { | ||
152 | lpfc_mbuf_free(phba, mlast->virt, mlast->phys); | ||
153 | list_del(&mlast->list); | ||
154 | kfree(mlast); | ||
155 | } | ||
156 | lpfc_mbuf_free(phba, mlist->virt, mlist->phys); | ||
157 | kfree(mlist); | ||
158 | return; | ||
159 | } | ||
160 | |||
161 | static struct lpfc_dmabuf * | ||
162 | lpfc_alloc_ct_rsp(struct lpfc_hba * phba, int cmdcode, struct ulp_bde64 * bpl, | ||
163 | uint32_t size, int *entries) | ||
164 | { | ||
165 | struct lpfc_dmabuf *mlist = NULL; | ||
166 | struct lpfc_dmabuf *mp; | ||
167 | int cnt, i = 0; | ||
168 | |||
169 | /* We get chucks of FCELSSIZE */ | ||
170 | cnt = size > FCELSSIZE ? FCELSSIZE: size; | ||
171 | |||
172 | while (size) { | ||
173 | /* Allocate buffer for rsp payload */ | ||
174 | mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); | ||
175 | if (!mp) { | ||
176 | if (mlist) | ||
177 | lpfc_free_ct_rsp(phba, mlist); | ||
178 | return NULL; | ||
179 | } | ||
180 | |||
181 | INIT_LIST_HEAD(&mp->list); | ||
182 | |||
183 | if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT)) | ||
184 | mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys)); | ||
185 | else | ||
186 | mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys)); | ||
187 | |||
188 | if (!mp->virt) { | ||
189 | kfree(mp); | ||
190 | lpfc_free_ct_rsp(phba, mlist); | ||
191 | return NULL; | ||
192 | } | ||
193 | |||
194 | /* Queue it to a linked list */ | ||
195 | if (!mlist) | ||
196 | mlist = mp; | ||
197 | else | ||
198 | list_add_tail(&mp->list, &mlist->list); | ||
199 | |||
200 | bpl->tus.f.bdeFlags = BUFF_USE_RCV; | ||
201 | /* build buffer ptr list for IOCB */ | ||
202 | bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) ); | ||
203 | bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) ); | ||
204 | bpl->tus.f.bdeSize = (uint16_t) cnt; | ||
205 | bpl->tus.w = le32_to_cpu(bpl->tus.w); | ||
206 | bpl++; | ||
207 | |||
208 | i++; | ||
209 | size -= cnt; | ||
210 | } | ||
211 | |||
212 | *entries = i; | ||
213 | return mlist; | ||
214 | } | ||
215 | |||
216 | static int | ||
217 | lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp, | ||
218 | struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp, | ||
219 | void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, | ||
220 | struct lpfc_iocbq *), | ||
221 | struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry, | ||
222 | uint32_t tmo) | ||
223 | { | ||
224 | |||
225 | struct lpfc_sli *psli = &phba->sli; | ||
226 | struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; | ||
227 | struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; | ||
228 | IOCB_t *icmd; | ||
229 | struct lpfc_iocbq *geniocb = NULL; | ||
230 | |||
231 | /* Allocate buffer for command iocb */ | ||
232 | spin_lock_irq(phba->host->host_lock); | ||
233 | list_remove_head(lpfc_iocb_list, geniocb, struct lpfc_iocbq, list); | ||
234 | spin_unlock_irq(phba->host->host_lock); | ||
235 | |||
236 | if (geniocb == NULL) | ||
237 | return 1; | ||
238 | memset(geniocb, 0, sizeof (struct lpfc_iocbq)); | ||
239 | |||
240 | icmd = &geniocb->iocb; | ||
241 | icmd->un.genreq64.bdl.ulpIoTag32 = 0; | ||
242 | icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); | ||
243 | icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); | ||
244 | icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BDL; | ||
245 | icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64)); | ||
246 | |||
247 | if (usr_flg) | ||
248 | geniocb->context3 = NULL; | ||
249 | else | ||
250 | geniocb->context3 = (uint8_t *) bmp; | ||
251 | |||
252 | /* Save for completion so we can release these resources */ | ||
253 | geniocb->context1 = (uint8_t *) inp; | ||
254 | geniocb->context2 = (uint8_t *) outp; | ||
255 | |||
256 | /* Fill in payload, bp points to frame payload */ | ||
257 | icmd->ulpCommand = CMD_GEN_REQUEST64_CR; | ||
258 | |||
259 | /* Fill in rest of iocb */ | ||
260 | icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); | ||
261 | icmd->un.genreq64.w5.hcsw.Dfctl = 0; | ||
262 | icmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL; | ||
263 | icmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; | ||
264 | |||
265 | if (!tmo) | ||
266 | tmo = (2 * phba->fc_ratov) + 1; | ||
267 | icmd->ulpTimeout = tmo; | ||
268 | icmd->ulpBdeCount = 1; | ||
269 | icmd->ulpLe = 1; | ||
270 | icmd->ulpClass = CLASS3; | ||
271 | icmd->ulpContext = ndlp->nlp_rpi; | ||
272 | |||
273 | /* Issue GEN REQ IOCB for NPORT <did> */ | ||
274 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
275 | "%d:0119 Issue GEN REQ IOCB for NPORT x%x " | ||
276 | "Data: x%x x%x\n", phba->brd_no, icmd->un.ulpWord[5], | ||
277 | icmd->ulpIoTag, phba->hba_state); | ||
278 | geniocb->iocb_cmpl = cmpl; | ||
279 | geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; | ||
280 | spin_lock_irq(phba->host->host_lock); | ||
281 | if (lpfc_sli_issue_iocb(phba, pring, geniocb, 0) == IOCB_ERROR) { | ||
282 | list_add_tail(&geniocb->list, lpfc_iocb_list); | ||
283 | spin_unlock_irq(phba->host->host_lock); | ||
284 | return 1; | ||
285 | } | ||
286 | spin_unlock_irq(phba->host->host_lock); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int | ||
292 | lpfc_ct_cmd(struct lpfc_hba *phba, struct lpfc_dmabuf *inmp, | ||
293 | struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp, | ||
294 | void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, | ||
295 | struct lpfc_iocbq *), | ||
296 | uint32_t rsp_size) | ||
297 | { | ||
298 | struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt; | ||
299 | struct lpfc_dmabuf *outmp; | ||
300 | int cnt = 0, status; | ||
301 | int cmdcode = ((struct lpfc_sli_ct_request *) inmp->virt)-> | ||
302 | CommandResponse.bits.CmdRsp; | ||
303 | |||
304 | bpl++; /* Skip past ct request */ | ||
305 | |||
306 | /* Put buffer(s) for ct rsp in bpl */ | ||
307 | outmp = lpfc_alloc_ct_rsp(phba, cmdcode, bpl, rsp_size, &cnt); | ||
308 | if (!outmp) | ||
309 | return -ENOMEM; | ||
310 | |||
311 | status = lpfc_gen_req(phba, bmp, inmp, outmp, cmpl, ndlp, 0, | ||
312 | cnt+1, 0); | ||
313 | if (status) { | ||
314 | lpfc_free_ct_rsp(phba, outmp); | ||
315 | return -ENOMEM; | ||
316 | } | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int | ||
321 | lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size) | ||
322 | { | ||
323 | struct lpfc_sli_ct_request *Response = | ||
324 | (struct lpfc_sli_ct_request *) mp->virt; | ||
325 | struct lpfc_nodelist *ndlp = NULL; | ||
326 | struct lpfc_dmabuf *mlast, *next_mp; | ||
327 | uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType; | ||
328 | uint32_t Did; | ||
329 | uint32_t CTentry; | ||
330 | int Cnt; | ||
331 | struct list_head head; | ||
332 | |||
333 | lpfc_set_disctmo(phba); | ||
334 | |||
335 | Cnt = Size > FCELSSIZE ? FCELSSIZE : Size; | ||
336 | |||
337 | list_add_tail(&head, &mp->list); | ||
338 | list_for_each_entry_safe(mp, next_mp, &head, list) { | ||
339 | mlast = mp; | ||
340 | |||
341 | Size -= Cnt; | ||
342 | |||
343 | if (!ctptr) | ||
344 | ctptr = (uint32_t *) mlast->virt; | ||
345 | else | ||
346 | Cnt -= 16; /* subtract length of CT header */ | ||
347 | |||
348 | /* Loop through entire NameServer list of DIDs */ | ||
349 | while (Cnt) { | ||
350 | |||
351 | /* Get next DID from NameServer List */ | ||
352 | CTentry = *ctptr++; | ||
353 | Did = ((be32_to_cpu(CTentry)) & Mask_DID); | ||
354 | |||
355 | ndlp = NULL; | ||
356 | if (Did != phba->fc_myDID) { | ||
357 | /* Check for rscn processing or not */ | ||
358 | ndlp = lpfc_setup_disc_node(phba, Did); | ||
359 | } | ||
360 | /* Mark all node table entries that are in the | ||
361 | Nameserver */ | ||
362 | if (ndlp) { | ||
363 | /* NameServer Rsp */ | ||
364 | lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||
365 | "%d:0238 Process x%x NameServer" | ||
366 | " Rsp Data: x%x x%x x%x\n", | ||
367 | phba->brd_no, | ||
368 | Did, ndlp->nlp_flag, | ||
369 | phba->fc_flag, | ||
370 | phba->fc_rscn_id_cnt); | ||
371 | } else { | ||
372 | /* NameServer Rsp */ | ||
373 | lpfc_printf_log(phba, | ||
374 | KERN_INFO, | ||
375 | LOG_DISCOVERY, | ||
376 | "%d:0239 Skip x%x NameServer " | ||
377 | "Rsp Data: x%x x%x x%x\n", | ||
378 | phba->brd_no, | ||
379 | Did, Size, phba->fc_flag, | ||
380 | phba->fc_rscn_id_cnt); | ||
381 | } | ||
382 | |||
383 | if (CTentry & (be32_to_cpu(SLI_CT_LAST_ENTRY))) | ||
384 | goto nsout1; | ||
385 | Cnt -= sizeof (uint32_t); | ||
386 | } | ||
387 | ctptr = NULL; | ||
388 | |||
389 | } | ||
390 | |||
391 | nsout1: | ||
392 | list_del(&head); | ||
393 | |||
394 | /* Here we are finished in the case RSCN */ | ||
395 | if (phba->hba_state == LPFC_HBA_READY) { | ||
396 | lpfc_els_flush_rscn(phba); | ||
397 | spin_lock_irq(phba->host->host_lock); | ||
398 | phba->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */ | ||
399 | spin_unlock_irq(phba->host->host_lock); | ||
400 | } | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | |||
405 | |||
406 | |||
407 | static void | ||
408 | lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
409 | struct lpfc_iocbq * rspiocb) | ||
410 | { | ||
411 | IOCB_t *irsp; | ||
412 | struct lpfc_sli *psli; | ||
413 | struct lpfc_dmabuf *bmp; | ||
414 | struct lpfc_dmabuf *inp; | ||
415 | struct lpfc_dmabuf *outp; | ||
416 | struct lpfc_nodelist *ndlp; | ||
417 | struct lpfc_sli_ct_request *CTrsp; | ||
418 | |||
419 | psli = &phba->sli; | ||
420 | /* we pass cmdiocb to state machine which needs rspiocb as well */ | ||
421 | cmdiocb->context_un.rsp_iocb = rspiocb; | ||
422 | |||
423 | inp = (struct lpfc_dmabuf *) cmdiocb->context1; | ||
424 | outp = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
425 | bmp = (struct lpfc_dmabuf *) cmdiocb->context3; | ||
426 | |||
427 | irsp = &rspiocb->iocb; | ||
428 | if (irsp->ulpStatus) { | ||
429 | if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||
430 | ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) || | ||
431 | (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) { | ||
432 | goto out; | ||
433 | } | ||
434 | |||
435 | /* Check for retry */ | ||
436 | if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) { | ||
437 | phba->fc_ns_retry++; | ||
438 | /* CT command is being retried */ | ||
439 | ndlp = | ||
440 | lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, | ||
441 | NameServer_DID); | ||
442 | if (ndlp) { | ||
443 | if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == | ||
444 | 0) { | ||
445 | goto out; | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | } else { | ||
450 | /* Good status, continue checking */ | ||
451 | CTrsp = (struct lpfc_sli_ct_request *) outp->virt; | ||
452 | if (CTrsp->CommandResponse.bits.CmdRsp == | ||
453 | be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) { | ||
454 | lpfc_ns_rsp(phba, outp, | ||
455 | (uint32_t) (irsp->un.genreq64.bdl.bdeSize)); | ||
456 | } else if (CTrsp->CommandResponse.bits.CmdRsp == | ||
457 | be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { | ||
458 | /* NameServer Rsp Error */ | ||
459 | lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||
460 | "%d:0240 NameServer Rsp Error " | ||
461 | "Data: x%x x%x x%x x%x\n", | ||
462 | phba->brd_no, | ||
463 | CTrsp->CommandResponse.bits.CmdRsp, | ||
464 | (uint32_t) CTrsp->ReasonCode, | ||
465 | (uint32_t) CTrsp->Explanation, | ||
466 | phba->fc_flag); | ||
467 | } else { | ||
468 | /* NameServer Rsp Error */ | ||
469 | lpfc_printf_log(phba, | ||
470 | KERN_INFO, | ||
471 | LOG_DISCOVERY, | ||
472 | "%d:0241 NameServer Rsp Error " | ||
473 | "Data: x%x x%x x%x x%x\n", | ||
474 | phba->brd_no, | ||
475 | CTrsp->CommandResponse.bits.CmdRsp, | ||
476 | (uint32_t) CTrsp->ReasonCode, | ||
477 | (uint32_t) CTrsp->Explanation, | ||
478 | phba->fc_flag); | ||
479 | } | ||
480 | } | ||
481 | /* Link up / RSCN discovery */ | ||
482 | lpfc_disc_start(phba); | ||
483 | out: | ||
484 | lpfc_free_ct_rsp(phba, outp); | ||
485 | lpfc_mbuf_free(phba, inp->virt, inp->phys); | ||
486 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||
487 | kfree(inp); | ||
488 | kfree(bmp); | ||
489 | spin_lock_irq(phba->host->host_lock); | ||
490 | list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list); | ||
491 | spin_unlock_irq(phba->host->host_lock); | ||
492 | return; | ||
493 | } | ||
494 | |||
495 | static void | ||
496 | lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
497 | struct lpfc_iocbq * rspiocb) | ||
498 | { | ||
499 | struct lpfc_sli *psli; | ||
500 | struct lpfc_dmabuf *bmp; | ||
501 | struct lpfc_dmabuf *inp; | ||
502 | struct lpfc_dmabuf *outp; | ||
503 | IOCB_t *irsp; | ||
504 | struct lpfc_sli_ct_request *CTrsp; | ||
505 | |||
506 | psli = &phba->sli; | ||
507 | /* we pass cmdiocb to state machine which needs rspiocb as well */ | ||
508 | cmdiocb->context_un.rsp_iocb = rspiocb; | ||
509 | |||
510 | inp = (struct lpfc_dmabuf *) cmdiocb->context1; | ||
511 | outp = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
512 | bmp = (struct lpfc_dmabuf *) cmdiocb->context3; | ||
513 | irsp = &rspiocb->iocb; | ||
514 | |||
515 | CTrsp = (struct lpfc_sli_ct_request *) outp->virt; | ||
516 | |||
517 | /* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */ | ||
518 | lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||
519 | "%d:0209 RFT request completes ulpStatus x%x " | ||
520 | "CmdRsp x%x\n", phba->brd_no, irsp->ulpStatus, | ||
521 | CTrsp->CommandResponse.bits.CmdRsp); | ||
522 | |||
523 | lpfc_free_ct_rsp(phba, outp); | ||
524 | lpfc_mbuf_free(phba, inp->virt, inp->phys); | ||
525 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||
526 | kfree(inp); | ||
527 | kfree(bmp); | ||
528 | spin_lock_irq(phba->host->host_lock); | ||
529 | list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list); | ||
530 | spin_unlock_irq(phba->host->host_lock); | ||
531 | return; | ||
532 | } | ||
533 | |||
534 | static void | ||
535 | lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
536 | struct lpfc_iocbq * rspiocb) | ||
537 | { | ||
538 | lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); | ||
539 | return; | ||
540 | } | ||
541 | |||
542 | static void | ||
543 | lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
544 | struct lpfc_iocbq * rspiocb) | ||
545 | { | ||
546 | lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); | ||
547 | return; | ||
548 | } | ||
549 | |||
550 | void | ||
551 | lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp) | ||
552 | { | ||
553 | char fwrev[16]; | ||
554 | |||
555 | lpfc_decode_firmware_rev(phba, fwrev, 0); | ||
556 | |||
557 | if (phba->Port[0]) { | ||
558 | sprintf(symbp, "Emulex %s Port %s FV%s DV%s", phba->ModelName, | ||
559 | phba->Port, fwrev, lpfc_release_version); | ||
560 | } else { | ||
561 | sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName, | ||
562 | fwrev, lpfc_release_version); | ||
563 | } | ||
564 | } | ||
565 | |||
566 | /* | ||
567 | * lpfc_ns_cmd | ||
568 | * Description: | ||
569 | * Issue Cmd to NameServer | ||
570 | * SLI_CTNS_GID_FT | ||
571 | * LI_CTNS_RFT_ID | ||
572 | */ | ||
573 | int | ||
574 | lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode) | ||
575 | { | ||
576 | struct lpfc_dmabuf *mp, *bmp; | ||
577 | struct lpfc_sli_ct_request *CtReq; | ||
578 | struct ulp_bde64 *bpl; | ||
579 | void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, | ||
580 | struct lpfc_iocbq *) = NULL; | ||
581 | uint32_t rsp_size = 1024; | ||
582 | |||
583 | /* fill in BDEs for command */ | ||
584 | /* Allocate buffer for command payload */ | ||
585 | mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); | ||
586 | if (!mp) | ||
587 | goto ns_cmd_exit; | ||
588 | |||
589 | INIT_LIST_HEAD(&mp->list); | ||
590 | mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys)); | ||
591 | if (!mp->virt) | ||
592 | goto ns_cmd_free_mp; | ||
593 | |||
594 | /* Allocate buffer for Buffer ptr list */ | ||
595 | bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); | ||
596 | if (!bmp) | ||
597 | goto ns_cmd_free_mpvirt; | ||
598 | |||
599 | INIT_LIST_HEAD(&bmp->list); | ||
600 | bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(bmp->phys)); | ||
601 | if (!bmp->virt) | ||
602 | goto ns_cmd_free_bmp; | ||
603 | |||
604 | /* NameServer Req */ | ||
605 | lpfc_printf_log(phba, | ||
606 | KERN_INFO, | ||
607 | LOG_DISCOVERY, | ||
608 | "%d:0236 NameServer Req Data: x%x x%x x%x\n", | ||
609 | phba->brd_no, cmdcode, phba->fc_flag, | ||
610 | phba->fc_rscn_id_cnt); | ||
611 | |||
612 | bpl = (struct ulp_bde64 *) bmp->virt; | ||
613 | memset(bpl, 0, sizeof(struct ulp_bde64)); | ||
614 | bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) ); | ||
615 | bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) ); | ||
616 | bpl->tus.f.bdeFlags = 0; | ||
617 | if (cmdcode == SLI_CTNS_GID_FT) | ||
618 | bpl->tus.f.bdeSize = GID_REQUEST_SZ; | ||
619 | else if (cmdcode == SLI_CTNS_RFT_ID) | ||
620 | bpl->tus.f.bdeSize = RFT_REQUEST_SZ; | ||
621 | else if (cmdcode == SLI_CTNS_RNN_ID) | ||
622 | bpl->tus.f.bdeSize = RNN_REQUEST_SZ; | ||
623 | else if (cmdcode == SLI_CTNS_RSNN_NN) | ||
624 | bpl->tus.f.bdeSize = RSNN_REQUEST_SZ; | ||
625 | else | ||
626 | bpl->tus.f.bdeSize = 0; | ||
627 | bpl->tus.w = le32_to_cpu(bpl->tus.w); | ||
628 | |||
629 | CtReq = (struct lpfc_sli_ct_request *) mp->virt; | ||
630 | memset(CtReq, 0, sizeof (struct lpfc_sli_ct_request)); | ||
631 | CtReq->RevisionId.bits.Revision = SLI_CT_REVISION; | ||
632 | CtReq->RevisionId.bits.InId = 0; | ||
633 | CtReq->FsType = SLI_CT_DIRECTORY_SERVICE; | ||
634 | CtReq->FsSubType = SLI_CT_DIRECTORY_NAME_SERVER; | ||
635 | CtReq->CommandResponse.bits.Size = 0; | ||
636 | switch (cmdcode) { | ||
637 | case SLI_CTNS_GID_FT: | ||
638 | CtReq->CommandResponse.bits.CmdRsp = | ||
639 | be16_to_cpu(SLI_CTNS_GID_FT); | ||
640 | CtReq->un.gid.Fc4Type = SLI_CTPT_FCP; | ||
641 | if (phba->hba_state < LPFC_HBA_READY) | ||
642 | phba->hba_state = LPFC_NS_QRY; | ||
643 | lpfc_set_disctmo(phba); | ||
644 | cmpl = lpfc_cmpl_ct_cmd_gid_ft; | ||
645 | rsp_size = FC_MAX_NS_RSP; | ||
646 | break; | ||
647 | |||
648 | case SLI_CTNS_RFT_ID: | ||
649 | CtReq->CommandResponse.bits.CmdRsp = | ||
650 | be16_to_cpu(SLI_CTNS_RFT_ID); | ||
651 | CtReq->un.rft.PortId = be32_to_cpu(phba->fc_myDID); | ||
652 | CtReq->un.rft.fcpReg = 1; | ||
653 | cmpl = lpfc_cmpl_ct_cmd_rft_id; | ||
654 | break; | ||
655 | |||
656 | case SLI_CTNS_RNN_ID: | ||
657 | CtReq->CommandResponse.bits.CmdRsp = | ||
658 | be16_to_cpu(SLI_CTNS_RNN_ID); | ||
659 | CtReq->un.rnn.PortId = be32_to_cpu(phba->fc_myDID); | ||
660 | memcpy(CtReq->un.rnn.wwnn, &phba->fc_nodename, | ||
661 | sizeof (struct lpfc_name)); | ||
662 | cmpl = lpfc_cmpl_ct_cmd_rnn_id; | ||
663 | break; | ||
664 | |||
665 | case SLI_CTNS_RSNN_NN: | ||
666 | CtReq->CommandResponse.bits.CmdRsp = | ||
667 | be16_to_cpu(SLI_CTNS_RSNN_NN); | ||
668 | memcpy(CtReq->un.rsnn.wwnn, &phba->fc_nodename, | ||
669 | sizeof (struct lpfc_name)); | ||
670 | lpfc_get_hba_sym_node_name(phba, CtReq->un.rsnn.symbname); | ||
671 | CtReq->un.rsnn.len = strlen(CtReq->un.rsnn.symbname); | ||
672 | cmpl = lpfc_cmpl_ct_cmd_rsnn_nn; | ||
673 | break; | ||
674 | } | ||
675 | |||
676 | if (!lpfc_ct_cmd(phba, mp, bmp, ndlp, cmpl, rsp_size)) | ||
677 | /* On success, The cmpl function will free the buffers */ | ||
678 | return 0; | ||
679 | |||
680 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||
681 | ns_cmd_free_bmp: | ||
682 | kfree(bmp); | ||
683 | ns_cmd_free_mpvirt: | ||
684 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
685 | ns_cmd_free_mp: | ||
686 | kfree(mp); | ||
687 | ns_cmd_exit: | ||
688 | return 1; | ||
689 | } | ||
690 | |||
691 | static void | ||
692 | lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba, | ||
693 | struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb) | ||
694 | { | ||
695 | struct lpfc_dmabuf *bmp = cmdiocb->context3; | ||
696 | struct lpfc_dmabuf *inp = cmdiocb->context1; | ||
697 | struct lpfc_dmabuf *outp = cmdiocb->context2; | ||
698 | struct lpfc_sli_ct_request *CTrsp = outp->virt; | ||
699 | struct lpfc_sli_ct_request *CTcmd = inp->virt; | ||
700 | struct lpfc_nodelist *ndlp; | ||
701 | uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp; | ||
702 | uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp; | ||
703 | |||
704 | ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID); | ||
705 | if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { | ||
706 | /* FDMI rsp failed */ | ||
707 | lpfc_printf_log(phba, | ||
708 | KERN_INFO, | ||
709 | LOG_DISCOVERY, | ||
710 | "%d:0220 FDMI rsp failed Data: x%x\n", | ||
711 | phba->brd_no, | ||
712 | be16_to_cpu(fdmi_cmd)); | ||
713 | } | ||
714 | |||
715 | switch (be16_to_cpu(fdmi_cmd)) { | ||
716 | case SLI_MGMT_RHBA: | ||
717 | lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_RPA); | ||
718 | break; | ||
719 | |||
720 | case SLI_MGMT_RPA: | ||
721 | break; | ||
722 | |||
723 | case SLI_MGMT_DHBA: | ||
724 | lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DPRT); | ||
725 | break; | ||
726 | |||
727 | case SLI_MGMT_DPRT: | ||
728 | lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_RHBA); | ||
729 | break; | ||
730 | } | ||
731 | |||
732 | lpfc_free_ct_rsp(phba, outp); | ||
733 | lpfc_mbuf_free(phba, inp->virt, inp->phys); | ||
734 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||
735 | kfree(inp); | ||
736 | kfree(bmp); | ||
737 | spin_lock_irq(phba->host->host_lock); | ||
738 | list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list); | ||
739 | spin_unlock_irq(phba->host->host_lock); | ||
740 | return; | ||
741 | } | ||
742 | int | ||
743 | lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode) | ||
744 | { | ||
745 | struct lpfc_dmabuf *mp, *bmp; | ||
746 | struct lpfc_sli_ct_request *CtReq; | ||
747 | struct ulp_bde64 *bpl; | ||
748 | uint32_t size; | ||
749 | REG_HBA *rh; | ||
750 | PORT_ENTRY *pe; | ||
751 | REG_PORT_ATTRIBUTE *pab; | ||
752 | ATTRIBUTE_BLOCK *ab; | ||
753 | ATTRIBUTE_ENTRY *ae; | ||
754 | void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, | ||
755 | struct lpfc_iocbq *); | ||
756 | |||
757 | |||
758 | /* fill in BDEs for command */ | ||
759 | /* Allocate buffer for command payload */ | ||
760 | mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); | ||
761 | if (!mp) | ||
762 | goto fdmi_cmd_exit; | ||
763 | |||
764 | mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys)); | ||
765 | if (!mp->virt) | ||
766 | goto fdmi_cmd_free_mp; | ||
767 | |||
768 | /* Allocate buffer for Buffer ptr list */ | ||
769 | bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); | ||
770 | if (!bmp) | ||
771 | goto fdmi_cmd_free_mpvirt; | ||
772 | |||
773 | bmp->virt = lpfc_mbuf_alloc(phba, 0, &(bmp->phys)); | ||
774 | if (!bmp->virt) | ||
775 | goto fdmi_cmd_free_bmp; | ||
776 | |||
777 | INIT_LIST_HEAD(&mp->list); | ||
778 | INIT_LIST_HEAD(&bmp->list); | ||
779 | |||
780 | /* FDMI request */ | ||
781 | lpfc_printf_log(phba, | ||
782 | KERN_INFO, | ||
783 | LOG_DISCOVERY, | ||
784 | "%d:0218 FDMI Request Data: x%x x%x x%x\n", | ||
785 | phba->brd_no, | ||
786 | phba->fc_flag, phba->hba_state, cmdcode); | ||
787 | |||
788 | CtReq = (struct lpfc_sli_ct_request *) mp->virt; | ||
789 | |||
790 | memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request)); | ||
791 | CtReq->RevisionId.bits.Revision = SLI_CT_REVISION; | ||
792 | CtReq->RevisionId.bits.InId = 0; | ||
793 | |||
794 | CtReq->FsType = SLI_CT_MANAGEMENT_SERVICE; | ||
795 | CtReq->FsSubType = SLI_CT_FDMI_Subtypes; | ||
796 | size = 0; | ||
797 | |||
798 | switch (cmdcode) { | ||
799 | case SLI_MGMT_RHBA: | ||
800 | { | ||
801 | lpfc_vpd_t *vp = &phba->vpd; | ||
802 | uint32_t i, j, incr; | ||
803 | int len; | ||
804 | |||
805 | CtReq->CommandResponse.bits.CmdRsp = | ||
806 | be16_to_cpu(SLI_MGMT_RHBA); | ||
807 | CtReq->CommandResponse.bits.Size = 0; | ||
808 | rh = (REG_HBA *) & CtReq->un.PortID; | ||
809 | memcpy(&rh->hi.PortName, &phba->fc_sparam.portName, | ||
810 | sizeof (struct lpfc_name)); | ||
811 | /* One entry (port) per adapter */ | ||
812 | rh->rpl.EntryCnt = be32_to_cpu(1); | ||
813 | memcpy(&rh->rpl.pe, &phba->fc_sparam.portName, | ||
814 | sizeof (struct lpfc_name)); | ||
815 | |||
816 | /* point to the HBA attribute block */ | ||
817 | size = 2 * sizeof (struct lpfc_name) + FOURBYTES; | ||
818 | ab = (ATTRIBUTE_BLOCK *) ((uint8_t *) rh + size); | ||
819 | ab->EntryCnt = 0; | ||
820 | |||
821 | /* Point to the beginning of the first HBA attribute | ||
822 | entry */ | ||
823 | /* #1 HBA attribute entry */ | ||
824 | size += FOURBYTES; | ||
825 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
826 | ae->ad.bits.AttrType = be16_to_cpu(NODE_NAME); | ||
827 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES | ||
828 | + sizeof (struct lpfc_name)); | ||
829 | memcpy(&ae->un.NodeName, &phba->fc_sparam.nodeName, | ||
830 | sizeof (struct lpfc_name)); | ||
831 | ab->EntryCnt++; | ||
832 | size += FOURBYTES + sizeof (struct lpfc_name); | ||
833 | |||
834 | /* #2 HBA attribute entry */ | ||
835 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
836 | ae->ad.bits.AttrType = be16_to_cpu(MANUFACTURER); | ||
837 | strcpy(ae->un.Manufacturer, "Emulex Corporation"); | ||
838 | len = strlen(ae->un.Manufacturer); | ||
839 | len += (len & 3) ? (4 - (len & 3)) : 4; | ||
840 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); | ||
841 | ab->EntryCnt++; | ||
842 | size += FOURBYTES + len; | ||
843 | |||
844 | /* #3 HBA attribute entry */ | ||
845 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
846 | ae->ad.bits.AttrType = be16_to_cpu(SERIAL_NUMBER); | ||
847 | strcpy(ae->un.SerialNumber, phba->SerialNumber); | ||
848 | len = strlen(ae->un.SerialNumber); | ||
849 | len += (len & 3) ? (4 - (len & 3)) : 4; | ||
850 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); | ||
851 | ab->EntryCnt++; | ||
852 | size += FOURBYTES + len; | ||
853 | |||
854 | /* #4 HBA attribute entry */ | ||
855 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
856 | ae->ad.bits.AttrType = be16_to_cpu(MODEL); | ||
857 | strcpy(ae->un.Model, phba->ModelName); | ||
858 | len = strlen(ae->un.Model); | ||
859 | len += (len & 3) ? (4 - (len & 3)) : 4; | ||
860 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); | ||
861 | ab->EntryCnt++; | ||
862 | size += FOURBYTES + len; | ||
863 | |||
864 | /* #5 HBA attribute entry */ | ||
865 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
866 | ae->ad.bits.AttrType = be16_to_cpu(MODEL_DESCRIPTION); | ||
867 | strcpy(ae->un.ModelDescription, phba->ModelDesc); | ||
868 | len = strlen(ae->un.ModelDescription); | ||
869 | len += (len & 3) ? (4 - (len & 3)) : 4; | ||
870 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); | ||
871 | ab->EntryCnt++; | ||
872 | size += FOURBYTES + len; | ||
873 | |||
874 | /* #6 HBA attribute entry */ | ||
875 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
876 | ae->ad.bits.AttrType = be16_to_cpu(HARDWARE_VERSION); | ||
877 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 8); | ||
878 | /* Convert JEDEC ID to ascii for hardware version */ | ||
879 | incr = vp->rev.biuRev; | ||
880 | for (i = 0; i < 8; i++) { | ||
881 | j = (incr & 0xf); | ||
882 | if (j <= 9) | ||
883 | ae->un.HardwareVersion[7 - i] = | ||
884 | (char)((uint8_t) 0x30 + | ||
885 | (uint8_t) j); | ||
886 | else | ||
887 | ae->un.HardwareVersion[7 - i] = | ||
888 | (char)((uint8_t) 0x61 + | ||
889 | (uint8_t) (j - 10)); | ||
890 | incr = (incr >> 4); | ||
891 | } | ||
892 | ab->EntryCnt++; | ||
893 | size += FOURBYTES + 8; | ||
894 | |||
895 | /* #7 HBA attribute entry */ | ||
896 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
897 | ae->ad.bits.AttrType = be16_to_cpu(DRIVER_VERSION); | ||
898 | strcpy(ae->un.DriverVersion, lpfc_release_version); | ||
899 | len = strlen(ae->un.DriverVersion); | ||
900 | len += (len & 3) ? (4 - (len & 3)) : 4; | ||
901 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); | ||
902 | ab->EntryCnt++; | ||
903 | size += FOURBYTES + len; | ||
904 | |||
905 | /* #8 HBA attribute entry */ | ||
906 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
907 | ae->ad.bits.AttrType = be16_to_cpu(OPTION_ROM_VERSION); | ||
908 | strcpy(ae->un.OptionROMVersion, phba->OptionROMVersion); | ||
909 | len = strlen(ae->un.OptionROMVersion); | ||
910 | len += (len & 3) ? (4 - (len & 3)) : 4; | ||
911 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); | ||
912 | ab->EntryCnt++; | ||
913 | size += FOURBYTES + len; | ||
914 | |||
915 | /* #9 HBA attribute entry */ | ||
916 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
917 | ae->ad.bits.AttrType = be16_to_cpu(FIRMWARE_VERSION); | ||
918 | lpfc_decode_firmware_rev(phba, ae->un.FirmwareVersion, | ||
919 | 1); | ||
920 | len = strlen(ae->un.FirmwareVersion); | ||
921 | len += (len & 3) ? (4 - (len & 3)) : 4; | ||
922 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); | ||
923 | ab->EntryCnt++; | ||
924 | size += FOURBYTES + len; | ||
925 | |||
926 | /* #10 HBA attribute entry */ | ||
927 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
928 | ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION); | ||
929 | sprintf(ae->un.OsNameVersion, "%s %s %s", | ||
930 | system_utsname.sysname, system_utsname.release, | ||
931 | system_utsname.version); | ||
932 | len = strlen(ae->un.OsNameVersion); | ||
933 | len += (len & 3) ? (4 - (len & 3)) : 4; | ||
934 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); | ||
935 | ab->EntryCnt++; | ||
936 | size += FOURBYTES + len; | ||
937 | |||
938 | /* #11 HBA attribute entry */ | ||
939 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); | ||
940 | ae->ad.bits.AttrType = be16_to_cpu(MAX_CT_PAYLOAD_LEN); | ||
941 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); | ||
942 | ae->un.MaxCTPayloadLen = (65 * 4096); | ||
943 | ab->EntryCnt++; | ||
944 | size += FOURBYTES + 4; | ||
945 | |||
946 | ab->EntryCnt = be32_to_cpu(ab->EntryCnt); | ||
947 | /* Total size */ | ||
948 | size = GID_REQUEST_SZ - 4 + size; | ||
949 | } | ||
950 | break; | ||
951 | |||
952 | case SLI_MGMT_RPA: | ||
953 | { | ||
954 | lpfc_vpd_t *vp; | ||
955 | struct serv_parm *hsp; | ||
956 | int len; | ||
957 | |||
958 | vp = &phba->vpd; | ||
959 | |||
960 | CtReq->CommandResponse.bits.CmdRsp = | ||
961 | be16_to_cpu(SLI_MGMT_RPA); | ||
962 | CtReq->CommandResponse.bits.Size = 0; | ||
963 | pab = (REG_PORT_ATTRIBUTE *) & CtReq->un.PortID; | ||
964 | size = sizeof (struct lpfc_name) + FOURBYTES; | ||
965 | memcpy((uint8_t *) & pab->PortName, | ||
966 | (uint8_t *) & phba->fc_sparam.portName, | ||
967 | sizeof (struct lpfc_name)); | ||
968 | pab->ab.EntryCnt = 0; | ||
969 | |||
970 | /* #1 Port attribute entry */ | ||
971 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); | ||
972 | ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_FC4_TYPES); | ||
973 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 32); | ||
974 | ae->un.SupportFC4Types[2] = 1; | ||
975 | ae->un.SupportFC4Types[7] = 1; | ||
976 | pab->ab.EntryCnt++; | ||
977 | size += FOURBYTES + 32; | ||
978 | |||
979 | /* #2 Port attribute entry */ | ||
980 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); | ||
981 | ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_SPEED); | ||
982 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); | ||
983 | if (FC_JEDEC_ID(vp->rev.biuRev) == VIPER_JEDEC_ID) | ||
984 | ae->un.SupportSpeed = HBA_PORTSPEED_10GBIT; | ||
985 | else if (FC_JEDEC_ID(vp->rev.biuRev) == HELIOS_JEDEC_ID) | ||
986 | ae->un.SupportSpeed = HBA_PORTSPEED_4GBIT; | ||
987 | else if ((FC_JEDEC_ID(vp->rev.biuRev) == | ||
988 | CENTAUR_2G_JEDEC_ID) | ||
989 | || (FC_JEDEC_ID(vp->rev.biuRev) == | ||
990 | PEGASUS_JEDEC_ID) | ||
991 | || (FC_JEDEC_ID(vp->rev.biuRev) == | ||
992 | THOR_JEDEC_ID)) | ||
993 | ae->un.SupportSpeed = HBA_PORTSPEED_2GBIT; | ||
994 | else | ||
995 | ae->un.SupportSpeed = HBA_PORTSPEED_1GBIT; | ||
996 | pab->ab.EntryCnt++; | ||
997 | size += FOURBYTES + 4; | ||
998 | |||
999 | /* #3 Port attribute entry */ | ||
1000 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); | ||
1001 | ae->ad.bits.AttrType = be16_to_cpu(PORT_SPEED); | ||
1002 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); | ||
1003 | switch(phba->fc_linkspeed) { | ||
1004 | case LA_1GHZ_LINK: | ||
1005 | ae->un.PortSpeed = HBA_PORTSPEED_1GBIT; | ||
1006 | break; | ||
1007 | case LA_2GHZ_LINK: | ||
1008 | ae->un.PortSpeed = HBA_PORTSPEED_2GBIT; | ||
1009 | break; | ||
1010 | case LA_4GHZ_LINK: | ||
1011 | ae->un.PortSpeed = HBA_PORTSPEED_4GBIT; | ||
1012 | break; | ||
1013 | default: | ||
1014 | ae->un.PortSpeed = | ||
1015 | HBA_PORTSPEED_UNKNOWN; | ||
1016 | break; | ||
1017 | } | ||
1018 | pab->ab.EntryCnt++; | ||
1019 | size += FOURBYTES + 4; | ||
1020 | |||
1021 | /* #4 Port attribute entry */ | ||
1022 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); | ||
1023 | ae->ad.bits.AttrType = be16_to_cpu(MAX_FRAME_SIZE); | ||
1024 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); | ||
1025 | hsp = (struct serv_parm *) & phba->fc_sparam; | ||
1026 | ae->un.MaxFrameSize = | ||
1027 | (((uint32_t) hsp->cmn. | ||
1028 | bbRcvSizeMsb) << 8) | (uint32_t) hsp->cmn. | ||
1029 | bbRcvSizeLsb; | ||
1030 | pab->ab.EntryCnt++; | ||
1031 | size += FOURBYTES + 4; | ||
1032 | |||
1033 | /* #5 Port attribute entry */ | ||
1034 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); | ||
1035 | ae->ad.bits.AttrType = be16_to_cpu(OS_DEVICE_NAME); | ||
1036 | strcpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME); | ||
1037 | len = strlen((char *)ae->un.OsDeviceName); | ||
1038 | len += (len & 3) ? (4 - (len & 3)) : 4; | ||
1039 | ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); | ||
1040 | pab->ab.EntryCnt++; | ||
1041 | size += FOURBYTES + len; | ||
1042 | |||
1043 | if (phba->cfg_fdmi_on == 2) { | ||
1044 | /* #6 Port attribute entry */ | ||
1045 | ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + | ||
1046 | size); | ||
1047 | ae->ad.bits.AttrType = be16_to_cpu(HOST_NAME); | ||
1048 | sprintf(ae->un.HostName, "%s", | ||
1049 | system_utsname.nodename); | ||
1050 | len = strlen(ae->un.HostName); | ||
1051 | len += (len & 3) ? (4 - (len & 3)) : 4; | ||
1052 | ae->ad.bits.AttrLen = | ||
1053 | be16_to_cpu(FOURBYTES + len); | ||
1054 | pab->ab.EntryCnt++; | ||
1055 | size += FOURBYTES + len; | ||
1056 | } | ||
1057 | |||
1058 | pab->ab.EntryCnt = be32_to_cpu(pab->ab.EntryCnt); | ||
1059 | /* Total size */ | ||
1060 | size = GID_REQUEST_SZ - 4 + size; | ||
1061 | } | ||
1062 | break; | ||
1063 | |||
1064 | case SLI_MGMT_DHBA: | ||
1065 | CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_MGMT_DHBA); | ||
1066 | CtReq->CommandResponse.bits.Size = 0; | ||
1067 | pe = (PORT_ENTRY *) & CtReq->un.PortID; | ||
1068 | memcpy((uint8_t *) & pe->PortName, | ||
1069 | (uint8_t *) & phba->fc_sparam.portName, | ||
1070 | sizeof (struct lpfc_name)); | ||
1071 | size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name); | ||
1072 | break; | ||
1073 | |||
1074 | case SLI_MGMT_DPRT: | ||
1075 | CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_MGMT_DPRT); | ||
1076 | CtReq->CommandResponse.bits.Size = 0; | ||
1077 | pe = (PORT_ENTRY *) & CtReq->un.PortID; | ||
1078 | memcpy((uint8_t *) & pe->PortName, | ||
1079 | (uint8_t *) & phba->fc_sparam.portName, | ||
1080 | sizeof (struct lpfc_name)); | ||
1081 | size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name); | ||
1082 | break; | ||
1083 | } | ||
1084 | |||
1085 | bpl = (struct ulp_bde64 *) bmp->virt; | ||
1086 | bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) ); | ||
1087 | bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) ); | ||
1088 | bpl->tus.f.bdeFlags = 0; | ||
1089 | bpl->tus.f.bdeSize = size; | ||
1090 | bpl->tus.w = le32_to_cpu(bpl->tus.w); | ||
1091 | |||
1092 | cmpl = lpfc_cmpl_ct_cmd_fdmi; | ||
1093 | |||
1094 | if (!lpfc_ct_cmd(phba, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP)) | ||
1095 | return 0; | ||
1096 | |||
1097 | lpfc_mbuf_free(phba, bmp->virt, bmp->phys); | ||
1098 | fdmi_cmd_free_bmp: | ||
1099 | kfree(bmp); | ||
1100 | fdmi_cmd_free_mpvirt: | ||
1101 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
1102 | fdmi_cmd_free_mp: | ||
1103 | kfree(mp); | ||
1104 | fdmi_cmd_exit: | ||
1105 | /* Issue FDMI request failed */ | ||
1106 | lpfc_printf_log(phba, | ||
1107 | KERN_INFO, | ||
1108 | LOG_DISCOVERY, | ||
1109 | "%d:0244 Issue FDMI request failed Data: x%x\n", | ||
1110 | phba->brd_no, | ||
1111 | cmdcode); | ||
1112 | return 1; | ||
1113 | } | ||
1114 | |||
1115 | void | ||
1116 | lpfc_fdmi_tmo(unsigned long ptr) | ||
1117 | { | ||
1118 | struct lpfc_hba *phba = (struct lpfc_hba *)ptr; | ||
1119 | unsigned long iflag; | ||
1120 | |||
1121 | spin_lock_irqsave(phba->host->host_lock, iflag); | ||
1122 | if (!(phba->work_hba_events & WORKER_FDMI_TMO)) { | ||
1123 | phba->work_hba_events |= WORKER_FDMI_TMO; | ||
1124 | if (phba->work_wait) | ||
1125 | wake_up(phba->work_wait); | ||
1126 | } | ||
1127 | spin_unlock_irqrestore(phba->host->host_lock,iflag); | ||
1128 | } | ||
1129 | |||
1130 | void | ||
1131 | lpfc_fdmi_tmo_handler(struct lpfc_hba *phba) | ||
1132 | { | ||
1133 | struct lpfc_nodelist *ndlp; | ||
1134 | |||
1135 | spin_lock_irq(phba->host->host_lock); | ||
1136 | if (!(phba->work_hba_events & WORKER_FDMI_TMO)) { | ||
1137 | spin_unlock_irq(phba->host->host_lock); | ||
1138 | return; | ||
1139 | } | ||
1140 | ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID); | ||
1141 | if (ndlp) { | ||
1142 | if (system_utsname.nodename[0] != '\0') { | ||
1143 | lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA); | ||
1144 | } else { | ||
1145 | mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60); | ||
1146 | } | ||
1147 | } | ||
1148 | spin_unlock_irq(phba->host->host_lock); | ||
1149 | return; | ||
1150 | } | ||
1151 | |||
1152 | |||
1153 | void | ||
1154 | lpfc_decode_firmware_rev(struct lpfc_hba * phba, char *fwrevision, int flag) | ||
1155 | { | ||
1156 | struct lpfc_sli *psli = &phba->sli; | ||
1157 | lpfc_vpd_t *vp = &phba->vpd; | ||
1158 | uint32_t b1, b2, b3, b4, i, rev; | ||
1159 | char c; | ||
1160 | uint32_t *ptr, str[4]; | ||
1161 | uint8_t *fwname; | ||
1162 | |||
1163 | if (vp->rev.rBit) { | ||
1164 | if (psli->sli_flag & LPFC_SLI2_ACTIVE) | ||
1165 | rev = vp->rev.sli2FwRev; | ||
1166 | else | ||
1167 | rev = vp->rev.sli1FwRev; | ||
1168 | |||
1169 | b1 = (rev & 0x0000f000) >> 12; | ||
1170 | b2 = (rev & 0x00000f00) >> 8; | ||
1171 | b3 = (rev & 0x000000c0) >> 6; | ||
1172 | b4 = (rev & 0x00000030) >> 4; | ||
1173 | |||
1174 | switch (b4) { | ||
1175 | case 0: | ||
1176 | c = 'N'; | ||
1177 | break; | ||
1178 | case 1: | ||
1179 | c = 'A'; | ||
1180 | break; | ||
1181 | case 2: | ||
1182 | c = 'B'; | ||
1183 | break; | ||
1184 | default: | ||
1185 | c = 0; | ||
1186 | break; | ||
1187 | } | ||
1188 | b4 = (rev & 0x0000000f); | ||
1189 | |||
1190 | if (psli->sli_flag & LPFC_SLI2_ACTIVE) | ||
1191 | fwname = vp->rev.sli2FwName; | ||
1192 | else | ||
1193 | fwname = vp->rev.sli1FwName; | ||
1194 | |||
1195 | for (i = 0; i < 16; i++) | ||
1196 | if (fwname[i] == 0x20) | ||
1197 | fwname[i] = 0; | ||
1198 | |||
1199 | ptr = (uint32_t*)fwname; | ||
1200 | |||
1201 | for (i = 0; i < 3; i++) | ||
1202 | str[i] = be32_to_cpu(*ptr++); | ||
1203 | |||
1204 | if (c == 0) { | ||
1205 | if (flag) | ||
1206 | sprintf(fwrevision, "%d.%d%d (%s)", | ||
1207 | b1, b2, b3, (char *)str); | ||
1208 | else | ||
1209 | sprintf(fwrevision, "%d.%d%d", b1, | ||
1210 | b2, b3); | ||
1211 | } else { | ||
1212 | if (flag) | ||
1213 | sprintf(fwrevision, "%d.%d%d%c%d (%s)", | ||
1214 | b1, b2, b3, c, | ||
1215 | b4, (char *)str); | ||
1216 | else | ||
1217 | sprintf(fwrevision, "%d.%d%d%c%d", | ||
1218 | b1, b2, b3, c, b4); | ||
1219 | } | ||
1220 | } else { | ||
1221 | rev = vp->rev.smFwRev; | ||
1222 | |||
1223 | b1 = (rev & 0xff000000) >> 24; | ||
1224 | b2 = (rev & 0x00f00000) >> 20; | ||
1225 | b3 = (rev & 0x000f0000) >> 16; | ||
1226 | c = (rev & 0x0000ff00) >> 8; | ||
1227 | b4 = (rev & 0x000000ff); | ||
1228 | |||
1229 | if (flag) | ||
1230 | sprintf(fwrevision, "%d.%d%d%c%d ", b1, | ||
1231 | b2, b3, c, b4); | ||
1232 | else | ||
1233 | sprintf(fwrevision, "%d.%d%d%c%d ", b1, | ||
1234 | b2, b3, c, b4); | ||
1235 | } | ||
1236 | return; | ||
1237 | } | ||