1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte 
2216dd44c2SDaniel Beauregard /* Copyright 2009 QLogic Corporation */
23fcf3ce44SJohn Forte 
24fcf3ce44SJohn Forte /*
2516dd44c2SDaniel Beauregard  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
26fcf3ce44SJohn Forte  * Use is subject to license terms.
27fcf3ce44SJohn Forte  */
28fcf3ce44SJohn Forte 
2916dd44c2SDaniel Beauregard #pragma ident	"Copyright 2009 QLogic Corporation; ql_debug.c"
30fcf3ce44SJohn Forte 
31fcf3ce44SJohn Forte /*
32fcf3ce44SJohn Forte  * Qlogic ISP22xx/ISP23xx/ISP24xx FCA driver source
33fcf3ce44SJohn Forte  *
34fcf3ce44SJohn Forte  * ***********************************************************************
35fcf3ce44SJohn Forte  * *									**
36fcf3ce44SJohn Forte  * *				NOTICE					**
3716dd44c2SDaniel Beauregard  * *		COPYRIGHT (C) 1996-2009 QLOGIC CORPORATION		**
38fcf3ce44SJohn Forte  * *			ALL RIGHTS RESERVED				**
39fcf3ce44SJohn Forte  * *									**
40fcf3ce44SJohn Forte  * ***********************************************************************
41fcf3ce44SJohn Forte  *
42fcf3ce44SJohn Forte  */
43fcf3ce44SJohn Forte 
44fcf3ce44SJohn Forte #include <ql_apps.h>
45fcf3ce44SJohn Forte #include <ql_api.h>
46fcf3ce44SJohn Forte #include <ql_debug.h>
47fcf3ce44SJohn Forte 
48fcf3ce44SJohn Forte static int ql_flash_errlog_store(ql_adapter_state_t *, uint32_t *);
4916dd44c2SDaniel Beauregard int ql_validate_trace_desc(ql_adapter_state_t *ha);
5016dd44c2SDaniel Beauregard char *ql_find_trace_start(ql_adapter_state_t *ha);
51fcf3ce44SJohn Forte 
52fcf3ce44SJohn Forte /*
53fcf3ce44SJohn Forte  * Global Data.
54fcf3ce44SJohn Forte  */
55fcf3ce44SJohn Forte uint32_t	el_message_number = 0;
56fcf3ce44SJohn Forte uint32_t	ql_enable_ellock = 0;
57fcf3ce44SJohn Forte 
58fcf3ce44SJohn Forte extern int 	getpcstack(pc_t *, int);
59fcf3ce44SJohn Forte extern char	*kobj_getsymname(uintptr_t, ulong_t *);
60fcf3ce44SJohn Forte 
61fcf3ce44SJohn Forte /*
62fcf3ce44SJohn Forte  * ql_dump_buffer
63fcf3ce44SJohn Forte  *	 Outputs buffer.
64fcf3ce44SJohn Forte  *
65fcf3ce44SJohn Forte  * Input:
66fcf3ce44SJohn Forte  *	 string:	Null terminated string (no newline at end).
67fcf3ce44SJohn Forte  *	 buffer:	buffer address.
68fcf3ce44SJohn Forte  *	 wd_size:	word size 8 bits
69fcf3ce44SJohn Forte  *	 count:		number of words.
70fcf3ce44SJohn Forte  */
71fcf3ce44SJohn Forte void
72fcf3ce44SJohn Forte ql_dump_buffer(uint8_t *b8, uint8_t wd_size, uint32_t count)
73fcf3ce44SJohn Forte {
74fcf3ce44SJohn Forte 	uint32_t	cnt;
75fcf3ce44SJohn Forte 	char		str[256], *sp;
76fcf3ce44SJohn Forte 	uint32_t	*b32 = (uint32_t *)b8;
77fcf3ce44SJohn Forte 	uint16_t	*b16 = (uint16_t *)b8;
78fcf3ce44SJohn Forte 
79fcf3ce44SJohn Forte 	sp = &str[0];
80fcf3ce44SJohn Forte 
81fcf3ce44SJohn Forte 	switch (wd_size) {
82fcf3ce44SJohn Forte 	case 32:
83fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "         0         4         8         C\n");
84fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "----------------------------------------\n");
85fcf3ce44SJohn Forte 
86fcf3ce44SJohn Forte 		for (cnt = 1; cnt <= count; cnt++) {
87fcf3ce44SJohn Forte 			(void) sprintf(sp, "%10x", *b32++);
88fcf3ce44SJohn Forte 			sp += 10;
89fcf3ce44SJohn Forte 			if (cnt % 4 == 0) {
90fcf3ce44SJohn Forte 				cmn_err(CE_CONT, "%s\n", str);
91fcf3ce44SJohn Forte 				sp = &str[0];
92fcf3ce44SJohn Forte 			}
93fcf3ce44SJohn Forte 		}
94fcf3ce44SJohn Forte 		break;
95fcf3ce44SJohn Forte 	case 16:
96fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "     0     2     4     6     8     A     C"
97fcf3ce44SJohn Forte 		    "     E\n");
98fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "------------------------------------------"
99fcf3ce44SJohn Forte 		    "------\n");
100fcf3ce44SJohn Forte 
101fcf3ce44SJohn Forte 		for (cnt = 1; cnt <= count; cnt++) {
102fcf3ce44SJohn Forte 			(void) sprintf(sp, "%6x", *b16++);
103fcf3ce44SJohn Forte 			sp += 6;
104fcf3ce44SJohn Forte 			if (cnt % 8 == 0) {
105fcf3ce44SJohn Forte 				cmn_err(CE_CONT, "%s\n", str);
106fcf3ce44SJohn Forte 				sp = &str[0];
107fcf3ce44SJohn Forte 			}
108fcf3ce44SJohn Forte 		}
109fcf3ce44SJohn Forte 		break;
110fcf3ce44SJohn Forte 	case 8:
111fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "   0   1   2   3   4   5   6   7   8   9   "
112fcf3ce44SJohn Forte 		    "A   B   C   D   E   F\n");
113fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "---------------------------------"
114fcf3ce44SJohn Forte 		    "-------------------------------\n");
115fcf3ce44SJohn Forte 
116fcf3ce44SJohn Forte 		for (cnt = 1; cnt <= count; cnt++) {
117fcf3ce44SJohn Forte 			(void) sprintf(sp, "%4x", *b8++);
118fcf3ce44SJohn Forte 			sp += 4;
119fcf3ce44SJohn Forte 			if (cnt % 16 == 0) {
120fcf3ce44SJohn Forte 				cmn_err(CE_CONT, "%s\n", str);
121fcf3ce44SJohn Forte 				sp = &str[0];
122fcf3ce44SJohn Forte 			}
123fcf3ce44SJohn Forte 		}
124fcf3ce44SJohn Forte 		break;
125fcf3ce44SJohn Forte 	default:
126fcf3ce44SJohn Forte 		break;
127fcf3ce44SJohn Forte 	}
128fcf3ce44SJohn Forte 	if (sp != &str[0]) {
129fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "%s\n", str);
130fcf3ce44SJohn Forte 	}
131fcf3ce44SJohn Forte }
132fcf3ce44SJohn Forte 
133fcf3ce44SJohn Forte /*
134fcf3ce44SJohn Forte  * ql_el_msg
135fcf3ce44SJohn Forte  *	Extended logging message
136fcf3ce44SJohn Forte  *
137fcf3ce44SJohn Forte  * Input:
138fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
139fcf3ce44SJohn Forte  *	fn:	function name.
140fcf3ce44SJohn Forte  *	ce:	level
141fcf3ce44SJohn Forte  *	...:	Variable argument list.
142fcf3ce44SJohn Forte  *
143fcf3ce44SJohn Forte  * Context:
144fcf3ce44SJohn Forte  *	Kernel/Interrupt context.
145fcf3ce44SJohn Forte  */
146fcf3ce44SJohn Forte void
147fcf3ce44SJohn Forte ql_el_msg(ql_adapter_state_t *ha, const char *fn, int ce, ...)
148fcf3ce44SJohn Forte {
149fcf3ce44SJohn Forte 	uint32_t	el_msg_num;
15016dd44c2SDaniel Beauregard 	char		*s, *fmt = 0, *fmt1 = 0;
15116dd44c2SDaniel Beauregard 	char		fmt2[256];
15216dd44c2SDaniel Beauregard 	int		rval, tmp;
15316dd44c2SDaniel Beauregard 	int		tracing = 0;
154fcf3ce44SJohn Forte 	va_list		vl;
155fcf3ce44SJohn Forte 
15616dd44c2SDaniel Beauregard 	/* Tracing is the default but it can be disabled. */
1575dfd244aSDaniel Beauregard 	if ((CFG_IST(ha, CFG_DISABLE_EXTENDED_LOGGING_TRACE) == 0) &&
15816dd44c2SDaniel Beauregard 	    (rval = ql_validate_trace_desc(ha) == DDI_SUCCESS)) {
15916dd44c2SDaniel Beauregard 		tracing = 1;
16016dd44c2SDaniel Beauregard 
16116dd44c2SDaniel Beauregard 		TRACE_BUFFER_LOCK(ha);
16216dd44c2SDaniel Beauregard 
16316dd44c2SDaniel Beauregard 		/*
16416dd44c2SDaniel Beauregard 		 * Ensure enough space for the string. Wrap to
16516dd44c2SDaniel Beauregard 		 * start when default message allocation size
16616dd44c2SDaniel Beauregard 		 * would overrun the end.
16716dd44c2SDaniel Beauregard 		 */
16816dd44c2SDaniel Beauregard 		if ((ha->el_trace_desc->next + EL_BUFFER_RESERVE) >=
16916dd44c2SDaniel Beauregard 		    ha->el_trace_desc->trace_buffer_size) {
17016dd44c2SDaniel Beauregard 			fmt = ha->el_trace_desc->trace_buffer;
17116dd44c2SDaniel Beauregard 			ha->el_trace_desc->next = 0;
17216dd44c2SDaniel Beauregard 		} else {
17316dd44c2SDaniel Beauregard 			fmt = ha->el_trace_desc->trace_buffer +
17416dd44c2SDaniel Beauregard 			    ha->el_trace_desc->next;
17516dd44c2SDaniel Beauregard 		}
17616dd44c2SDaniel Beauregard 	}
17716dd44c2SDaniel Beauregard 	/* if no buffer use the stack */
17816dd44c2SDaniel Beauregard 	if (fmt == NULL) {
17916dd44c2SDaniel Beauregard 		fmt = fmt2;
18016dd44c2SDaniel Beauregard 	}
18116dd44c2SDaniel Beauregard 
182fcf3ce44SJohn Forte 	va_start(vl, ce);
183fcf3ce44SJohn Forte 
184fcf3ce44SJohn Forte 	s = va_arg(vl, char *);
185fcf3ce44SJohn Forte 
186fcf3ce44SJohn Forte 	if (ql_enable_ellock) {
187fcf3ce44SJohn Forte 		/*
188fcf3ce44SJohn Forte 		 * Used when messages are *maybe* being lost.  Adds
18916dd44c2SDaniel Beauregard 		 * a unique number to the message so one can see if
190fcf3ce44SJohn Forte 		 * any messages have been dropped. NB: This slows
191fcf3ce44SJohn Forte 		 * down the driver, which may make the issue disappear.
192fcf3ce44SJohn Forte 		 */
193fcf3ce44SJohn Forte 		GLOBAL_EL_LOCK();
194fcf3ce44SJohn Forte 		el_msg_num = ++el_message_number;
195fcf3ce44SJohn Forte 		GLOBAL_EL_UNLOCK();
196fcf3ce44SJohn Forte 
19716dd44c2SDaniel Beauregard 		rval = (int)snprintf(fmt, (size_t)EL_BUFFER_RESERVE,
1985dfd244aSDaniel Beauregard 		    QL_BANG "QEL%d %s(%d,%d): %s, ", el_msg_num, QL_NAME,
1995dfd244aSDaniel Beauregard 		    ha->instance, ha->vp_index, fn);
20016dd44c2SDaniel Beauregard 		fmt1 = fmt + rval;
20116dd44c2SDaniel Beauregard 		tmp = (int)vsnprintf(fmt1,
20216dd44c2SDaniel Beauregard 		    (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl);
20316dd44c2SDaniel Beauregard 		rval += tmp;
204fcf3ce44SJohn Forte 	} else {
20516dd44c2SDaniel Beauregard 		rval = (int)snprintf(fmt, (size_t)EL_BUFFER_RESERVE,
20616dd44c2SDaniel Beauregard 		    QL_BANG "QEL %s(%d,%d): %s, ", QL_NAME, ha->instance,
20716dd44c2SDaniel Beauregard 		    ha->vp_index, fn);
20816dd44c2SDaniel Beauregard 		fmt1 = fmt + rval;
20916dd44c2SDaniel Beauregard 		tmp = (int)vsnprintf(fmt1,
21016dd44c2SDaniel Beauregard 		    (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl);
21116dd44c2SDaniel Beauregard 		rval += tmp;
21216dd44c2SDaniel Beauregard 	}
21316dd44c2SDaniel Beauregard 
21416dd44c2SDaniel Beauregard 	/*
21516dd44c2SDaniel Beauregard 	 * Calculate the offset where the next message will go,
21616dd44c2SDaniel Beauregard 	 * skipping the NULL.
21716dd44c2SDaniel Beauregard 	 */
21816dd44c2SDaniel Beauregard 	if (tracing) {
219*7a2b99c0SDaniel Beauregard 		uint16_t next = (uint16_t)(rval += 1);
220*7a2b99c0SDaniel Beauregard 		ha->el_trace_desc->next += next;
22116dd44c2SDaniel Beauregard 		TRACE_BUFFER_UNLOCK(ha);
22216dd44c2SDaniel Beauregard 	}
22316dd44c2SDaniel Beauregard 
2245dfd244aSDaniel Beauregard 	if (CFG_IST(ha, CFG_ENABLE_EXTENDED_LOGGING)) {
22516dd44c2SDaniel Beauregard 		cmn_err(ce, fmt);
22616dd44c2SDaniel Beauregard 	}
22716dd44c2SDaniel Beauregard 
22816dd44c2SDaniel Beauregard 	va_end(vl);
22916dd44c2SDaniel Beauregard }
23016dd44c2SDaniel Beauregard 
23116dd44c2SDaniel Beauregard /*
23216dd44c2SDaniel Beauregard  * ql_el_msg
23316dd44c2SDaniel Beauregard  *	Extended logging message
23416dd44c2SDaniel Beauregard  *
23516dd44c2SDaniel Beauregard  * Input:
23616dd44c2SDaniel Beauregard  *	ha:	adapter state pointer.
23716dd44c2SDaniel Beauregard  *	fn:	function name.
23816dd44c2SDaniel Beauregard  *	ce:	level
23916dd44c2SDaniel Beauregard  *	...:	Variable argument list.
24016dd44c2SDaniel Beauregard  *
24116dd44c2SDaniel Beauregard  * Context:
24216dd44c2SDaniel Beauregard  *	Kernel/Interrupt context.
24316dd44c2SDaniel Beauregard  */
24416dd44c2SDaniel Beauregard void
24516dd44c2SDaniel Beauregard ql_dbg_msg(const char *fn, int ce, ...)
24616dd44c2SDaniel Beauregard {
24716dd44c2SDaniel Beauregard 	uint32_t	el_msg_num;
24816dd44c2SDaniel Beauregard 	char		*s;
24916dd44c2SDaniel Beauregard 	char		fmt[256];
25016dd44c2SDaniel Beauregard 	va_list		vl;
25116dd44c2SDaniel Beauregard 
25216dd44c2SDaniel Beauregard 	va_start(vl, ce);
25316dd44c2SDaniel Beauregard 
25416dd44c2SDaniel Beauregard 	s = va_arg(vl, char *);
25516dd44c2SDaniel Beauregard 
25616dd44c2SDaniel Beauregard 	if (ql_enable_ellock) {
25716dd44c2SDaniel Beauregard 		/*
25816dd44c2SDaniel Beauregard 		 * Used when messages are *maybe* being lost.  Adds
25916dd44c2SDaniel Beauregard 		 * a unique number to the message to one can see if
26016dd44c2SDaniel Beauregard 		 * any messages have been dropped. NB: This slows
26116dd44c2SDaniel Beauregard 		 * down the driver, which may make the issue disappear.
26216dd44c2SDaniel Beauregard 		 */
26316dd44c2SDaniel Beauregard 		GLOBAL_EL_LOCK();
26416dd44c2SDaniel Beauregard 		el_msg_num = ++el_message_number;
26516dd44c2SDaniel Beauregard 		GLOBAL_EL_UNLOCK();
26616dd44c2SDaniel Beauregard 		(void) snprintf(fmt, EL_BUFFER_RESERVE, "QLP%d: %s %s, %s",
26716dd44c2SDaniel Beauregard 		    el_msg_num, QL_NAME, fn, s);
26816dd44c2SDaniel Beauregard 	} else {
26916dd44c2SDaniel Beauregard 		(void) snprintf(fmt, EL_BUFFER_RESERVE, "QLP: %s %s, %s",
27016dd44c2SDaniel Beauregard 		    QL_NAME, fn, s);
271fcf3ce44SJohn Forte 	}
272fcf3ce44SJohn Forte 
273fcf3ce44SJohn Forte 	vcmn_err(ce, fmt, vl);
274fcf3ce44SJohn Forte 
275fcf3ce44SJohn Forte 	va_end(vl);
276fcf3ce44SJohn Forte }
277fcf3ce44SJohn Forte 
278fcf3ce44SJohn Forte /*
279fcf3ce44SJohn Forte  * ql_stacktrace
280fcf3ce44SJohn Forte  *	Prints out current stack
281fcf3ce44SJohn Forte  *
282fcf3ce44SJohn Forte  * Input:
283fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
284fcf3ce44SJohn Forte  *
285fcf3ce44SJohn Forte  * Context:
286fcf3ce44SJohn Forte  *	Kernel/Interrupt context.
287fcf3ce44SJohn Forte  */
288fcf3ce44SJohn Forte void
289fcf3ce44SJohn Forte ql_stacktrace(ql_adapter_state_t *ha)
290fcf3ce44SJohn Forte {
291fcf3ce44SJohn Forte 	int	depth, i;
292fcf3ce44SJohn Forte 	pc_t	pcstack[DEBUG_STK_DEPTH];
293fcf3ce44SJohn Forte 	char	*sym = NULL;
294fcf3ce44SJohn Forte 	ulong_t	off;
295fcf3ce44SJohn Forte 
296fcf3ce44SJohn Forte 	depth = getpcstack(&pcstack[0], DEBUG_STK_DEPTH);
297fcf3ce44SJohn Forte 
298fcf3ce44SJohn Forte 	cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance,
299fcf3ce44SJohn Forte 	    ha->vp_index);
300fcf3ce44SJohn Forte 	for (i = 0; i < MIN(depth, DEBUG_STK_DEPTH); i++) {
301fcf3ce44SJohn Forte 		sym = kobj_getsymname((uintptr_t)pcstack[i], &off);
302fcf3ce44SJohn Forte 
303fcf3ce44SJohn Forte 		if (sym == NULL) {
304fcf3ce44SJohn Forte 			cmn_err(CE_CONT, "%s(%d,%d): sym is NULL\n", QL_NAME,
305fcf3ce44SJohn Forte 			    ha->instance, ha->vp_index);
306fcf3ce44SJohn Forte 		} else {
307fcf3ce44SJohn Forte 			cmn_err(CE_CONT, "%s(%d,%d): %s+%lx\n", QL_NAME,
308fcf3ce44SJohn Forte 			    ha->instance, ha->vp_index, sym ? sym : "?", off);
309fcf3ce44SJohn Forte 		}
310fcf3ce44SJohn Forte 	}
311fcf3ce44SJohn Forte 	cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance,
312fcf3ce44SJohn Forte 	    ha->vp_index);
313fcf3ce44SJohn Forte }
314fcf3ce44SJohn Forte 
315fcf3ce44SJohn Forte /*
316fcf3ce44SJohn Forte  * ql_flash_errlog
317fcf3ce44SJohn Forte  *	Adds error to flash error log.
318fcf3ce44SJohn Forte  *	Entry Layout:
319fcf3ce44SJohn Forte  *		uint32_t TimeStamp;
320fcf3ce44SJohn Forte  *		uint16_t CodeData[4];
321fcf3ce44SJohn Forte  *
322fcf3ce44SJohn Forte  * Input:
323fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
324fcf3ce44SJohn Forte  *	code:	Error code
325fcf3ce44SJohn Forte  *	d1-d3:	Error code data
326fcf3ce44SJohn Forte  *
327fcf3ce44SJohn Forte  * Returns:
328fcf3ce44SJohn Forte  *	ql local function return status code.
329fcf3ce44SJohn Forte  *
330fcf3ce44SJohn Forte  * Context:
331fcf3ce44SJohn Forte  *	Kernel/Interrupt context.
332fcf3ce44SJohn Forte  */
333fcf3ce44SJohn Forte int
334fcf3ce44SJohn Forte ql_flash_errlog(ql_adapter_state_t *ha, uint16_t code, uint16_t d1,
335fcf3ce44SJohn Forte     uint16_t d2, uint16_t d3)
336fcf3ce44SJohn Forte {
337fcf3ce44SJohn Forte 	char		*s;
338fcf3ce44SJohn Forte 	uint32_t	marker[2], fdata[2], faddr;
339fcf3ce44SJohn Forte 	int		rval;
340fcf3ce44SJohn Forte 
3415dfd244aSDaniel Beauregard 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
342fcf3ce44SJohn Forte 
343fcf3ce44SJohn Forte 	if (ha->flash_errlog_start == 0) {
344fcf3ce44SJohn Forte 		return (QL_NOT_SUPPORTED);
345fcf3ce44SJohn Forte 	}
346fcf3ce44SJohn Forte 
347fcf3ce44SJohn Forte 	EL(ha, "code=%xh, d1=%xh, d2=%xh, d3=%xh\n", code, d1, d2, d3);
348fcf3ce44SJohn Forte 
349fcf3ce44SJohn Forte 	/*
350fcf3ce44SJohn Forte 	 * If marker not already found, locate or write marker.
351fcf3ce44SJohn Forte 	 */
352fcf3ce44SJohn Forte 	if (!(ha->flags & FLASH_ERRLOG_MARKER)) {
353fcf3ce44SJohn Forte 
354fcf3ce44SJohn Forte 		/* Create marker. */
355fcf3ce44SJohn Forte 		marker[0] = CHAR_TO_LONG(ha->fw_subminor_version,
356fcf3ce44SJohn Forte 		    ha->fw_minor_version, ha->fw_major_version, 'S');
357fcf3ce44SJohn Forte 
358fcf3ce44SJohn Forte 		/*
359fcf3ce44SJohn Forte 		 * Version should be of the format: YYYYMMDD-v.vv
360fcf3ce44SJohn Forte 		 */
361fcf3ce44SJohn Forte 		if ((strlen(QL_VERSION) > 9) && (QL_VERSION[8] == '-')) {
362fcf3ce44SJohn Forte 			s = &QL_VERSION[9];
363fcf3ce44SJohn Forte 		} else {
364fcf3ce44SJohn Forte 			s = QL_VERSION;
365fcf3ce44SJohn Forte 		}
366fcf3ce44SJohn Forte 
367fcf3ce44SJohn Forte 		for (marker[1] = 0; *s != '\0'; s++) {
368fcf3ce44SJohn Forte 			if (*s >= '0' && *s <= '9') {
369fcf3ce44SJohn Forte 				marker[1] <<= 4;
370fcf3ce44SJohn Forte 				marker[1] |= *s - '0';
371fcf3ce44SJohn Forte 			} else if (*s != '.') {
372fcf3ce44SJohn Forte 				break;
373fcf3ce44SJohn Forte 			}
374fcf3ce44SJohn Forte 		}
375fcf3ce44SJohn Forte 
376fcf3ce44SJohn Forte 		/* Locate marker. */
377fcf3ce44SJohn Forte 		ha->flash_errlog_ptr = ha->flash_errlog_start;
378fcf3ce44SJohn Forte 		for (;;) {
3795dfd244aSDaniel Beauregard 			faddr = ha->flash_data_addr | ha->flash_errlog_ptr;
380fcf3ce44SJohn Forte 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[0]);
381fcf3ce44SJohn Forte 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[1]);
382fcf3ce44SJohn Forte 			if (fdata[0] == 0xffffffff && fdata[1] == 0xffffffff) {
383fcf3ce44SJohn Forte 				break;
384fcf3ce44SJohn Forte 			}
385fcf3ce44SJohn Forte 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[0]);
386fcf3ce44SJohn Forte 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[1]);
387fcf3ce44SJohn Forte 			ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE;
388fcf3ce44SJohn Forte 			if (ha->flash_errlog_ptr >=
389fcf3ce44SJohn Forte 			    ha->flash_errlog_start + FLASH_ERRLOG_SIZE) {
390fcf3ce44SJohn Forte 				EL(ha, "log full\n");
391fcf3ce44SJohn Forte 				return (QL_MEMORY_FULL);
392fcf3ce44SJohn Forte 			}
393fcf3ce44SJohn Forte 			if (fdata[0] == marker[0] && fdata[1] == marker[1]) {
394fcf3ce44SJohn Forte 				ha->flags |= FLASH_ERRLOG_MARKER;
395fcf3ce44SJohn Forte 				break;
396fcf3ce44SJohn Forte 			}
397fcf3ce44SJohn Forte 		}
398fcf3ce44SJohn Forte 
399fcf3ce44SJohn Forte 		/* No marker, write it. */
400fcf3ce44SJohn Forte 		if (!(ha->flags & FLASH_ERRLOG_MARKER)) {
401fcf3ce44SJohn Forte 			ha->flags |= FLASH_ERRLOG_MARKER;
402fcf3ce44SJohn Forte 			rval = ql_flash_errlog_store(ha, marker);
403fcf3ce44SJohn Forte 			if (rval != QL_SUCCESS) {
404fcf3ce44SJohn Forte 				EL(ha, "failed marker write=%xh\n", rval);
405fcf3ce44SJohn Forte 				return (rval);
406fcf3ce44SJohn Forte 			}
407fcf3ce44SJohn Forte 		}
408fcf3ce44SJohn Forte 	}
409fcf3ce44SJohn Forte 
410fcf3ce44SJohn Forte 	/*
411fcf3ce44SJohn Forte 	 * Store error.
412fcf3ce44SJohn Forte 	 */
413fcf3ce44SJohn Forte 	fdata[0] = SHORT_TO_LONG(d1, code);
414fcf3ce44SJohn Forte 	fdata[1] = SHORT_TO_LONG(d3, d2);
415fcf3ce44SJohn Forte 	rval = ql_flash_errlog_store(ha, fdata);
416fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
417fcf3ce44SJohn Forte 		EL(ha, "failed error write=%xh\n", rval);
418fcf3ce44SJohn Forte 	} else {
419fcf3ce44SJohn Forte 		/*EMPTY*/
4205dfd244aSDaniel Beauregard 		QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
421fcf3ce44SJohn Forte 	}
422fcf3ce44SJohn Forte 
423fcf3ce44SJohn Forte 	return (rval);
424fcf3ce44SJohn Forte }
425fcf3ce44SJohn Forte 
426fcf3ce44SJohn Forte /*
427fcf3ce44SJohn Forte  * ql_flash_errlog_store
428fcf3ce44SJohn Forte  *	Stores error to flash.
429fcf3ce44SJohn Forte  *	Entry Layout:
430fcf3ce44SJohn Forte  *		uint32_t TimeStamp;
431fcf3ce44SJohn Forte  *		uint16_t CodeData[4];
432fcf3ce44SJohn Forte  *
433fcf3ce44SJohn Forte  * Input:
434fcf3ce44SJohn Forte  *	ha:			adapter state pointer.
435fcf3ce44SJohn Forte  *	fdata:			Error code plus data.
436fcf3ce44SJohn Forte  *	ha->flash_errlog_ptr:	Current Flash error pointer.
437fcf3ce44SJohn Forte  *
438fcf3ce44SJohn Forte  * Output:
439fcf3ce44SJohn Forte  *	ha->flash_errlog_ptr:	updated pointer.
440fcf3ce44SJohn Forte  *
441fcf3ce44SJohn Forte  * Returns:
442fcf3ce44SJohn Forte  *	ql local function return status code.
443fcf3ce44SJohn Forte  *
444fcf3ce44SJohn Forte  * Context:
445fcf3ce44SJohn Forte  *	Kernel/Interrupt context.
446fcf3ce44SJohn Forte  */
447fcf3ce44SJohn Forte static int
448fcf3ce44SJohn Forte ql_flash_errlog_store(ql_adapter_state_t *ha, uint32_t *fdata)
449fcf3ce44SJohn Forte {
4505dfd244aSDaniel Beauregard 	int		rval;
451fcf3ce44SJohn Forte 	uint64_t	time;
452fcf3ce44SJohn Forte 	uint32_t	d1, d2, faddr;
453fcf3ce44SJohn Forte 
4545dfd244aSDaniel Beauregard 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
455fcf3ce44SJohn Forte 
456fcf3ce44SJohn Forte 	/* Locate first empty entry */
457fcf3ce44SJohn Forte 	for (;;) {
458fcf3ce44SJohn Forte 		if (ha->flash_errlog_ptr >=
459fcf3ce44SJohn Forte 		    ha->flash_errlog_start + FLASH_ERRLOG_SIZE) {
460fcf3ce44SJohn Forte 			EL(ha, "log full\n");
461fcf3ce44SJohn Forte 			return (QL_MEMORY_FULL);
462fcf3ce44SJohn Forte 		}
463fcf3ce44SJohn Forte 
4645dfd244aSDaniel Beauregard 		faddr = ha->flash_data_addr | ha->flash_errlog_ptr;
465fcf3ce44SJohn Forte 		ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE;
466fcf3ce44SJohn Forte 		(void) ql_24xx_read_flash(ha, faddr, &d1);
467fcf3ce44SJohn Forte 		(void) ql_24xx_read_flash(ha, faddr + 1, &d2);
468fcf3ce44SJohn Forte 		if (d1 == 0xffffffff && d2 == 0xffffffff) {
469fcf3ce44SJohn Forte 			(void) drv_getparm(TIME, &time);
470fcf3ce44SJohn Forte 
471fcf3ce44SJohn Forte 			/* Enable flash write. */
4725dfd244aSDaniel Beauregard 			if ((rval = ql_24xx_unprotect_flash(ha)) !=
4735dfd244aSDaniel Beauregard 			    QL_SUCCESS) {
4745dfd244aSDaniel Beauregard 				EL(ha, "unprotect_flash failed, rval=%xh\n",
4755dfd244aSDaniel Beauregard 				    rval);
4765dfd244aSDaniel Beauregard 				return (rval);
4775dfd244aSDaniel Beauregard 			}
478fcf3ce44SJohn Forte 
479fcf3ce44SJohn Forte 			(void) ql_24xx_write_flash(ha, faddr++, LSD(time));
480fcf3ce44SJohn Forte 			(void) ql_24xx_write_flash(ha, faddr++, MSD(time));
481fcf3ce44SJohn Forte 			(void) ql_24xx_write_flash(ha, faddr++, *fdata++);
482fcf3ce44SJohn Forte 			(void) ql_24xx_write_flash(ha, faddr++, *fdata);
483fcf3ce44SJohn Forte 
484fcf3ce44SJohn Forte 			/* Enable flash write-protection. */
485fcf3ce44SJohn Forte 			ql_24xx_protect_flash(ha);
486fcf3ce44SJohn Forte 			break;
487fcf3ce44SJohn Forte 		}
488fcf3ce44SJohn Forte 	}
489fcf3ce44SJohn Forte 
4905dfd244aSDaniel Beauregard 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
491fcf3ce44SJohn Forte 
492fcf3ce44SJohn Forte 	return (QL_SUCCESS);
493fcf3ce44SJohn Forte }
49416dd44c2SDaniel Beauregard 
49516dd44c2SDaniel Beauregard /*
49616dd44c2SDaniel Beauregard  * ql_dump_el_trace_buffer
49716dd44c2SDaniel Beauregard  *	 Outputs extended logging trace buffer.
49816dd44c2SDaniel Beauregard  *
49916dd44c2SDaniel Beauregard  * Input:
50016dd44c2SDaniel Beauregard  *	ha:	adapter state pointer.
50116dd44c2SDaniel Beauregard  */
50216dd44c2SDaniel Beauregard void
50316dd44c2SDaniel Beauregard ql_dump_el_trace_buffer(ql_adapter_state_t *ha)
50416dd44c2SDaniel Beauregard {
50516dd44c2SDaniel Beauregard 	char		*dump_start = NULL;
50616dd44c2SDaniel Beauregard 	char		*dump_current = NULL;
50716dd44c2SDaniel Beauregard 	char		*trace_start;
50816dd44c2SDaniel Beauregard 	char		*trace_end;
50916dd44c2SDaniel Beauregard 	int		wrapped = 0;
51016dd44c2SDaniel Beauregard 	int		rval;
51116dd44c2SDaniel Beauregard 
51216dd44c2SDaniel Beauregard 	TRACE_BUFFER_LOCK(ha);
51316dd44c2SDaniel Beauregard 
51416dd44c2SDaniel Beauregard 	rval = ql_validate_trace_desc(ha);
51516dd44c2SDaniel Beauregard 	if (rval != NULL) {
51616dd44c2SDaniel Beauregard 		cmn_err(CE_CONT, "%s(%d) Dump EL trace - invalid desc\n",
51716dd44c2SDaniel Beauregard 		    QL_NAME, ha->instance);
51816dd44c2SDaniel Beauregard 	} else if ((dump_start = ql_find_trace_start(ha)) != NULL) {
51916dd44c2SDaniel Beauregard 		dump_current = dump_start;
52016dd44c2SDaniel Beauregard 		trace_start = ha->el_trace_desc->trace_buffer;
52116dd44c2SDaniel Beauregard 		trace_end = trace_start +
52216dd44c2SDaniel Beauregard 		    ha->el_trace_desc->trace_buffer_size;
52316dd44c2SDaniel Beauregard 
52416dd44c2SDaniel Beauregard 		cmn_err(CE_CONT, "%s(%d) Dump EL trace - start %p %p\n",
52516dd44c2SDaniel Beauregard 		    QL_NAME, ha->instance,
52616dd44c2SDaniel Beauregard 		    (void *)dump_start, (void *)trace_start);
52716dd44c2SDaniel Beauregard 
52816dd44c2SDaniel Beauregard 		while (((uintptr_t)dump_current - (uintptr_t)trace_start) <=
5295dfd244aSDaniel Beauregard 		    (uintptr_t)ha->el_trace_desc->trace_buffer_size) {
53016dd44c2SDaniel Beauregard 			/* Show it... */
53116dd44c2SDaniel Beauregard 			cmn_err(CE_CONT, "%p - %s", (void *)dump_current,
53216dd44c2SDaniel Beauregard 			    dump_current);
53316dd44c2SDaniel Beauregard 			/* Make the next the current */
53416dd44c2SDaniel Beauregard 			dump_current += (strlen(dump_current) + 1);
53516dd44c2SDaniel Beauregard 			/* check for wrap */
53616dd44c2SDaniel Beauregard 			if ((dump_current + EL_BUFFER_RESERVE) >= trace_end) {
53716dd44c2SDaniel Beauregard 				dump_current = trace_start;
53816dd44c2SDaniel Beauregard 				wrapped = 1;
53916dd44c2SDaniel Beauregard 			} else if (wrapped) {
54016dd44c2SDaniel Beauregard 				/* Don't go past next. */
54116dd44c2SDaniel Beauregard 				if ((trace_start + ha->el_trace_desc->next) <=
54216dd44c2SDaniel Beauregard 				    dump_current) {
54316dd44c2SDaniel Beauregard 					break;
54416dd44c2SDaniel Beauregard 				}
54516dd44c2SDaniel Beauregard 			} else if (*dump_current == NULL) {
54616dd44c2SDaniel Beauregard 				break;
54716dd44c2SDaniel Beauregard 			}
54816dd44c2SDaniel Beauregard 		}
54916dd44c2SDaniel Beauregard 	}
55016dd44c2SDaniel Beauregard 	TRACE_BUFFER_UNLOCK(ha);
55116dd44c2SDaniel Beauregard }
55216dd44c2SDaniel Beauregard 
55316dd44c2SDaniel Beauregard /*
55416dd44c2SDaniel Beauregard  * ql_validate_trace_desc
55516dd44c2SDaniel Beauregard  *	 Ensures the extended logging trace descriptor is good
55616dd44c2SDaniel Beauregard  *
55716dd44c2SDaniel Beauregard  * Input:
55816dd44c2SDaniel Beauregard  *	ha:	adapter state pointer.
55916dd44c2SDaniel Beauregard  *
56016dd44c2SDaniel Beauregard  * Returns:
56116dd44c2SDaniel Beauregard  *	ql local function return status code.
56216dd44c2SDaniel Beauregard  */
56316dd44c2SDaniel Beauregard int
56416dd44c2SDaniel Beauregard ql_validate_trace_desc(ql_adapter_state_t *ha)
56516dd44c2SDaniel Beauregard {
56616dd44c2SDaniel Beauregard 	int	rval = DDI_SUCCESS;
56716dd44c2SDaniel Beauregard 
56816dd44c2SDaniel Beauregard 	if (ha->el_trace_desc == NULL) {
56916dd44c2SDaniel Beauregard 		rval = DDI_FAILURE;
57016dd44c2SDaniel Beauregard 	} else if (ha->el_trace_desc->trace_buffer == NULL) {
57116dd44c2SDaniel Beauregard 		rval = DDI_FAILURE;
57216dd44c2SDaniel Beauregard 	}
57316dd44c2SDaniel Beauregard 	return (rval);
57416dd44c2SDaniel Beauregard }
57516dd44c2SDaniel Beauregard 
57616dd44c2SDaniel Beauregard /*
57716dd44c2SDaniel Beauregard  * ql_find_trace_start
57816dd44c2SDaniel Beauregard  *	 Locate the oldest extended logging trace entry.
57916dd44c2SDaniel Beauregard  *
58016dd44c2SDaniel Beauregard  * Input:
58116dd44c2SDaniel Beauregard  *	ha:	adapter state pointer.
58216dd44c2SDaniel Beauregard  *
58316dd44c2SDaniel Beauregard  * Returns:
58416dd44c2SDaniel Beauregard  *	Pointer to a string.
58516dd44c2SDaniel Beauregard  *
58616dd44c2SDaniel Beauregard  * Context:
58716dd44c2SDaniel Beauregard  *	Kernel/Interrupt context.
58816dd44c2SDaniel Beauregard  */
58916dd44c2SDaniel Beauregard char *
59016dd44c2SDaniel Beauregard ql_find_trace_start(ql_adapter_state_t *ha)
59116dd44c2SDaniel Beauregard {
59216dd44c2SDaniel Beauregard 	char	*trace_start = 0;
59316dd44c2SDaniel Beauregard 	char	*trace_next  = 0;
59416dd44c2SDaniel Beauregard 
59516dd44c2SDaniel Beauregard 	trace_next = ha->el_trace_desc->trace_buffer + ha->el_trace_desc->next;
59616dd44c2SDaniel Beauregard 
59716dd44c2SDaniel Beauregard 	/*
59816dd44c2SDaniel Beauregard 	 * if the buffer has not wrapped next will point at a null so
59916dd44c2SDaniel Beauregard 	 * start is the beginning of the buffer.  if next points at a char
60016dd44c2SDaniel Beauregard 	 * then we must traverse the buffer until a null is detected and
60116dd44c2SDaniel Beauregard 	 * that will be the beginning of the oldest whole object in the buffer
60216dd44c2SDaniel Beauregard 	 * which is the start.
60316dd44c2SDaniel Beauregard 	 */
60416dd44c2SDaniel Beauregard 
60516dd44c2SDaniel Beauregard 	if ((trace_next + EL_BUFFER_RESERVE) >=
60616dd44c2SDaniel Beauregard 	    (ha->el_trace_desc->trace_buffer +
60716dd44c2SDaniel Beauregard 	    ha->el_trace_desc->trace_buffer_size)) {
60816dd44c2SDaniel Beauregard 		trace_start = ha->el_trace_desc->trace_buffer;
60916dd44c2SDaniel Beauregard 	} else if (*trace_next != NULL) {
61016dd44c2SDaniel Beauregard 		trace_start = trace_next + (strlen(trace_next) + 1);
61116dd44c2SDaniel Beauregard 	} else {
61216dd44c2SDaniel Beauregard 		trace_start = ha->el_trace_desc->trace_buffer;
61316dd44c2SDaniel Beauregard 	}
61416dd44c2SDaniel Beauregard 	return (trace_start);
61516dd44c2SDaniel Beauregard }
616