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