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