Exemplo n.º 1
0
/*ARGSUSED*/
static void
ppb_init_hotplug(ppb_devstate_t *ppb)
{
	ppb->hotplug_capable = B_FALSE;

	if (ddi_prop_exists(DDI_DEV_T_ANY, ppb->dip, DDI_PROP_DONTPASS,
	    "hotplug-capable")) {
		(void) modload("misc", "pcihp");

		if (pcihp_init(ppb->dip) != DDI_SUCCESS) {
			cmn_err(CE_WARN,
			    "%s #%d: Failed setting hotplug framework",
			    ddi_driver_name(ppb->dip),
			    ddi_get_instance(ppb->dip));
		} else
			ppb->hotplug_capable = B_TRUE;
	}

	if (ppb->hotplug_capable == B_FALSE) {
		/*
		 * create minor node for devctl interfaces
		 */
		if (ddi_create_minor_node(ppb->dip, "devctl", S_IFCHR,
		    PCI_MINOR_NUM(ddi_get_instance(ppb->dip), PCI_DEVCTL_MINOR),
		    DDI_NT_NEXUS, 0) != DDI_SUCCESS)
			cmn_err(CE_WARN,
			    "%s #%d: Failed to create a minor node",
			    ddi_driver_name(ppb->dip),
			    ddi_get_instance(ppb->dip));
	}
}
Exemplo n.º 2
0
static int vboxUSBMonSolarisResetDevice(char *pszDevicePath, bool fReattach)
{
    int rc = VERR_GENERAL_FAILURE;

    LogFunc((DEVICE_NAME ": vboxUSBMonSolarisResetDevice: pszDevicePath=%s fReattach=%d\n", pszDevicePath, fReattach));

    /*
     * Try grabbing the dev_info_t.
     */
    dev_info_t *pDeviceInfo = e_ddi_hold_devi_by_path(pszDevicePath, 0);
    if (pDeviceInfo)
    {
        ddi_release_devi(pDeviceInfo);

        /*
         * Grab the root device node from the parent hub for resetting.
         */
        dev_info_t *pTmpDeviceInfo = NULL;
        for (;;)
        {
            pTmpDeviceInfo = ddi_get_parent(pDeviceInfo);
            if (!pTmpDeviceInfo)
            {
                LogRel((DEVICE_NAME ":vboxUSBMonSolarisResetDevice: Failed to get parent device info for %s\n", pszDevicePath));
                return VERR_GENERAL_FAILURE;
            }

            if (ddi_prop_exists(DDI_DEV_T_ANY, pTmpDeviceInfo, DDI_PROP_DONTPASS, "usb-port-count"))   /* parent hub */
                break;

            pDeviceInfo = pTmpDeviceInfo;
        }

        /*
         * Try re-enumerating the device.
         */
        rc = usb_reset_device(pDeviceInfo, fReattach ? USB_RESET_LVL_REATTACH : USB_RESET_LVL_DEFAULT);
        Log((DEVICE_NAME ": vboxUSBMonSolarisResetDevice: usb_reset_device for %s level=%s rc=%d\n", pszDevicePath,
             fReattach ? "ReAttach" : "Default", rc));

        switch (rc)
        {
            case USB_SUCCESS:         rc = VINF_SUCCESS;                break;
            case USB_INVALID_PERM:    rc = VERR_PERMISSION_DENIED;      break;
            case USB_INVALID_ARGS:    rc = VERR_INVALID_PARAMETER;      break;
            case USB_BUSY:            rc = VERR_RESOURCE_BUSY;          break;
            case USB_INVALID_CONTEXT: rc = VERR_INVALID_CONTEXT;        break;
            case USB_FAILURE:         rc = VERR_GENERAL_FAILURE;        break;

            default:                  rc = VERR_UNRESOLVED_ERROR;       break;
        }
    }
    else
    {
        rc = VERR_INVALID_HANDLE;
        LogRel((DEVICE_NAME ": vboxUSBMonSolarisResetDevice: Cannot obtain device info for %s\n", pszDevicePath));
    }

    return rc;
}
Exemplo n.º 3
0
static int pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
    int flags, char *name, caddr_t valuep, int *lengthp)
{
	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "hotplug-capable"))
		return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip,
		    prop_op, flags, name, valuep, lengthp));

	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
}
Exemplo n.º 4
0
void
reset(void)
{
	extern	void acpi_reset_system();
#if !defined(__xpv)
	ushort_t *bios_memchk;

	/*
	 * Can't use psm_map_phys or acpi_reset_system before the hat is
	 * initialized.
	 */
	if (khat_running) {
		bios_memchk = (ushort_t *)psm_map_phys(0x472,
		    sizeof (ushort_t), PROT_READ | PROT_WRITE);
		if (bios_memchk)
			*bios_memchk = 0x1234;	/* bios memory check disable */

		if (options_dip != NULL &&
		    ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), 0,
		    "efi-systab")) {
			if (bootops == NULL)
				acpi_reset_system();
			efi_reset();
		}

		/*
		 * The problem with using stubs is that we can call
		 * acpi_reset_system only after the kernel is up and running.
		 *
		 * We should create a global state to keep track of how far
		 * up the kernel is but for the time being we will depend on
		 * bootops. bootops cleared in startup_end().
		 */
		if (bootops == NULL)
			acpi_reset_system();
	}

	pc_reset();
#else
	if (IN_XPV_PANIC()) {
		if (khat_running && bootops == NULL) {
			acpi_reset_system();
		}

		pc_reset();
	}

	(void) HYPERVISOR_shutdown(SHUTDOWN_reboot);
	panic("HYPERVISOR_shutdown() failed");
#endif
	/*NOTREACHED*/
}
Exemplo n.º 5
0
void
pcmu_child_cfg_save(dev_info_t *dip)
{
	dev_info_t *cdip;
	int ret = DDI_SUCCESS;

	/*
	 * Save the state of the configuration headers of child
	 * nodes.
	 */

	for (cdip = ddi_get_child(dip); cdip != NULL;
	    cdip = ddi_get_next_sibling(cdip)) {

		/*
		 * Not interested in children who are not already
		 * init'ed.  They will be set up in pcmu_init_child().
		 */
		if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
			PCMU_DBG2(PCMU_DBG_DETACH, dip, "DDI_SUSPEND: skipping "
			    "%s%d not in CF1\n", ddi_driver_name(cdip),
			    ddi_get_instance(cdip));

			continue;
		}

		/*
		 * Only save config registers if not already saved by child.
		 */
		if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
		    SAVED_CONFIG_REGS) == 1) {

			continue;
		}

		/*
		 * The nexus needs to save config registers.  Create a property
		 * so it knows to restore on resume.
		 */
		ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
		    "nexus-saved-config-regs");

		if (ret != DDI_PROP_SUCCESS) {
			cmn_err(CE_WARN, "%s%d can't update prop %s",
			    ddi_driver_name(cdip), ddi_get_instance(cdip),
			    "nexus-saved-config-regs");
		}

		(void) pci_save_config_regs(cdip);
	}
}
Exemplo n.º 6
0
void
pcmu_child_cfg_restore(dev_info_t *dip)
{
	dev_info_t *cdip;

	/*
	 * Restore config registers for children that did not save
	 * their own registers.  Children pwr states are UNKNOWN after
	 * a resume since it is possible for the PM framework to call
	 * resume without an actual power cycle. (ie if suspend fails).
	 */
	for (cdip = ddi_get_child(dip); cdip != NULL;
	    cdip = ddi_get_next_sibling(cdip)) {

		/*
		 * Not interested in children who are not already
		 * init'ed.  They will be set up by pcmu_init_child().
		 */
		if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
			PCMU_DBG2(PCMU_DBG_DETACH, dip,
			    "DDI_RESUME: skipping %s%d not in CF1\n",
			    ddi_driver_name(cdip), ddi_get_instance(cdip));
			continue;
		}

		/*
		 * Only restore config registers if saved by nexus.
		 */
		if (ddi_prop_exists(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
		    "nexus-saved-config-regs") == 1) {
			(void) pci_restore_config_regs(cdip);

			PCMU_DBG2(PCMU_DBG_PWR, dip,
			    "DDI_RESUME: nexus restoring %s%d config regs\n",
			    ddi_driver_name(cdip), ddi_get_instance(cdip));

			if (ndi_prop_remove(DDI_DEV_T_NONE, cdip,
			    "nexus-saved-config-regs") != DDI_PROP_SUCCESS) {
				cmn_err(CE_WARN, "%s%d can't remove prop %s",
				    ddi_driver_name(cdip),
				    ddi_get_instance(cdip),
				    "nexus-saved-config-regs");
			}
		}
	}
}
Exemplo n.º 7
0
/*
 * power management related initialization specific to px
 * called by px_attach()
 */
