1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Emulex.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <emlxs.h>
29 
30 
31 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
32 EMLXS_MSG_DEF(EMLXS_DIAG_C);
33 
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,
44 
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,
54 
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,
64 
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,
74 
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,
84 
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,
94 
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,
104 
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
114 };
115 
116 
117 /* Default pkt callback routine */
118 static void
119 emlxs_diag_pkt_callback(fc_packet_t *pkt)
120 {
121 	emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
122 
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);
128 
129 	return;
130 
131 } /* emlxs_diag_pkt_callback() */
132 
133 
134 extern uint32_t
135 emlxs_diag_echo_run(emlxs_port_t *port, uint32_t did, uint32_t pattern)
136 {
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;
150 
151 	/* Check did */
152 	if (did == 0) {
153 		did = port->did;
154 	}
155 
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.");
160 
161 		return (FC_TRAN_BUSY);
162 	}
163 
164 	/* Check for the host node */
165 	ndlp = emlxs_node_find_did(port, port->did);
166 
167 	if (!ndlp || !ndlp->nlp_active) {
168 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
169 		    "ECHO: HBA not ready.");
170 
171 		return (FC_TRAN_BUSY);
172 	}
173 
174 	length = 124;
175 
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);
182 
183 		return (FC_NOMEM);
184 	}
185 
186 	/* pkt initialization */
187 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
188 	pkt->pkt_timeout = 60;
189 
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;
204 
205 	/* Build the command */
206 	els = (ELS_PKT *) pkt->pkt_cmd;
207 	els->elsCode = 0x10;
208 	pattern_buffer = (char *)els->un.pad;
209 
210 	if (pattern) {
211 		/* Fill the transmit buffer with the pattern */
212 		lptr = (uint32_t *)pattern_buffer;
213 
214 		for (i = 0; i < length; i += 4) {
215 			*lptr++ = pattern;
216 		}
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.");
223 	}
224 
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.");
229 
230 		goto done;
231 	}
232 
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);
240 
241 	}
242 	mutex_exit(&EMLXS_PKT_LOCK);
243 
244 	if (pkt_ret == -1) {
245 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg,
246 		    "Packet timed out.");
247 
248 		return (FC_ABORTED);
249 	}
250 
251 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
252 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg,
253 		    "Transport error.");
254 
255 		rval = FC_TRANSPORT_ERROR;
256 		goto done;
257 	}
258 
259 	/* Check response payload */
260 	pkt_resp = (uint8_t *)pkt->pkt_resp + 4;
261 	pat = (uint8_t *)pattern_buffer;
262 	rval = FC_SUCCESS;
263 
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);
270 
271 			rval = EMLXS_TEST_FAILED;
272 
273 			break;
274 		}
275 	}
276 
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);
283 	}
284 
285 done:
286 
287 	/* Free the echo pkt */
288 	emlxs_pkt_free(pkt);
289 
290 	return (rval);
291 
292 } /* emlxs_diag_echo_run() */
293 
294 
295 extern uint32_t
296 emlxs_diag_biu_run(emlxs_hba_t *hba, uint32_t pattern)
297 {
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;
307 
308 	mp1 = 0;
309 	mbq = 0;
310 
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.");
315 
316 		return (FC_TRAN_BUSY);
317 	}
318 
319 	/*
320 	 * Get a buffer which will be used for the mailbox command
321 	 */
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.");
325 
326 		rval = FC_NOMEM;
327 		goto done;
328 	}
329 
330 	/*
331 	 * Setup and issue mailbox RUN BIU DIAG command Setup test buffers
332 	 */
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.");
337 
338 		rval = FC_NOMEM;
339 		goto done;
340 	}
341 
342 	if (pattern) {
343 		/* Fill the transmit buffer with the pattern */
344 		lptr = (uint32_t *)mp->virt;
345 
346 		for (i = 0; i < MEM_ELSBUF_SIZE; i += 4) {
347 			*lptr++ = pattern;
348 		}
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);
353 	}
354 	EMLXS_MPDATA_SYNC(mp->dma_handle, 0, MEM_ELSBUF_SIZE,
355 	    DDI_DMA_SYNC_FORDEV);
356 
357 	bzero(mp1->virt, MEM_ELSBUF_SIZE);
358 	EMLXS_MPDATA_SYNC(mp1->dma_handle, 0, MEM_ELSBUF_SIZE,
359 	    DDI_DMA_SYNC_FORDEV);
360 
361 	/* Create the biu diag request */
362 	(void) emlxs_mb_run_biu_diag(hba, mbq, mp->phys, mp1->phys);
363 
364 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 60);
365 
366 	if (rval == MBX_TIMEOUT) {
367 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg,
368 		    "BUI diagnostic timed out.");
369 
370 		rval = EMLXS_TEST_FAILED;
371 		goto done;
372 	}
373 
374 	EMLXS_MPDATA_SYNC(mp1->dma_handle, 0, MEM_ELSBUF_SIZE,
375 	    DDI_DMA_SYNC_FORKERNEL);
376 
377 	outptr = mp->virt;
378 	inptr = mp1->virt;
379 
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);
385 
386 			rval = EMLXS_TEST_FAILED;
387 			goto done;
388 		}
389 	}
390 
391 	/* Wait half second before returning */
392 	delay(drv_usectohz(500000));
393 	rval = FC_SUCCESS;
394 
395 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_complete_msg, "Status Good.");
396 
397 done:
398 
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;
408 		}
409 #endif  /* FMA_SUPPORT */
410 		emlxs_mem_put(hba, MEM_BUF, (void *)mp);
411 	}
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;
421 		}
422 #endif  /* FMA_SUPPORT */
423 		emlxs_mem_put(hba, MEM_BUF, (void *)mp1);
424 	}
425 	if (mbq) {
426 		emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
427 	}
428 
429 	return (rval);
430 
431 } /* emlxs_diag_biu_run() */
432 
433 
434 extern uint32_t
435 emlxs_diag_post_run(emlxs_hba_t *hba)
436 {
437 	emlxs_port_t *port = &PPORT;
438 	uint32_t rval = FC_SUCCESS;
439 
440 	if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
441 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
442 		    "POST: HBA shutdown.");
443 
444 		return (FC_TRAN_BUSY);
445 	}
446 
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.");
451 
452 		rval = FC_RESETFAIL;
453 	}
454 
455 	/* Restart the adapter */
456 	rval = EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
457 
458 	switch (rval) {
459 	case 0:
460 
461 		(void) emlxs_online(hba);
462 
463 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_complete_msg,
464 		    "Status good.");
465 
466 		rval = FC_SUCCESS;
467 
468 		break;
469 
470 	case 1:	/* failed */
471 
472 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg,
473 		    "HBA reset failed.");
474 
475 		rval = FC_RESETFAIL;
476 
477 		break;
478 
479 
480 	case 2:	/* failed */
481 
482 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
483 		    "HBA busy. Quiece and retry.");
484 
485 		rval = FC_STATEC_BUSY;
486 
487 		break;
488 
489 	}
490 
491 	return (rval);
492 
493 } /* emlxs_diag_post_run() */
494