/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #pragma pack(1) #include #include #include #include #include #include #include #include #pragma pack() #include struct { int value; char *text; } devinfo_array[] = { { MPI2_SAS_DEVICE_INFO_SEP, "SEP" }, { MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE, "ATAPI device" }, { MPI2_SAS_DEVICE_INFO_LSI_DEVICE, "LSI device" }, { MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH, "direct attach" }, { MPI2_SAS_DEVICE_INFO_SSP_TARGET, "SSP tgt" }, { MPI2_SAS_DEVICE_INFO_STP_TARGET, "STP tgt" }, { MPI2_SAS_DEVICE_INFO_SMP_TARGET, "SMP tgt" }, { MPI2_SAS_DEVICE_INFO_SATA_DEVICE, "SATA dev" }, { MPI2_SAS_DEVICE_INFO_SSP_INITIATOR, "SSP init" }, { MPI2_SAS_DEVICE_INFO_STP_INITIATOR, "STP init" }, { MPI2_SAS_DEVICE_INFO_SMP_INITIATOR, "SMP init" }, { MPI2_SAS_DEVICE_INFO_SATA_HOST, "SATA host" } }; static int atoi(const char *p) { int n; int c = *p++; for (n = 0; c >= '0' && c <= '9'; c = *p++) { n *= 10; /* two steps to avoid unnecessary overflow */ n += '0' - c; /* accum neg to avoid surprises at MAX */ } return (-n); } int construct_path(uintptr_t addr, char *result) { struct dev_info d; char devi_node[PATH_MAX]; char devi_addr[PATH_MAX]; if (mdb_vread(&d, sizeof (d), addr) == -1) { mdb_warn("couldn't read dev_info"); return (DCMD_ERR); } if (d.devi_parent) { construct_path((uintptr_t)d.devi_parent, result); mdb_readstr(devi_node, sizeof (devi_node), (uintptr_t)d.devi_node_name); mdb_readstr(devi_addr, sizeof (devi_addr), (uintptr_t)d.devi_addr); mdb_snprintf(result+strlen(result), PATH_MAX-strlen(result), "/%s%s%s", devi_node, (*devi_addr ? "@" : ""), devi_addr); } return (DCMD_OK); } /* ARGSUSED */ int mdi_info_cb(uintptr_t addr, const void *data, void *cbdata) { struct mdi_pathinfo pi; struct mdi_client c; char dev_path[PATH_MAX]; char string[PATH_MAX]; int mdi_target = 0, mdi_lun = 0; int target = *(int *)cbdata; if (mdb_vread(&pi, sizeof (pi), addr) == -1) { mdb_warn("couldn't read mdi_pathinfo"); return (DCMD_ERR); } mdb_readstr(string, sizeof (string), (uintptr_t)pi.pi_addr); mdi_target = atoi(string); mdi_lun = atoi(strchr(string, ',')+1); if (target != mdi_target) return (0); if (mdb_vread(&c, sizeof (c), (uintptr_t)pi.pi_client) == -1) { mdb_warn("couldn't read mdi_client"); return (-1); } *dev_path = NULL; if (construct_path((uintptr_t)c.ct_dip, dev_path) != DCMD_OK) strcpy(dev_path, "unknown"); mdb_printf("LUN %d: %s\n", mdi_lun, dev_path); mdb_printf(" dip: %p %s path", c.ct_dip, (pi.pi_preferred ? "preferred" : "")); switch (pi.pi_state & MDI_PATHINFO_STATE_MASK) { case MDI_PATHINFO_STATE_INIT: mdb_printf(" initializing"); break; case MDI_PATHINFO_STATE_ONLINE: mdb_printf(" online"); break; case MDI_PATHINFO_STATE_STANDBY: mdb_printf(" standby"); break; case MDI_PATHINFO_STATE_FAULT: mdb_printf(" fault"); break; case MDI_PATHINFO_STATE_OFFLINE: mdb_printf(" offline"); break; default: mdb_printf(" invalid state"); break; } mdb_printf("\n"); return (0); } void mdi_info(struct mptsas m, int target) { struct dev_info d; struct mdi_phci p; if (mdb_vread(&d, sizeof (d), (uintptr_t)m.m_dip) == -1) { mdb_warn("couldn't read m_dip"); return; } if (MDI_PHCI(&d)) { if (mdb_vread(&p, sizeof (p), (uintptr_t)d.devi_mdi_xhci) == -1) { mdb_warn("couldn't read m_dip.devi_mdi_xhci"); return; } if (p.ph_path_head) mdb_pwalk("mdipi_phci_list", (mdb_walk_cb_t)mdi_info_cb, &target, (uintptr_t)p.ph_path_head); return; } } void print_cdb(mptsas_cmd_t *m) { struct scsi_pkt pkt; uchar_t cdb[512]; /* an arbitrarily large number */ int j; if (mdb_vread(&pkt, sizeof (pkt), (uintptr_t)m->cmd_pkt) == -1) { mdb_warn("couldn't read cmd_pkt"); return; } /* * We use cmd_cdblen here because 5.10 doesn't * have the cdb length in the pkt */ if (mdb_vread(&cdb, m->cmd_cdblen, (uintptr_t)pkt.pkt_cdbp) == -1) { mdb_warn("couldn't read pkt_cdbp"); return; } mdb_printf("%3d,%-3d [ ", pkt.pkt_address.a_target, pkt.pkt_address.a_lun); for (j = 0; j < m->cmd_cdblen; j++) mdb_printf("%02x ", cdb[j]); mdb_printf("]\n"); } void display_ports(struct mptsas m) { int i; mdb_printf("\n"); mdb_printf("phy number and port mapping table\n"); for (i = 0; i < MPTSAS_MAX_PHYS; i++) { if (m.m_phy_info[i].attached_devhdl) { mdb_printf("phy %x --> port %x, phymask %x," "attached_devhdl %x\n", i, m.m_phy_info[i].port_num, m.m_phy_info[i].phy_mask, m.m_phy_info[i].attached_devhdl); } } mdb_printf("\n"); } static void * hash_traverse(mptsas_hash_table_t *hashtab, int pos, int alloc_size) { mptsas_hash_node_t *this = NULL; mptsas_hash_node_t h; void *ret = NULL; if (pos == MPTSAS_HASH_FIRST) { hashtab->line = 0; hashtab->cur = NULL; this = hashtab->head[0]; } else { if (hashtab->cur == NULL) { return (NULL); } else { mdb_vread(&h, sizeof (h), (uintptr_t)hashtab->cur); this = h.next; } } while (this == NULL) { hashtab->line++; if (hashtab->line >= MPTSAS_HASH_ARRAY_SIZE) { /* the traverse reaches the end */ hashtab->cur = NULL; return (NULL); } else { this = hashtab->head[hashtab->line]; } } hashtab->cur = this; if (mdb_vread(&h, sizeof (h), (uintptr_t)this) == -1) { mdb_warn("couldn't read hashtab"); return (NULL); } ret = mdb_alloc(alloc_size, UM_SLEEP); if (mdb_vread(ret, alloc_size, (uintptr_t)h.data) == -1) { mdb_warn("couldn't read hashdata"); return (NULL); } return (ret); } void display_targets(struct mptsas_slots *s) { mptsas_target_t *ptgt; mptsas_smp_t *psmp; mdb_printf("\n"); mdb_printf("The SCSI target information\n"); ptgt = (mptsas_target_t *)hash_traverse(&s->m_tgttbl, MPTSAS_HASH_FIRST, sizeof (mptsas_target_t)); while (ptgt != NULL) { mdb_printf("\n"); mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x," "devinfo %x\n", ptgt->m_devhdl, ptgt->m_sas_wwn, ptgt->m_phymask, ptgt->m_deviceinfo); mdb_printf("throttle %x, dr_flag %x, m_t_ncmds %x\n", ptgt->m_t_throttle, ptgt->m_dr_flag, ptgt->m_t_ncmds); mdb_free(ptgt, sizeof (mptsas_target_t)); ptgt = (mptsas_target_t *)hash_traverse( &s->m_tgttbl, MPTSAS_HASH_NEXT, sizeof (mptsas_target_t)); } mdb_printf("\n"); mdb_printf("The smp child information\n"); psmp = (mptsas_smp_t *)hash_traverse(&s->m_smptbl, MPTSAS_HASH_FIRST, sizeof (mptsas_smp_t)); while (psmp != NULL) { mdb_printf("\n"); mdb_printf("devhdl %x, sasaddress %"PRIx64", phymask %x \n", psmp->m_devhdl, psmp->m_sasaddr, psmp->m_phymask); mdb_free(psmp, sizeof (mptsas_smp_t)); psmp = (mptsas_smp_t *)hash_traverse( &s->m_smptbl, MPTSAS_HASH_NEXT, sizeof (mptsas_smp_t)); } mdb_printf("\n"); #if 0 mdb_printf("targ wwn ncmds throttle " "dr_flag timeout dups\n"); mdb_printf("-------------------------------" "--------------------------------\n"); for (i = 0; i < MPTSAS_MAX_TARGETS; i++) { if (s->m_target[i].m_sas_wwn || s->m_target[i].m_deviceinfo) { mdb_printf("%4d ", i); if (s->m_target[i].m_sas_wwn) mdb_printf("%"PRIx64" ", s->m_target[i].m_sas_wwn); mdb_printf("%3d", s->m_target[i].m_t_ncmds); switch (s->m_target[i].m_t_throttle) { case QFULL_THROTTLE: mdb_printf(" QFULL "); break; case DRAIN_THROTTLE: mdb_printf(" DRAIN "); break; case HOLD_THROTTLE: mdb_printf(" HOLD "); break; case MAX_THROTTLE: mdb_printf(" MAX "); break; case CHOKE_THROTTLE: mdb_printf(" CHOKE "); break; default: mdb_printf("%8d ", s->m_target[i].m_t_throttle); } switch (s->m_target[i].m_dr_flag) { case MPTSAS_DR_INACTIVE: mdb_printf(" INACTIVE "); break; case MPTSAS_DR_PRE_OFFLINE_TIMEOUT: mdb_printf(" TIMEOUT "); break; case MPTSAS_DR_PRE_OFFLINE_TIMEOUT_NO_CANCEL: mdb_printf("TIMEOUT_NC "); break; case MPTSAS_DR_OFFLINE_IN_PROGRESS: mdb_printf(" OFFLINING "); break; case MPTSAS_DR_ONLINE_IN_PROGRESS: mdb_printf(" ONLINING "); break; default: mdb_printf(" UNKNOWN "); break; } mdb_printf("%3d/%-3d %d/%d\n", s->m_target[i].m_dr_timeout, m.m_offline_delay, s->m_target[i].m_dr_online_dups, s->m_target[i].m_dr_offline_dups); if (verbose) { mdb_inc_indent(5); if ((s->m_target[i].m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) mdb_printf("Fanout expander: "); if ((s->m_target[i].m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER) mdb_printf("Edge expander: "); if ((s->m_target[i].m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == MPI2_SAS_DEVICE_INFO_END_DEVICE) mdb_printf("End device: "); if ((s->m_target[i].m_deviceinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == MPI2_SAS_DEVICE_INFO_NO_DEVICE) mdb_printf("No device "); for (loop = 0, comma = 0; loop < (sizeof (devinfo_array) / sizeof (devinfo_array[0])); loop++) { if (s->m_target[i].m_deviceinfo & devinfo_array[loop].value) { mdb_printf("%s%s", (comma ? ", " : ""), devinfo_array[loop].text); comma++; } } mdb_printf("\n"); if (s->m_target[i].m_tgt_dip) { *target_path = 0; if (construct_path((uintptr_t) s->m_target[i].m_tgt_dip, target_path) == DCMD_OK) mdb_printf("%s\n", target_path); } mdi_info(m, i); mdb_dec_indent(5); } } } #endif } int display_slotinfo() { #if 0 int i, nslots; struct mptsas_cmd c, *q, *slots; int header_output = 0; int rv = DCMD_OK; int slots_in_use = 0; int tcmds = 0; int mismatch = 0; int wq, dq; int ncmds = 0; ulong_t saved_indent; nslots = s->m_n_slots; slots = mdb_alloc(sizeof (mptsas_cmd_t) * nslots, UM_SLEEP); for (i = 0; i < nslots; i++) if (s->m_slot[i]) { slots_in_use++; if (mdb_vread(&slots[i], sizeof (mptsas_cmd_t), (uintptr_t)s->m_slot[i]) == -1) { mdb_warn("couldn't read slot"); s->m_slot[i] = NULL; } if ((slots[i].cmd_flags & CFLAG_CMDIOC) == 0) tcmds++; if (i != slots[i].cmd_slot) mismatch++; } for (q = m.m_waitq, wq = 0; q; q = c.cmd_linkp, wq++) if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) { mdb_warn("couldn't follow m_waitq"); rv = DCMD_ERR; goto exit; } for (q = m.m_doneq, dq = 0; q; q = c.cmd_linkp, dq++) if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) { mdb_warn("couldn't follow m_doneq"); rv = DCMD_ERR; goto exit; } for (i = 0; i < MPTSAS_MAX_TARGETS; i++) ncmds += s->m_target[i].m_t_ncmds; mdb_printf("\n"); mdb_printf(" mpt. slot mptsas_slots slot"); mdb_printf("\n"); mdb_printf("m_ncmds total" " targ throttle m_t_ncmds targ_tot wq dq"); mdb_printf("\n"); mdb_printf("----------------------------------------------------"); mdb_printf("\n"); mdb_printf("%7d ", m.m_ncmds); mdb_printf("%s", (m.m_ncmds == slots_in_use ? " " : "!=")); mdb_printf("%3d total %3d ", slots_in_use, ncmds); mdb_printf("%s", (tcmds == ncmds ? " " : " !=")); mdb_printf("%3d %2d %2d\n", tcmds, wq, dq); saved_indent = mdb_dec_indent(0); mdb_dec_indent(saved_indent); for (i = 0; i < s->m_n_slots; i++) if (s->m_slot[i]) { if (!header_output) { mdb_printf("\n"); mdb_printf("mptsas_cmd slot cmd_slot " "cmd_flags cmd_pkt_flags scsi_pkt " " targ,lun [ pkt_cdbp ...\n"); mdb_printf("-------------------------------" "--------------------------------------" "--------------------------------------" "------\n"); header_output = 1; } mdb_printf("%16p %4d %s %4d %8x %8x %16p ", s->m_slot[i], i, (i == slots[i].cmd_slot?" ":"BAD"), slots[i].cmd_slot, slots[i].cmd_flags, slots[i].cmd_pkt_flags, slots[i].cmd_pkt); (void) print_cdb(&slots[i]); } /* print the wait queue */ for (q = m.m_waitq; q; q = c.cmd_linkp) { if (q == m.m_waitq) mdb_printf("\n"); if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) { mdb_warn("couldn't follow m_waitq"); rv = DCMD_ERR; goto exit; } mdb_printf("%16p wait n/a %4d %8x %8x %16p ", q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags, c.cmd_pkt); print_cdb(&c); } /* print the done queue */ for (q = m.m_doneq; q; q = c.cmd_linkp) { if (q == m.m_doneq) mdb_printf("\n"); if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) { mdb_warn("couldn't follow m_doneq"); rv = DCMD_ERR; goto exit; } mdb_printf("%16p done n/a %4d %8x %8x %16p ", q, c.cmd_slot, c.cmd_flags, c.cmd_pkt_flags, c.cmd_pkt); print_cdb(&c); } mdb_inc_indent(saved_indent); if (m.m_ncmds != slots_in_use) mdb_printf("WARNING: mpt.m_ncmds does not match the number of " "slots in use\n"); if (tcmds != ncmds) mdb_printf("WARNING: the total of m_target[].m_t_ncmds does " "not match the slots in use\n"); if (mismatch) mdb_printf("WARNING: corruption in slot table, " "m_slot[].cmd_slot incorrect\n"); /* now check for corruptions */ for (q = m.m_waitq; q; q = c.cmd_linkp) { for (i = 0; i < nslots; i++) if (s->m_slot[i] == q) mdb_printf("WARNING: m_waitq entry" "(mptsas_cmd_t) %p is in m_slot[%i]\n", q, i); if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) { mdb_warn("couldn't follow m_waitq"); rv = DCMD_ERR; goto exit; } } for (q = m.m_doneq; q; q = c.cmd_linkp) { for (i = 0; i < nslots; i++) if (s->m_slot[i] == q) mdb_printf("WARNING: m_doneq entry " "(mptsas_cmd_t) %p is in m_slot[%i]\n", q, i); if (mdb_vread(&c, sizeof (mptsas_cmd_t), (uintptr_t)q) == -1) { mdb_warn("couldn't follow m_doneq"); rv = DCMD_ERR; goto exit; } if ((c.cmd_flags & CFLAG_FINISHED) == 0) mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p " "should have CFLAG_FINISHED set\n", q); if (c.cmd_flags & CFLAG_IN_TRANSPORT) mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p " "should not have CFLAG_IN_TRANSPORT set\n", q); if (c.cmd_flags & CFLAG_CMDARQ) mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p " "should not have CFLAG_CMDARQ set\n", q); if (c.cmd_flags & CFLAG_COMPLETED) mdb_printf("WARNING: m_doneq entry (mptsas_cmd_t) %p " "should not have CFLAG_COMPLETED set\n", q); } exit: mdb_free(slots, sizeof (mptsas_cmd_t) * nslots); return (rv); #endif mdb_printf("\n"); mdb_printf("The slot information is not implemented yet\n"); return (0); } void display_deviceinfo(struct mptsas m) { char device_path[PATH_MAX]; *device_path = 0; if (construct_path((uintptr_t)m.m_dip, device_path) != DCMD_OK) { strcpy(device_path, "couldn't determine device path"); } mdb_printf("\n"); mdb_printf("Path in device tree %s\n", device_path); #if 0 mdb_printf("base_wwid phys " "mptid prodid devid revid ssid\n"); mdb_printf("-----------------------------" "----------------------------------\n"); mdb_printf("%"PRIx64" %2d %3d " "0x%04x 0x%04x ", m.un.m_base_wwid, m.m_num_phys, m.m_mptid, m.m_productid, m.m_devid); switch (m.m_devid) { case MPTSAS_909: mdb_printf("(909) "); break; case MPTSAS_929: mdb_printf("(929) "); break; case MPTSAS_919: mdb_printf("(919) "); break; case MPTSAS_1030: mdb_printf("(1030) "); break; case MPTSAS_1064: mdb_printf("(1064) "); break; case MPTSAS_1068: mdb_printf("(1068) "); break; case MPTSAS_1064E: mdb_printf("(1064E) "); break; case MPTSAS_1068E: mdb_printf("(1068E) "); break; default: mdb_printf("(?????) "); break; } mdb_printf("0x%02x 0x%04x\n", m.m_revid, m.m_ssid); mdb_printf("%s\n", device_path); for (i = 0; i < MAX_MPI2_PORTS; i++) { if (i%4 == 0) mdb_printf("\n"); mdb_printf("%d:", i); switch (m.m_port_type[i]) { case MPI2_PORTFACTS_PORTTYPE_INACTIVE: mdb_printf("inactive ", m.m_protocol_flags[i]); break; case MPI2_PORTFACTS_PORTTYPE_SCSI: mdb_printf("SCSI (0x%1x) ", m.m_protocol_flags[i]); break; case MPI2_PORTFACTS_PORTTYPE_FC: mdb_printf("FC (0x%1x) ", m.m_protocol_flags[i]); break; case MPI2_PORTFACTS_PORTTYPE_ISCSI: mdb_printf("iSCSI (0x%1x) ", m.m_protocol_flags[i]); break; case MPI2_PORTFACTS_PORTTYPE_SAS: mdb_printf("SAS (0x%1x) ", m.m_protocol_flags[i]); break; default: mdb_printf("unknown "); } } #endif mdb_printf("\n"); } static int mptsas_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { struct mptsas m; struct mptsas_slots *s; int nslots; int slot_size = 0; uint_t verbose = FALSE; uint_t target_info = FALSE; uint_t slot_info = FALSE; uint_t device_info = FALSE; uint_t port_info = FALSE; int rv = DCMD_OK; void *mptsas_state; if (!(flags & DCMD_ADDRSPEC)) { mptsas_state = NULL; if (mdb_readvar(&mptsas_state, "mptsas_state") == -1) { mdb_warn("can't read mptsas_state"); return (DCMD_ERR); } if (mdb_pwalk_dcmd("genunix`softstate", "mpt_sas`mptsas", argc, argv, (uintptr_t)mptsas_state) == -1) { mdb_warn("mdb_pwalk_dcmd failed"); return (DCMD_ERR); } return (DCMD_OK); } if (mdb_getopts(argc, argv, 's', MDB_OPT_SETBITS, TRUE, &slot_info, 'd', MDB_OPT_SETBITS, TRUE, &device_info, 't', MDB_OPT_SETBITS, TRUE, &target_info, 'p', MDB_OPT_SETBITS, TRUE, &port_info, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc) return (DCMD_USAGE); if (mdb_vread(&m, sizeof (m), addr) == -1) { mdb_warn("couldn't read mpt struct at 0x%p", addr); return (DCMD_ERR); } s = mdb_alloc(sizeof (mptsas_slots_t), UM_SLEEP); if (mdb_vread(s, sizeof (mptsas_slots_t), (uintptr_t)m.m_active) == -1) { mdb_warn("couldn't read small mptsas_slots_t at 0x%p", m.m_active); mdb_free(s, sizeof (mptsas_slots_t)); return (DCMD_ERR); } nslots = s->m_n_slots; mdb_free(s, sizeof (mptsas_slots_t)); slot_size = sizeof (mptsas_slots_t) + (sizeof (mptsas_cmd_t *) * (nslots-1)); s = mdb_alloc(slot_size, UM_SLEEP); if (mdb_vread(s, slot_size, (uintptr_t)m.m_active) == -1) { mdb_warn("couldn't read large mptsas_slots_t at 0x%p", m.m_active); mdb_free(s, slot_size); return (DCMD_ERR); } /* processing completed */ if (((flags & DCMD_ADDRSPEC) && !(flags & DCMD_LOOP)) || (flags & DCMD_LOOPFIRST) || slot_info || device_info || target_info) { if ((flags & DCMD_LOOP) && !(flags & DCMD_LOOPFIRST)) mdb_printf("\n"); mdb_printf(" mptsas_t inst ncmds suspend power"); mdb_printf("\n"); mdb_printf("=========================================" "======================================="); mdb_printf("\n"); } mdb_printf("%16p %4d %5d ", addr, m.m_instance, m.m_ncmds); mdb_printf("%7d", m.m_suspended); switch (m.m_power_level) { case PM_LEVEL_D0: mdb_printf(" ON=D0 "); break; case PM_LEVEL_D1: mdb_printf(" D1 "); break; case PM_LEVEL_D2: mdb_printf(" D2 "); break; case PM_LEVEL_D3: mdb_printf("OFF=D3 "); break; default: mdb_printf("INVALD "); } mdb_printf("\n"); mdb_inc_indent(17); if (target_info) display_targets(s); if (port_info) display_ports(m); if (device_info) display_deviceinfo(m); if (slot_info) display_slotinfo(); mdb_dec_indent(17); mdb_free(s, slot_size); return (rv); } /* * Only -t is implemented now, will add more later when the driver is stable */ void mptsas_help() { mdb_printf("Prints summary information about each mpt_sas instance, " "including warning\nmessages when slot usage doesn't match " "summary information.\n" "Without the address of a \"struct mptsas\", prints every " "instance.\n\n" "Switches:\n" " -t includes information about targets\n" " -p includes information about port\n" " -d includes information about the hardware\n"); } static const mdb_dcmd_t dcmds[] = { { "mptsas", "?[-tpd]", "print mpt_sas information", mptsas_dcmd, mptsas_help}, { NULL } }; static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, NULL }; const mdb_modinfo_t * _mdb_init(void) { return (&modinfo); }