static int
px_pwr_setup(dev_info_t *dip)
{
	pcie_pwr_t *pwr_p;
	int instance = ddi_get_instance(dip);
	px_t *px_p = INST_TO_STATE(instance);
	ddi_intr_handle_impl_t hdl;

	ASSERT(PCIE_PMINFO(dip));
	pwr_p = PCIE_NEXUS_PMINFO(dip);
	ASSERT(pwr_p);

	/*
	 * indicate support LDI (Layered Driver Interface)
	 * Create the property, if it is not already there
	 */
	if (!ddi_prop_exists(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
	    DDI_KERNEL_IOCTL)) {
		if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
		    DDI_KERNEL_IOCTL, NULL, 0) != DDI_PROP_SUCCESS) {
			DBG(DBG_PWR, dip, "can't create kernel ioctl prop\n");
			return (DDI_FAILURE);
		}
	}
	/* No support for device PM. We are always at full power */
	pwr_p->pwr_func_lvl = PM_LEVEL_D0;

	mutex_init(&px_p->px_l23ready_lock, NULL, MUTEX_DRIVER,
	    DDI_INTR_PRI(px_pwr_pil));
	cv_init(&px_p->px_l23ready_cv, NULL, CV_DRIVER, NULL);

	/* Initialize handle */
	bzero(&hdl, sizeof (ddi_intr_handle_impl_t));
	hdl.ih_cb_arg1 = px_p;
	hdl.ih_ver = DDI_INTR_VERSION;
	hdl.ih_state = DDI_IHDL_STATE_ALLOC;
	hdl.ih_dip = dip;
	hdl.ih_pri = px_pwr_pil;

	/* Add PME_TO_ACK message handler */
	hdl.ih_cb_func = (ddi_intr_handler_t *)px_pmeq_intr;
	if (px_add_msiq_intr(dip, dip, &hdl, MSG_REC,
	    (msgcode_t)PCIE_PME_ACK_MSG, -1,
	    &px_p->px_pm_msiq_id) != DDI_SUCCESS) {
		DBG(DBG_PWR, dip, "px_pwr_setup: couldn't add "
		    " PME_TO_ACK intr\n");
		goto pwr_setup_err1;
	}
	px_lib_msg_setmsiq(dip, PCIE_PME_ACK_MSG, px_p->px_pm_msiq_id);
	px_lib_msg_setvalid(dip, PCIE_PME_ACK_MSG, PCIE_MSG_VALID);

	if (px_ib_update_intr_state(px_p, px_p->px_dip, hdl.ih_inum,
	    px_msiqid_to_devino(px_p, px_p->px_pm_msiq_id), px_pwr_pil,
	    PX_INTR_STATE_ENABLE, MSG_REC, PCIE_PME_ACK_MSG) != DDI_SUCCESS) {
		DBG(DBG_PWR, dip, "px_pwr_setup: PME_TO_ACK update interrupt"
		    " state failed\n");
		goto px_pwrsetup_err_state;
	}

	return (DDI_SUCCESS);

px_pwrsetup_err_state:
	px_lib_msg_setvalid(dip, PCIE_PME_ACK_MSG, PCIE_MSG_INVALID);
	(void) px_rem_msiq_intr(dip, dip, &hdl, MSG_REC, PCIE_PME_ACK_MSG,
	    px_p->px_pm_msiq_id);
pwr_setup_err1:
	mutex_destroy(&px_p->px_l23ready_lock);
	cv_destroy(&px_p->px_l23ready_cv);

	return (DDI_FAILURE);
}
Exemplo n.º 8
0
/*
 * Controller specific initialization
 */
uint_t
sil3xxx_init_controller(dev_info_t *dip,
	/* LINTED */
	ushort_t vendor_id, ushort_t device_id)
{
	ddi_acc_handle_t  pci_conf_handle; /* pci config space handle */
	uint8_t cache_lnsz, frrc = 0;
	uint32_t fifo_cnt_ctl;
	int ports, i;

#ifdef	DEBUG
	/* LINTED */
	ushort_t sfiscfg_val;
#endif

	/*
	 * Sil3114, Sil3512, Sil3112
	 * We want to perform this initialization only once per entire
	 * pciide controller (all channels)
	 */
	if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_get_parent(dip),
		DDI_PROP_DONTPASS, "sil3xxx-initialized")) {
		return (TRUE);
	}

	if (pci_config_setup(ddi_get_parent(dip), &pci_conf_handle) !=
	    DDI_SUCCESS) {
		cmn_err(CE_WARN,
		    "sil3xxx_init_controller: Can't do pci_config_setup\n");
		return (FALSE);
	}

	/*
	 * Sil3114/3512/3112 incorrectly change between MR and back to
	 * MRM for same transaction, which violates the PCI spec and can
	 * lead to incorrect data reads.  The workaround
	 * is to set bits 2:0 in the FIFO count and control register so
	 * that its value, a multiple of 32 bytes starting at 32, not 0,
	 * is greater or equal to the cacheline size, a multiple of 4
	 * bytes.  This will prevent any reads until the FIFO free space
	 * is greater than a cacheline size, ensuring only MRM is issued.
	 */

	cache_lnsz = pci_config_get8(pci_conf_handle, PCI_CONF_CACHE_LINESZ);

	/*
	 * The cache line is specified in 32-bit words, so multiply by 4
	 * to get bytes.  Then divide by 32 bytes, the granularity of the
	 * FIFO control bits 2:0.  Add 1 if there is any remainder to
	 * account for a partial 32-byte block, then subtract 1 since for
	 * FIFO controls bits 2:0, 0 corresponds to 32, 1 corresponds to
	 * 64, and so on.  The calculation is expanded for clarity.
	 */
	if (cache_lnsz != 0) {
		frrc = (cache_lnsz * 4 / 32) +
			(((cache_lnsz * 4) % 32) ? 1 : 0) - 1;
	}

	if (device_id == SIL3114_DEVICE_ID) {
		ports = 4;
	} else {
		ports = 2;
	}

	/*
	 * The following BAR5 registers are accessed via an indirect register
	 * in the PCI configuration space rather than mapping BAR5.
	 */
	for (i = 0; i < ports; i++) {
		GET_BAR5_INDIRECT(pci_conf_handle, fifocntctl[i],
		    fifo_cnt_ctl);
		fifo_cnt_ctl = (fifo_cnt_ctl & ~0x7) | (frrc & 0x7);
		PUT_BAR5_INDIRECT(pci_conf_handle, fifocntctl[i],
		    fifo_cnt_ctl);
		/*
		 * Correct default setting for FIS0cfg
		 */
#ifdef	DEBUG
		GET_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i],
			sfiscfg_val);
		ADBG_WARN(("sil3xxx_init_controller: old val SFISCfg "
			"ch%d: %x\n", i, sfiscfg_val));
#endif
		PUT_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i],
			SFISCFG_ERRATA);
#ifdef	DEBUG
		GET_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i],
			sfiscfg_val);
		ADBG_WARN(("sil3xxx_init_controller: new val SFISCfg "
			"ch%d: %x\n", i, sfiscfg_val));
