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