1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * hci1394_detach.c
31  *    HBA detach() routine with associated funtions.
32  */
33 
34 #include <sys/types.h>
35 #include <sys/kmem.h>
36 #include <sys/conf.h>
37 #include <sys/ddi.h>
38 #include <sys/modctl.h>
39 #include <sys/stat.h>
40 #include <sys/sunddi.h>
41 
42 #include <sys/1394/h1394.h>
43 #include <sys/1394/adapters/hci1394.h>
44 #include <sys/1394/adapters/hci1394_extern.h>
45 
46 
47 
48 int
49 hci1394_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
50 {
51 	hci1394_state_t *soft_state;
52 
53 
54 	TNF_PROBE_0_DEBUG(hci1394_detach_enter, HCI1394_TNF_HAL_STACK, "");
55 
56 	soft_state = ddi_get_soft_state(hci1394_statep, ddi_get_instance(dip));
57 	if (soft_state == NULL) {
58 		TNF_PROBE_1(hci1394_detach_ssn_fail, HCI1394_TNF_HAL_ERROR, "",
59 		    tnf_string, errmsg, "soft_state = NULL");
60 		TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK,
61 		    "");
62 		return (DDI_FAILURE);
63 	}
64 
65 	switch (cmd) {
66 	case DDI_DETACH:
67 		/* Don't allow the HW to generate any more interrupts */
68 		hci1394_ohci_intr_master_disable(soft_state->ohci);
69 
70 		/* don't accept anymore commands from services layer */
71 		(void) hci1394_state_set(&soft_state->drvinfo,
72 		    HCI1394_SHUTDOWN);
73 
74 		/* Reset the OHCI HW */
75 		(void) hci1394_ohci_soft_reset(soft_state->ohci);
76 
77 		/* Flush out async DMA Q's (cancels pendingQ timeouts too) */
78 		hci1394_async_flush(soft_state->async);
79 
80 		(void) h1394_detach(&soft_state->drvinfo.di_sl_private,
81 		    DDI_DETACH);
82 
83 		/* remove the minor node */
84 		ddi_remove_minor_node(dip, "devctl");
85 
86 		/* cleanup */
87 		hci1394_detach_hardware(soft_state);
88 
89 		/* cleanup Solaris interrupt stuff */
90 		hci1394_isr_fini(soft_state);
91 
92 		/* cleanup soft state stuff */
93 		hci1394_soft_state_fini(soft_state);
94 
95 		/* free soft state */
96 		ddi_soft_state_free(hci1394_statep,
97 		    soft_state->drvinfo.di_instance);
98 
99 		TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK,
100 		    "");
101 		return (DDI_SUCCESS);
102 
103 	case DDI_SUSPEND:
104 		/* Don't allow the HW to generate any more interrupts */
105 		hci1394_ohci_intr_master_disable(soft_state->ohci);
106 
107 		/* don't accept anymore commands from services layer */
108 		(void) hci1394_state_set(&soft_state->drvinfo,
109 		    HCI1394_SHUTDOWN);
110 
111 		/* Reset the OHCI HW */
112 		(void) hci1394_ohci_soft_reset(soft_state->ohci);
113 
114 		/* Make sure async engine is ready to suspend */
115 		hci1394_async_suspend(soft_state->async);
116 
117 		(void) h1394_detach(&soft_state->drvinfo.di_sl_private,
118 		    DDI_SUSPEND);
119 
120 		TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK,
121 		    "");
122 		return (DDI_SUCCESS);
123 
124 	default:
125 		TNF_PROBE_1(hci1394_detach_fail, HCI1394_TNF_HAL_ERROR, "",
126 		    tnf_string, errmsg, "in detach default");
127 		break;
128 	}
129 
130 	TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK, "");
131 
132 	return (DDI_FAILURE);
133 }
134 
135 
136 void
137 hci1394_detach_hardware(hci1394_state_t *soft_state)
138 {
139 	ASSERT(soft_state != NULL);
140 	TNF_PROBE_0_DEBUG(hci1394_detach_hardware_enter, HCI1394_TNF_HAL_STACK,
141 	    "");
142 
143 	/* free up vendor specific registers */
144 	hci1394_vendor_fini(&soft_state->vendor);
145 
146 	/* cleanup isoch layer */
147 	hci1394_isoch_fini(&soft_state->isoch);
148 
149 	/* cleanup async layer */
150 	hci1394_async_fini(&soft_state->async);
151 
152 	/* Free up csr register space */
153 	hci1394_csr_fini(&soft_state->csr);
154 
155 	/* free up OpenHCI registers */
156 	hci1394_ohci_fini(&soft_state->ohci);
157 
158 	/* free up PCI config space */
159 	hci1394_pci_fini(soft_state);
160 
161 	TNF_PROBE_0_DEBUG(hci1394_detach_hardware_exit, HCI1394_TNF_HAL_STACK,
162 	    "");
163 }
164 
165 
166 /*
167  * hci1394_pci_fini()
168  *    Cleanup after a PCI init.
169  */
170 void
171 hci1394_pci_fini(hci1394_state_t *soft_state)
172 {
173 	ASSERT(soft_state != NULL);
174 	TNF_PROBE_0_DEBUG(hci1394_pci_fini_enter, HCI1394_TNF_HAL_STACK, "");
175 	pci_config_teardown(&soft_state->pci_config);
176 	TNF_PROBE_0_DEBUG(hci1394_pci_fini_exit, HCI1394_TNF_HAL_STACK, "");
177 }
178 
179 
180 /*
181  * hci1394_soft_state_fini()
182  *    Cleanup any mutex's, etc. in soft_state.
183  */
184 void
185 hci1394_soft_state_fini(hci1394_state_t *soft_state)
186 {
187 	ASSERT(soft_state != NULL);
188 	TNF_PROBE_0_DEBUG(hci1394_soft_state_fini_enter, HCI1394_TNF_HAL_STACK,
189 	    "");
190 	mutex_destroy(&soft_state->drvinfo.di_drvstate.ds_mutex);
191 	TNF_PROBE_0_DEBUG(hci1394_soft_state_fini_exit, HCI1394_TNF_HAL_STACK,
192 	    "");
193 }
194