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
9  * http://www.opensource.org/licenses/cddl1.txt.
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 (c) 2004-2012 Emulex. All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <emlxs.h>
28 
29 
30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31 EMLXS_MSG_DEF(EMLXS_DIAG_C);
32 
33 uint32_t emlxs_diag_pattern[256] = {
34 	/* Walking ones */
35 	0x80000000, 0x40000000, 0x20000000, 0x10000000,
36 	0x08000000, 0x04000000, 0x02000000, 0x01000000,
37 	0x00800000, 0x00400000, 0x00200000, 0x00100000,
38 	0x00080000, 0x00040000, 0x00020000, 0x00010000,
39 	0x00008000, 0x00004000, 0x00002000, 0x00001000,
40 	0x00000800, 0x00000400, 0x00000200, 0x00000100,
41 	0x00000080, 0x00000040, 0x00000020, 0x00000010,
42 	0x00000008, 0x00000004, 0x00000002, 0x00000001,
43 
44 	/* Walking zeros */
45 	0x7fffffff, 0xbfffffff, 0xdfffffff, 0xefffffff,
46 	0xf7ffffff, 0xfbffffff, 0xfdffffff, 0xfeffffff,
47 	0xff7fffff, 0xffbfffff, 0xffdfffff, 0xffefffff,
48 	0xfff7ffff, 0xfffbffff, 0xfffdffff, 0xfffeffff,
49 	0xffff7fff, 0xffffbfff, 0xffffdfff, 0xffffefff,
50 	0xfffff7ff, 0xfffffbff, 0xfffffdff, 0xfffffeff,
51 	0xffffff7f, 0xffffffbf, 0xffffffdf, 0xffffffef,
52 	0xfffffff7, 0xfffffffb, 0xfffffffd, 0xfffffffe,
53 
54 	/* all zeros */
55 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
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 
64 	/* all ones */
65 	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
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 
74 	/* all 5's */
75 	0x55555555, 0x55555555, 0x55555555, 0x55555555,
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 
84 	/* all a's */
85 	0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
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 
94 	/* all 5a's */
95 	0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a,
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 
104 	/* all a5's */
105 	0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5,
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 };
114 
115 
116 /* Default pkt callback routine */
117 static void
emlxs_diag_pkt_callback(fc_packet_t * pkt)118 emlxs_diag_pkt_callback(fc_packet_t *pkt)
119 {
120 	emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
121 
122 	/* Set the completed flag and wake up sleeping threads */
123 	mutex_enter(&EMLXS_PKT_LOCK);
124 	pkt->pkt_tran_flags |= FC_TRAN_COMPLETED;
125 	cv_broadcast(&EMLXS_PKT_CV);
126 	mutex_exit(&EMLXS_PKT_LOCK);
127 
128 	return;
129 
130 } /* emlxs_diag_pkt_callback() */
131 
132 
133 extern uint32_t
emlxs_diag_echo_run(emlxs_port_t * port,uint32_t did,uint32_t pattern)134 emlxs_diag_echo_run(emlxs_port_t *port, uint32_t did, uint32_t pattern)
135 {
136 	emlxs_hba_t *hba = HBA;
137 	uint32_t i = 0;
138 	uint32_t rval = FC_SUCCESS;
139 	int32_t pkt_ret;
140 	fc_packet_t *pkt;
141 	ELS_PKT *els;
142 	clock_t timeout;
143 	uint8_t *pkt_resp;
144 	char *pattern_buffer;
145 	uint32_t length;
146 	uint32_t *lptr;
147 	NODELIST *ndlp;
148 	uint8_t *pat;
149 
150 	/* Check did */
151 	if (did == 0) {
152 		did = port->did;
153 	}
154 
155 	/* Check if device is ready */
156 	if ((hba->state < FC_LINK_UP) || (port->did == 0)) {
157 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
158 		    "ECHO: HBA not ready.");
159 
160 		return (FC_TRAN_BUSY);
161 	}
162 
163 	/* Check for the host node */
164 	ndlp = emlxs_node_find_did(port, port->did, 1);
165 
166 	if (!ndlp || !ndlp->nlp_active) {
167 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
168 		    "ECHO: HBA not ready.");
169 
170 		return (FC_TRAN_BUSY);
171 	}
172 
173 	length = 124;
174 
175 	/* Prepare ECHO pkt */
176 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (uint32_t) + length,
177 	    sizeof (uint32_t) + length, 0, KM_NOSLEEP))) {
178 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
179 		    "ECHO: Unable to allocate packet. size=%x",
180 		    sizeof (uint32_t) + length);
181 
182 		return (FC_NOMEM);
183 	}
184 
185 	/* pkt initialization */
186 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
187 	pkt->pkt_timeout = 60;
188 
189 	/* Build the fc header */
190 	pkt->pkt_cmd_fhdr.d_id = did;
191 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | R_CTL_UNSOL_CONTROL;
192 	pkt->pkt_cmd_fhdr.s_id = port->did;
193 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
194 	pkt->pkt_cmd_fhdr.f_ctl =
195 	    F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE | F_CTL_END_SEQ;
196 	pkt->pkt_cmd_fhdr.seq_id = 0;
197 	pkt->pkt_cmd_fhdr.df_ctl = 0;
198 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
199 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
200 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
201 	pkt->pkt_cmd_fhdr.ro = 0;
202 	pkt->pkt_comp = emlxs_diag_pkt_callback;
203 
204 	/* Build the command */
205 	els = (ELS_PKT *) pkt->pkt_cmd;
206 	els->elsCode = 0x10;
207 	pattern_buffer = (char *)els->un.pad;
208 
209 	if (pattern) {
210 		/* Fill the transmit buffer with the pattern */
211 		lptr = (uint32_t *)pattern_buffer;
212 
213 		for (i = 0; i < length; i += 4) {
214 			*lptr++ = pattern;
215 		}
216 	} else {
217 		/* Program the default echo pattern */
218 		bzero(pattern_buffer, length);
219 		(void) snprintf(pattern_buffer, length,
220 		    "Emulex. We network storage. Emulex. We network storage. "
221 		    "Emulex. We network storage. Emulex. We network storage.");
222 	}
223 
224 	/* Send ECHO pkt */
225 	if ((rval = emlxs_pkt_send(pkt, 1)) != FC_SUCCESS) {
226 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
227 		    "ECHO: Packet send failed.");
228 
229 		goto done;
230 	}
231 
232 	/* Wait for ECHO completion */
233 	mutex_enter(&EMLXS_PKT_LOCK);
234 	timeout = emlxs_timeout(hba, (pkt->pkt_timeout + 15));
235 	pkt_ret = 0;
236 	while ((pkt_ret != -1) && !(pkt->pkt_tran_flags & FC_TRAN_COMPLETED)) {
237 		pkt_ret =
238 		    cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK, timeout);
239 
240 	}
241 	mutex_exit(&EMLXS_PKT_LOCK);
242 
243 	if (pkt_ret == -1) {
244 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg,
245 		    "Packet timed out.");
246 
247 		return (FC_ABORTED);
248 	}
249 
250 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
251 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg,
252 		    "Transport error.");
253 
254 		rval = FC_TRANSPORT_ERROR;
255 		goto done;
256 	}
257 
258 	/* Check response payload */
259 	pkt_resp = (uint8_t *)pkt->pkt_resp + 4;
260 	pat = (uint8_t *)pattern_buffer;
261 	rval = FC_SUCCESS;
262 
263 	for (i = 0; i < length; i++, pkt_resp++, pat++) {
264 		if (*pkt_resp != *pat) {
265 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg,
266 			    "Data miscompare. did=%06x length=%d. Offset %d "
267 			    "value %02x should be %02x.", did, length, i,
268 			    *pkt_resp, *pat);
269 
270 			rval = EMLXS_TEST_FAILED;
271 
272 			break;
273 		}
274 	}
275 
276 	if (rval == FC_SUCCESS) {
277 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_complete_msg,
278 		    "did=%06x  length=%d  pattern=%02x,%02x,%02x,%02x...",
279 		    did, length, pattern_buffer[0] & 0xff,
280 		    pattern_buffer[1] & 0xff, pattern_buffer[2] & 0xff,
281 		    pattern_buffer[3] & 0xff);
282 	}
283 
284 done:
285 
286 	/* Free the echo pkt */
287 	emlxs_pkt_free(pkt);
288 
289 	return (rval);
290 
291 } /* emlxs_diag_echo_run() */
292 
293 
294 extern uint32_t
emlxs_diag_biu_run(emlxs_hba_t * hba,uint32_t pattern)295 emlxs_diag_biu_run(emlxs_hba_t *hba, uint32_t pattern)
296 {
297 	emlxs_port_t *port = &PPORT;
298 	MAILBOXQ *mbq = NULL;
299 	MATCHMAP *mp = NULL;
300 	MATCHMAP *mp1 = NULL;
301 	uint32_t i;
302 	uint8_t *inptr;
303 	uint8_t *outptr;
304 	int32_t rval = FC_SUCCESS;
305 	uint32_t *lptr;
306 
307 	/* Check if device is ready */
308 	if (hba->state < FC_LINK_DOWN) {
309 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
310 		    "BIU: HBA not ready.");
311 
312 		return (FC_TRAN_BUSY);
313 	}
314 
315 	/*
316 	 * Get a buffer which will be used for the mailbox command
317 	 */
318 	if ((mbq = (MAILBOXQ *) emlxs_mem_get(hba, MEM_MBOX)) == 0) {
319 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
320 		    "BIU: Mailbox allocation failed.");
321 
322 		rval = FC_NOMEM;
323 		goto done;
324 	}
325 
326 	/*
327 	 * Setup and issue mailbox RUN BIU DIAG command Setup test buffers
328 	 */
329 	if (((mp = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF)) == 0) ||
330 	    ((mp1 = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF)) == 0)) {
331 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
332 		    "BIU: Buffer allocation failed.");
333 
334 		rval = FC_NOMEM;
335 		goto done;
336 	}
337 
338 	if (pattern) {
339 		/* Fill the transmit buffer with the pattern */
340 		lptr = (uint32_t *)mp->virt;
341 
342 		for (i = 0; i < MEM_ELSBUF_SIZE; i += 4) {
343 			*lptr++ = pattern;
344 		}
345 	} else {
346 		/* Copy the default pattern into the trasmit buffer */
347 		bcopy((caddr_t)&emlxs_diag_pattern[0], (caddr_t)mp->virt,
348 		    MEM_ELSBUF_SIZE);
349 	}
350 	EMLXS_MPDATA_SYNC(mp->dma_handle, 0, MEM_ELSBUF_SIZE,
351 	    DDI_DMA_SYNC_FORDEV);
352 
353 	bzero(mp1->virt, MEM_ELSBUF_SIZE);
354 	EMLXS_MPDATA_SYNC(mp1->dma_handle, 0, MEM_ELSBUF_SIZE,
355 	    DDI_DMA_SYNC_FORDEV);
356 
357 	/* Create the biu diag request */
358 	(void) emlxs_mb_run_biu_diag(hba, mbq, mp->phys, mp1->phys);
359 
360 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 60);
361 
362 	if (rval == MBX_TIMEOUT) {
363 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg,
364 		    "BUI diagnostic timed out.");
365 
366 		rval = EMLXS_TEST_FAILED;
367 		goto done;
368 	}
369 
370 	EMLXS_MPDATA_SYNC(mp1->dma_handle, 0, MEM_ELSBUF_SIZE,
371 	    DDI_DMA_SYNC_FORKERNEL);
372 
373 	outptr = mp->virt;
374 	inptr = mp1->virt;
375 
376 	for (i = 0; i < MEM_ELSBUF_SIZE; i++, outptr++, inptr++) {
377 		if (*outptr != *inptr) {
378 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg,
379 			    "Data miscompare. Offset %d value %02x should "
380 			    "be %02x.", i, *inptr, *outptr);
381 
382 			rval = EMLXS_TEST_FAILED;
383 			goto done;
384 		}
385 	}
386 
387 	/* Wait half second before returning */
388 	delay(drv_usectohz(500000));
389 	rval = FC_SUCCESS;
390 
391 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_complete_msg, "Status Good.");
392 
393 done:
394 
395 	if (mp) {
396 #ifdef FMA_SUPPORT
397 		if (emlxs_fm_check_dma_handle(hba, mp->dma_handle)
398 		    != DDI_FM_OK) {
399 			EMLXS_MSGF(EMLXS_CONTEXT,
400 			    &emlxs_invalid_dma_handle_msg,
401 			    "diag_biu_run: hdl=%p",
402 			    mp->dma_handle);
403 			rval = EMLXS_TEST_FAILED;
404 		}
405 #endif  /* FMA_SUPPORT */
406 		emlxs_mem_put(hba, MEM_BUF, (void *)mp);
407 	}
408 	if (mp1) {
409 #ifdef FMA_SUPPORT
410 		if (emlxs_fm_check_dma_handle(hba, mp1->dma_handle)
411 		    != DDI_FM_OK) {
412 			EMLXS_MSGF(EMLXS_CONTEXT,
413 			    &emlxs_invalid_dma_handle_msg,
414 			    "diag_biu_run: hdl=%p",
415 			    mp1->dma_handle);
416 			rval = EMLXS_TEST_FAILED;
417 		}
418 #endif  /* FMA_SUPPORT */
419 		emlxs_mem_put(hba, MEM_BUF, (void *)mp1);
420 	}
421 	if (mbq) {
422 		emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
423 	}
424 
425 	return (rval);
426 
427 } /* emlxs_diag_biu_run() */
428 
429 
430 extern uint32_t
emlxs_diag_post_run(emlxs_hba_t * hba)431 emlxs_diag_post_run(emlxs_hba_t *hba)
432 {
433 	emlxs_port_t *port = &PPORT;
434 	uint32_t rval = FC_SUCCESS;
435 
436 	if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
437 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
438 		    "POST: HBA shutdown.");
439 
440 		return (FC_TRAN_BUSY);
441 	}
442 
443 	/* Take board offline */
444 	if ((rval = emlxs_offline(hba, 0))) {
445 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg,
446 		    "Unable to take adapter offline.");
447 
448 		rval = FC_RESETFAIL;
449 	}
450 
451 	/* Restart the adapter */
452 	rval = EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
453 
454 	switch (rval) {
455 	case 0:
456 
457 		(void) emlxs_online(hba);
458 
459 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_complete_msg,
460 		    "Status good.");
461 
462 		rval = FC_SUCCESS;
463 
464 		break;
465 
466 	case 1:	/* failed */
467 
468 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg,
469 		    "HBA reset failed.");
470 
471 		rval = FC_RESETFAIL;
472 
473 		break;
474 
475 
476 	case 2:	/* failed */
477 
478 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
479 		    "HBA busy. Quiece and retry.");
480 
481 		rval = FC_STATEC_BUSY;
482 
483 		break;
484 
485 	}
486 
487 	return (rval);
488 
489 } /* emlxs_diag_post_run() */
490