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