xref: /onnv-gate/usr/src/uts/common/io/1394/nx1394.c (revision 693:1c08294a694e)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * nx1394.c
31*0Sstevel@tonic-gate  *    1394 Services Layer Nexus Support Routines
32*0Sstevel@tonic-gate  *    Routines in this file implement nexus bus_ops.
33*0Sstevel@tonic-gate  */
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <sys/conf.h>
36*0Sstevel@tonic-gate #include <sys/ddi.h>
37*0Sstevel@tonic-gate #include <sys/modctl.h>
38*0Sstevel@tonic-gate #include <sys/sunddi.h>
39*0Sstevel@tonic-gate #include <sys/cmn_err.h>
40*0Sstevel@tonic-gate #include <sys/types.h>
41*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #include <sys/tnf_probe.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include <sys/1394/t1394.h>
46*0Sstevel@tonic-gate #include <sys/1394/s1394.h>
47*0Sstevel@tonic-gate #include <sys/1394/h1394.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate static int nx1394_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
50*0Sstevel@tonic-gate     ddi_dma_attr_t *attr, int (*waitfnp)(caddr_t), caddr_t arg,
51*0Sstevel@tonic-gate     ddi_dma_handle_t *handlep);
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate static int nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
54*0Sstevel@tonic-gate     void *arg, void *result);
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate static int nx1394_get_event_cookie(dev_info_t *dip, dev_info_t *rdip,
57*0Sstevel@tonic-gate     char *name, ddi_eventcookie_t *event_cookiep);
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate static int nx1394_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
60*0Sstevel@tonic-gate     ddi_eventcookie_t eventhdl, void (*callback)(), void *arg,
61*0Sstevel@tonic-gate     ddi_callback_id_t *cb_id);
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate static int nx1394_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id);
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate static int nx1394_post_event(dev_info_t *dip, dev_info_t *rdip,
66*0Sstevel@tonic-gate     ddi_eventcookie_t eventhdl, void *impl_data);
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate struct bus_ops nx1394_busops = {
69*0Sstevel@tonic-gate 	BUSO_REV,
70*0Sstevel@tonic-gate 	nullbusmap,			/* bus_map */
71*0Sstevel@tonic-gate 	NULL,				/* bus_get_intrspec */
72*0Sstevel@tonic-gate 	NULL,				/* bus_add_intrspec */
73*0Sstevel@tonic-gate 	NULL,				/* bus_remove_intrspec */
74*0Sstevel@tonic-gate 	i_ddi_map_fault,		/* XXXX bus_map_fault */
75*0Sstevel@tonic-gate 	ddi_dma_map,			/* bus_dma_map */
76*0Sstevel@tonic-gate 	nx1394_dma_allochdl,
77*0Sstevel@tonic-gate 	ddi_dma_freehdl,
78*0Sstevel@tonic-gate 	ddi_dma_bindhdl,
79*0Sstevel@tonic-gate 	ddi_dma_unbindhdl,
80*0Sstevel@tonic-gate 	ddi_dma_flush,
81*0Sstevel@tonic-gate 	ddi_dma_win,
82*0Sstevel@tonic-gate 	ddi_dma_mctl,			/* bus_dma_ctl */
83*0Sstevel@tonic-gate 	nx1394_bus_ctl,			/* bus_ctl */
84*0Sstevel@tonic-gate 	ddi_bus_prop_op,		/* bus_prop_op */
85*0Sstevel@tonic-gate 	nx1394_get_event_cookie,	/* (*bus_get_eventcookie() */
86*0Sstevel@tonic-gate 	nx1394_add_eventcall,		/* (*bus_add_eventcall)(); */
87*0Sstevel@tonic-gate 	nx1394_remove_eventcall,	/* (*bus_remove_eventcall)(); */
88*0Sstevel@tonic-gate 	nx1394_post_event,		/* (*bus_post_event)(); */
89*0Sstevel@tonic-gate 	0,				/* (*interrupt control)();	*/
90*0Sstevel@tonic-gate 	0,				/* (*bus_config)();	*/
91*0Sstevel@tonic-gate 	0,				/* (*bus_unconfig)();	*/
92*0Sstevel@tonic-gate 	0,				/* (*bus_fm_init)();	*/
93*0Sstevel@tonic-gate 	0,				/* (*bus_fm_fini)();	*/
94*0Sstevel@tonic-gate 	0,				/* (*bus_fm_access_enter)();	*/
95*0Sstevel@tonic-gate 	0,				/* (*bus_fm_access_exit)();	*/
96*0Sstevel@tonic-gate 	0,				/* (*bus_power)();	*/
97*0Sstevel@tonic-gate 	i_ddi_intr_ops			/* (*bus_intr_op)();	*/
98*0Sstevel@tonic-gate };
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate /*
101*0Sstevel@tonic-gate  * removal/insertion/reset events
102*0Sstevel@tonic-gate  */
103*0Sstevel@tonic-gate #define	NX1394_EVENT_TAG_HOT_REMOVAL		0
104*0Sstevel@tonic-gate #define	NX1394_EVENT_TAG_HOT_INSERTION		1
105*0Sstevel@tonic-gate #define	NX1394_EVENT_TAG_BUS_RESET		2
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate static ndi_event_definition_t nx1394_event_defs[] = {
108*0Sstevel@tonic-gate 	{NX1394_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
109*0Sstevel@tonic-gate 	    NDI_EVENT_POST_TO_TGT},
110*0Sstevel@tonic-gate 	{NX1394_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
111*0Sstevel@tonic-gate 	    NDI_EVENT_POST_TO_TGT},
112*0Sstevel@tonic-gate 	{NX1394_EVENT_TAG_BUS_RESET, DDI_DEVI_BUS_RESET_EVENT, EPL_KERNEL,
113*0Sstevel@tonic-gate 	    NDI_EVENT_POST_TO_ALL},
114*0Sstevel@tonic-gate };
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate #define	NX1394_N_EVENTS \
117*0Sstevel@tonic-gate 	(sizeof (nx1394_event_defs) / sizeof (ndi_event_definition_t))
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate static ndi_event_set_t nx1394_events = {
120*0Sstevel@tonic-gate 	NDI_EVENTS_REV1, NX1394_N_EVENTS, nx1394_event_defs
121*0Sstevel@tonic-gate };
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate /*
124*0Sstevel@tonic-gate  * nx1394_bus_ctl()
125*0Sstevel@tonic-gate  *    This routine implements nexus bus ctl operations. Of importance are
126*0Sstevel@tonic-gate  *    DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD
127*0Sstevel@tonic-gate  *    and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup
128*0Sstevel@tonic-gate  *    reg property on the child node and builds and sets the name
129*0Sstevel@tonic-gate  *    (name is of the form GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where
130*0Sstevel@tonic-gate  *    GGGGGGGGGGGGGGGG is the GUID and AAAAAAAAAAAA is the optional unit
131*0Sstevel@tonic-gate  *    address).
132*0Sstevel@tonic-gate  */
133*0Sstevel@tonic-gate static int
nx1394_bus_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)134*0Sstevel@tonic-gate nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
135*0Sstevel@tonic-gate     void *result)
136*0Sstevel@tonic-gate {
137*0Sstevel@tonic-gate 	int status;
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(nx1394_bus_ctl_enter, S1394_TNF_SL_NEXUS_STACK, "");
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	switch (op) {
142*0Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV: {
143*0Sstevel@tonic-gate 		dev_info_t *pdip = ddi_get_parent(rdip);
144*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "?%s%d at %s%d",
145*0Sstevel@tonic-gate 		    ddi_node_name(rdip), ddi_get_instance(rdip),
146*0Sstevel@tonic-gate 		    ddi_node_name(pdip), ddi_get_instance(pdip));
147*0Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
148*0Sstevel@tonic-gate 		    "");
149*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
150*0Sstevel@tonic-gate 	}
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD: {
153*0Sstevel@tonic-gate 		dev_info_t *ocdip, *cdip = (dev_info_t *)arg;
154*0Sstevel@tonic-gate 		dev_info_t *pdip = ddi_get_parent(cdip);
155*0Sstevel@tonic-gate 		int reglen, i;
156*0Sstevel@tonic-gate 		uint32_t *regptr;
157*0Sstevel@tonic-gate 		char addr[MAXNAMELEN];
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 		TNF_PROBE_1(nx1394_bus_ctl_init_child,
160*0Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque, dip, cdip);
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 		i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
163*0Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg", (int **)&regptr,
164*0Sstevel@tonic-gate 		    (uint_t *)&reglen);
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 		if (i != DDI_PROP_SUCCESS) {
167*0Sstevel@tonic-gate 			cmn_err(CE_NOTE, "!%s(%d): \"reg\" property not found",
168*0Sstevel@tonic-gate 			    ddi_node_name(cdip), ddi_get_instance(cdip));
169*0Sstevel@tonic-gate 			TNF_PROBE_2(nx1394_bus_ctl,
170*0Sstevel@tonic-gate 			    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg,
171*0Sstevel@tonic-gate 			    "Reg property not found", tnf_int, reason, i);
172*0Sstevel@tonic-gate 			TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
173*0Sstevel@tonic-gate 			    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op,
174*0Sstevel@tonic-gate 			    "initchild");
175*0Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
176*0Sstevel@tonic-gate 		}
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 		ASSERT(reglen != 0);
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 		/*
181*0Sstevel@tonic-gate 		 * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA]
182*0Sstevel@tonic-gate 		 */
183*0Sstevel@tonic-gate 		if (regptr[2] || regptr[3]) {
184*0Sstevel@tonic-gate 			(void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
185*0Sstevel@tonic-gate 			    regptr[1], regptr[2], regptr[3]);
186*0Sstevel@tonic-gate 		} else {
187*0Sstevel@tonic-gate 			(void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
188*0Sstevel@tonic-gate 		}
189*0Sstevel@tonic-gate 		ddi_prop_free(regptr);
190*0Sstevel@tonic-gate 		ddi_set_name_addr(cdip, addr);
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 		/*
193*0Sstevel@tonic-gate 		 * Check for a node with the same name & addr as the current
194*0Sstevel@tonic-gate 		 * node. If such a node exists, return failure.
195*0Sstevel@tonic-gate 		 */
196*0Sstevel@tonic-gate 		if ((ocdip = ndi_devi_find(pdip, ddi_node_name(cdip), addr)) !=
197*0Sstevel@tonic-gate 		    NULL && ocdip != cdip) {
198*0Sstevel@tonic-gate 			cmn_err(CE_NOTE,
199*0Sstevel@tonic-gate 			    "!%s(%d): Duplicate dev_info node found %s@%s",
200*0Sstevel@tonic-gate 			    ddi_node_name(cdip), ddi_get_instance(cdip),
201*0Sstevel@tonic-gate 			    ddi_node_name(ocdip), addr);
202*0Sstevel@tonic-gate 			TNF_PROBE_1(nx1394_bus_ctl,
203*0Sstevel@tonic-gate 			    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg,
204*0Sstevel@tonic-gate 			    "Duplicate nodes");
205*0Sstevel@tonic-gate 			TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
206*0Sstevel@tonic-gate 			    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op,
207*0Sstevel@tonic-gate 			    "initchild");
208*0Sstevel@tonic-gate 			ddi_set_name_addr(cdip, NULL);
209*0Sstevel@tonic-gate 			return (DDI_NOT_WELL_FORMED);
210*0Sstevel@tonic-gate 		}
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 		/*
213*0Sstevel@tonic-gate 		 * If HAL (parent dip) has "active-dma-flush" property, then
214*0Sstevel@tonic-gate 		 * add property to child as well.  Workaround for active
215*0Sstevel@tonic-gate 		 * context flushing bug in Schizo rev 2.1 and 2.2.
216*0Sstevel@tonic-gate 		 */
217*0Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
218*0Sstevel@tonic-gate 		    "active-dma-flush") != 0) {
219*0Sstevel@tonic-gate 			status = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
220*0Sstevel@tonic-gate 			    "active-dma-flush", 1);
221*0Sstevel@tonic-gate 			if (status != NDI_SUCCESS) {
222*0Sstevel@tonic-gate 				cmn_err(CE_NOTE, "!%s(%d): Unable to add "
223*0Sstevel@tonic-gate 				    "\"active-dma-flush\" property",
224*0Sstevel@tonic-gate 				    ddi_node_name(cdip),
225*0Sstevel@tonic-gate 				    ddi_get_instance(cdip));
226*0Sstevel@tonic-gate 				TNF_PROBE_1(nx1394_bus_ctl,
227*0Sstevel@tonic-gate 				    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string,
228*0Sstevel@tonic-gate 				    msg, "Unable to add \"active-dma-flush\" "
229*0Sstevel@tonic-gate 				    "property");
230*0Sstevel@tonic-gate 				TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
231*0Sstevel@tonic-gate 				    S1394_TNF_SL_NEXUS_STACK, "", tnf_string,
232*0Sstevel@tonic-gate 				    op, "initchild");
233*0Sstevel@tonic-gate 				ddi_set_name_addr(cdip, NULL);
234*0Sstevel@tonic-gate 				return (DDI_NOT_WELL_FORMED);
235*0Sstevel@tonic-gate 			}
236*0Sstevel@tonic-gate 		}
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
239*0Sstevel@tonic-gate 		    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild");
240*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
241*0Sstevel@tonic-gate 	}
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD: {
244*0Sstevel@tonic-gate 		ddi_prop_remove_all((dev_info_t *)arg);
245*0Sstevel@tonic-gate 		ddi_set_name_addr((dev_info_t *)arg, NULL);
246*0Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
247*0Sstevel@tonic-gate 		    "", tnf_string, op, "uninitchild");
248*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
249*0Sstevel@tonic-gate 	}
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN: {
252*0Sstevel@tonic-gate 		status = ddi_ctlops(dip, rdip, op, arg, result);
253*0Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
254*0Sstevel@tonic-gate 		    "", tnf_string, op, "iomin");
255*0Sstevel@tonic-gate 		return (status);
256*0Sstevel@tonic-gate 	}
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	case DDI_CTLOPS_POWER: {
259*0Sstevel@tonic-gate 		return (DDI_SUCCESS);
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	/*
263*0Sstevel@tonic-gate 	 * These ops correspond to functions that "shouldn't" be called
264*0Sstevel@tonic-gate 	 * by a 1394 client driver.
265*0Sstevel@tonic-gate 	 */
266*0Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
267*0Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
268*0Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
269*0Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
270*0Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
271*0Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
272*0Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
273*0Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
274*0Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK: {
275*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "!%s(%d): invalid op (%d) from %s(%d)",
276*0Sstevel@tonic-gate 		    ddi_node_name(dip), ddi_get_instance(dip),
277*0Sstevel@tonic-gate 		    op, ddi_node_name(rdip), ddi_get_instance(rdip));
278*0Sstevel@tonic-gate 		TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "",
279*0Sstevel@tonic-gate 		    tnf_string, msg, "invalid op", tnf_int, op, op);
280*0Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
281*0Sstevel@tonic-gate 		    "");
282*0Sstevel@tonic-gate 		return (DDI_FAILURE);
283*0Sstevel@tonic-gate 	}
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	/*
286*0Sstevel@tonic-gate 	 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
287*0Sstevel@tonic-gate 	 */
288*0Sstevel@tonic-gate 	default: {
289*0Sstevel@tonic-gate 		status = ddi_ctlops(dip, rdip, op, arg, result);
290*0Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
291*0Sstevel@tonic-gate 		    "");
292*0Sstevel@tonic-gate 		return (status);
293*0Sstevel@tonic-gate 	}
294*0Sstevel@tonic-gate 	}
295*0Sstevel@tonic-gate }
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate /*
298*0Sstevel@tonic-gate  * nx1394_dma_allochdl()
299*0Sstevel@tonic-gate  *    Merges the ddi_dma_attr_t passed in by the target (using
300*0Sstevel@tonic-gate  *    ddi_dma_alloc_handle() call) with that of the hal and passes the alloc
301*0Sstevel@tonic-gate  *    handle request up the device by calling ddi_dma_allochdl().
302*0Sstevel@tonic-gate  */
303*0Sstevel@tonic-gate static int
nx1394_dma_allochdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * attr,int (* waitfnp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)304*0Sstevel@tonic-gate nx1394_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
305*0Sstevel@tonic-gate     int (*waitfnp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
306*0Sstevel@tonic-gate {
307*0Sstevel@tonic-gate 	s1394_hal_t *hal;
308*0Sstevel@tonic-gate 	ddi_dma_attr_t *hal_attr;
309*0Sstevel@tonic-gate 	int status;
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	_NOTE(SCHEME_PROTECTS_DATA("unique (per thread)", ddi_dma_attr_t))
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(nx1394_dma_allochdl_enter, S1394_TNF_SL_NEXUS_STACK,
314*0Sstevel@tonic-gate 	    "");
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	/*
317*0Sstevel@tonic-gate 	 * If hal calls ddi_dma_alloc_handle, dip == rdip == hal dip.
318*0Sstevel@tonic-gate 	 * Unfortunately, we cannot verify this (by way of looking up for hal
319*0Sstevel@tonic-gate 	 * dip) here because h1394_attach() may happen much later.
320*0Sstevel@tonic-gate 	 */
321*0Sstevel@tonic-gate 	if (dip != rdip) {
322*0Sstevel@tonic-gate 		hal = s1394_dip_to_hal(ddi_get_parent(rdip));
323*0Sstevel@tonic-gate 		ASSERT(hal);
324*0Sstevel@tonic-gate 		hal_attr = &hal->halinfo.dma_attr;
325*0Sstevel@tonic-gate 		ASSERT(hal_attr);
326*0Sstevel@tonic-gate 		ddi_dma_attr_merge(attr, hal_attr);
327*0Sstevel@tonic-gate 	}
328*0Sstevel@tonic-gate 	status = ddi_dma_allochdl(dip, rdip, attr, waitfnp, arg, handlep);
329*0Sstevel@tonic-gate 	TNF_PROBE_1_DEBUG(nx1394_dma_allochdl_exit, S1394_TNF_SL_NEXUS_STACK,
330*0Sstevel@tonic-gate 	    "", tnf_int, status, status);
331*0Sstevel@tonic-gate 	return (status);
332*0Sstevel@tonic-gate }
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate /*
335*0Sstevel@tonic-gate  * nx1394_get_event_cookie()
336*0Sstevel@tonic-gate  *    Called when a child node calls ddi_get_eventcookie().
337*0Sstevel@tonic-gate  *    Returns event cookie corresponding to event "name".
338*0Sstevel@tonic-gate  */
339*0Sstevel@tonic-gate static int
nx1394_get_event_cookie(dev_info_t * dip,dev_info_t * rdip,char * name,ddi_eventcookie_t * event_cookiep)340*0Sstevel@tonic-gate nx1394_get_event_cookie(dev_info_t *dip, dev_info_t *rdip, char *name,
341*0Sstevel@tonic-gate     ddi_eventcookie_t *event_cookiep)
342*0Sstevel@tonic-gate {
343*0Sstevel@tonic-gate 	int ret;
344*0Sstevel@tonic-gate 	s1394_hal_t *hal;
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	TNF_PROBE_1_DEBUG(nx1394_get_event_cookie_enter,
347*0Sstevel@tonic-gate 	    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, name, name);
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	hal = s1394_dip_to_hal(dip);
350*0Sstevel@tonic-gate 	ASSERT(hal);
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	ret = ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl,
353*0Sstevel@tonic-gate 	    rdip, name, event_cookiep, 0);
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	TNF_PROBE_4_DEBUG(nx1394_get_event_cookie_exit,
356*0Sstevel@tonic-gate 	    S1394_TNF_SL_NEXUS_STACK, "", tnf_opaque, parent_dip, (void *)dip,
357*0Sstevel@tonic-gate 	    tnf_opaque, requestor_dip, (void *)rdip, tnf_string, event_name,
358*0Sstevel@tonic-gate 	    name, tnf_int, request_status, ret);
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	return (ret);
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate }
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate /*
365*0Sstevel@tonic-gate  * nx1394_add_eventcall()
366*0Sstevel@tonic-gate  *    This gets called when a child node calls ddi_add_eventcall(). Registers
367*0Sstevel@tonic-gate  *    the specified callback for the requested event cookie with the ndi
368*0Sstevel@tonic-gate  *    event framework.
369*0Sstevel@tonic-gate  *    dip is the hal dip. This routine calls ndi_event_add_callback(),
370*0Sstevel@tonic-gate  *    allowing requests for events we don't generate to pass up the tree.
371*0Sstevel@tonic-gate  */
372*0Sstevel@tonic-gate static int
nx1394_add_eventcall(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void (* callback)(),void * arg,ddi_callback_id_t * cb_id)373*0Sstevel@tonic-gate nx1394_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
374*0Sstevel@tonic-gate     ddi_eventcookie_t cookie, void (*callback)(), void *arg,
375*0Sstevel@tonic-gate     ddi_callback_id_t *cb_id)
376*0Sstevel@tonic-gate {
377*0Sstevel@tonic-gate 	int ret;
378*0Sstevel@tonic-gate 	s1394_hal_t *hal;
379*0Sstevel@tonic-gate #if defined(DEBUG)
380*0Sstevel@tonic-gate 	char *event_name = NULL;
381*0Sstevel@tonic-gate #endif
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 	hal = s1394_dip_to_hal(dip);
384*0Sstevel@tonic-gate 	ASSERT(hal);
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(nx1394_add_eventcall_enter, S1394_TNF_SL_NEXUS_STACK,
387*0Sstevel@tonic-gate 	    "");
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	ret = ndi_event_add_callback(hal->hal_ndi_event_hdl, rdip, cookie,
390*0Sstevel@tonic-gate 	    callback, arg, NDI_NOSLEEP, cb_id);
391*0Sstevel@tonic-gate #if defined(DEBUG)
392*0Sstevel@tonic-gate 	event_name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
393*0Sstevel@tonic-gate 	if (event_name == NULL)
394*0Sstevel@tonic-gate 	    event_name = "";
395*0Sstevel@tonic-gate #endif
396*0Sstevel@tonic-gate 	TNF_PROBE_4_DEBUG(nx1394_add_eventcall_exit, S1394_TNF_SL_NEXUS_STACK,
397*0Sstevel@tonic-gate 	    "", tnf_opaque, parent_dip, (void *)dip, tnf_opaque, requestor_dip,
398*0Sstevel@tonic-gate 	    (void *)rdip, tnf_string, event_name, event_name, tnf_int,
399*0Sstevel@tonic-gate 	    request_status, ret);
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 	return (ret);
402*0Sstevel@tonic-gate }
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate /*
405*0Sstevel@tonic-gate  * nx1394_remove_eventcall()
406*0Sstevel@tonic-gate  *    Called as a result of a child node calling ddi_remove_eventcall().
407*0Sstevel@tonic-gate  *    Unregisters the callback corresponding to the callback id passed in.
408*0Sstevel@tonic-gate  */
409*0Sstevel@tonic-gate static int
nx1394_remove_eventcall(dev_info_t * dip,ddi_callback_id_t cb_id)410*0Sstevel@tonic-gate nx1394_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
411*0Sstevel@tonic-gate {
412*0Sstevel@tonic-gate 	int ret;
413*0Sstevel@tonic-gate 	s1394_hal_t *hal;
414*0Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
415*0Sstevel@tonic-gate #if defined(DEBUG)
416*0Sstevel@tonic-gate 	char *event_name = NULL;
417*0Sstevel@tonic-gate #endif
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate 	ASSERT(cb_id);
420*0Sstevel@tonic-gate 	cookie = ((ndi_event_callbacks_t *)cb_id)->ndi_evtcb_cookie;
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	hal = s1394_dip_to_hal(dip);
423*0Sstevel@tonic-gate 	ASSERT(hal);
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(nx1394_remove_eventcall_enter,
426*0Sstevel@tonic-gate 	    S1394_TNF_SL_NEXUS_STACK, "");
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 	ret = ndi_event_remove_callback(hal->hal_ndi_event_hdl, cb_id);
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate #if defined(DEBUG)
431*0Sstevel@tonic-gate 	event_name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
432*0Sstevel@tonic-gate 	if (event_name == NULL)
433*0Sstevel@tonic-gate 	    event_name = "";
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	TNF_PROBE_4_DEBUG(nx1394_remove_eventcall_exit,
436*0Sstevel@tonic-gate 	    S1394_TNF_SL_NEXUS_STACK, "", tnf_opaque, parent_dip, (void *)dip,
437*0Sstevel@tonic-gate 	    tnf_opaque, callback_id, (void *)cb_id, tnf_string, event_name,
438*0Sstevel@tonic-gate 	    event_name, tnf_int, request_status, ret);
439*0Sstevel@tonic-gate #endif
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	return (ret);
442*0Sstevel@tonic-gate }
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate /*
445*0Sstevel@tonic-gate  * nx1394_post_event()
446*0Sstevel@tonic-gate  *    Called when a child node calls ddi_post_event. If the event is one of
447*0Sstevel@tonic-gate  *    the events supported by us (bus reset/insert/remove, for now), builds
448*0Sstevel@tonic-gate  *    a t1394_localinfo_t structure and calls ndi_event_run_callbacks(). This
449*0Sstevel@tonic-gate  *    will result in all registered callbacks being invoked with
450*0Sstevel@tonic-gate  *    t1394_localinfo_t as the impl_data. (see ddi_add_eventcall for callback
451*0Sstevel@tonic-gate  *    arguments.) If the event is not defined by us, the request is
452*0Sstevel@tonic-gate  *    propagated up the device tree by calling ndi_post_event().
453*0Sstevel@tonic-gate  */
454*0Sstevel@tonic-gate static int
nx1394_post_event(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void * impl_data)455*0Sstevel@tonic-gate nx1394_post_event(dev_info_t *dip, dev_info_t *rdip, ddi_eventcookie_t cookie,
456*0Sstevel@tonic-gate     void *impl_data)
457*0Sstevel@tonic-gate {
458*0Sstevel@tonic-gate 	int ret;
459*0Sstevel@tonic-gate 	char *name;
460*0Sstevel@tonic-gate 	s1394_hal_t *hal;
461*0Sstevel@tonic-gate 	t1394_localinfo_t localinfo;
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 	hal = s1394_dip_to_hal(dip);
464*0Sstevel@tonic-gate 	ASSERT(hal);
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(nx1394_post_event_enter, S1394_TNF_SL_NEXUS_STACK,
467*0Sstevel@tonic-gate 	    "");
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 	name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
470*0Sstevel@tonic-gate 	/* name is NULL if we don't generate the event */
471*0Sstevel@tonic-gate 	if (name != NULL) {
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 		mutex_enter(&hal->topology_tree_mutex);
474*0Sstevel@tonic-gate 		localinfo.bus_generation = hal->generation_count;
475*0Sstevel@tonic-gate 		localinfo.local_nodeID = hal->node_id;
476*0Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
477*0Sstevel@tonic-gate 		impl_data = &localinfo;
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 		ret = ndi_event_run_callbacks(hal->hal_ndi_event_hdl,
480*0Sstevel@tonic-gate 		    rdip, cookie, impl_data);
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 		TNF_PROBE_4_DEBUG(nx1394_post_event_exit,
483*0Sstevel@tonic-gate 		    S1394_TNF_SL_NEXUS_STACK, "", tnf_opaque, parent_dip,
484*0Sstevel@tonic-gate 		    (void *)dip, tnf_opaque, requestor_dip, (void *)rdip,
485*0Sstevel@tonic-gate 		    tnf_string, event_name, name, tnf_int, request_status, ret);
486*0Sstevel@tonic-gate 		return (ret);
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	} else {
489*0Sstevel@tonic-gate 		ret = ndi_post_event(ddi_get_parent(dip), rdip, cookie,
490*0Sstevel@tonic-gate 		    impl_data);
491*0Sstevel@tonic-gate 		TNF_PROBE_2_DEBUG(nx1394_post_event_exit,
492*0Sstevel@tonic-gate 		    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, msg,
493*0Sstevel@tonic-gate 		    "Not our event", tnf_int, ret, ret);
494*0Sstevel@tonic-gate 		return (ret);
495*0Sstevel@tonic-gate 	}
496*0Sstevel@tonic-gate }
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate /*
499*0Sstevel@tonic-gate  * nx1394_define_events()
500*0Sstevel@tonic-gate  *    Allocates event handle for the hal dip and binds event set to it.
501*0Sstevel@tonic-gate  */
502*0Sstevel@tonic-gate int
nx1394_define_events(s1394_hal_t * hal)503*0Sstevel@tonic-gate nx1394_define_events(s1394_hal_t *hal)
504*0Sstevel@tonic-gate {
505*0Sstevel@tonic-gate 	int ret;
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(nx1394_define_events_enter, S1394_TNF_SL_NEXUS_STACK,
508*0Sstevel@tonic-gate 	    "");
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	/* get event handle */
511*0Sstevel@tonic-gate 	ret = ndi_event_alloc_hdl(hal->halinfo.dip, hal->halinfo.hw_interrupt,
512*0Sstevel@tonic-gate 	    &hal->hal_ndi_event_hdl, NDI_SLEEP);
513*0Sstevel@tonic-gate 	if (ret != NDI_SUCCESS) {
514*0Sstevel@tonic-gate 		TNF_PROBE_1(nx1394_define_events_alloc_fail,
515*0Sstevel@tonic-gate 		    S1394_TNF_SL_NEXUS_ERROR, "", tnf_int, ret, ret);
516*0Sstevel@tonic-gate 	} else {
517*0Sstevel@tonic-gate 		/* and bind to it */
518*0Sstevel@tonic-gate 		ret = ndi_event_bind_set(hal->hal_ndi_event_hdl, &nx1394_events,
519*0Sstevel@tonic-gate 		    NDI_SLEEP);
520*0Sstevel@tonic-gate 		if (ret != NDI_SUCCESS) {
521*0Sstevel@tonic-gate 			TNF_PROBE_1(nx1394_define_events_bind_fail,
522*0Sstevel@tonic-gate 			    S1394_TNF_SL_NEXUS_ERROR, "", tnf_int, ret, ret);
523*0Sstevel@tonic-gate 			(void) ndi_event_free_hdl(hal->hal_ndi_event_hdl);
524*0Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(nx1394_define_events_exit,
525*0Sstevel@tonic-gate 			    S1394_TNF_SL_NEXUS_STACK, "");
526*0Sstevel@tonic-gate 			return (DDI_FAILURE);
527*0Sstevel@tonic-gate 		}
528*0Sstevel@tonic-gate 	}
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(nx1394_define_events_exit, S1394_TNF_SL_NEXUS_STACK,
531*0Sstevel@tonic-gate 	    "");
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
534*0Sstevel@tonic-gate }
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate /*
537*0Sstevel@tonic-gate  * nx1394_undefine_events()
538*0Sstevel@tonic-gate  *    Unbinds event set bound to the hal and frees the event handle.
539*0Sstevel@tonic-gate  */
540*0Sstevel@tonic-gate void
nx1394_undefine_events(s1394_hal_t * hal)541*0Sstevel@tonic-gate nx1394_undefine_events(s1394_hal_t *hal)
542*0Sstevel@tonic-gate {
543*0Sstevel@tonic-gate 	int ret;
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(nx1394_undefine_events_enter,
546*0Sstevel@tonic-gate 	    S1394_TNF_SL_NEXUS_STACK, "");
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 	ret = ndi_event_unbind_set(hal->hal_ndi_event_hdl, &nx1394_events,
549*0Sstevel@tonic-gate 	    NDI_SLEEP);
550*0Sstevel@tonic-gate 	if (ret != NDI_SUCCESS) {
551*0Sstevel@tonic-gate 		TNF_PROBE_1(nx1394_undefine_events_unbind_fail,
552*0Sstevel@tonic-gate 		    S1394_TNF_SL_NEXUS_ERROR, "", tnf_int, ret, ret);
553*0Sstevel@tonic-gate 	} else {
554*0Sstevel@tonic-gate 		ret = ndi_event_free_hdl(hal->hal_ndi_event_hdl);
555*0Sstevel@tonic-gate 		if (ret != NDI_SUCCESS) {
556*0Sstevel@tonic-gate 			TNF_PROBE_1(nx1394_undefine_events_free_hdl_fail,
557*0Sstevel@tonic-gate 			    S1394_TNF_SL_NEXUS_ERROR, "", tnf_int, ret, ret);
558*0Sstevel@tonic-gate 		}
559*0Sstevel@tonic-gate 	}
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(nx1394_undefine_events_exit,
562*0Sstevel@tonic-gate 	    S1394_TNF_SL_NEXUS_STACK, "");
563*0Sstevel@tonic-gate }
564