/* * 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. */ /* * Domain specific portion of the Starcat Management Network Driver */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAN_SCHIZO_BINDING_NAME "pci108e,8001" #define MAN_XMITS_BINDING_NAME "pci108e,8002" int man_is_on_domain = TRUE; /* * Domain side function prototypes. */ int man_get_iosram(manc_t *); int man_domain_configure(void); int man_domain_deconfigure(void); int man_path_discovery(void); int man_dossc_switch(uint32_t); int man_dr_attach(dev_info_t *); int man_dr_detach(dev_info_t *); static int man_dr_submit_work_wait(dev_info_t *, int); static int man_find_devs(mi_path_t *, uchar_t); static int man_dip_is_schizoxmits0_pcib(dev_info_t *, int *, int *); static int man_dip_is_eri(dev_info_t *, man_dev_t *); static int man_dip_is_attached(dev_info_t *); static int man_get_eri_dev_info(dev_info_t *, man_dev_t *); static int man_mbox_initialized = FALSE; /* * Externs */ extern int man_pg_cmd(mi_path_t *, man_work_t *); extern kmutex_t man_lock; extern void *man_softstate; extern man_work_t *man_work_alloc(int, int); extern void man_work_free(man_work_t *); extern void man_work_add(man_workq_t *, man_work_t *); extern man_workq_t *man_bwork_q; extern man_workq_t *man_iwork_q; extern queue_t *man_ctl_wq; #if defined(DEBUG) static void man_print_manc(manc_t *); extern uint32_t man_debug; #endif /* DEBUG */ int man_domain_configure(void) { int status = 0; /* * man_mbox_initialized is protected by inner perimiter lock. */ if (man_mbox_initialized == TRUE) goto exit; status = mboxsc_init(IOSRAM_KEY_SCMD, MBOXSC_MBOX_IN, NULL); if (status != 0) { cmn_err(CE_WARN, "man_domain_configure: failed to initialize" " MBOXSC_MBOX_IN, errno = %d", status); goto exit; } status = mboxsc_init(IOSRAM_KEY_MDSC, MBOXSC_MBOX_OUT, NULL); if (status != 0) { (void) mboxsc_fini(IOSRAM_KEY_SCMD); cmn_err(CE_WARN, "man_domain_configure: failed to initialize" " MBOXSC_MBOX_OUT, errno = %d", status); goto exit; } man_mbox_initialized = TRUE; status = man_path_discovery(); if (status != 0) { (void) mboxsc_fini(IOSRAM_KEY_SCMD); (void) mboxsc_fini(IOSRAM_KEY_MDSC); man_mbox_initialized = FALSE; } exit: return (status); } /* * Build pathgroup connecting a domain to the SSC. Only called on domains * at first man_open. On the SSC, pathgroups are built by IOCTL requests * from the MAN daemon (see man_ioctl and mand(1M)). * * Locks held * - exclusive innerperim. */ int man_path_discovery(void) { manc_t manc; mi_path_t mpath; int num_devs; int status = 0; int i; MAN_DBG(MAN_CONFIG, ("man_path_discovery:")); if (status = man_get_iosram(&manc)) { goto exit; } /* * If manc_ip_type indicates MAN network is not enabled * for this domain, then lets just bailout from here as if no * devices were found. */ if ((manc.manc_ip_type != AF_INET) && (manc.manc_ip_type != AF_INET6)) { goto exit; } MAN_DBGCALL(MAN_CONFIG, man_print_manc(&manc)); /* * Extract SC ethernet address from IOSRAM. */ ether_copy(&manc.manc_sc_eaddr, &mpath.mip_eaddr); mpath.mip_pg_id = 0; /* SC is always pathgroup ID 0 */ mpath.mip_man_ppa = 0; /* Domain only has one ppa, 0 */ /* * Get list of present devices, and update man_paths[] as needed. */ num_devs = man_find_devs(&mpath, MAN_MAX_EXPANDERS); if (num_devs <= 0) { status = ENODEV; goto exit; } mpath.mip_cmd = MI_PATH_ASSIGN; mutex_enter(&man_lock); status = man_pg_cmd(&mpath, NULL); if (status) { mutex_exit(&man_lock); goto exit; } /* * Now activate the ethernet on the golden io board. */ for (i = 0; i < num_devs; i++) { if (mpath.mip_devs[i].mdev_exp_id == manc.manc_golden_iob) mpath.mip_devs[0] = mpath.mip_devs[i]; } mpath.mip_ndevs = 1; mpath.mip_cmd = MI_PATH_ACTIVATE; status = man_pg_cmd(&mpath, NULL); mutex_exit(&man_lock); exit: MAN_DBG(MAN_CONFIG, ("man_path_discovery: returns %d\n", status)); return (status); } int man_domain_deconfigure(void) { (void) mboxsc_fini(IOSRAM_KEY_SCMD); (void) mboxsc_fini(IOSRAM_KEY_MDSC); /* * We are about to unload and know that there are no open * streams, so this change outside of the perimiter is ok. */ man_mbox_initialized = FALSE; return (0); } /* * Add a work request to the inner perimeter with the new eri device info. */ /* ARGSUSED */ int man_dr_attach(dev_info_t *dip) { man_t *manp; man_work_t *wp; int status = 0; man_dev_t mdev; mutex_enter(&man_lock); manp = ddi_get_soft_state(man_softstate, 0); if (manp == NULL || manp->man_pg == NULL) { goto exit; } if (man_get_eri_dev_info(dip, &mdev) == FALSE) { status = ENODEV; goto exit; } MAN_DBG(MAN_DR, ("man_dr_attach: dip major = %d instance =%d", mdev.mdev_major, mdev.mdev_ppa)); wp = man_work_alloc(MAN_WORK_DRATTACH, KM_NOSLEEP); if (wp == NULL) { status = ENOMEM; goto exit; } wp->mw_arg.a_man_ppa = 0; /* Domain only has one ppa, 0 */ wp->mw_arg.a_pg_id = 0; /* SC is always pathgroup ID 0 */ wp->mw_arg.a_sf_dev = mdev; wp->mw_flags = MAN_WFLAGS_NOWAITER; man_work_add(man_iwork_q, wp); if (man_ctl_wq) qenable(man_ctl_wq); exit: mutex_exit(&man_lock); return (status); } int man_dr_detach(dev_info_t *dip) { man_t *manp; int status = 0; int retries = 0; mutex_enter(&man_lock); manp = ddi_get_soft_state(man_softstate, 0); if (manp == NULL || manp->man_pg == NULL) { mutex_exit(&man_lock); goto exit; } mutex_exit(&man_lock); /* * Arrange to have the detaching path switched if it is active. * We will cv_wait_sig for the switch to complete if it is needed. */ again: status = man_dr_submit_work_wait(dip, MAN_WORK_DRSWITCH); if (status == EAGAIN && retries < manp->man_dr_retries) { /* * Delay a bit and retry. */ MAN_DBG(MAN_DR, ("man_dr_detach(switch): EAGAIN - retrying...")); retries++; delay(drv_usectohz(manp->man_dr_delay)); goto again; } if (status) goto exit; retries = 0; /* * Detaching device no longer in use, remove it from our * pathgroup. */ status = man_dr_submit_work_wait(dip, MAN_WORK_DRDETACH); if (status == EAGAIN && retries < manp->man_dr_retries) { MAN_DBG(MAN_DR, ("man_dr_detach(detach): EAGAIN - retrying...")); retries++; goto again; } exit: MAN_DBG(MAN_DR, ("man_dr_detach: returns %d", status)); return (status); } static int man_dr_submit_work_wait(dev_info_t *dip, int work_type) { man_work_t *wp; int status = 0; wp = man_work_alloc(work_type, KM_NOSLEEP); if (wp == NULL) { status = ENOMEM; goto exit; } wp->mw_arg.a_man_ppa = 0; wp->mw_arg.a_pg_id = 0; wp->mw_arg.a_sf_dev.mdev_major = ddi_driver_major(dip); wp->mw_arg.a_sf_dev.mdev_ppa = ddi_get_instance(dip); mutex_enter(&man_lock); wp->mw_flags = MAN_WFLAGS_CVWAITER; man_work_add(man_iwork_q, wp); /* TBD - change to ASSERT ? */ if (man_ctl_wq) qenable(man_ctl_wq); while (!(wp->mw_flags & MAN_WFLAGS_DONE)) { if (!cv_wait_sig(&wp->mw_cv, &man_lock)) { wp->mw_flags &= ~MAN_WFLAGS_CVWAITER; status = EINTR; break; } } /* * Note that if cv_wait_sig() returns zero because a signal * was received, MAN_WFLAGS_DONE may not be set. * This will happen if man_dr_submit_work_wait() reacquires * man_lock before man_iwork() can acquire man_lock just before * signalling its work is complete. * In this case, it is not necessary to call man_work_free() * here because it will be called by man_iwork() because * MAN_WFLAGS_CVWAITER was cleared. * Should man_iwork() obtain man_lock to signal completion, * MAN_WFLAGS_DONE will be set which will ensure man_work_free() * is called here. */ if (wp->mw_flags & MAN_WFLAGS_DONE) { status = wp->mw_status; man_work_free(wp); } mutex_exit(&man_lock); exit: return (status); } /* * Notify SSC of switch request and wait for response. */ int man_dossc_switch(uint32_t exp_id) { uint64_t req_tid; uint32_t req_cmd; uint64_t resp_tid; uint32_t resp_cmd; uint32_t type; man_mbox_msg_t req; man_mbox_msg_t resp; uint32_t length; int status = 0; /* * There should be nothing in inbound mailbox. */ resp_tid = resp_cmd = type = 0; length = sizeof (man_mbox_msg_t); bzero((char *)&resp, sizeof (man_mbox_msg_t)); while (mboxsc_getmsg(IOSRAM_KEY_SCMD, &type, &resp_cmd, &resp_tid, &length, &resp, 0) == 0) { resp_tid = resp_cmd = type = 0; length = sizeof (man_mbox_msg_t); bzero((char *)&resp, sizeof (man_mbox_msg_t)); MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: dumping message")); MAN_DBG(MAN_IOSRAM, ("\tcommand = 0x%x", resp_cmd)); } MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: sending message")); bzero((char *)&req, sizeof (man_mbox_msg_t)); req.mb_status = 0; req.mb_exp_id = exp_id; req_tid = 0; req_cmd = MAN_WORK_SWITCH; status = mboxsc_putmsg(IOSRAM_KEY_MDSC, MBOXSC_MSG_REQUEST, req_cmd, &req_tid, sizeof (man_mbox_msg_t), &req, MAN_IOSRAM_TIMEOUT); if (status != 0) { cmn_err(CE_WARN, "man_dossc_switch: mboxsc_putmsg failed," " errno = %d", status); goto exit; } bzero((char *)&resp, sizeof (man_mbox_msg_t)); resp_tid = type = resp_cmd = 0; length = sizeof (man_mbox_msg_t); status = mboxsc_getmsg(IOSRAM_KEY_SCMD, &type, &resp_cmd, &resp_tid, &length, (void *)&resp, MAN_IOSRAM_TIMEOUT); if (status != 0) { cmn_err(CE_WARN, "man_dossc_switch: mboxsc_getmsg failed," " errno = %d", status); goto exit; } MAN_DBG(MAN_IOSRAM, ("man_dossc_switch: received message")); if (req_cmd != resp_cmd || req_tid != resp_tid) { cmn_err(CE_WARN, "man_dossc_switch: failed," " cmd/transid mismatch (%d, %d)/(%d, %d)", req_cmd, resp_cmd, (int)req_tid, (int)resp_tid); status = EINVAL; goto exit; } status = resp.mb_status; if (status != 0) { cmn_err(CE_WARN, "man_dossc_switch: failed errno == %d", status); } exit: return (status); } /* * Read IOSRAM info. */ int man_get_iosram(manc_t *mcp) { int status; if (mcp == NULL) return (EINVAL); status = iosram_rd(IOSRAM_KEY_MANC, 0, sizeof (manc_t), (caddr_t)mcp); if (status) { cmn_err(CE_WARN, "man_get_iosram: iosram_rd failed" " errno = %d\n", status); return (status); } MAN_DBG(MAN_PATH, ("man_get_iosram:")); MAN_DBGCALL(MAN_PATH, man_print_manc(mcp)); if (mcp->manc_magic != IOSRAM_KEY_MANC) { cmn_err(CE_WARN, "man_get_iosram: bad magic - got(0x%x)" " expected(0x%x)\n", mcp->manc_magic, IOSRAM_KEY_MANC); status = EIO; } else if (mcp->manc_version != MANC_VERSION) { cmn_err(CE_WARN, "man_get_iosram: version mismatch -" " got(0x%x) expected(0x%x)\n", mcp->manc_version, MANC_VERSION); status = EIO; } return (status); } #if defined(MAN_NO_IOSRAM) static manc_t manc = { IOSRAM_KEY_MANC, MANC_VERSION, 0, AF_INET, /* 0x10010102, Two */ 0x10010103, /* Scot */ 0xFF000000, /* Scot netmask */ 0x10010101, /* SC 10.1.1.1 */ {0}, /* AF_INET6 addrs */ {0}, /* AF_INET6 addrs */ {0}, /* {0x8, 0x0, 0x20, 0x21, 0x44, 0x83}, Domain eaddr "two" */ {0x8, 0x0, 0x20, 0x8f, 0x84, 0x63}, /* Domain eaddr "scot" */ {0x8, 0x0, 0x20, 0x1f, 0xe3, 0x46}, /* SC eaddr "one" */ 0x1, 0x1 }; /* * Get IOSRAM info or release it. */ int man_get_iosram(manc_t *mcp) { int status = 0; if (mcp == NULL) return (EINVAL); *mcp = manc; if (mcp->manc_magic != IOSRAM_KEY_MANC) { cmn_err(CE_WARN, "man_get_iosram: bad magic - got(0x%x)" " expected(0x%x)\n", mcp->manc_magic, IOSRAM_KEY_MANC); status = EIO; } else if (mcp->manc_version != MANC_VERSION) { cmn_err(CE_WARN, "man_get_iosram: version mismatch -" " got(0x%x) expected(0x%x)\n", mcp->manc_version, MANC_VERSION); status = EIO; } return (status); } #endif /* MAN_NO_IOSRAM */ /* * Find all RIOs on the IO boards for the domain. We walk all the children * of the root node looking for a PCI devinfo with a safari port ID of * 0xDC that has a child with device ID of 3. This is gauranteed to be * the network portion of the RIO by virtue of the way Starcats are * physically built. */ static int man_find_devs(mi_path_t *mipathp, uchar_t golden_iob) { dev_info_t *bus_dip; dev_info_t *eri_dip; dev_info_t *rdip, *pdip; int exp_id; int found = 0; int circ; int circ2; man_dev_t ndev; int xmits; MAN_DBG(MAN_PATH, ("man_find_devs: mdevpp(0x%p) golden_iob(%d)\n", (void *)(mipathp), golden_iob)); /* * Hold parent busy while walking its child list. */ rdip = ddi_root_node(); ndi_devi_enter(rdip, &circ); bus_dip = ddi_get_child(rdip); while (bus_dip != NULL) { exp_id = -1; xmits = 0; if (man_dip_is_schizoxmits0_pcib(bus_dip, &exp_id, &xmits)) { eri_dip = NULL; pdip = bus_dip; if (xmits) { /* * If this is XMITS0 PCI_B leaf, then the * pci_pci bridge which is the only child, * is the parent to MAN RIO. */ pdip = ddi_get_child(bus_dip); if (pdip == NULL) { bus_dip = ddi_get_next_sibling(bus_dip); continue; } } ndi_devi_enter(pdip, &circ2); eri_dip = ddi_get_child(pdip); while (eri_dip != NULL) { MAN_DBG(MAN_PATH, ("man_find_devs: " "eri_dip %s\n", ddi_binding_name(eri_dip))); if (man_dip_is_eri(eri_dip, &ndev) && man_dip_is_attached(eri_dip)) { ASSERT(exp_id != -1); ndev.mdev_exp_id = exp_id; ndev.mdev_state = MDEV_ASSIGNED; mipathp->mip_devs[found] = ndev; found++; MAN_DBG(MAN_PATH, ("man_find_devs: found eri maj(%d) " "ppa(%d) on expander(%d)\n", ndev.mdev_major, ndev.mdev_ppa, exp_id)); } eri_dip = ddi_get_next_sibling(eri_dip); } ndi_devi_exit(pdip, circ2); } bus_dip = ddi_get_next_sibling(bus_dip); } ndi_devi_exit(rdip, circ); MAN_DBG(MAN_PATH, ("man_find_devs returns found = %d\n", found)); mipathp->mip_ndevs = found; return (found); } /* * Verify if the dip passed is an instance of 'eri' and set * the device info in mdevp. */ static int man_get_eri_dev_info(dev_info_t *dip, man_dev_t *mdevp) { dev_info_t *parent_dip; int exp_id; int xmits; char *name; ASSERT(dip != NULL); /* * Verify if the parent is schizo(xmits)0 and pci B leaf. */ if (((parent_dip = ddi_get_parent(dip)) == NULL) || ((name = ddi_binding_name(parent_dip)) == NULL)) return (FALSE); if (strcmp(name, MAN_SCHIZO_BINDING_NAME) != 0) { /* * This RIO could be on XMITS, so get the dip to * XMITS PCI Leaf. */ if ((parent_dip = ddi_get_parent(parent_dip)) == NULL) return (FALSE); if (((name = ddi_binding_name(parent_dip)) == NULL) || (strcmp(name, MAN_XMITS_BINDING_NAME) != 0)) { return (FALSE); } } if (man_dip_is_schizoxmits0_pcib(parent_dip, &exp_id, &xmits) == FALSE) return (FALSE); /* * Make sure it is attached. */ if (man_dip_is_attached(dip) == FALSE) { MAN_DBG(MAN_DR, ("man_get_eri_dev_info: " "dip 0x%p not attached\n", (void *)dip)); return (FALSE); } mdevp->mdev_exp_id = exp_id; mdevp->mdev_ppa = ddi_get_instance(dip); mdevp->mdev_major = ddi_driver_major(dip); mdevp->mdev_state = MDEV_ASSIGNED; return (TRUE); } /* * MAN RIO is connected to SCHIZO/XMITS 0 and PCI_B Leaf. * Incase of XMITS, it is actually connected to a PCI Bridge(21154) * which is directly connected to the PCI_B leaf of XMITS0. * * This function verifies if the given dip is SCHIZO/XMITS 0 and * PCI_B Leaf. This is done as follows: * * - Check the binding name to verify SCHIZO/XMITS. * - Verify the Device type to be "pci". * - Verify the PortID to be ending with 0x1C * - Verify the the CSR base to be 0x70.0000. */ static int man_dip_is_schizoxmits0_pcib(dev_info_t *dip, int *exp_id, int *xmits) { char dtype[MAN_DDI_BUFLEN]; int portid; uint_t pci_csr_base; struct pci_phys_spec *regbuf = NULL; int length = MAN_DDI_BUFLEN; char *name; ASSERT(dip != NULL); *exp_id = -1; if ((name = ddi_binding_name(dip)) == NULL) return (FALSE); if (strcmp(name, MAN_SCHIZO_BINDING_NAME) == 0) { MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib: " "SCHIZO found 0x%p\n", (void *)dip)); } else if (strcmp(name, MAN_XMITS_BINDING_NAME) == 0) { *xmits = TRUE; MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib: " "XMITS found 0x%p\n", (void *)dip)); } else return (FALSE); if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, MAN_DEVTYPE_PROP, (caddr_t)dtype, &length) == DDI_PROP_SUCCESS) { MAN_DBG(MAN_PATH, ("dtype: %s\n", dtype)); if (strncmp(dtype, MAN_DEVTYPE_PCI, 3) != 0) goto notfound; /* * Get safari ID (DDI port ID). */ if ((portid = (int)ddi_getprop(DDI_DEV_T_ANY, dip, 0, MAN_PORTID_PROP, -1)) == -1) { MAN_DBG(MAN_PATH, ("ddi_getpropp: failed\n")); goto notfound; } /* * All schizo 0 safari IDs end in 0x1C. */ if ((portid & MAN_SCHIZO_MASK) != MAN_SCHIZO_0_ID) goto notfound; /* * All PCI nodes "B" are at configspace 0x70.0000 */ if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, MAN_REG_PROP, (caddr_t)®buf, &length) != DDI_PROP_SUCCESS) { MAN_DBG(MAN_PATH, ("ddi_getlongprop_buf: failed")); goto notfound; } pci_csr_base = regbuf[0].pci_phys_mid & PCI_CONF_ADDR_MASK; kmem_free(regbuf, length); if (pci_csr_base == MAN_PCI_B_CSR_BASE) { MAN_DBG(MAN_PATH, ("man_dip_is_schizoxmits0_pcib:" " found PCI B at dip(0x%p)\n", (void *)dip)); *exp_id = portid >> 5; return (TRUE); } } notfound: return (FALSE); } static int man_dip_is_eri(dev_info_t *dip, man_dev_t *ndevp) { struct pci_phys_spec *regbuf = NULL; int length = 0; uint_t pci_device; uint_t pci_function; MAN_DBG(MAN_PATH, ("man_dip_is_eri: dip(0x%p) ndevp(0x%p)\n", (void *)dip, (void *)ndevp)); if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, MAN_REG_PROP, (caddr_t)®buf, &length) == DDI_PROP_SUCCESS) { pci_device = PCI_REG_DEV_G(regbuf->pci_phys_hi); pci_function = PCI_REG_FUNC_G(regbuf->pci_phys_hi); kmem_free(regbuf, length); /* * The network function of the RIO ASIC will always * be device 3 and function 1 ("network@3,1"). */ if (pci_device == 3 && pci_function == 1) { ndevp->mdev_ppa = ddi_get_instance(dip); ndevp->mdev_major = ddi_driver_major(dip); MAN_DBG(MAN_PATH, ("man_dip_is_eri: found eri maj(%d)" " ppa(%d)\n", ndevp->mdev_major, ndevp->mdev_ppa)); return (TRUE); } } MAN_DBG(MAN_PATH, ("man_dip_is_eri: returns FALSE\n")); return (FALSE); } static int man_dip_is_attached(dev_info_t *dip) { int state; state = ddi_get_devstate(dip); if (i_ddi_devi_attached(dip) || (state == DDI_DEVSTATE_UP)) { /* * The instance info is more important for us, * so verify. */ if (ddi_get_instance(dip) >= 0) { return (TRUE); } cmn_err(CE_WARN, "man_dip_is_attached: " "eri 0x%p instance is not set yet", (void *)dip); } return (FALSE); } #if defined(DEBUG) static void man_print_manc(manc_t *mcp) { cmn_err(CE_CONT, "\tmcp(0x%p)\n\n", (void *)mcp); if (mcp == NULL) return; cmn_err(CE_CONT, "\tmagic: 0x%x\n", mcp->manc_magic); cmn_err(CE_CONT, "\tversion: 0x%x\n", mcp->manc_version); cmn_err(CE_CONT, "\tcsum: %d\n", mcp->manc_csum); cmn_err(CE_CONT, "\tdom_eaddr: %s\n", ether_sprintf(&mcp->manc_dom_eaddr)); cmn_err(CE_CONT, "\tsc_eaddr: %s\n", ether_sprintf(&mcp->manc_sc_eaddr)); cmn_err(CE_CONT, "\tiob_bitmap: 0x%x\n", mcp->manc_iob_bitmap); cmn_err(CE_CONT, "\tgolden_iob: %d\n", mcp->manc_golden_iob); } #endif /* DEBUG */