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