#endif
	}

	/* Now tear down the pci config setup */
	pci_config_teardown(&pci_conf_handle);

	/* Create property indicating that initialization was done */
	(void) ddi_prop_update_int(DDI_DEV_T_NONE, ddi_get_parent(dip),
		"sil3xxx-initialized", 1);

	return (TRUE);
}
Exemplo n.º 9
0
static int
_raw_get_bsize(dev_t dev, uint64_t *bsizep, int *partitionp)
{
#ifdef DKIOCPARTITION
	struct partition64 *p64 = NULL;
#endif
	struct dk_cinfo *dki_info = NULL;
	struct dev_ops *ops;
	struct cred *cred;
	struct vtoc *vtoc = NULL;
	dev_info_t *dip;
	raw_dev_t *cdi;
	int rc, cd;
	int flags;
	int rval;

	*partitionp = -1;
	*bsizep = 0;

	if ((cd = __raw_get_cd(dev)) == -1 || !_nsc_raw_files[cd].in_use)
		return (-1);

	cdi = &_nsc_raw_files[cd];
	ops = cdi->major->devops;

	if (ops == NULL) {
		return (-1);
	}

	rc = (*ops->devo_getinfo)(NULL, DDI_INFO_DEVT2DEVINFO,
	    (void *)dev, (void **)&dip);

	if (rc != DDI_SUCCESS || dip == NULL) {
		return (-1);
	}

	if (!ddi_prop_exists(DDI_DEV_T_ANY, dip,
	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, DDI_KERNEL_IOCTL)) {
		return (-1);
	}

	cred = ddi_get_cred();

	flags = FKIOCTL | FREAD | FWRITE | DATAMODEL_NATIVE;

	dki_info = kmem_alloc(sizeof (*dki_info), KM_SLEEP);

	/* DKIOCINFO */
	rc = (*cdi->major->ioctl)(dev, DKIOCINFO,
	    (intptr_t)dki_info, flags, cred, &rval);

	if (rc != 0) {
		goto out;
	}

	/* return partition number */
	*partitionp = (int)dki_info->dki_partition;

	vtoc = kmem_alloc(sizeof (*vtoc), KM_SLEEP);

	/* DKIOCGVTOC */
	rc = (*cdi->major->ioctl)(dev, DKIOCGVTOC,
	    (intptr_t)vtoc, flags, cred, &rval);

	if (rc) {
		/* DKIOCGVTOC failed, but there might be an EFI label */
		rc = -1;

#ifdef DKIOCPARTITION
		/* do we have an EFI partition table? */
		p64 = kmem_alloc(sizeof (*p64), KM_SLEEP);
		p64->p_partno = (uint_t)*partitionp;

		/* DKIOCPARTITION */
		rc = (*cdi->major->ioctl)(dev, DKIOCPARTITION,
		    (intptr_t)p64, flags, cred, &rval);

		if (rc == 0) {
			/* found EFI, return size */
			*bsizep = (uint64_t)p64->p_size;
		} else {
			/* both DKIOCGVTOC and DKIOCPARTITION failed - error */
			rc = -1;
		}
#endif

		goto out;
	}

	if ((vtoc->v_sanity != VTOC_SANE) ||
	    (vtoc->v_version != V_VERSION && vtoc->v_version != 0) ||
	    (dki_info->dki_partition > V_NUMPAR)) {
		rc = -1;
		goto out;
	}

	*bsizep = (uint64_t)vtoc->v_part[(int)dki_info->dki_partition].p_size;
	rc = 0;

out:
	if (dki_info) {
		kmem_free(dki_info, sizeof (*dki_info));
	}

	if (vtoc) {
		kmem_free(vtoc, sizeof (*vtoc));
	}

#ifdef DKIOCPARTITION
	if (p64) {
		kmem_free(p64, sizeof (*p64));
	}
#endif

	return (rc);
}
Exemplo n.º 10
0
static int
gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
	int instance = ddi_get_instance(devi);
	struct dstate *dstatep;
	int rval;
	int n_devs;
	int n_minorcomps;
	int isclone;
	ddi_eventcookie_t dev_offline_cookie, dev_reset_cookie;
	ddi_eventcookie_t bus_reset_cookie, bus_quiesce_cookie;
	ddi_eventcookie_t bus_unquiesce_cookie, bus_test_post_cookie;
	int i_init = 0;
	int level_tmp;

	int i;
	char *pm_comp[] = {
		"NAME=leaf0",
		"0=D0",
		"1=D1",
		"2=D2",
		"3=D3",
		"NAME=leaf1",
		"0=off",
		"1=blank",
		"2=on"};
	char *pm_hw_state = {"needs-suspend-resume"};


	switch (cmd) {
	case DDI_ATTACH:

		if (ddi_soft_state_zalloc(dstates, instance) !=
		    DDI_SUCCESS) {
			cmn_err(CE_CONT, "%s%d: can't allocate state\n",
			    ddi_get_name(devi), instance);

			return (DDI_FAILURE);
		}

		dstatep = ddi_get_soft_state(dstates, instance);
		dstatep->dip = devi;
		mutex_init(&dstatep->lock, NULL, MUTEX_DRIVER, NULL);

		n_devs = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0,
		    "ndevs", 1);

		isclone = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0,
		    "isclone", 0);

		n_minorcomps = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0,
		    "ncomps", 1);

		GEN_DEBUG((CE_CONT,
		    "%s%d attaching: n_devs=%d n_minorcomps=%d isclone=%d",
		    ddi_get_name(devi), ddi_get_instance(devi),
		    n_devs, n_minorcomps, isclone));

		if (isclone) {
			if (ddi_create_minor_node(devi, "gen", S_IFCHR,
			    INST_TO_MINOR(instance), mnodetypes[0],
			    isclone) != DDI_SUCCESS) {
				ddi_remove_minor_node(devi, NULL);
				ddi_soft_state_free(dstates, instance);
				cmn_err(CE_WARN, "%s%d: can't create minor "
				"node", ddi_get_name(devi), instance);

				return (DDI_FAILURE);
			}
			rval = DDI_SUCCESS;
		} else {
			rval = gen_create_minor_nodes(devi, dstatep);
			if (rval != DDI_SUCCESS) {
				ddi_prop_remove_all(devi);
				ddi_remove_minor_node(devi, NULL);
				ddi_soft_state_free(dstates, instance);
				cmn_err(CE_WARN, "%s%d: can't create minor "
				"nodes", ddi_get_name(devi), instance);

				return (DDI_FAILURE);
			}
		}

		if (ddi_get_eventcookie(devi, "pshot_dev_offline",
		    &dev_offline_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi, dev_offline_cookie,
			    gen_event_cb, NULL, &(dstatep->gen_cb_ids[0]));
		}

		if (ddi_get_eventcookie(devi, "pshot_dev_reset",
		    &dev_reset_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi, dev_reset_cookie,
			    gen_event_cb, NULL, &(dstatep->gen_cb_ids[1]));
		}

		if (ddi_get_eventcookie(devi, "pshot_bus_reset",
		    &bus_reset_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi, bus_reset_cookie,
			    gen_event_cb, NULL, &(dstatep->gen_cb_ids[2]));
		}

		if (ddi_get_eventcookie(devi, "pshot_bus_quiesce",
		    &bus_quiesce_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi, bus_quiesce_cookie,
			    gen_event_cb, NULL, &(dstatep->gen_cb_ids[3]));
		}

		if (ddi_get_eventcookie(devi, "pshot_bus_unquiesce",
		    &bus_unquiesce_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi,
			    bus_unquiesce_cookie, gen_event_cb,
			    NULL, &(dstatep->gen_cb_ids[4]));
		}

		if (ddi_get_eventcookie(devi, "pshot_bus_test_post",
		    &bus_test_post_cookie) == DDI_SUCCESS) {
			(void) ddi_add_event_handler(devi,
			    bus_test_post_cookie, gen_event_cb,
			    NULL, &(dstatep->gen_cb_ids[5]));
		}

		/*
		 * initialize the devices' pm state
		 */
		mutex_enter(&dstatep->lock);
		dstatep->flag &= ~OPEN_FLAG;
		dstatep->flag &= ~PWR_HAS_CHANGED_ON_RESUME_FLAG;
		dstatep->flag &= ~FAIL_SUSPEND_FLAG;
		dstatep->flag &= ~PUP_WITH_PWR_HAS_CHANGED_FLAG;
		dstatep->flag |= LOWER_POWER_FLAG;
		dstatep->flag &= ~NO_INVOL_FLAG;
		dstatep->flag |= PM_SUPPORTED_FLAG;
		dstatep->busy[0] = 0;
		dstatep->busy[1] = 0;
		dstatep->level[0] = -1;
		dstatep->level[1] = -1;
		mutex_exit(&dstatep->lock);

		/*
		 * stash the nodename
		 */
		dstatep->nodename = ddi_node_name(devi);

		/*
		 * Check if the no-involuntary-power-cycles property
		 * was created. Set NO_INVOL_FLAG if so.
		 */
		if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip,
		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
		    "no-involuntary-power-cycles") == 1) {
			GEN_DEBUG((CE_CONT,
			    "%s%d: DDI_ATTACH:\n\tno-involuntary-power-cycles"
			    " property was created",
			    ddi_node_name(devi), ddi_get_instance(devi)));
			mutex_enter(&dstatep->lock);
			dstatep->flag |= NO_INVOL_FLAG;
			mutex_exit(&dstatep->lock);
		}

		/*
		 * Check if the dependency-property property
		 * was created.
		 */
		if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip,
		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
		    "dependency-property") == 1) {
			GEN_DEBUG((CE_CONT,
			    "%s%d: DDI_ATTACH:\n\tdependency-property"
			    " property was created",
			    ddi_node_name(devi), ddi_get_instance(devi)));
		}

		/*
		 * create the pm-components property. two comps:
		 * 4 levels on comp0, 3 on comp 1.
		 * - skip for a "tape" device, clear PM_SUPPORTED_FLAG
		 */
		if (strcmp(ddi_node_name(devi), "tape") != 0) {
			if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi,
			    "pm-components", pm_comp, 9) != DDI_PROP_SUCCESS) {
				cmn_err(CE_WARN, "%s%d: %s\n",
				    ddi_node_name(devi),
				    ddi_get_instance(devi),
				    "unable to create \"pm-components\" "
				    " property.");

				return (DDI_FAILURE);
			}
		} else {
			mutex_enter(&dstatep->lock);
			dstatep->flag &= ~PM_SUPPORTED_FLAG;
			mutex_exit(&dstatep->lock);
		}

		/*
		 * Check if the pm-components property was created
		 */
		if (dstatep->flag & PM_SUPPORTED_FLAG) {
			if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip,
			    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
			    "pm-components") != 1) {
				cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t%s",
				    ddi_node_name(devi),
				    ddi_get_instance(devi),
				    "\"pm-components\" property does"
				    " not exist");

				return (DDI_FAILURE);

			} else {
				GEN_DEBUG((CE_CONT, "%s%d: DDI_ATTACH:"
				    " created pm-components property",
				    ddi_node_name(devi),
				    ddi_get_instance(devi)));
			}
		}

		/*
		 * create the pm-hardware-state property.
		 * needed to get DDI_SUSPEND and DDI_RESUME calls
		 */
		if (ddi_prop_update_string(DDI_DEV_T_NONE, devi,
		    "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) {
			cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t%s\n",
			    ddi_node_name(devi), ddi_get_instance(devi),
			    "unable to create \"pm-hardware-state\" "
			    " property.");

			return (DDI_FAILURE);
		}

		/*
		 * set power levels to max via pm_raise_power(),
		 */
		mutex_enter(&dstatep->lock);
		i_init = (dstatep->flag & PM_SUPPORTED_FLAG) ? 0 : COMPONENTS;
		mutex_exit(&dstatep->lock);
		for (i = i_init; i < COMPONENTS; i++) {
			GEN_DEBUG((CE_CONT,
			    "%s%d: DDI_ATTACH: pm_raise_power comp %d "
			    "to level %d", ddi_node_name(devi),
			    ddi_get_instance(devi), i, maxpwr[i]));
			if (pm_raise_power(dstatep->dip, i, maxpwr[i]) !=
			    DDI_SUCCESS) {
				cmn_err(CE_WARN,
				    "%s%d: DDI_ATTACH: pm_raise_power failed\n",
				    ddi_node_name(devi),
				    ddi_get_instance(devi));
				dstatep->level[i] = -1;

				return (DDI_FAILURE);
			}
		}

		if (rval == DDI_SUCCESS) {
			ddi_report_dev(devi);
		}
		return (rval);


	case DDI_RESUME:
		GEN_DEBUG((CE_CONT, "%s%d: DDI_RESUME", ddi_node_name(devi),
		    ddi_get_instance(devi)));

		dstatep = ddi_get_soft_state(dstates, ddi_get_instance(devi));
		if (dstatep == NULL) {

			return (DDI_FAILURE);
		}

		/*
		 * Call pm_power_has_changed() if flag
		 * PWR_HAS_CHANGED_ON_RESUME_FLAG is set,
		 * then clear the flag
		 */
		mutex_enter(&dstatep->lock);
		i_init = (dstatep->flag & PM_SUPPORTED_FLAG) ? 0 : COMPONENTS;
		mutex_exit(&dstatep->lock);
		if (dstatep->flag & PWR_HAS_CHANGED_ON_RESUME_FLAG) {
			for (i = i_init; i < COMPONENTS; i++) {
				GEN_DEBUG((CE_CONT,
				    "%s%d: DDI_RESUME: pm_power_has_changed "
				    "comp %d to level %d", ddi_node_name(devi),
				    ddi_get_instance(devi), i, maxpwr[i]));
				mutex_enter(&dstatep->lock);
				level_tmp = dstatep->level[i];
				dstatep->level[i] = maxpwr[i];
				if (pm_power_has_changed(dstatep->dip, i,
				    maxpwr[i]) != DDI_SUCCESS) {
					cmn_err(CE_WARN,
					    "%s%d: DDI_RESUME:\n\t"
					    " pm_power_has_changed"
					    " failed: comp %d to level %d\n",
					    ddi_node_name(devi),
					    ddi_get_instance(devi),
					    i, maxpwr[i]);
					dstatep->level[i] = level_tmp;
				}
				mutex_exit(&dstatep->lock);
			}
		} else {
			/*
			 * Call pm_raise_power() instead
			 */
			for (i = i_init; i < COMPONENTS; i++) {
				GEN_DEBUG((CE_CONT,
				    "%s%d: DDI_RESUME: pm_raise_power"
				    " comp %d to level %d",
				    ddi_node_name(devi), ddi_get_instance(devi),
				    i, maxpwr[i]));
				if (pm_raise_power(dstatep->dip, i, maxpwr[i])
				    != DDI_SUCCESS) {
					cmn_err(CE_WARN,
					    "%s%d: DDI_RESUME:"
					    "\n\tpm_raise_power"
					    "failed: comp %d to level %d\n",
					    ddi_node_name(devi),
					    ddi_get_instance(devi),
					    i, maxpwr[i]);
				}
			}
		}

		return (DDI_SUCCESS);

	default:
		GEN_DEBUG((CE_WARN, "attach: default"));
		return (DDI_FAILURE);
	}
}
Exemplo n.º 11
0
/*
 * Find the BIOS date, and return TRUE if supplied
 * date is same or later than the BIOS date, or FALSE
 * if the BIOS date can't be fetched for any reason
 */
