OpenSolaris_b135/uts/common/io/1394/s1394_dev_disc.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*
 * s1394_dev_disc.c
 *    1394 Services Layer Device Discovery Routines
 *    This file contains the bus reset thread code, bus manager routines and
 *    various routines that are used to implement remote Config ROM reading.
 *
 *    FUTURE:
 *    Rescan the bus if invalid nodes are seen.
 *    Investigate taskq for reading phase2 config rom reads.
 *    If we are reading the entire bus info blk, we should attempt
 *    a block read and fallback to quad reads if this fails.
 */

#include <sys/conf.h>
#include <sys/sysmacros.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#include <sys/sunndi.h>
#include <sys/modctl.h>
#include <sys/ddi_impldefs.h>
#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/kstat.h>
#include <sys/varargs.h>

#include <sys/tnf_probe.h>

#include <sys/1394/t1394.h>
#include <sys/1394/s1394.h>
#include <sys/1394/h1394.h>
#include <sys/1394/ieee1394.h>
#include <sys/1394/ieee1212.h>

/* hcmd_ret_t */
typedef enum {
	S1394_HCMD_INVALID,
	S1394_HCMD_NODE_DONE,
	S1394_HCMD_NODE_EXPECT_MORE,
	S1394_HCMD_LOCK_FAILED
} hcmd_ret_t;

#define	QUAD_TO_CFGROM_ADDR(b, n, q, addr) {			\
	uint64_t bl = (b);					\
	uint64_t nl = (n);					\
	addr = ((bl) << IEEE1394_ADDR_BUS_ID_SHIFT) |		\
		((nl) << IEEE1394_ADDR_PHY_ID_SHIFT);		\
	addr += IEEE1394_CONFIG_ROM_ADDR + ((q) << 2);		\
}

#define	CFGROM_READ_PAUSE(d)						\
	((s1394_cfgrom_read_delay_ms == 0) ? (void) 0 :			\
	delay(drv_usectohz((d) * 1000)))

#define	BUMP_CFGROM_READ_DELAY(n)					\
	(n)->cfgrom_read_delay += s1394_cfgrom_read_delay_incr

#define	CFGROM_GET_READ_DELAY(n, d)					\
	((d) = (n)->cfgrom_read_delay)

#define	SETUP_QUAD_READ(n, reset_fails, quadlet, cnt)			\
{									\
	int i = (reset_fails);						\
	if (i != 0) { 							\
		(n)->cfgrom_read_fails = 0;				\
		(n)->cfgrom_read_delay = (uchar_t)s1394_cfgrom_read_delay_ms; \
	}								\
	(n)->cfgrom_quad_to_read = (quadlet);				\
	(n)->cfgrom_quad_read_cnt = (cnt);				\
}

static void s1394_wait_for_events(s1394_hal_t *hal, int firsttime);

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));

static void s1394_flush_cmplq(s1394_hal_t *hal);

static void s1394_br_thread_exit(s1394_hal_t *hal);

static void s1394_target_bus_reset_notifies(s1394_hal_t *hal,
    t1394_localinfo_t *localinfo);

static int s1394_alloc_cfgrom(s1394_hal_t *hal, s1394_node_t *node,
    s1394_status_t *status);

static int s1394_cfgrom_scan_phase1(s1394_hal_t *hal);

static hcmd_ret_t s1394_br_thread_handle_cmd_phase1(s1394_hal_t *hal,
    cmd1394_cmd_t *cmd);

static int s1394_cfgrom_scan_phase2(s1394_hal_t *hal);

static hcmd_ret_t s1394_br_thread_handle_cmd_phase2(s1394_hal_t *hal,
    cmd1394_cmd_t *cmd);

static int s1394_read_config_quadlet(s1394_hal_t *hal, cmd1394_cmd_t *cmd,
    s1394_status_t *status);

static void s1394_cfgrom_read_callback(cmd1394_cmd_t *cmd);

static void s1394_get_quad_info(cmd1394_cmd_t *cmd, uint32_t *node_num,
    uint32_t *quadlet, uint32_t *data);

static int s1394_match_GUID(s1394_hal_t *hal, s1394_node_t *nnode);

static int s1394_match_all_GUIDs(s1394_hal_t *hal);

static void s1394_become_bus_mgr(void *arg);

static void s1394_become_bus_mgr_callback(cmd1394_cmd_t *cmd);

static int s1394_bus_mgr_processing(s1394_hal_t *hal);

static int s1394_do_bus_mgr_processing(s1394_hal_t *hal);

static void s1394_bus_mgr_timers_stop(s1394_hal_t *hal,
    timeout_id_t *bus_mgr_query_tid, timeout_id_t *bus_mgr_tid);

static void s1394_bus_mgr_timers_start(s1394_hal_t *hal,
    timeout_id_t *bus_mgr_query_tid, timeout_id_t *bus_mgr_tid);

static int s1394_cycle_master_capable(s1394_hal_t *hal);

static int s1394_do_phy_config_pkt(s1394_hal_t *hal, int new_root,
    int new_gap_cnt, uint32_t IRM_flags);

static void s1394_phy_config_callback(cmd1394_cmd_t *cmd);

static int s1394_calc_next_quad(s1394_hal_t *hal, s1394_node_t *node,
    uint32_t quadlet, uint32_t *nextquadp);

static int s1394_cfgrom_read_retry_cnt = 3;	/* 1 + 3 retries */
static int s1394_cfgrom_read_delay_ms = 20;	/* start with 20ms */
static int s1394_cfgrom_read_delay_incr = 10;	/* 10ms increments */
static int s1394_enable_crc_validation = 0;
static int s1394_turn_off_dir_stack = 0;
static int s1394_crcsz_is_cfgsz = 0;
static int s1394_enable_rio_pass1_workarounds = 0;

/*
 * s1394_br_thread()
 *    is the bus reset thread. Its sole purpose is to read/reread config roms
 *    as appropriate and do bus reset time things (bus manager processing,
 *    isoch resource reallocation etc.).
 */
