17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
2744bf619dSJohn Levon /*
2844bf619dSJohn Levon  * Copyright 2019 Joyent, Inc.
293fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
3044bf619dSJohn Levon  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * s1394_dev_disc.c
347c478bd9Sstevel@tonic-gate  *    1394 Services Layer Device Discovery Routines
357c478bd9Sstevel@tonic-gate  *    This file contains the bus reset thread code, bus manager routines and
367c478bd9Sstevel@tonic-gate  *    various routines that are used to implement remote Config ROM reading.
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  *    FUTURE:
397c478bd9Sstevel@tonic-gate  *    Rescan the bus if invalid nodes are seen.
407c478bd9Sstevel@tonic-gate  *    Investigate taskq for reading phase2 config rom reads.
417c478bd9Sstevel@tonic-gate  *    If we are reading the entire bus info blk, we should attempt
427c478bd9Sstevel@tonic-gate  *    a block read and fallback to quad reads if this fails.
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include <sys/conf.h>
467c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
477c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
487c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
497c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
507c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
517c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
527c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
537c478bd9Sstevel@tonic-gate #include <sys/types.h>
547c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
557c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
567c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include <sys/1394/t1394.h>
597c478bd9Sstevel@tonic-gate #include <sys/1394/s1394.h>
607c478bd9Sstevel@tonic-gate #include <sys/1394/h1394.h>
617c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1394.h>
627c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1212.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /* hcmd_ret_t */
657c478bd9Sstevel@tonic-gate typedef enum {
667c478bd9Sstevel@tonic-gate 	S1394_HCMD_INVALID,
677c478bd9Sstevel@tonic-gate 	S1394_HCMD_NODE_DONE,
687c478bd9Sstevel@tonic-gate 	S1394_HCMD_NODE_EXPECT_MORE,
697c478bd9Sstevel@tonic-gate 	S1394_HCMD_LOCK_FAILED
707c478bd9Sstevel@tonic-gate } hcmd_ret_t;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #define	QUAD_TO_CFGROM_ADDR(b, n, q, addr) {			\
737c478bd9Sstevel@tonic-gate 	uint64_t bl = (b);					\
747c478bd9Sstevel@tonic-gate 	uint64_t nl = (n);					\
757c478bd9Sstevel@tonic-gate 	addr = ((bl) << IEEE1394_ADDR_BUS_ID_SHIFT) |		\
767c478bd9Sstevel@tonic-gate 		((nl) << IEEE1394_ADDR_PHY_ID_SHIFT);		\
777c478bd9Sstevel@tonic-gate 	addr += IEEE1394_CONFIG_ROM_ADDR + ((q) << 2);		\
787c478bd9Sstevel@tonic-gate }
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate #define	CFGROM_READ_PAUSE(d)						\
817c478bd9Sstevel@tonic-gate 	((s1394_cfgrom_read_delay_ms == 0) ? (void) 0 :			\
827c478bd9Sstevel@tonic-gate 	delay(drv_usectohz((d) * 1000)))
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate #define	BUMP_CFGROM_READ_DELAY(n)					\
857c478bd9Sstevel@tonic-gate 	(n)->cfgrom_read_delay += s1394_cfgrom_read_delay_incr
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #define	CFGROM_GET_READ_DELAY(n, d)					\
887c478bd9Sstevel@tonic-gate 	((d) = (n)->cfgrom_read_delay)
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate #define	SETUP_QUAD_READ(n, reset_fails, quadlet, cnt)			\
917c478bd9Sstevel@tonic-gate {									\
927c478bd9Sstevel@tonic-gate 	int i = (reset_fails);						\
9344bf619dSJohn Levon 	if (i != 0) {							\
947c478bd9Sstevel@tonic-gate 		(n)->cfgrom_read_fails = 0;				\
957c478bd9Sstevel@tonic-gate 		(n)->cfgrom_read_delay = (uchar_t)s1394_cfgrom_read_delay_ms; \
967c478bd9Sstevel@tonic-gate 	}								\
977c478bd9Sstevel@tonic-gate 	(n)->cfgrom_quad_to_read = (quadlet);				\
987c478bd9Sstevel@tonic-gate 	(n)->cfgrom_quad_read_cnt = (cnt);				\
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static void s1394_wait_for_events(s1394_hal_t *hal, int firsttime);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate static int s1394_wait_for_cfgrom_callbacks(s1394_hal_t *hal, uint_t wait_gen,
1047c478bd9Sstevel@tonic-gate     hcmd_ret_t(*handle_cmd_fn)(s1394_hal_t *hal, cmd1394_cmd_t *cmd));
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate static void s1394_flush_cmplq(s1394_hal_t *hal);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate static void s1394_br_thread_exit(s1394_hal_t *hal);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate static void s1394_target_bus_reset_notifies(s1394_hal_t *hal,
1117c478bd9Sstevel@tonic-gate     t1394_localinfo_t *localinfo);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static int s1394_alloc_cfgrom(s1394_hal_t *hal, s1394_node_t *node,
1147c478bd9Sstevel@tonic-gate     s1394_status_t *status);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static int s1394_cfgrom_scan_phase1(s1394_hal_t *hal);
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static hcmd_ret_t s1394_br_thread_handle_cmd_phase1(s1394_hal_t *hal,
1197c478bd9Sstevel@tonic-gate     cmd1394_cmd_t *cmd);
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate static int s1394_cfgrom_scan_phase2(s1394_hal_t *hal);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate static hcmd_ret_t s1394_br_thread_handle_cmd_phase2(s1394_hal_t *hal,
1247c478bd9Sstevel@tonic-gate     cmd1394_cmd_t *cmd);
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate static int s1394_read_config_quadlet(s1394_hal_t *hal, cmd1394_cmd_t *cmd,
1277c478bd9Sstevel@tonic-gate     s1394_status_t *status);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate static void s1394_cfgrom_read_callback(cmd1394_cmd_t *cmd);
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate static void s1394_get_quad_info(cmd1394_cmd_t *cmd, uint32_t *node_num,
1327c478bd9Sstevel@tonic-gate     uint32_t *quadlet, uint32_t *data);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate static int s1394_match_GUID(s1394_hal_t *hal, s1394_node_t *nnode);
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate static int s1394_match_all_GUIDs(s1394_hal_t *hal);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate static void s1394_become_bus_mgr(void *arg);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate static void s1394_become_bus_mgr_callback(cmd1394_cmd_t *cmd);
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate static int s1394_bus_mgr_processing(s1394_hal_t *hal);
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate static int s1394_do_bus_mgr_processing(s1394_hal_t *hal);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate static void s1394_bus_mgr_timers_stop(s1394_hal_t *hal,
1477c478bd9Sstevel@tonic-gate     timeout_id_t *bus_mgr_query_tid, timeout_id_t *bus_mgr_tid);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate static void s1394_bus_mgr_timers_start(s1394_hal_t *hal,
1507c478bd9Sstevel@tonic-gate     timeout_id_t *bus_mgr_query_tid, timeout_id_t *bus_mgr_tid);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate static int s1394_cycle_master_capable(s1394_hal_t *hal);
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate static int s1394_do_phy_config_pkt(s1394_hal_t *hal, int new_root,
1557c478bd9Sstevel@tonic-gate     int new_gap_cnt, uint32_t IRM_flags);
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate static void s1394_phy_config_callback(cmd1394_cmd_t *cmd);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate static int s1394_calc_next_quad(s1394_hal_t *hal, s1394_node_t *node,
1607c478bd9Sstevel@tonic-gate     uint32_t quadlet, uint32_t *nextquadp);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate static int s1394_cfgrom_read_retry_cnt = 3;	/* 1 + 3 retries */
1637c478bd9Sstevel@tonic-gate static int s1394_cfgrom_read_delay_ms = 20;	/* start with 20ms */
1647c478bd9Sstevel@tonic-gate static int s1394_cfgrom_read_delay_incr = 10;	/* 10ms increments */
1657c478bd9Sstevel@tonic-gate static int s1394_enable_crc_validation = 0;
1667c478bd9Sstevel@tonic-gate static int s1394_turn_off_dir_stack = 0;
1677c478bd9Sstevel@tonic-gate static int s1394_crcsz_is_cfgsz = 0;
1687c478bd9Sstevel@tonic-gate static int s1394_enable_rio_pass1_workarounds = 0;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate  * s1394_br_thread()
1727c478bd9Sstevel@tonic-gate  *    is the bus reset thread. Its sole purpose is to read/reread config roms
1737c478bd9Sstevel@tonic-gate  *    as appropriate and do bus reset time things (bus manager processing,
1747c478bd9Sstevel@tonic-gate  *    isoch resource reallocation etc.).
1757c478bd9Sstevel@tonic-gate  */
1767c478bd9Sstevel@tonic-gate void
s1394_br_thread(s1394_hal_t * hal)1777c478bd9Sstevel@tonic-gate s1394_br_thread(s1394_hal_t *hal)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	/* Initialize the Bus Mgr timers */
1827c478bd9Sstevel@tonic-gate 	hal->bus_mgr_timeout_id = 0;
1837c478bd9Sstevel@tonic-gate 	hal->bus_mgr_query_timeout_id = 0;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	/* Initialize the cmpletion Q */
1867c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->br_cmplq_mutex);
1877c478bd9Sstevel@tonic-gate 	hal->br_cmplq_head = hal->br_cmplq_tail = NULL;
1887c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->br_cmplq_mutex);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	s1394_wait_for_events(hal, 1);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	for (;;) {
1937c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 		s1394_wait_for_events(hal, 0);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 		/* stop bus manager timeouts, if needed */
2007c478bd9Sstevel@tonic-gate 		s1394_bus_mgr_timers_stop(hal, &hal->bus_mgr_query_timeout_id,
2017c478bd9Sstevel@tonic-gate 		    &hal->bus_mgr_timeout_id);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 		s1394_flush_cmplq(hal);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 		/* start timers for checking bus manager, if needed */
2067c478bd9Sstevel@tonic-gate 		s1394_bus_mgr_timers_start(hal, &hal->bus_mgr_query_timeout_id,
2077c478bd9Sstevel@tonic-gate 		    &hal->bus_mgr_timeout_id);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 		/* Try to reallocate all isoch resources */
2107c478bd9Sstevel@tonic-gate 		s1394_isoch_rsrc_realloc(hal);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 		if (s1394_cfgrom_scan_phase1(hal) != DDI_SUCCESS) {
2137c478bd9Sstevel@tonic-gate 			continue;
2147c478bd9Sstevel@tonic-gate 		}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 		if (s1394_bus_mgr_processing(hal) != DDI_SUCCESS) {
2177c478bd9Sstevel@tonic-gate 			continue;
2187c478bd9Sstevel@tonic-gate 		}
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 		if (s1394_cfgrom_scan_phase2(hal) != DDI_SUCCESS) {
2237c478bd9Sstevel@tonic-gate 			continue;
2247c478bd9Sstevel@tonic-gate 		}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate  * s1394_wait_for_events()
2327c478bd9Sstevel@tonic-gate  *    blocks waiting for a cv_signal on the bus reset condition variable.
2337c478bd9Sstevel@tonic-gate  *    Used by the bus reset thread for synchronizing with the bus reset/
2347c478bd9Sstevel@tonic-gate  *    self id interrupt callback from the hal. Does CPR initialization
2357c478bd9Sstevel@tonic-gate  *    first time it is called. If services layer sees a valid self id
2367c478bd9Sstevel@tonic-gate  *    buffer, it builds the topology tree and signals the bus reset thread
2377c478bd9Sstevel@tonic-gate  *    to read the config roms as appropriate (indicated by BR_THR_CFGROM_SCAN).
2387c478bd9Sstevel@tonic-gate  *    If the services layer wishes to kill the bus reset thread, it signals
2397c478bd9Sstevel@tonic-gate  *    this by signaling a BR_THR_GO_AWAY event.
2407c478bd9Sstevel@tonic-gate  */
2417c478bd9Sstevel@tonic-gate static void
s1394_wait_for_events(s1394_hal_t * hal,int firsttime)2427c478bd9Sstevel@tonic-gate s1394_wait_for_events(s1394_hal_t *hal, int firsttime)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate 	uint_t event;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->br_thread_mutex));
2477c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (firsttime)
2507c478bd9Sstevel@tonic-gate 		CALLB_CPR_INIT(&hal->hal_cprinfo, &hal->br_thread_mutex,
2517c478bd9Sstevel@tonic-gate 		    callb_generic_cpr, "s1394_br_thread");
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	/* Check and wait for a BUS RESET */
2547c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->br_thread_mutex);
2557c478bd9Sstevel@tonic-gate 	while ((event = hal->br_thread_ev_type) == 0) {
2567c478bd9Sstevel@tonic-gate 		CALLB_CPR_SAFE_BEGIN(&hal->hal_cprinfo);
2577c478bd9Sstevel@tonic-gate 		cv_wait(&hal->br_thread_cv, &hal->br_thread_mutex);
2587c478bd9Sstevel@tonic-gate 		CALLB_CPR_SAFE_END(&hal->hal_cprinfo, &hal->br_thread_mutex);
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	if (event & BR_THR_GO_AWAY) {
2627c478bd9Sstevel@tonic-gate 		s1394_br_thread_exit(hal);
2637c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
2647c478bd9Sstevel@tonic-gate 		return;
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	if (firsttime) {
2687c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->br_thread_mutex);
2697c478bd9Sstevel@tonic-gate 		return;
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
2737c478bd9Sstevel@tonic-gate 	hal->br_cfgrom_read_gen = hal->generation_count;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	hal->br_thread_ev_type &= ~BR_THR_CFGROM_SCAN;
2767c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
2777c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->br_thread_mutex);
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate /*
2817c478bd9Sstevel@tonic-gate  * s1394_wait_for_cfgrom_callbacks()
2827c478bd9Sstevel@tonic-gate  *    Waits for completed config rom reads. Takes each completion off the
2837c478bd9Sstevel@tonic-gate  *    completion queue and passes it to the "completion handler" function
2847c478bd9Sstevel@tonic-gate  *    that was passed in as an argument. Further processing of the completion
2857c478bd9Sstevel@tonic-gate  *    queue depends on the return status of the completion handler. If there
2867c478bd9Sstevel@tonic-gate  *    is a bus reset while waiting for completions or if the services layer
2877c478bd9Sstevel@tonic-gate  *    signals BR_THR_GO_AWAY, quits waiting for completions and returns
2887c478bd9Sstevel@tonic-gate  *    non-zero. Also returns non-zero if completion handler returns
2897c478bd9Sstevel@tonic-gate  *    S1394_HCMD_LOCK_FAILED.  Returns 0 if config roms for all nodes have
2907c478bd9Sstevel@tonic-gate  *    been dealt with.
2917c478bd9Sstevel@tonic-gate  */
2927c478bd9Sstevel@tonic-gate static int
s1394_wait_for_cfgrom_callbacks(s1394_hal_t * hal,uint_t wait_gen,hcmd_ret_t (* handle_cmd_fn)(s1394_hal_t * hal,cmd1394_cmd_t * cmd))2937c478bd9Sstevel@tonic-gate s1394_wait_for_cfgrom_callbacks(s1394_hal_t *hal, uint_t wait_gen,
2947c478bd9Sstevel@tonic-gate     hcmd_ret_t(*handle_cmd_fn)(s1394_hal_t *hal, cmd1394_cmd_t *cmd))
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t *cmd;
2977c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
2987c478bd9Sstevel@tonic-gate 	int ret, done = 0;
2997c478bd9Sstevel@tonic-gate 	hcmd_ret_t cmdret;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	ret = DDI_SUCCESS;
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	while (!done) {
3067c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->br_cmplq_mutex);
3077c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->topology_tree_mutex);
3087c478bd9Sstevel@tonic-gate 		while (wait_gen == hal->generation_count &&
3097c478bd9Sstevel@tonic-gate 		    (hal->br_thread_ev_type & BR_THR_GO_AWAY) == 0 &&
3107c478bd9Sstevel@tonic-gate 		    hal->br_cmplq_head == NULL) {
3117c478bd9Sstevel@tonic-gate 			mutex_exit(&hal->topology_tree_mutex);
3127c478bd9Sstevel@tonic-gate 			cv_wait(&hal->br_cmplq_cv, &hal->br_cmplq_mutex);
3137c478bd9Sstevel@tonic-gate 			mutex_enter(&hal->topology_tree_mutex);
3147c478bd9Sstevel@tonic-gate 		}
3157c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
3167c478bd9Sstevel@tonic-gate 		if (wait_gen != hal->generation_count ||
3177c478bd9Sstevel@tonic-gate 		    (hal->br_thread_ev_type & BR_THR_GO_AWAY) != 0) {
3187c478bd9Sstevel@tonic-gate 			mutex_exit(&hal->topology_tree_mutex);
3197c478bd9Sstevel@tonic-gate 			mutex_exit(&hal->br_cmplq_mutex);
3207c478bd9Sstevel@tonic-gate 			s1394_flush_cmplq(hal);
3217c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 		if ((cmd = hal->br_cmplq_head) != NULL) {
3267c478bd9Sstevel@tonic-gate 			s_priv = S1394_GET_CMD_PRIV(cmd);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 			hal->br_cmplq_head = s_priv->cmd_priv_next;
3297c478bd9Sstevel@tonic-gate 		}
3307c478bd9Sstevel@tonic-gate 		if (cmd == hal->br_cmplq_tail)
3317c478bd9Sstevel@tonic-gate 			hal->br_cmplq_tail = NULL;
3327c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->br_cmplq_mutex);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 		if (cmd != NULL) {
3357c478bd9Sstevel@tonic-gate 			if (cmd->bus_generation != wait_gen) {
3367c478bd9Sstevel@tonic-gate 				(void) s1394_free_cmd(hal, &cmd);
3377c478bd9Sstevel@tonic-gate 				continue;
3387c478bd9Sstevel@tonic-gate 			}
3397c478bd9Sstevel@tonic-gate 			cmdret = (*handle_cmd_fn)(hal, cmd);
3407c478bd9Sstevel@tonic-gate 			ASSERT(cmdret != S1394_HCMD_INVALID);
3417c478bd9Sstevel@tonic-gate 			if (cmdret == S1394_HCMD_LOCK_FAILED) {
3427c478bd9Sstevel@tonic-gate 				/* flush completion queue */
3437c478bd9Sstevel@tonic-gate 				ret = DDI_FAILURE;
3447c478bd9Sstevel@tonic-gate 				s1394_flush_cmplq(hal);
3457c478bd9Sstevel@tonic-gate 				break;
3467c478bd9Sstevel@tonic-gate 			} else if (cmdret == S1394_HCMD_NODE_DONE) {
3477c478bd9Sstevel@tonic-gate 				if (--hal->cfgroms_being_read == 0) {
3487c478bd9Sstevel@tonic-gate 					/* All done */
3497c478bd9Sstevel@tonic-gate 					break;
3507c478bd9Sstevel@tonic-gate 				}
3517c478bd9Sstevel@tonic-gate 			} else {
3527c478bd9Sstevel@tonic-gate 				ASSERT(cmdret == S1394_HCMD_NODE_EXPECT_MORE);
3537c478bd9Sstevel@tonic-gate 				done = 0;
3547c478bd9Sstevel@tonic-gate 			}
3557c478bd9Sstevel@tonic-gate 		}
3567c478bd9Sstevel@tonic-gate 	}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	return (ret);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate /*
3627c478bd9Sstevel@tonic-gate  * s1394_flush_cmplq()
3637c478bd9Sstevel@tonic-gate  *    Frees all cmds on the completion queue.
3647c478bd9Sstevel@tonic-gate  */
3657c478bd9Sstevel@tonic-gate static void
s1394_flush_cmplq(s1394_hal_t * hal)3667c478bd9Sstevel@tonic-gate s1394_flush_cmplq(s1394_hal_t *hal)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
3697c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t *cmd, *tcmd;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	cmd = NULL;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	do {
3767c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->br_cmplq_mutex);
3777c478bd9Sstevel@tonic-gate 		cmd = hal->br_cmplq_head;
3787c478bd9Sstevel@tonic-gate 		hal->br_cmplq_head = hal->br_cmplq_tail = NULL;
3797c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->br_cmplq_mutex);
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 		while (cmd != NULL) {
3827c478bd9Sstevel@tonic-gate 			s_priv = S1394_GET_CMD_PRIV(cmd);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 			tcmd = s_priv->cmd_priv_next;
3857c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, &cmd);
3867c478bd9Sstevel@tonic-gate 			cmd = tcmd;
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->br_cmplq_mutex);
3907c478bd9Sstevel@tonic-gate 		cmd = hal->br_cmplq_head;
3917c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->br_cmplq_mutex);
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	} while (cmd != NULL);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate /*
3977c478bd9Sstevel@tonic-gate  * s1394_br_thread_exit()
3987c478bd9Sstevel@tonic-gate  *    Flushes the completion queue and calls thread_exit() (which effectively
3997c478bd9Sstevel@tonic-gate  *    kills the bus reset thread).
4007c478bd9Sstevel@tonic-gate  */
4017c478bd9Sstevel@tonic-gate static void
s1394_br_thread_exit(s1394_hal_t * hal)4027c478bd9Sstevel@tonic-gate s1394_br_thread_exit(s1394_hal_t *hal)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->br_thread_mutex));
4057c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
4067c478bd9Sstevel@tonic-gate 	s1394_flush_cmplq(hal);
4077c478bd9Sstevel@tonic-gate #ifndef	__lock_lint
4087c478bd9Sstevel@tonic-gate 	CALLB_CPR_EXIT(&hal->hal_cprinfo);
4097c478bd9Sstevel@tonic-gate #endif
4107c478bd9Sstevel@tonic-gate 	hal->br_thread_ev_type &= ~BR_THR_GO_AWAY;
4117c478bd9Sstevel@tonic-gate 	thread_exit();
4127c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate /*
4167c478bd9Sstevel@tonic-gate  * s1394_target_bus_reset_notifies()
4177c478bd9Sstevel@tonic-gate  *    tells the ndi event framework to invoke any callbacks registered for
4187c478bd9Sstevel@tonic-gate  *    "bus reset event".
4197c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate static void
s1394_target_bus_reset_notifies(s1394_hal_t * hal,t1394_localinfo_t * localinfo)4217c478bd9Sstevel@tonic-gate s1394_target_bus_reset_notifies(s1394_hal_t *hal, t1394_localinfo_t *localinfo)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, NULL,
4287c478bd9Sstevel@tonic-gate 	    DDI_DEVI_BUS_RESET_EVENT, &cookie, NDI_EVENT_NOPASS) ==
4297c478bd9Sstevel@tonic-gate 	    NDI_SUCCESS) {
4307c478bd9Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, NULL,
4317c478bd9Sstevel@tonic-gate 		    cookie, localinfo);
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate /*
4367c478bd9Sstevel@tonic-gate  * s1394_alloc_cfgrom()
4377c478bd9Sstevel@tonic-gate  *    Allocates config rom for the node. Sets CFGROM_NEW_ALLOC bit in the
4387c478bd9Sstevel@tonic-gate  *    node cfgrom state. Drops topology_tree_mutex around the calls to
4397c478bd9Sstevel@tonic-gate  *    kmem_zalloc(). If re-locking fails, returns DDI_FAILURE, else returns
4407c478bd9Sstevel@tonic-gate  *    DDI_SUCCESS.
4417c478bd9Sstevel@tonic-gate  */
4427c478bd9Sstevel@tonic-gate static int
s1394_alloc_cfgrom(s1394_hal_t * hal,s1394_node_t * node,s1394_status_t * status)4437c478bd9Sstevel@tonic-gate s1394_alloc_cfgrom(s1394_hal_t *hal, s1394_node_t *node, s1394_status_t *status)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	uint32_t *cfgrom;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	*status = S1394_NOSTATUS;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	/*
4527c478bd9Sstevel@tonic-gate 	 * if cfgrom is non-NULL, this has to be generation changed
4537c478bd9Sstevel@tonic-gate 	 * case (where we allocate cfgrom again to reread the cfgrom)
4547c478bd9Sstevel@tonic-gate 	 */
4557c478bd9Sstevel@tonic-gate 	ASSERT(node->cfgrom == NULL || (node->cfgrom != NULL &&
4567c478bd9Sstevel@tonic-gate 	    CFGROM_GEN_CHANGED(node) == B_TRUE));
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	/*
4597c478bd9Sstevel@tonic-gate 	 * if node matched, either cfgrom has to be NULL or link should be
4607c478bd9Sstevel@tonic-gate 	 * off in the last matched node or config rom generations changed.
4617c478bd9Sstevel@tonic-gate 	 */
4627c478bd9Sstevel@tonic-gate 	ASSERT(NODE_MATCHED(node) == B_FALSE || (NODE_MATCHED(node) == B_TRUE &&
4637c478bd9Sstevel@tonic-gate 	    (node->cfgrom == NULL || LINK_ACTIVE(node->old_node) == B_FALSE) ||
4647c478bd9Sstevel@tonic-gate 	    CFGROM_GEN_CHANGED(node) == B_TRUE));
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
4677c478bd9Sstevel@tonic-gate 	cfgrom = (uint32_t *)kmem_zalloc(IEEE1394_CONFIG_ROM_SZ, KM_SLEEP);
4687c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
4697c478bd9Sstevel@tonic-gate 		kmem_free(cfgrom, IEEE1394_CONFIG_ROM_SZ);
4707c478bd9Sstevel@tonic-gate 		*status |= S1394_LOCK_FAILED;
4717c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 	node->cfgrom = cfgrom;
4747c478bd9Sstevel@tonic-gate 	node->cfgrom_size = IEEE1394_CONFIG_ROM_QUAD_SZ;
4757c478bd9Sstevel@tonic-gate 	SET_CFGROM_NEW_ALLOC(node);
4767c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
4777c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate /*
4817c478bd9Sstevel@tonic-gate  * s1394_free_cfgrom()
4827c478bd9Sstevel@tonic-gate  *    Marks the config rom invalid and frees up the config based on otpions.
4837c478bd9Sstevel@tonic-gate  */
4847c478bd9Sstevel@tonic-gate void
s1394_free_cfgrom(s1394_hal_t * hal,s1394_node_t * node,s1394_free_cfgrom_t options)4857c478bd9Sstevel@tonic-gate s1394_free_cfgrom(s1394_hal_t *hal, s1394_node_t *node,
4867c478bd9Sstevel@tonic-gate     s1394_free_cfgrom_t options)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
4897c478bd9Sstevel@tonic-gate 	ASSERT(node->cfgrom != NULL);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	if (options == S1394_FREE_CFGROM_BOTH) {
4927c478bd9Sstevel@tonic-gate 		/*
4937c478bd9Sstevel@tonic-gate 		 * free in both old and new trees; will be called with
4947c478bd9Sstevel@tonic-gate 		 * new node.
4957c478bd9Sstevel@tonic-gate 		 */
4967c478bd9Sstevel@tonic-gate 		s1394_node_t *onode = node->old_node;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 		if (NODE_MATCHED(node) == B_TRUE && onode->cfgrom != NULL)
4997c478bd9Sstevel@tonic-gate 			ASSERT(onode->cfgrom == node->cfgrom);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		if (onode != NULL && onode->cfgrom != NULL && onode->cfgrom !=
5027c478bd9Sstevel@tonic-gate 		    node->cfgrom)
5037c478bd9Sstevel@tonic-gate 			kmem_free(onode->cfgrom, IEEE1394_CONFIG_ROM_SZ);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 		kmem_free(node->cfgrom, IEEE1394_CONFIG_ROM_SZ);
5067c478bd9Sstevel@tonic-gate 		onode->cfgrom = NULL;
5077c478bd9Sstevel@tonic-gate 		node->cfgrom = NULL;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 		CLEAR_CFGROM_STATE(onode);
5107c478bd9Sstevel@tonic-gate 		CLEAR_CFGROM_STATE(node);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	} else if (options == S1394_FREE_CFGROM_NEW) {
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 		ASSERT(CFGROM_NEW_ALLOC(node) == B_TRUE);
5157c478bd9Sstevel@tonic-gate 		kmem_free(node->cfgrom, IEEE1394_CONFIG_ROM_SZ);
5167c478bd9Sstevel@tonic-gate 		CLEAR_CFGROM_NEW_ALLOC(node);
5177c478bd9Sstevel@tonic-gate 		node->cfgrom = NULL;
5187c478bd9Sstevel@tonic-gate 		CLEAR_CFGROM_STATE(node);
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	} else if (options == S1394_FREE_CFGROM_OLD) {
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 		/* freeing in old tree */
5237c478bd9Sstevel@tonic-gate 		kmem_free(node->cfgrom, IEEE1394_CONFIG_ROM_SZ);
5247c478bd9Sstevel@tonic-gate 		node->cfgrom = NULL;
5257c478bd9Sstevel@tonic-gate 		CLEAR_CFGROM_STATE(node);
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate /*
5307c478bd9Sstevel@tonic-gate  * s1394_copy_cfgrom()
5317c478bd9Sstevel@tonic-gate  *    Copies config rom info from "from" node to "to" node. Clears
5327c478bd9Sstevel@tonic-gate  *    CFGROM_NEW_ALLOC bit in cfgrom state in bothe nodes. (CFGROM_NEW_ALLOC
5337c478bd9Sstevel@tonic-gate  *    acts as a reference count. If set, only the node in the current tree
5347c478bd9Sstevel@tonic-gate  *    has a pointer to it; if clear, both the node in the current tree as
5357c478bd9Sstevel@tonic-gate  *    well as the corresponding node in the old tree point to the same memory).
5367c478bd9Sstevel@tonic-gate  */
5377c478bd9Sstevel@tonic-gate void
s1394_copy_cfgrom(s1394_node_t * to,s1394_node_t * from)5387c478bd9Sstevel@tonic-gate s1394_copy_cfgrom(s1394_node_t *to, s1394_node_t *from)
5397c478bd9Sstevel@tonic-gate {
5407c478bd9Sstevel@tonic-gate 	ASSERT(to->cfgrom == NULL);
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	to->cfgrom = from->cfgrom;
5437c478bd9Sstevel@tonic-gate 	to->cfgrom_state = from->cfgrom_state;
5447c478bd9Sstevel@tonic-gate 	to->cfgrom_valid_size = from->cfgrom_valid_size;
5457c478bd9Sstevel@tonic-gate 	to->cfgrom_size = from->cfgrom_size;
5467c478bd9Sstevel@tonic-gate 	to->node_state = from->node_state;
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	bcopy(from->dir_stack, to->dir_stack,
5497c478bd9Sstevel@tonic-gate 	    offsetof(s1394_node_t, cfgrom_quad_to_read) -
5507c478bd9Sstevel@tonic-gate 	    offsetof(s1394_node_t, dir_stack));
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	to->cfgrom_quad_to_read = from->cfgrom_quad_to_read;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	CLEAR_CFGROM_NEW_ALLOC(to);
5557c478bd9Sstevel@tonic-gate 	CLEAR_CFGROM_NEW_ALLOC(from);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	/*
5587c478bd9Sstevel@tonic-gate 	 * old link off, new link on => handled in s1394_cfgrom_scan_phase1
5597c478bd9Sstevel@tonic-gate 	 * old link on, new link off => handled in s1394_process_old_tree
5607c478bd9Sstevel@tonic-gate 	 */
5617c478bd9Sstevel@tonic-gate 	if (LINK_ACTIVE(from) == B_FALSE) {
5627c478bd9Sstevel@tonic-gate 		/*
5637c478bd9Sstevel@tonic-gate 		 * if last time around, link was off, there wouldn't
5647c478bd9Sstevel@tonic-gate 		 * have been config rom allocated.
5657c478bd9Sstevel@tonic-gate 		 */
5667c478bd9Sstevel@tonic-gate 		ASSERT(from->cfgrom == NULL);
5677c478bd9Sstevel@tonic-gate 		return;
5687c478bd9Sstevel@tonic-gate 	} else {
5697c478bd9Sstevel@tonic-gate 		s1394_selfid_pkt_t *selfid_pkt = to->selfid_packet;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 		if (IEEE1394_SELFID_ISLINKON(selfid_pkt))
5727c478bd9Sstevel@tonic-gate 			SET_LINK_ACTIVE(to);
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate /*
5777c478bd9Sstevel@tonic-gate  * s1394_read_bus_info_blk()
5787c478bd9Sstevel@tonic-gate  *    Attempts to kick off reading IEEE1212_NODE_CAP_QUAD quad or quad 0.
5797c478bd9Sstevel@tonic-gate  *    Increments cfgroms_being_read by 1. Returns DDI_SUCCESS command was
5807c478bd9Sstevel@tonic-gate  *    issued, else sets status to the failure reason and returns DDI_FAILURE.
5817c478bd9Sstevel@tonic-gate  */
5827c478bd9Sstevel@tonic-gate static int
s1394_read_bus_info_blk(s1394_hal_t * hal,s1394_node_t * node,s1394_status_t * status)5837c478bd9Sstevel@tonic-gate s1394_read_bus_info_blk(s1394_hal_t *hal, s1394_node_t *node,
5847c478bd9Sstevel@tonic-gate     s1394_status_t *status)
5857c478bd9Sstevel@tonic-gate {
5867c478bd9Sstevel@tonic-gate 	uint32_t quadlet;
5877c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t *cmd;
5887c478bd9Sstevel@tonic-gate 	uchar_t node_num;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
5917c478bd9Sstevel@tonic-gate 	ASSERT(LINK_ACTIVE(node) == B_TRUE);
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	node_num = node->node_num;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	/*
5967c478bd9Sstevel@tonic-gate 	 * drop the topology lock around command allocation. Return failure
5977c478bd9Sstevel@tonic-gate 	 * if either command allocation fails or cannot reacquire the lock
5987c478bd9Sstevel@tonic-gate 	 */
5997c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
6007c478bd9Sstevel@tonic-gate 	*status = S1394_NOSTATUS;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
6037c478bd9Sstevel@tonic-gate 		*status |= S1394_CMD_ALLOC_FAILED;
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
6067c478bd9Sstevel@tonic-gate 		*status |= S1394_LOCK_FAILED;
6077c478bd9Sstevel@tonic-gate 		/* free the cmd allocated above */
6087c478bd9Sstevel@tonic-gate 		if (((*status) & S1394_CMD_ALLOC_FAILED) != 0)
6097c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 	if (((*status) & (S1394_CMD_ALLOC_FAILED | S1394_LOCK_FAILED)) != 0) {
6127c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6137c478bd9Sstevel@tonic-gate 	}
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	/* allocate cfgrom if needed */
6167c478bd9Sstevel@tonic-gate 	if (node->cfgrom == NULL && s1394_alloc_cfgrom(hal, node, status) !=
6177c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS) {
6187c478bd9Sstevel@tonic-gate 		ASSERT(((*status) & S1394_LOCK_FAILED) != 0);
6197c478bd9Sstevel@tonic-gate 		(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
6207c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
6217c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	/*
6257c478bd9Sstevel@tonic-gate 	 * if this is a matched node, read quad 2 (node capabilities) to
6267c478bd9Sstevel@tonic-gate 	 * see if the generation count changed.
6277c478bd9Sstevel@tonic-gate 	 */
6287c478bd9Sstevel@tonic-gate 	quadlet = CFGROM_BIB_READ(node) ? IEEE1212_NODE_CAP_QUAD : 0;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	/*
6317c478bd9Sstevel@tonic-gate 	 * read bus info block at 100Mbit. This will help us with the cases
6327c478bd9Sstevel@tonic-gate 	 * where LINK is slower than PHY; s1394 uses PHY speed till speed map
6337c478bd9Sstevel@tonic-gate 	 * is updated.
6347c478bd9Sstevel@tonic-gate 	 */
6357c478bd9Sstevel@tonic-gate 	cmd->completion_callback = s1394_cfgrom_read_callback;
6367c478bd9Sstevel@tonic-gate 	cmd->bus_generation = hal->generation_count;
6377c478bd9Sstevel@tonic-gate 	cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
6387c478bd9Sstevel@tonic-gate 	    CMD1394_OVERRIDE_ADDR | CMD1394_OVERRIDE_SPEED);
6397c478bd9Sstevel@tonic-gate 	cmd->cmd_speed = IEEE1394_S100;
6407c478bd9Sstevel@tonic-gate 	cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	QUAD_TO_CFGROM_ADDR(IEEE1394_LOCAL_BUS, node_num,
6437c478bd9Sstevel@tonic-gate 	    quadlet, cmd->cmd_addr);
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	SETUP_QUAD_READ(node, 1, quadlet, 1);
6467c478bd9Sstevel@tonic-gate 	if (s1394_read_config_quadlet(hal, cmd, status) != DDI_SUCCESS) {
6477c478bd9Sstevel@tonic-gate 		/* free the command if it wasn't handed over to the HAL */
6487c478bd9Sstevel@tonic-gate 		if (((*status) & S1394_CMD_INFLIGHT) == 0) {
6497c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
6507c478bd9Sstevel@tonic-gate 		}
6517c478bd9Sstevel@tonic-gate 		if (((*status) & S1394_LOCK_FAILED) != 0) {
6527c478bd9Sstevel@tonic-gate 			ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
6537c478bd9Sstevel@tonic-gate 		}
6547c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	hal->cfgroms_being_read++;
6587c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate  * s1394_read_rest_of_cfgrom()
6657c478bd9Sstevel@tonic-gate  *    Attempts to start reading node->cfgrom_quad_to_read quadlet. Increments
6667c478bd9Sstevel@tonic-gate  *    cfgroms_being_read by 1 and returns DDI_SUCCESS if command was issued,
6677c478bd9Sstevel@tonic-gate  *    else sets status to the failure reason and returns DDI_FAILURE.
6687c478bd9Sstevel@tonic-gate  */
6697c478bd9Sstevel@tonic-gate int
s1394_read_rest_of_cfgrom(s1394_hal_t * hal,s1394_node_t * node,s1394_status_t * status)6707c478bd9Sstevel@tonic-gate s1394_read_rest_of_cfgrom(s1394_hal_t *hal, s1394_node_t *node,
6717c478bd9Sstevel@tonic-gate     s1394_status_t *status)
6727c478bd9Sstevel@tonic-gate {
6737c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t *cmd;
6747c478bd9Sstevel@tonic-gate 	uchar_t node_num = node->node_num;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
6777c478bd9Sstevel@tonic-gate 	ASSERT(LINK_ACTIVE(node) == B_TRUE);
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	/*
6807c478bd9Sstevel@tonic-gate 	 * drop the topology lock around command allocation. Return failure
6817c478bd9Sstevel@tonic-gate 	 * if either command allocation fails or cannot reacquire the lock
6827c478bd9Sstevel@tonic-gate 	 */
6837c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
6847c478bd9Sstevel@tonic-gate 	*status = S1394_NOSTATUS;
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
6877c478bd9Sstevel@tonic-gate 		*status |= S1394_CMD_ALLOC_FAILED;
6887c478bd9Sstevel@tonic-gate 	}
6897c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
6907c478bd9Sstevel@tonic-gate 		*status |= S1394_LOCK_FAILED;
6917c478bd9Sstevel@tonic-gate 		/* free if we allocated a cmd above */
6927c478bd9Sstevel@tonic-gate 		if (((*status) & S1394_CMD_ALLOC_FAILED) == 0)
6937c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
6947c478bd9Sstevel@tonic-gate 	}
6957c478bd9Sstevel@tonic-gate 	if (((*status) & (S1394_CMD_ALLOC_FAILED | S1394_LOCK_FAILED)) != 0) {
6967c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	cmd->completion_callback = s1394_cfgrom_read_callback;
7007c478bd9Sstevel@tonic-gate 	cmd->bus_generation = hal->generation_count;
7017c478bd9Sstevel@tonic-gate 	cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
7027c478bd9Sstevel@tonic-gate 	    CMD1394_OVERRIDE_ADDR);
7037c478bd9Sstevel@tonic-gate 	cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	QUAD_TO_CFGROM_ADDR(IEEE1394_LOCAL_BUS, node_num,
7067c478bd9Sstevel@tonic-gate 	    node->cfgrom_quad_to_read, cmd->cmd_addr);
7077c478bd9Sstevel@tonic-gate 	SETUP_QUAD_READ(node, 1, node->cfgrom_quad_to_read, 1);
7087c478bd9Sstevel@tonic-gate 	if (s1394_read_config_quadlet(hal, cmd, status) != DDI_SUCCESS) {
7097c478bd9Sstevel@tonic-gate 		/* free the command if it wasn't handed over to the HAL */
7107c478bd9Sstevel@tonic-gate 		if (((*status) & S1394_CMD_INFLIGHT) == 0) {
7117c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
7127c478bd9Sstevel@tonic-gate 		}
7137c478bd9Sstevel@tonic-gate 		if (((*status) & S1394_LOCK_FAILED) != 0) {
7147c478bd9Sstevel@tonic-gate 			ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
7157c478bd9Sstevel@tonic-gate 		}
7167c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	hal->cfgroms_being_read++;
7207c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7237c478bd9Sstevel@tonic-gate }
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate /*
7267c478bd9Sstevel@tonic-gate  * s1394_cfgrom_scan_phase1()
7277c478bd9Sstevel@tonic-gate  *    Attempts to read bus info blocks for nodes as needed. Returns DDI_FAILURE
7287c478bd9Sstevel@tonic-gate  *    if bus reset generations changed (as indicated by s1394_lock_tree()
7297c478bd9Sstevel@tonic-gate  *    return status) or if any of the callees return failure, else returns
7307c478bd9Sstevel@tonic-gate  *    DDI_SUCCESS.
7317c478bd9Sstevel@tonic-gate  */
7327c478bd9Sstevel@tonic-gate static int
s1394_cfgrom_scan_phase1(s1394_hal_t * hal)7337c478bd9Sstevel@tonic-gate s1394_cfgrom_scan_phase1(s1394_hal_t *hal)
7347c478bd9Sstevel@tonic-gate {
7357c478bd9Sstevel@tonic-gate 	uint32_t number_of_nodes;
7367c478bd9Sstevel@tonic-gate 	int ret;
7377c478bd9Sstevel@tonic-gate 	int node;
7387c478bd9Sstevel@tonic-gate 	int wait_in_gen;
7397c478bd9Sstevel@tonic-gate 	int wait_for_cbs;
7407c478bd9Sstevel@tonic-gate 	uint_t hal_node_num;
7417c478bd9Sstevel@tonic-gate 	uint_t hal_node_num_old;
7427c478bd9Sstevel@tonic-gate 	s1394_node_t *nnode, *onode;
7437c478bd9Sstevel@tonic-gate 	s1394_selfid_pkt_t *selfid_pkt;
7447c478bd9Sstevel@tonic-gate 	s1394_status_t status;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
7497c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 	wait_for_cbs = 0;
7527c478bd9Sstevel@tonic-gate 	number_of_nodes = hal->number_of_nodes;
7537c478bd9Sstevel@tonic-gate 	hal->cfgroms_being_read = 0;
7547c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
7557c478bd9Sstevel@tonic-gate 	hal_node_num_old = IEEE1394_NODE_NUM(hal->old_node_id);
7567c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	ret = DDI_SUCCESS;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	/* Send requests for all new node config ROM 0 */
7617c478bd9Sstevel@tonic-gate 	for (node = 0; node < number_of_nodes; node++) {
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 		status = S1394_UNKNOWN;
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
7667c478bd9Sstevel@tonic-gate 			status = S1394_LOCK_FAILED;
7677c478bd9Sstevel@tonic-gate 			break;
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 		nnode = &hal->topology_tree[node];
7717c478bd9Sstevel@tonic-gate 		onode = nnode->old_node;
7727c478bd9Sstevel@tonic-gate 		/* if node matched, onode should be non NULL */
7737c478bd9Sstevel@tonic-gate 		ASSERT(NODE_MATCHED(nnode) == B_FALSE || (NODE_MATCHED(nnode) ==
7747c478bd9Sstevel@tonic-gate 		    B_TRUE && onode != NULL));
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 		/*
7777c478bd9Sstevel@tonic-gate 		 * Read bus info block if it is a brand new node (MATCHED is 0)
7787c478bd9Sstevel@tonic-gate 		 * or if matched but link was off in previous generations or
7797c478bd9Sstevel@tonic-gate 		 * or if matched but had invalid cfgrom in last generation
7807c478bd9Sstevel@tonic-gate 		 * or if matched but config rom generation > 1 (this is to
7817c478bd9Sstevel@tonic-gate 		 * check if config rom generation changed between bus resets).
7827c478bd9Sstevel@tonic-gate 		 */
7837c478bd9Sstevel@tonic-gate 		if ((node != hal_node_num) &&
7847c478bd9Sstevel@tonic-gate 		    ((NODE_MATCHED(nnode) == B_FALSE) ||
7857c478bd9Sstevel@tonic-gate 		    (NODE_MATCHED(nnode) == B_TRUE && LINK_ACTIVE(onode) ==
7867c478bd9Sstevel@tonic-gate 		    B_FALSE) || (NODE_MATCHED(nnode) == B_TRUE &&
7877c478bd9Sstevel@tonic-gate 		    (onode->cfgrom == NULL || CFGROM_VALID(onode) ==
7887c478bd9Sstevel@tonic-gate 		    B_FALSE)) || (NODE_MATCHED(nnode) == B_TRUE &&
7897c478bd9Sstevel@tonic-gate 		    nnode->cfgrom != NULL && CONFIG_ROM_GEN(nnode->cfgrom) >
7907c478bd9Sstevel@tonic-gate 		    1))) {
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 			SET_NODE_VISITED(nnode);
7937c478bd9Sstevel@tonic-gate 			selfid_pkt = nnode->selfid_packet;
7947c478bd9Sstevel@tonic-gate 			if (IEEE1394_SELFID_ISLINKON(selfid_pkt)) {
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 				SET_LINK_ACTIVE(nnode);
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 				status = S1394_UNKNOWN;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 				if (s1394_read_bus_info_blk(hal, nnode,
8017c478bd9Sstevel@tonic-gate 				    &status) != DDI_SUCCESS) {
8027c478bd9Sstevel@tonic-gate 					if ((status & S1394_LOCK_FAILED) != 0)
8037c478bd9Sstevel@tonic-gate 						break;
8047c478bd9Sstevel@tonic-gate 				} else {
8057c478bd9Sstevel@tonic-gate 					wait_for_cbs++;
8067c478bd9Sstevel@tonic-gate 					wait_in_gen = hal->br_cfgrom_read_gen;
8077c478bd9Sstevel@tonic-gate 				}
8087c478bd9Sstevel@tonic-gate 			} else {
8097c478bd9Sstevel@tonic-gate 				/*
8107c478bd9Sstevel@tonic-gate 				 * Special case: if link was active last
8117c478bd9Sstevel@tonic-gate 				 * time around, this should be treated as
8127c478bd9Sstevel@tonic-gate 				 * node going away.
8137c478bd9Sstevel@tonic-gate 				 */
8147c478bd9Sstevel@tonic-gate 				CLEAR_LINK_ACTIVE(nnode);
8157c478bd9Sstevel@tonic-gate 				if (NODE_MATCHED(nnode) == B_TRUE &&
8167c478bd9Sstevel@tonic-gate 				    LINK_ACTIVE(onode) == B_TRUE) {
8177c478bd9Sstevel@tonic-gate 					CLEAR_CFGROM_STATE(nnode);
8187c478bd9Sstevel@tonic-gate 				}
8197c478bd9Sstevel@tonic-gate 			}
8207c478bd9Sstevel@tonic-gate 		} else {
8217c478bd9Sstevel@tonic-gate 			if (node == hal_node_num) {
8227c478bd9Sstevel@tonic-gate 				onode = &hal->old_tree[hal_node_num_old];
8237c478bd9Sstevel@tonic-gate 				/* Set up the local matched nodes */
8247c478bd9Sstevel@tonic-gate 				if (onode) {
8257c478bd9Sstevel@tonic-gate 					nnode->old_node = onode;
8267c478bd9Sstevel@tonic-gate 					SET_NODE_MATCHED(nnode);
8277c478bd9Sstevel@tonic-gate 					SET_NODE_MATCHED(onode);
8287c478bd9Sstevel@tonic-gate 					s1394_copy_cfgrom(nnode, onode);
8297c478bd9Sstevel@tonic-gate 				}
8307c478bd9Sstevel@tonic-gate 			}
8317c478bd9Sstevel@tonic-gate 		}
8327c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
8337c478bd9Sstevel@tonic-gate 	}
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	if ((status & S1394_LOCK_FAILED) != 0) {
8387c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	/*
8427c478bd9Sstevel@tonic-gate 	 * If we started any reads, wait for completion callbacks
8437c478bd9Sstevel@tonic-gate 	 */
8447c478bd9Sstevel@tonic-gate 	if (wait_for_cbs != 0) {
8457c478bd9Sstevel@tonic-gate 		ret = s1394_wait_for_cfgrom_callbacks(hal, wait_in_gen,
8467c478bd9Sstevel@tonic-gate 		    s1394_br_thread_handle_cmd_phase1);
8477c478bd9Sstevel@tonic-gate 	}
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	return (ret);
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate /*
8557c478bd9Sstevel@tonic-gate  * s1394_br_thread_handle_cmd_phase1()
8567c478bd9Sstevel@tonic-gate  *    Process the cmd completion for phase 1 config rom reads. If we
8577c478bd9Sstevel@tonic-gate  *    successfully read IEEE1212_NODE_CAP_QUAD quadlet and config rom gen
8587c478bd9Sstevel@tonic-gate  *    did not change, move targets hanging off the old node to the current
8597c478bd9Sstevel@tonic-gate  *    node. If config rom generations change, alloc new config rom and start
8607c478bd9Sstevel@tonic-gate  *    re-reading the new config rom. If all of bus info block is read (as
8617c478bd9Sstevel@tonic-gate  *    required), mark the node as CFGROM_BIB_READ. If config rom read fails
8627c478bd9Sstevel@tonic-gate  *    retry if not too many failures. Topology tree mutex is dropped and
8637c478bd9Sstevel@tonic-gate  *    reacquired in this routine. If reacquiring fails, returns
8647c478bd9Sstevel@tonic-gate  *    S1394_HCMD_LOCK_FAILED. If the entire bus info block is read, returns
8657c478bd9Sstevel@tonic-gate  *    S1394_HCMD_NODE_DONE, else returns S1394_HCMD_NODE_EXPECT_MORE (to
8667c478bd9Sstevel@tonic-gate  *    indicate not done with the node yet).
8677c478bd9Sstevel@tonic-gate  *
8687c478bd9Sstevel@tonic-gate  *    If we cannot read any of the quadlets in the bus info block, cfgrom
8697c478bd9Sstevel@tonic-gate  *    is marked invalid in this generation (a side effect of calling
8707c478bd9Sstevel@tonic-gate  *    s1394_free_cfgrom()). We free cfgrom in this routine only if the failure
8717c478bd9Sstevel@tonic-gate  *    is not due to bus generations changing.
8727c478bd9Sstevel@tonic-gate  */
8737c478bd9Sstevel@tonic-gate static hcmd_ret_t
s1394_br_thread_handle_cmd_phase1(s1394_hal_t * hal,cmd1394_cmd_t * cmd)8747c478bd9Sstevel@tonic-gate s1394_br_thread_handle_cmd_phase1(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
8757c478bd9Sstevel@tonic-gate {
8767c478bd9Sstevel@tonic-gate 	s1394_target_t *t;
8777c478bd9Sstevel@tonic-gate 	s1394_node_t *node, *onode;
8787c478bd9Sstevel@tonic-gate 	uint32_t node_num, quadlet, data;
8797c478bd9Sstevel@tonic-gate 	int freecmd, done, locked;
8807c478bd9Sstevel@tonic-gate 	hcmd_ret_t cmdret;
8817c478bd9Sstevel@tonic-gate 	uchar_t readdelay;
8827c478bd9Sstevel@tonic-gate 	s1394_status_t status;
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	s1394_get_quad_info(cmd, &node_num, &quadlet, &data);
8857c478bd9Sstevel@tonic-gate 	ASSERT(quadlet == 0 || quadlet < IEEE1394_BIB_QUAD_SZ);
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	cmdret = S1394_HCMD_NODE_EXPECT_MORE;
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	locked = 1;
8907c478bd9Sstevel@tonic-gate 	freecmd = 1;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
8937c478bd9Sstevel@tonic-gate 		locked = 0;
8947c478bd9Sstevel@tonic-gate 		goto bail;
8957c478bd9Sstevel@tonic-gate 	}
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	node = &hal->topology_tree[node_num];
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 		int reread = 0;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 		done = 0;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 		if (quadlet == IEEE1212_NODE_CAP_QUAD &&
9067c478bd9Sstevel@tonic-gate 		    CFGROM_BIB_READ(node)) {
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 			int cur_gen = ((data & IEEE1394_BIB_GEN_MASK) >>
9097c478bd9Sstevel@tonic-gate 			    IEEE1394_BIB_GEN_SHIFT);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 			/*
9127c478bd9Sstevel@tonic-gate 			 * node->old_node can be NULL if this is a new node &
9137c478bd9Sstevel@tonic-gate 			 * we are doing a rescan
9147c478bd9Sstevel@tonic-gate 			 */
9157c478bd9Sstevel@tonic-gate 			onode = node->old_node;
9167c478bd9Sstevel@tonic-gate 			if (CONFIG_ROM_GEN(node->cfgrom) == cur_gen) {
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 				if (CFGROM_PARSED(node) == B_TRUE) {
9197c478bd9Sstevel@tonic-gate 					rw_enter(&hal->target_list_rwlock,
9207c478bd9Sstevel@tonic-gate 					    RW_WRITER);
9217c478bd9Sstevel@tonic-gate 					/* Update the target list, if any */
9227c478bd9Sstevel@tonic-gate 					if (onode != NULL &&
9237c478bd9Sstevel@tonic-gate 					    (t = onode->target_list) != NULL) {
9247c478bd9Sstevel@tonic-gate 						node->target_list = t;
9257c478bd9Sstevel@tonic-gate 						while (t != NULL) {
9267c478bd9Sstevel@tonic-gate 							t->on_node = node;
9277c478bd9Sstevel@tonic-gate 							t = t->target_sibling;
9287c478bd9Sstevel@tonic-gate 						}
9297c478bd9Sstevel@tonic-gate 					}
9307c478bd9Sstevel@tonic-gate 					rw_exit(&hal->target_list_rwlock);
9317c478bd9Sstevel@tonic-gate 				}
9327c478bd9Sstevel@tonic-gate 				SET_NODE_MATCHED(node);
9337c478bd9Sstevel@tonic-gate 				if (onode)
9347c478bd9Sstevel@tonic-gate 					SET_NODE_MATCHED(onode);
9357c478bd9Sstevel@tonic-gate 				node->cfgrom_quad_to_read =
9367c478bd9Sstevel@tonic-gate 				    IEEE1394_BIB_QUAD_SZ;
9377c478bd9Sstevel@tonic-gate 				done++;
9387c478bd9Sstevel@tonic-gate 			} else {
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 				SET_CFGROM_GEN_CHANGED(node);
9417c478bd9Sstevel@tonic-gate 				if (onode != NULL)
9427c478bd9Sstevel@tonic-gate 					SET_CFGROM_GEN_CHANGED(onode);
9437c478bd9Sstevel@tonic-gate 				/*
9447c478bd9Sstevel@tonic-gate 				 * Reset BIB_READ flag and start reading entire
9457c478bd9Sstevel@tonic-gate 				 * config rom.
9467c478bd9Sstevel@tonic-gate 				 */
9477c478bd9Sstevel@tonic-gate 				CLEAR_CFGROM_BIB_READ(node);
9487c478bd9Sstevel@tonic-gate 				reread = 1;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 				/*
9517c478bd9Sstevel@tonic-gate 				 * if generations changed, allocate cfgrom for
9527c478bd9Sstevel@tonic-gate 				 * the new generation. s1394_match_GUID() will
9537c478bd9Sstevel@tonic-gate 				 * free up the cfgrom from the old generation.
9547c478bd9Sstevel@tonic-gate 				 */
9557c478bd9Sstevel@tonic-gate 				if (s1394_alloc_cfgrom(hal, node, &status) !=
9567c478bd9Sstevel@tonic-gate 				    DDI_SUCCESS) {
9577c478bd9Sstevel@tonic-gate 					ASSERT((status & S1394_LOCK_FAILED) !=
9587c478bd9Sstevel@tonic-gate 					    0);
9597c478bd9Sstevel@tonic-gate 					ASSERT(MUTEX_NOT_HELD(&hal->
9607c478bd9Sstevel@tonic-gate 					    topology_tree_mutex));
9617c478bd9Sstevel@tonic-gate 					locked = 0;
9627c478bd9Sstevel@tonic-gate 					/* we failed to relock the tree */
9637c478bd9Sstevel@tonic-gate 					goto bail;
9647c478bd9Sstevel@tonic-gate 				}
9657c478bd9Sstevel@tonic-gate 			}
9667c478bd9Sstevel@tonic-gate 		}
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 		/*
9697c478bd9Sstevel@tonic-gate 		 * we end up here if we don't have bus_info_blk for this
9707c478bd9Sstevel@tonic-gate 		 * node or if config rom generation changed.
9717c478bd9Sstevel@tonic-gate 		 */
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 		/*
9747c478bd9Sstevel@tonic-gate 		 * Pass1 Rio bug workaround. Due to this bug, if we read
9757c478bd9Sstevel@tonic-gate 		 * past quadlet 5 of the config rom, the PCI bus gets wedged.
9767c478bd9Sstevel@tonic-gate 		 * Avoid the hang by not reading past quadlet 5.
9777c478bd9Sstevel@tonic-gate 		 * We identify a remote Rio by the node vendor id part of
9787c478bd9Sstevel@tonic-gate 		 * quad 3 (which is == SUNW == S1394_SUNW_OUI (0x80020)).
9797c478bd9Sstevel@tonic-gate 		 */
9807c478bd9Sstevel@tonic-gate 		if (s1394_enable_rio_pass1_workarounds != 0) {
9817c478bd9Sstevel@tonic-gate 			if ((quadlet == 3) && ((data >> 8) == S1394_SUNW_OUI)) {
9827c478bd9Sstevel@tonic-gate 				node->cfgrom_size = IEEE1394_BIB_QUAD_SZ;
9837c478bd9Sstevel@tonic-gate 				node->cfgrom_valid_size = IEEE1394_BIB_QUAD_SZ;
9847c478bd9Sstevel@tonic-gate 			}
9857c478bd9Sstevel@tonic-gate 		}
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 		if (!done) {
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 			if (reread)
9907c478bd9Sstevel@tonic-gate 				quadlet = 0;
9917c478bd9Sstevel@tonic-gate 			else
9927c478bd9Sstevel@tonic-gate 				node->cfgrom[quadlet++] = data;
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 			/* if we don't have the entire bus_info_blk... */
9957c478bd9Sstevel@tonic-gate 			if (quadlet < IEEE1394_BIB_QUAD_SZ) {
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 				CFGROM_GET_READ_DELAY(node, readdelay);
9987c478bd9Sstevel@tonic-gate 				SETUP_QUAD_READ(node, 1, quadlet, 1);
9997c478bd9Sstevel@tonic-gate 				s1394_unlock_tree(hal);
10007c478bd9Sstevel@tonic-gate 				CFGROM_READ_PAUSE(readdelay);
10017c478bd9Sstevel@tonic-gate 				/* get next quadlet */
10027c478bd9Sstevel@tonic-gate 				if (s1394_lock_tree(hal) != DDI_SUCCESS) {
10037c478bd9Sstevel@tonic-gate 					locked = 0;
10047c478bd9Sstevel@tonic-gate 				} else if (s1394_read_config_quadlet(hal, cmd,
10057c478bd9Sstevel@tonic-gate 				    &status) != DDI_SUCCESS) {
10067c478bd9Sstevel@tonic-gate 					/*
10077c478bd9Sstevel@tonic-gate 					 * Failed to get going. If command was
10087c478bd9Sstevel@tonic-gate 					 * successfully handed over to the HAL,
10097c478bd9Sstevel@tonic-gate 					 * don't free it (it will get freed
10107c478bd9Sstevel@tonic-gate 					 * later in the callback).
10117c478bd9Sstevel@tonic-gate 					 */
10127c478bd9Sstevel@tonic-gate 					if ((status & S1394_CMD_INFLIGHT) !=
10137c478bd9Sstevel@tonic-gate 					    0) {
10147c478bd9Sstevel@tonic-gate 						freecmd = 0;
10157c478bd9Sstevel@tonic-gate 					}
10167c478bd9Sstevel@tonic-gate 					if ((status & S1394_LOCK_FAILED) != 0) {
10177c478bd9Sstevel@tonic-gate 						locked = 0;
10187c478bd9Sstevel@tonic-gate 					} else {
1019*d5ebc493SDan Cross 						const s1394_free_cfgrom_t S =
1020*d5ebc493SDan Cross 						    S1394_FREE_CFGROM_NEW;
10217c478bd9Sstevel@tonic-gate 						if (CFGROM_NEW_ALLOC(node) ==
10227c478bd9Sstevel@tonic-gate 						    B_TRUE) {
10237c478bd9Sstevel@tonic-gate 							s1394_free_cfgrom(hal,
1024*d5ebc493SDan Cross 							    node, S);
10257c478bd9Sstevel@tonic-gate 						} else {
10267c478bd9Sstevel@tonic-gate 							CLEAR_CFGROM_STATE(
10277c478bd9Sstevel@tonic-gate 							    node);
10287c478bd9Sstevel@tonic-gate 						}
10297c478bd9Sstevel@tonic-gate 					}
10307c478bd9Sstevel@tonic-gate 					done++;
10317c478bd9Sstevel@tonic-gate 				} else {
10327c478bd9Sstevel@tonic-gate 					freecmd = 0;
10337c478bd9Sstevel@tonic-gate 				}
10347c478bd9Sstevel@tonic-gate 			} else {
10357c478bd9Sstevel@tonic-gate 				/* got all of bus_info_blk */
10367c478bd9Sstevel@tonic-gate 				SET_CFGROM_BIB_READ(node);
10377c478bd9Sstevel@tonic-gate 				if (node->cfgrom_size == IEEE1394_BIB_QUAD_SZ)
1038*d5ebc493SDan Cross 					SET_CFGROM_ALL_READ(node);
10397c478bd9Sstevel@tonic-gate 				node->cfgrom_quad_to_read = quadlet;
10407c478bd9Sstevel@tonic-gate 				done++;
10417c478bd9Sstevel@tonic-gate 			}
10427c478bd9Sstevel@tonic-gate 		}
10437c478bd9Sstevel@tonic-gate 	} else {
10447c478bd9Sstevel@tonic-gate 		done = 1;
10457c478bd9Sstevel@tonic-gate 		node->cfgrom_read_fails++;
10467c478bd9Sstevel@tonic-gate 		BUMP_CFGROM_READ_DELAY(node);
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 		/* retry if not too many failures */
10497c478bd9Sstevel@tonic-gate 		if (node->cfgrom_read_fails < s1394_cfgrom_read_retry_cnt) {
10507c478bd9Sstevel@tonic-gate 			CFGROM_GET_READ_DELAY(node, readdelay);
10517c478bd9Sstevel@tonic-gate 			SETUP_QUAD_READ(node, 0, quadlet, 1);
10527c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
10537c478bd9Sstevel@tonic-gate 			CFGROM_READ_PAUSE(readdelay);
10547c478bd9Sstevel@tonic-gate 			if (s1394_lock_tree(hal) != DDI_SUCCESS) {
10557c478bd9Sstevel@tonic-gate 				locked = 0;
10567c478bd9Sstevel@tonic-gate 			} else if (s1394_read_config_quadlet(hal, cmd,
10577c478bd9Sstevel@tonic-gate 			    &status) != DDI_SUCCESS) {
10587c478bd9Sstevel@tonic-gate 				/*
10597c478bd9Sstevel@tonic-gate 				 * Failed to get going. If command was
10607c478bd9Sstevel@tonic-gate 				 * successfully handed over to the HAL,
10617c478bd9Sstevel@tonic-gate 				 * don't free it (it will get freed
10627c478bd9Sstevel@tonic-gate 				 * later in the callback).
10637c478bd9Sstevel@tonic-gate 				 */
10647c478bd9Sstevel@tonic-gate 				if ((status & S1394_CMD_INFLIGHT) != 0) {
10657c478bd9Sstevel@tonic-gate 					freecmd = 0;
10667c478bd9Sstevel@tonic-gate 				}
10677c478bd9Sstevel@tonic-gate 				if ((status & S1394_LOCK_FAILED) != 0) {
10687c478bd9Sstevel@tonic-gate 					locked = 0;
10697c478bd9Sstevel@tonic-gate 				} else {
10707c478bd9Sstevel@tonic-gate 					if (CFGROM_NEW_ALLOC(node) == B_TRUE) {
10717c478bd9Sstevel@tonic-gate 						s1394_free_cfgrom(hal, node,
10727c478bd9Sstevel@tonic-gate 						    S1394_FREE_CFGROM_NEW);
10737c478bd9Sstevel@tonic-gate 					} else {
10747c478bd9Sstevel@tonic-gate 						CLEAR_CFGROM_STATE(node);
10757c478bd9Sstevel@tonic-gate 					}
10767c478bd9Sstevel@tonic-gate 				}
10777c478bd9Sstevel@tonic-gate 			} else {
10787c478bd9Sstevel@tonic-gate 				done = 0;
10797c478bd9Sstevel@tonic-gate 				freecmd = 0;
10807c478bd9Sstevel@tonic-gate 			}
10817c478bd9Sstevel@tonic-gate 		} else {
10827c478bd9Sstevel@tonic-gate 			if (CFGROM_NEW_ALLOC(node) == B_TRUE) {
10837c478bd9Sstevel@tonic-gate 				s1394_free_cfgrom(hal, node,
10847c478bd9Sstevel@tonic-gate 				    S1394_FREE_CFGROM_NEW);
10857c478bd9Sstevel@tonic-gate 			} else {
10867c478bd9Sstevel@tonic-gate 				CLEAR_CFGROM_STATE(node);
10877c478bd9Sstevel@tonic-gate 			}
10887c478bd9Sstevel@tonic-gate 		}
10897c478bd9Sstevel@tonic-gate 	}
10907c478bd9Sstevel@tonic-gate bail:
10917c478bd9Sstevel@tonic-gate 	if (freecmd) {
10927c478bd9Sstevel@tonic-gate 		(void) s1394_free_cmd(hal, &cmd);
10937c478bd9Sstevel@tonic-gate 	}
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	if (done) {
10967c478bd9Sstevel@tonic-gate 		cmdret = S1394_HCMD_NODE_DONE;
10977c478bd9Sstevel@tonic-gate 	}
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	/* if we are bailing out because locking failed, locked == 0 */
11007c478bd9Sstevel@tonic-gate 	if (locked == 0)
11017c478bd9Sstevel@tonic-gate 		cmdret = S1394_HCMD_LOCK_FAILED;
11027c478bd9Sstevel@tonic-gate 	else
11037c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	return (cmdret);
11067c478bd9Sstevel@tonic-gate }
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate /*
11097c478bd9Sstevel@tonic-gate  * s1394_cfgrom_scan_phase2()
11107c478bd9Sstevel@tonic-gate  *    Handles phase 2 of bus reset processing. Matches GUIDs between old
11117c478bd9Sstevel@tonic-gate  *    and new topology trees to identify which node moved where. Processes
11127c478bd9Sstevel@tonic-gate  *    the old topology tree (involves offlining any nodes that got unplugged
11137c478bd9Sstevel@tonic-gate  *    between the last generation and the current generation). Updates speed
11147c478bd9Sstevel@tonic-gate  *    map, sets up physical AR request filer and does isoch resource
11157c478bd9Sstevel@tonic-gate  *    realloc failure notification and bus reset notifications. Then resends
11167c478bd9Sstevel@tonic-gate  *    any commands that were issued by targets while the reset was being
11177c478bd9Sstevel@tonic-gate  *    processed. Finally, the current topology tree is processed. This involves
11187c478bd9Sstevel@tonic-gate  *    reading config rom past the bus info block for new nodes and parsing
11197c478bd9Sstevel@tonic-gate  *    the config rom, creating a devinfo for each unit directory found in the
11207c478bd9Sstevel@tonic-gate  *    config rom.
11217c478bd9Sstevel@tonic-gate  *    Returns DDI_FAILURE if there was bus reset during any of the function
11227c478bd9Sstevel@tonic-gate  *    calls (as indicated by lock failures) or if any of the routines callees
11237c478bd9Sstevel@tonic-gate  *    return failure, else returns DDI_SUCCESS.
11247c478bd9Sstevel@tonic-gate  */
11257c478bd9Sstevel@tonic-gate static int
s1394_cfgrom_scan_phase2(s1394_hal_t * hal)11267c478bd9Sstevel@tonic-gate s1394_cfgrom_scan_phase2(s1394_hal_t *hal)
11277c478bd9Sstevel@tonic-gate {
11287c478bd9Sstevel@tonic-gate 	int ret;
11297c478bd9Sstevel@tonic-gate 	uint_t wait_gen;
11307c478bd9Sstevel@tonic-gate 	int wait_for_cbs = 0;
11317c478bd9Sstevel@tonic-gate 	t1394_localinfo_t localinfo;
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
11367c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11377c478bd9Sstevel@tonic-gate 	}
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	if (s1394_match_all_GUIDs(hal) == DDI_SUCCESS) {
11407c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	if (s1394_process_old_tree(hal) != DDI_SUCCESS) {
11447c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
11457c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11467c478bd9Sstevel@tonic-gate 	}
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
11497c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11507c478bd9Sstevel@tonic-gate 	}
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	s1394_update_speed_map_link_speeds(hal);
11537c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	/* Setup physical AR request filters */
11567c478bd9Sstevel@tonic-gate 	s1394_physical_arreq_setup_all(hal);
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	/* Notify targets of isoch resource realloc failures */
11597c478bd9Sstevel@tonic-gate 	s1394_isoch_rsrc_realloc_notify(hal);
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	/* Notify targets of the end of bus reset processing */
11627c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
11637c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11647c478bd9Sstevel@tonic-gate 	}
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	localinfo.bus_generation = hal->generation_count;
11677c478bd9Sstevel@tonic-gate 	localinfo.local_nodeID = hal->node_id;
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
11707c478bd9Sstevel@tonic-gate 	s1394_target_bus_reset_notifies(hal, &localinfo);
11717c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
11727c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	/* Set HAL state to normal */
11767c478bd9Sstevel@tonic-gate 	if (hal->disable_requests_bit == 0)
11777c478bd9Sstevel@tonic-gate 		hal->hal_state = S1394_HAL_NORMAL;
11787c478bd9Sstevel@tonic-gate 	else
11797c478bd9Sstevel@tonic-gate 		hal->hal_state = S1394_HAL_DREQ;
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	/* Flush the pending Q */
11847c478bd9Sstevel@tonic-gate 	s1394_resend_pending_cmds(hal);
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	if (s1394_process_topology_tree(hal, &wait_for_cbs, &wait_gen)) {
11877c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
11887c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11897c478bd9Sstevel@tonic-gate 	}
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
11927c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11937c478bd9Sstevel@tonic-gate 	}
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	s1394_print_node_info(hal);
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	ret = DDI_SUCCESS;
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	/*
12047c478bd9Sstevel@tonic-gate 	 * If we started any reads, wait for completion callbacks
12057c478bd9Sstevel@tonic-gate 	 */
12067c478bd9Sstevel@tonic-gate 	if (wait_for_cbs != 0) {
12077c478bd9Sstevel@tonic-gate 		ret = s1394_wait_for_cfgrom_callbacks(hal, wait_gen,
12087c478bd9Sstevel@tonic-gate 		    s1394_br_thread_handle_cmd_phase2);
12097c478bd9Sstevel@tonic-gate 	}
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	return (ret);
12147c478bd9Sstevel@tonic-gate }
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate /*
12177c478bd9Sstevel@tonic-gate  * s1394_br_thread_handle_cmd_phase2()
12187c478bd9Sstevel@tonic-gate  *    Process the cmd completion for phase 2 config rom reads. If all the
12197c478bd9Sstevel@tonic-gate  *    needed quads are read, validates the config rom; if config rom is
12207c478bd9Sstevel@tonic-gate  *    invalid (crc failures), frees the config rom, else marks the config rom
12217c478bd9Sstevel@tonic-gate  *    valid and calls s1394_update_devinfo_tree() to parse the config rom.
12227c478bd9Sstevel@tonic-gate  *    If need to get more quadlets, attempts to kick off the read and returns
12237c478bd9Sstevel@tonic-gate  *    S1394_HCMD_NODE_EXPECT_MORE if successfully started the read. If a bus
12247c478bd9Sstevel@tonic-gate  *    reset is seen while in this routine, returns S1394_HCMD_LOCK_FAILED. If
12257c478bd9Sstevel@tonic-gate  *    done with the node (with or withoug crc errors), returns
12267c478bd9Sstevel@tonic-gate  *    S1394_HCMD_NODE_DONE, else returns S1394_HCMD_NODE_EXPECT_MORE (to
12277c478bd9Sstevel@tonic-gate  *    indicate not done with the node yet).
12287c478bd9Sstevel@tonic-gate  */
12297c478bd9Sstevel@tonic-gate static hcmd_ret_t
s1394_br_thread_handle_cmd_phase2(s1394_hal_t * hal,cmd1394_cmd_t * cmd)12307c478bd9Sstevel@tonic-gate s1394_br_thread_handle_cmd_phase2(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
12317c478bd9Sstevel@tonic-gate {
12327c478bd9Sstevel@tonic-gate 	s1394_node_t *node;
12337c478bd9Sstevel@tonic-gate 	uint32_t node_num, quadlet, data;
12347c478bd9Sstevel@tonic-gate 	int update_devinfo, locked, freecmd, done;
12357c478bd9Sstevel@tonic-gate 	hcmd_ret_t cmdret;
12367c478bd9Sstevel@tonic-gate 	uchar_t readdelay;
12377c478bd9Sstevel@tonic-gate 	s1394_status_t status;
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 	/*
12407c478bd9Sstevel@tonic-gate 	 * we end up here if this is a brand new node or if it is a known node
12417c478bd9Sstevel@tonic-gate 	 * but the config ROM changed (and triggered a re-read).
12427c478bd9Sstevel@tonic-gate 	 */
12437c478bd9Sstevel@tonic-gate 	s1394_get_quad_info(cmd, &node_num, &quadlet, &data);
12447c478bd9Sstevel@tonic-gate 	ASSERT(quadlet == IEEE1394_BIB_QUAD_SZ || quadlet <
12457c478bd9Sstevel@tonic-gate 	    IEEE1394_CONFIG_ROM_QUAD_SZ);
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	locked = freecmd = done = 1;
12487c478bd9Sstevel@tonic-gate 	cmdret = S1394_HCMD_NODE_EXPECT_MORE;
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	update_devinfo = 0;
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
12537c478bd9Sstevel@tonic-gate 		locked = 0;
12547c478bd9Sstevel@tonic-gate 		goto bail;
12557c478bd9Sstevel@tonic-gate 	}
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	node = &hal->topology_tree[node_num];
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 		ASSERT(CFGROM_BIB_READ(node) == B_TRUE);
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 		node->cfgrom[quadlet] = data;
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 		if (s1394_calc_next_quad(hal, node, quadlet, &quadlet) != 0) {
12667c478bd9Sstevel@tonic-gate 			/*
12677c478bd9Sstevel@tonic-gate 			 * Done with this node. Mark config rom valid and
12687c478bd9Sstevel@tonic-gate 			 * update the devinfo tree for this node.
12697c478bd9Sstevel@tonic-gate 			 */
12707c478bd9Sstevel@tonic-gate 			node->cfgrom_valid_size = quadlet + 1;
12717c478bd9Sstevel@tonic-gate 			if (s1394_valid_cfgrom(hal, node) == B_TRUE) {
12727c478bd9Sstevel@tonic-gate 				SET_CFGROM_ALL_READ(node);
12737c478bd9Sstevel@tonic-gate 				update_devinfo++;
12747c478bd9Sstevel@tonic-gate 			} else {
12757c478bd9Sstevel@tonic-gate 				s1394_free_cfgrom(hal, node,
12767c478bd9Sstevel@tonic-gate 				    S1394_FREE_CFGROM_BOTH);
12777c478bd9Sstevel@tonic-gate 			}
12787c478bd9Sstevel@tonic-gate 		} else {
12797c478bd9Sstevel@tonic-gate 			CFGROM_GET_READ_DELAY(node, readdelay);
12807c478bd9Sstevel@tonic-gate 			SETUP_QUAD_READ(node, 1, quadlet, 1);
12817c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
12827c478bd9Sstevel@tonic-gate 			CFGROM_READ_PAUSE(readdelay);
12837c478bd9Sstevel@tonic-gate 			if (s1394_lock_tree(hal) != DDI_SUCCESS) {
12847c478bd9Sstevel@tonic-gate 				locked = 0;
12857c478bd9Sstevel@tonic-gate 			} else if (s1394_read_config_quadlet(hal, cmd,
12867c478bd9Sstevel@tonic-gate 			    &status) != DDI_SUCCESS) {
12877c478bd9Sstevel@tonic-gate 				/* give up on this guy */
12887c478bd9Sstevel@tonic-gate 				if ((status & S1394_CMD_INFLIGHT) != 0) {
12897c478bd9Sstevel@tonic-gate 					freecmd = 0;
12907c478bd9Sstevel@tonic-gate 				}
12917c478bd9Sstevel@tonic-gate 				if ((status & S1394_LOCK_FAILED) != 0) {
12927c478bd9Sstevel@tonic-gate 					locked = 0;
12937c478bd9Sstevel@tonic-gate 				} else {
12947c478bd9Sstevel@tonic-gate 					node->cfgrom_valid_size = quadlet;
12957c478bd9Sstevel@tonic-gate 					if (s1394_valid_cfgrom(hal, node) ==
12967c478bd9Sstevel@tonic-gate 					    B_TRUE) {
12977c478bd9Sstevel@tonic-gate 						SET_CFGROM_ALL_READ(node);
12987c478bd9Sstevel@tonic-gate 						update_devinfo++;
12997c478bd9Sstevel@tonic-gate 					} else {
13007c478bd9Sstevel@tonic-gate 						s1394_free_cfgrom(hal, node,
13017c478bd9Sstevel@tonic-gate 						    S1394_FREE_CFGROM_BOTH);
13027c478bd9Sstevel@tonic-gate 					}
13037c478bd9Sstevel@tonic-gate 				}
13047c478bd9Sstevel@tonic-gate 			} else {
13057c478bd9Sstevel@tonic-gate 				/* successfully started next read */
13067c478bd9Sstevel@tonic-gate 				done = 0;
13077c478bd9Sstevel@tonic-gate 				freecmd = 0;
13087c478bd9Sstevel@tonic-gate 			}
13097c478bd9Sstevel@tonic-gate 		}
13107c478bd9Sstevel@tonic-gate 	} else {
13117c478bd9Sstevel@tonic-gate 		node->cfgrom_read_fails++;
13127c478bd9Sstevel@tonic-gate 		BUMP_CFGROM_READ_DELAY(node);
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 		/* retry if not too many failures */
13157c478bd9Sstevel@tonic-gate 		if (node->cfgrom_read_fails < s1394_cfgrom_read_retry_cnt) {
13167c478bd9Sstevel@tonic-gate 			CFGROM_GET_READ_DELAY(node, readdelay);
13177c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
13187c478bd9Sstevel@tonic-gate 			SETUP_QUAD_READ(node, 0, quadlet, 1);
13197c478bd9Sstevel@tonic-gate 			CFGROM_READ_PAUSE(readdelay);
13207c478bd9Sstevel@tonic-gate 			if (s1394_lock_tree(hal) != DDI_SUCCESS) {
13217c478bd9Sstevel@tonic-gate 				locked = 0;
13227c478bd9Sstevel@tonic-gate 			} else if (s1394_read_config_quadlet(hal, cmd,
13237c478bd9Sstevel@tonic-gate 			    &status) != DDI_SUCCESS) {
13247c478bd9Sstevel@tonic-gate 				if ((status & S1394_CMD_INFLIGHT) != 0) {
13257c478bd9Sstevel@tonic-gate 					freecmd = 0;
13267c478bd9Sstevel@tonic-gate 				}
13277c478bd9Sstevel@tonic-gate 				if ((status & S1394_LOCK_FAILED) != 0) {
13287c478bd9Sstevel@tonic-gate 					locked = 0;
13297c478bd9Sstevel@tonic-gate 				} else {
13307c478bd9Sstevel@tonic-gate 					/* stop further reads */
13317c478bd9Sstevel@tonic-gate 					node->cfgrom_valid_size = quadlet + 1;
13327c478bd9Sstevel@tonic-gate 					if (s1394_valid_cfgrom(hal, node) ==
13337c478bd9Sstevel@tonic-gate 					    B_TRUE) {
13347c478bd9Sstevel@tonic-gate 						SET_CFGROM_ALL_READ(node);
13357c478bd9Sstevel@tonic-gate 						update_devinfo++;
13367c478bd9Sstevel@tonic-gate 					} else {
13377c478bd9Sstevel@tonic-gate 						s1394_free_cfgrom(hal, node,
13387c478bd9Sstevel@tonic-gate 						    S1394_FREE_CFGROM_BOTH);
13397c478bd9Sstevel@tonic-gate 					}
13407c478bd9Sstevel@tonic-gate 				}
13417c478bd9Sstevel@tonic-gate 			} else {
13427c478bd9Sstevel@tonic-gate 				/* successfully started next read */
13437c478bd9Sstevel@tonic-gate 				done = 0;
13447c478bd9Sstevel@tonic-gate 				freecmd = 0;
13457c478bd9Sstevel@tonic-gate 			}
13467c478bd9Sstevel@tonic-gate 		} else {
13477c478bd9Sstevel@tonic-gate 			node->cfgrom_valid_size = quadlet + 1;
13487c478bd9Sstevel@tonic-gate 			if (s1394_valid_cfgrom(hal, node) == B_TRUE) {
13497c478bd9Sstevel@tonic-gate 				SET_CFGROM_ALL_READ(node);
13507c478bd9Sstevel@tonic-gate 				update_devinfo++;
13517c478bd9Sstevel@tonic-gate 			} else {
13527c478bd9Sstevel@tonic-gate 				s1394_free_cfgrom(hal, node,
13537c478bd9Sstevel@tonic-gate 				    S1394_FREE_CFGROM_BOTH);
13547c478bd9Sstevel@tonic-gate 			}
13557c478bd9Sstevel@tonic-gate 		}
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate bail:
13587c478bd9Sstevel@tonic-gate 	if (freecmd) {
13597c478bd9Sstevel@tonic-gate 		(void) s1394_free_cmd(hal, &cmd);
13607c478bd9Sstevel@tonic-gate 	}
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 	if (done) {
13637c478bd9Sstevel@tonic-gate 		cmdret = S1394_HCMD_NODE_DONE;
13647c478bd9Sstevel@tonic-gate 	}
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	if (update_devinfo) {
13677c478bd9Sstevel@tonic-gate 		ASSERT(locked);
13687c478bd9Sstevel@tonic-gate 		/*
13697c478bd9Sstevel@tonic-gate 		 * s1394_update_devinfo_tree() drops and reacquires the
13707c478bd9Sstevel@tonic-gate 		 * topology_tree_mutex. If tree lock fails, it returns
13717c478bd9Sstevel@tonic-gate 		 * a DDI_FAILURE. Set locked to 0 so in this case so that
13727c478bd9Sstevel@tonic-gate 		 * we will return S1394_HCMD_LOCK_FAILED below
13737c478bd9Sstevel@tonic-gate 		 */
13747c478bd9Sstevel@tonic-gate 		if (s1394_update_devinfo_tree(hal, node) != DDI_SUCCESS) {
13757c478bd9Sstevel@tonic-gate 			ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
13767c478bd9Sstevel@tonic-gate 			locked = 0;
13777c478bd9Sstevel@tonic-gate 		}
13787c478bd9Sstevel@tonic-gate 	}
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 	/* if we are bailing out because locking failed, locked == 0 */
13817c478bd9Sstevel@tonic-gate 	if (locked == 0)
13827c478bd9Sstevel@tonic-gate 		cmdret = S1394_HCMD_LOCK_FAILED;
13837c478bd9Sstevel@tonic-gate 	else
13847c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	return (cmdret);
13877c478bd9Sstevel@tonic-gate }
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate /*
13907c478bd9Sstevel@tonic-gate  * s1394_read_config_quadlet()
13917c478bd9Sstevel@tonic-gate  *    Starts the reads of a config quadlet (deduced cmd_addr).  Returns
13927c478bd9Sstevel@tonic-gate  *    DDI_SUCCESS if the read was started with no errors, else DDI_FAILURE
13937c478bd9Sstevel@tonic-gate  *    is returned, with status indicating the reason for the failure(s).
13947c478bd9Sstevel@tonic-gate  */
13957c478bd9Sstevel@tonic-gate static int
s1394_read_config_quadlet(s1394_hal_t * hal,cmd1394_cmd_t * cmd,s1394_status_t * status)13967c478bd9Sstevel@tonic-gate s1394_read_config_quadlet(s1394_hal_t *hal, cmd1394_cmd_t *cmd,
13977c478bd9Sstevel@tonic-gate     s1394_status_t *status)
13987c478bd9Sstevel@tonic-gate {
13997c478bd9Sstevel@tonic-gate 	s1394_node_t *node;
14007c478bd9Sstevel@tonic-gate 	int ret, err, node_num, quadlet;
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
14037c478bd9Sstevel@tonic-gate 	node_num = IEEE1394_ADDR_PHY_ID(cmd->cmd_addr);
14047c478bd9Sstevel@tonic-gate 	node = &hal->topology_tree[node_num];
14057c478bd9Sstevel@tonic-gate 	quadlet = node->cfgrom_quad_to_read;
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	/* Calculate the 64-bit address */
14087c478bd9Sstevel@tonic-gate 	QUAD_TO_CFGROM_ADDR(IEEE1394_LOCAL_BUS, node_num, quadlet,
14097c478bd9Sstevel@tonic-gate 	    cmd->cmd_addr);
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	*status = S1394_NOSTATUS;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 	ret = s1394_setup_asynch_command(hal, NULL, cmd, S1394_CMD_READ, &err);
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
14167c478bd9Sstevel@tonic-gate 		*status |= S1394_UNKNOWN;
14177c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
14187c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
14197c478bd9Sstevel@tonic-gate 	}
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
14227c478bd9Sstevel@tonic-gate 	ret = DDI_SUCCESS;
14237c478bd9Sstevel@tonic-gate 	/* Send the command out */
14247c478bd9Sstevel@tonic-gate 	if (s1394_xfer_asynch_command(hal, cmd, &err) == DDI_SUCCESS) {
14257c478bd9Sstevel@tonic-gate 		/* Callers can expect a callback now */
14267c478bd9Sstevel@tonic-gate 		*status |= S1394_CMD_INFLIGHT;
14277c478bd9Sstevel@tonic-gate 	} else {
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 		s1394_cmd_priv_t *s_priv;
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 		/* Remove from queue */
14327c478bd9Sstevel@tonic-gate 		s1394_remove_q_asynch_cmd(hal, cmd);
14337c478bd9Sstevel@tonic-gate 		s_priv = S1394_GET_CMD_PRIV(cmd);
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 		s_priv->cmd_in_use = B_FALSE;
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 		*status |= S1394_XFER_FAILED;
14387c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
14397c478bd9Sstevel@tonic-gate 	}
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
14427c478bd9Sstevel@tonic-gate 		*status |= S1394_LOCK_FAILED;
14437c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
14447c478bd9Sstevel@tonic-gate 	}
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 	return (ret);
14477c478bd9Sstevel@tonic-gate }
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate /*
14507c478bd9Sstevel@tonic-gate  * s1394_cfgrom_read_callback()
14517c478bd9Sstevel@tonic-gate  *    callback routine for config rom reads. Frees the command if it failed
14527c478bd9Sstevel@tonic-gate  *    due to bus reset else appends the command to the completion queue
14537c478bd9Sstevel@tonic-gate  *    and signals the completion queue cv.
14547c478bd9Sstevel@tonic-gate  */
14557c478bd9Sstevel@tonic-gate static void
s1394_cfgrom_read_callback(cmd1394_cmd_t * cmd)14567c478bd9Sstevel@tonic-gate s1394_cfgrom_read_callback(cmd1394_cmd_t *cmd)
14577c478bd9Sstevel@tonic-gate {
14587c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t *tcmd;
14597c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
14607c478bd9Sstevel@tonic-gate 	s1394_hal_t *hal;
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate #if defined(DEBUG)
14637c478bd9Sstevel@tonic-gate 	uint32_t node_num, quadlet, data;
14647c478bd9Sstevel@tonic-gate #endif
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	/* Get the Services Layer private area */
14677c478bd9Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(cmd);
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	hal = (s1394_hal_t *)s_priv->sent_on_hal;
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate #if defined(DEBUG)
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 	s1394_get_quad_info(cmd, &node_num, &quadlet, &data);
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate #endif
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	if (cmd->cmd_result == CMD1394_EBUSRESET) {
14787c478bd9Sstevel@tonic-gate 		(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
14797c478bd9Sstevel@tonic-gate 	} else {
14807c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->br_cmplq_mutex);
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 		/* Put the command on completion queue */
14837c478bd9Sstevel@tonic-gate 		s_priv->cmd_priv_next = NULL;
14847c478bd9Sstevel@tonic-gate 		if ((tcmd = hal->br_cmplq_tail) != NULL) {
14857c478bd9Sstevel@tonic-gate 			s_priv = S1394_GET_CMD_PRIV(tcmd);
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate 			s_priv->cmd_priv_next = cmd;
14887c478bd9Sstevel@tonic-gate 		}
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 		hal->br_cmplq_tail = cmd;
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 		if (hal->br_cmplq_head == NULL)
14937c478bd9Sstevel@tonic-gate 			hal->br_cmplq_head = cmd;
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 		cv_signal(&hal->br_cmplq_cv);
14967c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->br_cmplq_mutex);
14977c478bd9Sstevel@tonic-gate 	}
14987c478bd9Sstevel@tonic-gate }
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate /*
15017c478bd9Sstevel@tonic-gate  * s1394_cfgrom_parse_unit_dir()
15027c478bd9Sstevel@tonic-gate  *    Parses the unit directory passed in and returns reg[2...5] of reg
15037c478bd9Sstevel@tonic-gate  *    property (see 1275 binding for reg property defintion). Currently,
15047c478bd9Sstevel@tonic-gate  *    returns 0 for all the values since none of the existing devices implement
15057c478bd9Sstevel@tonic-gate  *    this and future devices, per P1212r, need a binding change.
15067c478bd9Sstevel@tonic-gate  */
15077c478bd9Sstevel@tonic-gate /* ARGSUSED */
15087c478bd9Sstevel@tonic-gate void
s1394_cfgrom_parse_unit_dir(uint32_t * unit_dir,uint32_t * addr_hi,uint32_t * addr_lo,uint32_t * size_hi,uint32_t * size_lo)15097c478bd9Sstevel@tonic-gate s1394_cfgrom_parse_unit_dir(uint32_t *unit_dir, uint32_t *addr_hi,
15107c478bd9Sstevel@tonic-gate     uint32_t *addr_lo, uint32_t *size_hi, uint32_t *size_lo)
15117c478bd9Sstevel@tonic-gate {
15127c478bd9Sstevel@tonic-gate 	*addr_hi = *addr_lo = *size_hi = *size_lo = 0;
15137c478bd9Sstevel@tonic-gate }
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate /*
15167c478bd9Sstevel@tonic-gate  * s1394_get_quad_info()
15177c478bd9Sstevel@tonic-gate  *    Helper routine that picks apart the various fields of a 1394 address
15187c478bd9Sstevel@tonic-gate  */
15197c478bd9Sstevel@tonic-gate static void
s1394_get_quad_info(cmd1394_cmd_t * cmd,uint32_t * node_num,uint32_t * quadlet,uint32_t * data)15207c478bd9Sstevel@tonic-gate s1394_get_quad_info(cmd1394_cmd_t *cmd, uint32_t *node_num, uint32_t *quadlet,
15217c478bd9Sstevel@tonic-gate     uint32_t *data)
15227c478bd9Sstevel@tonic-gate {
15237c478bd9Sstevel@tonic-gate 	uint64_t addr;
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 	addr = cmd->cmd_addr;
15267c478bd9Sstevel@tonic-gate 	*node_num = IEEE1394_ADDR_PHY_ID(addr);
15277c478bd9Sstevel@tonic-gate 	*quadlet = ((addr & IEEE1394_ADDR_OFFSET_MASK) -
15287c478bd9Sstevel@tonic-gate 	    IEEE1394_CONFIG_ROM_ADDR);
15297c478bd9Sstevel@tonic-gate 	*quadlet = (*quadlet >> 2);
15307c478bd9Sstevel@tonic-gate 	*data = T1394_DATA32(cmd->cmd_u.q.quadlet_data);
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate /*
15347c478bd9Sstevel@tonic-gate  * s1394_match_GUID()
15357c478bd9Sstevel@tonic-gate  *    attempts to match nnode (which is in the current topology tree) with
15367c478bd9Sstevel@tonic-gate  *    a node in the old topology tree by comparing GUIDs. If a match is found
15377c478bd9Sstevel@tonic-gate  *    the old_node field of the current node and cur_node field of the old
15387c478bd9Sstevel@tonic-gate  *    are set point to each other. Also, this routine makes both the nodes
15397c478bd9Sstevel@tonic-gate  *    point at the same config rom.  If unable to relock the tree, returns
15407c478bd9Sstevel@tonic-gate  *    DDI_FAILURE, else returns DDI_SUCCESS.
15417c478bd9Sstevel@tonic-gate  */
15427c478bd9Sstevel@tonic-gate static int
s1394_match_GUID(s1394_hal_t * hal,s1394_node_t * nnode)15437c478bd9Sstevel@tonic-gate s1394_match_GUID(s1394_hal_t *hal, s1394_node_t *nnode)
15447c478bd9Sstevel@tonic-gate {
15457c478bd9Sstevel@tonic-gate 	int old_node;
15467c478bd9Sstevel@tonic-gate 	int gen_changed;
15477c478bd9Sstevel@tonic-gate 	uint32_t old_a, old_b;
15487c478bd9Sstevel@tonic-gate 	uint32_t new_a, new_b;
15497c478bd9Sstevel@tonic-gate 	s1394_node_t *onode;
15507c478bd9Sstevel@tonic-gate 	s1394_target_t *t;
15517c478bd9Sstevel@tonic-gate 	int	ret = DDI_SUCCESS;
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	ASSERT(nnode->cfgrom != NULL);
15547c478bd9Sstevel@tonic-gate 	ASSERT(CFGROM_BIB_READ(nnode));
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 	new_a = nnode->node_guid_hi;
15577c478bd9Sstevel@tonic-gate 	new_b = nnode->node_guid_lo;
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	for (old_node = 0; old_node < hal->old_number_of_nodes; old_node++) {
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 		onode = &hal->old_tree[old_node];
15627c478bd9Sstevel@tonic-gate 		if (onode->cfgrom == NULL || CFGROM_BIB_READ(onode) == B_FALSE)
15637c478bd9Sstevel@tonic-gate 			continue;
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 		old_a = onode->node_guid_hi;
15667c478bd9Sstevel@tonic-gate 		old_b = onode->node_guid_lo;
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 		if ((old_a == new_a) && (old_b == new_b)) {
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 			if (NODE_MATCHED(onode) == B_TRUE) {
15717c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "!Duplicate GUIDs: %08x%08x",
15727c478bd9Sstevel@tonic-gate 				    old_a, old_b);
15737c478bd9Sstevel@tonic-gate 				/* offline the new node that last matched */
15747c478bd9Sstevel@tonic-gate 				ret = s1394_offline_node(hal, onode->cur_node);
15757c478bd9Sstevel@tonic-gate 				/* and make the current new node invalid */
15767c478bd9Sstevel@tonic-gate 				ASSERT(CFGROM_NEW_ALLOC(nnode) == B_TRUE);
15777c478bd9Sstevel@tonic-gate 				s1394_free_cfgrom(hal, nnode,
15787c478bd9Sstevel@tonic-gate 				    S1394_FREE_CFGROM_NEW);
15797c478bd9Sstevel@tonic-gate 				break;
15807c478bd9Sstevel@tonic-gate 			}
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 			/*
15837c478bd9Sstevel@tonic-gate 			 * If there is indeed a cfgrom gen change,
15847c478bd9Sstevel@tonic-gate 			 * CFGROM_GEN_CHANGED() will be set iff we are matching
15857c478bd9Sstevel@tonic-gate 			 * tree nodes. Otherwise, CONFIG_ROM_GEN(old) !=
15867c478bd9Sstevel@tonic-gate 			 * CONFIG_ROM_GEN(new).
15877c478bd9Sstevel@tonic-gate 			 */
15887c478bd9Sstevel@tonic-gate 			if (CFGROM_GEN_CHANGED(nnode) == B_TRUE ||
15897c478bd9Sstevel@tonic-gate 			    (CONFIG_ROM_GEN(onode->cfgrom) !=
15907c478bd9Sstevel@tonic-gate 			    CONFIG_ROM_GEN(nnode->cfgrom))) {
15917c478bd9Sstevel@tonic-gate 				gen_changed = 1;
15927c478bd9Sstevel@tonic-gate 			} else {
15937c478bd9Sstevel@tonic-gate 				gen_changed = 0;
15947c478bd9Sstevel@tonic-gate 			}
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 			onode->cur_node = nnode;
15977c478bd9Sstevel@tonic-gate 			nnode->old_node = onode;
15987c478bd9Sstevel@tonic-gate 			nnode->node_state = onode->node_state;
15997c478bd9Sstevel@tonic-gate 			SET_NODE_VISITED(onode);
16007c478bd9Sstevel@tonic-gate 			SET_NODE_MATCHED(onode);
16017c478bd9Sstevel@tonic-gate 			SET_NODE_MATCHED(nnode);
16027c478bd9Sstevel@tonic-gate 			/*
16037c478bd9Sstevel@tonic-gate 			 * If generations changed, need to offline any targets
16047c478bd9Sstevel@tonic-gate 			 * hanging off the old node, prior to freeing up old
16057c478bd9Sstevel@tonic-gate 			 * cfgrom. If the generations didn't change, we can
16067c478bd9Sstevel@tonic-gate 			 * free up the new config rom and copy all info from
16077c478bd9Sstevel@tonic-gate 			 * the old node (this helps in picking up further
16087c478bd9Sstevel@tonic-gate 			 * reads from where the last generation left off).
16097c478bd9Sstevel@tonic-gate 			 */
16107c478bd9Sstevel@tonic-gate 			if (gen_changed == 1) {
16117c478bd9Sstevel@tonic-gate 				if (s1394_offline_node(hal, onode)) {
16127c478bd9Sstevel@tonic-gate 					ret = DDI_FAILURE;
16137c478bd9Sstevel@tonic-gate 					break;
16147c478bd9Sstevel@tonic-gate 				}
16157c478bd9Sstevel@tonic-gate 				s1394_free_cfgrom(hal, onode,
16167c478bd9Sstevel@tonic-gate 				    S1394_FREE_CFGROM_OLD);
16177c478bd9Sstevel@tonic-gate 				CLEAR_CFGROM_PARSED(nnode);
16187c478bd9Sstevel@tonic-gate 				CLEAR_CFGROM_NEW_ALLOC(nnode);
16197c478bd9Sstevel@tonic-gate 				CLEAR_CFGROM_NEW_ALLOC(onode);
16207c478bd9Sstevel@tonic-gate 				onode->cfgrom = nnode->cfgrom;
16217c478bd9Sstevel@tonic-gate 				/* done */
16227c478bd9Sstevel@tonic-gate 				break;
16237c478bd9Sstevel@tonic-gate 			}
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate 			/*
16267c478bd9Sstevel@tonic-gate 			 * Free up cfgrom memory in the new_node and
16277c478bd9Sstevel@tonic-gate 			 * point it at the same config rom as the old one.
16287c478bd9Sstevel@tonic-gate 			 */
16297c478bd9Sstevel@tonic-gate 			if (onode->cfgrom != nnode->cfgrom) {
16307c478bd9Sstevel@tonic-gate 				ASSERT(CFGROM_NEW_ALLOC(nnode) == B_TRUE);
16317c478bd9Sstevel@tonic-gate 				s1394_free_cfgrom(hal, nnode,
16327c478bd9Sstevel@tonic-gate 				    S1394_FREE_CFGROM_NEW);
16337c478bd9Sstevel@tonic-gate 			}
16347c478bd9Sstevel@tonic-gate 			nnode->cfgrom = onode->cfgrom;
16357c478bd9Sstevel@tonic-gate 			nnode->cfgrom_state = onode->cfgrom_state;
16367c478bd9Sstevel@tonic-gate 			nnode->cfgrom_valid_size = onode->cfgrom_valid_size;
16377c478bd9Sstevel@tonic-gate 			nnode->cfgrom_size = onode->cfgrom_size;
16387c478bd9Sstevel@tonic-gate 			nnode->cfgrom_quad_to_read = onode->cfgrom_quad_to_read;
16397c478bd9Sstevel@tonic-gate 			bcopy(onode->dir_stack, nnode->dir_stack,
16407c478bd9Sstevel@tonic-gate 			    offsetof(s1394_node_t, cfgrom_quad_to_read) -
16417c478bd9Sstevel@tonic-gate 			    offsetof(s1394_node_t, dir_stack));
16427c478bd9Sstevel@tonic-gate 			CLEAR_CFGROM_NEW_ALLOC(nnode);
16437c478bd9Sstevel@tonic-gate 			CLEAR_CFGROM_NEW_ALLOC(onode);
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 			if (CFGROM_PARSED(nnode) == B_TRUE) {
16467c478bd9Sstevel@tonic-gate 				rw_enter(&hal->target_list_rwlock, RW_WRITER);
16477c478bd9Sstevel@tonic-gate 				/* Update the target list */
16487c478bd9Sstevel@tonic-gate 				if ((t = onode->target_list) != NULL) {
16497c478bd9Sstevel@tonic-gate 					nnode->target_list = t;
16507c478bd9Sstevel@tonic-gate 					while (t != NULL) {
16517c478bd9Sstevel@tonic-gate 						t->on_node = nnode;
16527c478bd9Sstevel@tonic-gate 						t = t->target_sibling;
16537c478bd9Sstevel@tonic-gate 					}
16547c478bd9Sstevel@tonic-gate 				}
16557c478bd9Sstevel@tonic-gate 				rw_exit(&hal->target_list_rwlock);
16567c478bd9Sstevel@tonic-gate 			}
16577c478bd9Sstevel@tonic-gate 			break;
16587c478bd9Sstevel@tonic-gate 		}
16597c478bd9Sstevel@tonic-gate 	}
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate 	return (ret);
16627c478bd9Sstevel@tonic-gate }
16637c478bd9Sstevel@tonic-gate 
16647c478bd9Sstevel@tonic-gate /*
16657c478bd9Sstevel@tonic-gate  * s1394_match_all_GUIDs()
16667c478bd9Sstevel@tonic-gate  *    attempt to match each node in the current topology tree with the a
16677c478bd9Sstevel@tonic-gate  *    node in the old topology tree.  If unable to relock the tree, returns
16687c478bd9Sstevel@tonic-gate  *    DDI_FAILURE, else returns DDI_SUCCESS.
16697c478bd9Sstevel@tonic-gate  */
16707c478bd9Sstevel@tonic-gate static int
s1394_match_all_GUIDs(s1394_hal_t * hal)16717c478bd9Sstevel@tonic-gate s1394_match_all_GUIDs(s1394_hal_t *hal)
16727c478bd9Sstevel@tonic-gate {
16737c478bd9Sstevel@tonic-gate 	int node;
16747c478bd9Sstevel@tonic-gate 	int ret = DDI_SUCCESS;
16757c478bd9Sstevel@tonic-gate 	s1394_node_t *nnode;
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	for (node = 0; node < hal->number_of_nodes; node++) {
16807c478bd9Sstevel@tonic-gate 		nnode = &hal->topology_tree[node];
16817c478bd9Sstevel@tonic-gate 		if (LINK_ACTIVE(nnode) == B_FALSE || CFGROM_BIB_READ(nnode) ==
16827c478bd9Sstevel@tonic-gate 		    B_FALSE)
16837c478bd9Sstevel@tonic-gate 			continue;
16847c478bd9Sstevel@tonic-gate 		if (NODE_MATCHED(nnode)) {
16857c478bd9Sstevel@tonic-gate 			/*
16867c478bd9Sstevel@tonic-gate 			 * Skip if node matched. If config rom generations
16877c478bd9Sstevel@tonic-gate 			 * changed, we want to call s1394_match_GUID() even
16887c478bd9Sstevel@tonic-gate 			 * if the nodes matched.
16897c478bd9Sstevel@tonic-gate 			 */
16907c478bd9Sstevel@tonic-gate 			int gen_changed;
16917c478bd9Sstevel@tonic-gate 			s1394_node_t *onode = nnode->old_node;
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 			gen_changed = (onode && onode->cfgrom &&
16947c478bd9Sstevel@tonic-gate 			    CONFIG_ROM_GEN(onode->cfgrom) != CONFIG_ROM_GEN(
16957c478bd9Sstevel@tonic-gate 			    nnode->cfgrom)) ? 1 : 0;
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 			if (CFGROM_GEN_CHANGED(nnode) == 0 && gen_changed == 0)
16987c478bd9Sstevel@tonic-gate 				continue;
16997c478bd9Sstevel@tonic-gate 		}
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 		if (s1394_match_GUID(hal, nnode) == DDI_FAILURE) {
17027c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
17037c478bd9Sstevel@tonic-gate 		}
17047c478bd9Sstevel@tonic-gate 	}
17057c478bd9Sstevel@tonic-gate 
17067c478bd9Sstevel@tonic-gate 	return (ret);
17077c478bd9Sstevel@tonic-gate }
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate /*
17107c478bd9Sstevel@tonic-gate  * s1394_valid_cfgrom()
17117c478bd9Sstevel@tonic-gate  *    Performs crc check on the config rom. Returns B_TRUE if config rom has
17127c478bd9Sstevel@tonic-gate  *    good CRC else returns B_FALSE.
17137c478bd9Sstevel@tonic-gate  */
17147c478bd9Sstevel@tonic-gate /* ARGSUSED */
17157c478bd9Sstevel@tonic-gate boolean_t
s1394_valid_cfgrom(s1394_hal_t * hal,s1394_node_t * node)17167c478bd9Sstevel@tonic-gate s1394_valid_cfgrom(s1394_hal_t *hal, s1394_node_t *node)
17177c478bd9Sstevel@tonic-gate {
17187c478bd9Sstevel@tonic-gate 	uint32_t crc_len, crc_value, CRC, CRC_old, quad0;
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
17217c478bd9Sstevel@tonic-gate 	ASSERT(node->cfgrom);
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	if (s1394_enable_crc_validation == 0) {
17247c478bd9Sstevel@tonic-gate 		return (B_TRUE);
17257c478bd9Sstevel@tonic-gate 	}
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 	quad0 = node->cfgrom[0];
17287c478bd9Sstevel@tonic-gate 	crc_len = (quad0 >> IEEE1394_CFG_ROM_CRC_LEN_SHIFT) &
17297c478bd9Sstevel@tonic-gate 	    IEEE1394_CFG_ROM_CRC_LEN_MASK;
17307c478bd9Sstevel@tonic-gate 	crc_value = quad0 & IEEE1394_CFG_ROM_CRC_VALUE_MASK;
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	if (node->cfgrom_valid_size < crc_len + 1) {
17337c478bd9Sstevel@tonic-gate 		return (B_FALSE);
17347c478bd9Sstevel@tonic-gate 	}
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate 	CRC = s1394_CRC16(&node->cfgrom[1], crc_len);
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	if (CRC != crc_value) {
17397c478bd9Sstevel@tonic-gate 		CRC_old = s1394_CRC16_old(&node->cfgrom[1], crc_len);
17407c478bd9Sstevel@tonic-gate 		if (CRC_old == crc_value) {
17417c478bd9Sstevel@tonic-gate 			return (B_TRUE);
17427c478bd9Sstevel@tonic-gate 		}
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
17457c478bd9Sstevel@tonic-gate 		    "!Bad CRC in config rom (node's GUID %08x%08x)",
17467c478bd9Sstevel@tonic-gate 		    node->node_guid_hi, node->node_guid_lo);
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 		return (B_FALSE);
17497c478bd9Sstevel@tonic-gate 	}
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 	return (B_TRUE);
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate /*
17557c478bd9Sstevel@tonic-gate  * s1394_valid_dir()
17567c478bd9Sstevel@tonic-gate  *    Performs crc check on a directory.  Returns B_TRUE if dir has good CRC
17577c478bd9Sstevel@tonic-gate  *    else returns B_FALSE.
17587c478bd9Sstevel@tonic-gate  */
17597c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17607c478bd9Sstevel@tonic-gate boolean_t
s1394_valid_dir(s1394_hal_t * hal,s1394_node_t * node,uint32_t key,uint32_t * dir)17617c478bd9Sstevel@tonic-gate s1394_valid_dir(s1394_hal_t *hal, s1394_node_t *node,
17627c478bd9Sstevel@tonic-gate     uint32_t key, uint32_t *dir)
17637c478bd9Sstevel@tonic-gate {
17647c478bd9Sstevel@tonic-gate 	uint32_t dir_len, crc_value, CRC, CRC_old, quad0;
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 	/*
17677c478bd9Sstevel@tonic-gate 	 * Ideally, we would like to do crc validations for the entire cfgrom
17687c478bd9Sstevel@tonic-gate 	 * as well as the individual directories. However, we have seen devices
17697c478bd9Sstevel@tonic-gate 	 * that have valid directories but busted cfgrom crc and devices that
17707c478bd9Sstevel@tonic-gate 	 * have bad crcs in directories as well as for the entire cfgrom. This
17717c478bd9Sstevel@tonic-gate 	 * is sad, but unfortunately, real world!
17727c478bd9Sstevel@tonic-gate 	 */
17737c478bd9Sstevel@tonic-gate 	if (s1394_enable_crc_validation == 0) {
17747c478bd9Sstevel@tonic-gate 		return (B_TRUE);
17757c478bd9Sstevel@tonic-gate 	}
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	quad0 = dir[0];
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	dir_len = IEEE1212_DIR_LEN(quad0);
17807c478bd9Sstevel@tonic-gate 	crc_value = IEEE1212_DIR_CRC(quad0);
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 	CRC = s1394_CRC16(&dir[1], dir_len);
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 	if (CRC != crc_value) {
17877c478bd9Sstevel@tonic-gate 		CRC_old = s1394_CRC16_old(&dir[1], dir_len);
17887c478bd9Sstevel@tonic-gate 		if (CRC_old == crc_value) {
17897c478bd9Sstevel@tonic-gate 			return (B_TRUE);
17907c478bd9Sstevel@tonic-gate 		}
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 		return (B_FALSE);
17937c478bd9Sstevel@tonic-gate 	}
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	return (B_TRUE);
17967c478bd9Sstevel@tonic-gate }
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate /*
17997c478bd9Sstevel@tonic-gate  * s1394_become_bus_mgr()
18007c478bd9Sstevel@tonic-gate  *    is a callback from a timeout() setup by the main br_thread.  After
18017c478bd9Sstevel@tonic-gate  *    a bus reset, depending on the Bus Manager's incumbancy and the state
18027c478bd9Sstevel@tonic-gate  *    of its abdicate bit, a timer of a certain length is set.  After this
18037c478bd9Sstevel@tonic-gate  *    time expires, the local host may attempt to become the Bus Manager.
18047c478bd9Sstevel@tonic-gate  *    This is done by sending a request to the current IRM on the bus.  The
18057c478bd9Sstevel@tonic-gate  *    IRM holds the BUS_MANAGER_ID register.  Depending on whether or not
18067c478bd9Sstevel@tonic-gate  *    the local host is already the IRM, we will send a request onto the
18077c478bd9Sstevel@tonic-gate  *    1394 bus or call into the HAL.
18087c478bd9Sstevel@tonic-gate  */
18097c478bd9Sstevel@tonic-gate static void
s1394_become_bus_mgr(void * arg)18107c478bd9Sstevel@tonic-gate s1394_become_bus_mgr(void *arg)
18117c478bd9Sstevel@tonic-gate {
18127c478bd9Sstevel@tonic-gate 	s1394_hal_t	 *hal;
18137c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
18147c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t	 *cmd;
18157c478bd9Sstevel@tonic-gate 	uint64_t	 Bus_Mgr_ID_addr;
18167c478bd9Sstevel@tonic-gate 	uint32_t	 hal_node_num;
18177c478bd9Sstevel@tonic-gate 	uint32_t	 old_value;
18187c478bd9Sstevel@tonic-gate 	uint32_t	 generation;
18197c478bd9Sstevel@tonic-gate 	uint_t		 curr_bus_mgr;
18207c478bd9Sstevel@tonic-gate 	uint_t		 bm_node;
18217c478bd9Sstevel@tonic-gate 	uint_t		 IRM_node;
18227c478bd9Sstevel@tonic-gate 	int		 err;
18237c478bd9Sstevel@tonic-gate 	int		 ret;
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate 	hal = (s1394_hal_t *)arg;
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 	/* Lock the topology tree */
18287c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
18317c478bd9Sstevel@tonic-gate 	generation   = hal->generation_count;
18327c478bd9Sstevel@tonic-gate 	IRM_node = hal->IRM_node;
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->bus_mgr_node_mutex);
18357c478bd9Sstevel@tonic-gate 	bm_node = hal->bus_mgr_node;
18367c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->bus_mgr_node_mutex);
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	/* Unlock the topology tree */
18397c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 	/* Make sure we aren't already the Bus Manager */
18427c478bd9Sstevel@tonic-gate 	if (bm_node != -1) {
18437c478bd9Sstevel@tonic-gate 		return;
18447c478bd9Sstevel@tonic-gate 	}
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@tonic-gate 	/* Send compare-swap to BUS_MANAGER_ID */
18477c478bd9Sstevel@tonic-gate 	/* register on the Isoch Rsrc Mgr */
18487c478bd9Sstevel@tonic-gate 	if (IRM_node == hal_node_num) {
18497c478bd9Sstevel@tonic-gate 		/* Local */
18507c478bd9Sstevel@tonic-gate 		ret = HAL_CALL(hal).csr_cswap32(hal->halinfo.hal_private,
18517c478bd9Sstevel@tonic-gate 		    generation, (IEEE1394_SCSR_BUSMGR_ID &
18527c478bd9Sstevel@tonic-gate 		    IEEE1394_CSR_OFFSET_MASK), S1394_INVALID_NODE_NUM,
18537c478bd9Sstevel@tonic-gate 		    hal_node_num, &old_value);
18547c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
18557c478bd9Sstevel@tonic-gate 			return;
18567c478bd9Sstevel@tonic-gate 		}
18577c478bd9Sstevel@tonic-gate 		curr_bus_mgr = IEEE1394_NODE_NUM(old_value);
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->bus_mgr_node_mutex);
18607c478bd9Sstevel@tonic-gate 		if ((curr_bus_mgr == S1394_INVALID_NODE_NUM) ||
18617c478bd9Sstevel@tonic-gate 		    (curr_bus_mgr == hal_node_num)) {
18627c478bd9Sstevel@tonic-gate 			hal->bus_mgr_node = hal_node_num;
18637c478bd9Sstevel@tonic-gate 			hal->incumbent_bus_mgr = B_TRUE;
18647c478bd9Sstevel@tonic-gate 		} else {
18657c478bd9Sstevel@tonic-gate 			hal->bus_mgr_node = curr_bus_mgr;
18667c478bd9Sstevel@tonic-gate 			hal->incumbent_bus_mgr = B_FALSE;
18677c478bd9Sstevel@tonic-gate 		}
18687c478bd9Sstevel@tonic-gate 		cv_signal(&hal->bus_mgr_node_cv);
18697c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->bus_mgr_node_mutex);
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate 	} else {
18727c478bd9Sstevel@tonic-gate 		/* Remote */
18737c478bd9Sstevel@tonic-gate 		if (s1394_alloc_cmd(hal, T1394_ALLOC_CMD_NOSLEEP, &cmd) !=
18747c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
18757c478bd9Sstevel@tonic-gate 			return;
18767c478bd9Sstevel@tonic-gate 		}
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate 		cmd->cmd_options	   = (CMD1394_CANCEL_ON_BUS_RESET |
18797c478bd9Sstevel@tonic-gate 		    CMD1394_OVERRIDE_ADDR);
18807c478bd9Sstevel@tonic-gate 		cmd->cmd_type		   = CMD1394_ASYNCH_LOCK_32;
18817c478bd9Sstevel@tonic-gate 		cmd->completion_callback   = s1394_become_bus_mgr_callback;
18827c478bd9Sstevel@tonic-gate 		Bus_Mgr_ID_addr		   = (IEEE1394_ADDR_BUS_ID_MASK |
18837c478bd9Sstevel@tonic-gate 		    IEEE1394_SCSR_BUSMGR_ID) |
18847c478bd9Sstevel@tonic-gate 		    (((uint64_t)hal->IRM_node) << IEEE1394_ADDR_PHY_ID_SHIFT);
18857c478bd9Sstevel@tonic-gate 		cmd->cmd_addr		   = Bus_Mgr_ID_addr;
18867c478bd9Sstevel@tonic-gate 		cmd->bus_generation	   = generation;
18877c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.arg_value   = T1394_DATA32(
18887c478bd9Sstevel@tonic-gate 		    S1394_INVALID_NODE_NUM);
18897c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.data_value  = T1394_DATA32(hal_node_num);
18907c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.num_retries = 0;
18917c478bd9Sstevel@tonic-gate 		cmd->cmd_u.l32.lock_type   = CMD1394_LOCK_COMPARE_SWAP;
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 		/* Get the Services Layer private area */
18947c478bd9Sstevel@tonic-gate 		s_priv = S1394_GET_CMD_PRIV(cmd);
18957c478bd9Sstevel@tonic-gate 
18967c478bd9Sstevel@tonic-gate 		/* Lock the topology tree */
18977c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->topology_tree_mutex);
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 		ret = s1394_setup_asynch_command(hal, NULL, cmd,
19007c478bd9Sstevel@tonic-gate 		    S1394_CMD_LOCK, &err);
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate 		/* Unlock the topology tree */
19037c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 		/* Command has now been put onto the queue! */
19067c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
19077c478bd9Sstevel@tonic-gate 			/* Need to free the command */
19087c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
19097c478bd9Sstevel@tonic-gate 			return;
19107c478bd9Sstevel@tonic-gate 		}
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 		/* Send the command out */
19137c478bd9Sstevel@tonic-gate 		ret = s1394_xfer_asynch_command(hal, cmd, &err);
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
19167c478bd9Sstevel@tonic-gate 			/* Remove cmd outstanding request Q */
19177c478bd9Sstevel@tonic-gate 			s1394_remove_q_asynch_cmd(hal, cmd);
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 			s_priv->cmd_in_use = B_FALSE;
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 			mutex_enter(&hal->bus_mgr_node_mutex);
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 			/* Don't know who the bus_mgr is */
19247c478bd9Sstevel@tonic-gate 			hal->bus_mgr_node = S1394_INVALID_NODE_NUM;
19257c478bd9Sstevel@tonic-gate 			hal->incumbent_bus_mgr = B_FALSE;
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 			cv_signal(&hal->bus_mgr_node_cv);
19287c478bd9Sstevel@tonic-gate 			mutex_exit(&hal->bus_mgr_node_mutex);
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 			/* Need to free the command */
19317c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
19327c478bd9Sstevel@tonic-gate 		}
19337c478bd9Sstevel@tonic-gate 	}
19347c478bd9Sstevel@tonic-gate }
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate /*
19377c478bd9Sstevel@tonic-gate  * s1394_become_bus_mgr_callback()
19387c478bd9Sstevel@tonic-gate  *    is the callback used by s1394_become_bus_mgr() when it is necessary
19397c478bd9Sstevel@tonic-gate  *    to send the Bus Manager request to a remote IRM.  After the completion
19407c478bd9Sstevel@tonic-gate  *    of the compare-swap request, this routine looks at the "old_value"
19417c478bd9Sstevel@tonic-gate  *    in the request to determine whether or not it has become the Bus
19427c478bd9Sstevel@tonic-gate  *    Manager for the current generation.  It sets the bus_mgr_node and
19437c478bd9Sstevel@tonic-gate  *    incumbent_bus_mgr fields to their appropriate values.
19447c478bd9Sstevel@tonic-gate  */
19457c478bd9Sstevel@tonic-gate static void
s1394_become_bus_mgr_callback(cmd1394_cmd_t * cmd)19467c478bd9Sstevel@tonic-gate s1394_become_bus_mgr_callback(cmd1394_cmd_t *cmd)
19477c478bd9Sstevel@tonic-gate {
19487c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
19497c478bd9Sstevel@tonic-gate 	s1394_hal_t *hal;
19507c478bd9Sstevel@tonic-gate 	uint32_t hal_node_num;
19517c478bd9Sstevel@tonic-gate 	uint32_t temp;
19527c478bd9Sstevel@tonic-gate 	uint_t curr_bus_mgr;
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 	/* Get the Services Layer private area */
19557c478bd9Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(cmd);
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	hal = (s1394_hal_t *)s_priv->sent_on_hal;
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 	/* Lock the topology tree */
19607c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	/* Was the command successful? */
19657c478bd9Sstevel@tonic-gate 	if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
19667c478bd9Sstevel@tonic-gate 		temp = T1394_DATA32(cmd->cmd_u.l32.old_value);
19677c478bd9Sstevel@tonic-gate 		curr_bus_mgr = IEEE1394_NODE_NUM(temp);
19687c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->bus_mgr_node_mutex);
19697c478bd9Sstevel@tonic-gate 		if ((curr_bus_mgr == S1394_INVALID_NODE_NUM) ||
19707c478bd9Sstevel@tonic-gate 		    (curr_bus_mgr == hal_node_num)) {
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 			hal->bus_mgr_node = hal_node_num;
19737c478bd9Sstevel@tonic-gate 			hal->incumbent_bus_mgr = B_TRUE;
19747c478bd9Sstevel@tonic-gate 
19757c478bd9Sstevel@tonic-gate 		} else {
19767c478bd9Sstevel@tonic-gate 			hal->bus_mgr_node = curr_bus_mgr;
19777c478bd9Sstevel@tonic-gate 			hal->incumbent_bus_mgr = B_FALSE;
19787c478bd9Sstevel@tonic-gate 		}
19797c478bd9Sstevel@tonic-gate 		cv_signal(&hal->bus_mgr_node_cv);
19807c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->bus_mgr_node_mutex);
19817c478bd9Sstevel@tonic-gate 
19827c478bd9Sstevel@tonic-gate 	} else {
19837c478bd9Sstevel@tonic-gate 		mutex_enter(&hal->bus_mgr_node_mutex);
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 		/* Don't know who the bus_mgr is */
19867c478bd9Sstevel@tonic-gate 		hal->bus_mgr_node = S1394_INVALID_NODE_NUM;
19877c478bd9Sstevel@tonic-gate 		hal->incumbent_bus_mgr = B_FALSE;
19887c478bd9Sstevel@tonic-gate 
19897c478bd9Sstevel@tonic-gate 		cv_signal(&hal->bus_mgr_node_cv);
19907c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->bus_mgr_node_mutex);
19917c478bd9Sstevel@tonic-gate 	}
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 	/* Need to free the command */
19947c478bd9Sstevel@tonic-gate 	(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 	/* Unlock the topology tree */
19977c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
19987c478bd9Sstevel@tonic-gate }
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate /*
20017c478bd9Sstevel@tonic-gate  * s1394_bus_mgr_processing()
20027c478bd9Sstevel@tonic-gate  *    is called following "phase1" completion of reading Bus_Info_Blocks.
20037c478bd9Sstevel@tonic-gate  *    Its purpose is to determine whether the local node is capable of
20047c478bd9Sstevel@tonic-gate  *    becoming the Bus Manager (has the IRMC bit set) and if so to call
20057c478bd9Sstevel@tonic-gate  *    the s1394_do_bus_mgr_processing() routine.
20067c478bd9Sstevel@tonic-gate  *    NOTE: we overload DDI_FAILURE return value to mean jump back to
20077c478bd9Sstevel@tonic-gate  *    the start of bus reset processing.
20087c478bd9Sstevel@tonic-gate  */
20097c478bd9Sstevel@tonic-gate static int
s1394_bus_mgr_processing(s1394_hal_t * hal)20107c478bd9Sstevel@tonic-gate s1394_bus_mgr_processing(s1394_hal_t *hal)
20117c478bd9Sstevel@tonic-gate {
20127c478bd9Sstevel@tonic-gate 	int ret;
20137c478bd9Sstevel@tonic-gate 	int IRM_node_num;
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
20187c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
20197c478bd9Sstevel@tonic-gate 	}
20207c478bd9Sstevel@tonic-gate 	IRM_node_num = hal->IRM_node;
20217c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate 	ret = DDI_SUCCESS;
20247c478bd9Sstevel@tonic-gate 
20257c478bd9Sstevel@tonic-gate 	/* If we are IRM capable, then do bus_mgr stuff... */
20267c478bd9Sstevel@tonic-gate 	if (hal->halinfo.bus_capabilities & IEEE1394_BIB_IRMC_MASK) {
20277c478bd9Sstevel@tonic-gate 		/* If there is an IRM, then do bus_mgr stuff */
20287c478bd9Sstevel@tonic-gate 		if (IRM_node_num != -1) {
20297c478bd9Sstevel@tonic-gate 			if (s1394_do_bus_mgr_processing(hal))
20307c478bd9Sstevel@tonic-gate 				ret = DDI_FAILURE;
20317c478bd9Sstevel@tonic-gate 		}
20327c478bd9Sstevel@tonic-gate 	}
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 	return (ret);
20377c478bd9Sstevel@tonic-gate }
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate /*
20407c478bd9Sstevel@tonic-gate  * s1394_do_bus_mgr_processing()
20417c478bd9Sstevel@tonic-gate  *    is used to perform those operations expected of the Bus Manager.
20427c478bd9Sstevel@tonic-gate  *    After being called, s1394_do_bus_mgr_processing() looks at the value
20437c478bd9Sstevel@tonic-gate  *    in bus_mgr_node and waits if it is -1 (Bus Manager has not been
20447c478bd9Sstevel@tonic-gate  *    chosen yet).  Then, if there is more than one node on the 1394 bus,
20457c478bd9Sstevel@tonic-gate  *    and we are either the Bus Manager or (if there is no Bus Manager)
20467c478bd9Sstevel@tonic-gate  *    the IRM, it optimizes the gap_count and/or sets the cycle master's
20477c478bd9Sstevel@tonic-gate  *    root holdoff bit (to ensure that the cycle master is/stays root).
20487c478bd9Sstevel@tonic-gate  *
20497c478bd9Sstevel@tonic-gate  *    NOTE: we overload DDI_FAILURE return value to mean jump back to
20507c478bd9Sstevel@tonic-gate  *    the start of bus reset processing.
20517c478bd9Sstevel@tonic-gate  */
20527c478bd9Sstevel@tonic-gate static int
s1394_do_bus_mgr_processing(s1394_hal_t * hal)20537c478bd9Sstevel@tonic-gate s1394_do_bus_mgr_processing(s1394_hal_t *hal)
20547c478bd9Sstevel@tonic-gate {
20557c478bd9Sstevel@tonic-gate 	int	ret;
20567c478bd9Sstevel@tonic-gate 	int	IRM_flags, hal_bus_mgr_node;
20577c478bd9Sstevel@tonic-gate 	int	IRM_node_num;
20587c478bd9Sstevel@tonic-gate 	uint_t	hal_node_num, number_of_nodes;
20597c478bd9Sstevel@tonic-gate 	int	new_root, new_gap_cnt;
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 	/* Wait for Bus Manager to be determined */
20647c478bd9Sstevel@tonic-gate 	/* or a Bus Reset to happen */
20657c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->bus_mgr_node_mutex);
20667c478bd9Sstevel@tonic-gate 	if (hal->bus_mgr_node == -1)
20677c478bd9Sstevel@tonic-gate 		cv_wait(&hal->bus_mgr_node_cv, &hal->bus_mgr_node_mutex);
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	/* Check if a BUS RESET has come while we've been waiting */
20707c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->br_thread_mutex);
20717c478bd9Sstevel@tonic-gate 	if (hal->br_thread_ev_type & (BR_THR_CFGROM_SCAN | BR_THR_GO_AWAY)) {
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->br_thread_mutex);
20747c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->bus_mgr_node_mutex);
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 		return (1);
20777c478bd9Sstevel@tonic-gate 	}
20787c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->br_thread_mutex);
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	hal_bus_mgr_node = hal->bus_mgr_node;
20817c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->bus_mgr_node_mutex);
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
20847c478bd9Sstevel@tonic-gate 		return (1);
20857c478bd9Sstevel@tonic-gate 	}
20867c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
20877c478bd9Sstevel@tonic-gate 	IRM_node_num = hal->IRM_node;
20887c478bd9Sstevel@tonic-gate 	number_of_nodes = hal->number_of_nodes;
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate 	ret = 0;
20917c478bd9Sstevel@tonic-gate 
20927c478bd9Sstevel@tonic-gate 	/* If we are the bus_mgr or if there is no bus_mgr */
20937c478bd9Sstevel@tonic-gate 	/* the IRM and there is > 1 nodes on the bus */
20947c478bd9Sstevel@tonic-gate 	if ((number_of_nodes > 1) &&
20957c478bd9Sstevel@tonic-gate 	    ((hal_bus_mgr_node == (int)hal_node_num) ||
2096*d5ebc493SDan Cross 	    ((hal_bus_mgr_node == S1394_INVALID_NODE_NUM) &&
2097*d5ebc493SDan Cross 	    (IRM_node_num == (int)hal_node_num)))) {
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 		IRM_flags = 0;
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 		/* Make sure the root node is cycle master capable */
21027c478bd9Sstevel@tonic-gate 		if (!s1394_cycle_master_capable(hal)) {
21037c478bd9Sstevel@tonic-gate 			/* Make the local node root */
21047c478bd9Sstevel@tonic-gate 			new_root = hal_node_num;
21057c478bd9Sstevel@tonic-gate 			IRM_flags = IRM_flags | ROOT_HOLDOFF;
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 			/* If setting root, then optimize gap_count */
21087c478bd9Sstevel@tonic-gate 			new_gap_cnt = hal->optimum_gap_count;
21097c478bd9Sstevel@tonic-gate 			IRM_flags = IRM_flags | GAP_COUNT;
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 		} else {
21127c478bd9Sstevel@tonic-gate 			/* Make sure root's ROOT_HOLDOFF bit is set */
21137c478bd9Sstevel@tonic-gate 			new_root = (number_of_nodes - 1);
21147c478bd9Sstevel@tonic-gate 			IRM_flags = IRM_flags | ROOT_HOLDOFF;
21157c478bd9Sstevel@tonic-gate 		}
21167c478bd9Sstevel@tonic-gate 		if (hal->gap_count > hal->optimum_gap_count) {
21177c478bd9Sstevel@tonic-gate 			/* Set the gap_count to optimum */
21187c478bd9Sstevel@tonic-gate 			new_gap_cnt = hal->optimum_gap_count;
21197c478bd9Sstevel@tonic-gate 			IRM_flags = IRM_flags | GAP_COUNT;
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 		}
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 		if (IRM_flags) {
21267c478bd9Sstevel@tonic-gate 			ret = s1394_do_phy_config_pkt(hal, new_root,
21277c478bd9Sstevel@tonic-gate 			    new_gap_cnt, IRM_flags);
21287c478bd9Sstevel@tonic-gate 		}
21297c478bd9Sstevel@tonic-gate 		return (ret);
21307c478bd9Sstevel@tonic-gate 	}
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 	return (ret);
21357c478bd9Sstevel@tonic-gate }
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate /*
21387c478bd9Sstevel@tonic-gate  * s1394_bus_mgr_timers_stop()
21397c478bd9Sstevel@tonic-gate  *    Cancels bus manager timeouts
21407c478bd9Sstevel@tonic-gate  */
21417c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21427c478bd9Sstevel@tonic-gate static void
s1394_bus_mgr_timers_stop(s1394_hal_t * hal,timeout_id_t * bus_mgr_query_tid,timeout_id_t * bus_mgr_tid)21437c478bd9Sstevel@tonic-gate s1394_bus_mgr_timers_stop(s1394_hal_t *hal, timeout_id_t *bus_mgr_query_tid,
21447c478bd9Sstevel@tonic-gate     timeout_id_t *bus_mgr_tid)
21457c478bd9Sstevel@tonic-gate {
21467c478bd9Sstevel@tonic-gate 	/* Cancel the Bus Mgr timeouts (if necessary) */
21477c478bd9Sstevel@tonic-gate 	if (*bus_mgr_tid != 0) {
21487c478bd9Sstevel@tonic-gate 		(void) untimeout(*bus_mgr_tid);
21497c478bd9Sstevel@tonic-gate 		*bus_mgr_tid = 0;
21507c478bd9Sstevel@tonic-gate 	}
21517c478bd9Sstevel@tonic-gate 	if (*bus_mgr_query_tid != 0) {
21527c478bd9Sstevel@tonic-gate 		(void) untimeout(*bus_mgr_query_tid);
21537c478bd9Sstevel@tonic-gate 		*bus_mgr_query_tid = 0;
21547c478bd9Sstevel@tonic-gate 	}
21557c478bd9Sstevel@tonic-gate }
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate /*
21587c478bd9Sstevel@tonic-gate  * s1394_bus_mgr_timers_start()
21597c478bd9Sstevel@tonic-gate  *    Starts bus manager timeouts if the hal is IRM capable.
21607c478bd9Sstevel@tonic-gate  */
21617c478bd9Sstevel@tonic-gate static void
s1394_bus_mgr_timers_start(s1394_hal_t * hal,timeout_id_t * bus_mgr_query_tid,timeout_id_t * bus_mgr_tid)21627c478bd9Sstevel@tonic-gate s1394_bus_mgr_timers_start(s1394_hal_t *hal, timeout_id_t *bus_mgr_query_tid,
21637c478bd9Sstevel@tonic-gate     timeout_id_t *bus_mgr_tid)
21647c478bd9Sstevel@tonic-gate {
21657c478bd9Sstevel@tonic-gate 	boolean_t incumbant;
21667c478bd9Sstevel@tonic-gate 	uint_t	  hal_node_num;
21677c478bd9Sstevel@tonic-gate 	int	  IRM_node_num;
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate 	IRM_node_num = hal->IRM_node;
21727c478bd9Sstevel@tonic-gate 	hal_node_num = hal->node_id;
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->bus_mgr_node_mutex);
21757c478bd9Sstevel@tonic-gate 	incumbant = hal->incumbent_bus_mgr;
21767c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->bus_mgr_node_mutex);
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate 	/* If we are IRM capable, then do bus_mgr stuff... */
21797c478bd9Sstevel@tonic-gate 	if (hal->halinfo.bus_capabilities & IEEE1394_BIB_IRMC_MASK) {
21807c478bd9Sstevel@tonic-gate 		/*
21817c478bd9Sstevel@tonic-gate 		 * If we are the IRM, then wait 625ms
21827c478bd9Sstevel@tonic-gate 		 * before checking BUS_MANAGER_ID register
21837c478bd9Sstevel@tonic-gate 		 */
21847c478bd9Sstevel@tonic-gate 		if (IRM_node_num == IEEE1394_NODE_NUM(hal_node_num)) {
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 			mutex_exit(&hal->topology_tree_mutex);
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 			/* Wait 625ms, then check bus manager */
21897c478bd9Sstevel@tonic-gate 			*bus_mgr_query_tid = timeout(s1394_become_bus_mgr,
21907c478bd9Sstevel@tonic-gate 			    hal, drv_usectohz(IEEE1394_BM_IRM_TIMEOUT));
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 			mutex_enter(&hal->topology_tree_mutex);
21937c478bd9Sstevel@tonic-gate 		}
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 		/* If there is an IRM on the bus */
21967c478bd9Sstevel@tonic-gate 		if (IRM_node_num != -1) {
21977c478bd9Sstevel@tonic-gate 			if ((incumbant == B_TRUE) &&
21987c478bd9Sstevel@tonic-gate 			    (hal->abdicate_bus_mgr_bit == 0)) {
21997c478bd9Sstevel@tonic-gate 				mutex_exit(&hal->topology_tree_mutex);
22007c478bd9Sstevel@tonic-gate 
22017c478bd9Sstevel@tonic-gate 				/* Try to become bus manager */
22027c478bd9Sstevel@tonic-gate 				s1394_become_bus_mgr(hal);
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate 				mutex_enter(&hal->topology_tree_mutex);
22057c478bd9Sstevel@tonic-gate 			} else {
22067c478bd9Sstevel@tonic-gate 				hal->abdicate_bus_mgr_bit = 0;
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 				mutex_exit(&hal->topology_tree_mutex);
22097c478bd9Sstevel@tonic-gate 
22107c478bd9Sstevel@tonic-gate 				/* Wait 125ms, then try to become bus manager */
22117c478bd9Sstevel@tonic-gate 				*bus_mgr_tid = timeout(s1394_become_bus_mgr,
22127c478bd9Sstevel@tonic-gate 				    hal, drv_usectohz(
2213*d5ebc493SDan Cross 				    IEEE1394_BM_INCUMBENT_TIMEOUT));
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 				mutex_enter(&hal->topology_tree_mutex);
22167c478bd9Sstevel@tonic-gate 			}
22177c478bd9Sstevel@tonic-gate 		} else {
22187c478bd9Sstevel@tonic-gate 			mutex_enter(&hal->bus_mgr_node_mutex);
22197c478bd9Sstevel@tonic-gate 			hal->incumbent_bus_mgr = B_FALSE;
22207c478bd9Sstevel@tonic-gate 			mutex_exit(&hal->bus_mgr_node_mutex);
22217c478bd9Sstevel@tonic-gate 		}
22227c478bd9Sstevel@tonic-gate 	}
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
22257c478bd9Sstevel@tonic-gate }
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate /*
22287c478bd9Sstevel@tonic-gate  * s1394_get_maxpayload()
22297c478bd9Sstevel@tonic-gate  *    is used to determine a device's maximum payload size.  That is to
22307c478bd9Sstevel@tonic-gate  *    say, the largest packet that can be transmitted or received by the
22317c478bd9Sstevel@tonic-gate  *    the target device given the current topological (speed) constraints
22327c478bd9Sstevel@tonic-gate  *    and the constraints specified in the local host's and remote device's
22337c478bd9Sstevel@tonic-gate  *    Config ROM (max_rec).  Caller must hold the topology_tree_mutex and
22347c478bd9Sstevel@tonic-gate  *    the target_list_rwlock as an RW_READER (at least).
22357c478bd9Sstevel@tonic-gate  */
22367c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22377c478bd9Sstevel@tonic-gate void
s1394_get_maxpayload(s1394_target_t * target,uint_t * dev_max_payload,uint_t * current_max_payload)22387c478bd9Sstevel@tonic-gate s1394_get_maxpayload(s1394_target_t *target, uint_t *dev_max_payload,
22397c478bd9Sstevel@tonic-gate     uint_t *current_max_payload)
22407c478bd9Sstevel@tonic-gate {
22417c478bd9Sstevel@tonic-gate 	s1394_hal_t *hal;
22427c478bd9Sstevel@tonic-gate 	uint32_t bus_capabilities;
22437c478bd9Sstevel@tonic-gate 	uint32_t from_node;
22447c478bd9Sstevel@tonic-gate 	uint32_t to_node;
22457c478bd9Sstevel@tonic-gate 	uint_t local_max_rec;
22467c478bd9Sstevel@tonic-gate 	uint_t local_max_blk;
22477c478bd9Sstevel@tonic-gate 	uint_t max_rec;
22487c478bd9Sstevel@tonic-gate 	uint_t max_blk;
22497c478bd9Sstevel@tonic-gate 	uint_t curr_speed;
22507c478bd9Sstevel@tonic-gate 	uint_t speed_max_blk;
22517c478bd9Sstevel@tonic-gate 	uint_t temp;
22527c478bd9Sstevel@tonic-gate 
22537c478bd9Sstevel@tonic-gate 	/* Find the HAL this target resides on */
22547c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	/* Make sure we're holding the topology_tree_mutex */
22577c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
22587c478bd9Sstevel@tonic-gate 
22597c478bd9Sstevel@tonic-gate 	/* Set dev_max_payload to local (HAL's) size */
22607c478bd9Sstevel@tonic-gate 	bus_capabilities = target->on_hal->halinfo.bus_capabilities;
22617c478bd9Sstevel@tonic-gate 	local_max_rec = (bus_capabilities & IEEE1394_BIB_MAXREC_MASK) >>
22627c478bd9Sstevel@tonic-gate 	    IEEE1394_BIB_MAXREC_SHIFT;
22637c478bd9Sstevel@tonic-gate 	if ((local_max_rec > 0) && (local_max_rec < 14)) {
22647c478bd9Sstevel@tonic-gate 		local_max_blk = 1 << (local_max_rec + 1);
22657c478bd9Sstevel@tonic-gate 	} else {
22667c478bd9Sstevel@tonic-gate 		/* These are either unspecified or reserved */
22677c478bd9Sstevel@tonic-gate 		local_max_blk = 4;
22687c478bd9Sstevel@tonic-gate 	}
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 	/* Is this target on a node? */
22717c478bd9Sstevel@tonic-gate 	if ((target->target_state & S1394_TARG_GONE) == 0 &&
22727c478bd9Sstevel@tonic-gate 	    (target->on_node != NULL)) {
22737c478bd9Sstevel@tonic-gate 		ASSERT(target->on_node->cfgrom != NULL);
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 		bus_capabilities =
22767c478bd9Sstevel@tonic-gate 		    target->on_node->cfgrom[IEEE1212_NODE_CAP_QUAD];
22777c478bd9Sstevel@tonic-gate 		max_rec = (bus_capabilities & IEEE1394_BIB_MAXREC_MASK) >>
22787c478bd9Sstevel@tonic-gate 		    IEEE1394_BIB_MAXREC_SHIFT;
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate 		if ((max_rec > 0) && (max_rec < 14)) {
22817c478bd9Sstevel@tonic-gate 			max_blk = 1 << (max_rec + 1);
22827c478bd9Sstevel@tonic-gate 		} else {
22837c478bd9Sstevel@tonic-gate 			/* These are either unspecified or reserved */
22847c478bd9Sstevel@tonic-gate 			max_blk = 4;
22857c478bd9Sstevel@tonic-gate 		}
22867c478bd9Sstevel@tonic-gate 		(*dev_max_payload) = max_blk;
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate 		from_node = IEEE1394_NODE_NUM(target->on_hal->node_id);
22897c478bd9Sstevel@tonic-gate 		to_node = (target->on_node->node_num);
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 		/* Speed is to be filled in from speed map */
22927c478bd9Sstevel@tonic-gate 		curr_speed = (uint_t)s1394_speed_map_get(target->on_hal,
22937c478bd9Sstevel@tonic-gate 		    from_node, to_node);
22947c478bd9Sstevel@tonic-gate 		speed_max_blk = 512 << curr_speed;
22957c478bd9Sstevel@tonic-gate 		temp = (local_max_blk < max_blk) ? local_max_blk : max_blk;
22967c478bd9Sstevel@tonic-gate 		(*current_max_payload) = (temp < speed_max_blk) ? temp :
22977c478bd9Sstevel@tonic-gate 		    speed_max_blk;
22987c478bd9Sstevel@tonic-gate 	} else {
22997c478bd9Sstevel@tonic-gate 		/* Set dev_max_payload to local (HAL's) size */
23007c478bd9Sstevel@tonic-gate 		(*dev_max_payload) = local_max_blk;
23017c478bd9Sstevel@tonic-gate 		(*current_max_payload) = local_max_blk;
23027c478bd9Sstevel@tonic-gate 	}
23037c478bd9Sstevel@tonic-gate }
23047c478bd9Sstevel@tonic-gate 
23057c478bd9Sstevel@tonic-gate /*
23067c478bd9Sstevel@tonic-gate  * s1394_cycle_master_capable()
23077c478bd9Sstevel@tonic-gate  *    is used to determine whether or not the current root node on the
23087c478bd9Sstevel@tonic-gate  *    1394 bus has its CMC-bit set in it Config ROM.  If not, then it
23097c478bd9Sstevel@tonic-gate  *    is not capable of being cycle master and a new root node must be
23107c478bd9Sstevel@tonic-gate  *    selected.
23117c478bd9Sstevel@tonic-gate  */
23127c478bd9Sstevel@tonic-gate static int
s1394_cycle_master_capable(s1394_hal_t * hal)23137c478bd9Sstevel@tonic-gate s1394_cycle_master_capable(s1394_hal_t *hal)
23147c478bd9Sstevel@tonic-gate {
23157c478bd9Sstevel@tonic-gate 	s1394_node_t	*root;
23167c478bd9Sstevel@tonic-gate 	int		cycle_master_capable;
23177c478bd9Sstevel@tonic-gate 	uint_t		hal_node_num;
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
23207c478bd9Sstevel@tonic-gate 
23217c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
23227c478bd9Sstevel@tonic-gate 
23237c478bd9Sstevel@tonic-gate 	/* Get a pointer to the root node */
23247c478bd9Sstevel@tonic-gate 	root = s1394_topology_tree_get_root_node(hal);
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 	/* Ignore, if we are already root */
23277c478bd9Sstevel@tonic-gate 	if (root == &hal->topology_tree[hal_node_num]) {
23287c478bd9Sstevel@tonic-gate 		return (1);
23297c478bd9Sstevel@tonic-gate 	}
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate 	/*
23327c478bd9Sstevel@tonic-gate 	 * We want to pick a new root if link is off or we don't have
23337c478bd9Sstevel@tonic-gate 	 * valid config rom
23347c478bd9Sstevel@tonic-gate 	 */
23357c478bd9Sstevel@tonic-gate 	if (LINK_ACTIVE(root) == B_FALSE || root->cfgrom == NULL ||
23367c478bd9Sstevel@tonic-gate 	    CFGROM_BIB_READ(root) == 0) {
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 		return (0);
23397c478bd9Sstevel@tonic-gate 	}
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate 	/* Check the Cycle Master bit in the Bus Info Block */
23427c478bd9Sstevel@tonic-gate 	cycle_master_capable = root->cfgrom[IEEE1212_NODE_CAP_QUAD] &
23437c478bd9Sstevel@tonic-gate 	    IEEE1394_BIB_CMC_MASK;
23447c478bd9Sstevel@tonic-gate 
23457c478bd9Sstevel@tonic-gate 	if (cycle_master_capable) {
23467c478bd9Sstevel@tonic-gate 		return (1);
23477c478bd9Sstevel@tonic-gate 	} else {
23487c478bd9Sstevel@tonic-gate 		return (0);
23497c478bd9Sstevel@tonic-gate 	}
23507c478bd9Sstevel@tonic-gate }
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate /*
23537c478bd9Sstevel@tonic-gate  * s1394_do_phy_config_pkt()
23547c478bd9Sstevel@tonic-gate  *    is called by s1394_do_bus_mgr_processing() to setup and send out
23557c478bd9Sstevel@tonic-gate  *    a PHY configuration packet onto the 1394 bus.  Depending on the
23567c478bd9Sstevel@tonic-gate  *    values in IRM_flags, the gap_count and root_holdoff bits on the
23577c478bd9Sstevel@tonic-gate  *    bus will be affected by this packet.
23587c478bd9Sstevel@tonic-gate  *
23597c478bd9Sstevel@tonic-gate  *    NOTE: we overload DDI_FAILURE return value to mean jump back to
23607c478bd9Sstevel@tonic-gate  *    the start of bus reset processing.
23617c478bd9Sstevel@tonic-gate  */
23627c478bd9Sstevel@tonic-gate static int
s1394_do_phy_config_pkt(s1394_hal_t * hal,int new_root,int new_gap_cnt,uint32_t IRM_flags)23637c478bd9Sstevel@tonic-gate s1394_do_phy_config_pkt(s1394_hal_t *hal, int new_root, int new_gap_cnt,
23647c478bd9Sstevel@tonic-gate     uint32_t IRM_flags)
23657c478bd9Sstevel@tonic-gate {
23667c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t	 *cmd;
23677c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
23687c478bd9Sstevel@tonic-gate 	h1394_cmd_priv_t *h_priv;
23697c478bd9Sstevel@tonic-gate 	uint32_t	 pkt_data = 0;
23707c478bd9Sstevel@tonic-gate 	uint32_t	 gap_cnt = 0;
23717c478bd9Sstevel@tonic-gate 	uint32_t	 root = 0;
23727c478bd9Sstevel@tonic-gate 	int		 ret, result;
23737c478bd9Sstevel@tonic-gate 	uint_t		 flags = 0;
23747c478bd9Sstevel@tonic-gate 
23757c478bd9Sstevel@tonic-gate 	/* Gap count needs to be optimized */
23767c478bd9Sstevel@tonic-gate 	if (IRM_flags & GAP_COUNT) {
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate 		pkt_data = pkt_data | IEEE1394_PHY_CONFIG_T_BIT_MASK;
23797c478bd9Sstevel@tonic-gate 		gap_cnt = ((uint32_t)new_gap_cnt) <<
23807c478bd9Sstevel@tonic-gate 		    IEEE1394_PHY_CONFIG_GAP_CNT_SHIFT;
23817c478bd9Sstevel@tonic-gate 		gap_cnt = gap_cnt & IEEE1394_PHY_CONFIG_GAP_CNT_MASK;
23827c478bd9Sstevel@tonic-gate 		pkt_data = pkt_data | gap_cnt;
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate 		(void) HAL_CALL(hal).set_gap_count(hal->halinfo.hal_private,
23857c478bd9Sstevel@tonic-gate 		    (uint_t)new_gap_cnt);
23867c478bd9Sstevel@tonic-gate 	}
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate 	/* Root node needs to be changed */
23897c478bd9Sstevel@tonic-gate 	if (IRM_flags & ROOT_HOLDOFF) {
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 		pkt_data = pkt_data | IEEE1394_PHY_CONFIG_R_BIT_MASK;
23927c478bd9Sstevel@tonic-gate 		root = ((uint32_t)new_root) <<
23937c478bd9Sstevel@tonic-gate 		    IEEE1394_PHY_CONFIG_ROOT_HOLD_SHIFT;
23947c478bd9Sstevel@tonic-gate 		root = root & IEEE1394_PHY_CONFIG_ROOT_HOLD_MASK;
23957c478bd9Sstevel@tonic-gate 		pkt_data = pkt_data | root;
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 		(void) HAL_CALL(hal).set_root_holdoff_bit(
23987c478bd9Sstevel@tonic-gate 		    hal->halinfo.hal_private);
23997c478bd9Sstevel@tonic-gate 	}
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate 	if (IRM_flags) {
24037c478bd9Sstevel@tonic-gate 		if (s1394_alloc_cmd(hal, flags, &cmd) != DDI_SUCCESS) {
24047c478bd9Sstevel@tonic-gate 			return (0);
24057c478bd9Sstevel@tonic-gate 		}
24067c478bd9Sstevel@tonic-gate 
24077c478bd9Sstevel@tonic-gate 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
24087c478bd9Sstevel@tonic-gate 			/* lock tree failure indicates a bus gen change */
24097c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
24107c478bd9Sstevel@tonic-gate 			return (1);
24117c478bd9Sstevel@tonic-gate 		}
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 		/* Setup the callback routine */
24147c478bd9Sstevel@tonic-gate 		cmd->completion_callback  = s1394_phy_config_callback;
24157c478bd9Sstevel@tonic-gate 		cmd->cmd_callback_arg	  = (void *)(uintptr_t)IRM_flags;
24167c478bd9Sstevel@tonic-gate 		cmd->bus_generation	  = hal->generation_count;
24177c478bd9Sstevel@tonic-gate 		cmd->cmd_options	  = CMD1394_OVERRIDE_ADDR;
24187c478bd9Sstevel@tonic-gate 		cmd->cmd_type		  = CMD1394_ASYNCH_WR_QUAD;
24197c478bd9Sstevel@tonic-gate 		cmd->cmd_u.q.quadlet_data = pkt_data;
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate 		/* Get the Services Layer private area */
24227c478bd9Sstevel@tonic-gate 		s_priv = S1394_GET_CMD_PRIV(cmd);
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate 		/* Get a pointer to the HAL private struct */
24257c478bd9Sstevel@tonic-gate 		h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate 		s_priv->sent_by_target	= (s1394_target_t *)NULL;
24287c478bd9Sstevel@tonic-gate 		s_priv->sent_on_hal	= (s1394_hal_t *)hal;
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 		h_priv->bus_generation	= cmd->bus_generation;
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate 		/* Speed must be IEEE1394_S100 on PHY config packets */
24337c478bd9Sstevel@tonic-gate 		s_priv->hal_cmd_private.speed = IEEE1394_S100;
24347c478bd9Sstevel@tonic-gate 
24357c478bd9Sstevel@tonic-gate 		/* Mark command as being used */
24367c478bd9Sstevel@tonic-gate 		s_priv->cmd_in_use = B_TRUE;
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 		/* Put command on the HAL's outstanding request Q */
24417c478bd9Sstevel@tonic-gate 		s1394_insert_q_asynch_cmd(hal, cmd);
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 		ret = HAL_CALL(hal).send_phy_configuration_packet(
24447c478bd9Sstevel@tonic-gate 		    hal->halinfo.hal_private, (cmd1394_cmd_t *)cmd,
24457c478bd9Sstevel@tonic-gate 		    (h1394_cmd_priv_t *)&s_priv->hal_cmd_private, &result);
24467c478bd9Sstevel@tonic-gate 
24477c478bd9Sstevel@tonic-gate 		if (ret != DDI_SUCCESS) {
24487c478bd9Sstevel@tonic-gate 			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 			return (0);
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 		} else {
24537c478bd9Sstevel@tonic-gate 			/*
24547c478bd9Sstevel@tonic-gate 			 * There will be a bus reset only if GAP_COUNT changed
24557c478bd9Sstevel@tonic-gate 			 */
24567c478bd9Sstevel@tonic-gate 			if (IRM_flags & GAP_COUNT) {
24577c478bd9Sstevel@tonic-gate 				return (1);
24587c478bd9Sstevel@tonic-gate 			}
24597c478bd9Sstevel@tonic-gate 		}
24607c478bd9Sstevel@tonic-gate 	}
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 	return (0);
24637c478bd9Sstevel@tonic-gate }
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate /*
24667c478bd9Sstevel@tonic-gate  * s1394_phy_config_callback()
24677c478bd9Sstevel@tonic-gate  *    is the callback called after the PHY configuration packet has been
24687c478bd9Sstevel@tonic-gate  *    sent out onto the 1394 bus.  Depending on the values in IRM_flags,
24697c478bd9Sstevel@tonic-gate  *    (specifically if the gap_count has been changed) this routine may
24707c478bd9Sstevel@tonic-gate  *    initiate a bus reset.
24717c478bd9Sstevel@tonic-gate  */
24727c478bd9Sstevel@tonic-gate static void
s1394_phy_config_callback(cmd1394_cmd_t * cmd)24737c478bd9Sstevel@tonic-gate s1394_phy_config_callback(cmd1394_cmd_t *cmd)
24747c478bd9Sstevel@tonic-gate {
24757c478bd9Sstevel@tonic-gate 	s1394_cmd_priv_t *s_priv;
24767c478bd9Sstevel@tonic-gate 	s1394_hal_t *hal;
24777c478bd9Sstevel@tonic-gate 	uint32_t IRM_flags;
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	/* Get the Services Layer private area */
24807c478bd9Sstevel@tonic-gate 	s_priv = S1394_GET_CMD_PRIV(cmd);
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 	hal = (s1394_hal_t *)s_priv->sent_on_hal;
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 	IRM_flags = (uint32_t)(uintptr_t)cmd->cmd_callback_arg;
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	if (cmd->cmd_result != CMD1394_CMDSUCCESS) {
24877c478bd9Sstevel@tonic-gate 		(void) s1394_free_cmd(hal, &cmd);
24887c478bd9Sstevel@tonic-gate 	} else {
24897c478bd9Sstevel@tonic-gate 		(void) s1394_free_cmd(hal, &cmd);
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 		/* Only need a bus reset if we changed GAP_COUNT */
24927c478bd9Sstevel@tonic-gate 		if (IRM_flags & GAP_COUNT) {
24937c478bd9Sstevel@tonic-gate 			s1394_initiate_hal_reset(hal, NON_CRITICAL);
24947c478bd9Sstevel@tonic-gate 		}
24957c478bd9Sstevel@tonic-gate 	}
24967c478bd9Sstevel@tonic-gate }
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate /*
24997c478bd9Sstevel@tonic-gate  * s1394_lock_tree()
25007c478bd9Sstevel@tonic-gate  *    Attempts to lock the topology tree. Returns DDI_FAILURE if generations
25017c478bd9Sstevel@tonic-gate  *    changed or if the services layer signals the bus reset thread to go
25027c478bd9Sstevel@tonic-gate  *    away. Otherwise, returns DDI_SUCCESS.
25037c478bd9Sstevel@tonic-gate  */
25047c478bd9Sstevel@tonic-gate int
s1394_lock_tree(s1394_hal_t * hal)25057c478bd9Sstevel@tonic-gate s1394_lock_tree(s1394_hal_t *hal)
25067c478bd9Sstevel@tonic-gate {
25077c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->br_thread_mutex));
25087c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->br_thread_mutex);
25113fe80ca4SDan Cross 	ndi_devi_enter(hal->halinfo.dip);
25127c478bd9Sstevel@tonic-gate 	mutex_enter(&hal->topology_tree_mutex);
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate 	if ((hal->br_thread_ev_type & BR_THR_GO_AWAY) != 0) {
25157c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->br_thread_mutex);
25167c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
25173fe80ca4SDan Cross 		ndi_devi_exit(hal->halinfo.dip);
25187c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25197c478bd9Sstevel@tonic-gate 	} else if (hal->br_cfgrom_read_gen != hal->generation_count) {
25207c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->br_thread_mutex);
25217c478bd9Sstevel@tonic-gate 		mutex_exit(&hal->topology_tree_mutex);
25223fe80ca4SDan Cross 		ndi_devi_exit(hal->halinfo.dip);
25237c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25247c478bd9Sstevel@tonic-gate 	}
25257c478bd9Sstevel@tonic-gate 
25267c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->br_thread_mutex);
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
25297c478bd9Sstevel@tonic-gate }
25307c478bd9Sstevel@tonic-gate 
25317c478bd9Sstevel@tonic-gate /*
25327c478bd9Sstevel@tonic-gate  * s1394_unlock_tree()
25337c478bd9Sstevel@tonic-gate  *    Unlocks the topology tree
25347c478bd9Sstevel@tonic-gate  */
25357c478bd9Sstevel@tonic-gate void
s1394_unlock_tree(s1394_hal_t * hal)25367c478bd9Sstevel@tonic-gate s1394_unlock_tree(s1394_hal_t *hal)
25377c478bd9Sstevel@tonic-gate {
25387c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
25397c478bd9Sstevel@tonic-gate 	mutex_exit(&hal->topology_tree_mutex);
25403fe80ca4SDan Cross 	ndi_devi_exit(hal->halinfo.dip);
25417c478bd9Sstevel@tonic-gate }
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate /*
25447c478bd9Sstevel@tonic-gate  * s1394_calc_next_quad()
25457c478bd9Sstevel@tonic-gate  *    figures out the next quadlet to read. This maintains a stack of
25467c478bd9Sstevel@tonic-gate  *    directories in the node. When the first quad of a directory (the
25477c478bd9Sstevel@tonic-gate  *    first directory would be the root directory) is read, it is pushed on
25487c478bd9Sstevel@tonic-gate  *    the this stack. When the directory is all read, it scans the directory
25497c478bd9Sstevel@tonic-gate  *    looking for indirect entries. If any indirect directory entry is found,
25507c478bd9Sstevel@tonic-gate  *    it is pushed on stack and that directory is read. If we are done dealing
25517c478bd9Sstevel@tonic-gate  *    with all entries in the current dir, the directory is popped off the
25527c478bd9Sstevel@tonic-gate  *    stack. If the stack is empty, we are back at the root directory level
25537c478bd9Sstevel@tonic-gate  *    and essentially read the entire directory hierarchy.
25547c478bd9Sstevel@tonic-gate  *    Returns 0 is more quads to read, else returns non-zero.
25557c478bd9Sstevel@tonic-gate  */
25567c478bd9Sstevel@tonic-gate static int
s1394_calc_next_quad(s1394_hal_t * hal,s1394_node_t * node,uint32_t quadlet,uint32_t * nextquadp)25577c478bd9Sstevel@tonic-gate s1394_calc_next_quad(s1394_hal_t *hal, s1394_node_t *node, uint32_t quadlet,
25587c478bd9Sstevel@tonic-gate     uint32_t *nextquadp)
25597c478bd9Sstevel@tonic-gate {
25607c478bd9Sstevel@tonic-gate 	uint32_t data, type, key, value, *ptr;
25617c478bd9Sstevel@tonic-gate 
25627c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
25637c478bd9Sstevel@tonic-gate 
25647c478bd9Sstevel@tonic-gate 	if (((quadlet + 1) >= node->cfgrom_size) ||
2565*d5ebc493SDan Cross 	    (CFGROM_SIZE_IS_CRCSIZE(node) == B_TRUE &&
2566*d5ebc493SDan Cross 	    (quadlet + 1) >= node->cfgrom_valid_size)) {
25677c478bd9Sstevel@tonic-gate 		return (1);
25687c478bd9Sstevel@tonic-gate 	}
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	if (s1394_turn_off_dir_stack != 0 || CFGROM_DIR_STACK_OFF(node) ==
25717c478bd9Sstevel@tonic-gate 	    B_TRUE) {
25727c478bd9Sstevel@tonic-gate 		quadlet++;
25737c478bd9Sstevel@tonic-gate 		*nextquadp = quadlet;
25747c478bd9Sstevel@tonic-gate 		return (0);
25757c478bd9Sstevel@tonic-gate 	}
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate 	data = node->cfgrom[quadlet];
25787c478bd9Sstevel@tonic-gate 
25797c478bd9Sstevel@tonic-gate 	if (quadlet == IEEE1212_ROOT_DIR_QUAD) {
25807c478bd9Sstevel@tonic-gate 		node->dir_stack_top = -1;
25817c478bd9Sstevel@tonic-gate 		node->expected_dir_quad = quadlet;
25827c478bd9Sstevel@tonic-gate 		node->expected_type = IEEE1212_IMMEDIATE_TYPE;
25837c478bd9Sstevel@tonic-gate 	}
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 	CFGROM_TYPE_KEY_VALUE(data, type, key, value);
25867c478bd9Sstevel@tonic-gate 
25877c478bd9Sstevel@tonic-gate 	/*
25887c478bd9Sstevel@tonic-gate 	 * check to make sure we are looking at a dir. If the config rom
25897c478bd9Sstevel@tonic-gate 	 * is broken, then revert to normal scanning of the config rom
25907c478bd9Sstevel@tonic-gate 	 */
25917c478bd9Sstevel@tonic-gate 	if (node->expected_dir_quad == quadlet) {
25927c478bd9Sstevel@tonic-gate 		if (type != 0 || key != 0) {
25937c478bd9Sstevel@tonic-gate 			SET_CFGROM_DIR_STACK_OFF(node);
25947c478bd9Sstevel@tonic-gate 			quadlet = IEEE1212_ROOT_DIR_QUAD;
25957c478bd9Sstevel@tonic-gate 		} else {
25967c478bd9Sstevel@tonic-gate 			node->cur_dir_start = quadlet;
25977c478bd9Sstevel@tonic-gate 			node->cur_dir_size = IEEE1212_DIR_LEN(data);
25987c478bd9Sstevel@tonic-gate 			node->expected_dir_quad = 0;
25997c478bd9Sstevel@tonic-gate 			/* get the next quad */
26007c478bd9Sstevel@tonic-gate 			quadlet++;
26017c478bd9Sstevel@tonic-gate 		}
26027c478bd9Sstevel@tonic-gate 	} else {
26037c478bd9Sstevel@tonic-gate 		/*
26047c478bd9Sstevel@tonic-gate 		 * If we read all quads in cur dir and the cur dir is not
26057c478bd9Sstevel@tonic-gate 		 * a leaf, scan for offsets (if the directory's CRC checks
26067c478bd9Sstevel@tonic-gate 		 * out OK). If we have a directory or a leaf, we save the
26077c478bd9Sstevel@tonic-gate 		 * current location on the stack and start reading that
26087c478bd9Sstevel@tonic-gate 		 * directory. So, we will end up with a depth first read of
26097c478bd9Sstevel@tonic-gate 		 * the entire config rom. If we are done with the current
26107c478bd9Sstevel@tonic-gate 		 * directory, pop it off the stack and continue the scanning
26117c478bd9Sstevel@tonic-gate 		 * as appropriate.
26127c478bd9Sstevel@tonic-gate 		 */
26137c478bd9Sstevel@tonic-gate 		if (quadlet == node->cur_dir_start + node->cur_dir_size) {
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 			int i, top;
26167c478bd9Sstevel@tonic-gate 			boolean_t done_with_cur_dir = B_FALSE;
26177c478bd9Sstevel@tonic-gate 
26187c478bd9Sstevel@tonic-gate 			if (node->expected_type == IEEE1212_LEAF_TYPE) {
26197c478bd9Sstevel@tonic-gate 				node->expected_type = IEEE1212_IMMEDIATE_TYPE;
26207c478bd9Sstevel@tonic-gate 				done_with_cur_dir = B_TRUE;
26217c478bd9Sstevel@tonic-gate 				goto donewithcurdir;
26227c478bd9Sstevel@tonic-gate 			}
26237c478bd9Sstevel@tonic-gate 
26247c478bd9Sstevel@tonic-gate 			ptr = &node->cfgrom[node->cur_dir_start];
26257c478bd9Sstevel@tonic-gate 			CFGROM_TYPE_KEY_VALUE(*ptr, type, key, value);
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate 			/*
26287c478bd9Sstevel@tonic-gate 			 * If CRC for this directory is invalid, turn off
26297c478bd9Sstevel@tonic-gate 			 * dir stack and start re-reading from root dir.
26307c478bd9Sstevel@tonic-gate 			 * This wastes the work done thus far, but CRC
26317c478bd9Sstevel@tonic-gate 			 * errors in directories should be rather rare.
26327c478bd9Sstevel@tonic-gate 			 * if s1394_crcsz_is_cfgsz is set, then set
26337c478bd9Sstevel@tonic-gate 			 * cfgrom_valid_size to the len specfied as crc len
26347c478bd9Sstevel@tonic-gate 			 * in quadlet 0.
26357c478bd9Sstevel@tonic-gate 			 */
26367c478bd9Sstevel@tonic-gate 			if (s1394_valid_dir(hal, node, key, ptr) == B_FALSE) {
26377c478bd9Sstevel@tonic-gate 				SET_CFGROM_DIR_STACK_OFF(node);
26387c478bd9Sstevel@tonic-gate 				if (s1394_crcsz_is_cfgsz != 0) {
26397c478bd9Sstevel@tonic-gate 					SET_CFGROM_SIZE_IS_CRCSIZE(node);
26407c478bd9Sstevel@tonic-gate 					node->cfgrom_valid_size =
26417c478bd9Sstevel@tonic-gate 					    ((node->cfgrom[0] >>
26427c478bd9Sstevel@tonic-gate 					    IEEE1394_CFG_ROM_CRC_LEN_SHIFT) &
26437c478bd9Sstevel@tonic-gate 					    IEEE1394_CFG_ROM_CRC_LEN_MASK);
26447c478bd9Sstevel@tonic-gate 				}
26457c478bd9Sstevel@tonic-gate 				*nextquadp = IEEE1212_ROOT_DIR_QUAD;
26467c478bd9Sstevel@tonic-gate 				return (0);
26477c478bd9Sstevel@tonic-gate 			}
26487c478bd9Sstevel@tonic-gate 			i = node->cur_dir_start + 1;
26497c478bd9Sstevel@tonic-gate 		rescan:
26507c478bd9Sstevel@tonic-gate 			for (done_with_cur_dir = B_FALSE; i <=
26517c478bd9Sstevel@tonic-gate 			    node->cur_dir_start + node->cur_dir_size; i++) {
26527c478bd9Sstevel@tonic-gate 				data = node->cfgrom[i];
26537c478bd9Sstevel@tonic-gate 				CFGROM_TYPE_KEY_VALUE(data, type, key, value);
26547c478bd9Sstevel@tonic-gate 				/* read leaf type and directory types only */
26557c478bd9Sstevel@tonic-gate 				if (type == IEEE1212_LEAF_TYPE || type ==
26567c478bd9Sstevel@tonic-gate 				    IEEE1212_DIRECTORY_TYPE) {
26577c478bd9Sstevel@tonic-gate 
26587c478bd9Sstevel@tonic-gate 					/*
26597c478bd9Sstevel@tonic-gate 					 * push current dir on stack; if the
26607c478bd9Sstevel@tonic-gate 					 * stack is overflowing, ie, too many
26617c478bd9Sstevel@tonic-gate 					 * directory level nestings, turn off
26627c478bd9Sstevel@tonic-gate 					 * dir stack and fall back to serial
26637c478bd9Sstevel@tonic-gate 					 * scanning, starting at root dir. This
26647c478bd9Sstevel@tonic-gate 					 * wastes all the work we have done
26657c478bd9Sstevel@tonic-gate 					 * thus far, but more than 16 levels
26667c478bd9Sstevel@tonic-gate 					 * of directories is rather odd...
26677c478bd9Sstevel@tonic-gate 					 */
26687c478bd9Sstevel@tonic-gate 					top = ++node->dir_stack_top;
26697c478bd9Sstevel@tonic-gate 					if (top == S1394_DIR_STACK_SIZE) {
26707c478bd9Sstevel@tonic-gate 						SET_CFGROM_DIR_STACK_OFF(node);
26717c478bd9Sstevel@tonic-gate 						*nextquadp =
26727c478bd9Sstevel@tonic-gate 						    IEEE1212_ROOT_DIR_QUAD;
26737c478bd9Sstevel@tonic-gate 						return (0);
26747c478bd9Sstevel@tonic-gate 					}
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 					node->dir_stack[top].dir_start =
26777c478bd9Sstevel@tonic-gate 					    node->cur_dir_start;
26787c478bd9Sstevel@tonic-gate 					node->dir_stack[top].dir_size =
26797c478bd9Sstevel@tonic-gate 					    node->cur_dir_size;
26807c478bd9Sstevel@tonic-gate 					node->dir_stack[top].dir_next_quad =
26817c478bd9Sstevel@tonic-gate 					    i + 1;
26827c478bd9Sstevel@tonic-gate 					/* and set the next quadlet to read */
26837c478bd9Sstevel@tonic-gate 					quadlet = i + value;
26847c478bd9Sstevel@tonic-gate 					node->expected_dir_quad = quadlet;
26857c478bd9Sstevel@tonic-gate 					node->expected_type = type;
26867c478bd9Sstevel@tonic-gate 					break;
26877c478bd9Sstevel@tonic-gate 				}
26887c478bd9Sstevel@tonic-gate 			}
26897c478bd9Sstevel@tonic-gate 
26907c478bd9Sstevel@tonic-gate 		donewithcurdir:
26917c478bd9Sstevel@tonic-gate 
26927c478bd9Sstevel@tonic-gate 			if ((i > node->cur_dir_start + node->cur_dir_size) ||
2693*d5ebc493SDan Cross 			    done_with_cur_dir == B_TRUE) {
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 				/*
26967c478bd9Sstevel@tonic-gate 				 * all done with cur dir; pop it off the stack
26977c478bd9Sstevel@tonic-gate 				 */
26987c478bd9Sstevel@tonic-gate 				if (node->dir_stack_top >= 0) {
26997c478bd9Sstevel@tonic-gate 					top = node->dir_stack_top--;
27007c478bd9Sstevel@tonic-gate 					node->cur_dir_start =
27017c478bd9Sstevel@tonic-gate 					    node->dir_stack[top].dir_start;
27027c478bd9Sstevel@tonic-gate 					node->cur_dir_size =
27037c478bd9Sstevel@tonic-gate 					    node->dir_stack[top].dir_size;
27047c478bd9Sstevel@tonic-gate 					i = node->dir_stack[top].dir_next_quad;
27057c478bd9Sstevel@tonic-gate 					goto rescan;
27067c478bd9Sstevel@tonic-gate 				} else {
27077c478bd9Sstevel@tonic-gate 					/*
27087c478bd9Sstevel@tonic-gate 					 * if empty stack, we are at the top
27097c478bd9Sstevel@tonic-gate 					 * level; declare done.
27107c478bd9Sstevel@tonic-gate 					 */
27117c478bd9Sstevel@tonic-gate 					return (1);
27127c478bd9Sstevel@tonic-gate 				}
27137c478bd9Sstevel@tonic-gate 			}
27147c478bd9Sstevel@tonic-gate 		} else {
27157c478bd9Sstevel@tonic-gate 			/* get the next quadlet */
27167c478bd9Sstevel@tonic-gate 			quadlet++;
27177c478bd9Sstevel@tonic-gate 		}
27187c478bd9Sstevel@tonic-gate 	}
27197c478bd9Sstevel@tonic-gate 	*nextquadp = quadlet;
27207c478bd9Sstevel@tonic-gate 
27217c478bd9Sstevel@tonic-gate 	return (0);
27227c478bd9Sstevel@tonic-gate }
2723