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