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