/*
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* h1394.c
* 1394 Services Layer HAL Interface
* Contains all of the routines that define the HAL to Services Layer
* interface
*/
#include <sys/tnf_probe.h>
extern struct bus_ops nx1394_busops;
extern int s1394_ignore_invalid_gap_cnt;
/*
* Function: h1394_init()
* Input(s): modlp The structure containing all of the
* HAL's relevant information
*
* Output(s):
*
* Description: h1394_init() is called by the HAL's _init function and is
* used to set up the nexus bus ops.
*/
int
{
return (0);
}
/*
* Function: h1394_fini()
* Input(s): modlp The structure containing all of the
* HAL's relevant information
*
* Output(s):
*
* Description: h1394_fini() is called by the HAL's _fini function and is
* used to NULL out the nexus bus ops.
*/
void
{
}
/*
* Function: h1394_attach()
* Input(s): halinfo The structure containing all of the
* HAL's relevant information
* cmd The ddi_attach_cmd_t that tells us
* if this is a RESUME or a regular
* attach() call
*
* Output(s): sl_private The HAL "handle" to be used for
* all subsequent calls into the
* 1394 Software Framework
*
* Description: h1394_attach() registers the HAL with the 1394 Software
* Framework. It returns a HAL "handle" to be used for
* all subsequent calls into the 1394 Software Framework.
*/
int
{
int ret;
/* If this is a DDI_RESUME, return success */
if (cmd == DDI_RESUME) {
/* If we have a 1394A PHY, then reset the "contender bit" */
"");
return (DDI_SUCCESS);
} else if (cmd != DDI_ATTACH) {
"");
return (DDI_FAILURE);
}
/* Allocate space for s1394_hal_t */
/* Setup HAL state */
/* Copy in the halinfo struct */
/* Create the topology tree mutex */
/* Create the Cycle Mater timer mutex */
/* Initialize the Isoch CEC list */
/* Initialize the Bus Manager node ID mutex and cv */
/* Initialize the Bus Manager node ID - "-1" means undetermined */
/* Initialize the Target list */
/* Setup Request Q's */
/* Create the kmem_cache for command allocations */
/* Setup the event stuff */
if (ret != DDI_SUCCESS) {
/* Clean up before leaving */
"");
return (DDI_FAILURE);
}
/* Initialize the mutexes and cv's used by the bus reset thread */
/*
* Create a bus reset thread to handle the device discovery.
* It should take the default stack sizes, it should run
* the s1394_br_thread() routine at the start, passing the
* HAL pointer as its argument. The thread should be put
* on processor p0, its state should be set to runnable,
* but not yet on a processor, and its scheduling priority
* should be the minimum level of any system class.
*/
/* Until we see a bus reset this HAL has no nodes */
hal->number_of_nodes = 0;
/* Initialize the SelfID Info */
hal->current_buffer = 0;
/* Initialize kstat structures */
if (ret != DDI_SUCCESS) {
/* Clean up before leaving */
"");
return (DDI_FAILURE);
}
/* Setup the node tree pointers */
/* Initialize the local Config ROM entry */
if (ret != DDI_SUCCESS) {
/* Clean up before leaving */
return (DDI_FAILURE);
}
/* Initialize 1394 Address Space */
if (ret != DDI_SUCCESS) {
/* Clean up before leaving */
"");
return (DDI_FAILURE);
}
/* Initialize FCP subsystem */
if (ret != DDI_SUCCESS) {
/* Clean up before leaving */
"");
return (DDI_FAILURE);
}
/* Initialize the IRM node ID - "-1" means invalid, undetermined */
/* If we have a 1394A PHY, then set the "contender bit" */
/* Add into linked list */
} else {
}
/* Fill in services layer private info */
*sl_private = (void *)hal;
return (DDI_SUCCESS);
}
/*
* Function: h1394_detach()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* cmd The ddi_detach_cmd_t that tells us
* if this is a SUSPEND or a regular
* detach() call
*
* Output(s): DDI_SUCCESS HAL successfully detached
* DDI_FAILURE HAL failed to detach
*
* Description: h1394_detach() unregisters the HAL from the 1394 Software
* Framework. It can be called during a SUSPEND operation or
* for a real detach() event.
*/
int
{
switch (cmd) {
case DDI_DETACH:
/* Clean up before leaving */
/* NULL out the HAL "handle" */
*sl_private = NULL;
break;
case DDI_SUSPEND:
/* Turn off any timers that might be set */
/* Set the hal_was_suspended bit */
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Function: h1394_alloc_cmd()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* flags The flags parameter is described below
*
* Output(s): cmdp Pointer to the newly allocated command
* hal_priv_ptr Offset into the command, points to
* the HAL's private area
*
* Description: h1394_alloc_cmd() allocates a command for use with the
* h1394_read_request(), h1394_write_request(), or
* h1394_lock_request() interfaces of the 1394 Software Framework.
* By default, h1394_alloc_cmd() may sleep while allocating
* memory for the command structure. If this is undesirable,
* the HAL may set the H1394_ALLOC_CMD_NOSLEEP bit in the flags
* parameter.
*/
int
{
"");
S1394_TNF_SL_ARREQ_STACK, "");
return (DDI_FAILURE);
}
/* Get the Services Layer private area */
"");
return (DDI_SUCCESS);
}
/*
* Function: h1394_free_cmd()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* cmdp Pointer to the command to be freed
*
* Output(s): DDI_SUCCESS HAL successfully freed command
* DDI_FAILURE HAL failed to free command
*
* Description: h1394_free_cmd() attempts to free a command that has previously
* been allocated by the HAL. It is possible for h1394_free_cmd()
* to fail because the command is currently in-use by the 1394
* Software Framework.
*/
int
{
"");
/* Get the Services Layer private area */
/* Check that command isn't in use */
"");
return (DDI_FAILURE);
}
/* Command pointer is set to NULL before returning */
/* kstats - number of cmds freed */
"");
return (DDI_SUCCESS);
}
/*
* Function: h1394_cmd_is_complete()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* command_id Pointer to the command that has
* just completed
* cmd_type AT_RESP => AT response or ATREQ =
* AT request
* status Command's completion status
*
* Output(s): None
*
* Description: h1394_cmd_is_complete() is called by the HAL whenever an
* outstanding command has completed (successfully or otherwise).
* After determining whether it was an AT request or and AT
* response that we are handling, the command is dispatched to
* the appropriate handler in the 1394 Software Framework.
*/
void
{
/* Is it AT_RESP or AT_REQ? */
switch (cmd_type) {
case H1394_AT_REQ:
break;
case H1394_AT_RESP:
break;
default:
/* An unexpected error in the HAL */
/* Disable the HAL */
break;
}
}
/*
* Function: h1394_bus_reset()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
*
* Output(s): selfid_buf_addr The pointer to a buffer into which
* any Self ID packets should be put
*
* Description: h1394_bus_reset() is called whenever a 1394 bus reset event
* is detected by the HAL. This routine simply prepares for
* the subsequent Self ID packets.
*/
void
{
/* Update the HAL's state */
} else {
return;
}
if (hal->num_bus_reset_till_fail > 0) {
} else {
}
} else {
}
/* Reset the IRM node ID */
/* Slowest node defaults to IEEE1394_S400 */
/* Pick a SelfID buffer to give */
if (hal->current_buffer == 0) {
} else {
hal->current_buffer = 0;
}
/* Disable the CSR topology_map (temporarily) */
/* Reset the Bus Manager node ID */
}
/*
* Function: h1394_self_ids()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* selfid_buf_addr Pointer to the Self ID buffer
* selfid_size The size of the filled part of the
* Self ID buffer
* node_id The local (host) node ID for the
* current generation
* generation_count The current generation number
*
* Output(s): None
*
* Description: h1394_self_ids() does alot of the work at bus reset. It
* takes the Self ID packets and parses them, builds a topology
* tree representation of them, calculates gap count, IRM, speed
* map, does any node matching that's possible, and then wakes
* up the br_thread.
*/
void
{
int diameter;
/*
* NOTE: current topology tree is referred to as topology_tree
* and the old topology tree is referred to as old_tree.
* tree_valid indicates selfID buffer checked out OK and we were
* able to build the topology tree.
* tree_processed indicates we read the config ROMs as needed.
*/
/* Lock the topology tree */
"");
return;
}
/* kstats - number of selfid completes */
} else {
/* Use max_generation to determine how many bus resets */
}
/*
* If the current tree has a valid topology tree (selfids
* checked out OK etc) and config roms read as needed,
* then make it the old tree before building a new one.
*/
S1394_TNF_SL_BR_STACK, "");
/* Trees are switched after the copy completes */
}
/* Set the new generation and node id */
/* Invalidate the current topology tree */
hal->cfgroms_being_read = 0;
"");
/*
* Save the number of nodes prior to parsing the self id buffer.
* We need this saved value while initializing the topology tree
* (for non-copy case).
*/
/* Parse the SelfID buffer */
DDI_SUCCESS) {
/* Unlock the topology tree */
"");
/* kstats - SelfID buffer error */
return; /* Error parsing SelfIDs */
}
/* Sort the SelfID packets by node number (if it's a 1995 PHY) */
"");
}
/*
* Update the cycle master timer - if the timer is set and
* we were the root but we are not anymore, then disable it.
*/
} else {
}
"");
/* Determine the 1394 bus gap count */
/* If gap counts are inconsistent, reset */
/* Unlock the topology tree */
"");
/* kstats - SelfID buffer error (invalid gap counts) */
if (s1394_ignore_invalid_gap_cnt == 1) {
/* Lock the topology tree again */
} else {
return; /* Invalid gap counts in SelfID buffer */
}
}
/* Determine the Isoch Resource Manager */
S1394_TNF_SL_BR_STACK, "");
/* Build the topology tree */
/* Unlock the topology tree */
"");
/* kstats - SelfID buffer error (Invalid topology tree) */
return; /* Error building topology tree from SelfIDs */
}
"");
/* Update the CSR topology_map */
/* Calculate the diameter */
/* Determine the optimum gap count */
/* Fill in the speed map */
/* Initialize the two trees (for tree walking) */
/* Are both trees (old and new) valid? */
/* If HAL was in a suspended state, then do no matching */
} else {
/* If only one bus reset occurred, match the trees */
S1394_TNF_SL_BR_STACK, "");
}
}
}
/* Unlock the topology tree */
/* Wake up the bus reset processing thread */
S1394_TNF_SL_BR_STACK, "");
}
/*
* Function: h1394_read_request()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* req The incoming AR request
*
* Output(s): None
*
* Description: h1394_read_request() receives incoming AR requests. These
* asynchronous read requests are dispatched to the appropriate
* target (if one has registered) or are handled by the 1394
* Software Framework, which will send out an appropriate
* response.
*/
void
{
void (*recv_read_req)(cmd1394_cmd_t *);
"");
/* Get the Services Layer private area */
case CMD1394_ASYNCH_RD_QUAD:
break;
case CMD1394_ASYNCH_RD_BLOCK:
break;
default:
/* An unexpected error in the HAL */
/* Disable the HAL */
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
/* Lock the "used" tree */
/* Has the 1394 address been allocated? */
S1394_TNF_SL_ARREQ_STACK, "");
/* If it wasn't found, it isn't owned... */
/* Unlock the "used" tree */
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
/* Does the WHOLE request fit in the allocated block? */
/* Unlock the "used" tree */
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
/* Is a read request valid for this address space? */
/* Unlock the "used" tree */
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
/* Make sure quadlet requests are quadlet-aligned */
((offset & 0x3) != 0)) {
/* Unlock the "used" tree */
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
/* Fill in the backing store if necessary */
case CMD1394_ASYNCH_RD_QUAD:
break;
case CMD1394_ASYNCH_RD_BLOCK:
/* Update b_wptr to refelect the new data */
} else {
/* An unexpected error in the HAL */
/* Unlock the "used" tree */
/* Disable the HAL */
msg, "Error - mblk too small for request");
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
break;
default:
/* An unexpected error in the HAL */
/* Unlock the "used" tree */
/* Disable the HAL */
"Invalid command type specified");
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
}
/* Fill in the rest of the info in the request */
/* Unlock the "used" tree */
/*
* Add no code that modifies the command after the target
* callback is called or after the response is sent to the
* HAL.
*/
if (recv_read_req != NULL) {
S1394_TNF_SL_ARREQ_STACK, "");
} else {
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
"");
}
/*
* Function: h1394_write_request()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* req The incoming AR request
*
* Output(s): None
*
* Description: h1394_write_request() receives incoming AR requests. These
* asynchronous write requests are dispatched to the appropriate
* target (if one has registered) or are handled by the 1394
* Software Framework, which will send out an appropriate
* response.
*/
void
{
void (*recv_write_req)(cmd1394_cmd_t *);
"");
/* Get the Services Layer private area */
case CMD1394_ASYNCH_WR_QUAD:
break;
case CMD1394_ASYNCH_WR_BLOCK:
break;
default:
/* An unexpected error in the HAL */
/* Disable the HAL */
"Invalid command type specified");
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
/* Lock the "used" tree */
/* Has the 1394 address been allocated? */
S1394_TNF_SL_ARREQ_STACK, "");
/* Is this a posted write request? */
/* If it wasn't found, it isn't owned... */
goto write_error_check;
}
/* Does the WHOLE request fit in the allocated block? */
goto write_error_check;
}
/* Is a write request valid for this address space? */
goto write_error_check;
}
/* Make sure quadlet request is quadlet aligned */
((offset & 0x3) != 0)) {
goto write_error_check;
}
/* Check if posted-write when sending error responses */
if (write_error == B_TRUE) {
/* Unlock the "used" tree */
if (posted_write == B_TRUE) {
/* Get a pointer to the HAL private struct */
/* Free the command - Pass it back to the HAL */
S1394_TNF_SL_ARREQ_STACK, "");
return;
} else {
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
}
/* Fill in the backing store if necessary */
case CMD1394_ASYNCH_WR_QUAD:
(void *)bufp_addr, cmd_length);
break;
case CMD1394_ASYNCH_WR_BLOCK:
} else {
/* An unexpected error in the HAL */
/* Unlock the "used" tree */
/* Disable the HAL */
msg, "Error - mblk too small for request");
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
break;
default:
/* An unexpected error in the HAL */
/* Unlock the "used" tree */
/* Disable the HAL */
"Invalid command type specified");
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
}
/* Fill in the rest of the info in the request */
/* Unlock the "used" tree */
/*
* Add no code that modifies the command after the target
* callback is called or after the response is sent to the
* HAL.
*/
if (recv_write_req != NULL) {
S1394_TNF_SL_ARREQ_STACK, "");
} else {
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
S1394_TNF_SL_ARREQ_STACK, "");
}
/*
* Function: h1394_lock_request()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* req The incoming AR request
*
* Output(s): None
*
* Description: h1394_lock_request() receives incoming AR requests. These
* asynchronous lock requests are dispatched to the appropriate
* target (if one has registered) or are handled by the 1394
* Software Framework, which will send out an appropriate
* response.
*/
void
{
void (*recv_lock_req)(cmd1394_cmd_t *);
S1394_TNF_SL_ARREQ_STACK, "");
/* Get the Services Layer private area */
/* Lock the "used" tree */
/* Has the 1394 address been allocated? */
/* If it wasn't found, it isn't owned... */
/* Unlock the "used" tree */
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
/* Does the WHOLE request fit in the allocated block? */
case CMD1394_ASYNCH_LOCK_32:
/* kstats - 32-bit lock request */
break;
case CMD1394_ASYNCH_LOCK_64:
/* kstats - 64-bit lock request */
break;
default:
/* Unlock the "used" tree */
/* An unexpected error in the HAL */
/* Disable the HAL */
"Invalid command type specified");
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
/* Unlock the "used" tree */
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
/* Is a lock request valid for this address space? */
/* Unlock the "used" tree */
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
/* Fill in the backing store if necessary */
switch (lock_type) {
case CMD1394_LOCK_MASK_SWAP:
/* Mask-Swap (see P1394A - Table 1.7) */
/* Copy new_value into backing store */
break;
/* Compare-Swap */
/* Copy new_value into backing store */
(void *)bufp_addr,
}
break;
case CMD1394_LOCK_FETCH_ADD:
/* Fetch-Add (see P1394A - Table 1.7) */
/* Copy new_value into backing store */
break;
case CMD1394_LOCK_LITTLE_ADD:
/* Little-Add (see P1394A - Table 1.7) */
/* Copy new_value into backing store */
break;
case CMD1394_LOCK_BOUNDED_ADD:
/* Bounded-Add (see P1394A - Table 1.7) */
/* Copy new_value into backing store */
(void *)bufp_addr,
}
break;
case CMD1394_LOCK_WRAP_ADD:
/* Wrap-Add (see P1394A - Table 1.7) */
} else {
}
/* Copy new_value into backing store */
break;
default:
/* Unlock the "used" tree */
msg, "Invalid lock_type");
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
} else {
/* Handling for the 8-byte (64-bit) lock requests */
switch (lock_type) {
case CMD1394_LOCK_MASK_SWAP:
/* Mask-Swap (see P1394A - Table 1.7) */
/* Copy new_value into backing store */
break;
/* Compare-Swap */
/* Copy new_value into backing store */
(void *)bufp_addr,
}
break;
case CMD1394_LOCK_FETCH_ADD:
/* Fetch-Add (see P1394A - Table 1.7) */
/* Copy new_value into backing store */
break;
case CMD1394_LOCK_LITTLE_ADD:
/* Little-Add (see P1394A - Table 1.7) */
/* Copy new_value into backing store */
break;
case CMD1394_LOCK_BOUNDED_ADD:
/* Bounded-Add (see P1394A - Table 1.7) */
/* Copy new_value into backing store */
(void *)bufp_addr,
}
break;
case CMD1394_LOCK_WRAP_ADD:
/* Wrap-Add (see P1394A - Table 1.7) */
} else {
}
/* Copy new_value into backing store */
break;
default:
/* Unlock the "used" tree */
msg, "Invalid lock_type");
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
}
}
/* Fill in the rest of the info in the request */
/* Unlock the "used" tree */
/*
* Add no code that modifies the command after the target
* callback is called or after the response is sent to the
* HAL.
*/
if (recv_lock_req != NULL) {
S1394_TNF_SL_ARREQ_STACK, "");
} else {
S1394_TNF_SL_ARREQ_STACK, "");
return;
}
S1394_TNF_SL_ARREQ_STACK, "");
}
/*
* Function: h1394_ioctl()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* cmd ioctl cmd
* arg argument for the ioctl cmd
* mode mode bits (see ioctl(9e))
* cred_p cred structure pointer
* rval_p pointer to return value (see ioctl(9e))
*
* Output(s): EINVAL if not a DEVCTL ioctl, else return value from s1394_ioctl
*
* Description: h1394_ioctl() implements non-HAL specific ioctls. Currently,
* DEVCTL ioctls are the only generic ioctls supported.
*/
int
int *rval_p)
{
int status;
return (EINVAL);
return (status);
}
/*
* Function: h1394_phy_packet()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* packet_data Pointer to a buffer of packet data
* quadlet_count Length of the buffer
* timestamp Timestamp indicating time of arrival
*
* Output(s): None
*
* Description: h1394_phy_packet() is not implemented currently, but would
* be used to process the responses to PHY ping packets in P1394A
* When one is sent out, a timestamp is given indicating its time
* of departure. Comparing that old timestamp with this new
* timestamp, we can determine the time of flight and can use
* those times to optimize the gap count.
*/
/* ARGSUSED */
void
{
/* This interface is not yet implemented */
}
/*
* Function: h1394_error_detected()
* Input(s): sl_private The HAL "handle" returned by
* h1394_attach()
* type The type of error the HAL detected
* arg Pointer to any extra information
*
* Output(s): None
*
* Description: h1394_error_detected() is used by the HAL to report errors
* to the 1394 Software Framework.
*/
void
{
switch (type) {
case H1394_LOCK_RESP_ERR:
/* If we are the IRM, then initiate a bus reset */
if (IRM_node_num == hal_node_num)
break;
case H1394_POSTED_WR_ERR:
break;
break;
case H1394_CYCLE_TOO_LONG:
/* Set a timer to become cycle master after 1 second */
break;
default:
break;
}
}