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