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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright (c) 2017 Joyent, Inc.
28 * Copyright (c) 2014, Tegile Systems Inc. All rights reserved.
29 * Copyright 2023 Racktop Systems, Inc.
30 */
31
32 #include <limits.h>
33 #include <sys/mdb_modapi.h>
34 #include <sys/sysinfo.h>
35 #include <sys/sunmdi.h>
36 #include <sys/list.h>
37 #include <sys/scsi/scsi.h>
38 #include <sys/refhash.h>
39
40 #pragma pack(1)
41 #include <sys/scsi/adapters/mpi/mpi2_type.h>
42 #include <sys/scsi/adapters/mpi/mpi2.h>
43 #include <sys/scsi/adapters/mpi/mpi2_cnfg.h>
44 #include <sys/scsi/adapters/mpi/mpi2_init.h>
45 #include <sys/scsi/adapters/mpi/mpi2_ioc.h>
46 #include <sys/scsi/adapters/mpi/mpi2_sas.h>
47 #include <sys/scsi/adapters/mpi/mpi2_raid.h>
48 #include <sys/scsi/adapters/mpi/mpi2_tool.h>
49 #pragma pack()
50
51 #include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
52
53 struct {
54 int value;
55 char *text;
56 } devinfo_array[] = {
57 { MPI2_SAS_DEVICE_INFO_SEP, "SEP" },
58 { MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE, "ATAPI device" },
59 { MPI2_SAS_DEVICE_INFO_LSI_DEVICE, "LSI device" },
60 { MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH, "direct attach" },
61 { MPI2_SAS_DEVICE_INFO_SSP_TARGET, "SSP tgt" },
62 { MPI2_SAS_DEVICE_INFO_STP_TARGET, "STP tgt" },
63 { MPI2_SAS_DEVICE_INFO_SMP_TARGET, "SMP tgt" },
64 { MPI2_SAS_DEVICE_INFO_SATA_DEVICE, "SATA dev" },
65 { MPI2_SAS_DEVICE_INFO_SSP_INITIATOR, "SSP init" },
66 { MPI2_SAS_DEVICE_INFO_STP_INITIATOR, "STP init" },
67 { MPI2_SAS_DEVICE_INFO_SMP_INITIATOR, "SMP init" },
68 { MPI2_SAS_DEVICE_INFO_SATA_HOST, "SATA host" }
69 };
70
71 int
construct_path(uintptr_t addr,char * result)72 construct_path(uintptr_t addr, char *result)
73 {
74 struct dev_info d;
75 char devi_node[PATH_MAX];
76 char devi_addr[PATH_MAX];
77
78 if (mdb_vread(&d, sizeof (d), addr) == -1) {
79 mdb_warn("couldn't read dev_info");
80 return (DCMD_ERR);
81 }
82
83 if (d.devi_parent) {
84 construct_path((uintptr_t)d.devi_parent, result);
85 mdb_readstr(devi_node, sizeof (devi_node),
86 (uintptr_t)d.devi_node_name);
87 mdb_readstr(devi_addr, sizeof (devi_addr),
88 (uintptr_t)d.devi_addr);
89 mdb_snprintf(result+strlen(result),
90 PATH_MAX-strlen(result),
91 "/%s%s%s", devi_node, (*devi_addr ? "@" : ""),
92 devi_addr);
93 }
94 return (DCMD_OK);
95 }
96
97 /* ARGSUSED */
98 int
mdi_info_cb(uintptr_t addr,const void * data,void * cbdata)99 mdi_info_cb(uintptr_t addr, const void *data, void *cbdata)
100 {
101 struct mdi_pathinfo pi;
102 struct mdi_client c;
103 char dev_path[PATH_MAX];
104 char string[PATH_MAX];
105 int mdi_target = 0, mdi_lun = 0;
106 int target = *(int *)cbdata;
107
108 if (mdb_vread(&pi, sizeof (pi), addr) == -1) {
109 mdb_warn("couldn't read mdi_pathinfo");
110 return (DCMD_ERR);
111 }
112 mdb_readstr(string, sizeof (string), (uintptr_t)pi.pi_addr);
113 mdi_target = (int)mdb_strtoull(string);
114 mdi_lun = (int)mdb_strtoull(strchr(string, ',') + 1);
115 if (target != mdi_target)
116 return (0);
117
118 if (mdb_vread(&c, sizeof (c), (uintptr_t)pi.pi_client) == -1) {
119 mdb_warn("couldn't read mdi_client");
120 return (-1);
121 }
122
123 *dev_path = '\0';
124 if (construct_path((uintptr_t)c.ct_dip, dev_path) != DCMD_OK)
125 strcpy(dev_path, "unknown");
126
127 mdb_printf("LUN %d: %s\n", mdi_lun, dev_path);
128 mdb_printf(" dip: %p %s path", c.ct_dip,
129 (pi.pi_preferred ? "preferred" : ""));
130 switch (pi.pi_state & MDI_PATHINFO_STATE_MASK) {
131 case MDI_PATHINFO_STATE_INIT:
132 mdb_printf(" initializing");
133 break;
134 case MDI_PATHINFO_STATE_ONLINE:
135 mdb_printf(" online");
136 break;
137 case MDI_PATHINFO_STATE_STANDBY:
138 mdb_printf(" standby");
139 break;
140 case MDI_PATHINFO_STATE_FAULT:
141 mdb_printf(" fault");
142 break;
143 case MDI_PATHINFO_STATE_OFFLINE:
144 mdb_printf(" offline");
145 break;
146 default:
147 mdb_printf(" invalid state");
148 break;
149 }
150 mdb_printf("\n");
151 return (0);
152 }
153
154 void
mdi_info(struct mptsas * mp,int target)155 mdi_info(struct mptsas *mp, int target)
156 {
157 struct dev_info d;
158 struct mdi_phci p;
159
160 if (mdb_vread(&d, sizeof (d), (uintptr_t)mp->m_dip) == -1) {
161 mdb_warn("couldn't read m_dip");
162 return;
163 }
164
165 if (MDI_PHCI(&d)) {
166 if (mdb_vread(&p, sizeof (p), (uintptr_t)d.devi_mdi_xhci)
167 == -1) {
168 mdb_warn("couldn't read m_dip.devi_mdi_xhci");
169 return;
170 }
171 if (p.ph_path_head)
172 mdb_pwalk("mdipi_phci_list", (mdb_walk_cb_t)mdi_info_cb,
173 &target, (uintptr_t)p.ph_path_head);
174 return;
175 }
176 }
177
178 void
print_cdb(mptsas_cmd_t * m)179 print_cdb(mptsas_cmd_t *m)
180 {
181 struct scsi_pkt pkt;
182 uchar_t cdb[512]; /* an arbitrarily large number */
183 int j;
184
185 if (mdb_vread(&pkt, sizeof (pkt), (uintptr_t)m->cmd_pkt) == -1) {
186 mdb_warn("couldn't read cmd_pkt");
187 return;
188 }
189
190 /*
191 * We use cmd_cdblen here because 5.10 doesn't
192 * have the cdb length in the pkt
193 */
194 if (mdb_vread(&cdb, m->cmd_cdblen, (uintptr_t)pkt.pkt_cdbp) == -1) {
195 mdb_warn("couldn't read pkt_cdbp");
196 return;
197 }
198
199 mdb_printf("%3d,%-3d [ ",
200 pkt.pkt_address.a_target, pkt.pkt_address.a_lun);
201
202 for (j = 0; j < m->cmd_cdblen; j++)
203 mdb_printf("%02x ", cdb[j]);
204
205 mdb_printf("]\n");
206 }
207
208
209 void
display_ports(struct mptsas * mp)210 display_ports(struct mptsas *mp)
211 {
212 int i;
213 mdb_printf("\n");
214 mdb_printf("phy number and port mapping table\n");
215 for (i = 0; i < MPTSAS_MAX_PHYS; i++) {
216 if (mp->m_phy_info[i].attached_devhdl) {
217 mdb_printf("phy %x --> port %x, phymask %x,"
218 "attached_devhdl %x\n", i, mp->m_phy_info[i].port_num,
219 mp->m_phy_info[i].phy_mask,
220 mp->m_phy_info[i].attached_devhdl);
221 }
222 }
223 mdb_printf("\n");
224 }
225
226 static uintptr_t
klist_head(list_t * lp,uintptr_t klp)227 klist_head(list_t *lp, uintptr_t klp)
228 {
229 if ((uintptr_t)lp->list_head.list_next ==
230 klp + offsetof(struct list, list_head))
231 return (0);
232
233 return ((uintptr_t)(((char *)lp->list_head.list_next) -
234 lp->list_offset));
235 }
236
237 static uintptr_t
klist_next(list_t * lp,uintptr_t klp,void * op)238 klist_next(list_t *lp, uintptr_t klp, void *op)
239 {
240 /* LINTED E_BAD_PTR_CAST_ALIG */
241 struct list_node *np = (struct list_node *)(((char *)op) +
242 lp->list_offset);
243
244 if ((uintptr_t)np->list_next == klp + offsetof(struct list, list_head))
245 return (0);
246
247 return (((uintptr_t)(np->list_next)) - lp->list_offset);
248 }
249
250 static void *
krefhash_first(uintptr_t khp,uintptr_t * addr)251 krefhash_first(uintptr_t khp, uintptr_t *addr)
252 {
253 refhash_t mh;
254 uintptr_t klp;
255 uintptr_t kop;
256 void *rp;
257
258 mdb_vread(&mh, sizeof (mh), khp);
259 klp = klist_head(&mh.rh_objs, khp + offsetof(refhash_t, rh_objs));
260 if (klp == 0)
261 return (NULL);
262
263 kop = klp - mh.rh_link_off;
264 if (addr)
265 *addr = kop;
266 rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
267 mdb_vread(rp, mh.rh_obj_size, kop);
268
269 return (rp);
270 }
271
272 static void *
krefhash_next(uintptr_t khp,void * op,uintptr_t * addr)273 krefhash_next(uintptr_t khp, void *op, uintptr_t *addr)
274 {
275 refhash_t mh;
276 void *prev = op;
277 refhash_link_t *lp;
278 uintptr_t klp;
279 uintptr_t kop;
280 refhash_link_t ml;
281 void *rp;
282
283 mdb_vread(&mh, sizeof (mh), khp);
284 /* LINTED E_BAD_PTR_CAST_ALIG */
285 lp = (refhash_link_t *)(((char *)(op)) + mh.rh_link_off);
286 ml = *lp;
287 while ((klp = klist_next(&mh.rh_objs,
288 khp + offsetof(refhash_t, rh_objs), &ml)) != 0) {
289 mdb_vread(&ml, sizeof (ml), klp);
290 if (!(ml.rhl_flags & RHL_F_DEAD))
291 break;
292 }
293
294 if (klp == 0) {
295 mdb_free(prev, mh.rh_obj_size);
296 return (NULL);
297 }
298
299 kop = klp - mh.rh_link_off;
300 if (addr)
301 *addr = kop;
302 rp = mdb_alloc(mh.rh_obj_size, UM_SLEEP);
303 mdb_vread(rp, mh.rh_obj_size, kop);
304
305 mdb_free(prev, mh.rh_obj_size);
306 return (rp);
307 }
308
309 void
display_targets(struct mptsas * mp,uint_t verbose)310 display_targets(struct mptsas *mp, uint_t verbose)
311 {
312 mptsas_target_t *ptgt;
313 mptsas_smp_t *psmp;
314 int loop, comma;
315 uintptr_t p_addr;
316
317 mdb_printf("\n");
318 mdb_printf(" mptsas_target_t slot devhdl wwn ncmds throttle "
319 "dr_flag dups\n");
320 mdb_printf("---------------------------------------"
321 "-------------------------------\n");
322 for (ptgt = krefhash_first((uintptr_t)mp->m_targets, &p_addr);
323 ptgt != NULL;
324 ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt, &p_addr)) {
325 if (ptgt->m_addr.mta_wwn ||
326 ptgt->m_deviceinfo) {
327 mdb_printf("%16p ", p_addr);
328 mdb_printf("%4d ", ptgt->m_slot_num);
329 mdb_printf("%4d ", ptgt->m_devhdl);
330 if (ptgt->m_addr.mta_wwn)
331 mdb_printf("%"PRIx64" ",
332 ptgt->m_addr.mta_wwn);
333 mdb_printf("%3d", ptgt->m_t_ncmds);
334 switch (ptgt->m_t_throttle) {
335 case QFULL_THROTTLE:
336 mdb_printf(" QFULL ");
337 break;
338 case DRAIN_THROTTLE:
339 mdb_printf(" DRAIN ");
340 break;
341 case HOLD_THROTTLE:
342 mdb_printf(" HOLD ");
343 break;
344 case MAX_THROTTLE:
345 mdb_printf(" MAX ");
346 break;
347 default:
348 mdb_printf("%8d ",
349 ptgt->m_t_throttle);
350 }
351 switch (ptgt->m_dr_flag) {
352 case MPTSAS_DR_INACTIVE:
353 mdb_printf(" INACTIVE ");
354 break;
355 case MPTSAS_DR_INTRANSITION:
356 mdb_printf("TRANSITION ");
357 break;
358 default:
359 mdb_printf(" UNKNOWN ");
360 break;
361 }
362 mdb_printf("%d\n",
363 ptgt->m_dups);
364
365 if (verbose) {
366 mdb_inc_indent(5);
367 if ((ptgt->m_deviceinfo &
368 MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
369 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
370 mdb_printf("Fanout expander: ");
371 if ((ptgt->m_deviceinfo &
372 MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
373 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
374 mdb_printf("Edge expander: ");
375 if ((ptgt->m_deviceinfo &
376 MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
377 MPI2_SAS_DEVICE_INFO_END_DEVICE)
378 mdb_printf("End device: ");
379 if ((ptgt->m_deviceinfo &
380 MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) ==
381 MPI2_SAS_DEVICE_INFO_NO_DEVICE)
382 mdb_printf("No device ");
383
384 for (loop = 0, comma = 0;
385 loop < (sizeof (devinfo_array) /
386 sizeof (devinfo_array[0])); loop++) {
387 if (ptgt->m_deviceinfo &
388 devinfo_array[loop].value) {
389 mdb_printf("%s%s",
390 (comma ? ", " : ""),
391 devinfo_array[loop].text);
392 comma++;
393 }
394 }
395 mdb_printf("\n");
396 mdi_info(mp, ptgt->m_slot_num);
397 mdb_dec_indent(5);
398 }
399 }
400 }
401
402 mdb_printf("\n");
403 mdb_printf(" mptsas_smp_t devhdl wwn phymask\n");
404 mdb_printf("---------------------------------------"
405 "------------------\n");
406 for (psmp = (mptsas_smp_t *)krefhash_first(
407 (uintptr_t)mp->m_smp_targets, &p_addr);
408 psmp != NULL;
409 psmp = krefhash_next((uintptr_t)mp->m_smp_targets, psmp,
410 &p_addr)) {
411 mdb_printf("%16p ", p_addr);
412 mdb_printf("%4d %"PRIx64" %04x\n",
413 psmp->m_devhdl, psmp->m_addr.mta_wwn,
414 psmp->m_addr.mta_phymask);
415
416 if (!verbose)
417 continue;
418
419 mdb_inc_indent(5);
420 if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
421 == MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
422 mdb_printf("Fanout expander: ");
423 if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
424 == MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER)
425 mdb_printf("Edge expander: ");
426 if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
427 == MPI2_SAS_DEVICE_INFO_END_DEVICE)
428 mdb_printf("End device: ");
429 if ((psmp->m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE)
430 == MPI2_SAS_DEVICE_INFO_NO_DEVICE)
431 mdb_printf("No device ");
432
433 for (loop = 0, comma = 0;
434 loop < (sizeof (devinfo_array)
435 / sizeof (devinfo_array[0]));
436 loop++) {
437 if (psmp->m_deviceinfo &
438 devinfo_array[loop].value) {
439 mdb_printf("%s%s",
440 (comma ? ", " : ""),
441 devinfo_array[loop].text);
442 comma++;
443 }
444 }
445 mdb_printf("\n");
446 mdb_dec_indent(5);
447 }
448 }
449
450 int
display_slotinfo(struct mptsas * mp,struct mptsas_slots * s)451 display_slotinfo(struct mptsas *mp, struct mptsas_slots *s)
452 {
453 int i, nslots;
454 struct mptsas_cmd c, *q, *slots;
455 mptsas_target_t *ptgt;
456 int header_output = 0;
457 int rv = DCMD_OK;
458 int slots_in_use = 0;
459 int tcmds = 0;
460 int mismatch = 0;
461 int wq, dq;
462 int ncmds = 0;
463 ulong_t saved_indent;
464 uintptr_t panicstr;
465 int state;
466
467 if ((state = mdb_get_state()) == MDB_STATE_RUNNING) {
468 mdb_warn("mptsas: slot info can only be displayed on a system "
469 "dump or under kmdb\n");
470 return (DCMD_ERR);
471 }
472
473 if (mdb_readvar(&panicstr, "panicstr") == -1) {
474 mdb_warn("can't read variable 'panicstr'");
475 return (DCMD_ERR);
476 }
477
478 if (state != MDB_STATE_STOPPED && panicstr == 0) {
479 mdb_warn("mptsas: slot info not available for live dump\n");
480 return (DCMD_ERR);
481 }
482
483 nslots = s->m_n_normal;
484 slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP);
485
486 for (i = 0; i < nslots; i++)
487 if (s->m_slot[i]) {
488 slots_in_use++;
489 if (mdb_vread(&slots[i], sizeof (mptsas_cmd_t),
490 (uintptr_t)s->m_slot[i]) == -1) {
491 mdb_warn("couldn't read slot");
492 s->m_slot[i] = NULL;
493 }
494 if ((slots[i].cmd_flags & CFLAG_CMDIOC) == 0)
495 tcmds++;
496 if (i != slots[i].cmd_slot)
497 mismatch++;
498 }
499
500 for (q = mp->m_waitq, wq = 0; q; q = c.cmd_linkp, wq++)
501 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
502 mdb_warn("couldn't follow m_waitq");
503 rv = DCMD_ERR;
504 goto exit;
505 }
506
507 for (q = mp->m_doneq, dq = 0; q; q = c.cmd_linkp, dq++)
508 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
509 mdb_warn("couldn't follow m_doneq");
510 rv = DCMD_ERR;
511 goto exit;
512 }
513
514 for (ptgt = krefhash_first((uintptr_t)mp->m_targets, NULL);
515 ptgt != NULL;
516 ptgt = krefhash_next((uintptr_t)mp->m_targets, ptgt, NULL)) {
517 if (ptgt->m_addr.mta_wwn ||
518 ptgt->m_deviceinfo) {
519 ncmds += ptgt->m_t_ncmds;
520 }
521 }
522
523 mdb_printf("\n");
524 mdb_printf(" mpt. slot mptsas_slots slot");
525 mdb_printf("\n");
526 mdb_printf("m_ncmds total"
527 " targ throttle m_t_ncmds targ_tot wq dq");
528 mdb_printf("\n");
529 mdb_printf("----------------------------------------------------");
530 mdb_printf("\n");
531
532 mdb_printf("%7d ", mp->m_ncmds);
533 mdb_printf("%s", (mp->m_ncmds == slots_in_use ? " " : "!="));
534 mdb_printf("%3d total %3d ", slots_in_use, ncmds);
535 mdb_printf("%s", (tcmds == ncmds ? " " : " !="));
536 mdb_printf("%3d %2d %2d\n", tcmds, wq, dq);
537
538 saved_indent = mdb_dec_indent(0);
539 mdb_dec_indent(saved_indent);
540
541 for (i = 0; i < s->m_n_normal; i++)
542 if (s->m_slot[i]) {
543 if (!header_output) {
544 mdb_printf("\n");
545 mdb_printf("mptsas_cmd slot cmd_slot "
546 "cmd_flags cmd_pkt_flags scsi_pkt "
547 " targ,lun [ pkt_cdbp ...\n");
548 mdb_printf("-------------------------------"
549 "--------------------------------------"
550 "--------------------------------------"
551 "------\n");
552 header_output = 1;
553 }
554 mdb_printf("%16p %4d %s %4d %8x %8x %16p ",
555 s->m_slot[i], i,
556 (i == slots[i].cmd_slot?" ":"BAD"),
557 slots[i].cmd_slot,
558 slots[i].cmd_flags,
559 slots[i].cmd_pkt_flags,
560 slots[i].cmd_pkt);
561 (void) print_cdb(&slots[i]);
562 }
563
564 /* print the wait queue */
565
566 for (q = mp->m_waitq; q; q = c.cmd_linkp) {
567 if (q == mp->m_waitq)
568 mdb_printf("\n");
569 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
570 == -1) {
571 mdb_warn("couldn't follow m_waitq");
572 rv = DCMD_ERR;
573 goto exit;
574 }
575 mdb_printf("%16p wait n/a %4d %8x %8x %16p ",
576 q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags,
577 c.cmd_pkt);
578 print_cdb(&c);
579 }
580
581 /* print the done queue */
582
583 for (q = mp->m_doneq; q; q = c.cmd_linkp) {
584 if (q == mp->m_doneq)
585 mdb_printf("\n");
586 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q)
587 == -1) {
588 mdb_warn("couldn't follow m_doneq");
589 rv = DCMD_ERR;
590 goto exit;
591 }
592 mdb_printf("%16p done n/a %4d %8x %8x %16p ",
593 q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags,
594 c.cmd_pkt);
595 print_cdb(&c);
596 }
597
598 mdb_inc_indent(saved_indent);
599
600 if (mp->m_ncmds != slots_in_use)
601 mdb_printf("WARNING: mpt.m_ncmds does not match the number of "
602 "slots in use\n");
603
604 if (tcmds != ncmds)
605 mdb_printf("WARNING: the total of m_target[].m_t_ncmds does "
606 "not match the slots in use\n");
607
608 if (mismatch)
609 mdb_printf("WARNING: corruption in slot table, "
610 "m_slot[].cmd_slot incorrect\n");
611
612 /* now check for corruptions */
613
614 for (q = mp->m_waitq; q; q = c.cmd_linkp) {
615 for (i = 0; i < nslots; i++)
616 if (s->m_slot[i] == q)
617 mdb_printf("WARNING: m_waitq entry"
618 "(mptsas_cmd_t) %p is in m_slot[%i]\n",
619 q, i);
620
621 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
622 mdb_warn("couldn't follow m_waitq");
623 rv = DCMD_ERR;
624 goto exit;
625 }
626 }
627
628 for (q = mp->m_doneq; q; q = c.cmd_linkp) {
629 for (i = 0; i < nslots; i++)
630 if (s->m_slot[i] == q)
631 mdb_printf("WARNING: m_doneq entry "
632 "(mptsas_cmd_t) %p is in m_slot[%i]\n", q, i);
633
634 if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) {
635 mdb_warn("couldn't follow m_doneq");
636 rv = DCMD_ERR;
637 goto exit;
638 }
639 if ((c.cmd_flags & CFLAG_FINISHED) == 0)
640 mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
641 "should have CFLAG_FINISHED set\n", q);
642 if (c.cmd_flags & CFLAG_IN_TRANSPORT)
643 mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
644 "should not have CFLAG_IN_TRANSPORT set\n", q);
645 if (c.cmd_flags & CFLAG_CMDARQ)
646 mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
647 "should not have CFLAG_CMDARQ set\n", q);
648 if (c.cmd_flags & CFLAG_COMPLETED)
649 mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p "
650 "should not have CFLAG_COMPLETED set\n", q);
651 }
652
653 exit:
654 mdb_free(slots, sizeof (mptsas_cmd_t) * nslots);
655 return (rv);
656 }
657
658 void
display_deviceinfo(struct mptsas * mp)659 display_deviceinfo(struct mptsas *mp)
660 {
661 char device_path[PATH_MAX];
662
663 *device_path = 0;
664 if (construct_path((uintptr_t)mp->m_dip, device_path) != DCMD_OK) {
665 strcpy(device_path, "couldn't determine device path");
666 }
667
668 mdb_printf("\n");
669 mdb_printf("base_wwid phys "
670 " prodid devid revid ssid\n");
671 mdb_printf("-----------------------------"
672 "----------------------------------\n");
673 mdb_printf("%"PRIx64" %2d "
674 "0x%04x 0x%04x ", mp->un.m_base_wwid, mp->m_num_phys,
675 mp->m_productid, mp->m_devid);
676 switch (mp->m_devid) {
677 case MPI2_MFGPAGE_DEVID_SAS2004:
678 mdb_printf("(SAS2004) ");
679 break;
680 case MPI2_MFGPAGE_DEVID_SAS2008:
681 mdb_printf("(SAS2008) ");
682 break;
683 case MPI2_MFGPAGE_DEVID_SAS2108_1:
684 case MPI2_MFGPAGE_DEVID_SAS2108_2:
685 case MPI2_MFGPAGE_DEVID_SAS2108_3:
686 mdb_printf("(SAS2108) ");
687 break;
688 case MPI2_MFGPAGE_DEVID_SAS2116_1:
689 case MPI2_MFGPAGE_DEVID_SAS2116_2:
690 mdb_printf("(SAS2116) ");
691 break;
692 case MPI2_MFGPAGE_DEVID_SSS6200:
693 mdb_printf("(SSS6200) ");
694 break;
695 case MPI2_MFGPAGE_DEVID_SAS2208_1:
696 case MPI2_MFGPAGE_DEVID_SAS2208_2:
697 case MPI2_MFGPAGE_DEVID_SAS2208_3:
698 case MPI2_MFGPAGE_DEVID_SAS2208_4:
699 case MPI2_MFGPAGE_DEVID_SAS2208_5:
700 case MPI2_MFGPAGE_DEVID_SAS2208_6:
701 mdb_printf("(SAS2208) ");
702 break;
703 case MPI2_MFGPAGE_DEVID_SAS2308_1:
704 case MPI2_MFGPAGE_DEVID_SAS2308_2:
705 case MPI2_MFGPAGE_DEVID_SAS2308_3:
706 mdb_printf("(SAS2308) ");
707 break;
708 case MPI25_MFGPAGE_DEVID_SAS3004:
709 mdb_printf("(SAS3004) ");
710 break;
711 case MPI25_MFGPAGE_DEVID_SAS3008:
712 mdb_printf("(SAS3008) ");
713 break;
714 case MPI25_MFGPAGE_DEVID_SAS3108_1:
715 case MPI25_MFGPAGE_DEVID_SAS3108_2:
716 case MPI25_MFGPAGE_DEVID_SAS3108_5:
717 case MPI25_MFGPAGE_DEVID_SAS3108_6:
718 mdb_printf("(SAS3108) ");
719 break;
720 case MPI26_MFGPAGE_DEVID_SAS3216:
721 case MPI26_MFGPAGE_DEVID_SAS3316_1:
722 case MPI26_MFGPAGE_DEVID_SAS3316_2:
723 case MPI26_MFGPAGE_DEVID_SAS3316_3:
724 case MPI26_MFGPAGE_DEVID_SAS3316_4:
725 mdb_printf("(SAS3216) ");
726 break;
727 case MPI26_MFGPAGE_DEVID_SAS3224:
728 case MPI26_MFGPAGE_DEVID_SAS3324_1:
729 case MPI26_MFGPAGE_DEVID_SAS3324_2:
730 case MPI26_MFGPAGE_DEVID_SAS3324_3:
731 case MPI26_MFGPAGE_DEVID_SAS3324_4:
732 mdb_printf("(SAS3224) ");
733 break;
734 case MPI26_MFGPAGE_DEVID_SAS3408:
735 mdb_printf("(SAS3408) ");
736 break;
737 case MPI26_MFGPAGE_DEVID_SAS3416:
738 mdb_printf("(SAS3416) ");
739 break;
740 case MPI26_MFGPAGE_DEVID_SAS3508:
741 case MPI26_MFGPAGE_DEVID_SAS3508_1:
742 mdb_printf("(SAS3508) ");
743 break;
744 case MPI26_MFGPAGE_DEVID_SAS3516:
745 case MPI26_MFGPAGE_DEVID_SAS3516_1:
746 mdb_printf("(SAS3516) ");
747 break;
748 case MPI26_MFGPAGE_DEVID_SAS3616:
749 mdb_printf("(SAS3616) ");
750 break;
751 case MPI26_MFGPAGE_DEVID_SAS3708:
752 mdb_printf("(SAS3708) ");
753 break;
754 case MPI26_MFGPAGE_DEVID_SAS3716:
755 mdb_printf("(SAS3716) ");
756 break;
757 case MPI26_MFGPAGE_DEVID_SAS4008:
758 mdb_printf("(SAS4008) ");
759 break;
760 default:
761 mdb_printf("(SAS????) ");
762 break;
763 }
764 mdb_printf("0x%02x 0x%04x\n", mp->m_revid, mp->m_ssid);
765 mdb_printf("%s\n", device_path);
766
767 }
768
769 void
dump_debug_log(void)770 dump_debug_log(void)
771 {
772 uint32_t idx;
773 size_t linecnt, linelen;
774 char *logbuf;
775 int i;
776
777 if (mdb_readsym(&idx, sizeof (uint32_t), "mptsas_dbglog_idx") == -1) {
778 mdb_warn("No debug log buffer present");
779 return;
780 }
781 if (mdb_readsym(&linecnt, sizeof (size_t), "mptsas_dbglog_linecnt")
782 == -1) {
783 mdb_warn("No debug linecnt present");
784 return;
785 }
786 if (mdb_readsym(&linelen, sizeof (size_t), "mptsas_dbglog_linelen")
787 == -1) {
788 mdb_warn("No debug linelen present");
789 return;
790 }
791 logbuf = mdb_alloc(linelen * linecnt, UM_SLEEP);
792
793 if (mdb_readsym(logbuf, linelen * linecnt, "mptsas_dbglog_bufs")
794 == -1) {
795 mdb_warn("No debug log buffer present");
796 return;
797 }
798 mdb_printf("\n");
799 idx &= linecnt - 1;
800 for (i = 0; i < linecnt; i++) {
801 mdb_printf("%s\n", &logbuf[idx * linelen]);
802 idx++;
803 idx &= linecnt - 1;
804 }
805 mdb_free(logbuf, linelen * linecnt);
806 }
807
808 static int
mptsas_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)809 mptsas_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
810 {
811 struct mptsas m;
812 struct mptsas_slots *s;
813
814 int nslots;
815 int slot_size = 0;
816 uint_t verbose = FALSE;
817 uint_t target_info = FALSE;
818 uint_t slot_info = FALSE;
819 uint_t device_info = FALSE;
820 uint_t port_info = FALSE;
821 uint_t debug_log = FALSE;
822 int rv = DCMD_OK;
823
824 if (!(flags & DCMD_ADDRSPEC)) {
825 void *mptsas_state = NULL;
826
827 if (mdb_readvar(&mptsas_state, "mptsas_state") == -1) {
828 mdb_warn("can't read mptsas_state");
829 return (DCMD_ERR);
830 }
831 if (mdb_pwalk_dcmd("genunix`softstate", "mpt_sas`mptsas", argc,
832 argv, (uintptr_t)mptsas_state) == -1) {
833 mdb_warn("mdb_pwalk_dcmd failed");
834 return (DCMD_ERR);
835 }
836 return (DCMD_OK);
837 }
838
839 if (mdb_getopts(argc, argv,
840 's', MDB_OPT_SETBITS, TRUE, &slot_info,
841 'd', MDB_OPT_SETBITS, TRUE, &device_info,
842 't', MDB_OPT_SETBITS, TRUE, &target_info,
843 'p', MDB_OPT_SETBITS, TRUE, &port_info,
844 'v', MDB_OPT_SETBITS, TRUE, &verbose,
845 'D', MDB_OPT_SETBITS, TRUE, &debug_log,
846 NULL) != argc)
847 return (DCMD_USAGE);
848
849
850 if (mdb_vread(&m, sizeof (m), addr) == -1) {
851 mdb_warn("couldn't read mpt struct at 0x%p", addr);
852 return (DCMD_ERR);
853 }
854
855 s = mdb_alloc(sizeof (mptsas_slots_t), UM_SLEEP);
856
857 if (mdb_vread(s, sizeof (mptsas_slots_t),
858 (uintptr_t)m.m_active) == -1) {
859 mdb_warn("couldn't read small mptsas_slots_t at 0x%p",
860 m.m_active);
861 mdb_free(s, sizeof (mptsas_slots_t));
862 return (DCMD_ERR);
863 }
864
865 nslots = s->m_n_normal;
866
867 mdb_free(s, sizeof (mptsas_slots_t));
868
869 slot_size = sizeof (mptsas_slots_t) +
870 (sizeof (mptsas_cmd_t *) * (nslots-1));
871
872 s = mdb_alloc(slot_size, UM_SLEEP);
873
874 if (mdb_vread(s, slot_size, (uintptr_t)m.m_active) == -1) {
875 mdb_warn("couldn't read large mptsas_slots_t at 0x%p",
876 m.m_active);
877 mdb_free(s, slot_size);
878 return (DCMD_ERR);
879 }
880
881 /* processing completed */
882
883 if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) ||
884 (flags & DCMD_LOOPFIRST) || slot_info || device_info ||
885 target_info) {
886 if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST))
887 mdb_printf("\n");
888 mdb_printf(" mptsas_t inst ncmds suspend power");
889 mdb_printf("\n");
890 mdb_printf("========================================="
891 "=======================================");
892 mdb_printf("\n");
893 }
894
895 mdb_printf("%16p %4d %5d ", addr, m.m_instance, m.m_ncmds);
896 mdb_printf("%7d", m.m_suspended);
897 switch (m.m_power_level) {
898 case PM_LEVEL_D0:
899 mdb_printf(" ON=D0 ");
900 break;
901 case PM_LEVEL_D1:
902 mdb_printf(" D1 ");
903 break;
904 case PM_LEVEL_D2:
905 mdb_printf(" D2 ");
906 break;
907 case PM_LEVEL_D3:
908 mdb_printf("OFF=D3 ");
909 break;
910 default:
911 mdb_printf("INVALD ");
912 }
913 mdb_printf("\n");
914
915 mdb_inc_indent(17);
916
917 if (target_info)
918 display_targets(&m, verbose);
919
920 if (port_info)
921 display_ports(&m);
922
923 if (device_info)
924 display_deviceinfo(&m);
925
926 if (slot_info)
927 display_slotinfo(&m, s);
928
929 if (debug_log)
930 dump_debug_log();
931
932 mdb_dec_indent(17);
933
934 mdb_free(s, slot_size);
935
936 return (rv);
937 }
938
939 void
mptsas_help()940 mptsas_help()
941 {
942 mdb_printf("Prints summary information about each mpt_sas instance, "
943 "including warning\nmessages when slot usage doesn't match "
944 "summary information.\n"
945 "Without the address of a \"struct mptsas\", prints every "
946 "instance.\n\n"
947 "Switches:\n"
948 " -t[v] includes information about targets, v = be more verbose\n"
949 " -p includes information about port\n"
950 " -s includes information about mpt slots\n"
951 " -d includes information about the hardware\n"
952 " -D print the mptsas specific debug log\n");
953 }
954
955 static const mdb_dcmd_t dcmds[] = {
956 { "mptsas", "?[-tpsdD]", "print mpt_sas information", mptsas_dcmd,
957 mptsas_help}, { NULL }
958 };
959
960 static const mdb_modinfo_t modinfo = {
961 MDB_API_VERSION, dcmds, NULL
962 };
963
964 const mdb_modinfo_t *
_mdb_init(void)965 _mdb_init(void)
966 {
967 return (&modinfo);
968 }
969