static int
acpica_check_bios_date(int yy, int mm, int dd)
{

	char *datep;
	int bios_year, bios_month, bios_day;

	/* If firmware has no bios, skip the check */
	if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
	    "efi-systab"))
		return (TRUE);

	/*
	 * PC BIOSes contain a string in the form of
	 * "mm/dd/yy" at absolute address 0xffff5,
	 * where mm, dd and yy are all ASCII digits.
	 * We map the string, pluck out the values,
	 * and accept all BIOSes from 1 Jan 1999 on
	 * as valid.
	 */

	if ((datep = (char *)AcpiOsMapMemory(0xffff5, 8)) == NULL)
		return (FALSE);

	/* year */
	bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0');
	/* month */
	bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0');
	/* day */
	bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0');

	AcpiOsUnmapMemory((void *) datep, 8);

	if (bios_year < 0 || bios_year > 99 || bios_month < 0 ||
	    bios_month > 99 || bios_day < 0 || bios_day > 99) {
		/* non-digit chars in BIOS date */
		return (FALSE);
	}

	/*
	 * Adjust for 2-digit year; note to grand-children:
	 * need a new scheme before 2080 rolls around
	 */
	bios_year += (bios_year >= 80 && bios_year <= 99) ?
	    1900 : 2000;

	if (bios_year < yy)
		return (FALSE);
	else if (bios_year > yy)
		return (TRUE);

	if (bios_month < mm)
		return (FALSE);
	else if (bios_month > mm)
		return (TRUE);

	if (bios_day < dd)
		return (FALSE);

	return (TRUE);
}
Exemplo n.º 12
0
/*
 * smp_probe: probe device and create inquiry-like properties.
 */
