/*
* 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
* 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"
/*
* 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/sysmacros.h>
#include <sys/ddi_impldefs.h>
#include <sys/tnf_probe.h>
/* hcmd_ret_t */
typedef enum {
} hcmd_ret_t;
((nl) << IEEE1394_ADDR_PHY_ID_SHIFT); \
}
#define CFGROM_READ_PAUSE(d) \
((s1394_cfgrom_read_delay_ms == 0) ? (void) 0 : \
#define BUMP_CFGROM_READ_DELAY(n) \
#define CFGROM_GET_READ_DELAY(n, d) \
((d) = (n)->cfgrom_read_delay)
{ \
int i = (reset_fails); \
if (i != 0) { \
(n)->cfgrom_read_fails = 0; \
} \
(n)->cfgrom_quad_to_read = (quadlet); \
(n)->cfgrom_quad_read_cnt = (cnt); \
}
cmd1394_cmd_t *cmd);
cmd1394_cmd_t *cmd);
static void s1394_become_bus_mgr(void *arg);
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()
* as appropriate and do bus reset time things (bus manager processing,
* isoch resource reallocation etc.).
*/
void
{
"");
/* Initialize the Bus Mgr timers */
hal->bus_mgr_timeout_id = 0;
hal->bus_mgr_query_timeout_id = 0;
/* Initialize the cmpletion Q */
for (;;) {
s1394_wait_for_events(hal, 0);
/* stop bus manager timeouts, if needed */
/* start timers for checking bus manager, if needed */
/* Try to reallocate all isoch resources */
continue;
}
continue;
}
continue;
}
}
}
/*
* 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
{
if (firsttime)
callb_generic_cpr, "s1394_br_thread");
/* Check and wait for a BUS RESET */
}
if (event & BR_THR_GO_AWAY) {
/*NOTREACHED*/
return;
}
if (firsttime) {
return;
}
if (event & BR_THR_CFGROM_SCAN) {
}
}
/*
* 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
{
ret = DDI_SUCCESS;
while (!done) {
}
#endif
hal_gen);
return (DDI_FAILURE);
}
}
continue;
}
if (cmdret == S1394_HCMD_LOCK_FAILED) {
/* flush completion queue */
ret = DDI_FAILURE;
break;
} else if (cmdret == S1394_HCMD_NODE_DONE) {
if (--hal->cfgroms_being_read == 0) {
/* All done */
break;
}
} else {
done = 0;
}
}
}
return (ret);
}
/*
* s1394_flush_cmplq()
* Frees all cmds on the completion queue.
*/
static void
{
"");
do {
}
"");
}
/*
* s1394_br_thread_exit()
* Flushes the completion queue and calls thread_exit() (which effectively
* kills the bus reset thread).
*/
static void
{
#ifndef __lock_lint
#endif
thread_exit();
/*NOTREACHED*/
}
/*
* s1394_target_bus_reset_notifies()
* tells the ndi event framework to invoke any callbacks registered for
* "bus reset event".
*/
static void
{
NDI_SUCCESS) {
}
}
/*
* 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
{
"");
*status = S1394_NOSTATUS;
/*
* if cfgrom is non-NULL, this has to be generation changed
* case (where we allocate cfgrom again to reread the cfgrom)
*/
/*
* if node matched, either cfgrom has to be NULL or link should be
* off in the last matched node or config rom generations changed.
*/
*status |= S1394_LOCK_FAILED;
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* s1394_free_cfgrom()
* Marks the config rom invalid and frees up the config based on otpions.
*/
void
{
"");
if (options == S1394_FREE_CFGROM_BOTH) {
/*
* free in both old and new trees; will be called with
* new node.
*/
} else if (options == S1394_FREE_CFGROM_NEW) {
S1394_TNF_SL_HOTPLUG_STACK, "cfgrom free",
} else if (options == S1394_FREE_CFGROM_OLD) {
/* freeing in old tree */
S1394_TNF_SL_HOTPLUG_STACK, "cfgrom free",
}
"");
}
/*
* 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
{
/*
* 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 last time around, link was off, there wouldn't
* have been config rom allocated.
*/
return;
} else {
}
}
/*
* 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
{
/*
* drop the topology lock around command allocation. Return failure
* if either command allocation fails or cannot reacquire the lock
*/
*status = S1394_NOSTATUS;
}
*status |= S1394_LOCK_FAILED;
/* free the cmd allocated above */
if (((*status) & S1394_CMD_ALLOC_FAILED) != 0)
}
return (DDI_FAILURE);
}
/* allocate cfgrom if needed */
DDI_SUCCESS) {
return (DDI_FAILURE);
}
/*
* if this is a matched node, read quad 2 (node capabilities) to
* see if the generation count changed.
*/
/*
* 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.
*/
/* free the command if it wasn't handed over to the HAL */
if (((*status) & S1394_CMD_INFLIGHT) == 0) {
}
if (((*status) & S1394_LOCK_FAILED) != 0) {
}
return (DDI_FAILURE);
}
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
{
/*
* drop the topology lock around command allocation. Return failure
* if either command allocation fails or cannot reacquire the lock
*/
*status = S1394_NOSTATUS;
"command allocation failed");
}
*status |= S1394_LOCK_FAILED;
/* free if we allocated a cmd above */
if (((*status) & S1394_CMD_ALLOC_FAILED) == 0)
"unable to relock the tree");
}
return (DDI_FAILURE);
}
"unable to start read");
/* free the command if it wasn't handed over to the HAL */
if (((*status) & S1394_CMD_INFLIGHT) == 0) {
}
if (((*status) & S1394_LOCK_FAILED) != 0) {
}
return (DDI_FAILURE);
}
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
{
int ret;
int node;
int wait_in_gen;
int wait_for_cbs;
return (DDI_FAILURE);
}
wait_for_cbs = 0;
hal->cfgroms_being_read = 0;
ret = DDI_SUCCESS;
/* Send requests for all new node config ROM 0 */
break;
}
/* if node matched, onode should be non 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) &&
1))) {
if (IEEE1394_SELFID_ISLINKON(selfid_pkt)) {
&status) != DDI_SUCCESS) {
if ((status & S1394_LOCK_FAILED) != 0)
break;
} else {
wait_for_cbs++;
}
} else {
/*
* Special case: if link was active last
* time around, this should be treated as
* node going away.
*/
}
}
} else {
if (node == hal_node_num) {
/* Set up the local matched nodes */
if (onode) {
}
}
}
}
if ((status & S1394_LOCK_FAILED) != 0) {
return (DDI_FAILURE);
}
/*
* If we started any reads, wait for completion callbacks
*/
if (wait_for_cbs != 0) {
}
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_target_t *t;
locked = 1;
freecmd = 1;
"unable to lock tree");
locked = 0;
goto bail;
}
int reread = 0;
done = 0;
if (quadlet == IEEE1212_NODE_CAP_QUAD &&
CFGROM_BIB_READ(node)) {
/*
* node->old_node can be NULL if this is a new node &
* we are doing a rescan
*/
/* Update the target list, if any */
node->target_list = t;
while (t != NULL) {
t = t->target_sibling;
}
}
}
if (onode)
done++;
} else {
msg, "config rom generation changed",
/*
* Reset BIB_READ flag and start reading entire
* config rom.
*/
reread = 1;
/*
* if generations changed, allocate cfgrom for
* the new generation. s1394_match_GUID() will
* free up the cfgrom from the old generation.
*/
DDI_SUCCESS) {
0);
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 (!done) {
if (reread)
quadlet = 0;
else
/* if we don't have the entire bus_info_blk... */
if (quadlet < IEEE1394_BIB_QUAD_SZ) {
/* get next quadlet */
"unable to relock tree", tnf_uint,
locked = 0;
&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).
*/
"unable to read", tnf_uint,
if ((status & S1394_CMD_INFLIGHT) !=
0) {
freecmd = 0;
}
if ((status & S1394_LOCK_FAILED) != 0) {
locked = 0;
} else {
if (CFGROM_NEW_ALLOC(node) ==
B_TRUE) {
node,
} else {
node);
}
}
done++;
} else {
freecmd = 0;
}
} else {
/* got all of bus_info_blk */
done++;
}
}
} else {
done = 1;
/* retry if not too many failures */
"unable to relock tree", tnf_uint,
locked = 0;
&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).
*/
quadlet);
if ((status & S1394_CMD_INFLIGHT) != 0) {
freecmd = 0;
}
if ((status & S1394_LOCK_FAILED) != 0) {
locked = 0;
} else {
} else {
}
}
} else {
done = 0;
freecmd = 0;
}
} else {
} else {
}
}
}
bail:
if (freecmd) {
}
if (done) {
}
/* if we are bailing out because locking failed, locked == 0 */
if (locked == 0)
else
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
{
int ret;
int wait_for_cbs = 0;
return (DDI_FAILURE);
}
}
"non-success return from process_old_tree");
return (DDI_FAILURE);
}
"unable to relock the tree");
return (DDI_FAILURE);
}
/* Setup physical AR request filters */
/* Notify targets of isoch resource realloc failures */
/* Notify targets of the end of bus reset processing */
"unable to relock the tree after isoch notify");
return (DDI_FAILURE);
}
"unable to relock the tree after reset notify");
return (DDI_FAILURE);
}
/* Set HAL state to normal */
if (hal->disable_requests_bit == 0)
else
/* Flush the pending Q */
"non-success return from process_topology_tree");
return (DDI_FAILURE);
}
"unable to relock after processing topology tree");
return (DDI_FAILURE);
}
ret = DDI_SUCCESS;
/*
* If we started any reads, wait for completion callbacks
*/
if (wait_for_cbs != 0) {
ret);
}
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
{
/*
* 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).
*/
update_devinfo = 0;
locked = 0;
goto bail;
}
/*
* Done with this node. Mark config rom valid and
* update the devinfo tree for this node.
*/
quadlet);
} else {
}
} else {
locked = 0;
msg, "unable to relock the tree",
&status) != DDI_SUCCESS) {
/* give up on this guy */
quadlet);
if ((status & S1394_CMD_INFLIGHT) != 0) {
freecmd = 0;
}
if ((status & S1394_LOCK_FAILED) != 0) {
locked = 0;
} else {
B_TRUE) {
} else {
}
}
} else {
/* successfully started next read */
done = 0;
freecmd = 0;
}
}
} else {
/* retry if not too many failures */
locked = 0;
msg, "unable to relock for reread",
&status) != DDI_SUCCESS) {
if ((status & S1394_CMD_INFLIGHT) != 0) {
freecmd = 0;
}
if ((status & S1394_LOCK_FAILED) != 0) {
locked = 0;
} else {
/* stop further reads */
B_TRUE) {
} else {
}
}
} else {
/* successfully started next read */
done = 0;
freecmd = 0;
}
} else {
} else {
}
}
}
bail:
if (freecmd) {
}
if (done) {
}
if (update_devinfo) {
/*
* 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
*/
locked = 0;
"update devinfo returned failure", tnf_int,
}
}
/* if we are bailing out because locking failed, locked == 0 */
if (locked == 0)
else
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
{
/* Calculate the 64-bit address */
*status = S1394_NOSTATUS;
if (ret != DDI_SUCCESS) {
*status |= S1394_UNKNOWN;
return (DDI_FAILURE);
}
ret = DDI_SUCCESS;
/* Send the command out */
/* Callers can expect a callback now */
*status |= S1394_CMD_INFLIGHT;
} else {
"failure from xfer asynch command",
/* Remove from queue */
*status |= S1394_XFER_FAILED;
ret = DDI_FAILURE;
}
*status |= S1394_LOCK_FAILED;
ret = DDI_FAILURE;
"unable to relock the tree");
}
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
{
#if defined(DEBUG)
#endif
/* Get the Services Layer private area */
#if defined(DEBUG)
#endif
} else {
/* Put the command on completion queue */
}
}
}
/*
* 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_get_quad_info()
* Helper routine that picks apart the various fields of a 1394 address
*/
static void
{
}
/*
* 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
{
int old_node;
int gen_changed;
s1394_target_t *t;
"");
continue;
/* offline the new node that last matched */
/* and make the current new node invalid */
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).
*/
gen_changed = 1;
} else {
gen_changed = 0;
}
/*
* 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) {
ret = DDI_FAILURE;
break;
}
/* done */
break;
}
/*
* Free up cfgrom memory in the new_node and
* point it at the same config rom as the old one.
*/
}
/* Update the target list */
nnode->target_list = t;
while (t != NULL) {
t = t->target_sibling;
}
}
}
break;
}
}
"");
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
{
int node;
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;
continue;
}
ret = DDI_FAILURE;
}
}
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 */
{
"");
if (s1394_enable_crc_validation == 0) {
"validation turned off");
return (B_TRUE);
}
return (B_FALSE);
}
return (B_TRUE);
}
"!Bad CRC in config rom (node's GUID %08x%08x)",
return (B_FALSE);
}
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*/
{
"");
/*
* 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) {
"validation turned off");
return (B_TRUE);
}
return (B_TRUE);
}
return (B_FALSE);
}
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
{
int err;
int ret;
"");
/* Lock the topology tree */
/* Unlock the topology tree */
/* Make sure we aren't already the Bus Manager */
if (bm_node != -1) {
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 */
if (ret != DDI_SUCCESS) {
"Error in cswap32");
S1394_TNF_SL_BR_STACK, "");
return;
}
if ((curr_bus_mgr == S1394_INVALID_NODE_NUM) ||
(curr_bus_mgr == hal_node_num)) {
} else {
}
} else {
/* Remote */
DDI_SUCCESS) {
"Error in s1394_alloc_cmd()");
S1394_TNF_SL_BR_STACK, "");
return;
}
/* Get the Services Layer private area */
/* Lock the topology tree */
S1394_CMD_LOCK, &err);
/* Unlock the topology tree */
/* Command has now been put onto the queue! */
if (ret != DDI_SUCCESS) {
/* Need to free the command */
"Error in s1394_setup_asynch_command()");
S1394_TNF_SL_BR_STACK, "");
return;
}
/* Send the command out */
if (ret != DDI_SUCCESS) {
/* Remove cmd outstanding request Q */
/* Don't know who the bus_mgr is */
/* Need to free the command */
}
}
"");
}
/*
* 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_TNF_SL_BR_STACK, "");
/* Get the Services Layer private area */
/* Lock the topology tree */
/* Was the command successful? */
if ((curr_bus_mgr == S1394_INVALID_NODE_NUM) ||
(curr_bus_mgr == hal_node_num)) {
} else {
}
} else {
"Error while attempting to become bus manager",
/* Don't know who the bus_mgr is */
}
/* Need to free the command */
/* Unlock the topology tree */
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
{
int ret;
int IRM_node_num;
S1394_TNF_SL_BR_STACK, "");
return (DDI_FAILURE);
}
ret = DDI_SUCCESS;
/* If we are IRM capable, then do bus_mgr stuff... */
/* If there is an IRM, then do bus_mgr stuff */
if (IRM_node_num != -1) {
ret = DDI_FAILURE;
}
}
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)
*
* NOTE: we overload DDI_FAILURE return value to mean jump back to
* the start of bus reset processing.
*/
static int
{
int ret;
int IRM_node_num;
S1394_TNF_SL_BR_STACK, "");
/* Wait for Bus Manager to be determined */
/* or a Bus Reset to happen */
/* Check if a BUS RESET has come while we've been waiting */
S1394_TNF_SL_BR_STACK, "");
return (1);
}
return (1);
}
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 */
/* If setting root, then optimize gap_count */
} else {
/* Make sure root's ROOT_HOLDOFF bit is set */
}
/* Set the gap_count to optimum */
}
if (IRM_flags) {
}
S1394_TNF_SL_BR_STACK, "");
return (ret);
}
S1394_TNF_SL_BR_STACK, "");
return (ret);
}
/*
* s1394_bus_mgr_timers_stop()
* Cancels bus manager timeouts
*/
/*ARGSUSED*/
static void
{
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;
}
S1394_TNF_SL_BR_STACK, "");
}
/*
* s1394_bus_mgr_timers_start()
* Starts bus manager timeouts if the hal is IRM capable.
*/
static void
{
int IRM_node_num;
S1394_TNF_SL_BR_STACK, "");
/* If we are IRM capable, then do bus_mgr stuff... */
/*
* If we are the IRM, then wait 625ms
* before checking BUS_MANAGER_ID register
*/
S1394_TNF_SL_BR_STACK, "");
/* Wait 625ms, then check bus manager */
}
/* If there is an IRM on the bus */
if (IRM_node_num != -1) {
(hal->abdicate_bus_mgr_bit == 0)) {
/* Try to become bus manager */
} else {
hal->abdicate_bus_mgr_bit = 0;
S1394_TNF_SL_BR_STACK, "");
/* Wait 125ms, then try to become bus manager */
}
} else {
}
}
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
{
/* Find the HAL this target resides on */
/* Make sure we're holding the topology_tree_mutex */
/* Set dev_max_payload to local (HAL's) size */
} else {
/* These are either unspecified or reserved */
local_max_blk = 4;
}
/* Is this target on a node? */
} else {
/* These are either unspecified or reserved */
max_blk = 4;
}
(*dev_max_payload) = max_blk;
/* Speed is to be filled in from speed map */
} else {
/* Set dev_max_payload to local (HAL's) size */
(*dev_max_payload) = local_max_blk;
}
}
/*
* 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
{
int cycle_master_capable;
/* Get a pointer to the root node */
/* Ignore, if we are already root */
return (1);
}
/*
* We want to pick a new root if link is off or we don't have
* valid config rom
*/
CFGROM_BIB_READ(root) == 0) {
return (0);
}
/* Check the Cycle Master bit in the Bus Info Block */
if (cycle_master_capable) {
return (1);
} else {
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
{
/* Gap count needs to be optimized */
}
/* Root node needs to be changed */
if (IRM_flags & ROOT_HOLDOFF) {
}
if (IRM_flags) {
"Unable to allocate PHY config packet");
return (0);
}
/* lock tree failure indicates a bus gen change */
return (1);
}
/* Setup the callback routine */
/* Get the Services Layer private area */
/* Get a pointer to the HAL private struct */
/* Speed must be IEEE1394_S100 on PHY config packets */
/* Mark command as being used */
/* Put command on the HAL's outstanding request Q */
if (ret != DDI_SUCCESS) {
"Unable to send PHY config packet",
return (0);
} else {
/*
* There will be a bus reset only if GAP_COUNT changed
*/
return (1);
}
}
}
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
{
/* Get the Services Layer private area */
"Error sending PHY config packet",
} else {
/* Only need a bus reset if we changed GAP_COUNT */
}
}
}
/*
* 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
{
int circular;
"");
return (DDI_FAILURE);
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* s1394_unlock_tree()
* Unlocks the topology tree
*/
void
{
"");
"");
}
/*
* 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
{
node->cfgrom_valid_size)) {
return (1);
}
B_TRUE) {
quadlet++;
return (0);
}
if (quadlet == IEEE1212_ROOT_DIR_QUAD) {
}
/*
* 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
*/
"bad directory turning off stack", tnf_uint,
} else {
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.
*/
int i, top;
goto donewithcurdir;
}
/*
* 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_crcsz_is_cfgsz != 0) {
}
quadlet);
return (0);
}
for (done_with_cur_dir = B_FALSE; i <=
/* read leaf type and directory types only */
/*
* 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...
*/
if (top == S1394_DIR_STACK_SIZE) {
"dir stack overflow",
*nextquadp =
return (0);
}
i + 1;
/* and set the next quadlet to read */
break;
}
}
done_with_cur_dir == B_TRUE) {
/*
* all done with cur dir; pop it off the stack
*/
if (node->dir_stack_top >= 0) {
node->cur_dir_size =
goto rescan;
} else {
/*
* if empty stack, we are at the top
* level; declare done.
*/
return (1);
}
}
} else {
/* get the next quadlet */
quadlet++;
}
}
return (0);
}