Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / 1394 / s1394_hotplug.c
blobdace853e5929722472de86c591744d9f9dc3f583
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.
28 * s1394_hotplug.c
29 * 1394 Services Layer Hotplug Routines
30 * This file contains routines that walk the old and topology
31 * trees, at bus reset time, creating devinfo's for new nodes and offlining
32 * nodes that are removed.
35 #include <sys/conf.h>
36 #include <sys/sysmacros.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/sunndi.h>
40 #include <sys/modctl.h>
41 #include <sys/sunddi.h>
42 #include <sys/ddi_impldefs.h>
43 #include <sys/types.h>
45 #include <sys/tnf_probe.h>
47 #include <sys/1394/t1394.h>
48 #include <sys/1394/s1394.h>
49 #include <sys/1394/h1394.h>
50 #include <sys/1394/ieee1394.h>
52 static void s1394_send_remove_event(s1394_hal_t *hal, dev_info_t *dip,
53 t1394_localinfo_t *localinfo);
54 static void s1394_send_insert_event(s1394_hal_t *hal, dev_info_t *dip,
55 t1394_localinfo_t *localinfo);
56 static dev_info_t *s1394_create_devinfo(s1394_hal_t *hal, s1394_node_t *node,
57 uint32_t *unit_dir, int nunit);
58 static void s1394_update_unit_dir_location(s1394_hal_t *hal, dev_info_t *tdip,
59 uint_t offset);
62 * s1394_send_remove_event()
63 * Invokes any "remove event" callback registered for dip. Passes
64 * t1394_localinfo_t as impl_data for the callback.
66 static void
67 s1394_send_remove_event(s1394_hal_t *hal, dev_info_t *dip,
68 t1394_localinfo_t *localinfo)
70 char name[128];
71 ddi_eventcookie_t cookie;
73 (void) sprintf(name, "%s%d", ddi_driver_name(dip),
74 ddi_get_instance(dip));
76 if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, dip,
77 DDI_DEVI_REMOVE_EVENT, &cookie, NDI_EVENT_NOPASS)
78 == NDI_SUCCESS) {
79 (void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, dip,
80 cookie, localinfo);
85 * s1394_send_insert_event()
86 * Invokes any "insert event" callback registered for dip. Passes
87 * t1394_localinfo_t as impl_data for the callback.
89 static void
90 s1394_send_insert_event(s1394_hal_t *hal, dev_info_t *dip,
91 t1394_localinfo_t *localinfo)
93 char name[128];
94 ddi_eventcookie_t cookie;
96 (void) sprintf(name, "%s%d", ddi_driver_name(dip),
97 ddi_get_instance(dip));
99 if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, dip,
100 DDI_DEVI_INSERT_EVENT, &cookie, NDI_EVENT_NOPASS) ==
101 NDI_SUCCESS)
102 (void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, dip,
103 cookie, localinfo);
107 * s1394_create_devinfo()
108 * This routine creates a devinfo corresponding to the unit_dir passed in.
109 * It adds "hp-node", "reg", "compatible" properties to the devinfo
110 * (formats for "reg" and "compatible" properties are specified by 1275
111 * binding for IEEE1394). If unable to create the devinfo and/or add the
112 * the properties, returns NULL, otherwise, returns the devinfo created.
114 * NOTE: All ndi_* routines are interrupt callable (and thus won't sleep).
115 * So, we don't drop topology_mutex across ndi calls.
117 static dev_info_t *
118 s1394_create_devinfo(s1394_hal_t *hal, s1394_node_t *node, uint32_t *unit_dir,
119 int nunit)
121 dev_info_t *hal_dip;
122 uint32_t *root_dir;
123 dev_info_t *target_dip;
125 int root_dir_len;
126 int result, i, j, spec_id, sw_version;
127 int mod_ven, mod_hw, mod_spec, mod_sw;
128 int node_ven, node_hw, node_spec, node_sw;
130 /*LINTED type is unused*/
131 uint32_t type __unused, key, value;
132 uint32_t unit_spec_id, unit_sw_version;
133 uint32_t node_spec_id, node_sw_version;
134 uint32_t node_vendor_id, node_hw_version;
135 uint32_t module_spec_id, module_sw_version;
136 uint32_t module_vendor_id, module_hw_version;
138 char *fmt = "firewire%06x,%06x";
140 char *buf[5], data[5][24];
141 uint32_t reg[6];
143 ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
145 hal_dip = hal->halinfo.dip;
147 /* Allocate and init a new device node instance. */
148 result = ndi_devi_alloc(hal_dip, "unit", (pnode_t)DEVI_SID_NODEID,
149 &target_dip);
151 if (result != NDI_SUCCESS) {
152 cmn_err(CE_NOTE, "!Unable to create devinfo"
153 " (node's GUID %08x%08x)", node->node_guid_hi,
154 node->node_guid_lo);
155 return (NULL);
158 /* Add "hp-node" property */
159 result = ndi_prop_update_int(DDI_DEV_T_NONE, target_dip, "hp-node", 0);
160 if (result != NDI_SUCCESS) {
161 cmn_err(CE_NOTE, "!Unable to add \"hp-node\" property"
162 " (node's GUID %08x%08x)", node->node_guid_hi,
163 node->node_guid_lo);
164 #if defined(DEBUG)
165 cmn_err(CE_CONT, "!Error code %d", result);
166 #endif
167 ndi_prop_remove_all(target_dip);
168 (void) ndi_devi_free(target_dip);
169 return (NULL);
172 spec_id = sw_version = mod_ven = mod_hw = mod_spec = mod_sw =
173 node_ven = node_hw = node_spec = node_sw = 0;
174 unit_sw_version = node_sw_version = node_hw_version =
175 module_sw_version = module_hw_version = 0;
178 root_dir = CFGROM_ROOT_DIR(node->cfgrom);
179 root_dir_len = CFGROM_DIR_LEN(root_dir);
181 for (i = 0; i < root_dir_len; i++) {
183 CFGROM_TYPE_KEY_VALUE(root_dir[i + 1], type, key, value);
184 switch (key) {
186 case IEEE1212_MODULE_VENDOR_ID:
187 module_vendor_id = value;
188 mod_ven++;
189 break;
190 case IEEE1212_MODULE_HW_VERSION:
191 module_hw_version = value;
192 mod_hw++;
193 break;
194 case IEEE1212_MODULE_SPEC_ID:
195 module_spec_id = value;
196 mod_spec++;
197 break;
198 case IEEE1212_MODULE_SW_VERSION:
199 module_sw_version = value;
200 mod_sw++;
201 break;
202 case IEEE1212_NODE_VENDOR_ID:
203 node_vendor_id = value;
204 node_ven++;
205 break;
206 case IEEE1212_NODE_UNIQUE_ID: {
207 uint32_t *node_unique_leaf =
208 &root_dir[i + 1] + value;
209 node_vendor_id = (node_unique_leaf[1] >> 8);
210 node_ven++;
212 break;
213 case IEEE1212_NODE_HW_VERSION:
214 node_hw_version = value;
215 node_hw++;
216 break;
217 case IEEE1212_NODE_SPEC_ID:
218 node_spec_id = value;
219 node_spec++;
220 break;
221 case IEEE1212_NODE_SW_VERSION:
222 node_sw_version = value;
223 node_sw++;
224 break;
227 if (mod_ven && mod_hw && mod_spec && mod_sw && node_ven &&
228 node_hw && node_spec && node_sw) {
229 break;
234 * Search for unit spec and version
236 for (i = 0; i < CFGROM_DIR_LEN(unit_dir); i++) {
238 CFGROM_TYPE_KEY_VALUE(unit_dir[i + 1], type, key, value);
239 if (key == IEEE1212_UNIT_SPEC_ID) {
241 unit_spec_id = value;
242 spec_id++;
243 } else if (key == IEEE1212_UNIT_SW_VERSION) {
245 unit_sw_version = value;
246 sw_version++;
248 if (spec_id && sw_version)
249 break;
253 * Refer to IEEE1212 (pages 90-92) for information regarding various
254 * id's. Module_Vendor_Id is required. Node_Vendor_Id is optional and
255 * if not implemented, its assumed value is Module_Vendor_Id.
256 * Module_Spec_Id is optional and if not implemented, its assumed value
257 * is Module_Vendor_Id. Node_Spec_Id is optional, and if not
258 * implemented, its assumed value is Node_Vendor_Id. Unit_Spec_Id is
259 * optional, and if not implemented, its assumed value is
260 * Node_Vendor_Id.
262 if (node_ven == 0) {
263 node_vendor_id = module_vendor_id;
264 node_ven++;
267 if (node_spec == 0) {
268 node_spec_id = node_vendor_id;
269 node_spec++;
272 if (mod_spec == 0) {
273 module_spec_id = module_vendor_id;
274 mod_spec++;
277 if (spec_id == 0) {
278 unit_spec_id = node_vendor_id;
279 spec_id++;
282 i = 0;
283 if (sw_version != 0) {
284 buf[i] = data[i];
285 (void) sprintf(data[i++], fmt, unit_spec_id, unit_sw_version);
287 if (node_sw != 0) {
288 buf[i] = data[i];
289 (void) sprintf(data[i++], fmt, node_spec_id, node_sw_version);
291 if (node_hw != 0) {
292 buf[i] = data[i];
293 (void) sprintf(data[i++], fmt, node_vendor_id, node_hw_version);
295 if (mod_sw != 0) {
296 buf[i] = data[i];
297 (void) sprintf(data[i++], fmt, module_spec_id,
298 module_sw_version);
300 if (mod_hw != 0) {
301 buf[i] = data[i];
302 (void) sprintf(data[i++], fmt, module_vendor_id,
303 module_hw_version);
306 result = ndi_prop_update_string_array(DDI_DEV_T_NONE, target_dip,
307 "compatible", (char **)&buf, i);
308 if (result != NDI_SUCCESS) {
309 cmn_err(CE_NOTE, "!Unable to add \"compatible\" property"
310 " (node's GUID %08x%08x)", node->node_guid_hi,
311 node->node_guid_lo);
312 #if defined(DEBUG)
313 cmn_err(CE_CONT, "!Error code %d; nelements %d", result, i);
314 for (j = 0; j < i; j++) {
315 cmn_err(CE_CONT, "!buf[%d]: %s", j, buf[j]);
317 #endif
318 ndi_prop_remove_all(target_dip);
319 (void) ndi_devi_free(target_dip);
320 return (NULL);
323 /* GUID,ADDR */
324 reg[0] = node->node_guid_hi;
325 reg[1] = node->node_guid_lo;
326 s1394_cfgrom_parse_unit_dir(unit_dir, &reg[2], &reg[3], &reg[4],
327 &reg[5]);
329 reg[3] = nunit;
331 result = ndi_prop_update_int_array(DDI_DEV_T_NONE, target_dip, "reg",
332 (int *)reg, 6);
333 if (result != NDI_SUCCESS) {
334 cmn_err(CE_NOTE, "!Unable to add \"reg\" property");
335 #if defined(DEBUG)
336 cmn_err(CE_CONT, "!Error code %d", result);
337 for (j = 0; j < 6; j++) {
338 cmn_err(CE_CONT, "!reg[%d]: 0x%08x", j, reg[j]);
340 #endif
341 ndi_prop_remove_all(target_dip);
342 (void) ndi_devi_free(target_dip);
343 return (NULL);
346 return (target_dip);
350 * s1394_devi_find()
351 * Searches all children of pdip for a match of name@caddr. Builds the
352 * name and address of each child node by looking up the reg property on
353 * the node and compares the built name@addr with the name@addr passed in.
354 * Returns the child dip if a match is found, otherwise, returns NULL.
355 * NOTE:
356 * This routine is decidedly non-ddi. We had to use this one since
357 * ndi_devi_find() can find only nodes that have valid addr field
358 * set and that won't happen unless the node goes through INITCHILD
359 * (at which time nx1394.c calls ddi_set_name_addr()). If, in future,
360 * the ndi_devi_find() provides a way of looking up nodes using criteria
361 * other than addr, we can get rid of this routine.
363 /*ARGSUSED*/
364 dev_info_t *
365 s1394_devi_find(dev_info_t *pdip, char *name, char *caddr)
367 int i, reglen;
368 char addr[32];
369 uint32_t *regptr;
370 dev_info_t *cdip = NULL;
372 ASSERT((name != NULL) && (caddr != NULL));
375 * for each child of this parent, find name and addr and match with
376 * name and caddr passed in.
378 for (cdip = (dev_info_t *)DEVI(pdip)->devi_child; cdip != NULL;
379 cdip = (dev_info_t *)DEVI(cdip)->devi_sibling) {
381 i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
382 DDI_PROP_DONTPASS, "reg", (int **)&regptr,
383 (uint_t *)&reglen);
385 if (i != DDI_PROP_SUCCESS)
386 continue;
389 * Construct addr from the reg property (addr is of the format
390 * GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where GGGGGGGGGGGGGGGG is
391 * the address and AAAAAAAAAAAA is the optional unit address)
393 if (regptr[2] != (uintptr_t)NULL ||
394 regptr[3] != (uintptr_t)NULL) {
395 (void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
396 regptr[1], regptr[2], regptr[3]);
397 } else {
398 (void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
400 ddi_prop_free(regptr);
402 if (strcmp(caddr, addr) == 0) {
403 ASSERT(strcmp(ddi_node_name(cdip), name) == 0);
404 break;
408 return (cdip);
412 * s1394_update_devinfo_tree()
413 * Parses the config rom for the passed in node and creates/updates devinfo's
414 * for each unit directory found. If the devinfo corresponding to a unit
415 * already exists, any insert event callbacks registered for that devinfo
416 * are called (topology tree is unlocked and relocked around these
417 * callbacks). Returns DDI_SUCCESS if everything went fine and DDI_FAILURE
418 * if unable to reacquire the lock after callbacks (relock fails because of
419 * an intervening bus reset or if the services layer kills the bus reset
420 * thread). The node is marked as parsed before returning.
423 s1394_update_devinfo_tree(s1394_hal_t *hal, s1394_node_t *node)
425 dev_info_t *tdip;
426 int j, units, d, lockfail = 0;
427 s1394_target_t *target, *t;
428 uint32_t hi, lo, size_hi, size_lo, type, key, value;
429 uint32_t *ptr, *root_dir, dir_len;
430 t1394_localinfo_t linfo;
432 uint32_t *unit_dir_ptrs[32];
433 dev_info_t *devinfo_ptrs[32];
434 uint32_t new_devinfo = 0; /* to keep track of new allocations */
436 char caddr[32];
438 ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
440 ASSERT(CFGROM_PARSED(node) == B_FALSE);
441 ASSERT(node->cfgrom != NULL);
443 /* scan through config rom looking for unit dirs */
444 root_dir = CFGROM_ROOT_DIR(node->cfgrom);
446 if (node->cfgrom_valid_size < CFGROM_DIR_LEN(root_dir))
447 dir_len = node->cfgrom_valid_size;
448 else
449 dir_len = CFGROM_DIR_LEN(root_dir);
451 CFGROM_TYPE_KEY_VALUE(root_dir[0], type, key, value);
452 if (s1394_valid_dir(hal, node, key, root_dir) == B_FALSE) {
453 cmn_err(CE_NOTE,
454 "!Bad root directory in config rom (node's GUID %08x%08x)",
455 node->node_guid_hi, node->node_guid_lo);
457 SET_CFGROM_PARSED(node);
458 CLEAR_CFGROM_GEN_CHANGED(node); /* if set */
459 CLEAR_CFGROM_NEW_ALLOC(node);
461 return (DDI_SUCCESS);
464 for (units = 0, j = 1; j <= dir_len; j++) {
465 CFGROM_TYPE_KEY_VALUE(root_dir[j], type, key, value);
466 if (key == IEEE1212_UNIT_DIRECTORY && type ==
467 IEEE1212_DIRECTORY_TYPE) {
468 ptr = &root_dir[j] + value;
469 if (s1394_valid_dir(hal, node, key, ptr) == B_TRUE) {
470 unit_dir_ptrs[units++] = ptr;
471 } else {
472 cmn_err(CE_NOTE, "!Bad unit directory in config"
473 " rom (node's GUID %08x%08x)",
474 node->node_guid_hi, node->node_guid_lo);
479 for (d = 0, j = 0; j < units; j++) {
481 s1394_cfgrom_parse_unit_dir(unit_dir_ptrs[j],
482 &hi, &lo, &size_hi, &size_lo);
484 lo = j;
486 if (hi || lo) {
487 (void) sprintf(caddr, "%08x%08x,%04x%08x",
488 node->node_guid_hi, node->node_guid_lo, hi, lo);
489 } else {
490 (void) sprintf(caddr, "%08x%08x",
491 node->node_guid_hi, node->node_guid_lo);
494 tdip = s1394_devi_find(hal->halinfo.dip, "unit", caddr);
495 if (tdip != NULL) {
497 rw_enter(&hal->target_list_rwlock, RW_WRITER);
498 target = s1394_target_from_dip_locked(hal, tdip);
499 if (target != NULL) {
500 target->target_sibling = NULL;
501 target->on_node = node;
502 target->target_state &= ~S1394_TARG_GONE;
503 target->unit_dir = unit_dir_ptrs[j] - root_dir;
505 if ((t = node->target_list) != NULL) {
506 ASSERT(t != target);
507 while (t->target_sibling != NULL) {
508 t = t->target_sibling;
509 ASSERT(t != target);
511 t->target_sibling = target;
512 } else {
513 node->target_list = target;
516 target->target_list = node->target_list;
518 rw_exit(&hal->target_list_rwlock);
520 s1394_update_unit_dir_location(hal, tdip,
521 unit_dir_ptrs[j] - root_dir);
523 } else {
524 /* create devinfo for unit@caddr */
525 tdip = s1394_create_devinfo(hal, node,
526 unit_dir_ptrs[j], j);
527 if (tdip != NULL) {
528 new_devinfo |= (1 << d);
529 s1394_update_unit_dir_location(hal, tdip,
530 unit_dir_ptrs[j] - root_dir);
533 if (tdip != NULL)
534 devinfo_ptrs[d++] = tdip;
537 ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
538 /* Online all valid units */
539 for (j = 0; j < d; j++) {
540 if ((new_devinfo & (1 << j)) == 0) {
541 linfo.bus_generation = hal->generation_count;
542 linfo.local_nodeID = hal->node_id;
544 /* don't need to drop topology_tree_mutex across ndi calls */
545 (void) ndi_devi_online_async(devinfo_ptrs[j], 0);
546 if ((new_devinfo & (1 << j)) == 0) {
548 * send an insert event if this an existing devinfo.
549 * drop and reacquire topology_tree_mutex across
550 * the event calls
552 s1394_unlock_tree(hal);
553 s1394_send_insert_event(hal, devinfo_ptrs[j], &linfo);
554 if (s1394_lock_tree(hal) != DDI_SUCCESS) {
555 lockfail = 1;
556 break;
561 if (lockfail) {
562 return (DDI_FAILURE);
565 SET_CFGROM_PARSED(node);
566 CLEAR_CFGROM_GEN_CHANGED(node); /* if set */
567 CLEAR_CFGROM_NEW_ALLOC(node);
569 return (DDI_SUCCESS);
573 * s1394_offline_node()
574 * Offlines a node. This involves marking all targets attached to the
575 * node as gone, invoking any remove event callbacks and calling
576 * ndi_devi_offline to mark the devinfo as OFFLINE (for each unit
577 * directory on the node). The tree is unlocked and relocked around
578 * the callbacks. If unable to relock the tree, DDI_FAILURE, else
579 * returns DDI_SUCCESS.
582 s1394_offline_node(s1394_hal_t *hal, s1394_node_t *node)
584 s1394_target_t *t;
585 dev_info_t *tdip;
586 int j, d, units;
587 uint32_t *unit_dir_ptrs[32];
588 dev_info_t *devinfo_ptrs[32];
589 t1394_localinfo_t linfo;
590 uint_t node_num;
591 uint32_t *ptr, *root_dir, dir_len;
592 uint32_t hi, lo, size_hi, size_lo, type, key, value;
593 char caddr[32];
595 node_num = node->node_num;
597 ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
599 d = 0;
600 rw_enter(&hal->target_list_rwlock, RW_WRITER);
601 t = node->target_list;
602 while (t != NULL) {
603 t->target_state |= S1394_TARG_GONE;
604 t->on_node = NULL;
605 t = t->target_sibling;
607 rw_exit(&hal->target_list_rwlock);
609 /* scan through config rom looking for unit dirs */
610 root_dir = CFGROM_ROOT_DIR(node->cfgrom);
612 if (node->cfgrom_valid_size < CFGROM_DIR_LEN(root_dir))
613 dir_len = node->cfgrom_valid_size;
614 else
615 dir_len = CFGROM_DIR_LEN(root_dir);
617 CFGROM_TYPE_KEY_VALUE(root_dir[0], type, key, value);
619 for (units = 0, j = 1; j <= dir_len; j++) {
620 CFGROM_TYPE_KEY_VALUE(root_dir[j], type, key, value);
621 if (key == IEEE1212_UNIT_DIRECTORY && type ==
622 IEEE1212_DIRECTORY_TYPE) {
623 ptr = &root_dir[j] + value;
624 if (s1394_valid_dir(hal, node, key, ptr) == B_TRUE) {
625 unit_dir_ptrs[units++] = ptr;
630 for (d = 0, j = 0; j < units; j++) {
632 s1394_cfgrom_parse_unit_dir(unit_dir_ptrs[j],
633 &hi, &lo, &size_hi, &size_lo);
635 lo = j;
637 if (hi || lo) {
638 (void) sprintf(caddr, "%08x%08x,%04x%08x",
639 node->node_guid_hi, node->node_guid_lo, hi, lo);
640 } else {
641 (void) sprintf(caddr, "%08x%08x",
642 node->node_guid_hi, node->node_guid_lo);
645 if ((tdip = s1394_devi_find(hal->halinfo.dip, "unit", caddr)) !=
646 NULL)
647 devinfo_ptrs[d++] = tdip;
650 node->old_node = NULL;
652 linfo.bus_generation = hal->generation_count;
653 linfo.local_nodeID = hal->node_id;
655 for (j = 0; j < d; j++) {
656 s1394_unlock_tree(hal);
658 s1394_send_remove_event(hal, devinfo_ptrs[j], &linfo);
659 (void) ndi_devi_offline(devinfo_ptrs[j], NDI_DEVI_REMOVE);
660 if (s1394_lock_tree(hal) != DDI_SUCCESS) {
661 return (DDI_FAILURE);
665 ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
666 return (DDI_SUCCESS);
670 * s1394_process_topology_tree()
671 * Walks the topology tree, processing each node. If node that has
672 * already been parsed, updates the generation property on all devinfos
673 * for the node. Also, if the node exists in both old & new trees, ASSERTS
674 * that both point to the same config rom. If the node has valid config
675 * rom but hasn't been parsed yet, calls s1394_update_devinfo_tree()
676 * to parse and create devinfos for the node. Kicks off further config
677 * rom reading if only the bus info block for the node is read.
678 * Returns DDI_SUCCESS if everything went fine, else returns DDI_FAILURE
679 * (for eg. unable to reacquire the tree lock etc). wait_for_cbs argument
680 * tells the caller if some completions can be expected. wait_gen tells
681 * the generation the commands were issued at.
684 s1394_process_topology_tree(s1394_hal_t *hal, int *wait_for_cbs,
685 uint_t *wait_gen)
687 int i;
688 uint_t hal_node_num, number_of_nodes;
689 s1394_node_t *node, *onode;
690 s1394_status_t status;
692 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
694 if (s1394_lock_tree(hal) != DDI_SUCCESS) {
695 return (DDI_FAILURE);
698 hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
699 hal->cfgroms_being_read = 0;
700 number_of_nodes = hal->number_of_nodes;
701 s1394_unlock_tree(hal);
703 for (i = 0; i < number_of_nodes; i++) {
705 if (i == hal_node_num)
706 continue;
707 if (s1394_lock_tree(hal) != DDI_SUCCESS) {
708 return (DDI_FAILURE);
710 node = &hal->topology_tree[i];
712 if (LINK_ACTIVE(node) == B_FALSE) {
713 s1394_unlock_tree(hal);
714 continue;
716 if (node->cfgrom == NULL) {
717 s1394_unlock_tree(hal);
718 continue;
721 onode = node->old_node;
723 if (onode != NULL && onode->cfgrom != NULL && node->cfgrom !=
724 NULL) {
726 * onode->cfgrom != node->cfgrom should have been
727 * handled by s1394_match_GUID()!!!
729 ASSERT(onode->cfgrom == node->cfgrom);
732 if (CFGROM_PARSED(node) == B_FALSE && CFGROM_ALL_READ(node) ==
733 B_TRUE) {
734 ASSERT((node->cfgrom_size <
735 IEEE1394_CONFIG_ROM_QUAD_SZ) ||
736 NODE_MATCHED(node) == B_TRUE);
737 rw_enter(&hal->target_list_rwlock, RW_READER);
738 ASSERT(node->target_list == NULL);
739 rw_exit(&hal->target_list_rwlock);
740 if (s1394_update_devinfo_tree(hal, node) ==
741 DDI_FAILURE) {
742 ASSERT(MUTEX_NOT_HELD(
743 &hal->topology_tree_mutex));
744 return (DDI_FAILURE);
746 } else if (CFGROM_PARSED(node) == B_FALSE && CFGROM_BIB_READ(
747 node) == B_TRUE) {
748 if (s1394_read_rest_of_cfgrom(hal, node, &status) !=
749 DDI_SUCCESS) {
750 if ((status & S1394_LOCK_FAILED) == 0) {
751 ASSERT(MUTEX_HELD(&hal->
752 topology_tree_mutex));
753 *wait_for_cbs = 0;
754 s1394_unlock_tree(hal);
756 return (DDI_FAILURE);
757 } else {
758 *wait_for_cbs = 1;
759 *wait_gen = hal->br_cfgrom_read_gen;
763 s1394_unlock_tree(hal);
767 * flag the tree as processed; if a single bus reset happens after
768 * this, we will use tree matching.
770 if (s1394_lock_tree(hal) != DDI_SUCCESS) {
771 return (DDI_FAILURE);
773 hal->topology_tree_processed = B_TRUE;
774 s1394_unlock_tree(hal);
776 return (DDI_SUCCESS);
780 * s1394_process_old_tree()
781 * Walks through the old tree and offlines nodes that are removed. Nodes
782 * with an active link in the old tree but link powered off in the current
783 * generation are also offlined, as well as nodes with invalid config
784 * rom in current generation.
785 * The topology tree is locked/unlocked while walking through all the nodes;
786 * if the locking fails at any stage, stops further walking and returns
787 * DDI_FAILURE. Returns DDI_SUCCESS if everything went fine.
790 s1394_process_old_tree(s1394_hal_t *hal)
792 int i;
793 uint_t hal_node_num_old, old_number_of_nodes;
794 s1394_node_t *onode;
797 * NODE_MATCHED(onode) == 0 indicates this node doesn't exist
798 * any more.
800 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
802 if (s1394_lock_tree(hal) != DDI_SUCCESS) {
803 return (DDI_FAILURE);
805 hal_node_num_old = IEEE1394_NODE_NUM(hal->old_node_id);
806 old_number_of_nodes = hal->old_number_of_nodes;
807 s1394_unlock_tree(hal);
809 for (i = 0; i < old_number_of_nodes; i++) {
811 if (i == hal_node_num_old)
812 continue;
813 if (s1394_lock_tree(hal) != DDI_SUCCESS) {
814 return (DDI_FAILURE);
817 onode = &hal->old_tree[i];
819 if (onode->cfgrom == NULL) {
820 CLEAR_CFGROM_STATE(onode);
821 s1394_unlock_tree(hal);
822 continue;
826 * onode->cur_node == NULL iff we couldn't read cfgrom in the
827 * current generation in non-tree matching case (and thus
828 * match_GUIDs couldn't set cur_node).
830 if (NODE_MATCHED(onode) == B_FALSE || (onode->cur_node ==
831 NULL || ((CFGROM_VALID(onode) == B_TRUE &&
832 CFGROM_VALID(onode->cur_node) == B_FALSE) ||
833 (LINK_ACTIVE(onode) == B_TRUE && LINK_ACTIVE(onode->
834 cur_node) == B_FALSE)))) {
835 if (s1394_offline_node(hal, onode) != DDI_SUCCESS)
836 return (DDI_FAILURE);
837 s1394_free_cfgrom(hal, onode, S1394_FREE_CFGROM_OLD);
840 s1394_unlock_tree(hal);
843 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
845 return (DDI_SUCCESS);
849 * s1394_update_unit_dir_location()
850 * Updates the unit-dir-offset property on the devinfo.
851 * NOTE: ndi_prop_update_int() is interrupt callable (and thus won't block);
852 * so, the caller doesn't drop topology_tree_mutex when calling this routine.
854 /*ARGSUSED*/
855 static void
856 s1394_update_unit_dir_location(s1394_hal_t *hal, dev_info_t *tdip,
857 uint_t offset)
859 ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
860 ASSERT(tdip != NULL);
862 (void) ndi_prop_update_int(DDI_DEV_T_NONE, tdip, "unit-dir-offset",
863 offset);
867 * s1394_add_target_to_node()
868 * adds target to the list of targets hanging off the node. Figures out
869 * the node by searching the topology tree for the GUID corresponding
870 * to the target. Points on_node field of target structure at the node.
872 void
873 s1394_add_target_to_node(s1394_target_t *target)
875 s1394_target_t *t;
876 s1394_hal_t *hal;
877 uint32_t guid_hi;
878 uint32_t guid_lo;
879 int i;
880 char name[MAXNAMELEN];
881 char *ptr;
883 hal = target->on_hal;
884 ASSERT(hal != NULL);
886 /* Topology tree must be locked when it gets here! */
887 ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
889 /* target_list_rwlock should be held in write mode */
890 ASSERT(rw_read_locked(&target->on_hal->target_list_rwlock) == 0);
892 if ((ptr = ddi_get_name_addr(target->target_dip)) == NULL) {
893 return;
896 (void) sprintf(name, ptr);
897 /* Drop the ,<ADDR> part, if present */
898 if ((ptr = strchr(name, ',')) != NULL)
899 *ptr = '\0';
901 ptr = name;
902 guid_hi = s1394_stoi(ptr, 8, 16);
903 guid_lo = s1394_stoi(ptr + 8, 8, 16);
905 /* Search the HAL's node list for this GUID */
906 for (i = 0; i < hal->number_of_nodes; i++) {
907 if (CFGROM_VALID(&hal->topology_tree[i]) == B_TRUE) {
908 ASSERT(hal->topology_tree[i].cfgrom != NULL);
910 if ((hal->topology_tree[i].node_guid_hi == guid_hi) &&
911 (hal->topology_tree[i].node_guid_lo == guid_lo)) {
912 target->on_node = &hal->topology_tree[i];
913 if ((t = hal->topology_tree[i].target_list) !=
914 NULL) {
915 ASSERT(t != target);
916 while (t->target_sibling != NULL) {
917 t = t->target_sibling;
918 ASSERT(t != target);
920 t->target_sibling = target;
921 } else {
922 hal->topology_tree[i].target_list =
923 target;
927 * update target_list in all targets on the
928 * node
930 t = hal->topology_tree[i].target_list;
931 while (t != NULL) {
932 t->target_list =
933 hal->topology_tree[i].target_list;
934 t = t->target_sibling;
936 break;
943 * s1394_remove_target_from_node()
944 * Removes target from the corresponding node's target_list.
946 void
947 s1394_remove_target_from_node(s1394_target_t *target)
949 s1394_target_t *t, *t1;
950 s1394_hal_t *hal;
952 hal = target->on_hal;
953 ASSERT(hal != NULL);
955 /* Topology tree must be locked when it gets here! */
956 ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
958 /* target_list_rwlock should be held in write mode */
959 ASSERT(rw_read_locked(&target->on_hal->target_list_rwlock) == 0);
961 t = target->target_list;
962 t1 = NULL;
963 while (t != NULL) {
964 if (t == target) {
965 if (t1 == NULL) {
966 target->target_list = t->target_sibling;
967 } else {
968 t1->target_sibling = t->target_sibling;
970 break;
972 t1 = t;
973 t = t->target_sibling;
975 /* Update the target_list pointer in all the targets */
976 if (target->on_node != NULL)
977 target->on_node->target_list = target->target_list;
979 t = t1 = target->target_list;
980 while (t != NULL) {
981 t->target_list = t1;
982 t = t->target_sibling;
985 target->on_node = NULL;
986 target->target_sibling = NULL;