xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_fwlog.c (revision 3be32c0f0acac4f6258b029f1a27a16a7ec65bb0)
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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * This file contains firmware log routines.
27  */
28 
29 #include <sys/scsi/adapters/pmcs/pmcs.h>
30 #include <sys/scsi/adapters/pmcs/pmcs_fwlog.h>
31 
32 static int pmcs_dump_ioqs(pmcs_hw_t *, caddr_t, uint32_t);
33 static int pmcs_dump_spc_ver(pmcs_hw_t *, caddr_t, uint32_t);
34 static int pmcs_dump_mpi_table(pmcs_hw_t *, caddr_t, uint32_t);
35 static int pmcs_dump_gsm_conf(pmcs_hw_t *, caddr_t, uint32_t);
36 static int pmcs_dump_pcie_conf(pmcs_hw_t *, caddr_t, uint32_t);
37 static uint32_t pmcs_get_axil(pmcs_hw_t *);
38 static boolean_t pmcs_shift_axil(pmcs_hw_t *, uint32_t);
39 static void pmcs_restore_axil(pmcs_hw_t *, uint32_t);
40 static int pmcs_dump_gsm(pmcs_hw_t *, caddr_t, uint32_t);
41 static int pmcs_dump_gsm_addiregs(pmcs_hw_t *, caddr_t, uint32_t);
42 static int pmcs_dump_hsst_sregs(pmcs_hw_t *, caddr_t, uint32_t);
43 static int pmcs_dump_sspa_sregs(pmcs_hw_t *, caddr_t, uint32_t);
44 static int pmcs_dump_fwlog(pmcs_hw_t *, caddr_t, uint32_t);
45 static void pmcs_write_fwlog(pmcs_hw_t *, pmcs_fw_event_hdr_t *);
46 
47 /*
48  * Dump internal registers. Used after a firmware crash.
49  * Here dump various registers for firmware forensics,
50  * including MPI, GSM configuration, firmware log, IO Queues etc.
51  */
52 void
pmcs_register_dump_int(pmcs_hw_t * pwp)53 pmcs_register_dump_int(pmcs_hw_t *pwp)
54 {
55 	int n = 0;
56 	uint32_t size_left = 0;
57 	uint32_t scratch = 0;
58 	uint8_t slice = 0;
59 	caddr_t buf = NULL;
60 
61 	ASSERT(mutex_owned(&pwp->lock));
62 
63 	pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
64 	    "pmcs%d: Internal register dump", ddi_get_instance(pwp->dip));
65 
66 	if (pwp->regdumpp == NULL) {
67 		pwp->regdumpp =
68 		    kmem_zalloc(PMCS_REG_DUMP_SIZE, KM_NOSLEEP);
69 		if (pwp->regdumpp == NULL) {
70 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
71 			    "%s: register dump memory not allocated", __func__);
72 			return;
73 		}
74 	}
75 	buf = pwp->regdumpp;
76 	size_left = PMCS_REG_DUMP_SIZE - 1;
77 
78 	n = pmcs_dump_spc_ver(pwp, buf, size_left);
79 	ASSERT(size_left >= n);
80 	buf += n; size_left -= n;
81 	n = pmcs_dump_gsm_conf(pwp, buf, size_left);
82 	ASSERT(size_left >= n);
83 	buf += n; size_left -= n;
84 	n = pmcs_dump_pcie_conf(pwp, buf, size_left);
85 	ASSERT(size_left >= n);
86 	buf += n; size_left -= n;
87 	n = pmcs_dump_mpi_table(pwp, buf, size_left);
88 	ASSERT(size_left >= n);
89 	buf += n; size_left -= n;
90 	n = pmcs_dump_ioqs(pwp, buf, size_left);
91 	ASSERT(size_left >= n);
92 	buf += n; size_left -= n;
93 
94 	if (pwp->state == STATE_DEAD) {
95 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
96 		    "%s: HBA dead, skipping AAP1/IOP registers and event logs",
97 		    __func__);
98 		goto skip_logs;
99 	}
100 
101 	scratch = pmcs_rd_msgunit(pwp, PMCS_MSGU_SCRATCH1);
102 	if ((scratch & PMCS_MSGU_AAP_STATE_MASK) == PMCS_MSGU_AAP_STATE_ERROR) {
103 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
104 		    "%s: MSGU in error state, skipping AAP1/IOP registers and "
105 		    "event logs", __func__);
106 		goto skip_logs;
107 	}
108 
109 	mutex_exit(&pwp->lock);
110 	slice = (PMCS_REGISTER_DUMP_FLASH_SIZE / PMCS_FLASH_CHUNK_SIZE);
111 	n = snprintf(buf, size_left, "\nDump AAP1 register: \n"
112 	    "-----------------\n");
113 	ASSERT(size_left >= n);
114 	buf += n; size_left -= n;
115 	for (uint8_t j = 0; j < slice; j++) {
116 		n = pmcs_get_nvmd(pwp, PMCS_NVMD_REG_DUMP,
117 		    PMCIN_NVMD_AAP1, (j * PMCS_FLASH_CHUNK_SIZE),
118 		    buf, size_left);
119 		if (n == PMCS_FLASH_CHUNK_SIZE) {
120 			ASSERT(size_left >= n);
121 			buf += n; size_left -= n;
122 		} else if ((n < PMCS_FLASH_CHUNK_SIZE) && (n > 0)) {
123 			ASSERT(size_left >= n);
124 			buf += n; size_left -= n;
125 			break;
126 		} else if (n == 0) {
127 			n = snprintf(buf, size_left, "AAP1: Content of "
128 			    "register dump on flash is NULL\n");
129 			ASSERT(size_left >= n);
130 			buf += n; size_left -= n;
131 			break;
132 		} else {
133 			n = snprintf(buf, size_left,
134 			    "AAP1: Unable to obtain internal register dump\n");
135 			ASSERT(size_left >= n);
136 			buf += n; size_left -= n;
137 			break;
138 		}
139 
140 	}
141 
142 	n = snprintf(buf, size_left, "\nDump IOP register: \n"
143 	    "-----------------\n");
144 	ASSERT(size_left >= n);
145 	buf += n; size_left -= n;
146 	for (uint8_t j = 0; j < slice; j++) {
147 		n = pmcs_get_nvmd(pwp, PMCS_NVMD_REG_DUMP,
148 		    PMCIN_NVMD_IOP, (j * PMCS_FLASH_CHUNK_SIZE),
149 		    buf, size_left);
150 		if (n == PMCS_FLASH_CHUNK_SIZE) {
151 			ASSERT(size_left >= n);
152 			buf += n; size_left -= n;
153 		} else if ((n < PMCS_FLASH_CHUNK_SIZE) && (n > 0)) {
154 			ASSERT(size_left >= n);
155 			buf += n; size_left -= n;
156 			break;
157 		} else if (n == 0) {
158 			n = snprintf(buf, size_left,
159 			    "IOP: Content of internal register dump is NULL\n");
160 			ASSERT(size_left >= n);
161 			buf += n; size_left -= n;
162 			break;
163 		} else {
164 			n = snprintf(buf, size_left,
165 			    "IOP: Unable to obtain internal register dump\n");
166 			ASSERT(size_left >= n);
167 			buf += n; size_left -= n;
168 			break;
169 		}
170 
171 	}
172 
173 	n = snprintf(buf, size_left, "\nDump AAP1 event log: \n"
174 	    "-----------------\n");
175 	ASSERT(size_left >= n);
176 	buf += n; size_left -= n;
177 	for (uint8_t j = 0; j < slice; j++) {
178 		n = pmcs_get_nvmd(pwp, PMCS_NVMD_EVENT_LOG,
179 		    PMCIN_NVMD_AAP1, (j * PMCS_FLASH_CHUNK_SIZE),
180 		    buf, size_left);
181 		if (n > 0) {
182 			ASSERT(size_left >= n);
183 			buf += n; size_left -= n;
184 		} else {
185 			n = snprintf(buf, size_left,
186 			    "AAP1: Unable to obtain event log on flash\n");
187 			ASSERT(size_left >= n);
188 			buf += n; size_left -= n;
189 			break;
190 		}
191 	}
192 
193 	n = snprintf(buf, size_left, "\nDump IOP event log: \n"
194 	    "-----------------\n");
195 	ASSERT(size_left >= n);
196 	buf += n; size_left -= n;
197 	for (uint8_t j = 0; j < slice; j++) {
198 		n = pmcs_get_nvmd(pwp, PMCS_NVMD_EVENT_LOG,
199 		    PMCIN_NVMD_IOP, (j * PMCS_FLASH_CHUNK_SIZE),
200 		    buf, size_left);
201 		if (n > 0) {
202 			ASSERT(size_left >= n);
203 			buf += n; size_left -= n;
204 		} else {
205 			n = snprintf(buf, size_left,
206 			    "IOP: Unable to obtain event log dump\n");
207 			ASSERT(size_left >= n);
208 			buf += n; size_left -= n;
209 			break;
210 		}
211 	}
212 	mutex_enter(&pwp->lock);
213 
214 skip_logs:
215 	n = pmcs_dump_gsm_addiregs(pwp, buf, size_left);
216 	ASSERT(size_left >= n);
217 	buf += n; size_left -= n;
218 
219 	n = pmcs_dump_hsst_sregs(pwp, buf, size_left);
220 	ASSERT(size_left >= n);
221 	buf += n; size_left -= n;
222 
223 	n = pmcs_dump_sspa_sregs(pwp, buf, size_left);
224 	ASSERT(size_left >= n);
225 	buf += n; size_left -= n;
226 	n = snprintf(buf, size_left, "\nDump firmware log: \n"
227 	    "-----------------\n");
228 	ASSERT(size_left >= n);
229 	buf += n; size_left -= n;
230 
231 	n = pmcs_dump_fwlog(pwp, buf, size_left);
232 	ASSERT(size_left >= n);
233 	buf += n; size_left -= n;
234 
235 	n = pmcs_dump_gsm(pwp, buf, size_left);
236 	ASSERT(size_left >= n);
237 	buf += n; size_left -= n;
238 
239 	n = snprintf(buf, size_left, "-----------------\n"
240 	    "\n------------ Dump internal registers end  -------------\n");
241 	ASSERT(size_left >= n);
242 	buf += n; size_left -= n;
243 }
244 
245 static int
pmcs_dump_fwlog(pmcs_hw_t * pwp,caddr_t buf,uint32_t size_left)246 pmcs_dump_fwlog(pmcs_hw_t *pwp, caddr_t buf, uint32_t size_left)
247 {
248 	pmcs_fw_event_hdr_t *evl_hdr;
249 	int n = 0, retries = 0;
250 	uint32_t evlog_latest_idx;
251 	boolean_t log_is_current = B_FALSE;
252 
253 	if (pwp->fwlogp == NULL) {
254 		n = snprintf(buf, size_left, "\nFirmware logging "
255 		    "not enabled\n");
256 		return (n);
257 	}
258 
259 	/*
260 	 * First, check to make sure all entries have been DMAed to the
261 	 * log buffer.
262 	 *
263 	 * We'll wait the required 50ms, but if the latest entry keeps
264 	 * changing, we'll only retry twice
265 	 */
266 	evl_hdr = (pmcs_fw_event_hdr_t *)pwp->fwlogp;
267 	evlog_latest_idx = evl_hdr->fw_el_latest_idx;
268 
269 	while ((log_is_current == B_FALSE) && (retries < 3)) {
270 		drv_usecwait(50 * 1000);
271 		if (evl_hdr->fw_el_latest_idx == evlog_latest_idx) {
272 			log_is_current = B_TRUE;
273 		} else {
274 			++retries;
275 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
276 			    "%s: event log is still being updated... waiting",
277 			    __func__);
278 			evlog_latest_idx = evl_hdr->fw_el_latest_idx;
279 		}
280 	}
281 
282 	n = pmcs_dump_binary(pwp, pwp->fwlogp, 0, (PMCS_FWLOG_SIZE >> 2),
283 	    buf, size_left);
284 
285 	return (n);
286 }
287 
288 /*
289  * Dump Inbound and Outbound Queues.
290  */
291 static int
pmcs_dump_ioqs(pmcs_hw_t * pwp,caddr_t buf,uint32_t size_left)292 pmcs_dump_ioqs(pmcs_hw_t *pwp, caddr_t buf, uint32_t size_left)
293 {
294 	uint8_t i = 0, k = 0;
295 	uint32_t j = 0, depth = 0;
296 	int n = 0;
297 	uint32_t *ptr = NULL;
298 
299 	n += snprintf(&buf[n], (size_left - n), "\nDump I/O queues: \n"
300 	    "-----------------\n");
301 	for (i = 0; i < PMCS_NIQ; i++) {
302 		depth = PMCS_IQDX(pmcs_rd_iqc_tbl(pwp, PMCS_IQC_PARMX(i)));
303 		n += snprintf(&buf[n], (size_left - n),
304 		    "IQ[%d] Details:\n-----------------\n", i);
305 		n += snprintf(&buf[n], (size_left - n),
306 		    "    depth = 0x%04x\n", depth);
307 		n += snprintf(&buf[n], (size_left - n),
308 		    "    latest ci = 0x%02x\n", pmcs_rd_iqci(pwp, i));
309 		n += snprintf(&buf[n], (size_left - n),
310 		    "    latest pi = 0x%02x\n", pmcs_rd_iqpi(pwp, i));
311 		for (j = 0; j < depth; j++) {
312 			n += snprintf(&buf[n], (size_left - n),
313 			    "IOMB[%d]:\n", j);
314 			ptr = &pwp->iqp[i][(j * PMCS_QENTRY_SIZE) >> 2];
315 			for (k = 0; k < (PMCS_QENTRY_SIZE / sizeof (uint32_t));
316 			    k += 8) {
317 				n += snprintf(&buf[n], (size_left - n),
318 				    "0x%08x 0x%08x 0x%08x 0x%08x "
319 				    "0x%08x 0x%08x 0x%08x 0x%08x\n",
320 				    LE_32(ptr[k]), LE_32(ptr[k+1]),
321 				    LE_32(ptr[k+2]), LE_32(ptr[k+3]),
322 				    LE_32(ptr[k+4]), LE_32(ptr[k+5]),
323 				    LE_32(ptr[k+6]), LE_32(ptr[k+7]));
324 			}
325 		}
326 	}
327 	for (i = 0; i < PMCS_NOQ; i++) {
328 		depth = PMCS_OQDX(pmcs_rd_oqc_tbl(pwp, PMCS_OQC_PARMX(i)));
329 		n += snprintf(&buf[n], (size_left - n),
330 		    "OQ[%d] Details:\n", i);
331 		n += snprintf(&buf[n], (size_left - n),
332 		    "    depth = 0x%04x\n", depth);
333 		n += snprintf(&buf[n], (size_left - n),
334 		    "    latest ci = 0x%02x\n", pmcs_rd_oqci(pwp, i));
335 		n += snprintf(&buf[n], (size_left - n),
336 		    "    latest pi = 0x%02x\n", pmcs_rd_oqpi(pwp, i));
337 		for (j = 0; j < depth; j++) {
338 			n += snprintf(&buf[n], (size_left - n),
339 			    "IOMB[%d]:\n", j);
340 			ptr = &pwp->oqp[i][(j * PMCS_QENTRY_SIZE) >> 2];
341 			for (k = 0; k < (PMCS_QENTRY_SIZE / sizeof (uint32_t));
342 			    k += 8) {
343 				n += snprintf(&buf[n], (size_left - n),
344 				    "0x%08x 0x%08x 0x%08x 0x%08x "
345 				    "0x%08x 0x%08x 0x%08x 0x%08x\n",
346 				    LE_32(ptr[k]), LE_32(ptr[k+1]),
347 				    LE_32(ptr[k+2]), LE_32(ptr[k+3]),
348 				    LE_32(ptr[k+4]), LE_32(ptr[k+5]),
349 				    LE_32(ptr[k+6]), LE_32(ptr[k+7]));
350 			}
351 		}
352 
353 	}
354 	n += snprintf(&buf[n], (size_left - n), "-----------------\n"
355 	    "Dump I/O queues end \n");
356 	return (n);
357 }
358 
359 /*
360  * Dump SPC Version.
361  */
362 static int
pmcs_dump_spc_ver(pmcs_hw_t * pwp,caddr_t buf,uint32_t size_left)363 pmcs_dump_spc_ver(pmcs_hw_t *pwp, caddr_t buf, uint32_t size_left)
364 {
365 	int n = 0;
366 
367 	n += snprintf(&buf[n], (size_left - n), "\nDump SPC version: \n"
368 	    "-----------------\n");
369 	n += snprintf(&buf[n], (size_left - n), "Firmware Release Type = "
370 	    "0x%02x\n", PMCS_FW_TYPE(pwp));
371 	n += snprintf(&buf[n], (size_left - n), "    Sub-Minor Release "
372 	    "Number = 0x%02x\n", PMCS_FW_MICRO(pwp));
373 	n += snprintf(&buf[n], (size_left - n), "    Minor Release "
374 	    "Number = 0x%02x\n", PMCS_FW_MINOR(pwp));
375 	n += snprintf(&buf[n], (size_left - n), "    Major Release "
376 	    "Number = 0x%02x\n", PMCS_FW_MAJOR(pwp));
377 	n += snprintf(&buf[n], (size_left - n), "SPC DeviceID = 0x%04x\n",
378 	    pmcs_rd_topunit(pwp, PMCS_SPC_DEVICE_ID));
379 	n += snprintf(&buf[n], (size_left - n), "SPC Device Revision = "
380 	    "0x%08x\n", pmcs_rd_topunit(pwp, PMCS_DEVICE_REVISION));
381 	n += snprintf(&buf[n], (size_left - n), "SPC BootStrap Register = "
382 	    "0x%08x\n", pmcs_rd_topunit(pwp, PMCS_SPC_BOOT_STRAP));
383 	n += snprintf(&buf[n], (size_left - n), "SPC Reset Register = 0x%08x\n",
384 	    pmcs_rd_topunit(pwp, PMCS_SPC_RESET));
385 	n += snprintf(&buf[n], (size_left - n), "-----------------\n"
386 	    "Dump SPC version end \n");
387 	return (n);
388 }
389 
390 /*
391  * Dump MPI Table.
392  */
393 static int
pmcs_dump_mpi_table(pmcs_hw_t * pwp,caddr_t buf,uint32_t size_left)394 pmcs_dump_mpi_table(pmcs_hw_t *pwp, caddr_t buf, uint32_t size_left)
395 {
396 	int n = 0;
397 
398 	n += snprintf(&buf[n], (size_left - n), "\nDump MSGU registers: \n"
399 	    "-----------------\n");
400 	n += snprintf(&buf[n], (size_left - n), "inb_doorbell = 0x%08x\n",
401 	    pmcs_rd_msgunit(pwp, PMCS_MSGU_IBDB));
402 	n += snprintf(&buf[n], (size_left - n), "inb_doorbell_clear = 0x%08x"
403 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_IBDB_CLEAR));
404 	n += snprintf(&buf[n], (size_left - n), "outb_doorbell = 0x%08x"
405 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_OBDB));
406 	n += snprintf(&buf[n], (size_left - n), "outb_doorbell_clear = 0x%08x"
407 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_OBDB_CLEAR));
408 	n += snprintf(&buf[n], (size_left - n), "scratch_pad0 = 0x%08x"
409 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_SCRATCH0));
410 	n += snprintf(&buf[n], (size_left - n), "scratch_pad1 = 0x%08x"
411 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_SCRATCH1));
412 	n += snprintf(&buf[n], (size_left - n), "scratch_pad2 = 0x%08x"
413 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_SCRATCH2));
414 	n += snprintf(&buf[n], (size_left - n), "scratch_pad3 = 0x%08x"
415 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_SCRATCH3));
416 	n += snprintf(&buf[n], (size_left - n), "host_scratch_pad0 = 0x%08x"
417 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_HOST_SCRATCH0));
418 	n += snprintf(&buf[n], (size_left - n), "host_scratch_pad1 = 0x%08x"
419 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_HOST_SCRATCH1));
420 	n += snprintf(&buf[n], (size_left - n), "host_scratch_pad2 = 0x%08x"
421 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_HOST_SCRATCH2));
422 	n += snprintf(&buf[n], (size_left - n), "host_scratch_pad3 = 0x%08x"
423 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_HOST_SCRATCH3));
424 	n += snprintf(&buf[n], (size_left - n), "host_scratch_pad4 = 0x%08x"
425 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_HOST_SCRATCH4));
426 	n += snprintf(&buf[n], (size_left - n), "host_scratch_pad5 = 0x%08x"
427 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_HOST_SCRATCH5));
428 	n += snprintf(&buf[n], (size_left - n), "host_scratch_pad6 = 0x%08x"
429 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_HOST_SCRATCH6));
430 	n += snprintf(&buf[n], (size_left - n), "host_scratch_pad7 = 0x%08x"
431 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_HOST_SCRATCH7));
432 	n += snprintf(&buf[n], (size_left - n), "outb_doorbell_mask = 0x%08x"
433 	    "\n", pmcs_rd_msgunit(pwp, PMCS_MSGU_OBDB_MASK));
434 
435 	n += snprintf(&buf[n], (size_left - n), "MPI Configuration Table: \n"
436 	    "-----------------\n");
437 	n += snprintf(&buf[n], (size_left - n), "ASCII Signature = 0x%08x\n",
438 	    pmcs_rd_mpi_tbl(pwp, PMCS_MPI_AS));
439 	n += snprintf(&buf[n], (size_left - n), "Firmware Release Type = "
440 	    "0x%08x\n", PMCS_FW_TYPE(pwp));
441 	n += snprintf(&buf[n], (size_left - n), "Firmware Release Variant = "
442 	    "0x%08x\n", PMCS_FW_VARIANT(pwp));
443 	n += snprintf(&buf[n], (size_left - n), "Firmware Sub-Minor Release "
444 	    "Number = 0x%08x\n", PMCS_FW_MICRO(pwp));
445 	n += snprintf(&buf[n], (size_left - n), "Firmware Minor Release "
446 	    "Number = 0x%08x\n", PMCS_FW_MINOR(pwp));
447 	n += snprintf(&buf[n], (size_left - n), "Firmware Major Release "
448 	    "Number = 0x%08x\n", PMCS_FW_MAJOR(pwp));
449 	n += snprintf(&buf[n], (size_left - n), "Maximum Outstanding I/Os "
450 	    "supported = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_MOIO));
451 	n += snprintf(&buf[n], (size_left - n), "Maximum Scatter-Gather List "
452 	    "Elements = 0x%08x\n",
453 	    PMCS_MSGL(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO0)));
454 	n += snprintf(&buf[n], (size_left - n), "Maximum number of devices "
455 	    "connected to the SPC = 0x%08x\n",
456 	    PMCS_MD(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO0)));
457 	n += snprintf(&buf[n], (size_left - n), "Maximum Number of IQs "
458 	    "supported = 0x%08x\n",
459 	    PMCS_MNIQ(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO1)));
460 	n += snprintf(&buf[n], (size_left - n), "Maximum Number of OQs "
461 	    "supported = 0x%08x\n",
462 	    PMCS_MNOQ(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO1)));
463 	n += snprintf(&buf[n], (size_left - n), "High Priority Queue supported"
464 	    " = 0x%08x\n", PMCS_HPIQ(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO1)));
465 	n += snprintf(&buf[n], (size_left - n), "Interrupt Coalescing supported"
466 	    " = 0x%08x\n", PMCS_ICS(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO1)));
467 	n += snprintf(&buf[n], (size_left - n), "Number of Phys = "
468 	    "0x%08x\n", PMCS_NPHY(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO1)));
469 	n += snprintf(&buf[n], (size_left - n), "SAS Revision Specification = "
470 	    "0x%08x\n", PMCS_SASREV(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO1)));
471 	n += snprintf(&buf[n], (size_left - n), "General Status Table Offset = "
472 	    "0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_GSTO));
473 	n += snprintf(&buf[n], (size_left - n), "Inbound Queue Configuration "
474 	    "Table Offset = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_IQCTO));
475 	n += snprintf(&buf[n], (size_left - n), "Outbound Queue Configuration "
476 	    "Table Offset = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_OQCTO));
477 	n += snprintf(&buf[n], (size_left - n), "Inbound Queue Normal/High "
478 	    "Priority Processing Depth = 0x%02x 0x%02x\n",
479 	    (pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO2) & IQ_NORMAL_PRI_DEPTH_MASK),
480 	    ((pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO2) &
481 	    IQ_HIPRI_PRI_DEPTH_MASK) >> IQ_HIPRI_PRI_DEPTH_SHIFT));
482 	n += snprintf(&buf[n], (size_left - n), "General Event Notification "
483 	    "Queue = 0x%02x\n", (pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO2) &
484 	    GENERAL_EVENT_OQ_MASK) >> GENERAL_EVENT_OQ_SHIFT);
485 	n += snprintf(&buf[n], (size_left - n), "Device Handle Removed "
486 	    "Notification Queue = 0x%02x\n",
487 	    (uint32_t)(pmcs_rd_mpi_tbl(pwp, PMCS_MPI_INFO2) &
488 	    DEVICE_HANDLE_REMOVED_MASK) >> DEVICE_HANDLE_REMOVED_SHIFT);
489 	for (uint8_t i = 0; i < pwp->nphy; i++) {
490 		uint32_t woff = i / 4;
491 		uint32_t shf = (i % 4) * 8;
492 		n += snprintf(&buf[n], (size_left - n), "SAS HW Event "
493 		    "Notification Queue - PHY ID %d = 0x%02x\n", i,
494 		    (pmcs_rd_mpi_tbl(pwp, PMCS_MPI_EVQS + (woff << 2)) >> shf)
495 		    & 0xff);
496 	}
497 	for (uint8_t i = 0; i < pwp->nphy; i++) {
498 		uint32_t woff = i / 4;
499 		uint32_t shf = (i % 4) * 8;
500 		n += snprintf(&buf[n], (size_left - n), "SATA NCQ Error "
501 		    "Event Notification Queue - PHY ID %d = 0x%02x\n", i,
502 		    (pmcs_rd_mpi_tbl(pwp, PMCS_MPI_SNCQ + (woff << 2)) >> shf)
503 		    & 0xff);
504 	}
505 	for (uint8_t i = 0; i < pwp->nphy; i++) {
506 		uint32_t woff = i / 4;
507 		uint32_t shf = (i % 4) * 8;
508 		n += snprintf(&buf[n], (size_left - n), "I_T Nexus Target "
509 		    "Event Notification Queue - PHY ID %d = 0x%02x\n", i,
510 		    (pmcs_rd_mpi_tbl(pwp, PMCS_MPI_IT_NTENQ +
511 		    (woff << 2)) >> shf) & 0xff);
512 	}
513 	for (uint8_t i = 0; i < pwp->nphy; i++) {
514 		uint32_t woff = i / 4;
515 		uint32_t shf = (i % 4) * 8;
516 		n += snprintf(&buf[n], (size_left - n), "SSP Target "
517 		    "Event Notification Queue - PHY ID %d = 0x%02x\n", i,
518 		    (pmcs_rd_mpi_tbl(pwp, PMCS_MPI_SSP_TENQ +
519 		    (woff << 2)) >> shf) & 0xff);
520 	}
521 
522 	n += snprintf(&buf[n], (size_left - n), "I/O Abort Delay = 0x%04x\n",
523 	    pmcs_rd_mpi_tbl(pwp, PMCS_MPI_IOABTDLY) & 0xffff);
524 	n += snprintf(&buf[n], (size_left - n),
525 	    "Customization Setting = 0x%08x\n",
526 	    pmcs_rd_mpi_tbl(pwp, PMCS_MPI_CUSTSET));
527 	n += snprintf(&buf[n], (size_left - n), "MSGU Event Log Buffer Address "
528 	    "Higher = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_MELBAH));
529 	n += snprintf(&buf[n], (size_left - n), "MSGU Event Log Buffer Address "
530 	    "Lower = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_MELBAL));
531 	n += snprintf(&buf[n], (size_left - n), "MSGU Event Log Buffer Size "
532 	    "= 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_MELBS));
533 	n += snprintf(&buf[n], (size_left - n), "MSGU Event Log Severity "
534 	    "= 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_MELSEV));
535 	n += snprintf(&buf[n], (size_left - n), "IOP Event Log Buffer Address "
536 	    "Higher = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_IELBAH));
537 	n += snprintf(&buf[n], (size_left - n), "IOP Event Log Buffer Address "
538 	    "Lower = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_IELBAL));
539 	n += snprintf(&buf[n], (size_left - n), "IOP Event Log Buffer Size "
540 	    "= 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_IELBS));
541 	n += snprintf(&buf[n], (size_left - n), "IOP Event Log Severity "
542 	    "= 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_IELSEV));
543 	n += snprintf(&buf[n], (size_left - n), "Fatal Error Interrupt "
544 	    "= 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_MPI_FERR));
545 	n += snprintf(&buf[n], (size_left - n),
546 	    "Fatal Error Register Dump Offset "
547 	    "For MSGU = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_FERDOMSGU));
548 	n += snprintf(&buf[n], (size_left - n),
549 	    "Fatal Error Register Dump Length "
550 	    "For MSGU = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_FERDLMSGU));
551 	n += snprintf(&buf[n], (size_left - n),
552 	    "Fatal Error Register Dump Offset "
553 	    "For IOP = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_FERDOIOP));
554 	n += snprintf(&buf[n], (size_left - n),
555 	    "Fatal Error Register Dump Length "
556 	    "For IOP = 0x%08x\n", pmcs_rd_mpi_tbl(pwp, PMCS_FERDLIOP));
557 
558 	n += snprintf(&buf[n], (size_left - n), "Dump GS Table: \n"
559 	    "-----------------\n");
560 	n += snprintf(&buf[n], (size_left - n),  "GST MPI State: 0x%08x\n",
561 	    pmcs_rd_gst_tbl(pwp, PMCS_GST_BASE));
562 	n += snprintf(&buf[n], (size_left - n),  "Inbound Queue Freeze State 0 "
563 	    "= 0x%08x\n", pmcs_rd_gst_tbl(pwp, PMCS_GST_IQFRZ0));
564 	n += snprintf(&buf[n], (size_left - n), "Inbound Queue Freeze State 1 "
565 	    "= 0x%08x\n", pmcs_rd_gst_tbl(pwp, PMCS_GST_IQFRZ1));
566 	n += snprintf(&buf[n], (size_left - n), "MSGU Tick Count = 0x%08x \n",
567 	    pmcs_rd_gst_tbl(pwp, PMCS_GST_MSGU_TICK));
568 	n += snprintf(&buf[n], (size_left - n), "IOP Tick Count = 0x%08x\n",
569 	    pmcs_rd_gst_tbl(pwp, PMCS_GST_IOP_TICK));
570 	for (uint8_t i = 0; i < pwp->nphy; i++) {
571 		n += snprintf(&buf[n], (size_left - n), " Phy %d state = "
572 		    "0x%08x\n", i, pmcs_rd_gst_tbl(pwp, PMCS_GST_PHY_INFO(i)));
573 	}
574 	for (uint8_t i = 0; i < pwp->nphy; i++) {
575 		n += snprintf(&buf[n], (size_left - n), " Recoverable Error "
576 		    "Information %d = 0x%08x\n", i,
577 		    pmcs_rd_gst_tbl(pwp, PMCS_GST_RERR_INFO(i)));
578 	}
579 
580 	n += snprintf(&buf[n], (size_left - n), "Dump IQCT Table\n"
581 	    "-----------------\n");
582 	for (uint8_t i = 0; i < PMCS_NIQ; i++) {
583 		n += snprintf(&buf[n], (size_left - n), "Inbound Queue "
584 		    "Configuration Table - [%d]:\n", i);
585 		n += snprintf(&buf[n], (size_left - n), "    Inbound Queue "
586 		    "Depth = 0x%08x\n",
587 		    PMCS_IQDX(pmcs_rd_iqc_tbl(pwp, PMCS_IQC_PARMX(i))));
588 		n += snprintf(&buf[n], (size_left - n), "    Inbound Queue "
589 		    "Element Size and Priority = 0x%08x 0x%08x\n",
590 		    PMCS_IQESX(pmcs_rd_iqc_tbl(pwp, PMCS_IQC_PARMX(i))),
591 		    PMCS_IQPX(pmcs_rd_iqc_tbl(pwp, PMCS_IQC_PARMX(i))));
592 		n += snprintf(&buf[n], (size_left - n), "    Inbound Queue "
593 		    "Base Address High = 0x%08x\n",
594 		    pmcs_rd_iqc_tbl(pwp, PMCS_IQBAHX(i)));
595 		n += snprintf(&buf[n], (size_left - n), "    Inbound Queue "
596 		    "Base Address Low = 0x%08x\n",
597 		    pmcs_rd_iqc_tbl(pwp, PMCS_IQBALX(i)));
598 		n += snprintf(&buf[n], (size_left - n), "    Inbound Queue "
599 		    "Consumer Index Base Address High = 0x%08x\n",
600 		    pmcs_rd_iqc_tbl(pwp, PMCS_IQCIBAHX(i)));
601 		n += snprintf(&buf[n], (size_left - n), "    Inbound Queue "
602 		    "Consumer Index Base Address Low = 0x%08x\n",
603 		    pmcs_rd_iqc_tbl(pwp, PMCS_IQCIBALX(i)));
604 		n += snprintf(&buf[n], (size_left - n), "    Inbound Queue "
605 		    "Producer Index PCI BAR = 0x%08x\n",
606 		    pmcs_rd_iqc_tbl(pwp, PMCS_IQPIBARX(i)));
607 		n += snprintf(&buf[n], (size_left - n), "    Inbound Queue "
608 		    "Producer Index PCI BAR offset = 0x%08x\n",
609 		    pmcs_rd_iqc_tbl(pwp, PMCS_IQPIOFFX(i)));
610 	}
611 
612 	n += snprintf(&buf[n], (size_left - n), "Dump OQCT Table: \n"
613 	    "-----------------\n");
614 	for (uint8_t i = 0; i < PMCS_NOQ; i++) {
615 		n += snprintf(&buf[n], (size_left - n), "Outbound Queue "
616 		    "Configuration Table - [%d]:\n", i);
617 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
618 		    "Depth = 0x%08x\n",
619 		    PMCS_OQDX(pmcs_rd_oqc_tbl(pwp, PMCS_OQC_PARMX(i))));
620 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
621 		    "Element Size = 0x%08x\n",
622 		    PMCS_OQESX(pmcs_rd_oqc_tbl(pwp, PMCS_OQC_PARMX(i))));
623 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
624 		    "Base Address High = 0x%08x\n",
625 		    pmcs_rd_oqc_tbl(pwp, PMCS_OQBAHX(i)));
626 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
627 		    "Base Address Low = 0x%08x\n",
628 		    pmcs_rd_oqc_tbl(pwp, PMCS_OQBALX(i)));
629 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
630 		    "Producer Index Base Address High = 0x%08x\n",
631 		    pmcs_rd_oqc_tbl(pwp, PMCS_OQPIBAHX(i)));
632 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
633 		    "Producer Index Base Address Low = 0x%08x\n",
634 		    pmcs_rd_oqc_tbl(pwp, PMCS_OQPIBALX(i)));
635 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
636 		    "Consumer Index PCI BAR = 0x%08x\n",
637 		    pmcs_rd_oqc_tbl(pwp, PMCS_OQCIBARX(i)));
638 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
639 		    "Consumer Index PCI BAR offset = 0x%08x\n",
640 		    pmcs_rd_oqc_tbl(pwp, PMCS_OQCIOFFX(i)));
641 
642 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
643 		    "Interrupt Coalescing Timeout = 0x%08x\n",
644 		    PMCS_OQICT(pmcs_rd_oqc_tbl(pwp, PMCS_OQIPARM(i))));
645 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
646 		    "Interrupt Coalescing Count = 0x%08x\n",
647 		    PMCS_OQICC(pmcs_rd_oqc_tbl(pwp, PMCS_OQIPARM(i))));
648 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
649 		    "Interrupt Vector =  0x%08x\n",
650 		    PMCS_OQIV(pmcs_rd_oqc_tbl(pwp, PMCS_OQIPARM(i))));
651 		n += snprintf(&buf[n], (size_left - n), "    Outbound Queue "
652 		    "Dynamic Interrupt Coalescing Timeout = 0x%08x\n",
653 		    pmcs_rd_oqc_tbl(pwp, PMCS_OQDICX(i)));
654 
655 	}
656 	n += snprintf(&buf[n], (size_left - n), "-----------------\n"
657 	    "Dump MPI Table end\n");
658 	return (n);
659 }
660 
661 /*ARGSUSED*/
662 int
pmcs_dump_binary(pmcs_hw_t * pwp,uint32_t * addr,uint32_t off,uint32_t words_to_read,caddr_t buf,uint32_t size_left)663 pmcs_dump_binary(pmcs_hw_t *pwp, uint32_t *addr, uint32_t off,
664     uint32_t words_to_read, caddr_t buf, uint32_t size_left)
665 {
666 	uint32_t i;
667 	int n = 0;
668 	char c = ' ';
669 
670 	for (i = 0, n = 0; i < words_to_read; i++) {
671 		if ((i & 7) == 0) {
672 			n += snprintf(&buf[n], (size_left - n),
673 			    "%08x: ", (i << 2) + off);
674 		}
675 		if ((i + 1) & 7) {
676 			c = ' ';
677 		} else {
678 			c = '\n';
679 		}
680 		n += snprintf(&buf[n], (size_left - n), "%08x%c", addr[i], c);
681 	}
682 	return (n);
683 }
684 
685 /*
686  * Dump Global Shared Memory Configuration Registers
687  */
688 static int
pmcs_dump_gsm_conf(pmcs_hw_t * pwp,caddr_t buf,uint32_t size_left)689 pmcs_dump_gsm_conf(pmcs_hw_t *pwp, caddr_t buf, uint32_t size_left)
690 {
691 	int n = 0;
692 
693 	n += snprintf(&buf[n], (size_left - n), "\nDump GSM configuration "
694 	    "registers: \n -----------------\n");
695 	n += snprintf(&buf[n], (size_left - n), "RB6 Access Register = "
696 	    "0x%08x\n", pmcs_rd_gsm_reg(pwp, 0, RB6_ACCESS));
697 	n += snprintf(&buf[n], (size_left - n), "CFG and RST = 0x%08x\n",
698 	    pmcs_rd_gsm_reg(pwp, 0, GSM_CFG_AND_RESET));
699 	n += snprintf(&buf[n], (size_left - n), "RAM ECC ERR INDICATOR= "
700 	    "0x%08x\n", pmcs_rd_gsm_reg(pwp, 0,
701 	    RAM_ECC_DOUBLE_ERROR_INDICATOR));
702 	n += snprintf(&buf[n], (size_left - n), "READ ADR PARITY CHK EN = "
703 	    "0x%08x\n", pmcs_rd_gsm_reg(pwp, 0, READ_ADR_PARITY_CHK_EN));
704 	n += snprintf(&buf[n], (size_left - n), "WRITE ADR PARITY CHK EN = "
705 	    "0x%08x\n", pmcs_rd_gsm_reg(pwp, 0, WRITE_ADR_PARITY_CHK_EN));
706 	n += snprintf(&buf[n], (size_left - n), "WRITE DATA PARITY CHK EN= "
707 	    "0x%08x\n", pmcs_rd_gsm_reg(pwp, 0, WRITE_DATA_PARITY_CHK_EN));
708 	n += snprintf(&buf[n], (size_left - n),
709 	    "READ ADR PARITY ERROR INDICATOR = 0x%08x\n",
710 	    pmcs_rd_gsm_reg(pwp, 0, READ_ADR_PARITY_ERROR_INDICATOR));
711 	n += snprintf(&buf[n], (size_left - n),
712 	    "WRITE ADR PARITY ERROR INDICATOR = 0x%08x\n",
713 	    pmcs_rd_gsm_reg(pwp, 0, WRITE_ADR_PARITY_ERROR_INDICATOR));
714 	n += snprintf(&buf[n], (size_left - n),
715 	    "WRITE DATA PARITY ERROR INDICATOR = 0x%08x\n",
716 	    pmcs_rd_gsm_reg(pwp, 0, WRITE_DATA_PARITY_ERROR_INDICATOR));
717 	n += snprintf(&buf[n], (size_left - n), "NMI Enable VPE0 IOP Register"
718 	    " = 0x%08x\n", pmcs_rd_gsm_reg(pwp, 0, NMI_EN_VPE0_IOP));
719 	n += snprintf(&buf[n], (size_left - n), "NMI Enable VPE0 AAP1 Register"
720 	    " = 0x%08x\n", pmcs_rd_gsm_reg(pwp, 0, NMI_EN_VPE0_AAP1));
721 	n += snprintf(&buf[n], (size_left - n), "-----------------\n"
722 	    "Dump GSM configuration registers end \n");
723 	return (n);
724 }
725 
726 /*
727  * Dump PCIe Configuration Registers.
728  */
729 static int
pmcs_dump_pcie_conf(pmcs_hw_t * pwp,caddr_t buf,uint32_t size_left)730 pmcs_dump_pcie_conf(pmcs_hw_t *pwp, caddr_t buf, uint32_t size_left)
731 {
732 	int n = 0;
733 	uint32_t i = 0;
734 
735 	n += snprintf(&buf[n], (size_left - n), "\nDump PCIe configuration "
736 	    "registers: \n -----------------\n");
737 	n += snprintf(&buf[n], (size_left - n), "VENID = 0x%04x\n",
738 	    pci_config_get16(pwp->pci_acc_handle, PCI_CONF_VENID));
739 	n += snprintf(&buf[n], (size_left - n), "DEVICE_ID = 0x%04x\n",
740 	    pci_config_get16(pwp->pci_acc_handle, PCI_CONF_DEVID));
741 	n += snprintf(&buf[n], (size_left - n), "CFGCMD = 0x%04x\n",
742 	    pci_config_get16(pwp->pci_acc_handle, PCI_CONF_COMM));
743 	n += snprintf(&buf[n], (size_left - n), "CFGSTAT = 0x%04x\n",
744 	    pci_config_get16(pwp->pci_acc_handle, PCI_CONF_STAT));
745 	n += snprintf(&buf[n], (size_left - n), "CLSCODE and REVID = 0x%08x\n",
746 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_REVID));
747 	n += snprintf(&buf[n], (size_left - n), "BIST HDRTYPE LATTIM CLSIZE = "
748 	    "0x%08x\n",
749 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_CACHE_LINESZ));
750 	n += snprintf(&buf[n], (size_left - n), "MEMBASE-I LOWER = 0x%08x\n",
751 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_BASE0));
752 	n += snprintf(&buf[n], (size_left - n), "MEMBASE-I UPPER = 0x%08x\n",
753 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_BASE1));
754 	n += snprintf(&buf[n], (size_left - n), "MEMBASE-II LOWER = 0x%08x\n",
755 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_BASE2));
756 	n += snprintf(&buf[n], (size_left - n), "MEMBASE-II UPPER = 0x%08x\n",
757 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_BASE3));
758 	n += snprintf(&buf[n], (size_left - n), "MEMBASE-III = 0x%08x\n",
759 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_BASE4));
760 	n += snprintf(&buf[n], (size_left - n), "MEMBASE-IV = 0x%08x\n",
761 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_BASE5));
762 	n += snprintf(&buf[n], (size_left - n), "SVID = 0x%08x\n",
763 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_SUBVENID));
764 	n += snprintf(&buf[n], (size_left - n), "ROMBASE = 0x%08x\n",
765 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_ROM));
766 	n += snprintf(&buf[n], (size_left - n), "CAP_PTR = 0x%02x\n",
767 	    pci_config_get8(pwp->pci_acc_handle, PCI_CONF_CAP_PTR));
768 	n += snprintf(&buf[n], (size_left - n), "MAXLAT MINGNT INTPIN "
769 	    "INTLINE = 0x%08x\n",
770 	    pci_config_get32(pwp->pci_acc_handle, PCI_CONF_ILINE));
771 	n += snprintf(&buf[n], (size_left - n), "PMC PM_NEXT_CAP PM_CAP_ID = "
772 	    "0x%08x\n", pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_PMC));
773 	n += snprintf(&buf[n], (size_left - n), "PMCSR = 0x%08x\n",
774 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_PMCSR));
775 	n += snprintf(&buf[n], (size_left - n),
776 	    "MC MSI_NEXT_CAP MSI_CAP_ID = 0x%08x\n",
777 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_MSI));
778 	n += snprintf(&buf[n], (size_left - n), "MAL = 0x%08x\n",
779 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_MAL));
780 	n += snprintf(&buf[n], (size_left - n), "MAU = 0x%08x\n",
781 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_MAU));
782 	n += snprintf(&buf[n], (size_left - n), "MD = 0x%04x\n",
783 	    pci_config_get16(pwp->pci_acc_handle, PMCS_PCI_MD));
784 	n += snprintf(&buf[n], (size_left - n),
785 	    "PCIE_CAP PCIE_NEXT_CAP PCIE_CAP_ID = 0x%08x\n",
786 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_PCIE));
787 	n += snprintf(&buf[n], (size_left - n), "DEVICE_CAP = 0x%08x\n",
788 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_DEV_CAP));
789 	n += snprintf(&buf[n], (size_left - n),
790 	    "DEVICE_STAT DEVICE_CTRL = 0x%08x\n",
791 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_DEV_CTRL));
792 	n += snprintf(&buf[n], (size_left - n), "LINK_CAP = 0x%08x\n",
793 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_LINK_CAP));
794 	n += snprintf(&buf[n], (size_left - n),
795 	    "LINK_STAT LINK_CTRL = 0x%08x\n",
796 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_LINK_CTRL));
797 	n += snprintf(&buf[n], (size_left - n), "MSIX_CAP = 0x%08x\n",
798 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_MSIX_CAP));
799 	n += snprintf(&buf[n], (size_left - n), "TBL_OFFSET = 0x%08x\n",
800 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_TBL_OFFSET));
801 	n += snprintf(&buf[n], (size_left - n), "PBA_OFFSET = 0x%08x\n",
802 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_PBA_OFFSET));
803 	n += snprintf(&buf[n], (size_left - n), "PCIE_CAP_HD = 0x%08x\n",
804 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_PCIE_CAP_HD));
805 	n += snprintf(&buf[n], (size_left - n), "UE_STAT = 0x%08x\n",
806 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_UE_STAT));
807 	n += snprintf(&buf[n], (size_left - n), "UE_MASK = 0x%08x\n",
808 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_UE_MASK));
809 	n += snprintf(&buf[n], (size_left - n), "UE_SEV = 0x%08x\n",
810 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_UE_SEV));
811 	n += snprintf(&buf[n], (size_left - n), "CE_STAT = 0x%08x\n",
812 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_CE_STAT));
813 	n += snprintf(&buf[n], (size_left - n), "CE_MASK = 0x%08x\n",
814 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_CE_MASK));
815 	n += snprintf(&buf[n], (size_left - n), "ADV_ERR_CTRL = 0x%08x\n",
816 	    pci_config_get32(pwp->pci_acc_handle, PMCS_PCI_ADV_ERR_CTRL));
817 	for (i = 0; i < 4; i++) {
818 		n += snprintf(&buf[n], (size_left - n), "HD_LOG_DW%d = "
819 		    "0x%08x\n", i, pci_config_get32(pwp->pci_acc_handle,
820 		    (PMCS_PCI_HD_LOG_DW + i * 4)));
821 	}
822 	n += snprintf(&buf[n], (size_left - n), "-----------------\n"
823 	    "Dump PCIe configuration registers end \n");
824 	return (n);
825 }
826 /*
827  * Called with axil_lock held
828  */
829 static boolean_t
pmcs_shift_axil(pmcs_hw_t * pwp,uint32_t offset)830 pmcs_shift_axil(pmcs_hw_t *pwp, uint32_t offset)
831 {
832 	uint32_t newaxil = offset & ~GSM_BASE_MASK;
833 
834 	ASSERT(mutex_owned(&pwp->axil_lock));
835 	ddi_put32(pwp->top_acc_handle,
836 	    &pwp->top_regs[PMCS_AXI_TRANS >> 2], newaxil);
837 	drv_usecwait(10);
838 
839 	if (ddi_get32(pwp->top_acc_handle,
840 	    &pwp->top_regs[PMCS_AXI_TRANS >> 2]) != newaxil) {
841 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
842 		    "AXIL register update failed");
843 		return (B_FALSE);
844 	}
845 	return (B_TRUE);
846 }
847 
848 static uint32_t
pmcs_get_axil(pmcs_hw_t * pwp)849 pmcs_get_axil(pmcs_hw_t *pwp)
850 {
851 	uint32_t regval = 0;
852 	mutex_enter(&pwp->axil_lock);
853 	regval = ddi_get32(pwp->top_acc_handle,
854 	    &pwp->top_regs[PMCS_AXI_TRANS >> 2]);
855 	mutex_exit(&pwp->axil_lock);
856 	return (regval);
857 }
858 
859 static void
pmcs_restore_axil(pmcs_hw_t * pwp,uint32_t oldaxil)860 pmcs_restore_axil(pmcs_hw_t *pwp, uint32_t oldaxil)
861 {
862 	mutex_enter(&pwp->axil_lock);
863 	ddi_put32(pwp->top_acc_handle,
864 	    &pwp->top_regs[PMCS_AXI_TRANS >> 2], oldaxil);
865 	drv_usecwait(10);
866 
867 	if (ddi_get32(pwp->top_acc_handle,
868 	    &pwp->top_regs[PMCS_AXI_TRANS >> 2]) != oldaxil) {
869 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
870 		    "AXIL register restore failed");
871 	}
872 	mutex_exit(&pwp->axil_lock);
873 }
874 
875 /*
876  * Dump Additional GSM Registers.
877  */
878 static int
pmcs_dump_gsm_addiregs(pmcs_hw_t * pwp,caddr_t buf,uint32_t size_left)879 pmcs_dump_gsm_addiregs(pmcs_hw_t *pwp, caddr_t buf, uint32_t size_left)
880 {
881 	uint32_t i = 0;
882 	int n = 0, j = 0, nums = 0;
883 	uint32_t gsm_addr = 0, addr = 0;
884 
885 	n += snprintf(&buf[n], (size_left - n), "\nDump GSM Sparse Registers:"
886 	    "\n-----------------\n");
887 	for (i = 0; i < sizeof (gsm_spregs) / sizeof (pmcs_sparse_regs_t);
888 	    i++) {
889 		gsm_addr =
890 		    gsm_spregs[i].shift_addr + gsm_spregs[i].offset_start;
891 		nums = gsm_spregs[i].offset_end - gsm_spregs[i].offset_start;
892 		if (gsm_spregs[i].flag & PMCS_SPREGS_BLOCK_START) {
893 			n += snprintf(&buf[n], (size_left - n), "\n%s - 0x%08X"
894 			    "[MEMBASE-III SHIFT = 0x%08X]\nOffset:\n",
895 			    gsm_spregs[i].desc ? gsm_spregs[i].desc : "NULL",
896 			    gsm_spregs[i].base_addr, gsm_spregs[i].shift_addr);
897 		}
898 
899 		if (nums == 0) {
900 			n += snprintf(&buf[n], (size_left - n),
901 			    "[%04X]: %08X\n", gsm_spregs[i].offset_start,
902 			    pmcs_rd_gsm_reg(pwp, 0, gsm_addr));
903 		} else if (nums > 0) {
904 			n += snprintf(&buf[n], (size_left - n),
905 			    "\n[%04X] - [%04X]: \n", gsm_spregs[i].offset_start,
906 			    gsm_spregs[i].offset_end);
907 
908 			j = 0;
909 			while (nums > 0) {
910 				addr = gsm_addr + j * 4;
911 				n += snprintf(&buf[n], (size_left - n),
912 				    "[%04X]: %08X\n", addr & GSM_BASE_MASK,
913 				    pmcs_rd_gsm_reg(pwp, 0, addr));
914 				j++;
915 				nums -= 4;
916 			}
917 		}
918 
919 	}
920 
921 	n += snprintf(&buf[n], (size_left - n), "-----------------\n"
922 	    "------------ Dump GSM Sparse Registers end ------------\n");
923 	return (n);
924 
925 }
926 
927 /*
928  * Dump GSM Memory Regions.
929  */
930 static int
pmcs_dump_gsm(pmcs_hw_t * pwp,caddr_t buf,uint32_t size_left)931 pmcs_dump_gsm(pmcs_hw_t *pwp, caddr_t buf, uint32_t size_left)
932 {
933 	int n = 0;
934 	uint32_t i = 0;
935 	uint32_t oldaxil = 0;
936 	uint32_t gsm_addr = 0;
937 	uint32_t *local_buf = NULL;
938 
939 	local_buf = kmem_zalloc(GSM_SM_BLKSZ, KM_NOSLEEP);
940 	if (local_buf == NULL) {
941 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
942 		    "%s: local_buf memory not allocated", __func__);
943 		return (0);
944 	}
945 
946 	oldaxil = pmcs_get_axil(pwp);
947 	mutex_enter(&pwp->axil_lock);
948 	n += snprintf(&buf[n], (size_left - n), "\nDump GSM IO Status Table: \n"
949 	    " -----------------\n");
950 	for (i = 0; i < 4; i++) {
951 		gsm_addr = IO_STATUS_TABLE_BASE + GSM_SM_BLKSZ * i;
952 		if (pmcs_shift_axil(pwp, gsm_addr) == B_TRUE) {
953 			gsm_addr &= GSM_BASE_MASK;
954 			ddi_rep_get32(pwp->gsm_acc_handle, local_buf,
955 			    &pwp->gsm_regs[gsm_addr >> 2], GSM_SM_BLKSZ >> 2,
956 			    DDI_DEV_AUTOINCR);
957 			n += pmcs_dump_binary(pwp, local_buf, i * GSM_SM_BLKSZ,
958 			    GSM_SM_BLKSZ >> 2, &buf[n], size_left - n);
959 		}
960 	}
961 	n += snprintf(&buf[n], (size_left - n), "\n-----------------\n"
962 	    "Dump GSM IO Status Table end \n");
963 	n += snprintf(&buf[n], (size_left - n), "\nDump Ring Buffer Storage: \n"
964 	    " -----------------\n");
965 	for (i = 0; i < 2; i++) {
966 		gsm_addr = RING_BUF_STORAGE_0 + GSM_SM_BLKSZ * i;
967 		if (pmcs_shift_axil(pwp, gsm_addr) == B_TRUE) {
968 			gsm_addr &= GSM_BASE_MASK;
969 			ddi_rep_get32(pwp->gsm_acc_handle, local_buf,
970 			    &pwp->gsm_regs[gsm_addr >> 2], GSM_SM_BLKSZ >> 2,
971 			    DDI_DEV_AUTOINCR);
972 			n += pmcs_dump_binary(pwp, local_buf, i * GSM_SM_BLKSZ,
973 			    GSM_SM_BLKSZ >> 2, &buf[n], size_left - n);
974 		}
975 	}
976 	n += snprintf(&buf[n], (size_left - n), "\n-----------------\n"
977 	    "Dump Ring Buffer Storage end \n");
978 
979 	n += snprintf(&buf[n], (size_left - n), "\nDump Ring Buffer Pointers:\n"
980 	    " -----------------\n");
981 		gsm_addr = RING_BUF_PTR_ACC_BASE + RING_BUF_PTR_OFF;
982 		if (pmcs_shift_axil(pwp, gsm_addr) == B_TRUE) {
983 			gsm_addr &= GSM_BASE_MASK;
984 			ddi_rep_get32(pwp->gsm_acc_handle, local_buf,
985 			    &pwp->gsm_regs[gsm_addr >> 2],
986 			    RING_BUF_PTR_SIZE >> 2, DDI_DEV_AUTOINCR);
987 			n += pmcs_dump_binary(pwp, local_buf, 0,
988 			    RING_BUF_PTR_SIZE >> 2, &buf[n], size_left - n);
989 		}
990 	n += snprintf(&buf[n], (size_left - n), "\n-----------------\n"
991 	    "Dump Ring Buffer Pointers end \n");
992 
993 	n += snprintf(&buf[n], (size_left - n), "\nDump Ring Buffer Access: \n"
994 	    " -----------------\n");
995 		gsm_addr = RING_BUF_PTR_ACC_BASE + RING_BUF_ACC_OFF;
996 		if (pmcs_shift_axil(pwp, gsm_addr) == B_TRUE) {
997 			gsm_addr &= GSM_BASE_MASK;
998 			ddi_rep_get32(pwp->gsm_acc_handle, local_buf,
999 			    &pwp->gsm_regs[gsm_addr >> 2],
1000 			    RING_BUF_ACC_SIZE >> 2, DDI_DEV_AUTOINCR);
1001 			n += pmcs_dump_binary(pwp, local_buf, 0,
1002 			    RING_BUF_ACC_SIZE >> 2, &buf[n], size_left - n);
1003 		}
1004 	n += snprintf(&buf[n], (size_left - n), "\n-----------------\n"
1005 	    "Dump Ring Buffer Access end \n");
1006 
1007 	n += snprintf(&buf[n], (size_left - n), "\nDump GSM SM: \n"
1008 	    " -----------------\n");
1009 	for (i = 0; i < 16; i++) {
1010 		gsm_addr = GSM_SM_BASE + GSM_SM_BLKSZ * i;
1011 		if (pmcs_shift_axil(pwp, gsm_addr) == B_TRUE) {
1012 			gsm_addr &= GSM_BASE_MASK;
1013 			ddi_rep_get32(pwp->gsm_acc_handle, local_buf,
1014 			    &pwp->gsm_regs[gsm_addr >> 2],
1015 			    GSM_SM_BLKSZ >> 2, DDI_DEV_AUTOINCR);
1016 			n += pmcs_dump_binary(pwp, local_buf, i * GSM_SM_BLKSZ,
1017 			    GSM_SM_BLKSZ >> 2, &buf[n], size_left - n);
1018 		}
1019 	}
1020 	mutex_exit(&pwp->axil_lock);
1021 	pmcs_restore_axil(pwp, oldaxil);
1022 
1023 	n += snprintf(&buf[n], (size_left - n), "\n-----------------\n"
1024 	    "Dump GSM SM end \n");
1025 	n += snprintf(&buf[n], (size_left - n), "-----------------\n"
1026 	    "\n------------ Dump GSM Memory Regions end  -------------\n");
1027 	if (local_buf) {
1028 		kmem_free(local_buf, GSM_SM_BLKSZ);
1029 	}
1030 	return (n);
1031 }
1032 
1033 /*
1034  * Trace current Inbound Message host sent to SPC.
1035  */
1036 void
pmcs_iqp_trace(pmcs_hw_t * pwp,uint32_t qnum)1037 pmcs_iqp_trace(pmcs_hw_t *pwp, uint32_t qnum)
1038 {
1039 	uint32_t k = 0;
1040 	int n = 0;
1041 	uint32_t *ptr = NULL;
1042 	char *tbuf = pwp->iqpt->curpos;
1043 	uint32_t size_left = pwp->iqpt->size_left;
1044 
1045 	if (tbuf == NULL) {
1046 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1047 		    "%s: trace buffer is not ready,"
1048 		    " Inbound Message from host to SPC is not traced",
1049 		    __func__);
1050 		return;
1051 	} else if (size_left < PMCS_QENTRY_SIZE * PMCS_QENTRY_SIZE) {
1052 		tbuf = pwp->iqpt->curpos = pwp->iqpt->head;
1053 		size_left = pwp->iqpt->size_left = PMCS_IQP_TRACE_BUFFER_SIZE;
1054 	}
1055 
1056 	ptr = &pwp->iqp[qnum][pwp->shadow_iqpi[qnum] *
1057 	    (PMCS_QENTRY_SIZE >> 2)];
1058 	for (k = 0; k < (PMCS_QENTRY_SIZE / sizeof (uint32_t));
1059 	    k += 8) {
1060 		n += snprintf(&tbuf[n], (size_left - n),
1061 		    "0x%08x 0x%08x 0x%08x 0x%08x "
1062 		    "0x%08x 0x%08x 0x%08x 0x%08x\n",
1063 		    LE_32(ptr[k]), LE_32(ptr[k+1]),
1064 		    LE_32(ptr[k+2]), LE_32(ptr[k+3]),
1065 		    LE_32(ptr[k+4]), LE_32(ptr[k+5]),
1066 		    LE_32(ptr[k+6]), LE_32(ptr[k+7]));
1067 	}
1068 	pwp->iqpt->size_left -= n;
1069 	if (pwp->iqpt->size_left > 0) {
1070 		pwp->iqpt->curpos += n;
1071 	} else {
1072 		pwp->iqpt->curpos =
1073 		    pwp->iqpt->head + PMCS_IQP_TRACE_BUFFER_SIZE - 1;
1074 	}
1075 }
1076 
1077 /*
1078  * Capture HSST State Registers.
1079  */
1080 static int
pmcs_dump_hsst_sregs(pmcs_hw_t * pwp,caddr_t buf,uint32_t size_left)1081 pmcs_dump_hsst_sregs(pmcs_hw_t *pwp, caddr_t buf, uint32_t size_left)
1082 {
1083 	uint32_t i = 0, j = 0, addr = 0;
1084 	int n = 0;
1085 
1086 	n += snprintf(&buf[n], (size_left - n), "\nHSST State Capture : \n"
1087 	    "-----------------\n");
1088 	n += snprintf(&buf[n], (size_left - n), "%s \t %s \n",
1089 	    hsst_state[8].desc ? hsst_state[8].desc : "NULL",
1090 	    hsst_state[16].desc ? hsst_state[16].desc : "NULL");
1091 
1092 	for (i = 0; i < 8; i++) {
1093 		addr = hsst_state[i].offset_start +
1094 		    hsst_state[i].shift_addr;
1095 		n += snprintf(&buf[n], (size_left - n), "Phy[%1d]\n", i);
1096 		for (j = 0; j < 6; j++) {
1097 			pmcs_wr_gsm_reg(pwp, addr, j);
1098 			pmcs_wr_gsm_reg(pwp, addr, (0x0100 + j));
1099 			addr = hsst_state[i+8].offset_start +
1100 			    hsst_state[i+8].shift_addr;
1101 			n += snprintf(&buf[n], (size_left - n),
1102 			    "[%08X]: %08X\t", addr, pmcs_rd_gsm_reg(pwp, 0,
1103 			    addr));
1104 			addr = hsst_state[i+16].offset_start +
1105 			    hsst_state[i+16].shift_addr;
1106 			n += snprintf(&buf[n], (size_left - n),
1107 			    "[%08X]: %08X\n", addr, pmcs_rd_gsm_reg(pwp, 0,
1108 			    addr));
1109 		}
1110 
1111 	}
1112 	return (n);
1113 
1114 }
1115 
1116 /*
1117  * Capture SSPA State Registers.
1118  */
1119 static int
pmcs_dump_sspa_sregs(pmcs_hw_t * pwp,caddr_t buf,uint32_t size_left)1120 pmcs_dump_sspa_sregs(pmcs_hw_t *pwp, caddr_t buf, uint32_t size_left)
1121 {
1122 	uint32_t i = 0, rv = 0, addr = 0;
1123 	int n = 0;
1124 
1125 	n += snprintf(&buf[n], (size_left - n), "\nSSPA State Capture : \n"
1126 	    "-----------------\n");
1127 	for (i = 0; i < 8; i++) {
1128 		if (sspa_state[i].flag & PMCS_SPREGS_BLOCK_START) {
1129 			n += snprintf(&buf[n], (size_left - n), "%s \n",
1130 			    sspa_state[i].desc ? sspa_state[i].desc : "NULL");
1131 		}
1132 		addr = sspa_state[i].offset_start + sspa_state[i].shift_addr;
1133 		rv = pmcs_rd_gsm_reg(pwp, 0, addr);
1134 		rv |= PMCS_SSPA_CONTROL_REGISTER_BIT27;
1135 		pmcs_wr_gsm_reg(pwp, addr, rv);
1136 		n += snprintf(&buf[n], (size_left - n), "[%08X]: %08X \n",
1137 		    addr, pmcs_rd_gsm_reg(pwp, 0, addr));
1138 
1139 	}
1140 	return (n);
1141 }
1142 
1143 /*
1144  * Dump fatal error register content from GSM.
1145  */
1146 int
pmcs_dump_feregs(pmcs_hw_t * pwp,uint32_t * addr,uint8_t nvmd,caddr_t buf,uint32_t size_left)1147 pmcs_dump_feregs(pmcs_hw_t *pwp, uint32_t *addr, uint8_t nvmd,
1148     caddr_t buf, uint32_t size_left)
1149 {
1150 	uint32_t offset = 0, length = 0;
1151 	int i = 0;
1152 	uint8_t *ptr = (uint8_t *)addr;
1153 
1154 	if ((addr == NULL) || (buf == NULL)) {
1155 		return (0);
1156 	}
1157 	switch (nvmd) {
1158 		case PMCIN_NVMD_AAP1:
1159 			offset = pmcs_rd_mpi_tbl(pwp, PMCS_FERDOMSGU);
1160 			length = pmcs_rd_mpi_tbl(pwp, PMCS_FERDLMSGU);
1161 			break;
1162 		case PMCIN_NVMD_IOP:
1163 			offset = pmcs_rd_mpi_tbl(pwp, PMCS_FERDOIOP);
1164 			length = pmcs_rd_mpi_tbl(pwp, PMCS_FERDLIOP);
1165 			break;
1166 		default:
1167 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1168 			    "UNKNOWN NVMD DEVICE %s():%d", __func__, __LINE__);
1169 			return (0);
1170 	}
1171 
1172 	while ((i < length) && (ptr[i + offset] != 0xff) &&
1173 	    (ptr[i + offset] != '\0')) {
1174 		i += snprintf(&buf[i], (size_left - i),
1175 		    "%c", ptr[i + offset]);
1176 	}
1177 	return (i);
1178 }
1179 
1180 /*
1181  * Write out either the AAP1 or IOP event log
1182  */
1183 static void
pmcs_write_fwlog(pmcs_hw_t * pwp,pmcs_fw_event_hdr_t * fwlogp)1184 pmcs_write_fwlog(pmcs_hw_t *pwp, pmcs_fw_event_hdr_t *fwlogp)
1185 {
1186 	struct vnode *vnp;
1187 	caddr_t fwlogfile, bufp;
1188 	rlim64_t rlimit;
1189 	ssize_t resid;
1190 	offset_t offset = 0;
1191 	int error;
1192 	uint32_t data_len;
1193 
1194 	if (fwlogp == pwp->fwlogp_aap1) {
1195 		fwlogfile = pwp->fwlogfile_aap1;
1196 	} else {
1197 		fwlogfile = pwp->fwlogfile_iop;
1198 	}
1199 
1200 	if ((error = vn_open(fwlogfile, UIO_SYSSPACE, FCREAT|FWRITE, 0644,
1201 	    &vnp, CRCREAT, 0)) != 0) {
1202 		pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1203 		    "%s: Could not create '%s', error %d", __func__,
1204 		    fwlogfile, error);
1205 		return;
1206 	}
1207 
1208 	bufp = (caddr_t)fwlogp;
1209 	data_len = PMCS_FWLOG_SIZE / 2;
1210 	rlimit = data_len + 1;
1211 	for (;;) {
1212 		error = vn_rdwr(UIO_WRITE, vnp, bufp, data_len, offset,
1213 		    UIO_SYSSPACE, FSYNC, rlimit, CRED(), &resid);
1214 		if (error) {
1215 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1216 			    "%s: could not write %s, error %d", __func__,
1217 			    fwlogfile, error);
1218 			break;
1219 		}
1220 		if (resid == data_len) {
1221 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1222 			    "%s: Out of space in %s, error %d", __func__,
1223 			    fwlogfile, error);
1224 			error = ENOSPC;
1225 			break;
1226 		}
1227 		if (resid == 0)
1228 			break;
1229 		offset += (data_len - resid);
1230 		data_len = (ssize_t)resid;
1231 	}
1232 
1233 	if (error = VOP_CLOSE(vnp, FWRITE, 1, (offset_t)0, kcred, NULL)) {
1234 		if (!error) {
1235 			pmcs_prt(pwp, PMCS_PRT_DEBUG, NULL, NULL,
1236 			    "%s: Error on close %s, error %d", __func__,
1237 			    fwlogfile, error);
1238 		}
1239 	}
1240 
1241 	VN_RELE(vnp);
1242 }
1243 
1244 /*
1245  * Check the in-memory event log.  If it's filled up to or beyond the
1246  * threshold, write it out to the configured filename.
1247  */
1248 void
pmcs_gather_fwlog(pmcs_hw_t * pwp)1249 pmcs_gather_fwlog(pmcs_hw_t *pwp)
1250 {
1251 	uint32_t num_entries_aap1, num_entries_iop, fname_suffix;
1252 
1253 	ASSERT(!mutex_owned(&pwp->lock));
1254 
1255 	/*
1256 	 * Get our copies of the latest indices
1257 	 */
1258 	pwp->fwlog_latest_idx_aap1 = pwp->fwlogp_aap1->fw_el_latest_idx;
1259 	pwp->fwlog_latest_idx_iop = pwp->fwlogp_iop->fw_el_latest_idx;
1260 
1261 	/*
1262 	 * We need entries in the log before we can know how big they are
1263 	 */
1264 	if ((pwp->fwlog_max_entries_aap1 == 0) &&
1265 	    (pwp->fwlogp_aap1->fw_el_latest_idx != 0)) {
1266 		pwp->fwlog_max_entries_aap1 =
1267 		    (PMCS_FWLOG_SIZE / 2) / pwp->fwlogp_aap1->fw_el_entry_size;
1268 		pwp->fwlog_threshold_aap1 =
1269 		    (pwp->fwlog_max_entries_aap1 * PMCS_FWLOG_THRESH) / 100;
1270 	}
1271 
1272 	if ((pwp->fwlog_max_entries_iop == 0) &&
1273 	    (pwp->fwlogp_iop->fw_el_latest_idx != 0)) {
1274 		pwp->fwlog_max_entries_iop =
1275 		    (PMCS_FWLOG_SIZE / 2) / pwp->fwlogp_iop->fw_el_entry_size;
1276 		pwp->fwlog_threshold_iop =
1277 		    (pwp->fwlog_max_entries_iop * PMCS_FWLOG_THRESH) / 100;
1278 	}
1279 
1280 	/*
1281 	 * Check if we've reached the threshold in the AAP1 log.  We do this
1282 	 * by comparing the latest index with our copy of the oldest index
1283 	 * (not the chip's).
1284 	 */
1285 	if (pwp->fwlog_latest_idx_aap1 >= pwp->fwlog_oldest_idx_aap1) {
1286 		/* Log has not wrapped */
1287 		num_entries_aap1 =
1288 		    pwp->fwlog_latest_idx_aap1 - pwp->fwlog_oldest_idx_aap1;
1289 	} else {
1290 		/* Log has wrapped */
1291 		num_entries_aap1 = pwp->fwlog_max_entries_aap1 -
1292 		    (pwp->fwlog_oldest_idx_aap1 - pwp->fwlog_latest_idx_aap1);
1293 	}
1294 
1295 	/*
1296 	 * Now check the IOP log
1297 	 */
1298 	if (pwp->fwlog_latest_idx_iop >= pwp->fwlog_oldest_idx_iop) {
1299 		/* Log has not wrapped */
1300 		num_entries_iop = pwp->fwlog_latest_idx_iop -
1301 		    pwp->fwlog_oldest_idx_iop;
1302 	} else {
1303 		/* Log has wrapped */
1304 		num_entries_iop = pwp->fwlog_max_entries_iop -
1305 		    (pwp->fwlog_oldest_idx_iop - pwp->fwlog_latest_idx_iop);
1306 	}
1307 
1308 	if ((num_entries_aap1 < pwp->fwlog_threshold_aap1) &&
1309 	    (num_entries_iop < pwp->fwlog_threshold_iop)) {
1310 		return;
1311 	}
1312 
1313 	/*
1314 	 * We also can't write the event log out if it's too early in boot
1315 	 * (i.e. the root fs isn't mounted yet).
1316 	 */
1317 	if (!modrootloaded) {
1318 		return;
1319 	}
1320 
1321 	/*
1322 	 * Write out the necessary log file(s), update the "oldest" pointers
1323 	 * and the suffix to the written filenames.
1324 	 */
1325 	if (num_entries_aap1 >= pwp->fwlog_threshold_aap1) {
1326 		pmcs_write_fwlog(pwp, pwp->fwlogp_aap1);
1327 		pwp->fwlog_oldest_idx_aap1 = pwp->fwlog_latest_idx_aap1;
1328 
1329 		fname_suffix = strlen(pwp->fwlogfile_aap1) - 1;
1330 		if (pwp->fwlogfile_aap1[fname_suffix] == '4') {
1331 			pwp->fwlogfile_aap1[fname_suffix] = '0';
1332 		} else {
1333 			++pwp->fwlogfile_aap1[fname_suffix];
1334 		}
1335 	}
1336 
1337 	if (num_entries_iop >= pwp->fwlog_threshold_iop) {
1338 		pmcs_write_fwlog(pwp, pwp->fwlogp_iop);
1339 		pwp->fwlog_oldest_idx_iop = pwp->fwlog_latest_idx_iop;
1340 
1341 		fname_suffix = strlen(pwp->fwlogfile_iop) - 1;
1342 		if (pwp->fwlogfile_iop[fname_suffix] == '4') {
1343 			pwp->fwlogfile_iop[fname_suffix] = '0';
1344 		} else {
1345 			++pwp->fwlogfile_iop[fname_suffix];
1346 		}
1347 	}
1348 }
1349