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 2005 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 		/* unregister interrupt handler */
71 		hci1394_isr_handler_fini(soft_state);
72 
73 		/* don't accept anymore commands from services layer */
74 		(void) hci1394_state_set(&soft_state->drvinfo,
75 		    HCI1394_SHUTDOWN);
76 
77 		/* Reset the OHCI HW */
78 		(void) hci1394_ohci_soft_reset(soft_state->ohci);
79 
80 		/* Flush out async DMA Q's (cancels pendingQ timeouts too) */
81 		hci1394_async_flush(soft_state->async);
82 
83 		(void) h1394_detach(&soft_state->drvinfo.di_sl_private,
84 		    DDI_DETACH);
85 
86 		/* remove the minor node */
87 		ddi_remove_minor_node(dip, "devctl");
88 
89 		/* cleanup */
90 		hci1394_detach_hardware(soft_state);
91 
92 		/* cleanup Solaris interrupt stuff */
93 		hci1394_isr_fini(soft_state);
94 
95 		/* cleanup soft state stuff */
96 		hci1394_soft_state_fini(soft_state);
97 
98 		/* free soft state */
99 		ddi_soft_state_free(hci1394_statep,
100 		    soft_state->drvinfo.di_instance);
101 
102 		TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK,
103 		    "");
104 		return (DDI_SUCCESS);
105 
106 	case DDI_SUSPEND:
107 		/* Don't allow the HW to generate any more interrupts */
108 		hci1394_ohci_intr_master_disable(soft_state->ohci);
109 
110 		/* don't accept anymore commands from services layer */
111 		(void) hci1394_state_set(&soft_state->drvinfo,
112 		    HCI1394_SHUTDOWN);
113 
114 		/* Reset the OHCI HW */
115 		(void) hci1394_ohci_soft_reset(soft_state->ohci);
116 
117 		/* Make sure async engine is ready to suspend */
118 		hci1394_async_suspend(soft_state->async);
119 
120 		(void) h1394_detach(&soft_state->drvinfo.di_sl_private,
121 		    DDI_SUSPEND);
122 
123 		TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK,
124 		    "");
125 		return (DDI_SUCCESS);
126 
127 	default:
128 		TNF_PROBE_1(hci1394_detach_fail, HCI1394_TNF_HAL_ERROR, "",
129 		    tnf_string, errmsg, "in detach default");
130 		break;
131 	}
132 
133 	TNF_PROBE_0_DEBUG(hci1394_detach_exit, HCI1394_TNF_HAL_STACK, "");
134 
135 	return (DDI_FAILURE);
136 }
137 
138 
139 void
140 hci1394_detach_hardware(hci1394_state_t *soft_state)
141 {
142 	ASSERT(soft_state != NULL);
143 	TNF_PROBE_0_DEBUG(hci1394_detach_hardware_enter, HCI1394_TNF_HAL_STACK,
144 	    "");
145 
146 	/* free up vendor specific registers */
147 	hci1394_vendor_fini(&soft_state->vendor);
148 
149 	/* cleanup isoch layer */
150 	hci1394_isoch_fini(&soft_state->isoch);
151 
152 	/* cleanup async layer */
153 	hci1394_async_fini(&soft_state->async);
154 
155 	/* Free up csr register space */
156 	hci1394_csr_fini(&soft_state->csr);
157 
158 	/* free up OpenHCI registers */
159 	hci1394_ohci_fini(&soft_state->ohci);
160 
161 	/* free up PCI config space */
162 	hci1394_pci_fini(soft_state);
163 
164 	TNF_PROBE_0_DEBUG(hci1394_detach_hardware_exit, HCI1394_TNF_HAL_STACK,
165 	    "");
166 }
167 
168 
169 /*
170  * hci1394_pci_fini()
171  *    Cleanup after a PCI init.
172  */
173 void
174 hci1394_pci_fini(hci1394_state_t *soft_state)
175 {
176 	ASSERT(soft_state != NULL);
177 	TNF_PROBE_0_DEBUG(hci1394_pci_fini_enter, HCI1394_TNF_HAL_STACK, "");
178 	pci_config_teardown(&soft_state->pci_config);
179 	TNF_PROBE_0_DEBUG(hci1394_pci_fini_exit, HCI1394_TNF_HAL_STACK, "");
180 }
181 
182 
183 /*
184  * hci1394_soft_state_fini()
185  *    Cleanup any mutex's, etc. in soft_state.
186  */
187 void
188 hci1394_soft_state_fini(hci1394_state_t *soft_state)
189 {
190 	ASSERT(soft_state != NULL);
191 	TNF_PROBE_0_DEBUG(hci1394_soft_state_fini_enter, HCI1394_TNF_HAL_STACK,
192 	    "");
193 	mutex_destroy(&soft_state->drvinfo.di_drvstate.ds_mutex);
194 	TNF_PROBE_0_DEBUG(hci1394_soft_state_fini_exit, HCI1394_TNF_HAL_STACK,
195 	    "");
196 }
197