xref: /illumos-gate/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_diag.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2009 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
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
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);
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) sprintf(pattern_buffer, "Emulex. We network storage. "
220 		    "Emulex. We network storage. Emulex. We network storage. "
221 		    "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
295 emlxs_diag_biu_run(emlxs_hba_t *hba, uint32_t pattern)
296 {
297 	emlxs_port_t *port = &PPORT;
298 	MAILBOX *mb;
299 	MATCHMAP *mp;
300 	MATCHMAP *mp1;
301 	uint32_t i;
302 	uint8_t *inptr;
303 	uint8_t *outptr;
304 	int32_t rval = FC_SUCCESS;
305 	uint32_t *lptr;
306 
307 	mp1 = 0;
308 	mb = 0;
309 
310 	/* Check if device is ready */
311 	if (hba->state < FC_LINK_DOWN) {
312 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
313 		    "BIU: HBA not ready.");
314 
315 		return (FC_TRAN_BUSY);
316 	}
317 
318 	/*
319 	 * Get a buffer which will be used for the mailbox command
320 	 */
321 	if ((mb = (MAILBOX *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI)) == 0) {
322 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
323 		    "BIU: Mailbox allocation failed.");
324 
325 		rval = FC_NOMEM;
326 		goto done;
327 	}
328 
329 	/*
330 	 * Setup and issue mailbox RUN BIU DIAG command Setup test buffers
331 	 */
332 	if (((mp = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF | MEM_PRI)) == 0) ||
333 	    ((mp1 = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF | MEM_PRI)) == 0)) {
334 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
335 		    "BIU: Buffer allocation failed.");
336 
337 		rval = FC_NOMEM;
338 		goto done;
339 	}
340 
341 	if (pattern) {
342 		/* Fill the transmit buffer with the pattern */
343 		lptr = (uint32_t *)mp->virt;
344 
345 		for (i = 0; i < MEM_ELSBUF_SIZE; i += 4) {
346 			*lptr++ = pattern;
347 		}
348 	} else {
349 		/* Copy the default pattern into the trasmit buffer */
350 		bcopy((caddr_t)&emlxs_diag_pattern[0], (caddr_t)mp->virt,
351 		    MEM_ELSBUF_SIZE);
352 	}
353 	emlxs_mpdata_sync(mp->dma_handle, 0, MEM_ELSBUF_SIZE,
354 	    DDI_DMA_SYNC_FORDEV);
355 
356 	bzero(mp1->virt, MEM_ELSBUF_SIZE);
357 	emlxs_mpdata_sync(mp1->dma_handle, 0, MEM_ELSBUF_SIZE,
358 	    DDI_DMA_SYNC_FORDEV);
359 
360 	/* Create the biu diag request */
361 	(void) emlxs_mb_run_biu_diag(hba, mb, mp->phys, mp1->phys);
362 
363 	rval = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 60);
364 
365 	if (rval == MBX_TIMEOUT) {
366 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg,
367 		    "BUI diagnostic timed out.");
368 
369 		rval = EMLXS_TEST_FAILED;
370 		goto done;
371 	}
372 
373 	emlxs_mpdata_sync(mp1->dma_handle, 0, MEM_ELSBUF_SIZE,
374 	    DDI_DMA_SYNC_FORKERNEL);
375 
376 	outptr = mp->virt;
377 	inptr = mp1->virt;
378 
379 	for (i = 0; i < MEM_ELSBUF_SIZE; i++, outptr++, inptr++) {
380 		if (*outptr != *inptr) {
381 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg,
382 			    "Data miscompare. Offset %d value %02x should "
383 			    "be %02x.", i, *inptr, *outptr);
384 
385 			rval = EMLXS_TEST_FAILED;
386 			goto done;
387 		}
388 	}
389 
390 	/* Wait half second before returning */
391 	delay(drv_usectohz(500000));
392 	rval = FC_SUCCESS;
393 
394 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_complete_msg, "Status Good.");
395 
396 done:
397 
398 	if (mp) {
399 		(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp);
400 	}
401 	if (mp1) {
402 		(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp1);
403 	}
404 	if (mb) {
405 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
406 	}
407 
408 	return (rval);
409 
410 }  /* emlxs_diag_biu_run() */
411 
412 
413 extern uint32_t
414 emlxs_diag_post_run(emlxs_hba_t *hba)
415 {
416 	emlxs_port_t *port = &PPORT;
417 	uint32_t rval = FC_SUCCESS;
418 
419 	if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
420 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
421 		    "POST: HBA shutdown.");
422 
423 		return (FC_TRAN_BUSY);
424 	}
425 
426 	/* Take board offline */
427 	if ((rval = emlxs_offline(hba))) {
428 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg,
429 		    "Unable to take adapter offline.");
430 
431 		rval = FC_RESETFAIL;
432 	}
433 
434 	/* Restart the adapter */
435 	rval = emlxs_sli_hba_reset(hba, 1, 1);
436 
437 	switch (rval) {
438 	case 0:
439 
440 		(void) emlxs_online(hba);
441 
442 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_complete_msg,
443 		    "Status good.");
444 
445 		rval = FC_SUCCESS;
446 
447 		break;
448 
449 	case 1:	/* failed */
450 
451 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg,
452 		    "HBA reset failed.");
453 
454 		rval = FC_RESETFAIL;
455 
456 		break;
457 
458 
459 	case 2:	/* failed */
460 
461 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg,
462 		    "HBA busy. Quiece and retry.");
463 
464 		rval = FC_STATEC_BUSY;
465 
466 		break;
467 
468 	}
469 
470 	return (rval);
471 
472 }  /* emlxs_diag_post_run() */
473 
474 
475 /* ARGSUSED */
476 extern uint32_t
477 emlxs_core_size(emlxs_hba_t *hba)
478 {
479 
480 	return (256);
481 
482 
483 
484 }  /* emlxs_core_size() */
485 
486 
487 /* ARGSUSED */
488 extern uint32_t
489 emlxs_core_dump(emlxs_hba_t *hba, char *buffer, uint32_t size)
490 {
491 	uint32_t i;
492 
493 	bzero(buffer, size);
494 
495 	/* Fill the buffer with dummy data */
496 	for (i = 0; i < 256; i++) {
497 		buffer[i] = (char)(i & 0xff);
498 	}
499 	return (FC_SUCCESS);
500 
501 
502 
503 }  /* emlxs_core_dump() */
504