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