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