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