1890 Updated emlxs driver from Emulex
[unleashed.git] / usr / src / uts / common / io / fibre-channel / fca / emlxs / emlxs_diag.c
blobea4f08112ae452f68c030769790e79c55fb5e9ad
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2010 Emulex. All rights reserved.
24 * Use is subject to license terms.
28 #include <emlxs.h>
31 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
32 EMLXS_MSG_DEF(EMLXS_DIAG_C);
34 uint32_t emlxs_diag_pattern[256] = {
35 /* Walking ones */
36 0x80000000, 0x40000000, 0x20000000, 0x10000000,
37 0x08000000, 0x04000000, 0x02000000, 0x01000000,
38 0x00800000, 0x00400000, 0x00200000, 0x00100000,
39 0x00080000, 0x00040000, 0x00020000, 0x00010000,
40 0x00008000, 0x00004000, 0x00002000, 0x00001000,
41 0x00000800, 0x00000400, 0x00000200, 0x00000100,
42 0x00000080, 0x00000040, 0x00000020, 0x00000010,
43 0x00000008, 0x00000004, 0x00000002, 0x00000001,
45 /* Walking zeros */
46 0x7fffffff, 0xbfffffff, 0xdfffffff, 0xefffffff,
47 0xf7ffffff, 0xfbffffff, 0xfdffffff, 0xfeffffff,
48 0xff7fffff, 0xffbfffff, 0xffdfffff, 0xffefffff,
49 0xfff7ffff, 0xfffbffff, 0xfffdffff, 0xfffeffff,
50 0xffff7fff, 0xffffbfff, 0xffffdfff, 0xffffefff,
51 0xfffff7ff, 0xfffffbff, 0xfffffdff, 0xfffffeff,
52 0xffffff7f, 0xffffffbf, 0xffffffdf, 0xffffffef,
53 0xfffffff7, 0xfffffffb, 0xfffffffd, 0xfffffffe,
55 /* all zeros */
56 0x00000000, 0x00000000, 0x00000000, 0x00000000,
57 0x00000000, 0x00000000, 0x00000000, 0x00000000,
58 0x00000000, 0x00000000, 0x00000000, 0x00000000,
59 0x00000000, 0x00000000, 0x00000000, 0x00000000,
60 0x00000000, 0x00000000, 0x00000000, 0x00000000,
61 0x00000000, 0x00000000, 0x00000000, 0x00000000,
62 0x00000000, 0x00000000, 0x00000000, 0x00000000,
63 0x00000000, 0x00000000, 0x00000000, 0x00000000,
65 /* all ones */
66 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
67 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
68 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
69 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
70 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
71 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
72 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
73 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
75 /* all 5's */
76 0x55555555, 0x55555555, 0x55555555, 0x55555555,
77 0x55555555, 0x55555555, 0x55555555, 0x55555555,
78 0x55555555, 0x55555555, 0x55555555, 0x55555555,
79 0x55555555, 0x55555555, 0x55555555, 0x55555555,
80 0x55555555, 0x55555555, 0x55555555, 0x55555555,
81 0x55555555, 0x55555555, 0x55555555, 0x55555555,
82 0x55555555, 0x55555555, 0x55555555, 0x55555555,
83 0x55555555, 0x55555555, 0x55555555, 0x55555555,
85 /* all a's */
86 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
87 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
88 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
89 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
90 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
91 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
92 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
93 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
95 /* all 5a's */
96 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
97 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
98 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
99 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
100 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
101 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
102 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
103 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
105 /* all a5's */
106 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5,
107 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5,
108 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5,
109 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5,
110 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5,
111 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5,
112 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5,
113 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5
117 /* Default pkt callback routine */
118 static void
119 emlxs_diag_pkt_callback(fc_packet_t *pkt)
121 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
123 /* Set the completed flag and wake up sleeping threads */
124 mutex_enter(&EMLXS_PKT_LOCK);
125 pkt->pkt_tran_flags |= FC_TRAN_COMPLETED;
126 cv_broadcast(&EMLXS_PKT_CV);
127 mutex_exit(&EMLXS_PKT_LOCK);
129 return;
131 } /* emlxs_diag_pkt_callback() */
134 extern uint32_t
135 emlxs_diag_echo_run(emlxs_port_t *port, uint32_t did, uint32_t pattern)
137 emlxs_hba_t *hba = HBA;
138 uint32_t i = 0;
139 uint32_t rval = FC_SUCCESS;
140 int32_t pkt_ret;
141 fc_packet_t *pkt;
142 ELS_PKT *els;
143 clock_t timeout;
144 uint8_t *pkt_resp;
145 char *pattern_buffer;
146 uint32_t length;
147 uint32_t *lptr;
148 NODELIST *ndlp;
149 uint8_t *pat;
151 /* Check did */
152 if (did == 0) {
153 did = port->did;
156 /* Check if device is ready */
157 if ((hba->state < FC_LINK_UP) || (port->did == 0)) {
158 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
159 "ECHO: HBA not ready.");
161 return (FC_TRAN_BUSY);
164 /* Check for the host node */
165 ndlp = emlxs_node_find_did(port, port->did);
167 if (!ndlp || !ndlp->nlp_active) {
168 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
169 "ECHO: HBA not ready.");
171 return (FC_TRAN_BUSY);
174 length = 124;
176 /* Prepare ECHO pkt */
177 if (!(pkt = emlxs_pkt_alloc(port, sizeof (uint32_t) + length,
178 sizeof (uint32_t) + length, 0, KM_NOSLEEP))) {
179 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
180 "ECHO: Unable to allocate packet. size=%x",
181 sizeof (uint32_t) + length);
183 return (FC_NOMEM);
186 /* pkt initialization */
187 pkt->pkt_tran_type = FC_PKT_EXCHANGE;
188 pkt->pkt_timeout = 60;
190 /* Build the fc header */
191 pkt->pkt_cmd_fhdr.d_id = did;
192 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | R_CTL_UNSOL_CONTROL;
193 pkt->pkt_cmd_fhdr.s_id = port->did;
194 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
195 pkt->pkt_cmd_fhdr.f_ctl =
196 F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE | F_CTL_END_SEQ;
197 pkt->pkt_cmd_fhdr.seq_id = 0;
198 pkt->pkt_cmd_fhdr.df_ctl = 0;
199 pkt->pkt_cmd_fhdr.seq_cnt = 0;
200 pkt->pkt_cmd_fhdr.ox_id = 0xffff;
201 pkt->pkt_cmd_fhdr.rx_id = 0xffff;
202 pkt->pkt_cmd_fhdr.ro = 0;
203 pkt->pkt_comp = emlxs_diag_pkt_callback;
205 /* Build the command */
206 els = (ELS_PKT *) pkt->pkt_cmd;
207 els->elsCode = 0x10;
208 pattern_buffer = (char *)els->un.pad;
210 if (pattern) {
211 /* Fill the transmit buffer with the pattern */
212 lptr = (uint32_t *)pattern_buffer;
214 for (i = 0; i < length; i += 4) {
215 *lptr++ = pattern;
217 } else {
218 /* Program the default echo pattern */
219 bzero(pattern_buffer, length);
220 (void) sprintf(pattern_buffer, "Emulex. We network storage. "
221 "Emulex. We network storage. Emulex. We network storage. "
222 "Emulex. We network storage.");
225 /* Send ECHO pkt */
226 if ((rval = emlxs_pkt_send(pkt, 1)) != FC_SUCCESS) {
227 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
228 "ECHO: Packet send failed.");
230 goto done;
233 /* Wait for ECHO completion */
234 mutex_enter(&EMLXS_PKT_LOCK);
235 timeout = emlxs_timeout(hba, (pkt->pkt_timeout + 15));
236 pkt_ret = 0;
237 while ((pkt_ret != -1) && !(pkt->pkt_tran_flags & FC_TRAN_COMPLETED)) {
238 pkt_ret =
239 cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK, timeout);
242 mutex_exit(&EMLXS_PKT_LOCK);
244 if (pkt_ret == -1) {
245 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg,
246 "Packet timed out.");
248 return (FC_ABORTED);
251 if (pkt->pkt_state != FC_PKT_SUCCESS) {
252 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg,
253 "Transport error.");
255 rval = FC_TRANSPORT_ERROR;
256 goto done;
259 /* Check response payload */
260 pkt_resp = (uint8_t *)pkt->pkt_resp + 4;
261 pat = (uint8_t *)pattern_buffer;
262 rval = FC_SUCCESS;
264 for (i = 0; i < length; i++, pkt_resp++, pat++) {
265 if (*pkt_resp != *pat) {
266 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg,
267 "Data miscompare. did=%06x length=%d. Offset %d "
268 "value %02x should be %02x.", did, length, i,
269 *pkt_resp, *pat);
271 rval = EMLXS_TEST_FAILED;
273 break;
277 if (rval == FC_SUCCESS) {
278 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_complete_msg,
279 "did=%06x length=%d pattern=%02x,%02x,%02x,%02x...",
280 did, length, pattern_buffer[0] & 0xff,
281 pattern_buffer[1] & 0xff, pattern_buffer[2] & 0xff,
282 pattern_buffer[3] & 0xff);
285 done:
287 /* Free the echo pkt */
288 emlxs_pkt_free(pkt);
290 return (rval);
292 } /* emlxs_diag_echo_run() */
295 extern uint32_t
296 emlxs_diag_biu_run(emlxs_hba_t *hba, uint32_t pattern)
298 emlxs_port_t *port = &PPORT;
299 MAILBOXQ *mbq;
300 MATCHMAP *mp;
301 MATCHMAP *mp1;
302 uint32_t i;
303 uint8_t *inptr;
304 uint8_t *outptr;
305 int32_t rval = FC_SUCCESS;
306 uint32_t *lptr;
308 mp1 = 0;
309 mbq = 0;
311 /* Check if device is ready */
312 if (hba->state < FC_LINK_DOWN) {
313 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
314 "BIU: HBA not ready.");
316 return (FC_TRAN_BUSY);
320 * Get a buffer which will be used for the mailbox command
322 if ((mbq = (MAILBOXQ *) emlxs_mem_get(hba, MEM_MBOX, 1)) == 0) {
323 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
324 "BIU: Mailbox allocation failed.");
326 rval = FC_NOMEM;
327 goto done;
331 * Setup and issue mailbox RUN BIU DIAG command Setup test buffers
333 if (((mp = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF, 1)) == 0) ||
334 ((mp1 = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF, 1)) == 0)) {
335 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
336 "BIU: Buffer allocation failed.");
338 rval = FC_NOMEM;
339 goto done;
342 if (pattern) {
343 /* Fill the transmit buffer with the pattern */
344 lptr = (uint32_t *)mp->virt;
346 for (i = 0; i < MEM_ELSBUF_SIZE; i += 4) {
347 *lptr++ = pattern;
349 } else {
350 /* Copy the default pattern into the trasmit buffer */
351 bcopy((caddr_t)&emlxs_diag_pattern[0], (caddr_t)mp->virt,
352 MEM_ELSBUF_SIZE);
354 EMLXS_MPDATA_SYNC(mp->dma_handle, 0, MEM_ELSBUF_SIZE,
355 DDI_DMA_SYNC_FORDEV);
357 bzero(mp1->virt, MEM_ELSBUF_SIZE);
358 EMLXS_MPDATA_SYNC(mp1->dma_handle, 0, MEM_ELSBUF_SIZE,
359 DDI_DMA_SYNC_FORDEV);
361 /* Create the biu diag request */
362 (void) emlxs_mb_run_biu_diag(hba, mbq, mp->phys, mp1->phys);
364 rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 60);
366 if (rval == MBX_TIMEOUT) {
367 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg,
368 "BUI diagnostic timed out.");
370 rval = EMLXS_TEST_FAILED;
371 goto done;
374 EMLXS_MPDATA_SYNC(mp1->dma_handle, 0, MEM_ELSBUF_SIZE,
375 DDI_DMA_SYNC_FORKERNEL);
377 outptr = mp->virt;
378 inptr = mp1->virt;
380 for (i = 0; i < MEM_ELSBUF_SIZE; i++, outptr++, inptr++) {
381 if (*outptr != *inptr) {
382 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg,
383 "Data miscompare. Offset %d value %02x should "
384 "be %02x.", i, *inptr, *outptr);
386 rval = EMLXS_TEST_FAILED;
387 goto done;
391 /* Wait half second before returning */
392 delay(drv_usectohz(500000));
393 rval = FC_SUCCESS;
395 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_complete_msg, "Status Good.");
397 done:
399 if (mp) {
400 #ifdef FMA_SUPPORT
401 if (emlxs_fm_check_dma_handle(hba, mp->dma_handle)
402 != DDI_FM_OK) {
403 EMLXS_MSGF(EMLXS_CONTEXT,
404 &emlxs_invalid_dma_handle_msg,
405 "emlxs_diag_biu_run: hdl=%p",
406 mp->dma_handle);
407 rval = EMLXS_TEST_FAILED;
409 #endif /* FMA_SUPPORT */
410 emlxs_mem_put(hba, MEM_BUF, (void *)mp);
412 if (mp1) {
413 #ifdef FMA_SUPPORT
414 if (emlxs_fm_check_dma_handle(hba, mp1->dma_handle)
415 != DDI_FM_OK) {
416 EMLXS_MSGF(EMLXS_CONTEXT,
417 &emlxs_invalid_dma_handle_msg,
418 "emlxs_diag_biu_run: hdl=%p",
419 mp1->dma_handle);
420 rval = EMLXS_TEST_FAILED;
422 #endif /* FMA_SUPPORT */
423 emlxs_mem_put(hba, MEM_BUF, (void *)mp1);
425 if (mbq) {
426 emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
429 return (rval);
431 } /* emlxs_diag_biu_run() */
434 extern uint32_t
435 emlxs_diag_post_run(emlxs_hba_t *hba)
437 emlxs_port_t *port = &PPORT;
438 uint32_t rval = FC_SUCCESS;
440 if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
441 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
442 "POST: HBA shutdown.");
444 return (FC_TRAN_BUSY);
447 /* Take board offline */
448 if ((rval = emlxs_offline(hba))) {
449 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg,
450 "Unable to take adapter offline.");
452 rval = FC_RESETFAIL;
455 /* Restart the adapter */
456 rval = EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
458 switch (rval) {
459 case 0:
461 (void) emlxs_online(hba);
463 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_complete_msg,
464 "Status good.");
466 rval = FC_SUCCESS;
468 break;
470 case 1: /* failed */
472 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg,
473 "HBA reset failed.");
475 rval = FC_RESETFAIL;
477 break;
480 case 2: /* failed */
482 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
483 "HBA busy. Quiece and retry.");
485 rval = FC_STATEC_BUSY;
487 break;
491 return (rval);
493 } /* emlxs_diag_post_run() */