int
smp_probe(struct smp_device *smp_sd)
{
	smp_pkt_t				*smp_pkt;
	smp_pkt_t				smp_pkt_data;
	smp_request_frame_t			*srq;
	smp_response_frame_t			*srs;
	smp_report_manufacturer_info_resp_t	*srmir;
	int					ilen, clen;
	char					*component;
	uint8_t			srq_buf[SMP_REQ_MINLEN];
	uint8_t			srs_buf[SMP_RESP_MINLEN + sizeof (*srmir)];

	srq = (smp_request_frame_t *)srq_buf;
	bzero(srq, sizeof (srq_buf));
	srq->srf_frame_type = SMP_FRAME_TYPE_REQUEST;
	srq->srf_function = SMP_FUNC_REPORT_MANUFACTURER_INFO;

	smp_pkt = &smp_pkt_data;
	bzero(smp_pkt, sizeof (*smp_pkt));
	smp_pkt->smp_pkt_address = &smp_sd->smp_sd_address;
	smp_pkt->smp_pkt_req = (caddr_t)srq;
	smp_pkt->smp_pkt_reqsize = sizeof (srq_buf);
	smp_pkt->smp_pkt_rsp = (caddr_t)srs_buf;
	smp_pkt->smp_pkt_rspsize = sizeof (srs_buf);
	smp_pkt->smp_pkt_timeout = SMP_DEFAULT_TIMEOUT;

	bzero(srs_buf, sizeof (srs_buf));

	if (smp_transport(smp_pkt) != DDI_SUCCESS) {
		/*
		 * The EOVERFLOW should be excluded here, because it indicates
		 * the buffer (defined according to SAS1.1 Spec) to store
		 * response is shorter than transferred message frame.
		 * In this case, the smp device is alive and should be
		 * enumerated.
		 */
		if (smp_pkt->smp_pkt_reason != EOVERFLOW)
			return (DDI_PROBE_FAILURE);
	}

	/*
	 * NOTE: Deal with old drivers (mpt, mpt_sas) that allocate
	 * 'struct smp_device' on the stack.  When these drivers convert to
	 * SCSAv3, the check for a NULL smp_sd_dev can be removed.
	 */
	if (smp_sd->smp_sd_dev == NULL)
		return (DDI_PROBE_SUCCESS);

	/* Save raw response data for devid */
	srs = (smp_response_frame_t *)srs_buf;
	if (srs->srf_result != SMP_RES_FUNCTION_ACCEPTED)
		return (DDI_PROBE_SUCCESS);

	/*
	 * Convert smp_report_manufacturer_info_resp_t data into properties.
	 * NOTE: since things show up in the oposite order in prtconf, we are
	 * going from detailed information to generic here.
	 */
	srmir = (smp_report_manufacturer_info_resp_t *)&srs->srf_data[0];
	if (srmir->srmir_sas_1_1_format) {
		/* Establish 'component' property. */
		ilen = scsi_ascii_inquiry_len(
		    srmir->srmir_component_vendor_identification,
		    sizeof (srmir->srmir_component_vendor_identification));
		if (ilen > 0) {
			/* component value format is '%s.%05d.%03d' */
			clen = ilen + 1 + 5 + 1 + 3 + 1;
			component = kmem_zalloc(clen, KM_SLEEP);
			bcopy(srmir->srmir_component_vendor_identification,
			    component, ilen);
			(void) snprintf(&component[ilen], clen - ilen,
			    ".%05d.%03d", BE_16(srmir->srmir_component_id),
			    srmir->srmir_component_revision_level);
			if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev,
			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
			    "component") == 0)
				(void) ndi_prop_update_string(DDI_DEV_T_NONE,
				    smp_sd->smp_sd_dev, "component", component);
			kmem_free(component, clen);
		}
	}
	/* First one to define the property wins */
	if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev,
	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_REVISION_ID) == 0)
		(void) smp_device_prop_update_inqstring(smp_sd,
		    INQUIRY_REVISION_ID, srmir->srmir_product_revision_level,
		    sizeof (srmir->srmir_product_revision_level));

	if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev,
	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_PRODUCT_ID) == 0)
		(void) smp_device_prop_update_inqstring(smp_sd,
		    INQUIRY_PRODUCT_ID, srmir->srmir_product_identification,
		    sizeof (srmir->srmir_product_identification));

	if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev,
	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, INQUIRY_VENDOR_ID) == 0)
		(void) smp_device_prop_update_inqstring(smp_sd,
		    INQUIRY_VENDOR_ID, srmir->srmir_vendor_identification,
		    sizeof (srmir->srmir_vendor_identification));

	/* NOTE: SMP_PROP_REPORT_MANUFACTURER is deleted after devid created */
	if (ddi_prop_exists(DDI_DEV_T_NONE, smp_sd->smp_sd_dev,
	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
	    SMP_PROP_REPORT_MANUFACTURER) == 0)
		(void) ndi_prop_update_byte_array(DDI_DEV_T_NONE,
		    smp_sd->smp_sd_dev, SMP_PROP_REPORT_MANUFACTURER,
		    (uchar_t *)srs, sizeof (srs_buf));

	return (DDI_PROBE_SUCCESS);
}
Exemplo n.º 13
0
static int
pseudonex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
    void *arg, void *result)
{
	switch (ctlop) {
	case DDI_CTLOPS_REPORTDEV:
		if (rdip == NULL)
			return (DDI_FAILURE);
		cmn_err(CE_CONT, "?pseudo-device: %s%d\n",
		    ddi_driver_name(rdip), ddi_get_instance(rdip));
		return (DDI_SUCCESS);

	case DDI_CTLOPS_INITCHILD:
	{
		char name[12];	/* enough for a decimal integer */
		int instance = -1;
		dev_info_t *child = (dev_info_t *)arg;
		const char *childname = ddi_driver_name(child);
		char **childlist;
		uint_t nelems;
		int auto_assign = 0;

		/*
		 * If this pseudonex node has a valid-children property,
		 * then that acts as an access control list for children
		 * allowed to attach beneath this node.  Honor it.
		 */
		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
		    DDI_PROP_DONTPASS, "valid-children", &childlist,
		    &nelems) == DDI_PROP_SUCCESS) {
			int i, ok = 0;
			for (i = 0; i < nelems; i++) {
				if (strcmp(childlist[i], childname) == 0) {
					ok = 1;
					break;
				}
			}
			ddi_prop_free(childlist);
			if (!ok)
				return (DDI_FAILURE);
		}

		/*
		 * Look up the "instance" property. If it does not exist,
		 * check to see if the "auto-assign-instance" property is set.
		 * If not, default to using instance 0; while not ideal, this
		 * is a legacy behavior we must continue to support.
		 */
		instance = ddi_prop_get_int(DDI_DEV_T_ANY, child,
		    DDI_PROP_DONTPASS, "instance", -1);
		auto_assign = ddi_prop_exists(DDI_DEV_T_ANY, child,
		    DDI_PROP_DONTPASS, "auto-assign-instance");
		NDI_CONFIG_DEBUG((CE_NOTE,
		    "pseudonex: DDI_CTLOPS_INITCHILD(instance=%d, "
		    "auto-assign=%d)", instance, auto_assign));

		if (instance != -1 && auto_assign != 0) {
			NDI_CONFIG_DEBUG((CE_NOTE, "both instance and "
			    "auto-assign-instance properties specified. "
			    "Node rejected."));
			return (DDI_FAILURE);
		}

		if (instance == -1 && auto_assign == 0) {
			/* default to instance 0 if not specified */
			NDI_CONFIG_DEBUG((CE_NOTE, "defaulting to 0"));
			instance = 0;
		}

		/*
		 * If an instance has been specified, determine if this
		 * instance is already in use; if we need to pick an instance,
		 * we do it here.
		 */
		if (auto_assign) {
			if ((instance = pseudonex_auto_assign(child)) == -1) {
				NDI_CONFIG_DEBUG((CE_NOTE, "failed to "
				    "auto-select instance for %s", childname));
				return (DDI_FAILURE);
			}
			NDI_CONFIG_DEBUG((CE_NOTE,
			    "auto-selected instance for %s: %d",
			    childname, instance));
		} else {
			if (pseudonex_check_assignment(child, instance) ==
			    DDI_FAILURE) {
				NDI_CONFIG_DEBUG((CE_WARN,
				    "Duplicate instance %d of node \"%s\" "
				    "ignored.", instance, childname));
				return (DDI_FAILURE);
			}
			NDI_CONFIG_DEBUG((CE_NOTE,
			    "using fixed-assignment instance for %s: %d",
			    childname, instance));
		}

		/*
		 * Attach the instance number to the node. This allows
		 * us to have multiple instances of the same pseudo
		 * device, they will be named 'device@instance'. If this
		 * breaks programs, we may need to special-case instance 0
		 * into 'device'. Ick. devlinks appears to handle the
		 * new names ok, so if only names in /dev are used
		 * this may not be necessary.
		 */
		(void) snprintf(name, sizeof (name), "%d", instance);
		DEVI(child)->devi_instance = instance;
		ddi_set_name_addr(child, name);
		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_UNINITCHILD:
	{
		dev_info_t *child = (dev_info_t *)arg;

		NDI_CONFIG_DEBUG((CE_NOTE,
		    "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)",
		    ddi_driver_name(child), DEVI(child)->devi_instance));

		ddi_set_name_addr(child, NULL);

		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_DMAPMAPC:
	case DDI_CTLOPS_REPORTINT:
	case DDI_CTLOPS_REGSIZE:
	case DDI_CTLOPS_NREGS:
	case DDI_CTLOPS_SIDDEV:
	case DDI_CTLOPS_SLAVEONLY:
	case DDI_CTLOPS_AFFINITY:
	case DDI_CTLOPS_POKE:
	case DDI_CTLOPS_PEEK:
		/*
		 * These ops correspond to functions that "shouldn't" be called
		 * by a pseudo driver.  So we whine when we're called.
		 */
		cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
		    ddi_driver_name(dip), ddi_get_instance(dip), ctlop,
		    ddi_driver_name(rdip), ddi_get_instance(rdip));
		return (DDI_FAILURE);

	case DDI_CTLOPS_ATTACH:
	case DDI_CTLOPS_BTOP:
	case DDI_CTLOPS_BTOPR:
	case DDI_CTLOPS_DETACH:
	case DDI_CTLOPS_DVMAPAGESIZE:
	case DDI_CTLOPS_IOMIN:
	case DDI_CTLOPS_POWER:
	case DDI_CTLOPS_PTOB:
	default:
		/*
		 * The ops that we pass up (default).  We pass up memory
		 * allocation oriented ops that we receive - these may be
		 * associated with pseudo HBA drivers below us with target
		 * drivers below them that use ddi memory allocation
		 * interfaces like scsi_alloc_consistent_buf.
		 */
		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
	}
}
Exemplo n.º 14
0
/*
 * nx1394_bus_ctl()
 *    This routine implements nexus bus ctl operations. Of importance are
 *    DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD
 *    and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup
 *    reg property on the child node and builds and sets the name
 *    (name is of the form GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where
 *    GGGGGGGGGGGGGGGG is the GUID and AAAAAAAAAAAA is the optional unit
 *    address).
 */
