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 
22*4c3888b8SHans Rosenfeld /* Copyright 2015 QLogic Corporation */
23fcf3ce44SJohn Forte 
24fcf3ce44SJohn Forte /*
25*4c3888b8SHans Rosenfeld  * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
26fcf3ce44SJohn Forte  */
27fcf3ce44SJohn Forte 
28fcf3ce44SJohn Forte /*
29fcf3ce44SJohn Forte  * Qlogic ISP22xx/ISP23xx/ISP24xx FCA driver source
30fcf3ce44SJohn Forte  *
31fcf3ce44SJohn Forte  * ***********************************************************************
32fcf3ce44SJohn Forte  * *									**
33fcf3ce44SJohn Forte  * *				NOTICE					**
34*4c3888b8SHans Rosenfeld  * *		COPYRIGHT (C) 1996-2015 QLOGIC CORPORATION		**
35fcf3ce44SJohn Forte  * *			ALL RIGHTS RESERVED				**
36fcf3ce44SJohn Forte  * *									**
37fcf3ce44SJohn Forte  * ***********************************************************************
38fcf3ce44SJohn Forte  *
39fcf3ce44SJohn Forte  */
40fcf3ce44SJohn Forte 
41fcf3ce44SJohn Forte #include <ql_apps.h>
42fcf3ce44SJohn Forte #include <ql_api.h>
43fcf3ce44SJohn Forte #include <ql_debug.h>
44fcf3ce44SJohn Forte 
45fcf3ce44SJohn Forte static int ql_flash_errlog_store(ql_adapter_state_t *, uint32_t *);
46fcf3ce44SJohn Forte 
47fcf3ce44SJohn Forte /*
48fcf3ce44SJohn Forte  * Global Data.
49fcf3ce44SJohn Forte  */
50fcf3ce44SJohn Forte uint32_t	el_message_number = 0;
51fcf3ce44SJohn Forte uint32_t	ql_enable_ellock = 0;
52fcf3ce44SJohn Forte 
53c92b35bbSToomas Soome extern int	getpcstack(pc_t *, int);
54fcf3ce44SJohn Forte extern char	*kobj_getsymname(uintptr_t, ulong_t *);
55fcf3ce44SJohn Forte 
56fcf3ce44SJohn Forte /*
57fcf3ce44SJohn Forte  * ql_dump_buffer
58fcf3ce44SJohn Forte  *	 Outputs buffer.
59fcf3ce44SJohn Forte  *
60fcf3ce44SJohn Forte  * Input:
61fcf3ce44SJohn Forte  *	 string:	Null terminated string (no newline at end).
62fcf3ce44SJohn Forte  *	 buffer:	buffer address.
63fcf3ce44SJohn Forte  *	 wd_size:	word size 8 bits
64fcf3ce44SJohn Forte  *	 count:		number of words.
65fcf3ce44SJohn Forte  */
66fcf3ce44SJohn Forte void
ql_dump_buffer(uint8_t * b8,uint8_t wd_size,uint32_t count)67fcf3ce44SJohn Forte ql_dump_buffer(uint8_t *b8, uint8_t wd_size, uint32_t count)
68fcf3ce44SJohn Forte {
69fcf3ce44SJohn Forte 	uint32_t	cnt;
70fcf3ce44SJohn Forte 	char		str[256], *sp;
71fcf3ce44SJohn Forte 	uint32_t	*b32 = (uint32_t *)b8;
72fcf3ce44SJohn Forte 	uint16_t	*b16 = (uint16_t *)b8;
73fcf3ce44SJohn Forte 
74fcf3ce44SJohn Forte 	sp = &str[0];
75fcf3ce44SJohn Forte 
76fcf3ce44SJohn Forte 	switch (wd_size) {
77fcf3ce44SJohn Forte 	case 32:
78fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "         0         4         8         C\n");
79fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "----------------------------------------\n");
80fcf3ce44SJohn Forte 
81fcf3ce44SJohn Forte 		for (cnt = 1; cnt <= count; cnt++) {
82fcf3ce44SJohn Forte 			(void) sprintf(sp, "%10x", *b32++);
83fcf3ce44SJohn Forte 			sp += 10;
84fcf3ce44SJohn Forte 			if (cnt % 4 == 0) {
85fcf3ce44SJohn Forte 				cmn_err(CE_CONT, "%s\n", str);
86fcf3ce44SJohn Forte 				sp = &str[0];
87fcf3ce44SJohn Forte 			}
88fcf3ce44SJohn Forte 		}
89fcf3ce44SJohn Forte 		break;
90fcf3ce44SJohn Forte 	case 16:
91fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "     0     2     4     6     8     A     C"
92fcf3ce44SJohn Forte 		    "     E\n");
93fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "------------------------------------------"
94fcf3ce44SJohn Forte 		    "------\n");
95fcf3ce44SJohn Forte 
96fcf3ce44SJohn Forte 		for (cnt = 1; cnt <= count; cnt++) {
97fcf3ce44SJohn Forte 			(void) sprintf(sp, "%6x", *b16++);
98fcf3ce44SJohn Forte 			sp += 6;
99fcf3ce44SJohn Forte 			if (cnt % 8 == 0) {
100fcf3ce44SJohn Forte 				cmn_err(CE_CONT, "%s\n", str);
101fcf3ce44SJohn Forte 				sp = &str[0];
102fcf3ce44SJohn Forte 			}
103fcf3ce44SJohn Forte 		}
104fcf3ce44SJohn Forte 		break;
105fcf3ce44SJohn Forte 	case 8:
106fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "   0   1   2   3   4   5   6   7   8   9   "
107fcf3ce44SJohn Forte 		    "A   B   C   D   E   F\n");
108fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "---------------------------------"
109fcf3ce44SJohn Forte 		    "-------------------------------\n");
110fcf3ce44SJohn Forte 
111fcf3ce44SJohn Forte 		for (cnt = 1; cnt <= count; cnt++) {
112fcf3ce44SJohn Forte 			(void) sprintf(sp, "%4x", *b8++);
113fcf3ce44SJohn Forte 			sp += 4;
114fcf3ce44SJohn Forte 			if (cnt % 16 == 0) {
115fcf3ce44SJohn Forte 				cmn_err(CE_CONT, "%s\n", str);
116fcf3ce44SJohn Forte 				sp = &str[0];
117fcf3ce44SJohn Forte 			}
118fcf3ce44SJohn Forte 		}
119fcf3ce44SJohn Forte 		break;
120fcf3ce44SJohn Forte 	default:
121fcf3ce44SJohn Forte 		break;
122fcf3ce44SJohn Forte 	}
123fcf3ce44SJohn Forte 	if (sp != &str[0]) {
124fcf3ce44SJohn Forte 		cmn_err(CE_CONT, "%s\n", str);
125fcf3ce44SJohn Forte 	}
126fcf3ce44SJohn Forte }
127fcf3ce44SJohn Forte 
128fcf3ce44SJohn Forte /*
129fcf3ce44SJohn Forte  * ql_el_msg
130fcf3ce44SJohn Forte  *	Extended logging message
131fcf3ce44SJohn Forte  *
132fcf3ce44SJohn Forte  * Input:
133fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
134fcf3ce44SJohn Forte  *	fn:	function name.
135fcf3ce44SJohn Forte  *	ce:	level
136fcf3ce44SJohn Forte  *	...:	Variable argument list.
137fcf3ce44SJohn Forte  *
138fcf3ce44SJohn Forte  * Context:
139fcf3ce44SJohn Forte  *	Kernel/Interrupt context.
140fcf3ce44SJohn Forte  */
141fcf3ce44SJohn Forte void
ql_el_msg(ql_adapter_state_t * ha,const char * fn,int ce,...)142fcf3ce44SJohn Forte ql_el_msg(ql_adapter_state_t *ha, const char *fn, int ce, ...)
143fcf3ce44SJohn Forte {
144*4c3888b8SHans Rosenfeld 	char		*s, *fmt, *fmt1;
145*4c3888b8SHans Rosenfeld 	/*
146*4c3888b8SHans Rosenfeld 	 * EL_BUFFER_RESERVE 256 is the max # of bytes
147*4c3888b8SHans Rosenfeld 	 * that driver's log could be collected.
148*4c3888b8SHans Rosenfeld 	 * add 3 more buytes for safely maniplulation.
149*4c3888b8SHans Rosenfeld 	 */
150*4c3888b8SHans Rosenfeld 	char			buf[EL_BUFFER_RESERVE + 3];
151*4c3888b8SHans Rosenfeld 	char			buf1[QL_LOG_LENGTH];
152*4c3888b8SHans Rosenfeld 	size_t			tmp, rval, rval1, left;
153*4c3888b8SHans Rosenfeld 	va_list			vl;
154*4c3888b8SHans Rosenfeld 	ql_trace_desc_t		*desc;
155*4c3888b8SHans Rosenfeld 	ql_trace_entry_t	*entry;
156*4c3888b8SHans Rosenfeld 	uint32_t		cindex, count;
157*4c3888b8SHans Rosenfeld 	timespec_t		time;
158*4c3888b8SHans Rosenfeld 
159*4c3888b8SHans Rosenfeld 	if (ha == NULL && (ha = ql_hba.first->base_address) == NULL) {
160*4c3888b8SHans Rosenfeld 		return;
161*4c3888b8SHans Rosenfeld 	}
162*4c3888b8SHans Rosenfeld 
163*4c3888b8SHans Rosenfeld 	desc = ha->ql_trace_desc;
164fcf3ce44SJohn Forte 
165*4c3888b8SHans Rosenfeld 	(void) bzero((void *)&buf[0], EL_BUFFER_RESERVE + 3);
166*4c3888b8SHans Rosenfeld 	fmt1 = &buf[0];
167*4c3888b8SHans Rosenfeld 
168*4c3888b8SHans Rosenfeld 	TRACE_BUFFER_LOCK(ha);
16916dd44c2SDaniel Beauregard 
170*4c3888b8SHans Rosenfeld 	/* locate the entry to be filled out */
171*4c3888b8SHans Rosenfeld 	cindex = desc->nindex;
172*4c3888b8SHans Rosenfeld 	entry = &desc->trace_buffer[cindex];
17316dd44c2SDaniel Beauregard 
174*4c3888b8SHans Rosenfeld 	count = desc->count;
175*4c3888b8SHans Rosenfeld 
176*4c3888b8SHans Rosenfeld 	desc->end = desc->nindex;
177*4c3888b8SHans Rosenfeld 	desc->nindex++;
178*4c3888b8SHans Rosenfeld 
179*4c3888b8SHans Rosenfeld 	if (desc->nindex == desc->nentries) {
180*4c3888b8SHans Rosenfeld 		desc->nindex = 0;
181*4c3888b8SHans Rosenfeld 	}
182*4c3888b8SHans Rosenfeld 
183*4c3888b8SHans Rosenfeld 	if (desc->csize < desc->nentries) {
184*4c3888b8SHans Rosenfeld 		desc->csize++;
185*4c3888b8SHans Rosenfeld 	} else {
18616dd44c2SDaniel Beauregard 		/*
187*4c3888b8SHans Rosenfeld 		 * once wrapped, csize is fixed.
188*4c3888b8SHans Rosenfeld 		 * so we have to adjust start point
18916dd44c2SDaniel Beauregard 		 */
190*4c3888b8SHans Rosenfeld 		desc->start = desc->nindex;
19116dd44c2SDaniel Beauregard 	}
19216dd44c2SDaniel Beauregard 
193*4c3888b8SHans Rosenfeld 	gethrestime(&time);
194*4c3888b8SHans Rosenfeld 
195*4c3888b8SHans Rosenfeld 	rval = snprintf(fmt1, (size_t)EL_BUFFER_RESERVE,
196*4c3888b8SHans Rosenfeld 	    QL_BANG "%d=>QEL %s(%d,%d,%d):: %s, ", count, QL_NAME,
197*4c3888b8SHans Rosenfeld 	    ha->instance, ha->vp_index, ha->pci_function_number, fn);
198*4c3888b8SHans Rosenfeld 
199*4c3888b8SHans Rosenfeld 	rval1 = rval;
200fcf3ce44SJohn Forte 
201*4c3888b8SHans Rosenfeld 	va_start(vl, ce);
202fcf3ce44SJohn Forte 	s = va_arg(vl, char *);
203fcf3ce44SJohn Forte 
204*4c3888b8SHans Rosenfeld 	fmt = fmt1 + rval;
205*4c3888b8SHans Rosenfeld 
206*4c3888b8SHans Rosenfeld 	tmp = vsnprintf(fmt,
207*4c3888b8SHans Rosenfeld 	    (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl);
208*4c3888b8SHans Rosenfeld 
209*4c3888b8SHans Rosenfeld 	va_end(vl);
210*4c3888b8SHans Rosenfeld 
211*4c3888b8SHans Rosenfeld 	rval += tmp;
212*4c3888b8SHans Rosenfeld 
213*4c3888b8SHans Rosenfeld 	if (rval > QL_LOG_LENGTH - 1) {
214*4c3888b8SHans Rosenfeld 		left = rval - (QL_LOG_LENGTH - 1);
215*4c3888b8SHans Rosenfeld 
216*4c3888b8SHans Rosenfeld 		/* store the remaining string */
217*4c3888b8SHans Rosenfeld 		(void) strncpy(buf1, fmt1 + (QL_LOG_LENGTH - 1), left);
218*4c3888b8SHans Rosenfeld 
219*4c3888b8SHans Rosenfeld 		(void) strncpy(entry->buf, fmt1, (QL_LOG_LENGTH - 1));
220*4c3888b8SHans Rosenfeld 		entry->buf[QL_LOG_LENGTH - 1] = '\n';
221*4c3888b8SHans Rosenfeld 
222*4c3888b8SHans Rosenfeld 		bcopy((void *)&time, (void *)&entry->hs_time,
223*4c3888b8SHans Rosenfeld 		    sizeof (timespec_t));
224*4c3888b8SHans Rosenfeld 
225fcf3ce44SJohn Forte 		/*
226*4c3888b8SHans Rosenfeld 		 * remaining msg will be stored in the nex entry
227*4c3888b8SHans Rosenfeld 		 * with same timestamp and same sequence number
228fcf3ce44SJohn Forte 		 */
229*4c3888b8SHans Rosenfeld 		cindex = desc->nindex;
230*4c3888b8SHans Rosenfeld 		entry = &desc->trace_buffer[cindex];
231fcf3ce44SJohn Forte 
232*4c3888b8SHans Rosenfeld 		desc->end = desc->nindex;
233*4c3888b8SHans Rosenfeld 		desc->nindex++;
234*4c3888b8SHans Rosenfeld 
235*4c3888b8SHans Rosenfeld 		if (desc->nindex == desc->nentries) {
236*4c3888b8SHans Rosenfeld 			desc->nindex = 0;
237*4c3888b8SHans Rosenfeld 		}
238*4c3888b8SHans Rosenfeld 
239*4c3888b8SHans Rosenfeld 		if (desc->csize < desc->nentries) {
240*4c3888b8SHans Rosenfeld 			desc->csize++;
241*4c3888b8SHans Rosenfeld 		} else {
242*4c3888b8SHans Rosenfeld 			desc->start = desc->nindex;
243*4c3888b8SHans Rosenfeld 		}
244*4c3888b8SHans Rosenfeld 
245*4c3888b8SHans Rosenfeld 		(void) strncpy(&entry->buf[0], fmt1, rval1);
246*4c3888b8SHans Rosenfeld 		(void) strncpy(&entry->buf[rval1], &buf1[0], left);
247*4c3888b8SHans Rosenfeld 		entry->buf[rval1 + left] = 0;
248*4c3888b8SHans Rosenfeld 
249*4c3888b8SHans Rosenfeld 		bcopy((void *)&time, (void *)&entry->hs_time,
250*4c3888b8SHans Rosenfeld 		    sizeof (timespec_t));
251*4c3888b8SHans Rosenfeld 
252*4c3888b8SHans Rosenfeld 		if (CFG_IST(ha, CFG_ENABLE_EXTENDED_LOGGING)) {
253*4c3888b8SHans Rosenfeld 			cmn_err(ce, fmt1);
254*4c3888b8SHans Rosenfeld 		}
255*4c3888b8SHans Rosenfeld 
256*4c3888b8SHans Rosenfeld 		desc->count++;
25716dd44c2SDaniel Beauregard 
25816dd44c2SDaniel Beauregard 		TRACE_BUFFER_UNLOCK(ha);
259*4c3888b8SHans Rosenfeld 		return;
26016dd44c2SDaniel Beauregard 	}
26116dd44c2SDaniel Beauregard 
262*4c3888b8SHans Rosenfeld 	desc->count++;
263*4c3888b8SHans Rosenfeld 	bcopy((void *)&time, (void *)&entry->hs_time,
264*4c3888b8SHans Rosenfeld 	    sizeof (timespec_t));
265*4c3888b8SHans Rosenfeld 
266*4c3888b8SHans Rosenfeld 	(void) strncpy(entry->buf, fmt1, sizeof (entry->buf));
267*4c3888b8SHans Rosenfeld 	entry->buf[rval] = 0;
268*4c3888b8SHans Rosenfeld 
269*4c3888b8SHans Rosenfeld 	TRACE_BUFFER_UNLOCK(ha);
270*4c3888b8SHans Rosenfeld 
2715dfd244aSDaniel Beauregard 	if (CFG_IST(ha, CFG_ENABLE_EXTENDED_LOGGING)) {
272*4c3888b8SHans Rosenfeld 		cmn_err(ce, fmt1);
27316dd44c2SDaniel Beauregard 	}
27416dd44c2SDaniel Beauregard }
27516dd44c2SDaniel Beauregard 
27616dd44c2SDaniel Beauregard /*
277*4c3888b8SHans Rosenfeld  * ql_dbg_msg
27816dd44c2SDaniel Beauregard  *	Extended logging message
27916dd44c2SDaniel Beauregard  *
28016dd44c2SDaniel Beauregard  * Input:
28116dd44c2SDaniel Beauregard  *	ha:	adapter state pointer.
28216dd44c2SDaniel Beauregard  *	fn:	function name.
28316dd44c2SDaniel Beauregard  *	ce:	level
28416dd44c2SDaniel Beauregard  *	...:	Variable argument list.
28516dd44c2SDaniel Beauregard  *
28616dd44c2SDaniel Beauregard  * Context:
28716dd44c2SDaniel Beauregard  *	Kernel/Interrupt context.
28816dd44c2SDaniel Beauregard  */
28916dd44c2SDaniel Beauregard void
ql_dbg_msg(ql_adapter_state_t * ha,const char * fn,int ce,...)290*4c3888b8SHans Rosenfeld ql_dbg_msg(ql_adapter_state_t *ha, const char *fn, int ce, ...)
29116dd44c2SDaniel Beauregard {
29216dd44c2SDaniel Beauregard 	uint32_t	el_msg_num;
29316dd44c2SDaniel Beauregard 	char		*s;
294*4c3888b8SHans Rosenfeld 	char		fmt[EL_BUFFER_RESERVE];
29516dd44c2SDaniel Beauregard 	va_list		vl;
29616dd44c2SDaniel Beauregard 
29716dd44c2SDaniel Beauregard 	va_start(vl, ce);
29816dd44c2SDaniel Beauregard 
29916dd44c2SDaniel Beauregard 	s = va_arg(vl, char *);
30016dd44c2SDaniel Beauregard 
30116dd44c2SDaniel Beauregard 	if (ql_enable_ellock) {
30216dd44c2SDaniel Beauregard 		/*
30316dd44c2SDaniel Beauregard 		 * Used when messages are *maybe* being lost.  Adds
30416dd44c2SDaniel Beauregard 		 * a unique number to the message to one can see if
30516dd44c2SDaniel Beauregard 		 * any messages have been dropped. NB: This slows
30616dd44c2SDaniel Beauregard 		 * down the driver, which may make the issue disappear.
30716dd44c2SDaniel Beauregard 		 */
30816dd44c2SDaniel Beauregard 		GLOBAL_EL_LOCK();
30916dd44c2SDaniel Beauregard 		el_msg_num = ++el_message_number;
31016dd44c2SDaniel Beauregard 		GLOBAL_EL_UNLOCK();
311*4c3888b8SHans Rosenfeld 		if (ha == NULL) {
312*4c3888b8SHans Rosenfeld 			(void) snprintf(fmt, EL_BUFFER_RESERVE, "QLP%d: %s, "
313*4c3888b8SHans Rosenfeld 			    "%s", el_msg_num, fn, s);
314*4c3888b8SHans Rosenfeld 		} else {
315*4c3888b8SHans Rosenfeld 			(void) snprintf(fmt, EL_BUFFER_RESERVE, "QLP%d: %s"
316*4c3888b8SHans Rosenfeld 			    "(%d,%d,%d): %s", el_msg_num, fn, ha->instance,
317*4c3888b8SHans Rosenfeld 			    ha->vp_index, ha->pci_function_number, s);
318*4c3888b8SHans Rosenfeld 		}
31916dd44c2SDaniel Beauregard 	} else {
320*4c3888b8SHans Rosenfeld 		if (ha == NULL) {
321*4c3888b8SHans Rosenfeld 			(void) snprintf(fmt, EL_BUFFER_RESERVE, "QLP: %s, "
322*4c3888b8SHans Rosenfeld 			    "%s", fn, s);
323*4c3888b8SHans Rosenfeld 		} else {
324*4c3888b8SHans Rosenfeld 			(void) snprintf(fmt, EL_BUFFER_RESERVE, "QLP: %s"
325*4c3888b8SHans Rosenfeld 			    "(%d,%d,%d): %s", fn, ha->instance, ha->vp_index,
326*4c3888b8SHans Rosenfeld 			    ha->pci_function_number, s);
327*4c3888b8SHans Rosenfeld 		}
328fcf3ce44SJohn Forte 	}
329fcf3ce44SJohn Forte 
330fcf3ce44SJohn Forte 	vcmn_err(ce, fmt, vl);
331fcf3ce44SJohn Forte 
332fcf3ce44SJohn Forte 	va_end(vl);
333fcf3ce44SJohn Forte }
334fcf3ce44SJohn Forte 
335fcf3ce44SJohn Forte /*
336fcf3ce44SJohn Forte  * ql_stacktrace
337fcf3ce44SJohn Forte  *	Prints out current stack
338fcf3ce44SJohn Forte  *
339fcf3ce44SJohn Forte  * Input:
340fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
341fcf3ce44SJohn Forte  *
342fcf3ce44SJohn Forte  * Context:
343fcf3ce44SJohn Forte  *	Kernel/Interrupt context.
344fcf3ce44SJohn Forte  */
345fcf3ce44SJohn Forte void
ql_stacktrace(ql_adapter_state_t * ha)346fcf3ce44SJohn Forte ql_stacktrace(ql_adapter_state_t *ha)
347fcf3ce44SJohn Forte {
348fcf3ce44SJohn Forte 	int	depth, i;
349fcf3ce44SJohn Forte 	pc_t	pcstack[DEBUG_STK_DEPTH];
350fcf3ce44SJohn Forte 	char	*sym = NULL;
351fcf3ce44SJohn Forte 	ulong_t	off;
352fcf3ce44SJohn Forte 
353fcf3ce44SJohn Forte 	depth = getpcstack(&pcstack[0], DEBUG_STK_DEPTH);
354fcf3ce44SJohn Forte 
355fcf3ce44SJohn Forte 	cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance,
356fcf3ce44SJohn Forte 	    ha->vp_index);
357fcf3ce44SJohn Forte 	for (i = 0; i < MIN(depth, DEBUG_STK_DEPTH); i++) {
358fcf3ce44SJohn Forte 		sym = kobj_getsymname((uintptr_t)pcstack[i], &off);
359fcf3ce44SJohn Forte 
360fcf3ce44SJohn Forte 		if (sym == NULL) {
361fcf3ce44SJohn Forte 			cmn_err(CE_CONT, "%s(%d,%d): sym is NULL\n", QL_NAME,
362fcf3ce44SJohn Forte 			    ha->instance, ha->vp_index);
363fcf3ce44SJohn Forte 		} else {
364fcf3ce44SJohn Forte 			cmn_err(CE_CONT, "%s(%d,%d): %s+%lx\n", QL_NAME,
365fcf3ce44SJohn Forte 			    ha->instance, ha->vp_index, sym ? sym : "?", off);
366fcf3ce44SJohn Forte 		}
367fcf3ce44SJohn Forte 	}
368fcf3ce44SJohn Forte 	cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance,
369fcf3ce44SJohn Forte 	    ha->vp_index);
370fcf3ce44SJohn Forte }
371fcf3ce44SJohn Forte 
372fcf3ce44SJohn Forte /*
373fcf3ce44SJohn Forte  * ql_flash_errlog
374fcf3ce44SJohn Forte  *	Adds error to flash error log.
375fcf3ce44SJohn Forte  *	Entry Layout:
376fcf3ce44SJohn Forte  *		uint32_t TimeStamp;
377fcf3ce44SJohn Forte  *		uint16_t CodeData[4];
378fcf3ce44SJohn Forte  *
379fcf3ce44SJohn Forte  * Input:
380fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
381fcf3ce44SJohn Forte  *	code:	Error code
382fcf3ce44SJohn Forte  *	d1-d3:	Error code data
383fcf3ce44SJohn Forte  *
384fcf3ce44SJohn Forte  * Returns:
385fcf3ce44SJohn Forte  *	ql local function return status code.
386fcf3ce44SJohn Forte  *
387fcf3ce44SJohn Forte  * Context:
388fcf3ce44SJohn Forte  *	Kernel/Interrupt context.
389fcf3ce44SJohn Forte  */
390fcf3ce44SJohn Forte int
ql_flash_errlog(ql_adapter_state_t * ha,uint16_t code,uint16_t d1,uint16_t d2,uint16_t d3)391fcf3ce44SJohn Forte ql_flash_errlog(ql_adapter_state_t *ha, uint16_t code, uint16_t d1,
392fcf3ce44SJohn Forte     uint16_t d2, uint16_t d3)
393fcf3ce44SJohn Forte {
394fcf3ce44SJohn Forte 	char		*s;
395fcf3ce44SJohn Forte 	uint32_t	marker[2], fdata[2], faddr;
396fcf3ce44SJohn Forte 	int		rval;
397fcf3ce44SJohn Forte 
398*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "started\n");
399fcf3ce44SJohn Forte 
400fcf3ce44SJohn Forte 	if (ha->flash_errlog_start == 0) {
401fcf3ce44SJohn Forte 		return (QL_NOT_SUPPORTED);
402fcf3ce44SJohn Forte 	}
403fcf3ce44SJohn Forte 
404fcf3ce44SJohn Forte 	EL(ha, "code=%xh, d1=%xh, d2=%xh, d3=%xh\n", code, d1, d2, d3);
405fcf3ce44SJohn Forte 
406fcf3ce44SJohn Forte 	/*
407fcf3ce44SJohn Forte 	 * If marker not already found, locate or write marker.
408fcf3ce44SJohn Forte 	 */
409fcf3ce44SJohn Forte 	if (!(ha->flags & FLASH_ERRLOG_MARKER)) {
410fcf3ce44SJohn Forte 
411fcf3ce44SJohn Forte 		/* Create marker. */
412fcf3ce44SJohn Forte 		marker[0] = CHAR_TO_LONG(ha->fw_subminor_version,
413fcf3ce44SJohn Forte 		    ha->fw_minor_version, ha->fw_major_version, 'S');
414fcf3ce44SJohn Forte 
415fcf3ce44SJohn Forte 		/*
416fcf3ce44SJohn Forte 		 * Version should be of the format: YYYYMMDD-v.vv
417fcf3ce44SJohn Forte 		 */
418fcf3ce44SJohn Forte 		if ((strlen(QL_VERSION) > 9) && (QL_VERSION[8] == '-')) {
419fcf3ce44SJohn Forte 			s = &QL_VERSION[9];
420fcf3ce44SJohn Forte 		} else {
421fcf3ce44SJohn Forte 			s = QL_VERSION;
422fcf3ce44SJohn Forte 		}
423fcf3ce44SJohn Forte 
424fcf3ce44SJohn Forte 		for (marker[1] = 0; *s != '\0'; s++) {
425fcf3ce44SJohn Forte 			if (*s >= '0' && *s <= '9') {
426fcf3ce44SJohn Forte 				marker[1] <<= 4;
427fcf3ce44SJohn Forte 				marker[1] |= *s - '0';
428fcf3ce44SJohn Forte 			} else if (*s != '.') {
429fcf3ce44SJohn Forte 				break;
430fcf3ce44SJohn Forte 			}
431fcf3ce44SJohn Forte 		}
432fcf3ce44SJohn Forte 
433fcf3ce44SJohn Forte 		/* Locate marker. */
434fcf3ce44SJohn Forte 		ha->flash_errlog_ptr = ha->flash_errlog_start;
435fcf3ce44SJohn Forte 		for (;;) {
4365dfd244aSDaniel Beauregard 			faddr = ha->flash_data_addr | ha->flash_errlog_ptr;
437fcf3ce44SJohn Forte 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[0]);
438fcf3ce44SJohn Forte 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[1]);
439fcf3ce44SJohn Forte 			if (fdata[0] == 0xffffffff && fdata[1] == 0xffffffff) {
440fcf3ce44SJohn Forte 				break;
441fcf3ce44SJohn Forte 			}
442fcf3ce44SJohn Forte 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[0]);
443fcf3ce44SJohn Forte 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[1]);
444fcf3ce44SJohn Forte 			ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE;
445fcf3ce44SJohn Forte 			if (ha->flash_errlog_ptr >=
446fcf3ce44SJohn Forte 			    ha->flash_errlog_start + FLASH_ERRLOG_SIZE) {
447fcf3ce44SJohn Forte 				EL(ha, "log full\n");
448fcf3ce44SJohn Forte 				return (QL_MEMORY_FULL);
449fcf3ce44SJohn Forte 			}
450fcf3ce44SJohn Forte 			if (fdata[0] == marker[0] && fdata[1] == marker[1]) {
451fcf3ce44SJohn Forte 				ha->flags |= FLASH_ERRLOG_MARKER;
452fcf3ce44SJohn Forte 				break;
453fcf3ce44SJohn Forte 			}
454fcf3ce44SJohn Forte 		}
455fcf3ce44SJohn Forte 
456fcf3ce44SJohn Forte 		/* No marker, write it. */
457fcf3ce44SJohn Forte 		if (!(ha->flags & FLASH_ERRLOG_MARKER)) {
458fcf3ce44SJohn Forte 			ha->flags |= FLASH_ERRLOG_MARKER;
459fcf3ce44SJohn Forte 			rval = ql_flash_errlog_store(ha, marker);
460fcf3ce44SJohn Forte 			if (rval != QL_SUCCESS) {
461fcf3ce44SJohn Forte 				EL(ha, "failed marker write=%xh\n", rval);
462fcf3ce44SJohn Forte 				return (rval);
463fcf3ce44SJohn Forte 			}
464fcf3ce44SJohn Forte 		}
465fcf3ce44SJohn Forte 	}
466fcf3ce44SJohn Forte 
467fcf3ce44SJohn Forte 	/*
468fcf3ce44SJohn Forte 	 * Store error.
469fcf3ce44SJohn Forte 	 */
470fcf3ce44SJohn Forte 	fdata[0] = SHORT_TO_LONG(d1, code);
471fcf3ce44SJohn Forte 	fdata[1] = SHORT_TO_LONG(d3, d2);
472fcf3ce44SJohn Forte 	rval = ql_flash_errlog_store(ha, fdata);
473fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
474fcf3ce44SJohn Forte 		EL(ha, "failed error write=%xh\n", rval);
475fcf3ce44SJohn Forte 	} else {
476fcf3ce44SJohn Forte 		/*EMPTY*/
477*4c3888b8SHans Rosenfeld 		QL_PRINT_3(ha, "done\n");
478fcf3ce44SJohn Forte 	}
479fcf3ce44SJohn Forte 
480fcf3ce44SJohn Forte 	return (rval);
481fcf3ce44SJohn Forte }
482fcf3ce44SJohn Forte 
483fcf3ce44SJohn Forte /*
484fcf3ce44SJohn Forte  * ql_flash_errlog_store
485fcf3ce44SJohn Forte  *	Stores error to flash.
486fcf3ce44SJohn Forte  *	Entry Layout:
487fcf3ce44SJohn Forte  *		uint32_t TimeStamp;
488fcf3ce44SJohn Forte  *		uint16_t CodeData[4];
489fcf3ce44SJohn Forte  *
490fcf3ce44SJohn Forte  * Input:
491fcf3ce44SJohn Forte  *	ha:			adapter state pointer.
492fcf3ce44SJohn Forte  *	fdata:			Error code plus data.
493fcf3ce44SJohn Forte  *	ha->flash_errlog_ptr:	Current Flash error pointer.
494fcf3ce44SJohn Forte  *
495fcf3ce44SJohn Forte  * Output:
496fcf3ce44SJohn Forte  *	ha->flash_errlog_ptr:	updated pointer.
497fcf3ce44SJohn Forte  *
498fcf3ce44SJohn Forte  * Returns:
499fcf3ce44SJohn Forte  *	ql local function return status code.
500fcf3ce44SJohn Forte  *
501fcf3ce44SJohn Forte  * Context:
502fcf3ce44SJohn Forte  *	Kernel/Interrupt context.
503fcf3ce44SJohn Forte  */
504fcf3ce44SJohn Forte static int
ql_flash_errlog_store(ql_adapter_state_t * ha,uint32_t * fdata)505fcf3ce44SJohn Forte ql_flash_errlog_store(ql_adapter_state_t *ha, uint32_t *fdata)
506fcf3ce44SJohn Forte {
5075dfd244aSDaniel Beauregard 	int		rval;
508fcf3ce44SJohn Forte 	uint64_t	time;
509fcf3ce44SJohn Forte 	uint32_t	d1, d2, faddr;
510fcf3ce44SJohn Forte 
511*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "started\n");
512fcf3ce44SJohn Forte 
513fcf3ce44SJohn Forte 	/* Locate first empty entry */
514fcf3ce44SJohn Forte 	for (;;) {
515fcf3ce44SJohn Forte 		if (ha->flash_errlog_ptr >=
516fcf3ce44SJohn Forte 		    ha->flash_errlog_start + FLASH_ERRLOG_SIZE) {
517fcf3ce44SJohn Forte 			EL(ha, "log full\n");
518fcf3ce44SJohn Forte 			return (QL_MEMORY_FULL);
519fcf3ce44SJohn Forte 		}
520fcf3ce44SJohn Forte 
5215dfd244aSDaniel Beauregard 		faddr = ha->flash_data_addr | ha->flash_errlog_ptr;
522fcf3ce44SJohn Forte 		ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE;
523fcf3ce44SJohn Forte 		(void) ql_24xx_read_flash(ha, faddr, &d1);
524fcf3ce44SJohn Forte 		(void) ql_24xx_read_flash(ha, faddr + 1, &d2);
525fcf3ce44SJohn Forte 		if (d1 == 0xffffffff && d2 == 0xffffffff) {
526fcf3ce44SJohn Forte 			(void) drv_getparm(TIME, &time);
527fcf3ce44SJohn Forte 
528fcf3ce44SJohn Forte 			/* Enable flash write. */
5295dfd244aSDaniel Beauregard 			if ((rval = ql_24xx_unprotect_flash(ha)) !=
5305dfd244aSDaniel Beauregard 			    QL_SUCCESS) {
5315dfd244aSDaniel Beauregard 				EL(ha, "unprotect_flash failed, rval=%xh\n",
5325dfd244aSDaniel Beauregard 				    rval);
5335dfd244aSDaniel Beauregard 				return (rval);
5345dfd244aSDaniel Beauregard 			}
535fcf3ce44SJohn Forte 
536fcf3ce44SJohn Forte 			(void) ql_24xx_write_flash(ha, faddr++, LSD(time));
537fcf3ce44SJohn Forte 			(void) ql_24xx_write_flash(ha, faddr++, MSD(time));
538fcf3ce44SJohn Forte 			(void) ql_24xx_write_flash(ha, faddr++, *fdata++);
539fcf3ce44SJohn Forte 			(void) ql_24xx_write_flash(ha, faddr++, *fdata);
540fcf3ce44SJohn Forte 
541fcf3ce44SJohn Forte 			/* Enable flash write-protection. */
542fcf3ce44SJohn Forte 			ql_24xx_protect_flash(ha);
543fcf3ce44SJohn Forte 			break;
544fcf3ce44SJohn Forte 		}
545fcf3ce44SJohn Forte 	}
546fcf3ce44SJohn Forte 
547*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "done\n");
548fcf3ce44SJohn Forte 
549fcf3ce44SJohn Forte 	return (QL_SUCCESS);
550fcf3ce44SJohn Forte }
551