bmake-ify mega_sas
[unleashed.git] / usr / src / uts / common / io / 1394 / nx1394.c
blob1c11dbbddc5760c3cb12c06c6a27794ef907b74b
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
31 * nx1394.c
32 * 1394 Services Layer Nexus Support Routines
33 * Routines in this file implement nexus bus_ops.
36 #include <sys/conf.h>
37 #include <sys/ddi.h>
38 #include <sys/modctl.h>
39 #include <sys/sunddi.h>
40 #include <sys/cmn_err.h>
41 #include <sys/types.h>
42 #include <sys/ddi_impldefs.h>
44 #include <sys/tnf_probe.h>
46 #include <sys/1394/t1394.h>
47 #include <sys/1394/s1394.h>
48 #include <sys/1394/h1394.h>
50 static int nx1394_dma_allochdl(dev_info_t *dip, dev_info_t *rdip,
51 ddi_dma_attr_t *attr, int (*waitfnp)(caddr_t), caddr_t arg,
52 ddi_dma_handle_t *handlep);
54 static int nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
55 void *arg, void *result);
57 static int nx1394_get_event_cookie(dev_info_t *dip, dev_info_t *rdip,
58 char *name, ddi_eventcookie_t *event_cookiep);
60 static int nx1394_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
61 ddi_eventcookie_t eventhdl, void (*callback)(), void *arg,
62 ddi_callback_id_t *cb_id);
64 static int nx1394_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id);
66 static int nx1394_post_event(dev_info_t *dip, dev_info_t *rdip,
67 ddi_eventcookie_t eventhdl, void *impl_data);
69 struct bus_ops nx1394_busops = {
70 BUSO_REV,
71 nullbusmap, /* bus_map */
72 NULL, /* bus_get_intrspec */
73 NULL, /* bus_add_intrspec */
74 NULL, /* bus_remove_intrspec */
75 i_ddi_map_fault, /* XXXX bus_map_fault */
76 NULL, /* bus_dma_map */
77 nx1394_dma_allochdl,
78 ddi_dma_freehdl,
79 ddi_dma_bindhdl,
80 ddi_dma_unbindhdl,
81 ddi_dma_flush,
82 ddi_dma_win,
83 ddi_dma_mctl, /* bus_dma_ctl */
84 nx1394_bus_ctl, /* bus_ctl */
85 ddi_bus_prop_op, /* bus_prop_op */
86 nx1394_get_event_cookie, /* (*bus_get_eventcookie() */
87 nx1394_add_eventcall, /* (*bus_add_eventcall)(); */
88 nx1394_remove_eventcall, /* (*bus_remove_eventcall)(); */
89 nx1394_post_event, /* (*bus_post_event)(); */
90 0, /* (*interrupt control)(); */
91 0, /* (*bus_config)(); */
92 0, /* (*bus_unconfig)(); */
93 0, /* (*bus_fm_init)(); */
94 0, /* (*bus_fm_fini)(); */
95 0, /* (*bus_fm_access_enter)(); */
96 0, /* (*bus_fm_access_exit)(); */
97 0, /* (*bus_power)(); */
98 i_ddi_intr_ops /* (*bus_intr_op)(); */
102 * removal/insertion/reset events
104 #define NX1394_EVENT_TAG_HOT_REMOVAL 0
105 #define NX1394_EVENT_TAG_HOT_INSERTION 1
106 #define NX1394_EVENT_TAG_BUS_RESET 2
108 static ndi_event_definition_t nx1394_event_defs[] = {
109 {NX1394_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
110 NDI_EVENT_POST_TO_TGT},
111 {NX1394_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
112 NDI_EVENT_POST_TO_TGT},
113 {NX1394_EVENT_TAG_BUS_RESET, DDI_DEVI_BUS_RESET_EVENT, EPL_KERNEL,
114 NDI_EVENT_POST_TO_ALL},
117 #define NX1394_N_EVENTS \
118 (sizeof (nx1394_event_defs) / sizeof (ndi_event_definition_t))
120 static ndi_event_set_t nx1394_events = {
121 NDI_EVENTS_REV1, NX1394_N_EVENTS, nx1394_event_defs
125 * nx1394_bus_ctl()
126 * This routine implements nexus bus ctl operations. Of importance are
127 * DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD
128 * and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup
129 * reg property on the child node and builds and sets the name
130 * (name is of the form GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where
131 * GGGGGGGGGGGGGGGG is the GUID and AAAAAAAAAAAA is the optional unit
132 * address).
134 static int
135 nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
136 void *result)
138 int status;
140 switch (op) {
141 case DDI_CTLOPS_REPORTDEV: {
142 dev_info_t *pdip = ddi_get_parent(rdip);
143 cmn_err(CE_CONT, "?%s%d at %s%d",
144 ddi_node_name(rdip), ddi_get_instance(rdip),
145 ddi_node_name(pdip), ddi_get_instance(pdip));
146 return (DDI_SUCCESS);
149 case DDI_CTLOPS_INITCHILD: {
150 dev_info_t *ocdip, *cdip = (dev_info_t *)arg;
151 dev_info_t *pdip = ddi_get_parent(cdip);
152 int reglen, i;
153 uint32_t *regptr;
154 char addr[MAXNAMELEN];
156 i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
157 DDI_PROP_DONTPASS, "reg", (int **)&regptr,
158 (uint_t *)&reglen);
160 if (i != DDI_PROP_SUCCESS) {
161 cmn_err(CE_NOTE, "!%s(%d): \"reg\" property not found",
162 ddi_node_name(cdip), ddi_get_instance(cdip));
163 return (DDI_NOT_WELL_FORMED);
166 ASSERT(reglen != 0);
169 * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA]
171 if (regptr[2] || regptr[3]) {
172 (void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
173 regptr[1], regptr[2], regptr[3]);
174 } else {
175 (void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
177 ddi_prop_free(regptr);
178 ddi_set_name_addr(cdip, addr);
181 * Check for a node with the same name & addr as the current
182 * node. If such a node exists, return failure.
184 if ((ocdip = ndi_devi_find(pdip, ddi_node_name(cdip), addr)) !=
185 NULL && ocdip != cdip) {
186 cmn_err(CE_NOTE,
187 "!%s(%d): Duplicate dev_info node found %s@%s",
188 ddi_node_name(cdip), ddi_get_instance(cdip),
189 ddi_node_name(ocdip), addr);
190 ddi_set_name_addr(cdip, NULL);
191 return (DDI_NOT_WELL_FORMED);
195 * If HAL (parent dip) has "active-dma-flush" property, then
196 * add property to child as well. Workaround for active
197 * context flushing bug in Schizo rev 2.1 and 2.2.
199 if (ddi_prop_exists(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
200 "active-dma-flush") != 0) {
201 status = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
202 "active-dma-flush", 1);
203 if (status != NDI_SUCCESS) {
204 cmn_err(CE_NOTE, "!%s(%d): Unable to add "
205 "\"active-dma-flush\" property",
206 ddi_node_name(cdip),
207 ddi_get_instance(cdip));
208 ddi_set_name_addr(cdip, NULL);
209 return (DDI_NOT_WELL_FORMED);
213 return (DDI_SUCCESS);
216 case DDI_CTLOPS_UNINITCHILD: {
217 ddi_prop_remove_all((dev_info_t *)arg);
218 ddi_set_name_addr((dev_info_t *)arg, NULL);
219 return (DDI_SUCCESS);
222 case DDI_CTLOPS_IOMIN: {
223 status = ddi_ctlops(dip, rdip, op, arg, result);
224 return (status);
227 case DDI_CTLOPS_POWER: {
228 return (DDI_SUCCESS);
232 * These ops correspond to functions that "shouldn't" be called
233 * by a 1394 client driver.
235 case DDI_CTLOPS_DMAPMAPC:
236 case DDI_CTLOPS_REPORTINT:
237 case DDI_CTLOPS_REGSIZE:
238 case DDI_CTLOPS_NREGS:
239 case DDI_CTLOPS_SIDDEV:
240 case DDI_CTLOPS_SLAVEONLY:
241 case DDI_CTLOPS_AFFINITY:
242 case DDI_CTLOPS_POKE:
243 case DDI_CTLOPS_PEEK: {
244 cmn_err(CE_CONT, "!%s(%d): invalid op (%d) from %s(%d)",
245 ddi_node_name(dip), ddi_get_instance(dip),
246 op, ddi_node_name(rdip), ddi_get_instance(rdip));
247 return (DDI_FAILURE);
251 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
253 default: {
254 status = ddi_ctlops(dip, rdip, op, arg, result);
255 return (status);
261 * nx1394_dma_allochdl()
262 * Merges the ddi_dma_attr_t passed in by the target (using
263 * ddi_dma_alloc_handle() call) with that of the hal and passes the alloc
264 * handle request up the device by calling ddi_dma_allochdl().
266 static int
267 nx1394_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
268 int (*waitfnp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
270 s1394_hal_t *hal;
271 ddi_dma_attr_t *hal_attr;
272 int status;
274 _NOTE(SCHEME_PROTECTS_DATA("unique (per thread)", ddi_dma_attr_t))
277 * If hal calls ddi_dma_alloc_handle, dip == rdip == hal dip.
278 * Unfortunately, we cannot verify this (by way of looking up for hal
279 * dip) here because h1394_attach() may happen much later.
281 if (dip != rdip) {
282 hal = s1394_dip_to_hal(ddi_get_parent(rdip));
283 ASSERT(hal);
284 hal_attr = &hal->halinfo.dma_attr;
285 ASSERT(hal_attr);
286 ddi_dma_attr_merge(attr, hal_attr);
288 status = ddi_dma_allochdl(dip, rdip, attr, waitfnp, arg, handlep);
289 return (status);
293 * nx1394_get_event_cookie()
294 * Called when a child node calls ddi_get_eventcookie().
295 * Returns event cookie corresponding to event "name".
297 static int
298 nx1394_get_event_cookie(dev_info_t *dip, dev_info_t *rdip, char *name,
299 ddi_eventcookie_t *event_cookiep)
301 int ret;
302 s1394_hal_t *hal;
304 hal = s1394_dip_to_hal(dip);
305 ASSERT(hal);
307 ret = ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl,
308 rdip, name, event_cookiep, 0);
310 return (ret);
315 * nx1394_add_eventcall()
316 * This gets called when a child node calls ddi_add_eventcall(). Registers
317 * the specified callback for the requested event cookie with the ndi
318 * event framework.
319 * dip is the hal dip. This routine calls ndi_event_add_callback(),
320 * allowing requests for events we don't generate to pass up the tree.
322 static int
323 nx1394_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
324 ddi_eventcookie_t cookie, void (*callback)(), void *arg,
325 ddi_callback_id_t *cb_id)
327 int ret;
328 s1394_hal_t *hal;
329 #if defined(DEBUG)
330 char *event_name = NULL;
331 #endif
333 hal = s1394_dip_to_hal(dip);
334 ASSERT(hal);
336 ret = ndi_event_add_callback(hal->hal_ndi_event_hdl, rdip, cookie,
337 callback, arg, NDI_NOSLEEP, cb_id);
338 #if defined(DEBUG)
339 event_name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
340 if (event_name == NULL)
341 event_name = "";
342 #endif
344 return (ret);
348 * nx1394_remove_eventcall()
349 * Called as a result of a child node calling ddi_remove_eventcall().
350 * Unregisters the callback corresponding to the callback id passed in.
352 static int
353 nx1394_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
355 int ret;
356 s1394_hal_t *hal;
357 ddi_eventcookie_t cookie;
358 #if defined(DEBUG)
359 char *event_name = NULL;
360 #endif
362 ASSERT(cb_id);
363 cookie = ((ndi_event_callbacks_t *)cb_id)->ndi_evtcb_cookie;
365 hal = s1394_dip_to_hal(dip);
366 ASSERT(hal);
368 ret = ndi_event_remove_callback(hal->hal_ndi_event_hdl, cb_id);
370 #if defined(DEBUG)
371 event_name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
372 if (event_name == NULL)
373 event_name = "";
375 #endif
377 return (ret);
381 * nx1394_post_event()
382 * Called when a child node calls ddi_post_event. If the event is one of
383 * the events supported by us (bus reset/insert/remove, for now), builds
384 * a t1394_localinfo_t structure and calls ndi_event_run_callbacks(). This
385 * will result in all registered callbacks being invoked with
386 * t1394_localinfo_t as the impl_data. (see ddi_add_eventcall for callback
387 * arguments.) If the event is not defined by us, the request is
388 * propagated up the device tree by calling ndi_post_event().
390 static int
391 nx1394_post_event(dev_info_t *dip, dev_info_t *rdip, ddi_eventcookie_t cookie,
392 void *impl_data)
394 int ret;
395 char *name;
396 s1394_hal_t *hal;
397 t1394_localinfo_t localinfo;
399 hal = s1394_dip_to_hal(dip);
400 ASSERT(hal);
402 name = ndi_event_cookie_to_name(hal->hal_ndi_event_hdl, cookie);
403 /* name is NULL if we don't generate the event */
404 if (name != NULL) {
406 mutex_enter(&hal->topology_tree_mutex);
407 localinfo.bus_generation = hal->generation_count;
408 localinfo.local_nodeID = hal->node_id;
409 mutex_exit(&hal->topology_tree_mutex);
410 impl_data = &localinfo;
412 ret = ndi_event_run_callbacks(hal->hal_ndi_event_hdl,
413 rdip, cookie, impl_data);
415 return (ret);
417 } else {
418 ret = ndi_post_event(ddi_get_parent(dip), rdip, cookie,
419 impl_data);
420 return (ret);
425 * nx1394_define_events()
426 * Allocates event handle for the hal dip and binds event set to it.
429 nx1394_define_events(s1394_hal_t *hal)
431 int ret;
433 /* get event handle */
434 ret = ndi_event_alloc_hdl(hal->halinfo.dip, hal->halinfo.hw_interrupt,
435 &hal->hal_ndi_event_hdl, NDI_SLEEP);
436 if (ret != NDI_SUCCESS) {
437 } else {
438 /* and bind to it */
439 ret = ndi_event_bind_set(hal->hal_ndi_event_hdl, &nx1394_events,
440 NDI_SLEEP);
441 if (ret != NDI_SUCCESS) {
442 (void) ndi_event_free_hdl(hal->hal_ndi_event_hdl);
443 return (DDI_FAILURE);
447 return (DDI_SUCCESS);
451 * nx1394_undefine_events()
452 * Unbinds event set bound to the hal and frees the event handle.
454 void
455 nx1394_undefine_events(s1394_hal_t *hal)
457 int ret;
459 ret = ndi_event_unbind_set(hal->hal_ndi_event_hdl, &nx1394_events,
460 NDI_SLEEP);
461 if (ret != NDI_SUCCESS) {
462 } else {
463 ret = ndi_event_free_hdl(hal->hal_ndi_event_hdl);
464 if (ret != NDI_SUCCESS) {