/* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * hci1394_detach.c * HBA detach() routine with associated funtions. */ #include #include #include #include #include #include #include #include #include #include int hci1394_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) { hci1394_state_t *soft_state; TNF_PROBE_0_DEBUG(hci1394_detach_enter, HCI1394_TNF_HAL_STACK, ""); soft_state = ddi_get_soft_state(hci1394_statep, ddi_get_instance(dip)); if (soft_state == NULL) { TNF_PROBE_1(hci1394_detach_ssn_fail, HCI1394_TNF_HAL_ERROR, "", tnf_string, errmsg, "soft_state = NULL"); TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK, ""); return (DDI_FAILURE); } switch (cmd) { case DDI_DETACH: /* Don't allow the HW to generate any more interrupts */ hci1394_ohci_intr_master_disable(soft_state->ohci); hci1394_ohci_it_intr_disable(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_ir_intr_disable(soft_state->ohci, 0xFFFFFFFF); /* Clear any pending interrupts - no longer valid */ hci1394_ohci_intr_clear(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_it_intr_clear(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_ir_intr_clear(soft_state->ohci, 0xFFFFFFFF); /* Make sure we tell others on the bus we are dropping out */ (void) hci1394_ohci_phy_clr(soft_state->ohci, 4, 0xc0); ddi_put32(soft_state->ohci->ohci_reg_handle, &soft_state->ohci->ohci_regs->link_ctrl_clr, 0xFFFFFFFF); /* unregister interrupt handler */ hci1394_isr_handler_fini(soft_state); /* don't accept anymore commands from services layer */ (void) hci1394_state_set(&soft_state->drvinfo, HCI1394_SHUTDOWN); /* Do a long reset on the bus so every one knows we are gone */ (void) hci1394_ohci_bus_reset_nroot(soft_state->ohci); /* Reset the OHCI HW */ (void) hci1394_ohci_soft_reset(soft_state->ohci); /* Flush out async DMA Q's (cancels pendingQ timeouts too) */ hci1394_async_flush(soft_state->async); (void) h1394_detach(&soft_state->drvinfo.di_sl_private, DDI_DETACH); /* remove the minor node */ ddi_remove_minor_node(dip, "devctl"); /* cleanup */ hci1394_detach_hardware(soft_state); /* cleanup Solaris interrupt stuff */ hci1394_isr_fini(soft_state); /* cleanup soft state stuff */ hci1394_soft_state_fini(soft_state); /* free soft state */ ddi_soft_state_free(hci1394_statep, soft_state->drvinfo.di_instance); TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK, ""); return (DDI_SUCCESS); case DDI_SUSPEND: /* Don't allow the HW to generate any more interrupts */ hci1394_ohci_intr_master_disable(soft_state->ohci); hci1394_ohci_it_intr_disable(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_ir_intr_disable(soft_state->ohci, 0xFFFFFFFF); /* Clear any pending interrupts - no longer valid */ hci1394_ohci_intr_clear(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_it_intr_clear(soft_state->ohci, 0xFFFFFFFF); hci1394_ohci_ir_intr_clear(soft_state->ohci, 0xFFFFFFFF); /* Make sure we tell others on the bus we are dropping out */ (void) hci1394_ohci_phy_clr(soft_state->ohci, 4, 0xc0); ddi_put32(soft_state->ohci->ohci_reg_handle, &soft_state->ohci->ohci_regs->link_ctrl_clr, 0xFFFFFFFF); /* don't accept anymore commands from services layer */ (void) hci1394_state_set(&soft_state->drvinfo, HCI1394_SHUTDOWN); /* Do a long reset on the bus so every one knows we are gone */ (void) hci1394_ohci_bus_reset_nroot(soft_state->ohci); /* Reset the OHCI HW */ (void) hci1394_ohci_soft_reset(soft_state->ohci); /* Make sure async engine is ready to suspend */ hci1394_async_suspend(soft_state->async); (void) h1394_detach(&soft_state->drvinfo.di_sl_private, DDI_SUSPEND); TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK, ""); return (DDI_SUCCESS); default: TNF_PROBE_1(hci1394_detach_fail, HCI1394_TNF_HAL_ERROR, "", tnf_string, errmsg, "in detach default"); break; } TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK, ""); return (DDI_FAILURE); } void hci1394_detach_hardware(hci1394_state_t *soft_state) { ASSERT(soft_state != NULL); TNF_PROBE_0_DEBUG(hci1394_detach_hardware_enter, HCI1394_TNF_HAL_STACK, ""); /* free up vendor specific registers */ hci1394_vendor_fini(&soft_state->vendor); /* cleanup isoch layer */ hci1394_isoch_fini(&soft_state->isoch); /* cleanup async layer */ hci1394_async_fini(&soft_state->async); /* Free up csr register space */ hci1394_csr_fini(&soft_state->csr); /* free up OpenHCI registers */ hci1394_ohci_fini(&soft_state->ohci); /* free up PCI config space */ hci1394_pci_fini(soft_state); TNF_PROBE_0_DEBUG(hci1394_detach_hardware_exit, HCI1394_TNF_HAL_STACK, ""); } /* * hci1394_pci_fini() * Cleanup after a PCI init. */ void hci1394_pci_fini(hci1394_state_t *soft_state) { ASSERT(soft_state != NULL); TNF_PROBE_0_DEBUG(hci1394_pci_fini_enter, HCI1394_TNF_HAL_STACK, ""); pci_config_teardown(&soft_state->pci_config); TNF_PROBE_0_DEBUG(hci1394_pci_fini_exit, HCI1394_TNF_HAL_STACK, ""); } /* * hci1394_soft_state_fini() * Cleanup any mutex's, etc. in soft_state. */ void hci1394_soft_state_fini(hci1394_state_t *soft_state) { ASSERT(soft_state != NULL); TNF_PROBE_0_DEBUG(hci1394_soft_state_fini_enter, HCI1394_TNF_HAL_STACK, ""); mutex_destroy(&soft_state->drvinfo.di_drvstate.ds_mutex); TNF_PROBE_0_DEBUG(hci1394_soft_state_fini_exit, HCI1394_TNF_HAL_STACK, ""); }