static int
nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
    void *result)
{
	int status;

	TNF_PROBE_0_DEBUG(nx1394_bus_ctl_enter, S1394_TNF_SL_NEXUS_STACK, "");

	switch (op) {
	case DDI_CTLOPS_REPORTDEV: {
		dev_info_t *pdip = ddi_get_parent(rdip);
		cmn_err(CE_CONT, "?%s%d at %s%d",
		    ddi_node_name(rdip), ddi_get_instance(rdip),
		    ddi_node_name(pdip), ddi_get_instance(pdip));
		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "");
		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_INITCHILD: {
		dev_info_t *ocdip, *cdip = (dev_info_t *)arg;
		dev_info_t *pdip = ddi_get_parent(cdip);
		int reglen, i;
		uint32_t *regptr;
		char addr[MAXNAMELEN];

		TNF_PROBE_1(nx1394_bus_ctl_init_child,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque, dip, cdip);

		i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
		    DDI_PROP_DONTPASS, "reg", (int **)&regptr,
		    (uint_t *)&reglen);

		if (i != DDI_PROP_SUCCESS) {
			cmn_err(CE_NOTE, "!%s(%d): \"reg\" property not found",
			    ddi_node_name(cdip), ddi_get_instance(cdip));
			TNF_PROBE_2(nx1394_bus_ctl,
			    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg,
			    "Reg property not found", tnf_int, reason, i);
			TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
			    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op,
			    "initchild");
			return (DDI_NOT_WELL_FORMED);
		}

		ASSERT(reglen != 0);

		/*
		 * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA]
		 */
		if (regptr[2] || regptr[3]) {
			(void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
			    regptr[1], regptr[2], regptr[3]);
		} else {
			(void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
		}
		ddi_prop_free(regptr);
		ddi_set_name_addr(cdip, addr);

		/*
		 * Check for a node with the same name & addr as the current
		 * node. If such a node exists, return failure.
		 */
		if ((ocdip = ndi_devi_find(pdip, ddi_node_name(cdip), addr)) !=
		    NULL && ocdip != cdip) {
			cmn_err(CE_NOTE,
			    "!%s(%d): Duplicate dev_info node found %s@%s",
			    ddi_node_name(cdip), ddi_get_instance(cdip),
			    ddi_node_name(ocdip), addr);
			TNF_PROBE_1(nx1394_bus_ctl,
			    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg,
			    "Duplicate nodes");
			TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
			    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op,
			    "initchild");
			ddi_set_name_addr(cdip, NULL);
			return (DDI_NOT_WELL_FORMED);
		}

		/*
		 * If HAL (parent dip) has "active-dma-flush" property, then
		 * add property to child as well.  Workaround for active
		 * context flushing bug in Schizo rev 2.1 and 2.2.
		 */
		if (ddi_prop_exists(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
		    "active-dma-flush") != 0) {
			status = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
			    "active-dma-flush", 1);
			if (status != NDI_SUCCESS) {
				cmn_err(CE_NOTE, "!%s(%d): Unable to add "
				    "\"active-dma-flush\" property",
				    ddi_node_name(cdip),
				    ddi_get_instance(cdip));
				TNF_PROBE_1(nx1394_bus_ctl,
				    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string,
				    msg, "Unable to add \"active-dma-flush\" "
				    "property");
				TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
				    S1394_TNF_SL_NEXUS_STACK, "", tnf_string,
				    op, "initchild");
				ddi_set_name_addr(cdip, NULL);
				return (DDI_NOT_WELL_FORMED);
			}
		}

		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
		    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild");
		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_UNINITCHILD: {
		ddi_prop_remove_all((dev_info_t *)arg);
		ddi_set_name_addr((dev_info_t *)arg, NULL);
		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "", tnf_string, op, "uninitchild");
		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_IOMIN: {
		status = ddi_ctlops(dip, rdip, op, arg, result);
		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "", tnf_string, op, "iomin");
		return (status);
	}

	case DDI_CTLOPS_POWER: {
		return (DDI_SUCCESS);
	}

	/*
	 * These ops correspond to functions that "shouldn't" be called
	 * by a 1394 client driver.
	 */
	case DDI_CTLOPS_DMAPMAPC:
	case DDI_CTLOPS_REPORTINT:
	case DDI_CTLOPS_REGSIZE:
	case DDI_CTLOPS_NREGS:
	case DDI_CTLOPS_SIDDEV:
	case DDI_CTLOPS_SLAVEONLY:
	case DDI_CTLOPS_AFFINITY:
	case DDI_CTLOPS_POKE:
	case DDI_CTLOPS_PEEK: {
		cmn_err(CE_CONT, "!%s(%d): invalid op (%d) from %s(%d)",
		    ddi_node_name(dip), ddi_get_instance(dip),
		    op, ddi_node_name(rdip), ddi_get_instance(rdip));
		TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "",
		    tnf_string, msg, "invalid op", tnf_int, op, op);
		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "");
		return (DDI_FAILURE);
	}

	/*
	 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
	 */
	default: {
		status = ddi_ctlops(dip, rdip, op, arg, result);
		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "");
		return (status);
	}
	}
}
Exemplo n.º 15
0
/*
 * A hotplug version of fill_cpu().  (Doesn't assume that there's a node
 * in the PROM device tree for this CPU.)  We still need the PROM version
 * since it is called very early in the boot cycle before (before
 * setup_ddi()).  Sigh...someday this will all be cleaned up.
 */
