1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 */
25
26 #include <limits.h>
27 #include <sys/mdb_modapi.h>
28 #include <mdb/mdb_ctf.h>
29 #include <sys/sysinfo.h>
30 #include <sys/byteorder.h>
31 #include <sys/nvpair.h>
32 #include <sys/damap.h>
33 #include <sys/scsi/scsi.h>
34 #include <sys/scsi/adapters/pmcs/pmcs.h>
35 #ifndef _KMDB
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #endif /* _KMDB */
41
42 /*
43 * We need use this to pass the settings when display_iport
44 */
45 typedef struct per_iport_setting {
46 uint_t pis_damap_info; /* -m: DAM/damap */
47 uint_t pis_dtc_info; /* -d: device tree children: dev_info/path_info */
48 } per_iport_setting_t;
49
50 /*
51 * This structure is used for sorting work structures by the wserno
52 */
53 typedef struct wserno_list {
54 int serno;
55 int idx;
56 struct wserno_list *next;
57 struct wserno_list *prev;
58 } wserno_list_t;
59
60 #define MDB_RD(a, b, c) mdb_vread(a, b, (uintptr_t)c)
61 #define NOREAD(a, b) mdb_warn("could not read " #a " at 0x%p", b)
62
63 static pmcs_hw_t ss;
64 static pmcs_xscsi_t **targets = NULL;
65 static int target_idx;
66
67 static uint32_t sas_phys, sata_phys, exp_phys, num_expanders, empty_phys;
68
69 static pmcs_phy_t *pmcs_next_sibling(pmcs_phy_t *phyp);
70 static void display_one_work(pmcwork_t *wp, int verbose, int idx);
71
72 static void
print_sas_address(pmcs_phy_t * phy)73 print_sas_address(pmcs_phy_t *phy)
74 {
75 int idx;
76
77 for (idx = 0; idx < 8; idx++) {
78 mdb_printf("%02x", phy->sas_address[idx]);
79 }
80 }
81
82 static void
pmcs_fwtime_to_systime(struct pmcs_hw ss,uint32_t fw_hi,uint32_t fw_lo,struct timespec * stime)83 pmcs_fwtime_to_systime(struct pmcs_hw ss, uint32_t fw_hi, uint32_t fw_lo,
84 struct timespec *stime)
85 {
86 uint64_t fwtime;
87 time_t secs;
88 long nsecs;
89 boolean_t backward_time = B_FALSE;
90
91 fwtime = ((uint64_t)fw_hi << 32) | fw_lo;
92
93 /*
94 * If fwtime < ss.fw_timestamp, then we need to adjust the clock
95 * time backwards from ss.sys_timestamp. Otherwise, the adjustment
96 * goes forward in time
97 */
98 if (fwtime >= ss.fw_timestamp) {
99 fwtime -= ss.fw_timestamp;
100 } else {
101 fwtime = ss.fw_timestamp - fwtime;
102 backward_time = B_TRUE;
103 }
104
105 secs = ((time_t)fwtime / NSECS_PER_SEC);
106 nsecs = ((long)fwtime % NSECS_PER_SEC);
107
108 stime->tv_sec = ss.sys_timestamp.tv_sec;
109 stime->tv_nsec = ss.sys_timestamp.tv_nsec;
110
111 if (backward_time) {
112 if (stime->tv_nsec < nsecs) {
113 stime->tv_sec--;
114 stime->tv_nsec = stime->tv_nsec + NSECS_PER_SEC - nsecs;
115 } else {
116 stime->tv_nsec -= nsecs;
117 }
118 stime->tv_sec -= secs;
119 } else {
120 if (stime->tv_nsec + nsecs > NSECS_PER_SEC) {
121 stime->tv_sec++;
122 }
123 stime->tv_nsec = (stime->tv_nsec + nsecs) % NSECS_PER_SEC;
124 stime->tv_sec += secs;
125 }
126 }
127
128 /*ARGSUSED*/
129 static void
display_ic(struct pmcs_hw m,int verbose)130 display_ic(struct pmcs_hw m, int verbose)
131 {
132 int msec_per_tick;
133
134 if (mdb_readvar(&msec_per_tick, "msec_per_tick") == -1) {
135 mdb_warn("can't read msec_per_tick");
136 msec_per_tick = 0;
137 }
138
139 mdb_printf("\n");
140 mdb_printf("Interrupt coalescing timer info\n");
141 mdb_printf("-------------------------------\n");
142 if (msec_per_tick == 0) {
143 mdb_printf("Quantum : ?? ms\n");
144 } else {
145 mdb_printf("Quantum : %d ms\n",
146 m.io_intr_coal.quantum * msec_per_tick);
147 }
148 mdb_printf("Timer enabled : ");
149 if (m.io_intr_coal.timer_on) {
150 mdb_printf("Yes\n");
151 mdb_printf("Coalescing timer value : %d us\n",
152 m.io_intr_coal.intr_coal_timer);
153 } else {
154 mdb_printf("No\n");
155 }
156 mdb_printf("Total nsecs between interrupts: %ld\n",
157 m.io_intr_coal.nsecs_between_intrs);
158 mdb_printf("Time of last I/O interrupt : %ld\n",
159 m.io_intr_coal.last_io_comp);
160 mdb_printf("Number of I/O interrupts : %d\n",
161 m.io_intr_coal.num_intrs);
162 mdb_printf("Number of I/O completions : %d\n",
163 m.io_intr_coal.num_io_completions);
164 mdb_printf("Max I/O completion interrupts : %d\n",
165 m.io_intr_coal.max_io_completions);
166 mdb_printf("Measured ECHO int latency : %d ns\n",
167 m.io_intr_coal.intr_latency);
168 mdb_printf("Interrupt threshold : %d\n",
169 m.io_intr_coal.intr_threshold);
170 }
171
172 /*ARGSUSED*/
173 static int
pmcs_iport_phy_walk_cb(uintptr_t addr,const void * wdata,void * priv)174 pmcs_iport_phy_walk_cb(uintptr_t addr, const void *wdata, void *priv)
175 {
176 struct pmcs_phy phy;
177
178 if (mdb_vread(&phy, sizeof (struct pmcs_phy), addr) !=
179 sizeof (struct pmcs_phy)) {
180 return (DCMD_ERR);
181 }
182
183 mdb_printf("%16p %2d\n", addr, phy.phynum);
184
185 return (0);
186 }
187
188 static int
display_iport_damap(dev_info_t * pdip)189 display_iport_damap(dev_info_t *pdip)
190 {
191 int rval = DCMD_ERR;
192 struct dev_info dip;
193 scsi_hba_tran_t sht;
194 mdb_ctf_id_t istm_ctfid; /* impl_scsi_tgtmap_t ctf_id */
195 ulong_t tmd_offset = 0; /* tgtmap_dam offset to impl_scsi_tgtmap_t */
196 uintptr_t dam0;
197 uintptr_t dam1;
198
199 if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) !=
200 sizeof (struct dev_info)) {
201 return (rval);
202 }
203
204 if (dip.devi_driver_data == NULL) {
205 return (rval);
206 }
207
208 if (mdb_vread(&sht, sizeof (scsi_hba_tran_t),
209 (uintptr_t)dip.devi_driver_data) != sizeof (scsi_hba_tran_t)) {
210 return (rval);
211 }
212
213 if (sht.tran_tgtmap == NULL) {
214 return (rval);
215 }
216
217 if (mdb_ctf_lookup_by_name("impl_scsi_tgtmap_t", &istm_ctfid) != 0) {
218 return (rval);
219 }
220
221 if (mdb_ctf_offsetof(istm_ctfid, "tgtmap_dam", &tmd_offset) != 0) {
222 return (rval);
223 }
224
225 tmd_offset /= NBBY;
226 mdb_vread(&dam0, sizeof (dam0),
227 (uintptr_t)(tmd_offset + (char *)sht.tran_tgtmap));
228 mdb_vread(&dam1, sizeof (dam1),
229 (uintptr_t)(sizeof (dam0) + tmd_offset + (char *)sht.tran_tgtmap));
230
231 if (dam0 != NULL) {
232 rval = mdb_call_dcmd("damap", dam0, DCMD_ADDRSPEC, 0, NULL);
233 mdb_printf("\n");
234 if (rval != DCMD_OK) {
235 return (rval);
236 }
237 }
238
239 if (dam1 != NULL) {
240 rval = mdb_call_dcmd("damap", dam1, DCMD_ADDRSPEC, 0, NULL);
241 mdb_printf("\n");
242 }
243
244 return (rval);
245 }
246
247 /* ARGSUSED */
248 static int
display_iport_di_cb(uintptr_t addr,const void * wdata,void * priv)249 display_iport_di_cb(uintptr_t addr, const void *wdata, void *priv)
250 {
251 uint_t *idx = (uint_t *)priv;
252 struct dev_info dip;
253 char devi_name[MAXNAMELEN];
254 char devi_addr[MAXNAMELEN];
255
256 if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)addr) !=
257 sizeof (struct dev_info)) {
258 return (DCMD_ERR);
259 }
260
261 if (mdb_readstr(devi_name, sizeof (devi_name),
262 (uintptr_t)dip.devi_node_name) == -1) {
263 devi_name[0] = '?';
264 devi_name[1] = '\0';
265 }
266
267 if (mdb_readstr(devi_addr, sizeof (devi_addr),
268 (uintptr_t)dip.devi_addr) == -1) {
269 devi_addr[0] = '?';
270 devi_addr[1] = '\0';
271 }
272
273 mdb_printf(" %3d: @%-21s%10s@\t%p::devinfo -s\n",
274 (*idx)++, devi_addr, devi_name, addr);
275 return (DCMD_OK);
276 }
277
278 /* ARGSUSED */
279 static int
display_iport_pi_cb(uintptr_t addr,const void * wdata,void * priv)280 display_iport_pi_cb(uintptr_t addr, const void *wdata, void *priv)
281 {
282 uint_t *idx = (uint_t *)priv;
283 struct mdi_pathinfo mpi;
284 char pi_addr[MAXNAMELEN];
285
286 if (mdb_vread(&mpi, sizeof (struct mdi_pathinfo), (uintptr_t)addr) !=
287 sizeof (struct mdi_pathinfo)) {
288 return (DCMD_ERR);
289 }
290
291 if (mdb_readstr(pi_addr, sizeof (pi_addr),
292 (uintptr_t)mpi.pi_addr) == -1) {
293 pi_addr[0] = '?';
294 pi_addr[1] = '\0';
295 }
296
297 mdb_printf(" %3d: @%-21s %p::print struct mdi_pathinfo\n",
298 (*idx)++, pi_addr, addr);
299 return (DCMD_OK);
300 }
301
302 static int
display_iport_dtc(dev_info_t * pdip)303 display_iport_dtc(dev_info_t *pdip)
304 {
305 int rval = DCMD_ERR;
306 struct dev_info dip;
307 struct mdi_phci phci;
308 uint_t didx = 1;
309 uint_t pidx = 1;
310
311 if (mdb_vread(&dip, sizeof (struct dev_info), (uintptr_t)pdip) !=
312 sizeof (struct dev_info)) {
313 return (rval);
314 }
315
316 mdb_printf("Device tree children - dev_info:\n");
317 if (dip.devi_child == NULL) {
318 mdb_printf("\tdevi_child is NULL, no dev_info\n\n");
319 goto skip_di;
320 }
321
322 /*
323 * First, we dump the iport's children dev_info node information.
324 * use existing walker: devinfo_siblings
325 */
326 mdb_printf("\t#: @unit-address name@\tdrill-down\n");
327 rval = mdb_pwalk("devinfo_siblings", display_iport_di_cb,
328 (void *)&didx, (uintptr_t)dip.devi_child);
329 mdb_printf("\n");
330
331 skip_di:
332 /*
333 * Then we try to dump the iport's path_info node information.
334 * use existing walker: mdipi_phci_list
335 */
336 mdb_printf("Device tree children - path_info:\n");
337 if (mdb_vread(&phci, sizeof (struct mdi_phci),
338 (uintptr_t)dip.devi_mdi_xhci) != sizeof (struct mdi_phci)) {
339 mdb_printf("\tdevi_mdi_xhci is NULL, no path_info\n\n");
340 return (rval);
341 }
342
343 if (phci.ph_path_head == NULL) {
344 mdb_printf("\tph_path_head is NULL, no path_info\n\n");
345 return (rval);
346 }
347
348 mdb_printf("\t#: @unit-address drill-down\n");
349 rval = mdb_pwalk("mdipi_phci_list", display_iport_pi_cb,
350 (void *)&pidx, (uintptr_t)phci.ph_path_head);
351 mdb_printf("\n");
352 return (rval);
353 }
354
355 static void
display_iport_more(dev_info_t * dip,per_iport_setting_t * pis)356 display_iport_more(dev_info_t *dip, per_iport_setting_t *pis)
357 {
358 if (pis->pis_damap_info) {
359 (void) display_iport_damap(dip);
360 }
361
362 if (pis->pis_dtc_info) {
363 (void) display_iport_dtc(dip);
364 }
365 }
366
367 /*ARGSUSED*/
368 static int
pmcs_iport_walk_cb(uintptr_t addr,const void * wdata,void * priv)369 pmcs_iport_walk_cb(uintptr_t addr, const void *wdata, void *priv)
370 {
371 struct pmcs_iport iport;
372 uintptr_t list_addr;
373 char *ua_state;
374 char portid[4];
375 char unit_address[34];
376 per_iport_setting_t *pis = (per_iport_setting_t *)priv;
377
378 if (mdb_vread(&iport, sizeof (struct pmcs_iport), addr) !=
379 sizeof (struct pmcs_iport)) {
380 return (DCMD_ERR);
381 }
382
383 if (mdb_readstr(unit_address, sizeof (unit_address),
384 (uintptr_t)(iport.ua)) == -1) {
385 strncpy(unit_address, "Unset", sizeof (unit_address));
386 }
387
388 if (iport.portid == 0xffff) {
389 mdb_snprintf(portid, sizeof (portid), "%s", "-");
390 } else if (iport.portid == PMCS_IPORT_INVALID_PORT_ID) {
391 mdb_snprintf(portid, sizeof (portid), "%s", "N/A");
392 } else {
393 mdb_snprintf(portid, sizeof (portid), "%d", iport.portid);
394 }
395
396 switch (iport.ua_state) {
397 case UA_INACTIVE:
398 ua_state = "Inactive";
399 break;
400 case UA_PEND_ACTIVATE:
401 ua_state = "PendActivate";
402 break;
403 case UA_ACTIVE:
404 ua_state = "Active";
405 break;
406 case UA_PEND_DEACTIVATE:
407 ua_state = "PendDeactivate";
408 break;
409 default:
410 ua_state = "Unknown";
411 }
412
413 if (strlen(unit_address) < 3) {
414 /* Standard iport unit address */
415 mdb_printf("UA %-16s %16s %8s %8s %16s", "Iport", "UA State",
416 "PortID", "NumPhys", "DIP\n");
417 mdb_printf("%2s %16p %16s %8s %8d %16p\n", unit_address, addr,
418 ua_state, portid, iport.nphy, iport.dip);
419 } else {
420 /* Temporary iport unit address */
421 mdb_printf("%-32s %16s %20s %8s %8s %16s", "UA", "Iport",
422 "UA State", "PortID", "NumPhys", "DIP\n");
423 mdb_printf("%32s %16p %20s %8s %8d %16p\n", unit_address, addr,
424 ua_state, portid, iport.nphy, iport.dip);
425 }
426
427 if (iport.nphy > 0) {
428 mdb_inc_indent(4);
429 mdb_printf("%-18s %8s", "Phy", "PhyNum\n");
430 mdb_inc_indent(2);
431 list_addr =
432 (uintptr_t)(addr + offsetof(struct pmcs_iport, phys));
433 if (mdb_pwalk("list", pmcs_iport_phy_walk_cb, NULL,
434 list_addr) == -1) {
435 mdb_warn("pmcs iport walk failed");
436 }
437 mdb_dec_indent(6);
438 mdb_printf("\n");
439 }
440
441 /*
442 * See if we need to show more information based on 'd' or 'm' options
443 */
444 display_iport_more(iport.dip, pis);
445
446 return (0);
447 }
448
449 /*ARGSUSED*/
450 static void
display_iport(struct pmcs_hw m,uintptr_t addr,int verbose,per_iport_setting_t * pis)451 display_iport(struct pmcs_hw m, uintptr_t addr, int verbose,
452 per_iport_setting_t *pis)
453 {
454 uintptr_t list_addr;
455
456 if (m.iports_attached) {
457 mdb_printf("Iport information:\n");
458 mdb_printf("-----------------\n");
459 } else {
460 mdb_printf("No Iports found.\n\n");
461 return;
462 }
463
464 list_addr = (uintptr_t)(addr + offsetof(struct pmcs_hw, iports));
465
466 if (mdb_pwalk("list", pmcs_iport_walk_cb, pis, list_addr) == -1) {
467 mdb_warn("pmcs iport walk failed");
468 }
469
470 mdb_printf("\n");
471 }
472
473 /* ARGSUSED */
474 static int
pmcs_utarget_walk_cb(uintptr_t addr,const void * wdata,void * priv)475 pmcs_utarget_walk_cb(uintptr_t addr, const void *wdata, void *priv)
476 {
477 pmcs_phy_t phy;
478
479 if (mdb_vread(&phy, sizeof (pmcs_phy_t), (uintptr_t)addr) == -1) {
480 mdb_warn("pmcs_utarget_walk_cb: Failed to read PHY at %p",
481 (void *)addr);
482 return (DCMD_ERR);
483 }
484
485 if (phy.configured && (phy.target == NULL)) {
486 mdb_printf("SAS address: ");
487 print_sas_address(&phy);
488 mdb_printf(" DType: ");
489 switch (phy.dtype) {
490 case SAS:
491 mdb_printf("%4s", "SAS");
492 break;
493 case SATA:
494 mdb_printf("%4s", "SATA");
495 break;
496 case EXPANDER:
497 mdb_printf("%4s", "SMP");
498 break;
499 default:
500 mdb_printf("%4s", "N/A");
501 break;
502 }
503 mdb_printf(" Path: %s\n", phy.path);
504 }
505
506 return (0);
507 }
508
509 static void
display_unconfigured_targets(uintptr_t addr)510 display_unconfigured_targets(uintptr_t addr)
511 {
512 mdb_printf("Unconfigured target SAS address:\n\n");
513
514 if (mdb_pwalk("pmcs_phys", pmcs_utarget_walk_cb, NULL, addr) == -1) {
515 mdb_warn("pmcs phys walk failed");
516 }
517 }
518
519 static void
display_completion_queue(struct pmcs_hw ss)520 display_completion_queue(struct pmcs_hw ss)
521 {
522 pmcs_iocomp_cb_t ccb, *ccbp;
523 pmcwork_t work;
524
525 if (ss.iocomp_cb_head == NULL) {
526 mdb_printf("Completion queue is empty.\n");
527 return;
528 }
529
530 ccbp = ss.iocomp_cb_head;
531 mdb_printf("%8s %10s %20s %8s %8s O D\n",
532 "HTag", "State", "Phy Path", "Target", "Timer");
533
534 while (ccbp) {
535 if (mdb_vread(&ccb, sizeof (pmcs_iocomp_cb_t),
536 (uintptr_t)ccbp) != sizeof (pmcs_iocomp_cb_t)) {
537 mdb_warn("Unable to read completion queue entry\n");
538 return;
539 }
540
541 if (mdb_vread(&work, sizeof (pmcwork_t), (uintptr_t)ccb.pwrk)
542 != sizeof (pmcwork_t)) {
543 mdb_warn("Unable to read work structure\n");
544 return;
545 }
546
547 /*
548 * Only print the work structure if it's still active. If
549 * it's not, it's been completed since we started looking at
550 * it.
551 */
552 if (work.state != PMCS_WORK_STATE_NIL) {
553 display_one_work(&work, 0, 0);
554 }
555 ccbp = ccb.next;
556 }
557 }
558
559 static void
display_event_log(struct pmcs_hw ss)560 display_event_log(struct pmcs_hw ss)
561 {
562 pmcs_fw_event_hdr_t fwhdr;
563 char *header_id, *entry, *fwlogp;
564 uint32_t total_size = PMCS_FWLOG_SIZE, log_size, index, *swapp, sidx;
565 pmcs_fw_event_entry_t *fw_entryp;
566 struct timespec systime;
567
568 if (ss.fwlogp == NULL) {
569 mdb_printf("There is no firmware event log.\n");
570 return;
571 }
572
573 fwlogp = (char *)ss.fwlogp;
574
575 while (total_size != 0) {
576 if (mdb_vread(&fwhdr, sizeof (pmcs_fw_event_hdr_t),
577 (uintptr_t)fwlogp) != sizeof (pmcs_fw_event_hdr_t)) {
578 mdb_warn("Unable to read firmware event log header\n");
579 return;
580 }
581
582 /*
583 * Firmware event log is little-endian
584 */
585 swapp = (uint32_t *)&fwhdr;
586 for (sidx = 0; sidx < (sizeof (pmcs_fw_event_hdr_t) /
587 sizeof (uint32_t)); sidx++) {
588 *swapp = LE_32(*swapp);
589 swapp++;
590 }
591
592 if (fwhdr.fw_el_signature == PMCS_FWLOG_AAP1_SIG) {
593 header_id = "AAP1";
594 } else if (fwhdr.fw_el_signature == PMCS_FWLOG_IOP_SIG) {
595 header_id = "IOP";
596 } else {
597 mdb_warn("Invalid firmware event log signature\n");
598 return;
599 }
600
601 mdb_printf("Event Log: %s\n", header_id);
602 mdb_printf("Oldest entry: %d\n", fwhdr.fw_el_oldest_idx);
603 mdb_printf("Latest entry: %d\n", fwhdr.fw_el_latest_idx);
604
605 entry = mdb_alloc(fwhdr.fw_el_entry_size, UM_SLEEP);
606 fw_entryp = (pmcs_fw_event_entry_t *)((void *)entry);
607 total_size -= sizeof (pmcs_fw_event_hdr_t);
608 log_size = fwhdr.fw_el_buf_size;
609 fwlogp += fwhdr.fw_el_entry_start_offset;
610 swapp = (uint32_t *)((void *)entry);
611 index = 0;
612
613 mdb_printf("%8s %16s %32s %8s %3s %8s %8s %8s %8s",
614 "Index", "Timestamp", "Time", "Seq Num", "Sev", "Word 0",
615 "Word 1", "Word 2", "Word 3");
616 mdb_printf("\n");
617
618 while (log_size != 0) {
619 if (mdb_vread(entry, fwhdr.fw_el_entry_size,
620 (uintptr_t)fwlogp) != fwhdr.fw_el_entry_size) {
621 mdb_warn("Unable to read event log entry\n");
622 goto bail_out;
623 }
624
625 for (sidx = 0; sidx < (fwhdr.fw_el_entry_size /
626 sizeof (uint32_t)); sidx++) {
627 *(swapp + sidx) = LE_32(*(swapp + sidx));
628 }
629
630 if (fw_entryp->ts_upper || fw_entryp->ts_lower) {
631 pmcs_fwtime_to_systime(ss, fw_entryp->ts_upper,
632 fw_entryp->ts_lower, &systime);
633 mdb_printf("%8d %08x%08x [%Y.%09ld] %8d %3d "
634 "%08x %08x %08x %08x\n", index,
635 fw_entryp->ts_upper, fw_entryp->ts_lower,
636 systime, fw_entryp->seq_num,
637 fw_entryp->severity, fw_entryp->logw0,
638 fw_entryp->logw1, fw_entryp->logw2,
639 fw_entryp->logw3);
640 }
641
642 fwlogp += fwhdr.fw_el_entry_size;
643 total_size -= fwhdr.fw_el_entry_size;
644 log_size -= fwhdr.fw_el_entry_size;
645 index++;
646 }
647
648 mdb_printf("\n");
649 }
650
651 bail_out:
652 mdb_free(entry, fwhdr.fw_el_entry_size);
653 }
654
655 /*ARGSUSED*/
656 static void
display_hwinfo(struct pmcs_hw m,int verbose)657 display_hwinfo(struct pmcs_hw m, int verbose)
658 {
659 struct pmcs_hw *mp = &m;
660 char *fwsupport;
661
662 switch (PMCS_FW_TYPE(mp)) {
663 case PMCS_FW_TYPE_RELEASED:
664 fwsupport = "Released";
665 break;
666 case PMCS_FW_TYPE_DEVELOPMENT:
667 fwsupport = "Development";
668 break;
669 case PMCS_FW_TYPE_ALPHA:
670 fwsupport = "Alpha";
671 break;
672 case PMCS_FW_TYPE_BETA:
673 fwsupport = "Beta";
674 break;
675 default:
676 fwsupport = "Special";
677 break;
678 }
679
680 mdb_printf("\nHardware information:\n");
681 mdb_printf("---------------------\n");
682
683 mdb_printf("Chip revision: %c\n", 'A' + m.chiprev);
684 mdb_printf("SAS WWID: %"PRIx64"\n", m.sas_wwns[0]);
685 mdb_printf("Firmware version: %x.%x.%x (%s)\n",
686 PMCS_FW_MAJOR(mp), PMCS_FW_MINOR(mp), PMCS_FW_MICRO(mp),
687 fwsupport);
688 mdb_printf("ILA version: %08x\n", m.ila_ver);
689 mdb_printf("Active f/w img: %c\n", (m.fw_active_img) ? 'A' : 'B');
690
691 mdb_printf("Number of PHYs: %d\n", m.nphy);
692 mdb_printf("Maximum commands: %d\n", m.max_cmd);
693 mdb_printf("Maximum devices: %d\n", m.max_dev);
694 mdb_printf("I/O queue depth: %d\n", m.ioq_depth);
695 mdb_printf("Open retry intvl: %d usecs\n", m.open_retry_interval);
696 if (m.fwlog == 0) {
697 mdb_printf("Firmware logging: Disabled\n");
698 } else {
699 mdb_printf("Firmware logging: Enabled (%d)\n", m.fwlog);
700 }
701 if (m.fwlog_file == 0) {
702 mdb_printf("Firmware logfile: Not configured\n");
703 } else {
704 mdb_printf("Firmware logfile: Configured\n");
705 mdb_inc_indent(2);
706 mdb_printf("AAP1 log file: %s\n", m.fwlogfile_aap1);
707 mdb_printf("IOP logfile: %s\n", m.fwlogfile_iop);
708 mdb_dec_indent(2);
709 }
710 }
711
712 static void
display_targets(struct pmcs_hw m,int verbose,int totals_only)713 display_targets(struct pmcs_hw m, int verbose, int totals_only)
714 {
715 char *dtype;
716 pmcs_xscsi_t xs;
717 pmcs_phy_t phy;
718 uint16_t max_dev, idx;
719 uint32_t sas_targets = 0, smp_targets = 0, sata_targets = 0;
720
721 max_dev = m.max_dev;
722
723 if (targets == NULL) {
724 targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
725 }
726
727 if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
728 NOREAD(targets, m.targets);
729 return;
730 }
731
732 if (!totals_only) {
733 mdb_printf("\nTarget information:\n");
734 mdb_printf("---------------------------------------\n");
735 mdb_printf("VTGT %-16s %-16s %-5s %4s %6s %s", "SAS Address",
736 "PHY Address", "DType", "Actv", "OnChip", "DS");
737 mdb_printf("\n");
738 }
739
740 for (idx = 0; idx < max_dev; idx++) {
741 if (targets[idx] == NULL) {
742 continue;
743 }
744
745 if (MDB_RD(&xs, sizeof (xs), targets[idx]) == -1) {
746 NOREAD(pmcs_xscsi_t, targets[idx]);
747 continue;
748 }
749
750 /*
751 * It has to be new or assigned to be of interest.
752 */
753 if (xs.new == 0 && xs.assigned == 0) {
754 continue;
755 }
756
757 switch (xs.dtype) {
758 case NOTHING:
759 dtype = "None";
760 break;
761 case SATA:
762 dtype = "SATA";
763 sata_targets++;
764 break;
765 case SAS:
766 dtype = "SAS";
767 sas_targets++;
768 break;
769 case EXPANDER:
770 dtype = "SMP";
771 smp_targets++;
772 break;
773 }
774
775 if (totals_only) {
776 continue;
777 }
778
779 if (xs.phy) {
780 if (MDB_RD(&phy, sizeof (phy), xs.phy) == -1) {
781 NOREAD(pmcs_phy_t, xs.phy);
782 continue;
783 }
784 mdb_printf("%4d ", idx);
785 print_sas_address(&phy);
786 mdb_printf(" %16p", xs.phy);
787 } else {
788 mdb_printf("%4d %16s", idx, "<no phy avail>");
789 }
790 mdb_printf(" %5s", dtype);
791 mdb_printf(" %4d", xs.actv_pkts);
792 mdb_printf(" %6d", xs.actv_cnt);
793 mdb_printf(" %2d", xs.dev_state);
794
795 if (verbose) {
796 if (xs.new) {
797 mdb_printf(" new");
798 }
799 if (xs.assigned) {
800 mdb_printf(" assigned");
801 }
802 if (xs.draining) {
803 mdb_printf(" draining");
804 }
805 if (xs.reset_wait) {
806 mdb_printf(" reset_wait");
807 }
808 if (xs.resetting) {
809 mdb_printf(" resetting");
810 }
811 if (xs.recover_wait) {
812 mdb_printf(" recover_wait");
813 }
814 if (xs.recovering) {
815 mdb_printf(" recovering");
816 }
817 if (xs.event_recovery) {
818 mdb_printf(" event recovery");
819 }
820 if (xs.special_running) {
821 mdb_printf(" special_active");
822 }
823 if (xs.ncq) {
824 mdb_printf(" ncq_tagmap=0x%x qdepth=%d",
825 xs.tagmap, xs.qdepth);
826 } else if (xs.pio) {
827 mdb_printf(" pio");
828 }
829 }
830
831 mdb_printf("\n");
832 }
833
834 if (!totals_only) {
835 mdb_printf("\n");
836 }
837
838 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
839 "Configured targets:", (sas_targets + sata_targets + smp_targets),
840 sas_targets, sata_targets, smp_targets);
841 }
842
843 static char *
work_state_to_string(uint32_t state)844 work_state_to_string(uint32_t state)
845 {
846 char *state_string;
847
848 switch (state) {
849 case PMCS_WORK_STATE_NIL:
850 state_string = "Free";
851 break;
852 case PMCS_WORK_STATE_READY:
853 state_string = "Ready";
854 break;
855 case PMCS_WORK_STATE_ONCHIP:
856 state_string = "On Chip";
857 break;
858 case PMCS_WORK_STATE_INTR:
859 state_string = "In Intr";
860 break;
861 case PMCS_WORK_STATE_IOCOMPQ:
862 state_string = "I/O Comp";
863 break;
864 case PMCS_WORK_STATE_ABORTED:
865 state_string = "I/O Aborted";
866 break;
867 case PMCS_WORK_STATE_TIMED_OUT:
868 state_string = "I/O Timed Out";
869 break;
870 default:
871 state_string = "INVALID";
872 break;
873 }
874
875 return (state_string);
876 }
877
878 static void
display_one_work(pmcwork_t * wp,int verbose,int idx)879 display_one_work(pmcwork_t *wp, int verbose, int idx)
880 {
881 char *state, *last_state;
882 char *path;
883 pmcs_xscsi_t xs;
884 pmcs_phy_t phy;
885 int tgt;
886
887 state = work_state_to_string(wp->state);
888 last_state = work_state_to_string(wp->last_state);
889
890 if (wp->ssp_event && wp->ssp_event != 0xffffffff) {
891 mdb_printf("SSP event 0x%x", wp->ssp_event);
892 }
893
894 tgt = -1;
895 if (wp->xp) {
896 if (MDB_RD(&xs, sizeof (xs), wp->xp) == -1) {
897 NOREAD(pmcs_xscsi_t, wp->xp);
898 } else {
899 tgt = xs.target_num;
900 }
901 }
902 if (wp->phy) {
903 if (MDB_RD(&phy, sizeof (phy), wp->phy) == -1) {
904 NOREAD(pmcs_phy_t, wp->phy);
905 }
906 path = phy.path;
907 } else {
908 path = "N/A";
909 }
910
911 if (verbose) {
912 mdb_printf("%4d ", idx);
913 }
914 if (tgt == -1) {
915 mdb_printf("%08x %10s %20s N/A %8u %1d %1d ",
916 wp->htag, state, path, wp->timer,
917 wp->onwire, wp->dead);
918 } else {
919 mdb_printf("%08x %10s %20s %8d %8u %1d %1d ",
920 wp->htag, state, path, tgt, wp->timer,
921 wp->onwire, wp->dead);
922 }
923 if (verbose) {
924 mdb_printf("%08x %10s 0x%016p 0x%016p 0x%016p\n",
925 wp->last_htag, last_state, wp->last_phy, wp->last_xp,
926 wp->last_arg);
927 } else {
928 mdb_printf("\n");
929 }
930 }
931
932 static void
display_work(struct pmcs_hw m,int verbose,int wserno)933 display_work(struct pmcs_hw m, int verbose, int wserno)
934 {
935 int idx;
936 boolean_t header_printed = B_FALSE;
937 pmcwork_t *wp;
938 wserno_list_t *sernop, *sp, *newsp, *sphead = NULL;
939 uintptr_t _wp;
940 int serno;
941
942 wp = mdb_alloc(sizeof (pmcwork_t) * m.max_cmd, UM_SLEEP);
943 _wp = (uintptr_t)m.work;
944 sernop = mdb_alloc(sizeof (wserno_list_t) * m.max_cmd, UM_SLEEP);
945 bzero(sernop, sizeof (wserno_list_t) * m.max_cmd);
946
947 mdb_printf("\nActive Work structure information:\n");
948 mdb_printf("----------------------------------\n");
949
950 /*
951 * Read in all the work structures
952 */
953 for (idx = 0; idx < m.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
954 if (MDB_RD(wp + idx, sizeof (pmcwork_t), _wp) == -1) {
955 NOREAD(pmcwork_t, _wp);
956 continue;
957 }
958 }
959
960 /*
961 * Sort by serial number?
962 */
963 if (wserno) {
964 for (idx = 0; idx < m.max_cmd; idx++) {
965 if ((wp + idx)->htag == 0) {
966 serno = PMCS_TAG_SERNO((wp + idx)->last_htag);
967 } else {
968 serno = PMCS_TAG_SERNO((wp + idx)->htag);
969 }
970
971 /* Start at the beginning of the list */
972 sp = sphead;
973 newsp = sernop + idx;
974 /* If this is the first entry, just add it */
975 if (sphead == NULL) {
976 sphead = sernop;
977 sphead->serno = serno;
978 sphead->idx = idx;
979 sphead->next = NULL;
980 sphead->prev = NULL;
981 continue;
982 }
983
984 newsp->serno = serno;
985 newsp->idx = idx;
986
987 /* Find out where in the list this goes */
988 while (sp) {
989 /* This item goes before sp */
990 if (serno < sp->serno) {
991 newsp->next = sp;
992 newsp->prev = sp->prev;
993 if (newsp->prev == NULL) {
994 sphead = newsp;
995 } else {
996 newsp->prev->next = newsp;
997 }
998 sp->prev = newsp;
999 break;
1000 }
1001
1002 /*
1003 * If sp->next is NULL, this entry goes at the
1004 * end of the list
1005 */
1006 if (sp->next == NULL) {
1007 sp->next = newsp;
1008 newsp->next = NULL;
1009 newsp->prev = sp;
1010 break;
1011 }
1012
1013 sp = sp->next;
1014 }
1015 }
1016
1017 /*
1018 * Now print the sorted list
1019 */
1020 mdb_printf(" Idx %8s %10s %20s %8s %8s O D ",
1021 "HTag", "State", "Phy Path", "Target", "Timer");
1022 mdb_printf("%8s %10s %18s %18s %18s\n", "LastHTAG",
1023 "LastState", "LastPHY", "LastTgt", "LastArg");
1024
1025 sp = sphead;
1026 while (sp) {
1027 display_one_work(wp + sp->idx, 1, sp->idx);
1028 sp = sp->next;
1029 }
1030
1031 goto out;
1032 }
1033
1034 /*
1035 * Now print the list, sorted by index
1036 */
1037 for (idx = 0; idx < m.max_cmd; idx++) {
1038 if (!verbose && ((wp + idx)->htag == PMCS_TAG_TYPE_FREE)) {
1039 continue;
1040 }
1041
1042 if (header_printed == B_FALSE) {
1043 if (verbose) {
1044 mdb_printf("%4s ", "Idx");
1045 }
1046 mdb_printf("%8s %10s %20s %8s %8s O D ",
1047 "HTag", "State", "Phy Path", "Target", "Timer");
1048 if (verbose) {
1049 mdb_printf("%8s %10s %18s %18s %18s\n",
1050 "LastHTAG", "LastState", "LastPHY",
1051 "LastTgt", "LastArg");
1052 } else {
1053 mdb_printf("\n");
1054 }
1055 header_printed = B_TRUE;
1056 }
1057
1058 display_one_work(wp + idx, verbose, idx);
1059 }
1060
1061 out:
1062 mdb_free(wp, sizeof (pmcwork_t) * m.max_cmd);
1063 mdb_free(sernop, sizeof (wserno_list_t) * m.max_cmd);
1064 }
1065
1066 static void
print_spcmd(pmcs_cmd_t * sp,void * kaddr,int printhdr,int verbose)1067 print_spcmd(pmcs_cmd_t *sp, void *kaddr, int printhdr, int verbose)
1068 {
1069 int cdb_size, idx;
1070 struct scsi_pkt pkt;
1071 uchar_t cdb[256];
1072
1073 if (printhdr) {
1074 if (verbose) {
1075 mdb_printf("%16s %16s %16s %8s %s CDB\n", "Command",
1076 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
1077 } else {
1078 mdb_printf("%16s %16s %16s %8s %s\n", "Command",
1079 "SCSA pkt", "DMA Chunks", "HTAG", "SATL Tag");
1080 }
1081 }
1082
1083 mdb_printf("%16p %16p %16p %08x %08x ",
1084 kaddr, sp->cmd_pkt, sp->cmd_clist, sp->cmd_tag, sp->cmd_satltag);
1085
1086 /*
1087 * If we're printing verbose, dump the CDB as well.
1088 */
1089 if (verbose) {
1090 if (sp->cmd_pkt) {
1091 if (mdb_vread(&pkt, sizeof (struct scsi_pkt),
1092 (uintptr_t)sp->cmd_pkt) !=
1093 sizeof (struct scsi_pkt)) {
1094 mdb_warn("Unable to read SCSI pkt\n");
1095 return;
1096 }
1097 cdb_size = pkt.pkt_cdblen;
1098 if (mdb_vread(&cdb[0], cdb_size,
1099 (uintptr_t)pkt.pkt_cdbp) != cdb_size) {
1100 mdb_warn("Unable to read CDB\n");
1101 return;
1102 }
1103
1104 for (idx = 0; idx < cdb_size; idx++) {
1105 mdb_printf("%02x ", cdb[idx]);
1106 }
1107 } else {
1108 mdb_printf("N/A");
1109 }
1110
1111 mdb_printf("\n");
1112 } else {
1113 mdb_printf("\n");
1114 }
1115 }
1116
1117 /*ARGSUSED1*/
1118 static void
display_waitqs(struct pmcs_hw m,int verbose)1119 display_waitqs(struct pmcs_hw m, int verbose)
1120 {
1121 pmcs_cmd_t *sp, s;
1122 pmcs_xscsi_t xs;
1123 int first, i;
1124 int max_dev = m.max_dev;
1125
1126 sp = m.dq.stqh_first;
1127 first = 1;
1128 while (sp) {
1129 if (first) {
1130 mdb_printf("\nDead Command Queue:\n");
1131 mdb_printf("---------------------------\n");
1132 }
1133 if (MDB_RD(&s, sizeof (s), sp) == -1) {
1134 NOREAD(pmcs_cmd_t, sp);
1135 break;
1136 }
1137 print_spcmd(&s, sp, first, verbose);
1138 sp = s.cmd_next.stqe_next;
1139 first = 0;
1140 }
1141
1142 sp = m.cq.stqh_first;
1143 first = 1;
1144 while (sp) {
1145 if (first) {
1146 mdb_printf("\nCompletion Command Queue:\n");
1147 mdb_printf("---------------------------\n");
1148 }
1149 if (MDB_RD(&s, sizeof (s), sp) == -1) {
1150 NOREAD(pmcs_cmd_t, sp);
1151 break;
1152 }
1153 print_spcmd(&s, sp, first, verbose);
1154 sp = s.cmd_next.stqe_next;
1155 first = 0;
1156 }
1157
1158
1159 if (targets == NULL) {
1160 targets = mdb_alloc(sizeof (targets) * max_dev, UM_SLEEP);
1161 }
1162
1163 if (MDB_RD(targets, sizeof (targets) * max_dev, m.targets) == -1) {
1164 NOREAD(targets, m.targets);
1165 return;
1166 }
1167
1168 for (i = 0; i < max_dev; i++) {
1169 if (targets[i] == NULL) {
1170 continue;
1171 }
1172 if (MDB_RD(&xs, sizeof (xs), targets[i]) == -1) {
1173 NOREAD(pmcs_xscsi_t, targets[i]);
1174 continue;
1175 }
1176 sp = xs.wq.stqh_first;
1177 first = 1;
1178 while (sp) {
1179 if (first) {
1180 mdb_printf("\nTarget %u Wait Queue:\n",
1181 xs.target_num);
1182 mdb_printf("---------------------------\n");
1183 }
1184 if (MDB_RD(&s, sizeof (s), sp) == -1) {
1185 NOREAD(pmcs_cmd_t, sp);
1186 break;
1187 }
1188 print_spcmd(&s, sp, first, verbose);
1189 sp = s.cmd_next.stqe_next;
1190 first = 0;
1191 }
1192 sp = xs.aq.stqh_first;
1193 first = 1;
1194 while (sp) {
1195 if (first) {
1196 mdb_printf("\nTarget %u Active Queue:\n",
1197 xs.target_num);
1198 mdb_printf("---------------------------\n");
1199 }
1200 if (MDB_RD(&s, sizeof (s), sp) == -1) {
1201 NOREAD(pmcs_cmd_t, sp);
1202 break;
1203 }
1204 print_spcmd(&s, sp, first, verbose);
1205 sp = s.cmd_next.stqe_next;
1206 first = 0;
1207 }
1208 sp = xs.sq.stqh_first;
1209 first = 1;
1210 while (sp) {
1211 if (first) {
1212 mdb_printf("\nTarget %u Special Queue:\n",
1213 xs.target_num);
1214 mdb_printf("---------------------------\n");
1215 }
1216 if (MDB_RD(&s, sizeof (s), sp) == -1) {
1217 NOREAD(pmcs_cmd_t, sp);
1218 break;
1219 }
1220 print_spcmd(&s, sp, first, verbose);
1221 sp = s.cmd_next.stqe_next;
1222 first = 0;
1223 }
1224 }
1225 }
1226
1227 static char *
ibq_type(int qnum)1228 ibq_type(int qnum)
1229 {
1230 if (qnum < 0 || qnum >= PMCS_NIQ) {
1231 return ("UNKNOWN");
1232 }
1233
1234 if (qnum < PMCS_IQ_OTHER) {
1235 return ("I/O");
1236 }
1237
1238 return ("Other");
1239 }
1240
1241 static char *
obq_type(int qnum)1242 obq_type(int qnum)
1243 {
1244 switch (qnum) {
1245 case PMCS_OQ_IODONE:
1246 return ("I/O");
1247 case PMCS_OQ_GENERAL:
1248 return ("General");
1249 case PMCS_OQ_EVENTS:
1250 return ("Events");
1251 default:
1252 return ("UNKNOWN");
1253 }
1254 }
1255
1256 static char *
iomb_cat(uint32_t cat)1257 iomb_cat(uint32_t cat)
1258 {
1259 switch (cat) {
1260 case PMCS_IOMB_CAT_NET:
1261 return ("NET");
1262 case PMCS_IOMB_CAT_FC:
1263 return ("FC");
1264 case PMCS_IOMB_CAT_SAS:
1265 return ("SAS");
1266 case PMCS_IOMB_CAT_SCSI:
1267 return ("SCSI");
1268 default:
1269 return ("???");
1270 }
1271 }
1272
1273 static char *
iomb_event(uint8_t event)1274 iomb_event(uint8_t event)
1275 {
1276 switch (event) {
1277 case IOP_EVENT_PHY_STOP_STATUS:
1278 return ("PHY STOP");
1279 case IOP_EVENT_SAS_PHY_UP:
1280 return ("PHY UP");
1281 case IOP_EVENT_SATA_PHY_UP:
1282 return ("SATA PHY UP");
1283 case IOP_EVENT_SATA_SPINUP_HOLD:
1284 return ("SATA SPINUP HOLD");
1285 case IOP_EVENT_PHY_DOWN:
1286 return ("PHY DOWN");
1287 case IOP_EVENT_BROADCAST_CHANGE:
1288 return ("BROADCAST CHANGE");
1289 case IOP_EVENT_BROADCAST_SES:
1290 return ("BROADCAST SES");
1291 case IOP_EVENT_PHY_ERR_INBOUND_CRC:
1292 return ("INBOUND CRC ERROR");
1293 case IOP_EVENT_HARD_RESET_RECEIVED:
1294 return ("HARD RESET");
1295 case IOP_EVENT_EVENT_ID_FRAME_TIMO:
1296 return ("IDENTIFY FRAME TIMEOUT");
1297 case IOP_EVENT_BROADCAST_EXP:
1298 return ("BROADCAST EXPANDER");
1299 case IOP_EVENT_PHY_START_STATUS:
1300 return ("PHY START");
1301 case IOP_EVENT_PHY_ERR_INVALID_DWORD:
1302 return ("INVALID DWORD");
1303 case IOP_EVENT_PHY_ERR_DISPARITY_ERROR:
1304 return ("DISPARITY ERROR");
1305 case IOP_EVENT_PHY_ERR_CODE_VIOLATION:
1306 return ("CODE VIOLATION");
1307 case IOP_EVENT_PHY_ERR_LOSS_OF_DWORD_SYN:
1308 return ("LOSS OF DWORD SYNC");
1309 case IOP_EVENT_PHY_ERR_PHY_RESET_FAILD:
1310 return ("PHY RESET FAILED");
1311 case IOP_EVENT_PORT_RECOVERY_TIMER_TMO:
1312 return ("PORT RECOVERY TIMEOUT");
1313 case IOP_EVENT_PORT_RECOVER:
1314 return ("PORT RECOVERY");
1315 case IOP_EVENT_PORT_RESET_TIMER_TMO:
1316 return ("PORT RESET TIMEOUT");
1317 case IOP_EVENT_PORT_RESET_COMPLETE:
1318 return ("PORT RESET COMPLETE");
1319 case IOP_EVENT_BROADCAST_ASYNC_EVENT:
1320 return ("BROADCAST ASYNC");
1321 case IOP_EVENT_IT_NEXUS_LOSS:
1322 return ("I/T NEXUS LOSS");
1323 default:
1324 return ("Unknown Event");
1325 }
1326 }
1327
1328 static char *
inbound_iomb_opcode(uint32_t opcode)1329 inbound_iomb_opcode(uint32_t opcode)
1330 {
1331 switch (opcode) {
1332 case PMCIN_ECHO:
1333 return ("ECHO");
1334 case PMCIN_GET_INFO:
1335 return ("GET_INFO");
1336 case PMCIN_GET_VPD:
1337 return ("GET_VPD");
1338 case PMCIN_PHY_START:
1339 return ("PHY_START");
1340 case PMCIN_PHY_STOP:
1341 return ("PHY_STOP");
1342 case PMCIN_SSP_INI_IO_START:
1343 return ("INI_IO_START");
1344 case PMCIN_SSP_INI_TM_START:
1345 return ("INI_TM_START");
1346 case PMCIN_SSP_INI_EXT_IO_START:
1347 return ("INI_EXT_IO_START");
1348 case PMCIN_DEVICE_HANDLE_ACCEPT:
1349 return ("DEVICE_HANDLE_ACCEPT");
1350 case PMCIN_SSP_TGT_IO_START:
1351 return ("TGT_IO_START");
1352 case PMCIN_SSP_TGT_RESPONSE_START:
1353 return ("TGT_RESPONSE_START");
1354 case PMCIN_SSP_INI_EDC_EXT_IO_START:
1355 return ("INI_EDC_EXT_IO_START");
1356 case PMCIN_SSP_INI_EDC_EXT_IO_START1:
1357 return ("INI_EDC_EXT_IO_START1");
1358 case PMCIN_SSP_TGT_EDC_IO_START:
1359 return ("TGT_EDC_IO_START");
1360 case PMCIN_SSP_ABORT:
1361 return ("SSP_ABORT");
1362 case PMCIN_DEREGISTER_DEVICE_HANDLE:
1363 return ("DEREGISTER_DEVICE_HANDLE");
1364 case PMCIN_GET_DEVICE_HANDLE:
1365 return ("GET_DEVICE_HANDLE");
1366 case PMCIN_SMP_REQUEST:
1367 return ("SMP_REQUEST");
1368 case PMCIN_SMP_RESPONSE:
1369 return ("SMP_RESPONSE");
1370 case PMCIN_SMP_ABORT:
1371 return ("SMP_ABORT");
1372 case PMCIN_ASSISTED_DISCOVERY:
1373 return ("ASSISTED_DISCOVERY");
1374 case PMCIN_REGISTER_DEVICE:
1375 return ("REGISTER_DEVICE");
1376 case PMCIN_SATA_HOST_IO_START:
1377 return ("SATA_HOST_IO_START");
1378 case PMCIN_SATA_ABORT:
1379 return ("SATA_ABORT");
1380 case PMCIN_LOCAL_PHY_CONTROL:
1381 return ("LOCAL_PHY_CONTROL");
1382 case PMCIN_GET_DEVICE_INFO:
1383 return ("GET_DEVICE_INFO");
1384 case PMCIN_TWI:
1385 return ("TWI");
1386 case PMCIN_FW_FLASH_UPDATE:
1387 return ("FW_FLASH_UPDATE");
1388 case PMCIN_SET_VPD:
1389 return ("SET_VPD");
1390 case PMCIN_GPIO:
1391 return ("GPIO");
1392 case PMCIN_SAS_DIAG_MODE_START_END:
1393 return ("SAS_DIAG_MODE_START_END");
1394 case PMCIN_SAS_DIAG_EXECUTE:
1395 return ("SAS_DIAG_EXECUTE");
1396 case PMCIN_SAS_HW_EVENT_ACK:
1397 return ("SAS_HW_EVENT_ACK");
1398 case PMCIN_GET_TIME_STAMP:
1399 return ("GET_TIME_STAMP");
1400 case PMCIN_PORT_CONTROL:
1401 return ("PORT_CONTROL");
1402 case PMCIN_GET_NVMD_DATA:
1403 return ("GET_NVMD_DATA");
1404 case PMCIN_SET_NVMD_DATA:
1405 return ("SET_NVMD_DATA");
1406 case PMCIN_SET_DEVICE_STATE:
1407 return ("SET_DEVICE_STATE");
1408 case PMCIN_GET_DEVICE_STATE:
1409 return ("GET_DEVICE_STATE");
1410 default:
1411 return ("UNKNOWN");
1412 }
1413 }
1414
1415 static char *
outbound_iomb_opcode(uint32_t opcode)1416 outbound_iomb_opcode(uint32_t opcode)
1417 {
1418 switch (opcode) {
1419 case PMCOUT_ECHO:
1420 return ("ECHO");
1421 case PMCOUT_GET_INFO:
1422 return ("GET_INFO");
1423 case PMCOUT_GET_VPD:
1424 return ("GET_VPD");
1425 case PMCOUT_SAS_HW_EVENT:
1426 return ("SAS_HW_EVENT");
1427 case PMCOUT_SSP_COMPLETION:
1428 return ("SSP_COMPLETION");
1429 case PMCOUT_SMP_COMPLETION:
1430 return ("SMP_COMPLETION");
1431 case PMCOUT_LOCAL_PHY_CONTROL:
1432 return ("LOCAL_PHY_CONTROL");
1433 case PMCOUT_SAS_ASSISTED_DISCOVERY_EVENT:
1434 return ("SAS_ASSISTED_DISCOVERY_SENT");
1435 case PMCOUT_SATA_ASSISTED_DISCOVERY_EVENT:
1436 return ("SATA_ASSISTED_DISCOVERY_SENT");
1437 case PMCOUT_DEVICE_REGISTRATION:
1438 return ("DEVICE_REGISTRATION");
1439 case PMCOUT_DEREGISTER_DEVICE_HANDLE:
1440 return ("DEREGISTER_DEVICE_HANDLE");
1441 case PMCOUT_GET_DEVICE_HANDLE:
1442 return ("GET_DEVICE_HANDLE");
1443 case PMCOUT_SATA_COMPLETION:
1444 return ("SATA_COMPLETION");
1445 case PMCOUT_SATA_EVENT:
1446 return ("SATA_EVENT");
1447 case PMCOUT_SSP_EVENT:
1448 return ("SSP_EVENT");
1449 case PMCOUT_DEVICE_HANDLE_ARRIVED:
1450 return ("DEVICE_HANDLE_ARRIVED");
1451 case PMCOUT_SSP_REQUEST_RECEIVED:
1452 return ("SSP_REQUEST_RECEIVED");
1453 case PMCOUT_DEVICE_INFO:
1454 return ("DEVICE_INFO");
1455 case PMCOUT_FW_FLASH_UPDATE:
1456 return ("FW_FLASH_UPDATE");
1457 case PMCOUT_SET_VPD:
1458 return ("SET_VPD");
1459 case PMCOUT_GPIO:
1460 return ("GPIO");
1461 case PMCOUT_GPIO_EVENT:
1462 return ("GPIO_EVENT");
1463 case PMCOUT_GENERAL_EVENT:
1464 return ("GENERAL_EVENT");
1465 case PMCOUT_TWI:
1466 return ("TWI");
1467 case PMCOUT_SSP_ABORT:
1468 return ("SSP_ABORT");
1469 case PMCOUT_SATA_ABORT:
1470 return ("SATA_ABORT");
1471 case PMCOUT_SAS_DIAG_MODE_START_END:
1472 return ("SAS_DIAG_MODE_START_END");
1473 case PMCOUT_SAS_DIAG_EXECUTE:
1474 return ("SAS_DIAG_EXECUTE");
1475 case PMCOUT_GET_TIME_STAMP:
1476 return ("GET_TIME_STAMP");
1477 case PMCOUT_SAS_HW_EVENT_ACK_ACK:
1478 return ("SAS_HW_EVENT_ACK_ACK");
1479 case PMCOUT_PORT_CONTROL:
1480 return ("PORT_CONTROL");
1481 case PMCOUT_SKIP_ENTRIES:
1482 return ("SKIP_ENTRIES");
1483 case PMCOUT_SMP_ABORT:
1484 return ("SMP_ABORT");
1485 case PMCOUT_GET_NVMD_DATA:
1486 return ("GET_NVMD_DATA");
1487 case PMCOUT_SET_NVMD_DATA:
1488 return ("SET_NVMD_DATA");
1489 case PMCOUT_DEVICE_HANDLE_REMOVED:
1490 return ("DEVICE_HANDLE_REMOVED");
1491 case PMCOUT_SET_DEVICE_STATE:
1492 return ("SET_DEVICE_STATE");
1493 case PMCOUT_GET_DEVICE_STATE:
1494 return ("GET_DEVICE_STATE");
1495 case PMCOUT_SET_DEVICE_INFO:
1496 return ("SET_DEVICE_INFO");
1497 default:
1498 return ("UNKNOWN");
1499 }
1500 }
1501
1502 static uint32_t
get_devid_from_ob_iomb(struct pmcs_hw ss,uint32_t * qentryp,uint16_t opcode)1503 get_devid_from_ob_iomb(struct pmcs_hw ss, uint32_t *qentryp, uint16_t opcode)
1504 {
1505 uint32_t devid = PMCS_INVALID_DEVICE_ID;
1506
1507 switch (opcode) {
1508 /*
1509 * These are obtained via the HTAG which is in word 1
1510 */
1511 case PMCOUT_SSP_COMPLETION:
1512 case PMCOUT_SMP_COMPLETION:
1513 case PMCOUT_DEREGISTER_DEVICE_HANDLE:
1514 case PMCOUT_GET_DEVICE_HANDLE:
1515 case PMCOUT_SATA_COMPLETION:
1516 case PMCOUT_SSP_ABORT:
1517 case PMCOUT_SATA_ABORT:
1518 case PMCOUT_SMP_ABORT:
1519 case PMCOUT_SAS_HW_EVENT_ACK_ACK: {
1520 uint32_t htag;
1521 pmcwork_t *wp;
1522 pmcs_phy_t *phy;
1523 uintptr_t _wp, _phy;
1524 uint16_t index;
1525
1526 htag = LE_32(*(qentryp + 1));
1527 index = htag & PMCS_TAG_INDEX_MASK;
1528
1529 wp = mdb_alloc(sizeof (pmcwork_t), UM_SLEEP);
1530 _wp = (uintptr_t)ss.work + (sizeof (pmcwork_t) * index);
1531
1532 if (MDB_RD(wp, sizeof (pmcwork_t), _wp) == -1) {
1533 NOREAD(pmcwork_t, _wp);
1534 mdb_free(wp, sizeof (pmcwork_t));
1535 break;
1536 }
1537
1538 phy = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP);
1539 if (wp->phy == NULL) {
1540 _phy = (uintptr_t)wp->last_phy;
1541 } else {
1542 _phy = (uintptr_t)wp->phy;
1543 }
1544
1545 /*
1546 * If we have a PHY, read it in and get it's handle
1547 */
1548 if (_phy != NULL) {
1549 if (MDB_RD(phy, sizeof (*phy), _phy) == -1) {
1550 NOREAD(pmcs_phy_t, phy);
1551 } else {
1552 devid = phy->device_id;
1553 }
1554 }
1555
1556 mdb_free(phy, sizeof (pmcs_phy_t));
1557 mdb_free(wp, sizeof (pmcwork_t));
1558 break;
1559 }
1560
1561 /*
1562 * The device ID is in the outbound IOMB at word 1
1563 */
1564 case PMCOUT_SSP_REQUEST_RECEIVED:
1565 devid = LE_32(*(qentryp + 1)) & PMCS_DEVICE_ID_MASK;
1566 break;
1567
1568 /*
1569 * The device ID is in the outbound IOMB at word 2
1570 */
1571 case PMCOUT_DEVICE_HANDLE_ARRIVED:
1572 case PMCOUT_DEVICE_HANDLE_REMOVED:
1573 devid = LE_32(*(qentryp + 2)) & PMCS_DEVICE_ID_MASK;
1574 break;
1575
1576 /*
1577 * In this (very rare - never seen it) state, the device ID
1578 * comes from the HTAG in the inbound IOMB, which would be word
1579 * 3 in the outbound IOMB
1580 */
1581 case PMCOUT_GENERAL_EVENT:
1582 /*
1583 * The device ID is in the outbound IOMB at word 3
1584 */
1585 case PMCOUT_DEVICE_REGISTRATION:
1586 case PMCOUT_DEVICE_INFO:
1587 case PMCOUT_SET_DEVICE_STATE:
1588 case PMCOUT_GET_DEVICE_STATE:
1589 case PMCOUT_SET_DEVICE_INFO:
1590 devid = LE_32(*(qentryp + 3)) & PMCS_DEVICE_ID_MASK;
1591 break;
1592
1593 /*
1594 * Device ID is in the outbound IOMB at word 4
1595 */
1596 case PMCOUT_SATA_EVENT:
1597 case PMCOUT_SSP_EVENT:
1598 devid = LE_32(*(qentryp + 4)) & PMCS_DEVICE_ID_MASK;
1599 break;
1600 }
1601
1602 return (devid);
1603 }
1604
1605 static boolean_t
iomb_is_dev_hdl_specific(uint32_t word0,boolean_t inbound)1606 iomb_is_dev_hdl_specific(uint32_t word0, boolean_t inbound)
1607 {
1608 uint16_t opcode = word0 & PMCS_IOMB_OPCODE_MASK;
1609
1610 if (inbound) {
1611 switch (opcode) {
1612 case PMCIN_SSP_INI_IO_START:
1613 case PMCIN_SSP_INI_TM_START:
1614 case PMCIN_SSP_INI_EXT_IO_START:
1615 case PMCIN_SSP_TGT_IO_START:
1616 case PMCIN_SSP_TGT_RESPONSE_START:
1617 case PMCIN_SSP_ABORT:
1618 case PMCIN_DEREGISTER_DEVICE_HANDLE:
1619 case PMCIN_SMP_REQUEST:
1620 case PMCIN_SMP_RESPONSE:
1621 case PMCIN_SMP_ABORT:
1622 case PMCIN_ASSISTED_DISCOVERY:
1623 case PMCIN_SATA_HOST_IO_START:
1624 case PMCIN_SATA_ABORT:
1625 case PMCIN_GET_DEVICE_INFO:
1626 case PMCIN_SET_DEVICE_STATE:
1627 case PMCIN_GET_DEVICE_STATE:
1628 return (B_TRUE);
1629 }
1630
1631 return (B_FALSE);
1632 }
1633
1634 switch (opcode) {
1635 case PMCOUT_SSP_COMPLETION:
1636 case PMCOUT_SMP_COMPLETION:
1637 case PMCOUT_DEVICE_REGISTRATION:
1638 case PMCOUT_DEREGISTER_DEVICE_HANDLE:
1639 case PMCOUT_GET_DEVICE_HANDLE:
1640 case PMCOUT_SATA_COMPLETION:
1641 case PMCOUT_SATA_EVENT:
1642 case PMCOUT_SSP_EVENT:
1643 case PMCOUT_DEVICE_HANDLE_ARRIVED:
1644 case PMCOUT_SSP_REQUEST_RECEIVED:
1645 case PMCOUT_DEVICE_INFO:
1646 case PMCOUT_FW_FLASH_UPDATE:
1647 case PMCOUT_GENERAL_EVENT:
1648 case PMCOUT_SSP_ABORT:
1649 case PMCOUT_SATA_ABORT:
1650 case PMCOUT_SAS_HW_EVENT_ACK_ACK:
1651 case PMCOUT_SMP_ABORT:
1652 case PMCOUT_DEVICE_HANDLE_REMOVED:
1653 case PMCOUT_SET_DEVICE_STATE:
1654 case PMCOUT_GET_DEVICE_STATE:
1655 case PMCOUT_SET_DEVICE_INFO:
1656 return (B_TRUE);
1657 }
1658
1659 return (B_FALSE);
1660 }
1661
1662 static void
dump_one_qentry_outbound(struct pmcs_hw ss,uint32_t * qentryp,int idx,uint64_t devid_filter)1663 dump_one_qentry_outbound(struct pmcs_hw ss, uint32_t *qentryp, int idx,
1664 uint64_t devid_filter)
1665 {
1666 int qeidx;
1667 uint32_t word0 = LE_32(*qentryp);
1668 uint32_t word1 = LE_32(*(qentryp + 1));
1669 uint8_t iop_event;
1670 uint32_t devid;
1671
1672 /*
1673 * Check to see if we're filtering on a device ID
1674 */
1675 if (devid_filter != PMCS_INVALID_DEVICE_ID) {
1676 if (!iomb_is_dev_hdl_specific(word0, B_FALSE)) {
1677 return;
1678 }
1679
1680 /*
1681 * Go find the device id. It might be in the outbound
1682 * IOMB or we may have to go find the work structure and
1683 * get it from there.
1684 */
1685 devid = get_devid_from_ob_iomb(ss, qentryp,
1686 word0 & PMCS_IOMB_OPCODE_MASK);
1687 if ((devid == PMCS_INVALID_DEVICE_ID) ||
1688 (devid_filter != devid)) {
1689 return;
1690 }
1691 }
1692
1693 mdb_printf("Entry #%02d\n", idx);
1694 mdb_inc_indent(2);
1695
1696 mdb_printf("Header: 0x%08x (", word0);
1697 if (word0 & PMCS_IOMB_VALID) {
1698 mdb_printf("VALID, ");
1699 }
1700 if (word0 & PMCS_IOMB_HIPRI) {
1701 mdb_printf("HIPRI, ");
1702 }
1703 mdb_printf("OBID=%d, ",
1704 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
1705 mdb_printf("CAT=%s, ",
1706 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
1707 mdb_printf("OPCODE=%s",
1708 outbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
1709 if ((word0 & PMCS_IOMB_OPCODE_MASK) == PMCOUT_SAS_HW_EVENT) {
1710 iop_event = IOP_EVENT_EVENT(word1);
1711 mdb_printf(" <%s>", iomb_event(iop_event));
1712 }
1713 mdb_printf(")\n");
1714
1715 mdb_printf("Remaining Payload:\n");
1716
1717 mdb_inc_indent(2);
1718 for (qeidx = 1; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
1719 mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
1720 }
1721 mdb_printf("\n");
1722 mdb_dec_indent(4);
1723 }
1724
1725 static void
display_outbound_queues(struct pmcs_hw ss,uint64_t devid_filter,uint_t verbose)1726 display_outbound_queues(struct pmcs_hw ss, uint64_t devid_filter,
1727 uint_t verbose)
1728 {
1729 int idx, qidx;
1730 uintptr_t obqp;
1731 uint32_t *cip;
1732 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
1733 uint32_t last_consumed, oqpi;
1734
1735 mdb_printf("\n");
1736 mdb_printf("Outbound Queues\n");
1737 mdb_printf("---------------\n");
1738
1739 mdb_inc_indent(2);
1740
1741 for (qidx = 0; qidx < PMCS_NOQ; qidx++) {
1742 obqp = (uintptr_t)ss.oqp[qidx];
1743
1744 if (obqp == NULL) {
1745 mdb_printf("No outbound queue ptr for queue #%d\n",
1746 qidx);
1747 continue;
1748 }
1749
1750 mdb_printf("Outbound Queue #%d (Queue Type = %s)\n", qidx,
1751 obq_type(qidx));
1752 /*
1753 * Chip is the producer, so read the actual producer index
1754 * and not the driver's version
1755 */
1756 cip = (uint32_t *)((void *)ss.cip);
1757 if (MDB_RD(&oqpi, 4, cip + OQPI_BASE_OFFSET +
1758 (qidx * 4)) == -1) {
1759 mdb_warn("Couldn't read oqpi\n");
1760 break;
1761 }
1762
1763 mdb_printf("Producer index: %d Consumer index: %d\n\n",
1764 LE_32(oqpi), ss.oqci[qidx]);
1765 mdb_inc_indent(2);
1766
1767 if (ss.oqci[qidx] == 0) {
1768 last_consumed = ss.ioq_depth - 1;
1769 } else {
1770 last_consumed = ss.oqci[qidx] - 1;
1771 }
1772
1773
1774 if (!verbose) {
1775 mdb_printf("Last processed entry:\n");
1776 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1777 (obqp + (PMCS_QENTRY_SIZE * last_consumed)))
1778 == -1) {
1779 mdb_warn("Couldn't read queue entry at 0x%p\n",
1780 (obqp + (PMCS_QENTRY_SIZE *
1781 last_consumed)));
1782 break;
1783 }
1784 dump_one_qentry_outbound(ss, qentryp, last_consumed,
1785 devid_filter);
1786 mdb_printf("\n");
1787 mdb_dec_indent(2);
1788 continue;
1789 }
1790
1791 for (idx = 0; idx < ss.ioq_depth; idx++) {
1792 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1793 (obqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
1794 mdb_warn("Couldn't read queue entry at 0x%p\n",
1795 (obqp + (PMCS_QENTRY_SIZE * idx)));
1796 break;
1797 }
1798 dump_one_qentry_outbound(ss, qentryp, idx,
1799 devid_filter);
1800 }
1801
1802 mdb_printf("\n");
1803 mdb_dec_indent(2);
1804 }
1805
1806 mdb_dec_indent(2);
1807 mdb_free(qentryp, PMCS_QENTRY_SIZE);
1808 }
1809
1810 static void
dump_one_qentry_inbound(uint32_t * qentryp,int idx,uint64_t devid_filter)1811 dump_one_qentry_inbound(uint32_t *qentryp, int idx, uint64_t devid_filter)
1812 {
1813 int qeidx;
1814 uint32_t word0 = LE_32(*qentryp);
1815 uint32_t devid = LE_32(*(qentryp + 2));
1816
1817 /*
1818 * Check to see if we're filtering on a device ID
1819 */
1820 if (devid_filter != PMCS_INVALID_DEVICE_ID) {
1821 if (iomb_is_dev_hdl_specific(word0, B_TRUE)) {
1822 if (devid_filter != devid) {
1823 return;
1824 }
1825 } else {
1826 return;
1827 }
1828 }
1829
1830 mdb_printf("Entry #%02d\n", idx);
1831 mdb_inc_indent(2);
1832
1833 mdb_printf("Header: 0x%08x (", word0);
1834 if (word0 & PMCS_IOMB_VALID) {
1835 mdb_printf("VALID, ");
1836 }
1837 if (word0 & PMCS_IOMB_HIPRI) {
1838 mdb_printf("HIPRI, ");
1839 }
1840 mdb_printf("OBID=%d, ",
1841 (word0 & PMCS_IOMB_OBID_MASK) >> PMCS_IOMB_OBID_SHIFT);
1842 mdb_printf("CAT=%s, ",
1843 iomb_cat((word0 & PMCS_IOMB_CAT_MASK) >> PMCS_IOMB_CAT_SHIFT));
1844 mdb_printf("OPCODE=%s",
1845 inbound_iomb_opcode(word0 & PMCS_IOMB_OPCODE_MASK));
1846 mdb_printf(")\n");
1847
1848 mdb_printf("HTAG: 0x%08x\n", LE_32(*(qentryp + 1)));
1849 mdb_printf("Remaining Payload:\n");
1850
1851 mdb_inc_indent(2);
1852 for (qeidx = 2; qeidx < (PMCS_QENTRY_SIZE / 4); qeidx++) {
1853 mdb_printf("%08x ", LE_32(*(qentryp + qeidx)));
1854 }
1855 mdb_printf("\n");
1856 mdb_dec_indent(4);
1857 }
1858
1859 static void
display_inbound_queues(struct pmcs_hw ss,uint64_t devid_filter,uint_t verbose)1860 display_inbound_queues(struct pmcs_hw ss, uint64_t devid_filter, uint_t verbose)
1861 {
1862 int idx, qidx, iqci, last_consumed;
1863 uintptr_t ibqp;
1864 uint32_t *qentryp = mdb_alloc(PMCS_QENTRY_SIZE, UM_SLEEP);
1865 uint32_t *cip;
1866
1867 mdb_printf("\n");
1868 mdb_printf("Inbound Queues\n");
1869 mdb_printf("--------------\n");
1870
1871 mdb_inc_indent(2);
1872
1873 for (qidx = 0; qidx < PMCS_NIQ; qidx++) {
1874 ibqp = (uintptr_t)ss.iqp[qidx];
1875
1876 if (ibqp == NULL) {
1877 mdb_printf("No inbound queue ptr for queue #%d\n",
1878 qidx);
1879 continue;
1880 }
1881
1882 mdb_printf("Inbound Queue #%d (Queue Type = %s)\n", qidx,
1883 ibq_type(qidx));
1884
1885 cip = (uint32_t *)((void *)ss.cip);
1886 if (MDB_RD(&iqci, 4, cip + (qidx * 4)) == -1) {
1887 mdb_warn("Couldn't read iqci\n");
1888 break;
1889 }
1890 iqci = LE_32(iqci);
1891
1892 mdb_printf("Producer index: %d Consumer index: %d\n\n",
1893 ss.shadow_iqpi[qidx], iqci);
1894 mdb_inc_indent(2);
1895
1896 if (iqci == 0) {
1897 last_consumed = ss.ioq_depth - 1;
1898 } else {
1899 last_consumed = iqci - 1;
1900 }
1901
1902 if (!verbose) {
1903 mdb_printf("Last processed entry:\n");
1904 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1905 (ibqp + (PMCS_QENTRY_SIZE * last_consumed)))
1906 == -1) {
1907 mdb_warn("Couldn't read queue entry at 0x%p\n",
1908 (ibqp + (PMCS_QENTRY_SIZE *
1909 last_consumed)));
1910 break;
1911 }
1912 dump_one_qentry_inbound(qentryp, last_consumed,
1913 devid_filter);
1914 mdb_printf("\n");
1915 mdb_dec_indent(2);
1916 continue;
1917 }
1918
1919 for (idx = 0; idx < ss.ioq_depth; idx++) {
1920 if (MDB_RD(qentryp, PMCS_QENTRY_SIZE,
1921 (ibqp + (PMCS_QENTRY_SIZE * idx))) == -1) {
1922 mdb_warn("Couldn't read queue entry at 0x%p\n",
1923 (ibqp + (PMCS_QENTRY_SIZE * idx)));
1924 break;
1925 }
1926 dump_one_qentry_inbound(qentryp, idx, devid_filter);
1927 }
1928
1929 mdb_printf("\n");
1930 mdb_dec_indent(2);
1931 }
1932
1933 mdb_dec_indent(2);
1934 mdb_free(qentryp, PMCS_QENTRY_SIZE);
1935 }
1936
1937 /*
1938 * phy is our copy of the PHY structure. phyp is the pointer to the actual
1939 * kernel PHY data structure
1940 */
1941 static void
display_phy(struct pmcs_phy phy,struct pmcs_phy * phyp,int verbose,int totals_only)1942 display_phy(struct pmcs_phy phy, struct pmcs_phy *phyp, int verbose,
1943 int totals_only)
1944 {
1945 char *dtype, *speed;
1946 char *yes = "Yes";
1947 char *no = "No";
1948 char *cfgd = no;
1949 char *apend = no;
1950 char *asent = no;
1951 char *dead = no;
1952 char *changed = no;
1953 char route_attr, route_method;
1954
1955 switch (phy.dtype) {
1956 case NOTHING:
1957 dtype = "None";
1958 break;
1959 case SATA:
1960 dtype = "SATA";
1961 if (phy.configured) {
1962 ++sata_phys;
1963 }
1964 break;
1965 case SAS:
1966 dtype = "SAS";
1967 if (phy.configured) {
1968 ++sas_phys;
1969 }
1970 break;
1971 case EXPANDER:
1972 dtype = "EXP";
1973 if (phy.configured) {
1974 ++exp_phys;
1975 }
1976 break;
1977 }
1978
1979 if (phy.dtype == NOTHING) {
1980 empty_phys++;
1981 } else if ((phy.dtype == EXPANDER) && phy.configured) {
1982 num_expanders++;
1983 }
1984
1985 if (totals_only) {
1986 return;
1987 }
1988
1989 switch (phy.link_rate) {
1990 case SAS_LINK_RATE_1_5GBIT:
1991 speed = "1.5Gb/s";
1992 break;
1993 case SAS_LINK_RATE_3GBIT:
1994 speed = "3 Gb/s";
1995 break;
1996 case SAS_LINK_RATE_6GBIT:
1997 speed = "6 Gb/s";
1998 break;
1999 default:
2000 speed = "N/A";
2001 break;
2002 }
2003
2004 if ((phy.dtype != NOTHING) || verbose) {
2005 print_sas_address(&phy);
2006
2007 if (phy.device_id != PMCS_INVALID_DEVICE_ID) {
2008 mdb_printf(" %3d %4d %6s %4s ",
2009 phy.device_id, phy.phynum, speed, dtype);
2010 } else {
2011 mdb_printf(" N/A %4d %6s %4s ",
2012 phy.phynum, speed, dtype);
2013 }
2014
2015 if (verbose) {
2016 if (phy.abort_sent) {
2017 asent = yes;
2018 }
2019 if (phy.abort_pending) {
2020 apend = yes;
2021 }
2022 if (phy.configured) {
2023 cfgd = yes;
2024 }
2025 if (phy.dead) {
2026 dead = yes;
2027 }
2028 if (phy.changed) {
2029 changed = yes;
2030 }
2031
2032 switch (phy.routing_attr) {
2033 case SMP_ROUTING_DIRECT:
2034 route_attr = 'D';
2035 break;
2036 case SMP_ROUTING_SUBTRACTIVE:
2037 route_attr = 'S';
2038 break;
2039 case SMP_ROUTING_TABLE:
2040 route_attr = 'T';
2041 break;
2042 default:
2043 route_attr = '?';
2044 break;
2045 }
2046
2047 switch (phy.routing_method) {
2048 case SMP_ROUTING_DIRECT:
2049 route_method = 'D';
2050 break;
2051 case SMP_ROUTING_SUBTRACTIVE:
2052 route_method = 'S';
2053 break;
2054 case SMP_ROUTING_TABLE:
2055 route_method = 'T';
2056 break;
2057 default:
2058 route_attr = '?';
2059 break;
2060 }
2061
2062 mdb_printf("%-4s %-4s %-4s %-4s %-4s %3d %3c/%1c %3d "
2063 "%1d 0x%p ", cfgd, apend, asent, changed, dead,
2064 phy.ref_count, route_attr, route_method,
2065 phy.enum_attempts, phy.reenumerate, phy.phy_lock);
2066 }
2067
2068 mdb_printf("Path: %s\n", phy.path);
2069
2070 /*
2071 * In verbose mode, on the next line print the drill down
2072 * info to see either the DISCOVER response or the REPORT
2073 * GENERAL response depending on the PHY's dtype
2074 */
2075 if (verbose) {
2076 uintptr_t tphyp = (uintptr_t)phyp;
2077
2078 mdb_inc_indent(4);
2079 switch (phy.dtype) {
2080 case EXPANDER:
2081 if (!phy.configured) {
2082 break;
2083 }
2084 mdb_printf("REPORT GENERAL response: %p::"
2085 "print smp_report_general_resp_t\n",
2086 (tphyp + offsetof(struct pmcs_phy,
2087 rg_resp)));
2088 break;
2089 case SAS:
2090 case SATA:
2091 mdb_printf("DISCOVER response: %p::"
2092 "print smp_discover_resp_t\n",
2093 (tphyp + offsetof(struct pmcs_phy,
2094 disc_resp)));
2095 break;
2096 default:
2097 break;
2098 }
2099 mdb_dec_indent(4);
2100 }
2101 }
2102 }
2103
2104 static void
display_phys(struct pmcs_hw ss,int verbose,struct pmcs_phy * parent,int level,int totals_only)2105 display_phys(struct pmcs_hw ss, int verbose, struct pmcs_phy *parent, int level,
2106 int totals_only)
2107 {
2108 pmcs_phy_t phy;
2109 pmcs_phy_t *pphy = parent;
2110
2111 mdb_inc_indent(3);
2112
2113 if (parent == NULL) {
2114 pphy = (pmcs_phy_t *)ss.root_phys;
2115 } else {
2116 pphy = (pmcs_phy_t *)parent;
2117 }
2118
2119 if (level == 0) {
2120 sas_phys = 0;
2121 sata_phys = 0;
2122 exp_phys = 0;
2123 num_expanders = 0;
2124 empty_phys = 0;
2125 }
2126
2127 if (!totals_only) {
2128 if (level == 0) {
2129 mdb_printf("PHY information\n");
2130 }
2131 mdb_printf("--------\n");
2132 mdb_printf("Level %2d\n", level);
2133 mdb_printf("--------\n");
2134 mdb_printf("SAS Address Hdl Phy# Speed Type ");
2135
2136 if (verbose) {
2137 mdb_printf("Cfgd AbtP AbtS Chgd Dead Ref RtA/M Enm R "
2138 "Lock\n");
2139 } else {
2140 mdb_printf("\n");
2141 }
2142 }
2143
2144 while (pphy) {
2145 if (MDB_RD(&phy, sizeof (phy), (uintptr_t)pphy) == -1) {
2146 NOREAD(pmcs_phy_t, phy);
2147 break;
2148 }
2149
2150 display_phy(phy, pphy, verbose, totals_only);
2151
2152 if (phy.children) {
2153 display_phys(ss, verbose, phy.children, level + 1,
2154 totals_only);
2155 if (!totals_only) {
2156 mdb_printf("\n");
2157 }
2158 }
2159
2160 pphy = phy.sibling;
2161 }
2162
2163 mdb_dec_indent(3);
2164
2165 if (level == 0) {
2166 if (verbose) {
2167 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP) "
2168 "(+%d subsidiary + %d empty)\n", "Occupied PHYs:",
2169 (sas_phys + sata_phys + num_expanders),
2170 sas_phys, sata_phys, num_expanders,
2171 (exp_phys - num_expanders), empty_phys);
2172 } else {
2173 mdb_printf("%19s %d (%d SAS + %d SATA + %d SMP)\n",
2174 "Occupied PHYs:",
2175 (sas_phys + sata_phys + num_expanders),
2176 sas_phys, sata_phys, num_expanders);
2177 }
2178 }
2179 }
2180
2181 /*
2182 * filter is used to indicate whether we are filtering log messages based
2183 * on "instance". The other filtering (based on options) depends on the
2184 * values that are passed in for "sas_addr" and "phy_path".
2185 *
2186 * MAX_INST_STRLEN is the largest string size from which we will attempt
2187 * to convert to an instance number. The string will be formed up as
2188 * "0t<inst>\0" so that mdb_strtoull can parse it properly.
2189 */
2190 #define MAX_INST_STRLEN 8
2191
2192 static int
pmcs_dump_tracelog(boolean_t filter,int instance,uint64_t tail_lines,const char * phy_path,uint64_t sas_address,uint64_t verbose)2193 pmcs_dump_tracelog(boolean_t filter, int instance, uint64_t tail_lines,
2194 const char *phy_path, uint64_t sas_address, uint64_t verbose)
2195 {
2196 pmcs_tbuf_t *tbuf_addr;
2197 uint_t tbuf_idx;
2198 pmcs_tbuf_t tbuf;
2199 boolean_t wrap, elem_filtered;
2200 uint_t start_idx, elems_to_print, idx, tbuf_num_elems;
2201 char *bufp;
2202 char elem_inst[MAX_INST_STRLEN], ei_idx;
2203 uint64_t sas_addr;
2204 uint8_t *sas_addressp;
2205
2206 /* Get the address of the first element */
2207 if (mdb_readvar(&tbuf_addr, "pmcs_tbuf") == -1) {
2208 mdb_warn("can't read pmcs_tbuf");
2209 return (DCMD_ERR);
2210 }
2211
2212 /* Get the total number */
2213 if (mdb_readvar(&tbuf_num_elems, "pmcs_tbuf_num_elems") == -1) {
2214 mdb_warn("can't read pmcs_tbuf_num_elems");
2215 return (DCMD_ERR);
2216 }
2217
2218 /* Get the current index */
2219 if (mdb_readvar(&tbuf_idx, "pmcs_tbuf_idx") == -1) {
2220 mdb_warn("can't read pmcs_tbuf_idx");
2221 return (DCMD_ERR);
2222 }
2223
2224 /* Indicator as to whether the buffer has wrapped */
2225 if (mdb_readvar(&wrap, "pmcs_tbuf_wrap") == -1) {
2226 mdb_warn("can't read pmcs_tbuf_wrap");
2227 return (DCMD_ERR);
2228 }
2229
2230 /*
2231 * On little-endian systems, the SAS address passed in will be
2232 * byte swapped. Take care of that here.
2233 */
2234 #if defined(_LITTLE_ENDIAN)
2235 sas_addr = ((sas_address << 56) |
2236 ((sas_address << 40) & 0xff000000000000ULL) |
2237 ((sas_address << 24) & 0xff0000000000ULL) |
2238 ((sas_address << 8) & 0xff00000000ULL) |
2239 ((sas_address >> 8) & 0xff000000ULL) |
2240 ((sas_address >> 24) & 0xff0000ULL) |
2241 ((sas_address >> 40) & 0xff00ULL) |
2242 (sas_address >> 56));
2243 #else
2244 sas_addr = sas_address;
2245 #endif
2246 sas_addressp = (uint8_t *)&sas_addr;
2247
2248 /* Ensure the tail number isn't greater than the size of the log */
2249 if (tail_lines > tbuf_num_elems) {
2250 tail_lines = tbuf_num_elems;
2251 }
2252
2253 /* Figure out where we start and stop */
2254 if (wrap) {
2255 if (tail_lines) {
2256 /* Do we need to wrap backwards? */
2257 if (tail_lines > tbuf_idx) {
2258 start_idx = tbuf_num_elems - (tail_lines -
2259 tbuf_idx);
2260 } else {
2261 start_idx = tbuf_idx - tail_lines;
2262 }
2263 elems_to_print = tail_lines;
2264 } else {
2265 start_idx = tbuf_idx;
2266 elems_to_print = tbuf_num_elems;
2267 }
2268 } else {
2269 if (tail_lines > tbuf_idx) {
2270 tail_lines = tbuf_idx;
2271 }
2272 if (tail_lines) {
2273 start_idx = tbuf_idx - tail_lines;
2274 elems_to_print = tail_lines;
2275 } else {
2276 start_idx = 0;
2277 elems_to_print = tbuf_idx;
2278 }
2279 }
2280
2281 idx = start_idx;
2282
2283 /* Dump the buffer contents */
2284 while (elems_to_print != 0) {
2285 if (MDB_RD(&tbuf, sizeof (pmcs_tbuf_t), (tbuf_addr + idx))
2286 == -1) {
2287 NOREAD(tbuf, (tbuf_addr + idx));
2288 return (DCMD_ERR);
2289 }
2290
2291 /*
2292 * Check for filtering on HBA instance
2293 */
2294 elem_filtered = B_FALSE;
2295
2296 if (filter) {
2297 bufp = tbuf.buf;
2298 /* Skip the driver name */
2299 while (*bufp < '0' || *bufp > '9') {
2300 bufp++;
2301 }
2302
2303 ei_idx = 0;
2304 elem_inst[ei_idx++] = '0';
2305 elem_inst[ei_idx++] = 't';
2306 while (*bufp != ':' && ei_idx < (MAX_INST_STRLEN - 1)) {
2307 elem_inst[ei_idx++] = *bufp;
2308 bufp++;
2309 }
2310 elem_inst[ei_idx] = 0;
2311
2312 /* Get the instance */
2313 if ((int)mdb_strtoull(elem_inst) != instance) {
2314 elem_filtered = B_TRUE;
2315 }
2316 }
2317
2318 if (!elem_filtered && (phy_path || sas_address)) {
2319 /*
2320 * This message is not being filtered by HBA instance.
2321 * Now check to see if we're filtering based on
2322 * PHY path or SAS address.
2323 * Filtering is an "OR" operation. So, if any of the
2324 * criteria matches, this message will be printed.
2325 */
2326 elem_filtered = B_TRUE;
2327
2328 if (phy_path != NULL) {
2329 if (strncmp(phy_path, tbuf.phy_path,
2330 PMCS_TBUF_UA_MAX_SIZE) == 0) {
2331 elem_filtered = B_FALSE;
2332 }
2333 }
2334 if (sas_address != 0) {
2335 if (memcmp(sas_addressp, tbuf.phy_sas_address,
2336 8) == 0) {
2337 elem_filtered = B_FALSE;
2338 }
2339 }
2340 }
2341
2342 if (!elem_filtered) {
2343 /*
2344 * If the -v flag was given, print the firmware
2345 * timestamp along with the clock time
2346 */
2347 mdb_printf("%Y.%09ld ", tbuf.timestamp);
2348 if (verbose) {
2349 mdb_printf("(0x%" PRIx64 ") ",
2350 tbuf.fw_timestamp);
2351 }
2352 mdb_printf("%s\n", tbuf.buf);
2353 }
2354
2355 --elems_to_print;
2356 if (++idx == tbuf_num_elems) {
2357 idx = 0;
2358 }
2359 }
2360
2361 return (DCMD_OK);
2362 }
2363
2364 /*
2365 * Walkers
2366 */
2367 static int
targets_walk_i(mdb_walk_state_t * wsp)2368 targets_walk_i(mdb_walk_state_t *wsp)
2369 {
2370 if (wsp->walk_addr == NULL) {
2371 mdb_warn("Can not perform global walk\n");
2372 return (WALK_ERR);
2373 }
2374
2375 /*
2376 * Address provided belongs to HBA softstate. Get the targets pointer
2377 * to begin the walk.
2378 */
2379 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
2380 sizeof (pmcs_hw_t)) {
2381 mdb_warn("Unable to read HBA softstate\n");
2382 return (WALK_ERR);
2383 }
2384
2385 if (targets == NULL) {
2386 targets = mdb_alloc(sizeof (targets) * ss.max_dev, UM_SLEEP);
2387 }
2388
2389 if (MDB_RD(targets, sizeof (targets) * ss.max_dev, ss.targets) == -1) {
2390 NOREAD(targets, ss.targets);
2391 return (WALK_ERR);
2392 }
2393
2394 target_idx = 0;
2395 wsp->walk_addr = (uintptr_t)(targets[0]);
2396 wsp->walk_data = mdb_alloc(sizeof (pmcs_xscsi_t), UM_SLEEP);
2397
2398 return (WALK_NEXT);
2399 }
2400
2401 static int
targets_walk_s(mdb_walk_state_t * wsp)2402 targets_walk_s(mdb_walk_state_t *wsp)
2403 {
2404 int status;
2405
2406 if (target_idx == ss.max_dev) {
2407 return (WALK_DONE);
2408 }
2409
2410 if (mdb_vread(wsp->walk_data, sizeof (pmcs_xscsi_t),
2411 wsp->walk_addr) == -1) {
2412 mdb_warn("Failed to read target at %p", (void *)wsp->walk_addr);
2413 return (WALK_DONE);
2414 }
2415
2416 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
2417 wsp->walk_cbdata);
2418
2419 do {
2420 wsp->walk_addr = (uintptr_t)(targets[++target_idx]);
2421 } while ((wsp->walk_addr == NULL) && (target_idx < ss.max_dev));
2422
2423 if (target_idx == ss.max_dev) {
2424 return (WALK_DONE);
2425 }
2426
2427 return (status);
2428 }
2429
2430 static void
targets_walk_f(mdb_walk_state_t * wsp)2431 targets_walk_f(mdb_walk_state_t *wsp)
2432 {
2433 mdb_free(wsp->walk_data, sizeof (pmcs_xscsi_t));
2434 }
2435
2436
2437 static pmcs_phy_t *
pmcs_next_sibling(pmcs_phy_t * phyp)2438 pmcs_next_sibling(pmcs_phy_t *phyp)
2439 {
2440 pmcs_phy_t parent;
2441
2442 /*
2443 * First, if this is a root PHY, there are no more siblings
2444 */
2445 if (phyp->level == 0) {
2446 return (NULL);
2447 }
2448
2449 /*
2450 * Otherwise, next sibling is the parent's sibling
2451 */
2452 while (phyp->level > 0) {
2453 if (mdb_vread(&parent, sizeof (pmcs_phy_t),
2454 (uintptr_t)phyp->parent) == -1) {
2455 mdb_warn("pmcs_next_sibling: Failed to read PHY at %p",
2456 (void *)phyp->parent);
2457 return (NULL);
2458 }
2459
2460 if (parent.sibling != NULL) {
2461 break;
2462 }
2463
2464 /*
2465 * If this PHY's sibling is NULL and it's a root phy,
2466 * we're done.
2467 */
2468 if (parent.level == 0) {
2469 return (NULL);
2470 }
2471
2472 phyp = phyp->parent;
2473 }
2474
2475 return (parent.sibling);
2476 }
2477
2478 static int
phy_walk_i(mdb_walk_state_t * wsp)2479 phy_walk_i(mdb_walk_state_t *wsp)
2480 {
2481 if (wsp->walk_addr == NULL) {
2482 mdb_warn("Can not perform global walk\n");
2483 return (WALK_ERR);
2484 }
2485
2486 /*
2487 * Address provided belongs to HBA softstate. Get the targets pointer
2488 * to begin the walk.
2489 */
2490 if (mdb_vread(&ss, sizeof (pmcs_hw_t), wsp->walk_addr) !=
2491 sizeof (pmcs_hw_t)) {
2492 mdb_warn("Unable to read HBA softstate\n");
2493 return (WALK_ERR);
2494 }
2495
2496 wsp->walk_addr = (uintptr_t)(ss.root_phys);
2497 wsp->walk_data = mdb_alloc(sizeof (pmcs_phy_t), UM_SLEEP);
2498
2499 return (WALK_NEXT);
2500 }
2501
2502 static int
phy_walk_s(mdb_walk_state_t * wsp)2503 phy_walk_s(mdb_walk_state_t *wsp)
2504 {
2505 pmcs_phy_t *phyp, *nphyp;
2506 int status;
2507
2508 if (mdb_vread(wsp->walk_data, sizeof (pmcs_phy_t),
2509 wsp->walk_addr) == -1) {
2510 mdb_warn("phy_walk_s: Failed to read PHY at %p",
2511 (void *)wsp->walk_addr);
2512 return (WALK_DONE);
2513 }
2514
2515 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
2516 wsp->walk_cbdata);
2517
2518 phyp = (pmcs_phy_t *)wsp->walk_data;
2519 if (phyp->children) {
2520 wsp->walk_addr = (uintptr_t)(phyp->children);
2521 } else {
2522 wsp->walk_addr = (uintptr_t)(phyp->sibling);
2523 }
2524
2525 if (wsp->walk_addr == NULL) {
2526 /*
2527 * We reached the end of this sibling list. Trudge back up
2528 * to the parent and find the next sibling after the expander
2529 * we just finished traversing, if there is one.
2530 */
2531 nphyp = pmcs_next_sibling(phyp);
2532
2533 if (nphyp == NULL) {
2534 return (WALK_DONE);
2535 }
2536
2537 wsp->walk_addr = (uintptr_t)nphyp;
2538 }
2539
2540 return (status);
2541 }
2542
2543 static void
phy_walk_f(mdb_walk_state_t * wsp)2544 phy_walk_f(mdb_walk_state_t *wsp)
2545 {
2546 mdb_free(wsp->walk_data, sizeof (pmcs_phy_t));
2547 }
2548
2549 static void
display_matching_work(struct pmcs_hw ss,uintmax_t index,uintmax_t snum,uintmax_t tag_type)2550 display_matching_work(struct pmcs_hw ss, uintmax_t index, uintmax_t snum,
2551 uintmax_t tag_type)
2552 {
2553 int idx;
2554 pmcwork_t work, *wp = &work;
2555 uintptr_t _wp;
2556 boolean_t printed_header = B_FALSE;
2557 uint32_t mask, mask_val, match_val;
2558 char *match_type;
2559
2560 if (index != UINT_MAX) {
2561 match_type = "index";
2562 mask = PMCS_TAG_INDEX_MASK;
2563 mask_val = index << PMCS_TAG_INDEX_SHIFT;
2564 match_val = index;
2565 } else if (snum != UINT_MAX) {
2566 match_type = "serial number";
2567 mask = PMCS_TAG_SERNO_MASK;
2568 mask_val = snum << PMCS_TAG_SERNO_SHIFT;
2569 match_val = snum;
2570 } else {
2571 switch (tag_type) {
2572 case PMCS_TAG_TYPE_NONE:
2573 match_type = "tag type NONE";
2574 break;
2575 case PMCS_TAG_TYPE_CBACK:
2576 match_type = "tag type CBACK";
2577 break;
2578 case PMCS_TAG_TYPE_WAIT:
2579 match_type = "tag type WAIT";
2580 break;
2581 }
2582 mask = PMCS_TAG_TYPE_MASK;
2583 mask_val = tag_type << PMCS_TAG_TYPE_SHIFT;
2584 match_val = tag_type;
2585 }
2586
2587 _wp = (uintptr_t)ss.work;
2588
2589 for (idx = 0; idx < ss.max_cmd; idx++, _wp += sizeof (pmcwork_t)) {
2590 if (MDB_RD(&work, sizeof (pmcwork_t), _wp) == -1) {
2591 NOREAD(pmcwork_t, _wp);
2592 continue;
2593 }
2594
2595 if ((work.htag & mask) != mask_val) {
2596 continue;
2597 }
2598
2599 if (printed_header == B_FALSE) {
2600 if (tag_type) {
2601 mdb_printf("\nWork structures matching %s\n\n",
2602 match_type, match_val);
2603 } else {
2604 mdb_printf("\nWork structures matching %s of "
2605 "0x%x\n\n", match_type, match_val);
2606 }
2607 mdb_printf("%8s %10s %20s %8s %8s O D\n",
2608 "HTag", "State", "Phy Path", "Target", "Timer");
2609 printed_header = B_TRUE;
2610 }
2611
2612 display_one_work(wp, 0, 0);
2613 }
2614
2615 if (!printed_header) {
2616 mdb_printf("No work structure matches found\n");
2617 }
2618 }
2619
2620 static int
pmcs_tag(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2621 pmcs_tag(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2622 {
2623 struct pmcs_hw ss;
2624 uintmax_t tag_type = UINT_MAX;
2625 uintmax_t snum = UINT_MAX;
2626 uintmax_t index = UINT_MAX;
2627 int args = 0;
2628 void *pmcs_state;
2629 char *state_str;
2630 struct dev_info dip;
2631
2632 if (!(flags & DCMD_ADDRSPEC)) {
2633 pmcs_state = NULL;
2634 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
2635 mdb_warn("can't read pmcs_softc_state");
2636 return (DCMD_ERR);
2637 }
2638 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_tag", argc,
2639 argv, (uintptr_t)pmcs_state) == -1) {
2640 mdb_warn("mdb_pwalk_dcmd failed");
2641 return (DCMD_ERR);
2642 }
2643 return (DCMD_OK);
2644 }
2645
2646 if (mdb_getopts(argc, argv,
2647 'i', MDB_OPT_UINT64, &index,
2648 's', MDB_OPT_UINT64, &snum,
2649 't', MDB_OPT_UINT64, &tag_type) != argc)
2650 return (DCMD_USAGE);
2651
2652 /*
2653 * Count the number of supplied options and make sure they are
2654 * within appropriate ranges. If they're set to UINT_MAX, that means
2655 * they were not supplied, in which case reset them to 0.
2656 */
2657 if (index != UINT_MAX) {
2658 args++;
2659 if (index > PMCS_TAG_INDEX_MASK) {
2660 mdb_warn("Index is out of range\n");
2661 return (DCMD_USAGE);
2662 }
2663 }
2664
2665 if (tag_type != UINT_MAX) {
2666 args++;
2667 switch (tag_type) {
2668 case PMCS_TAG_TYPE_NONE:
2669 case PMCS_TAG_TYPE_CBACK:
2670 case PMCS_TAG_TYPE_WAIT:
2671 break;
2672 default:
2673 mdb_warn("Invalid tag type\n");
2674 return (DCMD_USAGE);
2675 }
2676 }
2677
2678 if (snum != UINT_MAX) {
2679 args++;
2680 if (snum > (PMCS_TAG_SERNO_MASK >> PMCS_TAG_SERNO_SHIFT)) {
2681 mdb_warn("Serial number is out of range\n");
2682 return (DCMD_USAGE);
2683 }
2684 }
2685
2686 /*
2687 * Make sure 1 and only 1 option is specified
2688 */
2689 if ((args == 0) || (args > 1)) {
2690 mdb_warn("Exactly one of -i, -s and -t must be specified\n");
2691 return (DCMD_USAGE);
2692 }
2693
2694 if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
2695 NOREAD(pmcs_hw_t, addr);
2696 return (DCMD_ERR);
2697 }
2698
2699 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
2700 NOREAD(pmcs_hw_t, addr);
2701 return (DCMD_ERR);
2702 }
2703
2704 /* processing completed */
2705
2706 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
2707 (flags & DCMD_LOOPFIRST)) {
2708 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
2709 mdb_printf("\n");
2710 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n",
2711 "Address", "State", "Inst", "DIP");
2712 mdb_printf("================================="
2713 "============================================\n");
2714 }
2715
2716 switch (ss.state) {
2717 case STATE_NIL:
2718 state_str = "Invalid";
2719 break;
2720 case STATE_PROBING:
2721 state_str = "Probing";
2722 break;
2723 case STATE_RUNNING:
2724 state_str = "Running";
2725 break;
2726 case STATE_UNPROBING:
2727 state_str = "Unprobing";
2728 break;
2729 case STATE_DEAD:
2730 state_str = "Dead";
2731 break;
2732 case STATE_IN_RESET:
2733 state_str = "In Reset";
2734 break;
2735 }
2736
2737 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
2738 state_str, dip.devi_instance, ss.blocked, ss.configuring,
2739 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
2740 mdb_printf("\n");
2741
2742 mdb_inc_indent(4);
2743 display_matching_work(ss, index, snum, tag_type);
2744 mdb_dec_indent(4);
2745 mdb_printf("\n");
2746
2747 return (DCMD_OK);
2748 }
2749
2750 #ifndef _KMDB
2751 static int
pmcs_dump_fwlog(struct pmcs_hw * ss,int instance,const char * ofile)2752 pmcs_dump_fwlog(struct pmcs_hw *ss, int instance, const char *ofile)
2753 {
2754 uint8_t *fwlogp;
2755 int ofilefd = -1;
2756 char ofilename[MAXPATHLEN];
2757 int rval = DCMD_OK;
2758
2759 if (ss->fwlogp == NULL) {
2760 mdb_warn("Firmware event log disabled for instance %d",
2761 instance);
2762 return (DCMD_OK);
2763 }
2764
2765 if (snprintf(ofilename, MAXPATHLEN, "%s%d", ofile, instance) >
2766 MAXPATHLEN) {
2767 mdb_warn("Output filename is too long for instance %d",
2768 instance);
2769 return (DCMD_ERR);
2770 }
2771
2772 fwlogp = mdb_alloc(PMCS_FWLOG_SIZE, UM_SLEEP);
2773
2774 if (MDB_RD(fwlogp, PMCS_FWLOG_SIZE, ss->fwlogp) == -1) {
2775 NOREAD(fwlogp, ss->fwlogp);
2776 rval = DCMD_ERR;
2777 goto cleanup;
2778 }
2779
2780 ofilefd = open(ofilename, O_WRONLY | O_CREAT,
2781 S_IRUSR | S_IRGRP | S_IROTH);
2782 if (ofilefd < 0) {
2783 mdb_warn("Unable to open '%s' to dump instance %d event log",
2784 ofilename, instance);
2785 rval = DCMD_ERR;
2786 goto cleanup;
2787 }
2788
2789 if (write(ofilefd, fwlogp, PMCS_FWLOG_SIZE) != PMCS_FWLOG_SIZE) {
2790 mdb_warn("Failed to write %d bytes to output file: instance %d",
2791 PMCS_FWLOG_SIZE, instance);
2792 rval = DCMD_ERR;
2793 goto cleanup;
2794 }
2795
2796 mdb_printf("Event log for instance %d written to %s\n", instance,
2797 ofilename);
2798
2799 cleanup:
2800 if (ofilefd >= 0) {
2801 close(ofilefd);
2802 }
2803 mdb_free(fwlogp, PMCS_FWLOG_SIZE);
2804 return (rval);
2805 }
2806
2807 static int
pmcs_fwlog(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2808 pmcs_fwlog(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2809 {
2810 void *pmcs_state;
2811 const char *ofile = NULL;
2812 struct pmcs_hw ss;
2813 struct dev_info dip;
2814
2815 if (mdb_getopts(argc, argv, 'o', MDB_OPT_STR, &ofile, NULL) != argc) {
2816 return (DCMD_USAGE);
2817 }
2818
2819 if (ofile == NULL) {
2820 mdb_printf("No output file specified\n");
2821 return (DCMD_USAGE);
2822 }
2823
2824 if (!(flags & DCMD_ADDRSPEC)) {
2825 pmcs_state = NULL;
2826 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
2827 mdb_warn("can't read pmcs_softc_state");
2828 return (DCMD_ERR);
2829 }
2830 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_fwlog", argc,
2831 argv, (uintptr_t)pmcs_state) == -1) {
2832 mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
2833 return (DCMD_ERR);
2834 }
2835 return (DCMD_OK);
2836 }
2837
2838 if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
2839 NOREAD(pmcs_hw_t, addr);
2840 return (DCMD_ERR);
2841 }
2842
2843 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
2844 NOREAD(pmcs_hw_t, addr);
2845 return (DCMD_ERR);
2846 }
2847
2848 return (pmcs_dump_fwlog(&ss, dip.devi_instance, ofile));
2849 }
2850 #endif /* _KMDB */
2851
2852 static int
pmcs_log(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2853 pmcs_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2854 {
2855 void *pmcs_state;
2856 struct pmcs_hw ss;
2857 struct dev_info dip;
2858 const char *match_phy_path = NULL;
2859 uint64_t match_sas_address = 0, tail_lines = 0;
2860 uint_t verbose = 0;
2861
2862 if (!(flags & DCMD_ADDRSPEC)) {
2863 pmcs_state = NULL;
2864 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
2865 mdb_warn("can't read pmcs_softc_state");
2866 return (DCMD_ERR);
2867 }
2868 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs_log", argc,
2869 argv, (uintptr_t)pmcs_state) == -1) {
2870 mdb_warn("mdb_pwalk_dcmd failed for pmcs_log");
2871 return (DCMD_ERR);
2872 }
2873 return (DCMD_OK);
2874 }
2875
2876 if (mdb_getopts(argc, argv,
2877 'l', MDB_OPT_UINT64, &tail_lines,
2878 'p', MDB_OPT_STR, &match_phy_path,
2879 's', MDB_OPT_UINT64, &match_sas_address,
2880 'v', MDB_OPT_SETBITS, TRUE, &verbose,
2881 NULL) != argc) {
2882 return (DCMD_USAGE);
2883 }
2884
2885 if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
2886 NOREAD(pmcs_hw_t, addr);
2887 return (DCMD_ERR);
2888 }
2889
2890 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
2891 NOREAD(pmcs_hw_t, addr);
2892 return (DCMD_ERR);
2893 }
2894
2895 if (!(flags & DCMD_LOOP)) {
2896 return (pmcs_dump_tracelog(B_TRUE, dip.devi_instance,
2897 tail_lines, match_phy_path, match_sas_address, verbose));
2898 } else if (flags & DCMD_LOOPFIRST) {
2899 return (pmcs_dump_tracelog(B_FALSE, 0, tail_lines,
2900 match_phy_path, match_sas_address, verbose));
2901 } else {
2902 return (DCMD_OK);
2903 }
2904 }
2905
2906 static int
pmcs_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2907 pmcs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2908 {
2909 struct pmcs_hw ss;
2910 uint_t verbose = FALSE;
2911 uint_t phy_info = FALSE;
2912 uint_t hw_info = FALSE;
2913 uint_t target_info = FALSE;
2914 uint_t work_info = FALSE;
2915 uint_t ic_info = FALSE;
2916 uint_t iport_info = FALSE;
2917 uint_t waitqs_info = FALSE;
2918 uint_t ibq = FALSE;
2919 uint_t obq = FALSE;
2920 uint_t tgt_phy_count = FALSE;
2921 uint_t compq = FALSE;
2922 uint_t unconfigured = FALSE;
2923 uint_t damap_info = FALSE;
2924 uint_t dtc_info = FALSE;
2925 uint_t wserno = FALSE;
2926 uint_t fwlog = FALSE;
2927 boolean_t devid_filter = FALSE;
2928 uintptr_t pdevid;
2929 uint32_t devid;
2930 int rv = DCMD_OK;
2931 void *pmcs_state;
2932 char *state_str;
2933 struct dev_info dip;
2934 per_iport_setting_t pis;
2935
2936 if (!(flags & DCMD_ADDRSPEC)) {
2937 pmcs_state = NULL;
2938 if (mdb_readvar(&pmcs_state, "pmcs_softc_state") == -1) {
2939 mdb_warn("can't read pmcs_softc_state");
2940 return (DCMD_ERR);
2941 }
2942 if (mdb_pwalk_dcmd("genunix`softstate", "pmcs`pmcs", argc, argv,
2943 (uintptr_t)pmcs_state) == -1) {
2944 mdb_warn("mdb_pwalk_dcmd failed");
2945 return (DCMD_ERR);
2946 }
2947 return (DCMD_OK);
2948 }
2949
2950 if (mdb_getopts(argc, argv,
2951 'c', MDB_OPT_SETBITS, TRUE, &compq,
2952 'd', MDB_OPT_SETBITS, TRUE, &dtc_info,
2953 'D', MDB_OPT_UINTPTR_SET, &devid_filter, &pdevid,
2954 'e', MDB_OPT_SETBITS, TRUE, &fwlog,
2955 'h', MDB_OPT_SETBITS, TRUE, &hw_info,
2956 'i', MDB_OPT_SETBITS, TRUE, &ic_info,
2957 'I', MDB_OPT_SETBITS, TRUE, &iport_info,
2958 'm', MDB_OPT_SETBITS, TRUE, &damap_info,
2959 'p', MDB_OPT_SETBITS, TRUE, &phy_info,
2960 'q', MDB_OPT_SETBITS, TRUE, &ibq,
2961 'Q', MDB_OPT_SETBITS, TRUE, &obq,
2962 's', MDB_OPT_SETBITS, TRUE, &wserno,
2963 't', MDB_OPT_SETBITS, TRUE, &target_info,
2964 'T', MDB_OPT_SETBITS, TRUE, &tgt_phy_count,
2965 'u', MDB_OPT_SETBITS, TRUE, &unconfigured,
2966 'v', MDB_OPT_SETBITS, TRUE, &verbose,
2967 'w', MDB_OPT_SETBITS, TRUE, &work_info,
2968 'W', MDB_OPT_SETBITS, TRUE, &waitqs_info,
2969 NULL) != argc)
2970 return (DCMD_USAGE);
2971
2972 /*
2973 * The 'd' and 'm' options implicitly enable the 'I' option
2974 */
2975 pis.pis_damap_info = damap_info;
2976 pis.pis_dtc_info = dtc_info;
2977 if (damap_info || dtc_info) {
2978 iport_info = TRUE;
2979 }
2980
2981 /*
2982 * The -D option is meaningless without -q and/or -Q, and implies
2983 * verbosity.
2984 */
2985 if (devid_filter) {
2986 devid = (uint64_t)pdevid & 0xffffffff;
2987 if (!ibq && !obq) {
2988 mdb_printf("-D requires either -q or -Q\n");
2989 return (DCMD_USAGE);
2990 }
2991 if (devid > PMCS_DEVICE_ID_MASK) {
2992 mdb_printf("Device ID invalid\n");
2993 return (DCMD_USAGE);
2994 }
2995 verbose = TRUE;
2996 }
2997
2998 if (MDB_RD(&ss, sizeof (ss), addr) == -1) {
2999 NOREAD(pmcs_hw_t, addr);
3000 return (DCMD_ERR);
3001 }
3002
3003 if (MDB_RD(&dip, sizeof (struct dev_info), ss.dip) == -1) {
3004 NOREAD(pmcs_hw_t, addr);
3005 return (DCMD_ERR);
3006 }
3007
3008 /* processing completed */
3009
3010 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
3011 (flags & DCMD_LOOPFIRST) || phy_info || target_info || hw_info ||
3012 work_info || waitqs_info || ibq || obq || tgt_phy_count || compq ||
3013 unconfigured || fwlog) {
3014 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
3015 mdb_printf("\n");
3016 mdb_printf("%16s %9s %4s B C WorkFlags wserno DbgMsk %16s\n",
3017 "Address", "State", "Inst", "DIP");
3018 mdb_printf("================================="
3019 "============================================\n");
3020 }
3021
3022 switch (ss.state) {
3023 case STATE_NIL:
3024 state_str = "Invalid";
3025 break;
3026 case STATE_PROBING:
3027 state_str = "Probing";
3028 break;
3029 case STATE_RUNNING:
3030 state_str = "Running";
3031 break;
3032 case STATE_UNPROBING:
3033 state_str = "Unprobing";
3034 break;
3035 case STATE_DEAD:
3036 state_str = "Dead";
3037 break;
3038 case STATE_IN_RESET:
3039 state_str = "In Reset";
3040 break;
3041 }
3042
3043 mdb_printf("%16p %9s %4d %1d %1d 0x%08x 0x%04x 0x%04x %16p\n", addr,
3044 state_str, dip.devi_instance, ss.blocked, ss.configuring,
3045 ss.work_flags, ss.wserno, ss.debug_mask, ss.dip);
3046 mdb_printf("\n");
3047
3048 mdb_inc_indent(4);
3049
3050 if (waitqs_info)
3051 display_waitqs(ss, verbose);
3052
3053 if (hw_info)
3054 display_hwinfo(ss, verbose);
3055
3056 if (phy_info || tgt_phy_count)
3057 display_phys(ss, verbose, NULL, 0, tgt_phy_count);
3058
3059 if (target_info || tgt_phy_count)
3060 display_targets(ss, verbose, tgt_phy_count);
3061
3062 if (work_info || wserno)
3063 display_work(ss, verbose, wserno);
3064
3065 if (ic_info)
3066 display_ic(ss, verbose);
3067
3068 if (ibq)
3069 display_inbound_queues(ss, devid, verbose);
3070
3071 if (obq)
3072 display_outbound_queues(ss, devid, verbose);
3073
3074 if (iport_info)
3075 display_iport(ss, addr, verbose, &pis);
3076
3077 if (compq)
3078 display_completion_queue(ss);
3079
3080 if (unconfigured)
3081 display_unconfigured_targets(addr);
3082
3083 if (fwlog)
3084 display_event_log(ss);
3085
3086 mdb_dec_indent(4);
3087
3088 return (rv);
3089 }
3090
3091 void
pmcs_help()3092 pmcs_help()
3093 {
3094 mdb_printf("Prints summary information about each pmcs instance.\n"
3095 " -c: Dump the completion queue\n"
3096 " -d: Print per-iport information about device tree children\n"
3097 " -D <device ID>: With -q/-Q, filter by device handle\n"
3098 " -e: Display the in-memory firmware event log\n"
3099 " -h: Print more detailed hardware information\n"
3100 " -i: Print interrupt coalescing information\n"
3101 " -I: Print information about each iport\n"
3102 " -m: Print per-iport information about DAM/damap state\n"
3103 " -p: Print information about each attached PHY\n"
3104 " -q: Dump inbound queues\n"
3105 " -Q: Dump outbound queues\n"
3106 " -s: Dump all work structures sorted by serial number\n"
3107 " -t: Print information about each configured target\n"
3108 " -T: Print target and PHY count summary\n"
3109 " -u: Show SAS address of all unconfigured targets\n"
3110 " -w: Dump work structures\n"
3111 " -W: List pmcs cmds waiting on various queues\n"
3112 " -v: Add verbosity to the above options\n");
3113 }
3114
3115 void
pmcs_log_help()3116 pmcs_log_help()
3117 {
3118 mdb_printf("Dump the pmcs log buffer, possibly with filtering.\n"
3119 " -l TAIL_LINES: Dump the last TAIL_LINES messages\n"
3120 " -p PHY_PATH: Dump messages matching PHY_PATH\n"
3121 " -s SAS_ADDRESS: Dump messages matching SAS_ADDRESS\n\n"
3122 "Where: PHY_PATH can be found with ::pmcs -p (e.g. pp04.18.18.01)\n"
3123 " SAS_ADDRESS can be found with ::pmcs -t "
3124 "(e.g. 5000c5000358c221)\n");
3125 }
3126 void
pmcs_tag_help()3127 pmcs_tag_help()
3128 {
3129 mdb_printf("Print all work structures by matching the tag.\n"
3130 " -i index: Match tag index (0x000 - 0xfff)\n"
3131 " -s serialnumber: Match serial number (0x0000 - 0xffff)\n"
3132 " -t tagtype: Match tag type [NONE(1), CBACK(2), "
3133 "WAIT(3)]\n");
3134 }
3135
3136 static const mdb_dcmd_t dcmds[] = {
3137 { "pmcs", "?[-cdehiImpQqtTuwWv] [-D <device ID>]",
3138 "print pmcs information", pmcs_dcmd, pmcs_help
3139 },
3140 { "pmcs_log",
3141 "?[-v] [-p PHY_PATH | -s SAS_ADDRESS | -l TAIL_LINES]",
3142 "dump pmcs log file", pmcs_log, pmcs_log_help
3143 },
3144 { "pmcs_tag", "?[-t tagtype|-s serialnum|-i index]",
3145 "Find work structures by tag type, serial number or index",
3146 pmcs_tag, pmcs_tag_help
3147 },
3148 #ifndef _KMDB
3149 { "pmcs_fwlog",
3150 "?-o output_file",
3151 "dump pmcs firmware event log to output_file", pmcs_fwlog, NULL
3152 },
3153 #endif /* _KMDB */
3154 { NULL }
3155 };
3156
3157 static const mdb_walker_t walkers[] = {
3158 { "pmcs_targets", "walk target structures",
3159 targets_walk_i, targets_walk_s, targets_walk_f },
3160 { "pmcs_phys", "walk PHY structures",
3161 phy_walk_i, phy_walk_s, phy_walk_f },
3162 { NULL }
3163 };
3164
3165 static const mdb_modinfo_t modinfo = {
3166 MDB_API_VERSION, dcmds, walkers
3167 };
3168
3169 const mdb_modinfo_t *
_mdb_init(void)3170 _mdb_init(void)
3171 {
3172 return (&modinfo);
3173 }
3174