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 /* Copyright 2008 QLogic Corporation */
23 
24 /*
25  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 #pragma ident	"Copyright 2008 QLogic Corporation; ql_debug.c"
30 
31 /*
32  * Qlogic ISP22xx/ISP23xx/ISP24xx FCA driver source
33  *
34  * ***********************************************************************
35  * *									**
36  * *				NOTICE					**
37  * *		COPYRIGHT (C) 1996-2008 QLOGIC CORPORATION		**
38  * *			ALL RIGHTS RESERVED				**
39  * *									**
40  * ***********************************************************************
41  *
42  */
43 
44 #include <ql_apps.h>
45 #include <ql_api.h>
46 #include <ql_debug.h>
47 
48 static int ql_flash_errlog_store(ql_adapter_state_t *, uint32_t *);
49 
50 /*
51  * Global Data.
52  */
53 uint32_t	el_message_number = 0;
54 uint32_t	ql_enable_ellock = 0;
55 
56 extern int 	getpcstack(pc_t *, int);
57 extern char	*kobj_getsymname(uintptr_t, ulong_t *);
58 
59 /*
60  * ql_dump_buffer
61  *	 Outputs buffer.
62  *
63  * Input:
64  *	 string:	Null terminated string (no newline at end).
65  *	 buffer:	buffer address.
66  *	 wd_size:	word size 8 bits
67  *	 count:		number of words.
68  */
69 void
70 ql_dump_buffer(uint8_t *b8, uint8_t wd_size, uint32_t count)
71 {
72 	uint32_t	cnt;
73 	char		str[256], *sp;
74 	uint32_t	*b32 = (uint32_t *)b8;
75 	uint16_t	*b16 = (uint16_t *)b8;
76 
77 	sp = &str[0];
78 
79 	switch (wd_size) {
80 	case 32:
81 		cmn_err(CE_CONT, "         0         4         8         C\n");
82 		cmn_err(CE_CONT, "----------------------------------------\n");
83 
84 		for (cnt = 1; cnt <= count; cnt++) {
85 			(void) sprintf(sp, "%10x", *b32++);
86 			sp += 10;
87 			if (cnt % 4 == 0) {
88 				cmn_err(CE_CONT, "%s\n", str);
89 				sp = &str[0];
90 			}
91 		}
92 		break;
93 	case 16:
94 		cmn_err(CE_CONT, "     0     2     4     6     8     A     C"
95 		    "     E\n");
96 		cmn_err(CE_CONT, "------------------------------------------"
97 		    "------\n");
98 
99 		for (cnt = 1; cnt <= count; cnt++) {
100 			(void) sprintf(sp, "%6x", *b16++);
101 			sp += 6;
102 			if (cnt % 8 == 0) {
103 				cmn_err(CE_CONT, "%s\n", str);
104 				sp = &str[0];
105 			}
106 		}
107 		break;
108 	case 8:
109 		cmn_err(CE_CONT, "   0   1   2   3   4   5   6   7   8   9   "
110 		    "A   B   C   D   E   F\n");
111 		cmn_err(CE_CONT, "---------------------------------"
112 		    "-------------------------------\n");
113 
114 		for (cnt = 1; cnt <= count; cnt++) {
115 			(void) sprintf(sp, "%4x", *b8++);
116 			sp += 4;
117 			if (cnt % 16 == 0) {
118 				cmn_err(CE_CONT, "%s\n", str);
119 				sp = &str[0];
120 			}
121 		}
122 		break;
123 	default:
124 		break;
125 	}
126 	if (sp != &str[0]) {
127 		cmn_err(CE_CONT, "%s\n", str);
128 	}
129 }
130 
131 /*
132  * ql_el_msg
133  *	Extended logging message
134  *
135  * Input:
136  *	ha:	adapter state pointer.
137  *	fn:	function name.
138  *	ce:	level
139  *	...:	Variable argument list.
140  *
141  * Context:
142  *	Kernel/Interrupt context.
143  */
144 void
145 ql_el_msg(ql_adapter_state_t *ha, const char *fn, int ce, ...)
146 {
147 	uint32_t	el_msg_num;
148 	char		*s, fmt[EL_BUF_LEN];
149 	va_list		vl;
150 
151 	va_start(vl, ce);
152 
153 	s = va_arg(vl, char *);
154 
155 	if (ql_enable_ellock) {
156 		/*
157 		 * Used when messages are *maybe* being lost.  Adds
158 		 * a unique number to the message to one can see if
159 		 * any messages have been dropped. NB: This slows
160 		 * down the driver, which may make the issue disappear.
161 		 */
162 		GLOBAL_EL_LOCK();
163 		el_msg_num = ++el_message_number;
164 		GLOBAL_EL_UNLOCK();
165 
166 		ha == NULL ?
167 		    (void) snprintf(fmt, EL_BUF_LEN, "QLP%d: %s %s, %s",
168 		    el_msg_num, QL_NAME, fn, s) :
169 		    (void) snprintf(fmt, EL_BUF_LEN, QL_BANG "QEL%d %s(%d,%d)"
170 		    ": %s, %s", el_msg_num, QL_NAME, ha->instance,
171 		    ha->vp_index, fn, s);
172 	} else {
173 		ha == NULL ?
174 		    (void) snprintf(fmt, EL_BUF_LEN, "QLP: %s %s, %s",
175 		    QL_NAME, fn, s) :
176 		    (void) snprintf(fmt, EL_BUF_LEN, QL_BANG "QEL %s(%d,%d): "
177 		    "%s, %s", QL_NAME, ha->instance, ha->vp_index, fn, s);
178 	}
179 
180 	vcmn_err(ce, fmt, vl);
181 
182 	va_end(vl);
183 }
184 
185 /*
186  * ql_stacktrace
187  *	Prints out current stack
188  *
189  * Input:
190  *	ha:	adapter state pointer.
191  *
192  * Context:
193  *	Kernel/Interrupt context.
194  */
195 void
196 ql_stacktrace(ql_adapter_state_t *ha)
197 {
198 	int	depth, i;
199 	pc_t	pcstack[DEBUG_STK_DEPTH];
200 	char	*sym = NULL;
201 	ulong_t	off;
202 
203 	depth = getpcstack(&pcstack[0], DEBUG_STK_DEPTH);
204 
205 	cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance,
206 	    ha->vp_index);
207 	for (i = 0; i < MIN(depth, DEBUG_STK_DEPTH); i++) {
208 		sym = kobj_getsymname((uintptr_t)pcstack[i], &off);
209 
210 		if (sym == NULL) {
211 			cmn_err(CE_CONT, "%s(%d,%d): sym is NULL\n", QL_NAME,
212 			    ha->instance, ha->vp_index);
213 		} else {
214 			cmn_err(CE_CONT, "%s(%d,%d): %s+%lx\n", QL_NAME,
215 			    ha->instance, ha->vp_index, sym ? sym : "?", off);
216 		}
217 	}
218 	cmn_err(CE_CONT, "%s(%d,%d): ---------- \n", QL_NAME, ha->instance,
219 	    ha->vp_index);
220 }
221 
222 /*
223  * ql_flash_errlog
224  *	Adds error to flash error log.
225  *	Entry Layout:
226  *		uint32_t TimeStamp;
227  *		uint16_t CodeData[4];
228  *
229  * Input:
230  *	ha:	adapter state pointer.
231  *	code:	Error code
232  *	d1-d3:	Error code data
233  *
234  * Returns:
235  *	ql local function return status code.
236  *
237  * Context:
238  *	Kernel/Interrupt context.
239  */
240 int
241 ql_flash_errlog(ql_adapter_state_t *ha, uint16_t code, uint16_t d1,
242     uint16_t d2, uint16_t d3)
243 {
244 	char		*s;
245 	uint32_t	marker[2], fdata[2], faddr;
246 	int		rval;
247 
248 	QL_PRINT_3(CE_CONT, "(%d): entered\n", ha->instance);
249 
250 	if (ha->flash_errlog_start == 0) {
251 		return (QL_NOT_SUPPORTED);
252 	}
253 
254 	EL(ha, "code=%xh, d1=%xh, d2=%xh, d3=%xh\n", code, d1, d2, d3);
255 
256 	/*
257 	 * If marker not already found, locate or write marker.
258 	 */
259 	if (!(ha->flags & FLASH_ERRLOG_MARKER)) {
260 
261 		/* Create marker. */
262 		marker[0] = CHAR_TO_LONG(ha->fw_subminor_version,
263 		    ha->fw_minor_version, ha->fw_major_version, 'S');
264 
265 		/*
266 		 * Version should be of the format: YYYYMMDD-v.vv
267 		 */
268 		if ((strlen(QL_VERSION) > 9) && (QL_VERSION[8] == '-')) {
269 			s = &QL_VERSION[9];
270 		} else {
271 			s = QL_VERSION;
272 		}
273 
274 		for (marker[1] = 0; *s != '\0'; s++) {
275 			if (*s >= '0' && *s <= '9') {
276 				marker[1] <<= 4;
277 				marker[1] |= *s - '0';
278 			} else if (*s != '.') {
279 				break;
280 			}
281 		}
282 
283 		/* Locate marker. */
284 		ha->flash_errlog_ptr = ha->flash_errlog_start;
285 		for (;;) {
286 			faddr = FLASH_DATA_ADDR | ha->flash_errlog_ptr;
287 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[0]);
288 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[1]);
289 			if (fdata[0] == 0xffffffff && fdata[1] == 0xffffffff) {
290 				break;
291 			}
292 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[0]);
293 			(void) ql_24xx_read_flash(ha, faddr++, &fdata[1]);
294 			ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE;
295 			if (ha->flash_errlog_ptr >=
296 			    ha->flash_errlog_start + FLASH_ERRLOG_SIZE) {
297 				EL(ha, "log full\n");
298 				return (QL_MEMORY_FULL);
299 			}
300 			if (fdata[0] == marker[0] && fdata[1] == marker[1]) {
301 				ha->flags |= FLASH_ERRLOG_MARKER;
302 				break;
303 			}
304 		}
305 
306 		/* No marker, write it. */
307 		if (!(ha->flags & FLASH_ERRLOG_MARKER)) {
308 			ha->flags |= FLASH_ERRLOG_MARKER;
309 			rval = ql_flash_errlog_store(ha, marker);
310 			if (rval != QL_SUCCESS) {
311 				EL(ha, "failed marker write=%xh\n", rval);
312 				return (rval);
313 			}
314 		}
315 	}
316 
317 	/*
318 	 * Store error.
319 	 */
320 	fdata[0] = SHORT_TO_LONG(d1, code);
321 	fdata[1] = SHORT_TO_LONG(d3, d2);
322 	rval = ql_flash_errlog_store(ha, fdata);
323 	if (rval != QL_SUCCESS) {
324 		EL(ha, "failed error write=%xh\n", rval);
325 	} else {
326 		/*EMPTY*/
327 		QL_PRINT_3(CE_CONT, "(%d): exiting\n", ha->instance);
328 	}
329 
330 	return (rval);
331 }
332 
333 /*
334  * ql_flash_errlog_store
335  *	Stores error to flash.
336  *	Entry Layout:
337  *		uint32_t TimeStamp;
338  *		uint16_t CodeData[4];
339  *
340  * Input:
341  *	ha:			adapter state pointer.
342  *	fdata:			Error code plus data.
343  *	ha->flash_errlog_ptr:	Current Flash error pointer.
344  *
345  * Output:
346  *	ha->flash_errlog_ptr:	updated pointer.
347  *
348  * Returns:
349  *	ql local function return status code.
350  *
351  * Context:
352  *	Kernel/Interrupt context.
353  */
354 static int
355 ql_flash_errlog_store(ql_adapter_state_t *ha, uint32_t *fdata)
356 {
357 	uint64_t	time;
358 	uint32_t	d1, d2, faddr;
359 
360 	QL_PRINT_3(CE_CONT, "(%d): entered\n", ha->instance);
361 
362 	/* Locate first empty entry */
363 	for (;;) {
364 		if (ha->flash_errlog_ptr >=
365 		    ha->flash_errlog_start + FLASH_ERRLOG_SIZE) {
366 			EL(ha, "log full\n");
367 			return (QL_MEMORY_FULL);
368 		}
369 
370 		faddr = FLASH_DATA_ADDR | ha->flash_errlog_ptr;
371 		ha->flash_errlog_ptr += FLASH_ERRLOG_ENTRY_SIZE;
372 		(void) ql_24xx_read_flash(ha, faddr, &d1);
373 		(void) ql_24xx_read_flash(ha, faddr + 1, &d2);
374 		if (d1 == 0xffffffff && d2 == 0xffffffff) {
375 			(void) drv_getparm(TIME, &time);
376 
377 			/* Enable flash write. */
378 			ql_24xx_unprotect_flash(ha);
379 
380 			(void) ql_24xx_write_flash(ha, faddr++, LSD(time));
381 			(void) ql_24xx_write_flash(ha, faddr++, MSD(time));
382 			(void) ql_24xx_write_flash(ha, faddr++, *fdata++);
383 			(void) ql_24xx_write_flash(ha, faddr++, *fdata);
384 
385 			/* Enable flash write-protection. */
386 			ql_24xx_protect_flash(ha);
387 			break;
388 		}
389 	}
390 
391 	QL_PRINT_3(CE_CONT, "(%d): exiting\n", ha->instance);
392 
393 	return (QL_SUCCESS);
394 }
395