void
fill_cpu_ddi(dev_info_t *dip)
{
    extern int cpu_get_cpu_unum(int, char *, int, int *);
    struct cpu_node *cpunode;
    processorid_t cpuid;
    int portid;
    int len = OBP_MAXPROPNAME;
    int tlbsize;
    dev_info_t *cmpnode;
    char namebuf[OBP_MAXPROPNAME], unum[UNUM_NAMLEN];
    char *namebufp;
    char dev_type[OBP_MAXPROPNAME];

    if ((portid = get_portid_ddi(dip, &cmpnode)) == -1) {
        cmn_err(CE_PANIC, "portid not found");
    }

    if ((cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
                                  DDI_PROP_DONTPASS, "cpuid", -1)) == -1) {
        cpuid = portid;
    }

    if (cpuid < 0 || cpuid >= NCPU) {
        cmn_err(CE_PANIC, "cpu dip %p: cpuid %d out of range",
                (void *)dip, cpuid);
        return;
    }

    cpunode = &cpunodes[cpuid];
    cpunode->portid = portid;
    cpunode->nodeid = ddi_get_nodeid(dip);

    if (cmpnode != NULL) {
        /*
         * For the CMT case, the parent "core" node contains
         * properties needed below, use it instead of the
         * cpu node.
         */
        if ((ddi_prop_op(DDI_DEV_T_ANY, cmpnode, PROP_LEN_AND_VAL_BUF,
                         DDI_PROP_DONTPASS, "device_type",
                         (caddr_t)dev_type, &len) == DDI_PROP_SUCCESS) &&
                (strcmp(dev_type, "core") == 0))
            dip = cmpnode;
    }

    if (cpu_get_cpu_unum(cpuid, unum, UNUM_NAMLEN, &len) != 0) {
        cpunode->fru_fmri[0] = '\0';
    } else {
        (void) snprintf(cpunode->fru_fmri, sizeof (cpunode->fru_fmri),
                        "%s%s", CPU_FRU_FMRI, unum);
    }

    len = sizeof (namebuf);
    (void) ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN_AND_VAL_BUF,
                       DDI_PROP_DONTPASS, (cmpnode ? "compatible" : "name"),
                       (caddr_t)namebuf, &len);

    namebufp = namebuf;
    if (strncmp(namebufp, "SUNW,", 5) == 0)
        namebufp += 5;
    else if (strncmp(namebufp, "FJSV,", 5) == 0)
        namebufp += 5;
    (void) strcpy(cpunode->name, namebufp);

    cpunode->implementation = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
                              DDI_PROP_DONTPASS, "implementation#", 0);

    cpunode->version = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
                                        DDI_PROP_DONTPASS, "mask#", 0);

    if (IS_CHEETAH(cpunode->implementation)) {
        /* remap mask reg */
        cpunode->version = REMAP_CHEETAH_MASK(cpunode->version);
    }

    cpunode->clock_freq = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, dip,
                          DDI_PROP_DONTPASS, "clock-frequency", 0);

    ASSERT(cpunode->clock_freq != 0);
    /*
     * Compute scaling factor based on rate of %tick. This is used
     * to convert from ticks derived from %tick to nanoseconds. See
     * comment in sun4u/sys/clock.h for details.
     */
    cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC <<
                                         (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq);

    tlbsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
                               DDI_PROP_DONTPASS, "#itlb-entries", 0);
    ASSERT(tlbsize < USHRT_MAX); /* since we cast it */
    cpunode->itlb_size = (ushort_t)tlbsize;

    tlbsize = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
                               DDI_PROP_DONTPASS, "#dtlb-entries", 0);
    ASSERT(tlbsize < USHRT_MAX); /* since we cast it */
    cpunode->dtlb_size = (ushort_t)tlbsize;

    if (cmpnode != NULL) {
        /*
         * If the CPU has a level 3 cache, then that is it's
         * external cache. Otherwise the external cache must
         * be the level 2 cache.
         */
        cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY,
                                                dip, DDI_PROP_DONTPASS, "l3-cache-size", 0);
        if (cpunode->ecache_size == 0)
            cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY,
                                                    dip, DDI_PROP_DONTPASS, "l2-cache-size", 0);
        ASSERT(cpunode->ecache_size != 0);

        cpunode->ecache_linesize = ddi_prop_get_int(DDI_DEV_T_ANY,
                                   dip, DDI_PROP_DONTPASS, "l3-cache-line-size", 0);
        if (cpunode->ecache_linesize == 0)
            cpunode->ecache_linesize =
                ddi_prop_get_int(DDI_DEV_T_ANY, dip,
                                 DDI_PROP_DONTPASS, "l2-cache-line-size", 0);
        ASSERT(cpunode->ecache_linesize != 0);

        cpunode->ecache_associativity = ddi_prop_get_int(DDI_DEV_T_ANY,
                                        dip, DDI_PROP_DONTPASS, "l2-cache-associativity", 0);
        ASSERT(cpunode->ecache_associativity != 0);

        cmp_add_cpu(portid, cpuid);
    } else {
        cpunode->ecache_size = ddi_prop_get_int(DDI_DEV_T_ANY,
                                                dip, DDI_PROP_DONTPASS, "ecache-size", 0);
        ASSERT(cpunode->ecache_size != 0);

        cpunode->ecache_linesize = ddi_prop_get_int(DDI_DEV_T_ANY,
                                   dip, DDI_PROP_DONTPASS, "ecache-line-size", 0);
        ASSERT(cpunode->ecache_linesize != 0);

        cpunode->ecache_associativity = ddi_prop_get_int(DDI_DEV_T_ANY,
                                        dip, DDI_PROP_DONTPASS, "ecache-associativity", 0);
        ASSERT(cpunode->ecache_associativity != 0);
    }

    /* by default set msram to non-mirrored one */
    cpunode->msram = ECACHE_CPU_NON_MIRROR;

    if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "msram")) {
        cpunode->msram = ECACHE_CPU_MIRROR;
    } else if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
                               "msram-observed")) {
        cpunode->msram = ECACHE_CPU_MIRROR;
    }

    ASSERT(ncpunode > 0);	/* fiximp not req'd */

    cpunode->ecache_setsize =
        cpunode->ecache_size / cpunode->ecache_associativity;

    adj_ecache_setsize(cpunode->ecache_setsize);

    ncpunode++;
}
Exemplo n.º 16
0
static int
ppb_initchild(dev_info_t *child)
{
	char name[MAXNAMELEN];
	ddi_acc_handle_t config_handle;
	ushort_t command_preserve, command;
	uint_t n;
	ushort_t bcr;
	uchar_t header_type;
	uchar_t min_gnt, latency_timer;
	ppb_devstate_t *ppb;

	/*
	 * Name the child
	 */
	if (ppb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
		return (DDI_FAILURE);

	ddi_set_name_addr(child, name);
	ddi_set_parent_data(child, NULL);

	/*
	 * Pseudo nodes indicate a prototype node with per-instance
	 * properties to be merged into the real h/w device node.
	 * The interpretation of the unit-address is DD[,F]
	 * where DD is the device id and F is the function.
	 */
	if (ndi_dev_is_persistent_node(child) == 0) {
		extern int pci_allow_pseudo_children;

		/*
		 * Try to merge the properties from this prototype
		 * node into real h/w nodes.
		 */
		if (ndi_merge_node(child, ppb_name_child) == DDI_SUCCESS) {
			/*
			 * Merged ok - return failure to remove the node.
			 */
			ppb_removechild(child);
			return (DDI_FAILURE);
		}

		/* workaround for ddivs to run under PCI */
		if (pci_allow_pseudo_children)
			return (DDI_SUCCESS);

		/*
		 * The child was not merged into a h/w node,
		 * but there's not much we can do with it other
		 * than return failure to cause the node to be removed.
		 */
		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
		    ddi_driver_name(child), ddi_get_name_addr(child),
		    ddi_driver_name(child));
		ppb_removechild(child);
		return (DDI_NOT_WELL_FORMED);
	}

	ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
	    ddi_get_instance(ddi_get_parent(child)));

	ddi_set_parent_data(child, NULL);

	/*
	 * If hardware is PM capable, set up the power info structure.
	 * This also ensures the the bus will not be off (0MHz) otherwise
	 * system panics during a bus access.
	 */
	if (PM_CAPABLE(ppb->ppb_pwr_p)) {
		/*
		 * Create a pwr_info struct for child.  Bus will be
		 * at full speed after creating info.
		 */
		pci_pwr_create_info(ppb->ppb_pwr_p, child);
#ifdef DEBUG
		ASSERT(ppb->ppb_pwr_p->current_lvl == PM_LEVEL_B0);
#endif
	}

	/*
	 * If configuration registers were previously saved by
	 * child (before it entered D3), then let the child do the
	 * restore to set up the config regs as it'll first need to
	 * power the device out of D3.
	 */
	if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
	    "config-regs-saved-by-child") == 1) {
		DEBUG2(DBG_PWR, ddi_get_parent(child),
		    "INITCHILD: config regs to be restored by child"
		    " for %s@%s\n", ddi_node_name(child),
		    ddi_get_name_addr(child));

		return (DDI_SUCCESS);
	}

	DEBUG2(DBG_PWR, ddi_get_parent(child),
	    "INITCHILD: config regs setup for %s@%s\n",
	    ddi_node_name(child), ddi_get_name_addr(child));

	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
		if (PM_CAPABLE(ppb->ppb_pwr_p)) {
			pci_pwr_rm_info(ppb->ppb_pwr_p, child);
		}

		return (DDI_FAILURE);
	}

	/*
	 * Determine the configuration header type.
	 */
	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);

	/*
	 * Support for the "command-preserve" property.
	 */
	command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
	    DDI_PROP_DONTPASS, "command-preserve", 0);
	command = pci_config_get16(config_handle, PCI_CONF_COMM);
	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
	command |= (ppb_command_default & ~command_preserve);
	pci_config_put16(config_handle, PCI_CONF_COMM, command);

	/*
	 * If the device has a bus control register then program it
	 * based on the settings in the command register.
	 */
	if ((header_type  & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
		bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
		if (ppb_command_default & PCI_COMM_PARITY_DETECT)
			bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
		if (ppb_command_default & PCI_COMM_SERR_ENABLE)
			bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
		bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
		pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
	}

	/*
	 * Initialize cache-line-size configuration register if needed.
	 */
	if (ppb_set_cache_line_size_register &&
	    ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
	    "cache-line-size", 0) == 0) {
		pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
		    ppb->ppb_cache_line_size);
		n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
		if (n != 0) {
			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
			    "cache-line-size", n);
		}
	}

	/*
	 * Initialize latency timer configuration registers if needed.
	 */
	if (ppb_set_latency_timer_register &&
	    ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
	    "latency-timer", 0) == 0) {

		if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
			latency_timer = ppb->ppb_latency_timer;
			pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
			    ppb->ppb_latency_timer);
		} else {
			min_gnt = pci_config_get8(config_handle,
			    PCI_CONF_MIN_G);
			latency_timer = min_gnt * 8;
		}
		pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
		    latency_timer);
		n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
		if (n != 0) {
			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
			    "latency-timer", n);
		}
	}

	/*
	 * SPARC PCIe FMA specific
	 *
	 * Note: parent_data for parent is created only if this is sparc PCI-E
	 * platform, for which, SG take a different route to handle device
	 * errors.
	 */
	if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
		if (pcie_init_cfghdl(child) != DDI_SUCCESS) {
			pci_config_teardown(&config_handle);
			return (DDI_FAILURE);
		}
		pcie_init_dom(child);
	}

	/*
	 * Check to see if the XMITS/PCI-X workaround applies.
	 */
	n = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_NOTPROM,
	    "pcix-update-cmd-reg", -1);

	if (n != -1) {
		extern void pcix_set_cmd_reg(dev_info_t *child, uint16_t value);
		DEBUG1(DBG_INIT_CLD, child, "Turning on XMITS NCPQ "
		    "Workaround: value = %x\n", n);
		pcix_set_cmd_reg(child, n);
	}
	pci_config_teardown(&config_handle);
	return (DDI_SUCCESS);
}
Exemplo n.º 17
0
/*ARGSUSED*/
static int
ppb_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
	dev_info_t *root = ddi_root_node();
	int instance;
	ppb_devstate_t *ppb;
	dev_info_t *pdip;
	ddi_acc_handle_t config_handle;
	char *bus;

	switch (cmd) {
	case DDI_ATTACH:

		/*
		 * Make sure the "device_type" property exists.
		 */
		(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
		    "device_type", "pci");

		/*
		 * Allocate and get soft state structure.
		 */
		instance = ddi_get_instance(devi);
		if (ddi_soft_state_zalloc(ppb_state, instance) != DDI_SUCCESS)
			return (DDI_FAILURE);
		ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, instance);
		ppb->dip = devi;
		mutex_init(&ppb->ppb_mutex, NULL, MUTEX_DRIVER, NULL);
		ppb->ppb_soft_state = PCI_SOFT_STATE_CLOSED;
		if (pci_config_setup(devi, &config_handle) != DDI_SUCCESS) {
			mutex_destroy(&ppb->ppb_mutex);
			ddi_soft_state_free(ppb_state, instance);
			return (DDI_FAILURE);
		}
		ppb_pwr_setup(ppb, devi);

		if (PM_CAPABLE(ppb->ppb_pwr_p)) {
			mutex_enter(&ppb->ppb_pwr_p->pwr_mutex);

			/*
			 * Before reading config registers, make sure power is
			 * on, and remains on.
			 */
			ppb->ppb_pwr_p->pwr_fp++;

			pci_pwr_change(ppb->ppb_pwr_p,
			    ppb->ppb_pwr_p->current_lvl,
			    pci_pwr_new_lvl(ppb->ppb_pwr_p));
		}

		ppb->ppb_cache_line_size =
		    pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
		ppb->ppb_latency_timer =
		    pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);

		/*
		 * Check whether the "ranges" property is present.
		 * Otherwise create the ranges property by reading
		 * the configuration registers
		 */
		if (ddi_prop_exists(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
		    "ranges") == 0) {
			ppb_create_ranges_prop(devi, config_handle);
		}

		pci_config_teardown(&config_handle);

		if (PM_CAPABLE(ppb->ppb_pwr_p)) {
			ppb->ppb_pwr_p->pwr_fp--;

			pci_pwr_change(ppb->ppb_pwr_p,
			    ppb->ppb_pwr_p->current_lvl,
			    pci_pwr_new_lvl(ppb->ppb_pwr_p));

			mutex_exit(&ppb->ppb_pwr_p->pwr_mutex);
		}

		ppb->parent_bus = PCIE_PCIECAP_DEV_TYPE_PCI_PSEUDO;
		for (pdip = ddi_get_parent(ppb->dip); pdip && (pdip != root) &&
		    (ppb->parent_bus != PCIE_PCIECAP_DEV_TYPE_PCIE_DEV);
		    pdip = ddi_get_parent(pdip)) {
			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip,
			    DDI_PROP_DONTPASS, "device_type", &bus) !=
			    DDI_PROP_SUCCESS)
				break;

			if (strcmp(bus, "pciex") == 0)
				ppb->parent_bus =
				    PCIE_PCIECAP_DEV_TYPE_PCIE_DEV;

			ddi_prop_free(bus);
		}

		/*
		 * Initialize hotplug support on this bus.
		 */
		if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV)
			if (pcie_init(devi, NULL) != DDI_SUCCESS) {
				(void) ppb_detach(devi, DDI_DETACH);
				return (DDI_FAILURE);
			}
		else
			ppb_init_hotplug(ppb);

		DEBUG1(DBG_ATTACH, devi,
		    "ppb_attach(): this nexus %s hotplug slots\n",
		    ppb->hotplug_capable == B_TRUE ? "has":"has no");

		ppb_fm_init(ppb);
		ddi_report_dev(devi);

		return (DDI_SUCCESS);

	case DDI_RESUME:
		/*
		 * Get the soft state structure for the bridge.
		 */
		ppb = (ppb_devstate_t *)
		    ddi_get_soft_state(ppb_state, ddi_get_instance(devi));

		pci_pwr_resume(devi, ppb->ppb_pwr_p);

		return (DDI_SUCCESS);
	}
	return (DDI_FAILURE);
}