void
s1394_br_thread(s1394_hal_t *hal)
{
	TNF_PROBE_0_DEBUG(s1394_br_thread_enter, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	/* Initialize the Bus Mgr timers */
	hal->bus_mgr_timeout_id = 0;
	hal->bus_mgr_query_timeout_id = 0;

	/* Initialize the cmpletion Q */
	mutex_enter(&hal->br_cmplq_mutex);
	hal->br_cmplq_head = hal->br_cmplq_tail = NULL;
	mutex_exit(&hal->br_cmplq_mutex);

	s1394_wait_for_events(hal, 1);

	for (;;) {
		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

		TNF_PROBE_0_DEBUG(s1394_br_thread_wait,
		    S1394_TNF_SL_HOTPLUG_STACK, "");

		s1394_wait_for_events(hal, 0);

		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

		TNF_PROBE_1_DEBUG(s1394_br_thread_restart,
		    S1394_TNF_SL_HOTPLUG_STACK, "",
		    tnf_int, hal_instance, ddi_get_instance(hal->halinfo.dip));

		/* stop bus manager timeouts, if needed */
		s1394_bus_mgr_timers_stop(hal, &hal->bus_mgr_query_timeout_id,
		    &hal->bus_mgr_timeout_id);

		s1394_flush_cmplq(hal);

		/* start timers for checking bus manager, if needed */
		s1394_bus_mgr_timers_start(hal, &hal->bus_mgr_query_timeout_id,
		    &hal->bus_mgr_timeout_id);

		/* Try to reallocate all isoch resources */
		s1394_isoch_rsrc_realloc(hal);

		if (s1394_cfgrom_scan_phase1(hal) != DDI_SUCCESS) {
			TNF_PROBE_0_DEBUG(br_thread_phase1_restart,
			    S1394_TNF_SL_HOTPLUG_STACK, "");
			continue;
		}

		TNF_PROBE_1_DEBUG(s1394_br_thread_phase1_done,
		    S1394_TNF_SL_HOTPLUG_STACK, "",
		    tnf_int, hal_instance, ddi_get_instance(hal->halinfo.dip));

		if (s1394_bus_mgr_processing(hal) != DDI_SUCCESS) {
			TNF_PROBE_0_DEBUG(br_thread_bus_mgr_restart,
			    S1394_TNF_SL_HOTPLUG_STACK, "");
			continue;
		}

		TNF_PROBE_1_DEBUG(s1394_br_thread_bus_mgr_proc_done,
		    S1394_TNF_SL_HOTPLUG_STACK, "",
		    tnf_int, hal_instance, ddi_get_instance(hal->halinfo.dip));

		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

		if (s1394_cfgrom_scan_phase2(hal) != DDI_SUCCESS) {
			TNF_PROBE_0_DEBUG(br_thread_phase2_restart,
			    S1394_TNF_SL_HOTPLUG_STACK, "");
			continue;
		}

		TNF_PROBE_1_DEBUG(s1394_br_thread_done,
		    S1394_TNF_SL_HOTPLUG_STACK, "",
		    tnf_int, hal_instance, ddi_get_instance(hal->halinfo.dip));

		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
	}
}

/*
 * s1394_wait_for_events()
 *    blocks waiting for a cv_signal on the bus reset condition variable.
 *    Used by the bus reset thread for synchronizing with the bus reset/
 *    self id interrupt callback from the hal. Does CPR initialization
 *    first time it is called. If services layer sees a valid self id
 *    buffer, it builds the topology tree and signals the bus reset thread
 *    to read the config roms as appropriate (indicated by BR_THR_CFGROM_SCAN).
 *    If the services layer wishes to kill the bus reset thread, it signals
 *    this by signaling a BR_THR_GO_AWAY event.
 */
static void
s1394_wait_for_events(s1394_hal_t *hal, int firsttime)
{
	uint_t event;

	TNF_PROBE_0_DEBUG(s1394_wait_for_events_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	ASSERT(MUTEX_NOT_HELD(&hal->br_thread_mutex));
	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	if (firsttime)
		CALLB_CPR_INIT(&hal->hal_cprinfo, &hal->br_thread_mutex,
		    callb_generic_cpr, "s1394_br_thread");

	/* Check and wait for a BUS RESET */
	mutex_enter(&hal->br_thread_mutex);
	while ((event = hal->br_thread_ev_type) == 0) {
		CALLB_CPR_SAFE_BEGIN(&hal->hal_cprinfo);
		cv_wait(&hal->br_thread_cv, &hal->br_thread_mutex);
		CALLB_CPR_SAFE_END(&hal->hal_cprinfo, &hal->br_thread_mutex);
	}

	if (event & BR_THR_GO_AWAY) {
		TNF_PROBE_1(s1394_wait_for_events, S1394_TNF_SL_HOTPLUG_STACK,
		    "", tnf_string, msg, "Go away set");
		s1394_br_thread_exit(hal);
		TNF_PROBE_0_DEBUG(s1394_wait_for_events_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		/*NOTREACHED*/
		return;
	}

	if (firsttime) {
		TNF_PROBE_0_DEBUG(s1394_wait_for_events_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		mutex_exit(&hal->br_thread_mutex);
		return;
	}

	mutex_enter(&hal->topology_tree_mutex);
	if (event & BR_THR_CFGROM_SCAN) {
		TNF_PROBE_2_DEBUG(s1394_wait_for_events_scan,
		    S1394_TNF_SL_HOTPLUG_STACK, "",
		    tnf_int, br_thread_gen, hal->br_cfgrom_read_gen,
		    tnf_int, hal_generation, hal->generation_count);
	}
	hal->br_cfgrom_read_gen = hal->generation_count;

	hal->br_thread_ev_type &= ~BR_THR_CFGROM_SCAN;
	mutex_exit(&hal->topology_tree_mutex);
	mutex_exit(&hal->br_thread_mutex);

	TNF_PROBE_0_DEBUG(s1394_wait_for_events_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");
}

/*
 * s1394_wait_for_cfgrom_callbacks()
 *    Waits for completed config rom reads. Takes each completion off the
 *    completion queue and passes it to the "completion handler" function
 *    that was passed in as an argument. Further processing of the completion
 *    queue depends on the return status of the completion handler. If there
 *    is a bus reset while waiting for completions or if the services layer
 *    signals BR_THR_GO_AWAY, quits waiting for completions and returns
 *    non-zero. Also returns non-zero if completion handler returns
 *    S1394_HCMD_LOCK_FAILED.  Returns 0 if config roms for all nodes have
 *    been dealt with.
 */
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))
{
	cmd1394_cmd_t *cmd;
	s1394_cmd_priv_t *s_priv;
	int ret, done = 0;
	hcmd_ret_t cmdret;

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_1_DEBUG(s1394_wait_for_cfgrom_callbacks_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, wait_gen, wait_gen);

	ret = DDI_SUCCESS;

	while (!done) {
		mutex_enter(&hal->br_cmplq_mutex);
		mutex_enter(&hal->topology_tree_mutex);
		while (wait_gen == hal->generation_count &&
		    (hal->br_thread_ev_type & BR_THR_GO_AWAY) == 0 &&
		    hal->br_cmplq_head == NULL) {
			mutex_exit(&hal->topology_tree_mutex);
			cv_wait(&hal->br_cmplq_cv, &hal->br_cmplq_mutex);
			mutex_enter(&hal->topology_tree_mutex);
		}
		ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
		if (wait_gen != hal->generation_count ||
		    (hal->br_thread_ev_type & BR_THR_GO_AWAY) != 0) {

#if !defined(NPROBE) && defined(TNF_DEBUG)
			int hal_gen = hal->generation_count;
#endif

			mutex_exit(&hal->topology_tree_mutex);
			mutex_exit(&hal->br_cmplq_mutex);
			s1394_flush_cmplq(hal);
			TNF_PROBE_1_DEBUG(s1394_wait_for_cfgrom_callbacks_exit,
			    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, hal_gen,
			    hal_gen);
			return (DDI_FAILURE);
		}
		mutex_exit(&hal->topology_tree_mutex);

		if ((cmd = hal->br_cmplq_head) != NULL) {
			s_priv = S1394_GET_CMD_PRIV(cmd);

			hal->br_cmplq_head = s_priv->cmd_priv_next;
		}
		if (cmd == hal->br_cmplq_tail)
			hal->br_cmplq_tail = NULL;
		mutex_exit(&hal->br_cmplq_mutex);

		if (cmd != NULL) {
			if (cmd->bus_generation != wait_gen) {
				TNF_PROBE_3(
				    s1394_wait_for_cfgrom_callbacks,
				    S1394_TNF_SL_HOTPLUG_STACK, "",
				    tnf_string, msg, "command gen != wait_gen",
				    tnf_uint, cmd_gen, cmd->bus_generation,
				    tnf_uint, wait_gen, wait_gen);
				(void) s1394_free_cmd(hal, &cmd);
				continue;
			}
			cmdret = (*handle_cmd_fn)(hal, cmd);
			TNF_PROBE_2_DEBUG(s1394_wait_for_cfgrom_callbacks,
			    S1394_TNF_SL_HOTPLUG_STACK, "",
			    tnf_opaque, cmd, cmd, tnf_int, cmdret, cmdret);
			ASSERT(cmdret != S1394_HCMD_INVALID);
			if (cmdret == S1394_HCMD_LOCK_FAILED) {
				/* flush completion queue */
				ret = DDI_FAILURE;
				s1394_flush_cmplq(hal);
				break;
			} else if (cmdret == S1394_HCMD_NODE_DONE) {
				if (--hal->cfgroms_being_read == 0) {
					/* All done */
					break;
				}
			} else {
				ASSERT(cmdret == S1394_HCMD_NODE_EXPECT_MORE);
				done = 0;
			}
		}
	}

	TNF_PROBE_0_DEBUG(s1394_wait_for_cfgrom_callbacks_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	return (ret);
}

/*
 * s1394_flush_cmplq()
 *    Frees all cmds on the completion queue.
 */
static void
s1394_flush_cmplq(s1394_hal_t *hal)
{
	s1394_cmd_priv_t *s_priv;
	cmd1394_cmd_t *cmd, *tcmd;

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_0_DEBUG(s1394_flush_cmplq_enter, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

	cmd = NULL;

	do {
		mutex_enter(&hal->br_cmplq_mutex);
		cmd = hal->br_cmplq_head;
		hal->br_cmplq_head = hal->br_cmplq_tail = NULL;
		mutex_exit(&hal->br_cmplq_mutex);

		while (cmd != NULL) {
			s_priv = S1394_GET_CMD_PRIV(cmd);

			tcmd = s_priv->cmd_priv_next;
			TNF_PROBE_2_DEBUG(s1394_flush_cmplq,
			    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque, cmd,
			    cmd, tnf_uint, cmd_gen, cmd->bus_generation);
			(void) s1394_free_cmd(hal, &cmd);
			cmd = tcmd;
		}

		mutex_enter(&hal->br_cmplq_mutex);
		cmd = hal->br_cmplq_head;
		mutex_exit(&hal->br_cmplq_mutex);

	} while (cmd != NULL);

	TNF_PROBE_0_DEBUG(s1394_flush_cmplq_exit, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

}

/*
 * s1394_br_thread_exit()
 *    Flushes the completion queue and calls thread_exit() (which effectively
 *    kills the bus reset thread).
 */
static void
s1394_br_thread_exit(s1394_hal_t *hal)
{
	ASSERT(MUTEX_HELD(&hal->br_thread_mutex));
	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
	TNF_PROBE_0(s1394_br_thread_exit_enter, S1394_TNF_SL_HOTPLUG_STACK, "");
	s1394_flush_cmplq(hal);
#ifndef	__lock_lint
	CALLB_CPR_EXIT(&hal->hal_cprinfo);
#endif
	hal->br_thread_ev_type &= ~BR_THR_GO_AWAY;
	thread_exit();
	/*NOTREACHED*/
	TNF_PROBE_0(s1394_br_thread_exit_enter, S1394_TNF_SL_HOTPLUG_STACK, "");
}

/*
 * s1394_target_bus_reset_notifies()
 *    tells the ndi event framework to invoke any callbacks registered for
 *    "bus reset event".
 */
static void
s1394_target_bus_reset_notifies(s1394_hal_t *hal, t1394_localinfo_t *localinfo)
{
	ddi_eventcookie_t cookie;

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_2_DEBUG(s1394_target_bus_reset_notifies_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, bus_gen,
	    localinfo->bus_generation, tnf_uint, node_id,
	    localinfo->local_nodeID);

	if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, NULL,
	    DDI_DEVI_BUS_RESET_EVENT, &cookie, NDI_EVENT_NOPASS) ==
	    NDI_SUCCESS) {
		(void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, NULL,
		    cookie, localinfo);
	}
	TNF_PROBE_0_DEBUG(s1394_target_bus_reset_notifies_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");
}

/*
 * s1394_alloc_cfgrom()
 *    Allocates config rom for the node. Sets CFGROM_NEW_ALLOC bit in the
 *    node cfgrom state. Drops topology_tree_mutex around the calls to
 *    kmem_zalloc(). If re-locking fails, returns DDI_FAILURE, else returns
 *    DDI_SUCCESS.
 */
static int
s1394_alloc_cfgrom(s1394_hal_t *hal, s1394_node_t *node, s1394_status_t *status)
{
	uint32_t *cfgrom;

	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_0_DEBUG(s1394_alloc_cfgrom_enter, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

	*status = S1394_NOSTATUS;

	/*
	 * if cfgrom is non-NULL, this has to be generation changed
	 * case (where we allocate cfgrom again to reread the cfgrom)
	 */
	ASSERT(node->cfgrom == NULL || (node->cfgrom != NULL &&
	    CFGROM_GEN_CHANGED(node) == B_TRUE));

	/*
	 * if node matched, either cfgrom has to be NULL or link should be
	 * off in the last matched node or config rom generations changed.
	 */
	ASSERT(NODE_MATCHED(node) == B_FALSE || (NODE_MATCHED(node) == B_TRUE &&
	    (node->cfgrom == NULL || LINK_ACTIVE(node->old_node) == B_FALSE) ||
	    CFGROM_GEN_CHANGED(node) == B_TRUE));

	s1394_unlock_tree(hal);
	cfgrom = (uint32_t *)kmem_zalloc(IEEE1394_CONFIG_ROM_SZ, KM_SLEEP);
	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		kmem_free(cfgrom, IEEE1394_CONFIG_ROM_SZ);
		*status |= S1394_LOCK_FAILED;
		TNF_PROBE_1(s1394_alloc_cfgrom, S1394_TNF_SL_HOTPLUG_ERROR,
		    "", tnf_string, msg, "cannot relock the tree");
		TNF_PROBE_0_DEBUG(s1394_alloc_cfgrom_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}
	node->cfgrom = cfgrom;
	node->cfgrom_size = IEEE1394_CONFIG_ROM_QUAD_SZ;
	SET_CFGROM_NEW_ALLOC(node);
	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
	TNF_PROBE_3(s1394_alloc_cfgrom_exit, S1394_TNF_SL_HOTPLUG_STACK,
	    "cfgrom alloc", tnf_uint, hal_gen, hal->generation_count, tnf_uint,
	    node_num, node->node_num, tnf_opaque, cfgrom, cfgrom);
	return (DDI_SUCCESS);
}

/*
 * s1394_free_cfgrom()
 *    Marks the config rom invalid and frees up the config based on otpions.
 */
void
s1394_free_cfgrom(s1394_hal_t *hal, s1394_node_t *node,
    s1394_free_cfgrom_t options)
{
	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
	ASSERT(node->cfgrom != NULL);

	TNF_PROBE_0_DEBUG(s1394_free_cfgrom_enter, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

	if (options == S1394_FREE_CFGROM_BOTH) {
		/*
		 * free in both old and new trees; will be called with
		 * new node.
		 */
		s1394_node_t *onode = node->old_node;

		if (NODE_MATCHED(node) == B_TRUE && onode->cfgrom != NULL)
			ASSERT(onode->cfgrom == node->cfgrom);

		TNF_PROBE_4(s1394_free_cfgrom_both,
		    S1394_TNF_SL_HOTPLUG_STACK, "cfgrom free", tnf_uint,
		    hal_gen, hal->generation_count, tnf_int, node_num,
		    node->node_num, tnf_opaque, old_cfgrom, onode->cfgrom,
		    tnf_opaque, cfgrom, node->cfgrom);

		if (onode != NULL && onode->cfgrom != NULL && onode->cfgrom !=
		    node->cfgrom)
			kmem_free(onode->cfgrom, IEEE1394_CONFIG_ROM_SZ);

		kmem_free(node->cfgrom, IEEE1394_CONFIG_ROM_SZ);
		onode->cfgrom = NULL;
		node->cfgrom = NULL;

		CLEAR_CFGROM_STATE(onode);
		CLEAR_CFGROM_STATE(node);

	} else if (options == S1394_FREE_CFGROM_NEW) {

		TNF_PROBE_2(s1394_free_cfgrom_new,
		    S1394_TNF_SL_HOTPLUG_STACK, "cfgrom free",
		    tnf_int, node_num, node->node_num,
		    tnf_opaque, cfgrom, node->cfgrom);

		ASSERT(CFGROM_NEW_ALLOC(node) == B_TRUE);
		kmem_free(node->cfgrom, IEEE1394_CONFIG_ROM_SZ);
		CLEAR_CFGROM_NEW_ALLOC(node);
		node->cfgrom = NULL;
		CLEAR_CFGROM_STATE(node);

	} else if (options == S1394_FREE_CFGROM_OLD) {

		/* freeing in old tree */
		TNF_PROBE_2_DEBUG(s1394_free_cfgrom_old,
		    S1394_TNF_SL_HOTPLUG_STACK, "cfgrom free",
		    tnf_int, node_num, node->node_num,
		    tnf_opaque, cfgrom, node->cfgrom);
		kmem_free(node->cfgrom, IEEE1394_CONFIG_ROM_SZ);
		node->cfgrom = NULL;
		CLEAR_CFGROM_STATE(node);
	}

	TNF_PROBE_0_DEBUG(s1394_free_cfgrom_exit, S1394_TNF_SL_HOTPLUG_STACK,
	    "");
}

/*
 * s1394_copy_cfgrom()
 *    Copies config rom info from "from" node to "to" node. Clears
 *    CFGROM_NEW_ALLOC bit in cfgrom state in bothe nodes. (CFGROM_NEW_ALLOC
 *    acts as a reference count. If set, only the node in the current tree
 *    has a pointer to it; if clear, both the node in the current tree as
 *    well as the corresponding node in the old tree point to the same memory).
 */
void
s1394_copy_cfgrom(s1394_node_t *to, s1394_node_t *from)
{
	TNF_PROBE_3_DEBUG(s1394_copy_cfgrom_enter, S1394_TNF_SL_HOTPLUG_STACK,
	    "", tnf_int, to_node, to->node_num, tnf_int,
	    from_node, from->node_num, tnf_opaque, from_cfgrom, from->cfgrom);

	ASSERT(to->cfgrom == NULL);

	to->cfgrom = from->cfgrom;
	to->cfgrom_state = from->cfgrom_state;
	to->cfgrom_valid_size = from->cfgrom_valid_size;
	to->cfgrom_size = from->cfgrom_size;
	to->node_state = from->node_state;

	bcopy(from->dir_stack, to->dir_stack,
	    offsetof(s1394_node_t, cfgrom_quad_to_read) -
	    offsetof(s1394_node_t, dir_stack));

	to->cfgrom_quad_to_read = from->cfgrom_quad_to_read;

	CLEAR_CFGROM_NEW_ALLOC(to);
	CLEAR_CFGROM_NEW_ALLOC(from);

	/*
	 * old link off, new link on => handled in s1394_cfgrom_scan_phase1
	 * old link on, new link off => handled in s1394_process_old_tree
	 */
	if (LINK_ACTIVE(from) == B_FALSE) {
		/*
		 * if last time around, link was off, there wouldn't
		 * have been config rom allocated.
		 */
		ASSERT(from->cfgrom == NULL);
		TNF_PROBE_0_DEBUG(s1394_copy_cfgrom_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return;
	} else {
		s1394_selfid_pkt_t *selfid_pkt = to->selfid_packet;

		if (IEEE1394_SELFID_ISLINKON(selfid_pkt))
			SET_LINK_ACTIVE(to);
	}

	TNF_PROBE_0_DEBUG(s1394_copy_cfgrom_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");
}

/*
 * s1394_read_bus_info_blk()
 *    Attempts to kick off reading IEEE1212_NODE_CAP_QUAD quad or quad 0.
 *    Increments cfgroms_being_read by 1. Returns DDI_SUCCESS command was
 *    issued, else sets status to the failure reason and returns DDI_FAILURE.
 */
static int
s1394_read_bus_info_blk(s1394_hal_t *hal, s1394_node_t *node,
    s1394_status_t *status)
{
	uint32_t quadlet;
	cmd1394_cmd_t *cmd;
	uchar_t node_num;

	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
	ASSERT(LINK_ACTIVE(node) == B_TRUE);

	node_num = node->node_num;

	TNF_PROBE_2_DEBUG(s1394_read_bus_info_blk_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, hal_gen,
	    hal->generation_count, tnf_int, node_num, node_num);

	/*
	 * drop the topology lock around command allocation. Return failure
	 * if either command allocation fails or cannot reacquire the lock
	 */
	s1394_unlock_tree(hal);
	*status = S1394_NOSTATUS;

	if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
		TNF_PROBE_1(s1394_read_bus_info_blk, S1394_TNF_SL_HOTPLUG_ERROR,
		    "", tnf_string, msg, "command allocation failed");
		*status |= S1394_CMD_ALLOC_FAILED;
	}
	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		*status |= S1394_LOCK_FAILED;
		TNF_PROBE_1(s1394_read_bus_info_blk, S1394_TNF_SL_HOTPLUG_ERROR,
		    "", tnf_string, msg, "unable to relock the tree");
		/* free the cmd allocated above */
		if (((*status) & S1394_CMD_ALLOC_FAILED) != 0)
			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
	}
	if (((*status) & (S1394_CMD_ALLOC_FAILED | S1394_LOCK_FAILED)) != 0) {
		TNF_PROBE_0_DEBUG(s1394_read_bus_info_blk_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	/* allocate cfgrom if needed */
	if (node->cfgrom == NULL && s1394_alloc_cfgrom(hal, node, status) !=
	    DDI_SUCCESS) {
		ASSERT(((*status) & S1394_LOCK_FAILED) != 0);
		(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
		TNF_PROBE_1(s1394_read_bus_info_blk, S1394_TNF_SL_HOTPLUG_ERROR,
		    "", tnf_string, msg, "config rom allocation failed");
		TNF_PROBE_0_DEBUG(s1394_read_bus_info_blk_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	/*
	 * if this is a matched node, read quad 2 (node capabilities) to
	 * see if the generation count changed.
	 */
	quadlet = CFGROM_BIB_READ(node) ? IEEE1212_NODE_CAP_QUAD : 0;

	/*
	 * read bus info block at 100Mbit. This will help us with the cases
	 * where LINK is slower than PHY; s1394 uses PHY speed till speed map
	 * is updated.
	 */
	cmd->completion_callback = s1394_cfgrom_read_callback;
	cmd->bus_generation = hal->generation_count;
	cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
	    CMD1394_OVERRIDE_ADDR | CMD1394_OVERRIDE_SPEED);
	cmd->cmd_speed = IEEE1394_S100;
	cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD;

	QUAD_TO_CFGROM_ADDR(IEEE1394_LOCAL_BUS, node_num,
	    quadlet, cmd->cmd_addr);

	TNF_PROBE_3_DEBUG(s1394_read_bus_info_blk,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, hal_gen,
	    hal->generation_count, tnf_int, node_num, node_num, tnf_uint,
	    quadlet, quadlet);

	TNF_PROBE_5_DEBUG(s1394_read_bus_info_blk,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int,
	    node_num, node_num, tnf_int, parsed, CFGROM_PARSED(node), tnf_int,
	    matched, NODE_MATCHED(node), tnf_int, visited,
	    NODE_VISITED(node), tnf_int, generation_changed,
	    CFGROM_GEN_CHANGED(node));

	SETUP_QUAD_READ(node, 1, quadlet, 1);
	if (s1394_read_config_quadlet(hal, cmd, status) != DDI_SUCCESS) {
		TNF_PROBE_1(s1394_read_bus_info_blk, S1394_TNF_SL_HOTPLUG_ERROR,
		    "", tnf_string, msg, "Unable to start read");
		/* free the command if it wasn't handed over to the HAL */
		if (((*status) & S1394_CMD_INFLIGHT) == 0) {
			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
		}
		if (((*status) & S1394_LOCK_FAILED) != 0) {
			ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
		}
		TNF_PROBE_0_DEBUG(s1394_read_bus_info_blk_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	hal->cfgroms_being_read++;
	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_1_DEBUG(s1394_read_bus_info_blk_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, cfgrom_read_cnt,
	    hal->cfgroms_being_read);

	return (DDI_SUCCESS);
}

/*
 * s1394_read_rest_of_cfgrom()
 *    Attempts to start reading node->cfgrom_quad_to_read quadlet. Increments
 *    cfgroms_being_read by 1 and returns DDI_SUCCESS if command was issued,
 *    else sets status to the failure reason and returns DDI_FAILURE.
 */
int
s1394_read_rest_of_cfgrom(s1394_hal_t *hal, s1394_node_t *node,
    s1394_status_t *status)
{
	cmd1394_cmd_t *cmd;
	uchar_t node_num = node->node_num;

	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
	ASSERT(LINK_ACTIVE(node) == B_TRUE);

	TNF_PROBE_2_DEBUG(s1394_read_rest_of_cfgrom_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, hal_gen,
	    hal->generation_count, tnf_int, node_num, node_num);

	/*
	 * drop the topology lock around command allocation. Return failure
	 * if either command allocation fails or cannot reacquire the lock
	 */
	s1394_unlock_tree(hal);
	*status = S1394_NOSTATUS;

	if (s1394_alloc_cmd(hal, 0, &cmd) != DDI_SUCCESS) {
		*status |= S1394_CMD_ALLOC_FAILED;
		TNF_PROBE_1(s1394_read_rest_of_cfgrom,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "command allocation failed");
	}
	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		*status |= S1394_LOCK_FAILED;
		/* free if we allocated a cmd above */
		if (((*status) & S1394_CMD_ALLOC_FAILED) == 0)
			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
		TNF_PROBE_1(s1394_read_rest_of_cfgrom,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "unable to relock the tree");
	}
	if (((*status) & (S1394_CMD_ALLOC_FAILED | S1394_LOCK_FAILED)) != 0) {
		TNF_PROBE_0_DEBUG(s1394_read_rest_of_cfgrom_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	cmd->completion_callback = s1394_cfgrom_read_callback;
	cmd->bus_generation = hal->generation_count;
	cmd->cmd_options = (CMD1394_CANCEL_ON_BUS_RESET |
	    CMD1394_OVERRIDE_ADDR);
	cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD;

	TNF_PROBE_2_DEBUG(s1394_read_rest_of_cfgrom, S1394_TNF_SL_HOTPLUG_STACK,
	    "", tnf_uint, hal_gen, hal->generation_count, tnf_int, node_num,
	    node->node_num);

	QUAD_TO_CFGROM_ADDR(IEEE1394_LOCAL_BUS, node_num,
	    node->cfgrom_quad_to_read, cmd->cmd_addr);
	SETUP_QUAD_READ(node, 1, node->cfgrom_quad_to_read, 1);
	if (s1394_read_config_quadlet(hal, cmd, status) != DDI_SUCCESS) {
		TNF_PROBE_1(s1394_read_rest_of_cfgrom_exit,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "unable to start read");
		/* free the command if it wasn't handed over to the HAL */
		if (((*status) & S1394_CMD_INFLIGHT) == 0) {
			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
		}
		if (((*status) & S1394_LOCK_FAILED) != 0) {
			ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
		}
		TNF_PROBE_0_DEBUG(s1394_read_rest_of_cfgrom_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	hal->cfgroms_being_read++;
	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_1_DEBUG(s1394_read_rest_of_cfgrom_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, cfgrom_read_cnt,
	    hal->cfgroms_being_read);

	return (DDI_SUCCESS);
}

/*
 * s1394_cfgrom_scan_phase1()
 *    Attempts to read bus info blocks for nodes as needed. Returns DDI_FAILURE
 *    if bus reset generations changed (as indicated by s1394_lock_tree()
 *    return status) or if any of the callees return failure, else returns
 *    DDI_SUCCESS.
 */
static int
s1394_cfgrom_scan_phase1(s1394_hal_t *hal)
{
	uint32_t number_of_nodes;
	int ret;
	int node;
	int wait_in_gen;
	int wait_for_cbs;
	uint_t hal_node_num;
	uint_t hal_node_num_old;
	s1394_node_t *nnode, *onode;
	s1394_selfid_pkt_t *selfid_pkt;
	s1394_status_t status;

	TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase1_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase1_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}
	wait_for_cbs = 0;
	number_of_nodes = hal->number_of_nodes;
	hal->cfgroms_being_read = 0;
	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
	hal_node_num_old = IEEE1394_NODE_NUM(hal->old_node_id);
	s1394_unlock_tree(hal);

	ret = DDI_SUCCESS;

	/* Send requests for all new node config ROM 0 */
	for (node = 0; node < number_of_nodes; node++) {

		status = S1394_UNKNOWN;

		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
			status = S1394_LOCK_FAILED;
			break;
		}

		nnode = &hal->topology_tree[node];
		onode = nnode->old_node;
		/* if node matched, onode should be non NULL */
		ASSERT(NODE_MATCHED(nnode) == B_FALSE || (NODE_MATCHED(nnode) ==
		    B_TRUE && onode != NULL));

		/*
		 * Read bus info block if it is a brand new node (MATCHED is 0)
		 * or if matched but link was off in previous generations or
		 * or if matched but had invalid cfgrom in last generation
		 * or if matched but config rom generation > 1 (this is to
		 * check if config rom generation changed between bus resets).
		 */
		if ((node != hal_node_num) &&
		    ((NODE_MATCHED(nnode) == B_FALSE) ||
		    (NODE_MATCHED(nnode) == B_TRUE && LINK_ACTIVE(onode) ==
		    B_FALSE) || (NODE_MATCHED(nnode) == B_TRUE &&
		    (onode->cfgrom == NULL || CFGROM_VALID(onode) ==
		    B_FALSE)) || (NODE_MATCHED(nnode) == B_TRUE &&
		    nnode->cfgrom != NULL && CONFIG_ROM_GEN(nnode->cfgrom) >
		    1))) {

			SET_NODE_VISITED(nnode);
			selfid_pkt = nnode->selfid_packet;
			if (IEEE1394_SELFID_ISLINKON(selfid_pkt)) {

				SET_LINK_ACTIVE(nnode);

				status = S1394_UNKNOWN;

				if (s1394_read_bus_info_blk(hal, nnode,
				    &status) != DDI_SUCCESS) {
					if ((status & S1394_LOCK_FAILED) != 0)
						break;
				} else {
					wait_for_cbs++;
					wait_in_gen = hal->br_cfgrom_read_gen;
				}
			} else {
				/*
				 * Special case: if link was active last
				 * time around, this should be treated as
				 * node going away.
				 */
				CLEAR_LINK_ACTIVE(nnode);
				if (NODE_MATCHED(nnode) == B_TRUE &&
				    LINK_ACTIVE(onode) == B_TRUE) {
					CLEAR_CFGROM_STATE(nnode);
					TNF_PROBE_3(s1394_cfgrom_scan_phase1,
					    S1394_TNF_SL_HOTPLUG_ERROR,
					    "", tnf_string, msg,
					    "link lost power", tnf_int, node,
					    node, tnf_int, onode,
					    onode->node_num);
				}
			}
		} else {
			if (node == hal_node_num) {
				onode = &hal->old_tree[hal_node_num_old];
				/* Set up the local matched nodes */
				if (onode) {
					nnode->old_node = onode;
					SET_NODE_MATCHED(nnode);
					SET_NODE_MATCHED(onode);
					s1394_copy_cfgrom(nnode, onode);
				}
			}
		}
		s1394_unlock_tree(hal);
	}

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	if ((status & S1394_LOCK_FAILED) != 0) {
		TNF_PROBE_1(s1394_cfrom_scan_phase1_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "",
		    tnf_string, msg, "Generations changed");
		return (DDI_FAILURE);
	}

	/*
	 * If we started any reads, wait for completion callbacks
	 */
	if (wait_for_cbs != 0) {
		ret = s1394_wait_for_cfgrom_callbacks(hal, wait_in_gen,
		    s1394_br_thread_handle_cmd_phase1);
	}

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_0_DEBUG(s1394_cfrom_scan_phase1_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	return (ret);
}

/*
 * s1394_br_thread_handle_cmd_phase1()
 *    Process the cmd completion for phase 1 config rom reads. If we
 *    successfully read IEEE1212_NODE_CAP_QUAD quadlet and config rom gen
 *    did not change, move targets hanging off the old node to the current
 *    node. If config rom generations change, alloc new config rom and start
 *    re-reading the new config rom. If all of bus info block is read (as
 *    required), mark the node as CFGROM_BIB_READ. If config rom read fails
 *    retry if not too many failures. Topology tree mutex is dropped and
 *    reacquired in this routine. If reacquiring fails, returns
 *    S1394_HCMD_LOCK_FAILED. If the entire bus info block is read, returns
 *    S1394_HCMD_NODE_DONE, else returns S1394_HCMD_NODE_EXPECT_MORE (to
 *    indicate not done with the node yet).
 *
 *    If we cannot read any of the quadlets in the bus info block, cfgrom
 *    is marked invalid in this generation (a side effect of calling
 *    s1394_free_cfgrom()). We free cfgrom in this routine only if the failure
 *    is not due to bus generations changing.
 */
static hcmd_ret_t
s1394_br_thread_handle_cmd_phase1(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
{
	s1394_target_t *t;
	s1394_node_t *node, *onode;
	uint32_t node_num, quadlet, data;
	int freecmd, done, locked;
	hcmd_ret_t cmdret;
	uchar_t readdelay;
	s1394_status_t status;

	s1394_get_quad_info(cmd, &node_num, &quadlet, &data);
	ASSERT(quadlet == 0 || quadlet < IEEE1394_BIB_QUAD_SZ);

	TNF_PROBE_0_DEBUG(s1394_br_thread_handle_cmd_phase1_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	cmdret = S1394_HCMD_NODE_EXPECT_MORE;

	locked = 1;
	freecmd = 1;

	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		TNF_PROBE_1(s1394_br_thread_handle_cmd_phase1,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
		    "unable to lock tree");
		locked = 0;
		goto bail;
	}

	node = &hal->topology_tree[node_num];

	if (cmd->cmd_result == CMD1394_CMDSUCCESS) {

		int reread = 0;

		done = 0;

		if (quadlet == IEEE1212_NODE_CAP_QUAD &&
		    CFGROM_BIB_READ(node)) {

			int cur_gen = ((data & IEEE1394_BIB_GEN_MASK) >>
			    IEEE1394_BIB_GEN_SHIFT);

			/*
			 * node->old_node can be NULL if this is a new node &
			 * we are doing a rescan
			 */
			onode = node->old_node;
			if (CONFIG_ROM_GEN(node->cfgrom) == cur_gen) {

				if (CFGROM_PARSED(node) == B_TRUE) {
					rw_enter(&hal->target_list_rwlock,
					    RW_WRITER);
					/* Update the target list, if any */
					if (onode != NULL &&
					    (t = onode->target_list) != NULL) {
						node->target_list = t;
						while (t != NULL) {
							t->on_node = node;
							t = t->target_sibling;
						}
					}
					rw_exit(&hal->target_list_rwlock);
				}
				SET_NODE_MATCHED(node);
				if (onode)
					SET_NODE_MATCHED(onode);
				node->cfgrom_quad_to_read =
				    IEEE1394_BIB_QUAD_SZ;
				done++;
			} else {

				TNF_PROBE_4(s1394_br_thread_handle_cmd_phase1,
				    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string,
				    msg, "config rom generation changed",
				    tnf_int, node_num, node_num,
				    tnf_int, cur_gen, cur_gen, tnf_int, old_gen,
				    CONFIG_ROM_GEN(node->cfgrom));

				SET_CFGROM_GEN_CHANGED(node);
				if (onode != NULL)
					SET_CFGROM_GEN_CHANGED(onode);
				/*
				 * Reset BIB_READ flag and start reading entire
				 * config rom.
				 */
				CLEAR_CFGROM_BIB_READ(node);
				reread = 1;

				/*
				 * if generations changed, allocate cfgrom for
				 * the new generation. s1394_match_GUID() will
				 * free up the cfgrom from the old generation.
				 */
				if (s1394_alloc_cfgrom(hal, node, &status) !=
				    DDI_SUCCESS) {
					ASSERT((status & S1394_LOCK_FAILED) !=
					    0);
					ASSERT(MUTEX_NOT_HELD(&hal->
					    topology_tree_mutex));
					locked = 0;
					/* we failed to relock the tree */
					goto bail;
				}
			}
		}

		/*
		 * we end up here if we don't have bus_info_blk for this
		 * node or if config rom generation changed.
		 */

		/*
		 * Pass1 Rio bug workaround. Due to this bug, if we read
		 * past quadlet 5 of the config rom, the PCI bus gets wedged.
		 * Avoid the hang by not reading past quadlet 5.
		 * We identify a remote Rio by the node vendor id part of
		 * quad 3 (which is == SUNW == S1394_SUNW_OUI (0x80020)).
		 */
		if (s1394_enable_rio_pass1_workarounds != 0) {
			if ((quadlet == 3) && ((data >> 8) == S1394_SUNW_OUI)) {
				node->cfgrom_size = IEEE1394_BIB_QUAD_SZ;
				node->cfgrom_valid_size = IEEE1394_BIB_QUAD_SZ;
			}
		}

		if (!done) {

			if (reread)
				quadlet = 0;
			else
				node->cfgrom[quadlet++] = data;

			/* if we don't have the entire bus_info_blk... */
			if (quadlet < IEEE1394_BIB_QUAD_SZ) {

				CFGROM_GET_READ_DELAY(node, readdelay);
				SETUP_QUAD_READ(node, 1, quadlet, 1);
				s1394_unlock_tree(hal);
				CFGROM_READ_PAUSE(readdelay);
				/* get next quadlet */
				if (s1394_lock_tree(hal) != DDI_SUCCESS) {
					TNF_PROBE_3(
					    s1394_br_thread_handle_cmd_phase1,
					    S1394_TNF_SL_HOTPLUG_STACK, "",
					    tnf_string, msg,
					    "unable to relock tree", tnf_uint,
					    node_num, node_num, tnf_int,
					    quad_to_read, quadlet);
					locked = 0;
				} else if (s1394_read_config_quadlet(hal, cmd,
				    &status) != DDI_SUCCESS) {
					/*
					 * Failed to get going. If command was
					 * successfully handed over to the HAL,
					 * don't free it (it will get freed
					 * later in the callback).
					 */
					TNF_PROBE_3(
					    s1394_br_thread_handle_cmd_phase1,
					    S1394_TNF_SL_HOTPLUG_STACK, "",
					    tnf_string, msg,
					    "unable to read", tnf_uint,
					    node_num, node_num, tnf_int,
					    quad_to_read, quadlet);
					if ((status & S1394_CMD_INFLIGHT) !=
					    0) {
						freecmd = 0;
					}
					if ((status & S1394_LOCK_FAILED) != 0) {
						locked = 0;
					} else {
						if (CFGROM_NEW_ALLOC(node) ==
						    B_TRUE) {
							s1394_free_cfgrom(hal,
							    node,
							S1394_FREE_CFGROM_NEW);
						} else {
							CLEAR_CFGROM_STATE(
							    node);
						}
					}
					done++;
				} else {
					freecmd = 0;
				}
			} else {
				/* got all of bus_info_blk */
				SET_CFGROM_BIB_READ(node);
				if (node->cfgrom_size == IEEE1394_BIB_QUAD_SZ)
				    SET_CFGROM_ALL_READ(node);
				node->cfgrom_quad_to_read = quadlet;
				done++;
				TNF_PROBE_3_DEBUG(
				    s1394_br_thread_handle_cmd_phase1,
				    S1394_TNF_SL_HOTPLUG_STACK,
				    "", tnf_string, msg, "read bus info blk",
				    tnf_int, node_num, node->node_num,
				    tnf_opaque, cfgrom, node->cfgrom);
			}
		}
	} else {
		done = 1;
		node->cfgrom_read_fails++;
		BUMP_CFGROM_READ_DELAY(node);

		/* retry if not too many failures */
		if (node->cfgrom_read_fails < s1394_cfgrom_read_retry_cnt) {
			CFGROM_GET_READ_DELAY(node, readdelay);
			SETUP_QUAD_READ(node, 0, quadlet, 1);
			s1394_unlock_tree(hal);
			CFGROM_READ_PAUSE(readdelay);
			if (s1394_lock_tree(hal) != DDI_SUCCESS) {
				TNF_PROBE_3(
				    s1394_br_thread_handle_cmd_phase1,
				    S1394_TNF_SL_HOTPLUG_ERROR, "",
				    tnf_string, msg,
				    "unable to relock tree", tnf_uint,
				    node_num, node_num, tnf_int,
				    quad_to_read, quadlet);
				locked = 0;
			} else if (s1394_read_config_quadlet(hal, cmd,
			    &status) != DDI_SUCCESS) {
				/*
				 * Failed to get going. If command was
				 * successfully handed over to the HAL,
				 * don't free it (it will get freed
				 * later in the callback).
				 */
				TNF_PROBE_3(
				    s1394_br_thread_handle_cmd_phase1,
				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
				    msg, "unable to re-read", tnf_uint,
				    node_num, node_num, tnf_int, quad_to_read,
				    quadlet);
				if ((status & S1394_CMD_INFLIGHT) != 0) {
					freecmd = 0;
				}
				if ((status & S1394_LOCK_FAILED) != 0) {
					locked = 0;
				} else {
					if (CFGROM_NEW_ALLOC(node) == B_TRUE) {
						s1394_free_cfgrom(hal, node,
						    S1394_FREE_CFGROM_NEW);
					} else {
						CLEAR_CFGROM_STATE(node);
					}
				}
			} else {
				done = 0;
				freecmd = 0;
			}
		} else {
			TNF_PROBE_4(s1394_br_thread_handle_cmd_phase1,
			    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
			    "retries exceeded", tnf_int, node_num, node_num,
			    tnf_int, quadlet, quadlet, tnf_opaque, cfgrom,
			    node->cfgrom);
			if (CFGROM_NEW_ALLOC(node) == B_TRUE) {
				s1394_free_cfgrom(hal, node,
				    S1394_FREE_CFGROM_NEW);
			} else {
				CLEAR_CFGROM_STATE(node);
			}
		}
	}
bail:
	if (freecmd) {
		(void) s1394_free_cmd(hal, &cmd);
	}

	if (done) {
		cmdret = S1394_HCMD_NODE_DONE;
		TNF_PROBE_2_DEBUG(s1394_br_thread_handle_cmd_phase1,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
		    "done with node", tnf_int, node_num, node_num);
	}

	/* if we are bailing out because locking failed, locked == 0 */
	if (locked == 0)
		cmdret = S1394_HCMD_LOCK_FAILED;
	else
		s1394_unlock_tree(hal);

	TNF_PROBE_0_DEBUG(s1394_br_thread_handle_cmd_phase1_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	return (cmdret);
}

/*
 * s1394_cfgrom_scan_phase2()
 *    Handles phase 2 of bus reset processing. Matches GUIDs between old
 *    and new topology trees to identify which node moved where. Processes
 *    the old topology tree (involves offlining any nodes that got unplugged
 *    between the last generation and the current generation). Updates speed
 *    map, sets up physical AR request filer and does isoch resource
 *    realloc failure notification and bus reset notifications. Then resends
 *    any commands that were issued by targets while the reset was being
 *    processed. Finally, the current topology tree is processed. This involves
 *    reading config rom past the bus info block for new nodes and parsing
 *    the config rom, creating a devinfo for each unit directory found in the
 *    config rom.
 *    Returns DDI_FAILURE if there was bus reset during any of the function
 *    calls (as indicated by lock failures) or if any of the routines callees
 *    return failure, else returns DDI_SUCCESS.
 */
static int
s1394_cfgrom_scan_phase2(s1394_hal_t *hal)
{
	int ret;
	uint_t wait_gen;
	int wait_for_cbs = 0;
	t1394_localinfo_t localinfo;

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase2_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase2_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	if (s1394_match_all_GUIDs(hal) == DDI_SUCCESS) {
		s1394_unlock_tree(hal);
	}

	if (s1394_process_old_tree(hal) != DDI_SUCCESS) {
		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
		TNF_PROBE_1(s1394_cfgrom_scan_phase2,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "non-success return from process_old_tree");
		TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase2_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		TNF_PROBE_1(s1394_cfgrom_scan_phase2,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "unable to relock the tree");
		TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase2_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	s1394_update_speed_map_link_speeds(hal);
	s1394_unlock_tree(hal);

	/* Setup physical AR request filters */
	s1394_physical_arreq_setup_all(hal);

	/* Notify targets of isoch resource realloc failures */
	s1394_isoch_rsrc_realloc_notify(hal);

	/* Notify targets of the end of bus reset processing */
	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		TNF_PROBE_1(s1394_cfgrom_scan_phase2,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "unable to relock the tree after isoch notify");
		TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase2_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	localinfo.bus_generation = hal->generation_count;
	localinfo.local_nodeID = hal->node_id;

	s1394_unlock_tree(hal);
	s1394_target_bus_reset_notifies(hal, &localinfo);
	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		TNF_PROBE_1(s1394_cfgrom_scan_phase2,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "unable to relock the tree after reset notify");
		TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase2_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	/* Set HAL state to normal */
	if (hal->disable_requests_bit == 0)
		hal->hal_state = S1394_HAL_NORMAL;
	else
		hal->hal_state = S1394_HAL_DREQ;

	s1394_unlock_tree(hal);

	/* Flush the pending Q */
	s1394_resend_pending_cmds(hal);

	if (s1394_process_topology_tree(hal, &wait_for_cbs, &wait_gen)) {
		TNF_PROBE_1(s1394_cfgrom_scan_phase2,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "non-success return from process_topology_tree");
		TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase2_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
		return (DDI_FAILURE);
	}

	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		TNF_PROBE_1(s1394_cfgrom_scan_phase2,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "unable to relock after processing topology tree");
		TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase2_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	s1394_print_node_info(hal);

	s1394_unlock_tree(hal);

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	ret = DDI_SUCCESS;

	/*
	 * If we started any reads, wait for completion callbacks
	 */
	if (wait_for_cbs != 0) {
		ret = s1394_wait_for_cfgrom_callbacks(hal, wait_gen,
		    s1394_br_thread_handle_cmd_phase2);

		TNF_PROBE_2_DEBUG(s1394_cfgrom_scan_phase2,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
		    "returned from waiting for cfgrom callbacks", tnf_int, ret,
		    ret);
	}

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_0_DEBUG(s1394_cfgrom_scan_phase2_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	return (ret);
}

/*
 * s1394_br_thread_handle_cmd_phase2()
 *    Process the cmd completion for phase 2 config rom reads. If all the
 *    needed quads are read, validates the config rom; if config rom is
 *    invalid (crc failures), frees the config rom, else marks the config rom
 *    valid and calls s1394_update_devinfo_tree() to parse the config rom.
 *    If need to get more quadlets, attempts to kick off the read and returns
 *    S1394_HCMD_NODE_EXPECT_MORE if successfully started the read. If a bus
 *    reset is seen while in this routine, returns S1394_HCMD_LOCK_FAILED. If
 *    done with the node (with or withoug crc errors), returns
 *    S1394_HCMD_NODE_DONE, else returns S1394_HCMD_NODE_EXPECT_MORE (to
 *    indicate not done with the node yet).
 */
static hcmd_ret_t
s1394_br_thread_handle_cmd_phase2(s1394_hal_t *hal, cmd1394_cmd_t *cmd)
{
	s1394_node_t *node;
	uint32_t node_num, quadlet, data;
	int update_devinfo, locked, freecmd, done;
	hcmd_ret_t cmdret;
	uchar_t readdelay;
	s1394_status_t status;

	TNF_PROBE_0_DEBUG(s1394_br_thread_handle_cmd_phase2_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	/*
	 * we end up here if this is a brand new node or if it is a known node
	 * but the config ROM changed (and triggered a re-read).
	 */
	s1394_get_quad_info(cmd, &node_num, &quadlet, &data);
	ASSERT(quadlet == IEEE1394_BIB_QUAD_SZ || quadlet <
	    IEEE1394_CONFIG_ROM_QUAD_SZ);

	locked = freecmd = done = 1;
	cmdret = S1394_HCMD_NODE_EXPECT_MORE;

	update_devinfo = 0;

	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		TNF_PROBE_3(s1394_br_thread_handle_cmd_phase2,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "unable to lock tree", tnf_int, node_num, node_num,
		    tnf_int, quadlet, quadlet);
		locked = 0;
		goto bail;
	}

	node = &hal->topology_tree[node_num];

	if (cmd->cmd_result == CMD1394_CMDSUCCESS) {

		ASSERT(CFGROM_BIB_READ(node) == B_TRUE);

		node->cfgrom[quadlet] = data;

		if (s1394_calc_next_quad(hal, node, quadlet, &quadlet) != 0) {
			/*
			 * Done with this node. Mark config rom valid and
			 * update the devinfo tree for this node.
			 */
			TNF_PROBE_4_DEBUG(s1394_br_thread_handle_cmd_phase2,
			    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
			    "all read", tnf_int, node_num, node->node_num,
			    tnf_opaque, cfgrom, node->cfgrom, tnf_int, quadlet,
			    quadlet);

			node->cfgrom_valid_size = quadlet + 1;
			if (s1394_valid_cfgrom(hal, node) == B_TRUE) {
				SET_CFGROM_ALL_READ(node);
				update_devinfo++;
			} else {
				s1394_free_cfgrom(hal, node,
				    S1394_FREE_CFGROM_BOTH);
			}
		} else {
			CFGROM_GET_READ_DELAY(node, readdelay);
			SETUP_QUAD_READ(node, 1, quadlet, 1);
			s1394_unlock_tree(hal);
			CFGROM_READ_PAUSE(readdelay);
			if (s1394_lock_tree(hal) != DDI_SUCCESS) {
				locked = 0;
				TNF_PROBE_3(s1394_br_thread_handle_cmd_phase2,
				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
				    msg, "unable to relock the tree",
				    tnf_int, node_num, node->node_num,
				    tnf_int, quadlet, quadlet);
			} else if (s1394_read_config_quadlet(hal, cmd,
			    &status) != DDI_SUCCESS) {
				/* give up on this guy */
				TNF_PROBE_3(s1394_br_thread_handle_cmd_phase2,
				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
				    msg, "cannot start quadlet read", tnf_int,
				    node_num, node_num, tnf_int, quadlet,
				    quadlet);

				if ((status & S1394_CMD_INFLIGHT) != 0) {
					freecmd = 0;
				}
				if ((status & S1394_LOCK_FAILED) != 0) {
					locked = 0;
				} else {
					node->cfgrom_valid_size = quadlet;
					if (s1394_valid_cfgrom(hal, node) ==
					    B_TRUE) {
						SET_CFGROM_ALL_READ(node);
						update_devinfo++;
					} else {
						s1394_free_cfgrom(hal, node,
						    S1394_FREE_CFGROM_BOTH);
					}
				}
			} else {
				/* successfully started next read */
				done = 0;
				freecmd = 0;
			}
		}
	} else {
		node->cfgrom_read_fails++;
		BUMP_CFGROM_READ_DELAY(node);

		/* retry if not too many failures */
		if (node->cfgrom_read_fails < s1394_cfgrom_read_retry_cnt) {
			CFGROM_GET_READ_DELAY(node, readdelay);
			s1394_unlock_tree(hal);
			SETUP_QUAD_READ(node, 0, quadlet, 1);
			CFGROM_READ_PAUSE(readdelay);
			if (s1394_lock_tree(hal) != DDI_SUCCESS) {
				locked = 0;
				TNF_PROBE_3(s1394_br_thread_handle_cmd_phase2,
				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
				    msg, "unable to relock for reread",
				    tnf_int, node_num, node->node_num,
				    tnf_int, quadlet, quadlet);
			} else if (s1394_read_config_quadlet(hal, cmd,
			    &status) != DDI_SUCCESS) {
				if ((status & S1394_CMD_INFLIGHT) != 0) {
					freecmd = 0;
				}
				if ((status & S1394_LOCK_FAILED) != 0) {
					locked = 0;
				} else {
					/* stop further reads */
					TNF_PROBE_4(
					    s1394_br_thread_handle_cmd_phase2,
					    S1394_TNF_SL_HOTPLUG_ERROR, "",
					    tnf_string, msg, "unable to retry",
					    tnf_int, node_num, node->node_num,
					    tnf_int, quadlet, quadlet,
					    tnf_opaque, cfgrom, node->cfgrom);
					node->cfgrom_valid_size = quadlet + 1;
					if (s1394_valid_cfgrom(hal, node) ==
					    B_TRUE) {
						SET_CFGROM_ALL_READ(node);
						update_devinfo++;
					} else {
						s1394_free_cfgrom(hal, node,
						    S1394_FREE_CFGROM_BOTH);
					}
				}
			} else {
				/* successfully started next read */
				done = 0;
				freecmd = 0;
			}
		} else {

			TNF_PROBE_4(s1394_br_thread_handle_cmd_phase2,
			    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
			    "retries exceeded", tnf_int, node_num, node_num,
			    tnf_int, quadlet, quadlet, tnf_opaque, cfgrom,
			    node->cfgrom);

			node->cfgrom_valid_size = quadlet + 1;
			if (s1394_valid_cfgrom(hal, node) == B_TRUE) {
				SET_CFGROM_ALL_READ(node);
				update_devinfo++;
			} else {
				s1394_free_cfgrom(hal, node,
				    S1394_FREE_CFGROM_BOTH);
			}
		}
	}
bail:
	if (freecmd) {
		(void) s1394_free_cmd(hal, &cmd);
	}

	if (done) {
		cmdret = S1394_HCMD_NODE_DONE;
		TNF_PROBE_2_DEBUG(s1394_br_thread_handle_cmd_phase2,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
		    "done with a node", tnf_int, node_num, node_num);
	}

	if (update_devinfo) {
		ASSERT(locked);
		/*
		 * s1394_update_devinfo_tree() drops and reacquires the
		 * topology_tree_mutex. If tree lock fails, it returns
		 * a DDI_FAILURE. Set locked to 0 so in this case so that
		 * we will return S1394_HCMD_LOCK_FAILED below
		 */
		if (s1394_update_devinfo_tree(hal, node) != DDI_SUCCESS) {
			ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
			locked = 0;
			TNF_PROBE_2(s1394_br_thread_handle_cmd_phase2,
			    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
			    "update devinfo returned failure", tnf_int,
			    node_num, node_num);
		}
	}

	/* if we are bailing out because locking failed, locked == 0 */
	if (locked == 0)
		cmdret = S1394_HCMD_LOCK_FAILED;
	else
		s1394_unlock_tree(hal);

	TNF_PROBE_1_DEBUG(s1394_br_thread_handle_cmd_phase2_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, cmdret, (int)cmdret);

	return (cmdret);
}

/*
 * s1394_read_config_quadlet()
 *    Starts the reads of a config quadlet (deduced cmd_addr).  Returns
 *    DDI_SUCCESS if the read was started with no errors, else DDI_FAILURE
 *    is returned, with status indicating the reason for the failure(s).
 */
static int
s1394_read_config_quadlet(s1394_hal_t *hal, cmd1394_cmd_t *cmd,
    s1394_status_t *status)
{
	s1394_node_t *node;
	int ret, err, node_num, quadlet;

	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
	node_num = IEEE1394_ADDR_PHY_ID(cmd->cmd_addr);
	node = &hal->topology_tree[node_num];
	quadlet = node->cfgrom_quad_to_read;

	TNF_PROBE_2_DEBUG(s1394_read_config_quadlet_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, node_num, node_num,
	    tnf_uint, quadlet, quadlet);

	/* Calculate the 64-bit address */
	QUAD_TO_CFGROM_ADDR(IEEE1394_LOCAL_BUS, node_num, quadlet,
	    cmd->cmd_addr);

	*status = S1394_NOSTATUS;

	ret = s1394_setup_asynch_command(hal, NULL, cmd, S1394_CMD_READ, &err);

	if (ret != DDI_SUCCESS) {
		*status |= S1394_UNKNOWN;
		ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
		TNF_PROBE_3(s1394_read_config_quadlet,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "failure from setup asynch command", tnf_uint, node_num,
		    node_num, tnf_uint, quadlet, quadlet);
		TNF_PROBE_0_DEBUG(s1394_read_config_quadlet_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (DDI_FAILURE);
	}

	s1394_unlock_tree(hal);
	ret = DDI_SUCCESS;
	/* Send the command out */
	if (s1394_xfer_asynch_command(hal, cmd, &err) == DDI_SUCCESS) {
		/* Callers can expect a callback now */
		*status |= S1394_CMD_INFLIGHT;
	} else {

		s1394_cmd_priv_t *s_priv;

		TNF_PROBE_3(s1394_read_config_quadlet,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "failure from xfer asynch command",
		    tnf_int, quadlet, quadlet, tnf_int, node_num, node_num);

		/* Remove from queue */
		s1394_remove_q_asynch_cmd(hal, cmd);
		s_priv = S1394_GET_CMD_PRIV(cmd);

		s_priv->cmd_in_use = B_FALSE;

		*status |= S1394_XFER_FAILED;
		ret = DDI_FAILURE;
	}

	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		*status |= S1394_LOCK_FAILED;
		ret = DDI_FAILURE;
		TNF_PROBE_1(s1394_read_config_quadlet,
		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
		    "unable to relock the tree");
	}

	TNF_PROBE_0_DEBUG(s1394_read_config_quadlet_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	return (ret);
}

/*
 * s1394_cfgrom_read_callback()
 *    callback routine for config rom reads. Frees the command if it failed
 *    due to bus reset else appends the command to the completion queue
 *    and signals the completion queue cv.
 */
static void
s1394_cfgrom_read_callback(cmd1394_cmd_t *cmd)
{
	cmd1394_cmd_t *tcmd;
	s1394_cmd_priv_t *s_priv;
	s1394_hal_t *hal;

#if defined(DEBUG)
	uint32_t node_num, quadlet, data;
#endif

	TNF_PROBE_0_DEBUG(s1394_cfgrom_read_callback_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	/* Get the Services Layer private area */
	s_priv = S1394_GET_CMD_PRIV(cmd);

	hal = (s1394_hal_t *)s_priv->sent_on_hal;

#if defined(DEBUG)

	s1394_get_quad_info(cmd, &node_num, &quadlet, &data);

	TNF_PROBE_5_DEBUG(s1394_cfgrom_read_callback,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, gen, cmd->bus_generation,
	    tnf_int, quadlet, quadlet,
	    tnf_int, node_num, node_num,
	    tnf_int, data, data, tnf_int, result, cmd->cmd_result);
#endif

	if (cmd->cmd_result == CMD1394_EBUSRESET) {
		(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
	} else {
		mutex_enter(&hal->br_cmplq_mutex);

		/* Put the command on completion queue */
		s_priv->cmd_priv_next = NULL;
		if ((tcmd = hal->br_cmplq_tail) != NULL) {
			s_priv = S1394_GET_CMD_PRIV(tcmd);

			s_priv->cmd_priv_next = cmd;
		}

		hal->br_cmplq_tail = cmd;

		if (hal->br_cmplq_head == NULL)
			hal->br_cmplq_head = cmd;

		cv_signal(&hal->br_cmplq_cv);
		mutex_exit(&hal->br_cmplq_mutex);
	}

	TNF_PROBE_0_DEBUG(s1394_cfgrom_read_callback_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");
}

/*
 * s1394_cfgrom_parse_unit_dir()
 *    Parses the unit directory passed in and returns reg[2...5] of reg
 *    property (see 1275 binding for reg property defintion). Currently,
 *    returns 0 for all the values since none of the existing devices implement
 *    this and future devices, per P1212r, need a binding change.
 */
/* ARGSUSED */
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)
{
	TNF_PROBE_0_DEBUG(s1394_cfgrom_parse_unit_dir_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");
	*addr_hi = *addr_lo = *size_hi = *size_lo = 0;
	TNF_PROBE_0_DEBUG(s1394_cfgrom_parse_unit_dir_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");
}

/*
 * s1394_get_quad_info()
 *    Helper routine that picks apart the various fields of a 1394 address
 */
static void
s1394_get_quad_info(cmd1394_cmd_t *cmd, uint32_t *node_num, uint32_t *quadlet,
    uint32_t *data)
{
	uint64_t addr;

	TNF_PROBE_0_DEBUG(s1394_get_quad_info_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	addr = cmd->cmd_addr;
	*node_num = IEEE1394_ADDR_PHY_ID(addr);
	*quadlet = ((addr & IEEE1394_ADDR_OFFSET_MASK) -
	    IEEE1394_CONFIG_ROM_ADDR);
	*quadlet = (*quadlet >> 2);
	*data = T1394_DATA32(cmd->cmd_u.q.quadlet_data);

	TNF_PROBE_0_DEBUG(s1394_get_quad_info_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");
}

/*
 * s1394_match_GUID()
 *    attempts to match nnode (which is in the current topology tree) with
 *    a node in the old topology tree by comparing GUIDs. If a match is found
 *    the old_node field of the current node and cur_node field of the old
 *    are set point to each other. Also, this routine makes both the nodes
 *    point at the same config rom.  If unable to relock the tree, returns
 *    DDI_FAILURE, else returns DDI_SUCCESS.
 */
static int
s1394_match_GUID(s1394_hal_t *hal, s1394_node_t *nnode)
{
	int old_node;
	int gen_changed;
	uint32_t old_a, old_b;
	uint32_t new_a, new_b;
	s1394_node_t *onode;
	s1394_target_t *t;
	int	ret = DDI_SUCCESS;

	TNF_PROBE_0_DEBUG(s1394_match_GUID_enter, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

	ASSERT(nnode->cfgrom != NULL);
	ASSERT(CFGROM_BIB_READ(nnode));

	new_a = nnode->node_guid_hi;
	new_b = nnode->node_guid_lo;

	for (old_node = 0; old_node < hal->old_number_of_nodes; old_node++) {

		onode = &hal->old_tree[old_node];
		if (onode->cfgrom == NULL || CFGROM_BIB_READ(onode) == B_FALSE)
			continue;

		old_a = onode->node_guid_hi;
		old_b = onode->node_guid_lo;

		if ((old_a == new_a) && (old_b == new_b)) {

			if (NODE_MATCHED(onode) == B_TRUE) {
				TNF_PROBE_4(s1394_match_GUID_duplicate,
				    S1394_TNF_SL_HOTPLUG_ERROR, "",
				    tnf_uint, guid_hi, old_a,
				    tnf_uint, guid_lo, old_b,
				    tnf_uint, old_node_num, old_node,
				    tnf_uint, node_num, nnode->node_num);
				cmn_err(CE_NOTE, "!Duplicate GUIDs: %08x%08x",
				    old_a, old_b);
				/* offline the new node that last matched */
				ret = s1394_offline_node(hal, onode->cur_node);
				/* and make the current new node invalid */
				ASSERT(CFGROM_NEW_ALLOC(nnode) == B_TRUE);
				s1394_free_cfgrom(hal, nnode,
				    S1394_FREE_CFGROM_NEW);
				break;
			}

			/*
			 * If there is indeed a cfgrom gen change,
			 * CFGROM_GEN_CHANGED() will be set iff we are matching
			 * tree nodes. Otherwise, CONFIG_ROM_GEN(old) !=
			 * CONFIG_ROM_GEN(new).
			 */
			if (CFGROM_GEN_CHANGED(nnode) == B_TRUE ||
			    (CONFIG_ROM_GEN(onode->cfgrom) !=
			    CONFIG_ROM_GEN(nnode->cfgrom))) {
				gen_changed = 1;
				TNF_PROBE_4_DEBUG(s1394_match_GUID_gen_change,
				    S1394_TNF_SL_HOTPLUG_STACK, "",
				    tnf_opaque, old_cfgrom, onode->cfgrom,
				    tnf_int, old_gen,
				    CONFIG_ROM_GEN(onode->cfgrom), tnf_opaque,
				    cfgrom, nnode->cfgrom, tnf_int, new_gen,
				    CONFIG_ROM_GEN(nnode->cfgrom));
			} else {
				gen_changed = 0;
			}

			onode->cur_node = nnode;
			nnode->old_node = onode;
			nnode->node_state = onode->node_state;
			SET_NODE_VISITED(onode);
			SET_NODE_MATCHED(onode);
			SET_NODE_MATCHED(nnode);
			/*
			 * If generations changed, need to offline any targets
			 * hanging off the old node, prior to freeing up old
			 * cfgrom. If the generations didn't change, we can
			 * free up the new config rom and copy all info from
			 * the old node (this helps in picking up further
			 * reads from where the last generation left off).
			 */
			if (gen_changed == 1) {
				if (s1394_offline_node(hal, onode)) {
					ret = DDI_FAILURE;
					break;
				}
				TNF_PROBE_2(s1394_match_GUID_gen_freecfg,
				    S1394_TNF_SL_HOTPLUG_STACK, "",
				    tnf_opaque, old_cfgrom, onode->cfgrom,
				    tnf_opaque, new_cfgrom, nnode->cfgrom);
				s1394_free_cfgrom(hal, onode,
				    S1394_FREE_CFGROM_OLD);
				CLEAR_CFGROM_PARSED(nnode);
				CLEAR_CFGROM_NEW_ALLOC(nnode);
				CLEAR_CFGROM_NEW_ALLOC(onode);
				onode->cfgrom = nnode->cfgrom;
				/* done */
				break;
			}

			/*
			 * Free up cfgrom memory in the new_node and
			 * point it at the same config rom as the old one.
			 */
			if (onode->cfgrom != nnode->cfgrom) {

				TNF_PROBE_5_DEBUG(s1394_match_GUID,
				    S1394_TNF_SL_HOTPLUG_STACK, "",
				    tnf_int, node_num, nnode->node_num,
				    tnf_opaque, cfgrom, nnode->cfgrom,
				    tnf_int, old_node_num, old_node,
				    tnf_opaque, old_cfgrom, onode->cfgrom,
				    tnf_uint, cfgrom_state,
				    nnode->cfgrom_state);

				ASSERT(CFGROM_NEW_ALLOC(nnode) == B_TRUE);
				s1394_free_cfgrom(hal, nnode,
				    S1394_FREE_CFGROM_NEW);
			}
			nnode->cfgrom = onode->cfgrom;
			nnode->cfgrom_state = onode->cfgrom_state;
			nnode->cfgrom_valid_size = onode->cfgrom_valid_size;
			nnode->cfgrom_size = onode->cfgrom_size;
			nnode->cfgrom_quad_to_read = onode->cfgrom_quad_to_read;
			bcopy(onode->dir_stack, nnode->dir_stack,
			    offsetof(s1394_node_t, cfgrom_quad_to_read) -
			    offsetof(s1394_node_t, dir_stack));
			CLEAR_CFGROM_NEW_ALLOC(nnode);
			CLEAR_CFGROM_NEW_ALLOC(onode);

			if (CFGROM_PARSED(nnode) == B_TRUE) {
				rw_enter(&hal->target_list_rwlock, RW_WRITER);
				/* Update the target list */
				if ((t = onode->target_list) != NULL) {
					nnode->target_list = t;
					while (t != NULL) {
						t->on_node = nnode;
						t = t->target_sibling;
					}
				}
				rw_exit(&hal->target_list_rwlock);
			}
			break;
		}
	}

	TNF_PROBE_0_DEBUG(s1394_match_GUID_exit, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

	return (ret);
}

/*
 * s1394_match_all_GUIDs()
 *    attempt to match each node in the current topology tree with the a
 *    node in the old topology tree.  If unable to relock the tree, returns
 *    DDI_FAILURE, else returns DDI_SUCCESS.
 */
static int
s1394_match_all_GUIDs(s1394_hal_t *hal)
{
	int node;
	int ret = DDI_SUCCESS;
	s1394_node_t *nnode;

	TNF_PROBE_0_DEBUG(s1394_match_all_GUIDs_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));

	for (node = 0; node < hal->number_of_nodes; node++) {
		nnode = &hal->topology_tree[node];
		if (LINK_ACTIVE(nnode) == B_FALSE || CFGROM_BIB_READ(nnode) ==
		    B_FALSE)
			continue;
		if (NODE_MATCHED(nnode)) {
			/*
			 * Skip if node matched. If config rom generations
			 * changed, we want to call s1394_match_GUID() even
			 * if the nodes matched.
			 */
			int gen_changed;
			s1394_node_t *onode = nnode->old_node;

			gen_changed = (onode && onode->cfgrom &&
			    CONFIG_ROM_GEN(onode->cfgrom) != CONFIG_ROM_GEN(
			    nnode->cfgrom)) ? 1 : 0;

			if (CFGROM_GEN_CHANGED(nnode) == 0 && gen_changed == 0)
				continue;
		}

		if (s1394_match_GUID(hal, nnode) == DDI_FAILURE) {
			ret = DDI_FAILURE;
		}
	}

	TNF_PROBE_0_DEBUG(s1394_match_all_GUIDs_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	return (ret);
}

/*
 * s1394_valid_cfgrom()
 *    Performs crc check on the config rom. Returns B_TRUE if config rom has
 *    good CRC else returns B_FALSE.
 */
/* ARGSUSED */
boolean_t
s1394_valid_cfgrom(s1394_hal_t *hal, s1394_node_t *node)
{
	uint32_t crc_len, crc_value, CRC, CRC_old, quad0;

	TNF_PROBE_0_DEBUG(s1394_valid_cfgrom_enter, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
	ASSERT(node->cfgrom);

	if (s1394_enable_crc_validation == 0) {
		TNF_PROBE_1_DEBUG(s1394_valid_cfgrom_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
		    "validation turned off");
		return (B_TRUE);
	}

	quad0 = node->cfgrom[0];
	crc_len = (quad0 >> IEEE1394_CFG_ROM_CRC_LEN_SHIFT) &
	    IEEE1394_CFG_ROM_CRC_LEN_MASK;
	crc_value = quad0 & IEEE1394_CFG_ROM_CRC_VALUE_MASK;

	if (node->cfgrom_valid_size < crc_len + 1) {
		TNF_PROBE_4(s1394_valid_cfgrom_not_enough,
		    S1394_TNF_SL_HOTPLUG_ERROR, "",
		    tnf_uint, node_guid_hi, node->node_guid_hi,
		    tnf_uint, node_guid_lo, node->node_guid_lo,
		    tnf_uint, crc_len, crc_len,
		    tnf_uint, valid_size, node->cfgrom_valid_size);
		TNF_PROBE_0_DEBUG(s1394_valid_cfgrom_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (B_FALSE);
	}

	CRC = s1394_CRC16(&node->cfgrom[1], crc_len);

	if (CRC != crc_value) {
		CRC_old = s1394_CRC16_old(&node->cfgrom[1], crc_len);
		if (CRC_old == crc_value) {
			TNF_PROBE_4_DEBUG(s1394_valid_cfgrom_busted_crc,
			    S1394_TNF_SL_HOTPLUG_ERROR, "",
			    tnf_uint, node_guid_hi, node->node_guid_hi,
			    tnf_uint, node_guid_lo, node->node_guid_lo,
			    tnf_uint, node_num, node->node_num,
			    tnf_uint, crc_len, crc_len);
			TNF_PROBE_0_DEBUG(s1394_valid_cfgrom_exit,
			    S1394_TNF_SL_HOTPLUG_STACK, "");
			return (B_TRUE);
		}

		cmn_err(CE_NOTE,
		    "!Bad CRC in config rom (node's GUID %08x%08x)",
		    node->node_guid_hi, node->node_guid_lo);

		TNF_PROBE_5(s1394_valid_cfgrom_bad_crc,
		    S1394_TNF_SL_HOTPLUG_ERROR, "",
		    tnf_uint, node_guid_hi, node->node_guid_hi,
		    tnf_uint, node_guid_lo, node->node_guid_lo,
		    tnf_uint, crc_len, crc_len,
		    tnf_uint, crc, crc_value, tnf_uint, crc_computed, CRC);
		TNF_PROBE_0_DEBUG(s1394_valid_cfgrom_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (B_FALSE);
	}

	TNF_PROBE_3_DEBUG(s1394_valid_cfgrom_exit, S1394_TNF_SL_HOTPLUG_STACK,
	    "", tnf_uint, node_num, node->node_num, tnf_uint, crc_len, crc_len,
	    tnf_uint, crc, crc_value);

	return (B_TRUE);
}

/*
 * s1394_valid_dir()
 *    Performs crc check on a directory.  Returns B_TRUE if dir has good CRC
 *    else returns B_FALSE.
 */
/*ARGSUSED*/
boolean_t
s1394_valid_dir(s1394_hal_t *hal, s1394_node_t *node,
    uint32_t key, uint32_t *dir)
{
	uint32_t dir_len, crc_value, CRC, CRC_old, quad0;

	TNF_PROBE_0_DEBUG(s1394_valid_dir_enter, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

	/*
	 * Ideally, we would like to do crc validations for the entire cfgrom
	 * as well as the individual directories. However, we have seen devices
	 * that have valid directories but busted cfgrom crc and devices that
	 * have bad crcs in directories as well as for the entire cfgrom. This
	 * is sad, but unfortunately, real world!
	 */
	if (s1394_enable_crc_validation == 0) {
		TNF_PROBE_1_DEBUG(s1394_valid_dir_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
		    "validation turned off");
		return (B_TRUE);
	}

	quad0 = dir[0];

	dir_len = IEEE1212_DIR_LEN(quad0);
	crc_value = IEEE1212_DIR_CRC(quad0);

	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));

	CRC = s1394_CRC16(&dir[1], dir_len);

	if (CRC != crc_value) {
		CRC_old = s1394_CRC16_old(&dir[1], dir_len);
		if (CRC_old == crc_value) {
			TNF_PROBE_5_DEBUG(s1394_valid_dir_crc_old,
			    S1394_TNF_SL_HOTPLUG_STACK, "",
			    tnf_uint, node_guid_hi, node->node_guid_hi,
			    tnf_uint, node_guid_lo, node->node_guid_lo,
			    tnf_uint, node_num, node->node_num,
			    tnf_uint, key, key, tnf_uint, dir_len, dir_len);
			TNF_PROBE_0_DEBUG(s1394_valid_dir_exit,
			    S1394_TNF_SL_HOTPLUG_STACK, "");
			return (B_TRUE);
		}

		TNF_PROBE_5(s1394_valid_dir_bad_crc,
		    S1394_TNF_SL_HOTPLUG_STACK, "",
		    tnf_uint, node_guid_hi, node->node_guid_hi,
		    tnf_uint, node_guid_lo, node->node_guid_lo,
		    tnf_uint, node_num, node->node_num,
		    tnf_uint, key, key, tnf_uint, dir_len, dir_len);

		TNF_PROBE_0_DEBUG(s1394_valid_dir_exit,
			    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (B_FALSE);
	}

	TNF_PROBE_4_DEBUG(s1394_valid_dir,
	    S1394_TNF_SL_HOTPLUG_STACK, "",
	    tnf_uint, node_guid_hi, node->node_guid_hi,
	    tnf_uint, node_guid_lo, node->node_guid_lo,
	    tnf_uint, node_num, node->node_num, tnf_uint, key, key);

	return (B_TRUE);
}

/*
 * s1394_become_bus_mgr()
 *    is a callback from a timeout() setup by the main br_thread.  After
 *    a bus reset, depending on the Bus Manager's incumbancy and the state
 *    of its abdicate bit, a timer of a certain length is set.  After this
 *    time expires, the local host may attempt to become the Bus Manager.
 *    This is done by sending a request to the current IRM on the bus.  The
 *    IRM holds the BUS_MANAGER_ID register.  Depending on whether or not
 *    the local host is already the IRM, we will send a request onto the
 *    1394 bus or call into the HAL.
 */
static void
s1394_become_bus_mgr(void *arg)
{
	s1394_hal_t	 *hal;
	s1394_cmd_priv_t *s_priv;
	cmd1394_cmd_t	 *cmd;
	uint64_t	 Bus_Mgr_ID_addr;
	uint32_t	 hal_node_num;
	uint32_t	 old_value;
	uint32_t	 generation;
	uint_t		 curr_bus_mgr;
	uint_t		 bm_node;
	uint_t		 IRM_node;
	int		 err;
	int		 ret;

	TNF_PROBE_0_DEBUG(s1394_become_bus_mgr_enter, S1394_TNF_SL_BR_STACK,
	    "");

	hal = (s1394_hal_t *)arg;

	/* Lock the topology tree */
	mutex_enter(&hal->topology_tree_mutex);

	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
	generation   = hal->generation_count;
	IRM_node = hal->IRM_node;

	mutex_enter(&hal->bus_mgr_node_mutex);
	bm_node = hal->bus_mgr_node;
	mutex_exit(&hal->bus_mgr_node_mutex);

	/* Unlock the topology tree */
	mutex_exit(&hal->topology_tree_mutex);

	/* Make sure we aren't already the Bus Manager */
	if (bm_node != -1) {
		TNF_PROBE_0_DEBUG(s1394_become_bus_mgr_exit,
		    S1394_TNF_SL_BR_STACK, "");
		return;
	}

	/* Send compare-swap to BUS_MANAGER_ID */
	/* register on the Isoch Rsrc Mgr */
	if (IRM_node == hal_node_num) {
		/* Local */
		ret = HAL_CALL(hal).csr_cswap32(hal->halinfo.hal_private,
		    generation, (IEEE1394_SCSR_BUSMGR_ID &
		    IEEE1394_CSR_OFFSET_MASK), S1394_INVALID_NODE_NUM,
		    hal_node_num, &old_value);
		if (ret != DDI_SUCCESS) {
			TNF_PROBE_1(s1394_become_bus_mgr_error,
			    S1394_TNF_SL_BR_ERROR, "", tnf_string, msg,
			    "Error in cswap32");
			TNF_PROBE_0_DEBUG(s1394_become_bus_mgr_exit,
			    S1394_TNF_SL_BR_STACK, "");
			return;
		}
		curr_bus_mgr = IEEE1394_NODE_NUM(old_value);

		mutex_enter(&hal->bus_mgr_node_mutex);
		if ((curr_bus_mgr == S1394_INVALID_NODE_NUM) ||
		    (curr_bus_mgr == hal_node_num)) {
			hal->bus_mgr_node = hal_node_num;
			hal->incumbent_bus_mgr = B_TRUE;
		} else {
			hal->bus_mgr_node = curr_bus_mgr;
			hal->incumbent_bus_mgr = B_FALSE;
		}
		cv_signal(&hal->bus_mgr_node_cv);
		mutex_exit(&hal->bus_mgr_node_mutex);

	} else {
		/* Remote */
		if (s1394_alloc_cmd(hal, T1394_ALLOC_CMD_NOSLEEP, &cmd) !=
		    DDI_SUCCESS) {
			TNF_PROBE_1(s1394_become_bus_mgr_error,
			    S1394_TNF_SL_BR_ERROR, "", tnf_string, msg,
			    "Error in s1394_alloc_cmd()");
			TNF_PROBE_0_DEBUG(s1394_become_bus_mgr_exit,
			    S1394_TNF_SL_BR_STACK, "");
			return;
		}

		cmd->cmd_options	   = (CMD1394_CANCEL_ON_BUS_RESET |
		    CMD1394_OVERRIDE_ADDR);
		cmd->cmd_type		   = CMD1394_ASYNCH_LOCK_32;
		cmd->completion_callback   = s1394_become_bus_mgr_callback;
		Bus_Mgr_ID_addr		   = (IEEE1394_ADDR_BUS_ID_MASK |
		    IEEE1394_SCSR_BUSMGR_ID) |
		    (((uint64_t)hal->IRM_node) << IEEE1394_ADDR_PHY_ID_SHIFT);
		cmd->cmd_addr		   = Bus_Mgr_ID_addr;
		cmd->bus_generation	   = generation;
		cmd->cmd_u.l32.arg_value   = T1394_DATA32(
		    S1394_INVALID_NODE_NUM);
		cmd->cmd_u.l32.data_value  = T1394_DATA32(hal_node_num);
		cmd->cmd_u.l32.num_retries = 0;
		cmd->cmd_u.l32.lock_type   = CMD1394_LOCK_COMPARE_SWAP;

		/* Get the Services Layer private area */
		s_priv = S1394_GET_CMD_PRIV(cmd);

		/* Lock the topology tree */
		mutex_enter(&hal->topology_tree_mutex);

		ret = s1394_setup_asynch_command(hal, NULL, cmd,
		    S1394_CMD_LOCK, &err);

		/* Unlock the topology tree */
		mutex_exit(&hal->topology_tree_mutex);

		/* Command has now been put onto the queue! */
		if (ret != DDI_SUCCESS) {
			/* Need to free the command */
			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
			TNF_PROBE_1(s1394_become_bus_mgr_error,
			    S1394_TNF_SL_BR_ERROR, "", tnf_string, msg,
			    "Error in s1394_setup_asynch_command()");
			TNF_PROBE_0_DEBUG(s1394_become_bus_mgr_exit,
			    S1394_TNF_SL_BR_STACK, "");
			return;
		}

		/* Send the command out */
		ret = s1394_xfer_asynch_command(hal, cmd, &err);

		if (ret != DDI_SUCCESS) {
			/* Remove cmd outstanding request Q */
			s1394_remove_q_asynch_cmd(hal, cmd);

			s_priv->cmd_in_use = B_FALSE;

			mutex_enter(&hal->bus_mgr_node_mutex);

			/* Don't know who the bus_mgr is */
			hal->bus_mgr_node = S1394_INVALID_NODE_NUM;
			hal->incumbent_bus_mgr = B_FALSE;

			cv_signal(&hal->bus_mgr_node_cv);
			mutex_exit(&hal->bus_mgr_node_mutex);

			/* Need to free the command */
			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
		}
	}

	TNF_PROBE_0_DEBUG(s1394_become_bus_mgr_exit, S1394_TNF_SL_BR_STACK,
	    "");
}

/*
 * s1394_become_bus_mgr_callback()
 *    is the callback used by s1394_become_bus_mgr() when it is necessary
 *    to send the Bus Manager request to a remote IRM.  After the completion
 *    of the compare-swap request, this routine looks at the "old_value"
 *    in the request to determine whether or not it has become the Bus
 *    Manager for the current generation.  It sets the bus_mgr_node and
 *    incumbent_bus_mgr fields to their appropriate values.
 */
static void
s1394_become_bus_mgr_callback(cmd1394_cmd_t *cmd)
{
	s1394_cmd_priv_t *s_priv;
	s1394_hal_t *hal;
	uint32_t hal_node_num;
	uint32_t temp;
	uint_t curr_bus_mgr;

	TNF_PROBE_0_DEBUG(s1394_become_bus_mgr_callback_enter,
	    S1394_TNF_SL_BR_STACK, "");

	/* Get the Services Layer private area */
	s_priv = S1394_GET_CMD_PRIV(cmd);

	hal = (s1394_hal_t *)s_priv->sent_on_hal;

	/* Lock the topology tree */
	mutex_enter(&hal->topology_tree_mutex);

	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);

	/* Was the command successful? */
	if (cmd->cmd_result == CMD1394_CMDSUCCESS) {
		temp = T1394_DATA32(cmd->cmd_u.l32.old_value);
		curr_bus_mgr = IEEE1394_NODE_NUM(temp);
		mutex_enter(&hal->bus_mgr_node_mutex);
		if ((curr_bus_mgr == S1394_INVALID_NODE_NUM) ||
		    (curr_bus_mgr == hal_node_num)) {

			hal->bus_mgr_node = hal_node_num;
			hal->incumbent_bus_mgr = B_TRUE;

		} else {
			hal->bus_mgr_node = curr_bus_mgr;
			hal->incumbent_bus_mgr = B_FALSE;
		}
		cv_signal(&hal->bus_mgr_node_cv);
		mutex_exit(&hal->bus_mgr_node_mutex);

	} else {
		TNF_PROBE_2(s1394_become_bus_mgr_callback_error,
		    S1394_TNF_SL_BR_ERROR, "", tnf_string, msg,
		    "Error while attempting to become bus manager",
		    tnf_uint, status, cmd->cmd_result);

		mutex_enter(&hal->bus_mgr_node_mutex);

		/* Don't know who the bus_mgr is */
		hal->bus_mgr_node = S1394_INVALID_NODE_NUM;
		hal->incumbent_bus_mgr = B_FALSE;

		cv_signal(&hal->bus_mgr_node_cv);
		mutex_exit(&hal->bus_mgr_node_mutex);
	}

	/* Need to free the command */
	(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);

	/* Unlock the topology tree */
	mutex_exit(&hal->topology_tree_mutex);

	TNF_PROBE_0_DEBUG(s1394_become_bus_mgr_callback_exit,
	    S1394_TNF_SL_BR_STACK, "");
}

/*
 * s1394_bus_mgr_processing()
 *    is called following "phase1" completion of reading Bus_Info_Blocks.
 *    Its purpose is to determine whether the local node is capable of
 *    becoming the Bus Manager (has the IRMC bit set) and if so to call
 *    the s1394_do_bus_mgr_processing() routine.
 *    NOTE: we overload DDI_FAILURE return value to mean jump back to
 *    the start of bus reset processing.
 */
static int
s1394_bus_mgr_processing(s1394_hal_t *hal)
{
	int ret;
	int IRM_node_num;

	TNF_PROBE_0_DEBUG(s1394_bus_mgr_processing_enter,
	    S1394_TNF_SL_BR_STACK, "");

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		return (DDI_FAILURE);
	}
	IRM_node_num = hal->IRM_node;
	s1394_unlock_tree(hal);

	ret = DDI_SUCCESS;

	/* If we are IRM capable, then do bus_mgr stuff... */
	if (hal->halinfo.bus_capabilities & IEEE1394_BIB_IRMC_MASK) {
		/* If there is an IRM, then do bus_mgr stuff */
		if (IRM_node_num != -1) {
			if (s1394_do_bus_mgr_processing(hal))
				ret = DDI_FAILURE;
		}
	}

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_0_DEBUG(s1394_bus_mgr_processing_exit,
	    S1394_TNF_SL_BR_STACK, "");
	return (ret);
}

/*
 * s1394_do_bus_mgr_processing()
 *    is used to perform those operations expected of the Bus Manager.
 *    After being called, s1394_do_bus_mgr_processing() looks at the value
 *    in bus_mgr_node and waits if it is -1 (Bus Manager has not been
 *    chosen yet).  Then, if there is more than one node on the 1394 bus,
 *    and we are either the Bus Manager or (if there is no Bus Manager)
 *    the IRM, it optimizes the gap_count and/or sets the cycle master's
 *    root holdoff bit (to ensure that the cycle master is/stays root).
 *
 *    NOTE: we overload DDI_FAILURE return value to mean jump back to
 *    the start of bus reset processing.
 */
static int
s1394_do_bus_mgr_processing(s1394_hal_t *hal)
{
	int	ret;
	int	IRM_flags, hal_bus_mgr_node;
	int	IRM_node_num;
	uint_t	hal_node_num, number_of_nodes;
	int	new_root, new_gap_cnt;

	TNF_PROBE_0_DEBUG(s1394_do_bus_mgr_processing_enter,
	    S1394_TNF_SL_BR_STACK, "");

	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	/* Wait for Bus Manager to be determined */
	/* or a Bus Reset to happen */
	mutex_enter(&hal->bus_mgr_node_mutex);
	if (hal->bus_mgr_node == -1)
		cv_wait(&hal->bus_mgr_node_cv, &hal->bus_mgr_node_mutex);

	/* Check if a BUS RESET has come while we've been waiting */
	mutex_enter(&hal->br_thread_mutex);
	if (hal->br_thread_ev_type & (BR_THR_CFGROM_SCAN | BR_THR_GO_AWAY)) {

		mutex_exit(&hal->br_thread_mutex);
		mutex_exit(&hal->bus_mgr_node_mutex);

		TNF_PROBE_0_DEBUG(s1394_do_bus_mgr_processing_exit,
		    S1394_TNF_SL_BR_STACK, "");
		return (1);
	}
	mutex_exit(&hal->br_thread_mutex);

	hal_bus_mgr_node = hal->bus_mgr_node;
	mutex_exit(&hal->bus_mgr_node_mutex);

	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
		return (1);
	}
	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
	IRM_node_num = hal->IRM_node;
	number_of_nodes = hal->number_of_nodes;

	ret = 0;

	/* If we are the bus_mgr or if there is no bus_mgr */
	/* the IRM and there is > 1 nodes on the bus */
	if ((number_of_nodes > 1) &&
	    ((hal_bus_mgr_node == (int)hal_node_num) ||
		((hal_bus_mgr_node == S1394_INVALID_NODE_NUM) &&
		    (IRM_node_num == (int)hal_node_num)))) {

		IRM_flags = 0;

		/* Make sure the root node is cycle master capable */
		if (!s1394_cycle_master_capable(hal)) {
			/* Make the local node root */
			new_root = hal_node_num;
			IRM_flags = IRM_flags | ROOT_HOLDOFF;

			/* If setting root, then optimize gap_count */
			new_gap_cnt = hal->optimum_gap_count;
			IRM_flags = IRM_flags | GAP_COUNT;

		} else {
			/* Make sure root's ROOT_HOLDOFF bit is set */
			new_root = (number_of_nodes - 1);
			IRM_flags = IRM_flags | ROOT_HOLDOFF;
		}
		if (hal->gap_count > hal->optimum_gap_count) {
			/* Set the gap_count to optimum */
			new_gap_cnt = hal->optimum_gap_count;
			IRM_flags = IRM_flags | GAP_COUNT;

		}

		s1394_unlock_tree(hal);

		if (IRM_flags) {
			ret = s1394_do_phy_config_pkt(hal, new_root,
			    new_gap_cnt, IRM_flags);
		}
		TNF_PROBE_0_DEBUG(s1394_do_bus_mgr_processing_exit,
		    S1394_TNF_SL_BR_STACK, "");
		return (ret);
	}

	s1394_unlock_tree(hal);

	TNF_PROBE_0_DEBUG(s1394_do_bus_mgr_processing_exit,
	    S1394_TNF_SL_BR_STACK, "");
	return (ret);
}

/*
 * s1394_bus_mgr_timers_stop()
 *    Cancels bus manager timeouts
 */
/*ARGSUSED*/
static void
s1394_bus_mgr_timers_stop(s1394_hal_t *hal, timeout_id_t *bus_mgr_query_tid,
    timeout_id_t *bus_mgr_tid)
{
	TNF_PROBE_0_DEBUG(s1394_bus_mgr_timers_stop_enter,
	    S1394_TNF_SL_BR_STACK, "");

	/* Cancel the Bus Mgr timeouts (if necessary) */
	if (*bus_mgr_tid != 0) {
		(void) untimeout(*bus_mgr_tid);
		*bus_mgr_tid = 0;
	}
	if (*bus_mgr_query_tid != 0) {
		(void) untimeout(*bus_mgr_query_tid);
		*bus_mgr_query_tid = 0;
	}

	TNF_PROBE_0_DEBUG(s1394_bus_mgr_timers_stop_exit,
	    S1394_TNF_SL_BR_STACK, "");
}

/*
 * s1394_bus_mgr_timers_start()
 *    Starts bus manager timeouts if the hal is IRM capable.
 */
static void
s1394_bus_mgr_timers_start(s1394_hal_t *hal, timeout_id_t *bus_mgr_query_tid,
    timeout_id_t *bus_mgr_tid)
{
	boolean_t incumbant;
	uint_t	  hal_node_num;
	int	  IRM_node_num;

	TNF_PROBE_0_DEBUG(s1394_bus_mgr_timers_start_enter,
	    S1394_TNF_SL_BR_STACK, "");

	mutex_enter(&hal->topology_tree_mutex);

	IRM_node_num = hal->IRM_node;
	hal_node_num = hal->node_id;

	mutex_enter(&hal->bus_mgr_node_mutex);
	incumbant = hal->incumbent_bus_mgr;
	mutex_exit(&hal->bus_mgr_node_mutex);

	/* If we are IRM capable, then do bus_mgr stuff... */
	if (hal->halinfo.bus_capabilities & IEEE1394_BIB_IRMC_MASK) {
		/*
		 * If we are the IRM, then wait 625ms
		 * before checking BUS_MANAGER_ID register
		 */
		if (IRM_node_num == IEEE1394_NODE_NUM(hal_node_num)) {

			TNF_PROBE_0_DEBUG(s1394_bus_mgr_timers_625ms,
			    S1394_TNF_SL_BR_STACK, "");

			mutex_exit(&hal->topology_tree_mutex);

			/* Wait 625ms, then check bus manager */
			*bus_mgr_query_tid = timeout(s1394_become_bus_mgr,
			    hal, drv_usectohz(IEEE1394_BM_IRM_TIMEOUT));

			mutex_enter(&hal->topology_tree_mutex);
		}

		/* If there is an IRM on the bus */
		if (IRM_node_num != -1) {
			if ((incumbant == B_TRUE) &&
			    (hal->abdicate_bus_mgr_bit == 0)) {
				mutex_exit(&hal->topology_tree_mutex);

				/* Try to become bus manager */
				s1394_become_bus_mgr(hal);

				mutex_enter(&hal->topology_tree_mutex);
			} else {
				hal->abdicate_bus_mgr_bit = 0;

				TNF_PROBE_0_DEBUG(s1394_bus_mgr_timers_125ms,
				    S1394_TNF_SL_BR_STACK, "");

				mutex_exit(&hal->topology_tree_mutex);

				/* Wait 125ms, then try to become bus manager */
				*bus_mgr_tid = timeout(s1394_become_bus_mgr,
				    hal, drv_usectohz(
					IEEE1394_BM_INCUMBENT_TIMEOUT));

				mutex_enter(&hal->topology_tree_mutex);
			}
		} else {
			mutex_enter(&hal->bus_mgr_node_mutex);
			hal->incumbent_bus_mgr = B_FALSE;
			mutex_exit(&hal->bus_mgr_node_mutex);
		}
	}

	mutex_exit(&hal->topology_tree_mutex);

	TNF_PROBE_0_DEBUG(s1394_bus_mgr_timers_start_exit,
	    S1394_TNF_SL_BR_STACK, "");
}

/*
 * s1394_get_maxpayload()
 *    is used to determine a device's maximum payload size.  That is to
 *    say, the largest packet that can be transmitted or received by the
 *    the target device given the current topological (speed) constraints
 *    and the constraints specified in the local host's and remote device's
 *    Config ROM (max_rec).  Caller must hold the topology_tree_mutex and
 *    the target_list_rwlock as an RW_READER (at least).
 */
/*ARGSUSED*/
void
s1394_get_maxpayload(s1394_target_t *target, uint_t *dev_max_payload,
    uint_t *current_max_payload)
{
	s1394_hal_t *hal;
	uint32_t bus_capabilities;
	uint32_t from_node;
	uint32_t to_node;
	uint_t local_max_rec;
	uint_t local_max_blk;
	uint_t max_rec;
	uint_t max_blk;
	uint_t curr_speed;
	uint_t speed_max_blk;
	uint_t temp;

	TNF_PROBE_0_DEBUG(s1394_get_maxpayload_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	/* Find the HAL this target resides on */
	hal = target->on_hal;

	/* Make sure we're holding the topology_tree_mutex */
	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));

	/* Set dev_max_payload to local (HAL's) size */
	bus_capabilities = target->on_hal->halinfo.bus_capabilities;
	local_max_rec = (bus_capabilities & IEEE1394_BIB_MAXREC_MASK) >>
	    IEEE1394_BIB_MAXREC_SHIFT;
	if ((local_max_rec > 0) && (local_max_rec < 14)) {
		local_max_blk = 1 << (local_max_rec + 1);
	} else {
		/* These are either unspecified or reserved */
		local_max_blk = 4;
	}

	/* Is this target on a node? */
	if ((target->target_state & S1394_TARG_GONE) == 0 &&
	    (target->on_node != NULL)) {
		ASSERT(target->on_node->cfgrom != NULL);

		bus_capabilities =
		    target->on_node->cfgrom[IEEE1212_NODE_CAP_QUAD];
		max_rec = (bus_capabilities & IEEE1394_BIB_MAXREC_MASK) >>
		    IEEE1394_BIB_MAXREC_SHIFT;

		if ((max_rec > 0) && (max_rec < 14)) {
			max_blk = 1 << (max_rec + 1);
		} else {
			/* These are either unspecified or reserved */
			max_blk = 4;
		}
		(*dev_max_payload) = max_blk;

		from_node = IEEE1394_NODE_NUM(target->on_hal->node_id);
		to_node = (target->on_node->node_num);

		/* Speed is to be filled in from speed map */
		curr_speed = (uint_t)s1394_speed_map_get(target->on_hal,
		    from_node, to_node);
		speed_max_blk = 512 << curr_speed;
		temp = (local_max_blk < max_blk) ? local_max_blk : max_blk;
		(*current_max_payload) = (temp < speed_max_blk) ? temp :
		    speed_max_blk;
	} else {
		/* Set dev_max_payload to local (HAL's) size */
		(*dev_max_payload) = local_max_blk;
		(*current_max_payload) = local_max_blk;
	}

	TNF_PROBE_0_DEBUG(s1394_get_maxpayload_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");
}

/*
 * s1394_cycle_master_capable()
 *    is used to determine whether or not the current root node on the
 *    1394 bus has its CMC-bit set in it Config ROM.  If not, then it
 *    is not capable of being cycle master and a new root node must be
 *    selected.
 */
static int
s1394_cycle_master_capable(s1394_hal_t *hal)
{
	s1394_node_t	*root;
	int		cycle_master_capable;
	uint_t		hal_node_num;

	TNF_PROBE_0_DEBUG(s1394_cycle_master_capable_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));

	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);

	/* Get a pointer to the root node */
	root = s1394_topology_tree_get_root_node(hal);

	/* Ignore, if we are already root */
	if (root == &hal->topology_tree[hal_node_num]) {
		TNF_PROBE_2_DEBUG(s1394_cmstr_capable_hal,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int,
		    node_num, hal_node_num, tnf_int, ret, 1);
		return (1);
	}

	/*
	 * We want to pick a new root if link is off or we don't have
	 * valid config rom
	 */
	if (LINK_ACTIVE(root) == B_FALSE || root->cfgrom == NULL ||
	    CFGROM_BIB_READ(root) == 0) {

		TNF_PROBE_4_DEBUG(s1394_cmstr_capable_not_hal,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int,
		    root, root->node_num, tnf_int, link_active,
		    LINK_ACTIVE(root), tnf_opaque, cfgrom, root->cfgrom,
		    tnf_int, bib, CFGROM_BIB_READ(root));

		return (0);
	}

	/* Check the Cycle Master bit in the Bus Info Block */
	cycle_master_capable = root->cfgrom[IEEE1212_NODE_CAP_QUAD] &
	    IEEE1394_BIB_CMC_MASK;

	if (cycle_master_capable) {
		TNF_PROBE_1_DEBUG(s1394_cmstr_capable_root,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int,
		    root, root->node_num);
		return (1);
	} else {
		TNF_PROBE_1(s1394_cmstr_not_capable_root,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int,
		    root, root->node_num);
		return (0);
	}
}

/*
 * s1394_do_phy_config_pkt()
 *    is called by s1394_do_bus_mgr_processing() to setup and send out
 *    a PHY configuration packet onto the 1394 bus.  Depending on the
 *    values in IRM_flags, the gap_count and root_holdoff bits on the
 *    bus will be affected by this packet.
 *
 *    NOTE: we overload DDI_FAILURE return value to mean jump back to
 *    the start of bus reset processing.
 */
static int
s1394_do_phy_config_pkt(s1394_hal_t *hal, int new_root, int new_gap_cnt,
    uint32_t IRM_flags)
{
	cmd1394_cmd_t	 *cmd;
	s1394_cmd_priv_t *s_priv;
	h1394_cmd_priv_t *h_priv;
	uint32_t	 pkt_data = 0;
	uint32_t	 gap_cnt = 0;
	uint32_t	 root = 0;
	int		 ret, result;
	uint_t		 flags = 0;

	TNF_PROBE_0_DEBUG(s1394_do_phy_config_pkt_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	/* Gap count needs to be optimized */
	if (IRM_flags & GAP_COUNT) {

		pkt_data = pkt_data | IEEE1394_PHY_CONFIG_T_BIT_MASK;
		gap_cnt = ((uint32_t)new_gap_cnt) <<
		    IEEE1394_PHY_CONFIG_GAP_CNT_SHIFT;
		gap_cnt = gap_cnt & IEEE1394_PHY_CONFIG_GAP_CNT_MASK;
		pkt_data = pkt_data | gap_cnt;

		(void) HAL_CALL(hal).set_gap_count(hal->halinfo.hal_private,
		    (uint_t)new_gap_cnt);
	}

	/* Root node needs to be changed */
	if (IRM_flags & ROOT_HOLDOFF) {

		pkt_data = pkt_data | IEEE1394_PHY_CONFIG_R_BIT_MASK;
		root = ((uint32_t)new_root) <<
		    IEEE1394_PHY_CONFIG_ROOT_HOLD_SHIFT;
		root = root & IEEE1394_PHY_CONFIG_ROOT_HOLD_MASK;
		pkt_data = pkt_data | root;

		(void) HAL_CALL(hal).set_root_holdoff_bit(
		    hal->halinfo.hal_private);
	}


	if (IRM_flags) {
		if (s1394_alloc_cmd(hal, flags, &cmd) != DDI_SUCCESS) {
			TNF_PROBE_1_DEBUG(s1394_do_phy_config_pkt_error,
			    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
			    "Unable to allocate PHY config packet");
			TNF_PROBE_0_DEBUG(s1394_do_phy_config_pkt_exit,
			    S1394_TNF_SL_HOTPLUG_STACK, "");
			return (0);
		}

		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
			/* lock tree failure indicates a bus gen change */
			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);
			TNF_PROBE_0_DEBUG(s1394_do_phy_config_pkt_exit,
			    S1394_TNF_SL_HOTPLUG_STACK, "");
			return (1);
		}

		/* Setup the callback routine */
		cmd->completion_callback  = s1394_phy_config_callback;
		cmd->cmd_callback_arg	  = (void *)(uintptr_t)IRM_flags;
		cmd->bus_generation	  = hal->generation_count;
		cmd->cmd_options	  = CMD1394_OVERRIDE_ADDR;
		cmd->cmd_type		  = CMD1394_ASYNCH_WR_QUAD;
		cmd->cmd_u.q.quadlet_data = pkt_data;

		/* Get the Services Layer private area */
		s_priv = S1394_GET_CMD_PRIV(cmd);

		/* Get a pointer to the HAL private struct */
		h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;

		s_priv->sent_by_target	= (s1394_target_t *)NULL;
		s_priv->sent_on_hal	= (s1394_hal_t *)hal;

		h_priv->bus_generation	= cmd->bus_generation;

		/* Speed must be IEEE1394_S100 on PHY config packets */
		s_priv->hal_cmd_private.speed = IEEE1394_S100;

		/* Mark command as being used */
		s_priv->cmd_in_use = B_TRUE;

		s1394_unlock_tree(hal);

		/* Put command on the HAL's outstanding request Q */
		s1394_insert_q_asynch_cmd(hal, cmd);

		ret = HAL_CALL(hal).send_phy_configuration_packet(
		    hal->halinfo.hal_private, (cmd1394_cmd_t *)cmd,
		    (h1394_cmd_priv_t *)&s_priv->hal_cmd_private, &result);

		if (ret != DDI_SUCCESS) {
			TNF_PROBE_2_DEBUG(s1394_do_phy_config_pkt_error,
			    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
			    "Unable to send PHY config packet",
			    tnf_int, result, result);

			(void) s1394_free_cmd(hal, (cmd1394_cmd_t **)&cmd);

			TNF_PROBE_0_DEBUG(s1394_do_phy_config_pkt_exit,
			    S1394_TNF_SL_HOTPLUG_STACK, "");
			return (0);

		} else {
			/*
			 * There will be a bus reset only if GAP_COUNT changed
			 */
			if (IRM_flags & GAP_COUNT) {
				return (1);
			}
		}
	}

	TNF_PROBE_0_DEBUG(s1394_do_phy_config_pkt_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");
	return (0);
}

/*
 * s1394_phy_config_callback()
 *    is the callback called after the PHY configuration packet has been
 *    sent out onto the 1394 bus.  Depending on the values in IRM_flags,
 *    (specifically if the gap_count has been changed) this routine may
 *    initiate a bus reset.
 */
static void
s1394_phy_config_callback(cmd1394_cmd_t *cmd)
{
	s1394_cmd_priv_t *s_priv;
	s1394_hal_t *hal;
	uint32_t IRM_flags;

	TNF_PROBE_0_DEBUG(s1394_phy_config_callback_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "");

	/* Get the Services Layer private area */
	s_priv = S1394_GET_CMD_PRIV(cmd);

	hal = (s1394_hal_t *)s_priv->sent_on_hal;

	IRM_flags = (uint32_t)(uintptr_t)cmd->cmd_callback_arg;

	if (cmd->cmd_result != CMD1394_CMDSUCCESS) {
		TNF_PROBE_2_DEBUG(s1394_do_phy_config_pkt_error,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
		    "Error sending PHY config packet",
		    tnf_int, result, cmd->cmd_result);
		(void) s1394_free_cmd(hal, &cmd);
	} else {
		(void) s1394_free_cmd(hal, &cmd);

		/* Only need a bus reset if we changed GAP_COUNT */
		if (IRM_flags & GAP_COUNT) {
			s1394_initiate_hal_reset(hal, NON_CRITICAL);
		}
	}

	TNF_PROBE_0_DEBUG(s1394_phy_config_callback_exit,
	    S1394_TNF_SL_HOTPLUG_STACK, "");
}

/*
 * s1394_lock_tree()
 *    Attempts to lock the topology tree. Returns DDI_FAILURE if generations
 *    changed or if the services layer signals the bus reset thread to go
 *    away. Otherwise, returns DDI_SUCCESS.
 */
int
s1394_lock_tree(s1394_hal_t *hal)
{
	int	circular;

	ASSERT(MUTEX_NOT_HELD(&hal->br_thread_mutex));
	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_0_DEBUG(s1394_lock_tree_enter, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

	mutex_enter(&hal->br_thread_mutex);
	ndi_devi_enter(hal->halinfo.dip, &circular);
	mutex_enter(&hal->topology_tree_mutex);

	if ((hal->br_thread_ev_type & BR_THR_GO_AWAY) != 0) {
		TNF_PROBE_2(s1394_lock_tree_go_away,
		    S1394_TNF_SL_HOTPLUG_STACK, "",
		    tnf_int, hal_generation, hal->generation_count,
		    tnf_int, br_thread_gen, hal->br_cfgrom_read_gen);
		TNF_PROBE_0_DEBUG(s1394_lock_tree_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		mutex_exit(&hal->br_thread_mutex);
		mutex_exit(&hal->topology_tree_mutex);
		ndi_devi_exit(hal->halinfo.dip, circular);
		return (DDI_FAILURE);
	} else if (hal->br_cfgrom_read_gen != hal->generation_count) {
		TNF_PROBE_2(s1394_lock_tree_gen_changed,
		    S1394_TNF_SL_HOTPLUG_STACK, "",
		    tnf_int, hal_generation, hal->generation_count,
		    tnf_int, br_thread_gen, hal->br_cfgrom_read_gen);

		TNF_PROBE_0_DEBUG(s1394_lock_tree_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		mutex_exit(&hal->br_thread_mutex);
		mutex_exit(&hal->topology_tree_mutex);
		ndi_devi_exit(hal->halinfo.dip, circular);
		return (DDI_FAILURE);
	}

	mutex_exit(&hal->br_thread_mutex);

	TNF_PROBE_0_DEBUG(s1394_lock_tree_exit, S1394_TNF_SL_HOTPLUG_STACK, "");

	return (DDI_SUCCESS);
}

/*
 * s1394_unlock_tree()
 *    Unlocks the topology tree
 */
void
s1394_unlock_tree(s1394_hal_t *hal)
{
	TNF_PROBE_0_DEBUG(s1394_unlock_tree_enter, S1394_TNF_SL_HOTPLUG_STACK,
	    "");

	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
	mutex_exit(&hal->topology_tree_mutex);
	ndi_devi_exit(hal->halinfo.dip, 0);

	TNF_PROBE_0_DEBUG(s1394_unlock_tree_exit, S1394_TNF_SL_HOTPLUG_STACK,
	    "");
}

/*
 * s1394_calc_next_quad()
 *    figures out the next quadlet to read. This maintains a stack of
 *    directories in the node. When the first quad of a directory (the
 *    first directory would be the root directory) is read, it is pushed on
 *    the this stack. When the directory is all read, it scans the directory
 *    looking for indirect entries. If any indirect directory entry is found,
 *    it is pushed on stack and that directory is read. If we are done dealing
 *    with all entries in the current dir, the directory is popped off the
 *    stack. If the stack is empty, we are back at the root directory level
 *    and essentially read the entire directory hierarchy.
 *    Returns 0 is more quads to read, else returns non-zero.
 */
static int
s1394_calc_next_quad(s1394_hal_t *hal, s1394_node_t *node, uint32_t quadlet,
    uint32_t *nextquadp)
{
	uint32_t data, type, key, value, *ptr;

	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));

	TNF_PROBE_4_DEBUG(s1394_calc_next_quad_enter,
	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, node_num, node->node_num,
	    tnf_uint, quadlet, quadlet, tnf_int, cfgrom_size, node->cfgrom_size,
	    tnf_uint, hal_gen, hal->generation_count);

	if (((quadlet + 1) >= node->cfgrom_size) ||
	    (CFGROM_SIZE_IS_CRCSIZE(node) == B_TRUE && (quadlet + 1) >=
		node->cfgrom_valid_size)) {
		TNF_PROBE_0_DEBUG(s1394_calc_next_quad_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "");
		return (1);
	}

	if (s1394_turn_off_dir_stack != 0 || CFGROM_DIR_STACK_OFF(node) ==
	    B_TRUE) {
		quadlet++;
		*nextquadp = quadlet;
		TNF_PROBE_3_DEBUG(s1394_calc_next_quad_exit,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
		    "dir stack turned off", tnf_uint, quadlet, quadlet,
		    tnf_opaque, cfgrom, node->cfgrom);
		return (0);
	}

	data = node->cfgrom[quadlet];

	if (quadlet == IEEE1212_ROOT_DIR_QUAD) {
		node->dir_stack_top = -1;
		node->expected_dir_quad = quadlet;
		node->expected_type = IEEE1212_IMMEDIATE_TYPE;
	}

	CFGROM_TYPE_KEY_VALUE(data, type, key, value);

	/*
	 * check to make sure we are looking at a dir. If the config rom
	 * is broken, then revert to normal scanning of the config rom
	 */
	if (node->expected_dir_quad == quadlet) {
		if (type != 0 || key != 0) {
			TNF_PROBE_3_DEBUG(s1394_calc_next_quad,
			    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
			    "bad directory turning off stack", tnf_uint,
			    quadlet, quadlet, tnf_uint, data, data);
			SET_CFGROM_DIR_STACK_OFF(node);
			quadlet = IEEE1212_ROOT_DIR_QUAD;
		} else {
			node->cur_dir_start = quadlet;
			node->cur_dir_size = IEEE1212_DIR_LEN(data);
			node->expected_dir_quad = 0;
			/* get the next quad */
			quadlet++;
		}
	} else {
		/*
		 * If we read all quads in cur dir and the cur dir is not
		 * a leaf, scan for offsets (if the directory's CRC checks
		 * out OK). If we have a directory or a leaf, we save the
		 * current location on the stack and start reading that
		 * directory. So, we will end up with a depth first read of
		 * the entire config rom. If we are done with the current
		 * directory, pop it off the stack and continue the scanning
		 * as appropriate.
		 */
		if (quadlet == node->cur_dir_start + node->cur_dir_size) {

			int i, top;
			boolean_t done_with_cur_dir = B_FALSE;

			if (node->expected_type == IEEE1212_LEAF_TYPE) {
				node->expected_type = IEEE1212_IMMEDIATE_TYPE;
				done_with_cur_dir = B_TRUE;
				TNF_PROBE_2_DEBUG(s1394_calc_next_quad,
				    S1394_TNF_SL_HOTPLUG_STACK, "",
				    tnf_string, msg, "done with a leaf",
				    tnf_uint, quadlet, quadlet);
				goto donewithcurdir;
			}

			ptr = &node->cfgrom[node->cur_dir_start];
			CFGROM_TYPE_KEY_VALUE(*ptr, type, key, value);

			/*
			 * If CRC for this directory is invalid, turn off
			 * dir stack and start re-reading from root dir.
			 * This wastes the work done thus far, but CRC
			 * errors in directories should be rather rare.
			 * if s1394_crcsz_is_cfgsz is set, then set
			 * cfgrom_valid_size to the len specfied as crc len
			 * in quadlet 0.
			 */
			if (s1394_valid_dir(hal, node, key, ptr) == B_FALSE) {
				SET_CFGROM_DIR_STACK_OFF(node);
				if (s1394_crcsz_is_cfgsz != 0) {
					SET_CFGROM_SIZE_IS_CRCSIZE(node);
					node->cfgrom_valid_size =
					    ((node->cfgrom[0] >>
					    IEEE1394_CFG_ROM_CRC_LEN_SHIFT) &
					    IEEE1394_CFG_ROM_CRC_LEN_MASK);
					TNF_PROBE_2(s1394_calc_next_quad,
					    S1394_TNF_SL_HOTPLUG_ERROR, "",
					    tnf_string, msg, "crc sz is cfg sz",
					    tnf_uint, size,
					    node->cfgrom_valid_size);
				}
				TNF_PROBE_2_DEBUG(s1394_calc_next_quad_exit,
				    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string,
				    msg, "crc error", tnf_uint, quadlet,
				    quadlet);
				*nextquadp = IEEE1212_ROOT_DIR_QUAD;
				return (0);
			}
			i = node->cur_dir_start + 1;
		rescan:
			for (done_with_cur_dir = B_FALSE; i <=
			    node->cur_dir_start + node->cur_dir_size; i++) {
				data = node->cfgrom[i];
				CFGROM_TYPE_KEY_VALUE(data, type, key, value);
				/* read leaf type and directory types only */
				if (type == IEEE1212_LEAF_TYPE || type ==
				    IEEE1212_DIRECTORY_TYPE) {

					/*
					 * push current dir on stack; if the
					 * stack is overflowing, ie, too many
					 * directory level nestings, turn off
					 * dir stack and fall back to serial
					 * scanning, starting at root dir. This
					 * wastes all the work we have done
					 * thus far, but more than 16 levels
					 * of directories is rather odd...
					 */
					top = ++node->dir_stack_top;
					if (top == S1394_DIR_STACK_SIZE) {

						TNF_PROBE_2_DEBUG(
						    s1394_calc_next_quad_exit,
						    S1394_TNF_SL_HOTPLUG_STACK,
						    "", tnf_string, msg,
						    "dir stack overflow",
						    tnf_uint, quadlet, quadlet);
						SET_CFGROM_DIR_STACK_OFF(node);
						*nextquadp =
						    IEEE1212_ROOT_DIR_QUAD;
						return (0);
					}

					TNF_PROBE_3_DEBUG(
					    s1394_calc_next_quad,
					    S1394_TNF_SL_HOTPLUG_STACK, "",
					    tnf_string, msg, "push dir stack",
					    tnf_uint, quadlet, quadlet,
					    tnf_int, top, top);

					node->dir_stack[top].dir_start =
					    node->cur_dir_start;
					node->dir_stack[top].dir_size =
					    node->cur_dir_size;
					node->dir_stack[top].dir_next_quad =
					    i + 1;
					/* and set the next quadlet to read */
					quadlet = i + value;
					node->expected_dir_quad = quadlet;
					node->expected_type = type;
					break;
				}
			}

		donewithcurdir:

			if ((i > node->cur_dir_start + node->cur_dir_size) ||
				done_with_cur_dir == B_TRUE) {

				/*
				 * all done with cur dir; pop it off the stack
				 */
				if (node->dir_stack_top >= 0) {
					TNF_PROBE_3_DEBUG(
					    s1394_calc_next_quad_exit,
					    S1394_TNF_SL_HOTPLUG_STACK, "",
					    tnf_string, msg, "pop dir stack",
					    tnf_uint, quadlet, quadlet,
					    tnf_int, top, node->dir_stack_top);
					top = node->dir_stack_top--;
					node->cur_dir_start =
					    node->dir_stack[top].dir_start;
					node->cur_dir_size =
					    node->dir_stack[top].dir_size;
					i = node->dir_stack[top].dir_next_quad;
					goto rescan;
				} else {
					/*
					 * if empty stack, we are at the top
					 * level; declare done.
					 */
					TNF_PROBE_1_DEBUG(
					    s1394_calc_next_quad_exit,
					    S1394_TNF_SL_HOTPLUG_STACK, "",
					    tnf_string, msg, "all done");
					return (1);
				}
			}
		} else {
			/* get the next quadlet */
			quadlet++;
		}
	}
	*nextquadp = quadlet;

	TNF_PROBE_1_DEBUG(s1394_calc_next_quad_exit, S1394_TNF_SL_HOTPLUG_STACK,
	    "", tnf_uint, next_quad, quadlet);

	return (0);
}