/*
* 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 (c) 1999-2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* s1394_csr.c
* 1394 Services Layer CSR and Config ROM Routines
* Contains all of the CSR callback routines for various required
* CSR registers. Also contains routines for their initialization
* and destruction, as well as routines to handle the processing
* of Config ROM update requests.
*/
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/types.h>
#include <sys/kmem.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>
static void s1394_CSR_state_clear(cmd1394_cmd_t *req);
static void s1394_CSR_state_set(cmd1394_cmd_t *req);
static void s1394_CSR_node_ids(cmd1394_cmd_t *req);
static void s1394_CSR_reset_start(cmd1394_cmd_t *req);
static void s1394_CSR_split_timeout(cmd1394_cmd_t *req);
static void s1394_CSR_argument_regs(cmd1394_cmd_t *req);
static void s1394_CSR_test_regs(cmd1394_cmd_t *req);
static void s1394_CSR_interrupt_regs(cmd1394_cmd_t *req);
static void s1394_CSR_clock_regs(cmd1394_cmd_t *req);
static void s1394_CSR_message_regs(cmd1394_cmd_t *req);
static void s1394_CSR_cycle_time(cmd1394_cmd_t *req);
static void s1394_CSR_bus_time(cmd1394_cmd_t *req);
static void s1394_CSR_busy_timeout(cmd1394_cmd_t *req);
static void s1394_CSR_IRM_regs(cmd1394_cmd_t *req);
static void s1394_CSR_topology_map(cmd1394_cmd_t *req);
static void s1394_common_CSR_routine(s1394_hal_t *hal, cmd1394_cmd_t *req);
static int s1394_init_config_rom_structures(s1394_hal_t *hal);
static int s1394_destroy_config_rom_structures(s1394_hal_t *hal);
/*
* s1394_setup_CSR_space()
* setups up the local host's CSR registers and callback routines.
*/
int
s1394_setup_CSR_space(s1394_hal_t *hal)
{
s1394_addr_space_blk_t *curr_blk;
t1394_alloc_addr_t addr;
t1394_addr_enable_t rw_flags;
int result;
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_enter, S1394_TNF_SL_CSR_STACK,
"");
/*
* Although they are not freed up in this routine, if
* one of the s1394_claim_addr_blk() routines fails,
* all of the previously successful claims will be
* freed up in s1394_destroy_addr_space() upon returning
* DDI_FAILURE from this routine.
*/
rw_flags = T1394_ADDR_RDENBL | T1394_ADDR_WRENBL;
/*
* STATE_CLEAR
* see IEEE 1394-1995, Section 8.3.2.2.1 or
* IEEE 1212-1994, Section 7.4.1
*/
addr.aa_address = IEEE1394_CSR_STATE_CLEAR;
addr.aa_length = IEEE1394_QUADLET;
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_state_clear;
addr.aa_evts.recv_write_request = s1394_CSR_state_clear;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"STATE_CLEAR: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* STATE_SET
* see IEEE 1394-1995, Section 8.3.2.2.2 or
* IEEE 1212-1994, Section 7.4.2
*/
addr.aa_address = IEEE1394_CSR_STATE_SET;
addr.aa_length = IEEE1394_QUADLET;
addr.aa_enable = T1394_ADDR_WRENBL;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = NULL;
addr.aa_evts.recv_write_request = s1394_CSR_state_set;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"STATE_SET: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* NODE_IDS
* see IEEE 1394-1995, Section 8.3.2.2.3 or
* IEEE 1212-1994, Section 7.4.3
*/
addr.aa_address = IEEE1394_CSR_NODE_IDS;
addr.aa_length = IEEE1394_QUADLET;
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_node_ids;
addr.aa_evts.recv_write_request = s1394_CSR_node_ids;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"NODE_IDS: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* RESET_START
* see IEEE 1394-1995, Section 8.3.2.2.4 or
* IEEE 1212-1994, Section 7.4.4
*/
addr.aa_address = IEEE1394_CSR_RESET_START;
addr.aa_length = IEEE1394_QUADLET;
addr.aa_enable = T1394_ADDR_WRENBL;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = NULL;
addr.aa_evts.recv_write_request = s1394_CSR_reset_start;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"RESET_START: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* SPLIT_TIMEOUT
* see IEEE 1394-1995, Section 8.3.2.2.6 or
* IEEE 1212-1994, Section 7.4.7
*/
addr.aa_address = IEEE1394_CSR_SPLIT_TIMEOUT_HI;
addr.aa_length = IEEE1394_OCTLET;
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_split_timeout;
addr.aa_evts.recv_write_request = s1394_CSR_split_timeout;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"SPLIT_TIMEOUT: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* ARGUMENT_HI and ARGUMENT_LO
* see IEEE 1394-1995, Section 8.3.2.2.7 or
* IEEE 1212-1994, Section 7.4.8
*/
addr.aa_address = IEEE1394_CSR_ARG_HI;
addr.aa_length = 2 * (IEEE1394_QUADLET);
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_argument_regs;
addr.aa_evts.recv_write_request = s1394_CSR_argument_regs;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"ARGUMENT registers: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* TEST_START and TEST_STATUS
* see IEEE 1394-1995, Section 8.3.2.2.7 or
* IEEE 1212-1994, Section 7.4.9 - 7.4.10
*/
addr.aa_address = IEEE1394_CSR_TEST_START;
addr.aa_length = 2 * (IEEE1394_QUADLET);
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_test_regs;
addr.aa_evts.recv_write_request = s1394_CSR_test_regs;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"TEST registers: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* INTERRUPT_TARGET and INTERRUPT_MASK
* see IEEE 1394-1995, Section 8.3.2.2.9 or
* IEEE 1212-1994, Section 7.4.15 - 7.4.16
*/
addr.aa_address = IEEE1394_CSR_INTERRUPT_TARGET;
addr.aa_length = 2 * (IEEE1394_QUADLET);
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_interrupt_regs;
addr.aa_evts.recv_write_request = s1394_CSR_interrupt_regs;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"INTERRUPT registers: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* CLOCK_VALUE, CLOCK_TICK_PERIOD, CLOCK_INFO, etc.
* see IEEE 1394-1995, Section 8.3.2.2.10 or
* IEEE 1212-1994, Section 7.4.17 - 7.4.20
*/
addr.aa_address = IEEE1394_CSR_CLOCK_VALUE;
addr.aa_length = IEEE1394_CSR_CLOCK_VALUE_SZ;
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_clock_regs;
addr.aa_evts.recv_write_request = s1394_CSR_clock_regs;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"CLOCK registers: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* MESSAGE_REQUEST and MESSAGE_RESPONSE
* see IEEE 1394-1995, Section 8.3.2.2.11 or
* IEEE 1212-1994, Section 7.4.21
*/
addr.aa_address = IEEE1394_CSR_MESSAGE_REQUEST;
addr.aa_length = IEEE1394_CSR_MESSAGE_REQUEST_SZ;
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_message_regs;
addr.aa_evts.recv_write_request = s1394_CSR_message_regs;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"MESSAGE registers: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* CYCLE_TIME
* see IEEE 1394-1995, Section 8.3.2.3.1
*/
addr.aa_address = IEEE1394_SCSR_CYCLE_TIME;
addr.aa_length = IEEE1394_QUADLET;
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_cycle_time;
addr.aa_evts.recv_write_request = s1394_CSR_cycle_time;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"CYCLE_TIME: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* BUS_TIME
* see IEEE 1394-1995, Section 8.3.2.3.2
*/
addr.aa_address = IEEE1394_SCSR_BUS_TIME;
addr.aa_length = IEEE1394_QUADLET;
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_bus_time;
addr.aa_evts.recv_write_request = s1394_CSR_bus_time;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"BUS_TIME: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* BUSY_TIMEOUT
* see IEEE 1394-1995, Section 8.3.2.3.5
*/
addr.aa_address = IEEE1394_SCSR_BUSY_TIMEOUT;
addr.aa_length = IEEE1394_QUADLET;
addr.aa_enable = rw_flags;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_busy_timeout;
addr.aa_evts.recv_write_request = s1394_CSR_busy_timeout;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"BUSY_TIMEOUT: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* BUS_MANAGER_ID
* BANDWIDTH_AVAILABLE
* CHANNELS_AVAILABLE
* see IEEE 1394-1995, Section 8.3.2.3.6 - 8.3.2.3.8
*/
addr.aa_address = IEEE1394_SCSR_BUSMGR_ID;
addr.aa_length = 3 * (IEEE1394_QUADLET);
addr.aa_enable = T1394_ADDR_RDENBL | T1394_ADDR_LKENBL;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_IRM_regs;
addr.aa_evts.recv_write_request = NULL;
addr.aa_evts.recv_lock_request = s1394_CSR_IRM_regs;
addr.aa_kmem_bufp = NULL;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"IRM registers: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* Reserved for Configuration ROM
* see IEEE 1394-1995, Section 8.3.2.5.3
*/
addr.aa_address = IEEE1394_CONFIG_ROM_ADDR;
addr.aa_length = IEEE1394_CONFIG_ROM_SZ;
result = s1394_reserve_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"Unable to reserve Config ROM");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* TOPOLOGY_MAP
* see IEEE 1394-1995, Section 8.3.2.4.1
*/
hal->CSR_topology_map = kmem_zalloc(IEEE1394_UCSR_TOPOLOGY_MAP_SZ,
KM_SLEEP);
addr.aa_address = IEEE1394_UCSR_TOPOLOGY_MAP;
addr.aa_length = IEEE1394_UCSR_TOPOLOGY_MAP_SZ;
addr.aa_enable = T1394_ADDR_RDENBL;
addr.aa_type = T1394_ADDR_FIXED;
addr.aa_evts.recv_read_request = s1394_CSR_topology_map;
addr.aa_evts.recv_write_request = NULL;
addr.aa_evts.recv_lock_request = NULL;
addr.aa_kmem_bufp = (caddr_t)hal->CSR_topology_map;
addr.aa_arg = hal;
result = s1394_claim_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
kmem_free((void *)hal->CSR_topology_map,
IEEE1394_UCSR_TOPOLOGY_MAP_SZ);
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"TOPOLOGY_MAP: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
curr_blk = (s1394_addr_space_blk_t *)(addr.aa_hdl);
/* Set up the block so that we free kmem_bufp at detach */
curr_blk->free_kmem_bufp = B_TRUE;
/*
* Reserve the SPEED_MAP
* see IEEE 1394-1995, Section 8.3.2.4.1
* (obsoleted in P1394A)
*/
addr.aa_address = IEEE1394_UCSR_SPEED_MAP;
addr.aa_length = IEEE1394_UCSR_SPEED_MAP_SZ;
result = s1394_reserve_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"SPEED_MAP: CSR setup failed");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
S1394_TNF_SL_CSR_STACK, "");
return (DDI_FAILURE);
}
/*
* Reserved - Boundary between reserved Serial Bus
* dependent registers and other CSR register space.
* See IEEE 1394-1995, Table 8-4 for this address.
*
* This quadlet is reserved as a way of preventing
* the inadvertant allocation of a part of CSR space
* that will likely be used by future specifications
*/
addr.aa_address = IEEE1394_UCSR_RESERVED_BOUNDARY;
addr.aa_length = IEEE1394_QUADLET;
result = s1394_reserve_addr_blk(hal, &addr);
if (result != DDI_SUCCESS) {
TNF_PROBE_1(s1394_setup_CSR_space_error,
S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
"Unable to reserve boundary quadlet");
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit,
"stacktrace 1394 s1394", "");
return (DDI_FAILURE);
}
TNF_PROBE_0_DEBUG(s1394_setup_CSR_space_exit, S1394_TNF_SL_CSR_STACK,
"");
return (DDI_SUCCESS);
}
/*
* s1394_CSR_state_clear()
* handles all requests to the STATE_CLEAR CSR register. It enforces
* that certain bits that can be twiddled only by a given node (IRM or
* Bus Manager).
*/
static void
s1394_CSR_state_clear(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
uint32_t data;
uint_t offset;
uint_t is_from;
uint_t should_be_from;
int result;
TNF_PROBE_0_DEBUG(s1394_CSR_state_clear_enter, S1394_TNF_SL_CSR_STACK,
"");
hal = (s1394_hal_t *)req->cmd_callback_arg;
/* Register offset */
offset = req->cmd_addr & IEEE1394_CSR_OFFSET_MASK;
/* Verify that request is quadlet aligned */
if ((offset & 0x3) != 0) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_state_clear_exit,
S1394_TNF_SL_CSR_STACK, "");
return;
}
/* Only writes from IRM or Bus Mgr allowed (in some cases) */
mutex_enter(&hal->topology_tree_mutex);
is_from = IEEE1394_NODE_NUM(req->nodeID);
if (hal->bus_mgr_node != -1)
should_be_from = IEEE1394_NODE_NUM(hal->bus_mgr_node);
else if (hal->IRM_node != -1)
should_be_from = IEEE1394_NODE_NUM(hal->IRM_node);
else
should_be_from = S1394_INVALID_NODE_NUM;
mutex_exit(&hal->topology_tree_mutex);
switch (req->cmd_type) {
case CMD1394_ASYNCH_RD_QUAD:
/*
* The csr_read() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. But although the STATE_CLEAR register
* is required to be implemented and readable, we will
* return IEEE1394_RESP_ADDRESS_ERROR in the response if
* we ever see this error.
*/
result = HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
offset, &data);
if (result == DDI_SUCCESS) {
req->cmd_u.q.quadlet_data = data;
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
case CMD1394_ASYNCH_WR_QUAD:
data = req->cmd_u.q.quadlet_data;
/* CMSTR bit - request must be from bus_mgr/IRM */
if (is_from != should_be_from) {
data = data & ~IEEE1394_CSR_STATE_CMSTR;
}
mutex_enter(&hal->topology_tree_mutex);
/* DREQ bit - disabling DREQ can come from anyone */
if (data & IEEE1394_CSR_STATE_DREQ) {
hal->disable_requests_bit = 0;
if (hal->hal_state == S1394_HAL_DREQ)
hal->hal_state = S1394_HAL_NORMAL;
}
/* ABDICATE bit */
if (data & IEEE1394_CSR_STATE_ABDICATE) {
hal->abdicate_bus_mgr_bit = 0;
}
mutex_exit(&hal->topology_tree_mutex);
/*
* The csr_write() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. But although the STATE_CLEAR register
* is required to be implemented and writeable, we will
* return IEEE1394_RESP_ADDRESS_ERROR in the response if
* we ever see this error.
*/
result = HAL_CALL(hal).csr_write(hal->halinfo.hal_private,
offset, data);
if (result == DDI_SUCCESS) {
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
default:
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
}
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_state_clear_exit, S1394_TNF_SL_CSR_STACK,
"");
}
/*
* s1394_CSR_state_set()
* handles all requests to the STATE_SET CSR register. It enforces that
* certain bits that can be twiddled only by a given node (IRM or Bus
* Manager).
*/
static void
s1394_CSR_state_set(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
uint32_t data;
uint_t offset;
uint_t is_from;
uint_t should_be_from;
uint_t hal_node_num;
uint_t hal_number_of_nodes;
int result;
TNF_PROBE_0_DEBUG(s1394_CSR_state_set_enter, S1394_TNF_SL_CSR_STACK,
"");
hal = (s1394_hal_t *)req->cmd_callback_arg;
/* Register offset */
offset = req->cmd_addr & IEEE1394_CSR_OFFSET_MASK;
/* Verify that request is quadlet aligned */
if ((offset & 0x3) != 0) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_state_set_exit,
S1394_TNF_SL_CSR_STACK, "");
return;
}
/* Only writes from IRM or Bus Mgr allowed (in some cases) */
mutex_enter(&hal->topology_tree_mutex);
is_from = IEEE1394_NODE_NUM(req->nodeID);
if (hal->bus_mgr_node != -1)
should_be_from = IEEE1394_NODE_NUM(hal->bus_mgr_node);
else if (hal->IRM_node != -1)
should_be_from = IEEE1394_NODE_NUM(hal->IRM_node);
else
should_be_from = S1394_INVALID_NODE_NUM;
hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
hal_number_of_nodes = hal->number_of_nodes;
mutex_exit(&hal->topology_tree_mutex);
switch (req->cmd_type) {
case CMD1394_ASYNCH_WR_QUAD:
data = req->cmd_u.q.quadlet_data;
/* CMSTR bit - request must be from bus_mgr/IRM */
/* & must be root to have bit set */
if ((is_from != should_be_from) ||
(hal_node_num != (hal_number_of_nodes - 1))) {
data = data & ~IEEE1394_CSR_STATE_CMSTR;
}
mutex_enter(&hal->topology_tree_mutex);
/* DREQ bit - only bus_mgr/IRM can set this bit */
if (is_from != should_be_from) {
data = data & ~IEEE1394_CSR_STATE_DREQ;
} else if (data & IEEE1394_CSR_STATE_DREQ) {
hal->disable_requests_bit = 1;
if (hal->hal_state == S1394_HAL_NORMAL)
hal->hal_state = S1394_HAL_DREQ;
}
/* ABDICATE bit */
if (data & IEEE1394_CSR_STATE_ABDICATE) {
hal->abdicate_bus_mgr_bit = 1;
}
mutex_exit(&hal->topology_tree_mutex);
/*
* The csr_write() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. But although the STATE_SET register
* is required to be implemented and writeable, we will
* return IEEE1394_RESP_ADDRESS_ERROR in the response if
* we ever see this error.
*/
result = HAL_CALL(hal).csr_write(hal->halinfo.hal_private,
offset, data);
if (result == DDI_SUCCESS) {
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
default:
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
}
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_state_set_exit, S1394_TNF_SL_CSR_STACK,
"");
}
/*
* s1394_CSR_node_ids()
* handles all requests to the NODE_IDS CSR register. It passes all
* requests to the common routine - s1394_common_CSR_routine().
*/
static void
s1394_CSR_node_ids(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
TNF_PROBE_0_DEBUG(s1394_CSR_node_ids_enter, S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
s1394_common_CSR_routine(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_node_ids_exit, S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_reset_start()
* handles all requests to the RESET_START CSR register. Only write
* requests are legal, everything else gets a type_error response.
*/
static void
s1394_CSR_reset_start(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
uint32_t data;
uint_t offset;
TNF_PROBE_0_DEBUG(s1394_CSR_reset_start_enter, S1394_TNF_SL_CSR_STACK,
"");
hal = (s1394_hal_t *)req->cmd_callback_arg;
/* RESET_START register offset */
offset = req->cmd_addr & IEEE1394_CSR_OFFSET_MASK;
/* Verify that request is quadlet aligned */
if ((offset & 0x3) != 0) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_reset_start_exit,
S1394_TNF_SL_CSR_STACK, "");
return;
}
switch (req->cmd_type) {
case CMD1394_ASYNCH_WR_QUAD:
data = req->cmd_u.q.quadlet_data;
/*
* The csr_write() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. Because we don't do any thing with
* the RESET_START register we will ignore failures and
* return IEEE1394_RESP_COMPLETE regardless.
*/
(void) HAL_CALL(hal).csr_write(hal->halinfo.hal_private,
offset, data);
req->cmd_result = IEEE1394_RESP_COMPLETE;
break;
default:
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
}
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_reset_start_exit, S1394_TNF_SL_CSR_STACK,
"");
}
/*
* s1394_CSR_split_timeout()
* handles all requests to the SPLIT_TIMEOUT CSR register. It passes all
* requests to the common routine - s1394_common_CSR_routine().
*/
static void
s1394_CSR_split_timeout(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
TNF_PROBE_0_DEBUG(s1394_CSR_split_timeout_enter,
S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
s1394_common_CSR_routine(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_split_timeout_exit,
S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_argument_regs()
* handles all requests to the ARGUMENT CSR registers. It passes all
* requests to the common routine - s1394_common_CSR_routine().
*/
static void
s1394_CSR_argument_regs(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
TNF_PROBE_0_DEBUG(s1394_CSR_argument_regs_enter,
S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
s1394_common_CSR_routine(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_argument_regs_exit,
S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_test_regs()
* handles all requests to the TEST CSR registers. It passes all requests
* to the common routine - s1394_common_CSR_routine().
*/
static void
s1394_CSR_test_regs(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
uint_t offset;
TNF_PROBE_0_DEBUG(s1394_CSR_test_regs_enter,
S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
/* TEST register offset */
offset = req->cmd_addr & IEEE1394_CSR_OFFSET_MASK;
/* TEST_STATUS is Read-Only */
if ((offset == (IEEE1394_CSR_TEST_STATUS & IEEE1394_CSR_OFFSET_MASK)) &&
(req->cmd_type == CMD1394_ASYNCH_WR_QUAD)) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
} else {
s1394_common_CSR_routine(hal, req);
}
TNF_PROBE_0_DEBUG(s1394_CSR_test_regs_exit,
S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_interrupt_regs()
* handles all requests to the INTERRUPT CSR registers. It passes all
* requests to the common routine - s1394_common_CSR_routine().
*/
static void
s1394_CSR_interrupt_regs(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
TNF_PROBE_0_DEBUG(s1394_CSR_interrupt_regs_enter,
S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
s1394_common_CSR_routine(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_interrupt_regs_exit,
S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_clock_regs()
* handles all requests to the CLOCK CSR registers. It passes all
* requests to the common routine - s1394_common_CSR_routine().
*/
static void
s1394_CSR_clock_regs(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
TNF_PROBE_0_DEBUG(s1394_CSR_clock_regs_enter,
S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
s1394_common_CSR_routine(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_clock_regs_exit,
S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_message_regs()
* handles all requests to the MESSAGE CSR registers. It passes all
* requests to the common routine - s1394_common_CSR_routine().
*/
static void
s1394_CSR_message_regs(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
TNF_PROBE_0_DEBUG(s1394_CSR_message_regs_enter,
S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
s1394_common_CSR_routine(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_message_regs_exit,
S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_cycle_time()
* handles all requests to the CYCLE_TIME CSR register.
*/
static void
s1394_CSR_cycle_time(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
uint32_t data;
uint_t offset;
int result;
TNF_PROBE_0_DEBUG(s1394_CSR_cycle_time_enter,
S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
/* CYCLE_TIME register offset */
offset = req->cmd_addr & IEEE1394_CSR_OFFSET_MASK;
/* Verify that request is quadlet aligned */
if ((offset & 0x3) != 0) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_cycle_time_exit,
S1394_TNF_SL_CSR_STACK, "");
return;
}
switch (req->cmd_type) {
case CMD1394_ASYNCH_RD_QUAD:
/*
* The csr_read() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. But although the CYCLE_TIME register
* is required to be implemented on devices capable of
* providing isochronous services (like us), we will
* return IEEE1394_RESP_ADDRESS_ERROR in the response
* if we ever see this error.
*/
result = HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
offset, &data);
if (result == DDI_SUCCESS) {
req->cmd_u.q.quadlet_data = data;
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
case CMD1394_ASYNCH_WR_QUAD:
data = req->cmd_u.q.quadlet_data;
/*
* The csr_write() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. But although the CYCLE_TIME register
* is required to be implemented on devices capable of
* providing isochronous services (like us), the effects
* of a write are "node-dependent" so we will return
* IEEE1394_RESP_ADDRESS_ERROR in the response if we
* ever see this error.
*/
result = HAL_CALL(hal).csr_write(hal->halinfo.hal_private,
offset, data);
if (result == DDI_SUCCESS) {
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
default:
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
}
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_cycle_time_exit,
S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_bus_time()
* handles all requests to the BUS_TIME CSR register. It enforces that
* only a broadcast write request from the IRM or Bus Manager can change
* its value.
*/
static void
s1394_CSR_bus_time(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
uint32_t data;
uint_t offset;
uint_t is_from;
uint_t should_be_from;
int result;
TNF_PROBE_0_DEBUG(s1394_CSR_bus_time_enter, S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
/* BUS_TIME register offset */
offset = req->cmd_addr & IEEE1394_CSR_OFFSET_MASK;
/* Verify that request is quadlet aligned */
if ((offset & 0x3) != 0) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_bus_time_exit,
S1394_TNF_SL_CSR_STACK, "");
return;
}
switch (req->cmd_type) {
case CMD1394_ASYNCH_RD_QUAD:
/*
* The csr_read() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. But although the BUS_TIME register
* is required to be implemented by devices capable of
* being cycle master (like us), we will return
* IEEE1394_RESP_ADDRESS_ERROR in the response if we
* ever see this error.
*/
result = HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
offset, &data);
if (result == DDI_SUCCESS) {
req->cmd_u.q.quadlet_data = data;
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
case CMD1394_ASYNCH_WR_QUAD:
/* Only broadcast writes from IRM or Bus Mgr allowed */
mutex_enter(&hal->topology_tree_mutex);
is_from = IEEE1394_NODE_NUM(req->nodeID);
if (hal->bus_mgr_node != -1)
should_be_from = IEEE1394_NODE_NUM(hal->bus_mgr_node);
else if (hal->IRM_node != -1)
should_be_from = IEEE1394_NODE_NUM(hal->IRM_node);
else
should_be_from = S1394_INVALID_NODE_NUM;
mutex_exit(&hal->topology_tree_mutex);
if ((req->broadcast != 1) || (is_from != should_be_from)) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
break;
}
data = req->cmd_u.q.quadlet_data;
/*
* The csr_write() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. But although the BUS_TIME register
* is required to be implemented on devices capable of
* being cycle master (like us), we will return
* IEEE1394_RESP_ADDRESS_ERROR in the response if we
* ever see this error.
*/
result = HAL_CALL(hal).csr_write(hal->halinfo.hal_private,
offset, data);
if (result == DDI_SUCCESS) {
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
default:
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
}
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_bus_time_exit, S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_busy_timeout()
* handles all requests to the BUSY_TIMEOUT CSR register. It passes all
* requests to the common routine - s1394_common_CSR_routine().
*/
static void
s1394_CSR_busy_timeout(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
TNF_PROBE_0_DEBUG(s1394_CSR_busy_timeout_enter,
S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
s1394_common_CSR_routine(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_busy_timeout_exit,
S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_IRM_regs()
* handles all requests to the IRM registers, including BANDWIDTH_AVAILABLE,
* CHANNELS_AVAILABLE, and the BUS_MANAGER_ID. Only quadlet read and lock
* requests are allowed.
*/
static void
s1394_CSR_IRM_regs(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
uint32_t generation;
uint32_t data;
uint32_t compare;
uint32_t swap;
uint32_t old;
uint_t offset;
int result;
TNF_PROBE_0_DEBUG(s1394_CSR_IRM_regs_enter, S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
/* IRM register offset */
offset = (req->cmd_addr & IEEE1394_CSR_OFFSET_MASK);
/* Verify that request is quadlet aligned */
if ((offset & 0x3) != 0) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_IRM_regs_exit,
S1394_TNF_SL_CSR_STACK, "");
return;
}
switch (req->cmd_type) {
case CMD1394_ASYNCH_RD_QUAD:
/*
* The csr_read() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. In many cases these registers will
* have been implemented in HW. We are not likely to ever
* receive this callback. If we do, though, we will
* return IEEE1394_RESP_ADDRESS_ERROR when we get an error
* and IEEE1394_RESP_COMPLETE for success.
*/
result = HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
offset, &data);
if (result == DDI_SUCCESS) {
req->cmd_u.q.quadlet_data = data;
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
case CMD1394_ASYNCH_LOCK_32:
mutex_enter(&hal->topology_tree_mutex);
generation = hal->generation_count;
mutex_exit(&hal->topology_tree_mutex);
if (req->cmd_u.l32.lock_type == CMD1394_LOCK_COMPARE_SWAP) {
compare = req->cmd_u.l32.arg_value;
swap = req->cmd_u.l32.data_value;
/*
* The csr_cswap32() call can return DDI_FAILURE if
* the HAL is shutdown, if the register at "offset"
* is unimplemented, or if the generation has changed.
* In the last case, it shouldn't matter because the
* call to s1394_send_response will fail on a bad
* generation and the command will be freed.
*/
result = HAL_CALL(hal).csr_cswap32(
hal->halinfo.hal_private, generation,
offset, compare, swap, &old);
if (result == DDI_SUCCESS) {
req->cmd_u.l32.old_value = old;
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
} else {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
}
break;
default:
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
}
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_IRM_regs_exit, S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_topology_map()
* handles all request for the TOPOLOGY_MAP[]. Since it is implemented
* with backing store, there isn't much to do besides return success or
* failure.
*/
static void
s1394_CSR_topology_map(cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
TNF_PROBE_0_DEBUG(s1394_CSR_topology_map_enter,
S1394_TNF_SL_CSR_STACK, "");
hal = (s1394_hal_t *)req->cmd_callback_arg;
/* Make sure it's a quadlet read request */
if (req->cmd_type == CMD1394_ASYNCH_RD_QUAD)
req->cmd_result = IEEE1394_RESP_COMPLETE;
else
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_CSR_topology_map_exit,
S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_CSR_topology_map_update()
* is used to update the local host's TOPOLOGY_MAP[] buffer. It copies in
* the SelfID packets, updates the generation and other fields, and
* computes the necessary CRC values before returning.
* Callers must be holding the topology_tree_mutex.
*/
void
s1394_CSR_topology_map_update(s1394_hal_t *hal)
{
s1394_selfid_pkt_t *selfid_packet;
uint32_t *tm_ptr;
uint32_t *data_ptr;
uint32_t node_count;
uint32_t self_id_count;
uint_t CRC;
uint32_t length;
int i, j, c;
TNF_PROBE_0_DEBUG(s1394_CSR_topology_map_update_enter,
S1394_TNF_SL_BR_CSR_STACK, "");
ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
tm_ptr = (uint32_t *)hal->CSR_topology_map;
data_ptr = (uint32_t *)&(tm_ptr[3]);
c = 0;
for (i = 0; i < hal->number_of_nodes; i++) {
j = -1;
selfid_packet = hal->selfid_ptrs[i];
do {
j++;
data_ptr[c++] = selfid_packet[j].spkt_data;
}
while (IEEE1394_SELFID_ISMORE(&selfid_packet[j]));
}
/* Update Topology Map Generation */
tm_ptr[1] = tm_ptr[1] + 1;
/* Update Node_Count and Self_Id_Count */
node_count = (i & IEEE1394_TOP_MAP_LEN_MASK);
self_id_count = (c & IEEE1394_TOP_MAP_LEN_MASK);
tm_ptr[2] = (node_count << IEEE1394_TOP_MAP_LEN_SHIFT) |
(self_id_count);
/* Calculate CRC-16 */
length = self_id_count + 2;
CRC = s1394_CRC16(&(tm_ptr[1]), length);
tm_ptr[0] = (length << IEEE1394_TOP_MAP_LEN_SHIFT) | CRC;
TNF_PROBE_0_DEBUG(s1394_CSR_topology_map_update_exit,
S1394_TNF_SL_BR_CSR_STACK, "");
}
/*
* s1394_CSR_topology_map_disable()
* is used to disable the local host's TOPOLOGY_MAP[] buffer (during bus
* reset processing). It sets the topology map's length to zero to
* indicate that it is invalid.
*/
void
s1394_CSR_topology_map_disable(s1394_hal_t *hal)
{
uint32_t *tm_ptr;
TNF_PROBE_0_DEBUG(s1394_CSR_topology_map_disable_enter,
S1394_TNF_SL_BR_CSR_STACK, "");
ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
tm_ptr = (uint32_t *)hal->CSR_topology_map;
/* Set length = 0 */
tm_ptr[0] = tm_ptr[0] & IEEE1394_TOP_MAP_LEN_MASK;
TNF_PROBE_0_DEBUG(s1394_CSR_topology_map_disable_exit,
S1394_TNF_SL_BR_CSR_STACK, "");
}
/*
* s1394_common_CSR_routine()
* is used to handle most of the CSR register requests. They are passed
* to the appropriate HAL entry point for further processing. Then they
* are filled in with an appropriate response code, and the response is sent.
*/
static void
s1394_common_CSR_routine(s1394_hal_t *hal, cmd1394_cmd_t *req)
{
uint32_t data;
uint_t offset;
int result;
TNF_PROBE_0_DEBUG(s1394_common_CSR_routine_enter,
S1394_TNF_SL_CSR_STACK, "");
/* Register offset */
offset = (req->cmd_addr & IEEE1394_CSR_OFFSET_MASK);
/* Verify that request is quadlet aligned */
if ((offset & 0x3) != 0) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
}
switch (req->cmd_type) {
case CMD1394_ASYNCH_RD_QUAD:
/*
* The csr_read() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. We will return IEEE1394_RESP_ADDRESS_ERROR
* in the response if we see this error.
*/
result = HAL_CALL(hal).csr_read(hal->halinfo.hal_private,
offset, &data);
if (result == DDI_SUCCESS) {
req->cmd_u.q.quadlet_data = data;
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
case CMD1394_ASYNCH_WR_QUAD:
data = req->cmd_u.q.quadlet_data;
/*
* The csr_read() call can return DDI_FAILURE if the HAL
* is shutdown or if the register at "offset" is
* unimplemented. We will return IEEE1394_RESP_ADDRESS_ERROR
* in the response if we see this error.
*/
result = HAL_CALL(hal).csr_write(hal->halinfo.hal_private,
offset, data);
if (result == DDI_SUCCESS) {
req->cmd_result = IEEE1394_RESP_COMPLETE;
} else {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
}
break;
default:
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
}
(void) s1394_send_response(hal, req);
TNF_PROBE_0_DEBUG(s1394_common_CSR_routine_exit,
S1394_TNF_SL_CSR_STACK, "");
}
/*
* s1394_init_local_config_rom()
* is called in the HAL attach routine - h1394_attach() - to setup the
* initial Config ROM entries on the local host, including the
* bus_info_block and the root and unit directories.
*/
int
s1394_init_local_config_rom(s1394_hal_t *hal)
{
uint32_t *config_rom;
uint32_t *node_unique_id_leaf;
uint32_t *unit_dir;
uint32_t *text_leaf;
void *n_handle;
uint64_t guid;
uint32_t guid_hi, guid_lo;
uint32_t bus_capabilities;
uint32_t irmc, g;
uint32_t module_vendor_id;
uint32_t node_capabilities;
uint32_t root_dir_len;
uint32_t CRC;
int status, i, ret;
TNF_PROBE_0_DEBUG(s1394_init_local_config_rom_enter,
S1394_TNF_SL_CFGROM_STACK, "");
/* Setup Config ROM mutex */
mutex_init(&hal->local_config_rom_mutex,
NULL, MUTEX_DRIVER, hal->halinfo.hw_interrupt);
/* Allocate 1K for the Config ROM buffer */
hal->local_config_rom = (uint32_t *)kmem_zalloc(IEEE1394_CONFIG_ROM_SZ,
KM_SLEEP);
/* Allocate 1K for the temporary buffer */
hal->temp_config_rom_buf = (uint32_t *)kmem_zalloc(
IEEE1394_CONFIG_ROM_SZ, KM_SLEEP);
config_rom = hal->local_config_rom;
/* Lock the Config ROM buffer */
mutex_enter(&hal->local_config_rom_mutex);
/* Build the config ROM structures */
ret = s1394_init_config_rom_structures(hal);
if (ret != DDI_SUCCESS) {
/* Unlock the Config ROM buffer */
mutex_exit(&hal->local_config_rom_mutex);
kmem_free((void *)hal->temp_config_rom_buf,
IEEE1394_CONFIG_ROM_SZ);
kmem_free((void *)hal->local_config_rom,
IEEE1394_CONFIG_ROM_SZ);
mutex_destroy(&hal->local_config_rom_mutex);
TNF_PROBE_1(s1394_init_local_config_rom_error,
S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
"Failed in s1394_init_config_rom_structures()");
TNF_PROBE_0_DEBUG(s1394_init_local_config_rom_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_FAILURE);
}
/* Build the Bus_Info_Block - see IEEE 1394-1995, Section 8.3.2.5.4 */
bus_capabilities = hal->halinfo.bus_capabilities;
/*
* If we are Isoch Resource Manager capable then we are
* Bus Manager capable too.
*/
irmc = (bus_capabilities & IEEE1394_BIB_IRMC_MASK) >>
IEEE1394_BIB_IRMC_SHIFT;
if (irmc)
bus_capabilities = bus_capabilities | IEEE1394_BIB_BMC_MASK;
/*
* Set generation to P1394a valid (but changeable)
* Even if we have a 1995 PHY, we will still provide
* certain P1394A functionality (especially with respect
* to Config ROM updates). So we must publish this
* information.
*/
g = 2 << IEEE1394_BIB_GEN_SHIFT;
bus_capabilities = bus_capabilities | g;
/* Get the GUID */
guid = hal->halinfo.guid;
guid_hi = (uint32_t)(guid >> 32);
guid_lo = (uint32_t)(guid & 0x00000000FFFFFFFF);
config_rom[1] = 0x31333934; /* "1394" */
config_rom[2] = bus_capabilities;
config_rom[3] = guid_hi;
config_rom[4] = guid_lo;
/* The CRC covers only our Bus_Info_Block */
CRC = s1394_CRC16(&config_rom[1], 4);
config_rom[0] = (0x04040000) | CRC;
/* Do byte-swapping if necessary (x86) */
for (i = 0; i < IEEE1394_BIB_QUAD_SZ; i++)
config_rom[i] = T1394_DATA32(config_rom[i]);
/* Build the Root_Directory - see IEEE 1394-1995, Section 8.3.2.5.5 */
/* MODULE_VENDOR_ID - see IEEE 1394-1995, Section 8.3.2.5.5.1 */
module_vendor_id = S1394_SUNW_OUI;
/* NODE_CAPABILITIES - see IEEE 1394-1995, Section 8.3.2.5.5.2 */
node_capabilities = hal->halinfo.node_capabilities &
IEEE1212_NODE_CAPABILITIES_MASK;
root_dir_len = 2;
config_rom[6] = (IEEE1212_MODULE_VENDOR_ID <<
IEEE1212_KEY_VALUE_SHIFT) | module_vendor_id;
config_rom[7] = (IEEE1212_NODE_CAPABILITIES <<
IEEE1212_KEY_VALUE_SHIFT) | node_capabilities;
CRC = s1394_CRC16(&config_rom[6], root_dir_len);
config_rom[IEEE1394_BIB_QUAD_SZ] =
(root_dir_len << IEEE1394_CFG_ROM_LEN_SHIFT) | CRC;
/* Do byte-swapping if necessary (x86) */
for (i = IEEE1394_BIB_QUAD_SZ; i < 8; i++)
config_rom[i] = T1394_DATA32(config_rom[i]);
/* Build the Root Text leaf - see IEEE 1394-1995, Section 8.3.2.5.7 */
text_leaf = (uint32_t *)kmem_zalloc(S1394_ROOT_TEXT_LEAF_SZ, KM_SLEEP);
text_leaf[1] = 0x00000000;
text_leaf[2] = 0x00000000;
text_leaf[3] = 0x53756e20; /* "Sun " */
text_leaf[4] = 0x4d696372; /* "Micr" */
text_leaf[5] = 0x6f737973; /* "osys" */
text_leaf[6] = 0x74656d73; /* "tems" */
text_leaf[7] = 0x2c20496e; /* ", In" */
text_leaf[8] = 0x632e0000; /* "c." */
CRC = s1394_CRC16(&text_leaf[1], S1394_ROOT_TEXT_LEAF_QUAD_SZ - 1);
text_leaf[0] = (0x00080000) | CRC;
/* Do byte-swapping if necessary (x86) */
for (i = 0; i < 9; i++)
text_leaf[i] = T1394_DATA32(text_leaf[i]);
ret = s1394_add_config_rom_entry(hal, S1394_ROOT_TEXT_KEY, text_leaf,
S1394_ROOT_TEXT_LEAF_QUAD_SZ, &n_handle, &status);
if (ret != DDI_SUCCESS) {
kmem_free((void *)text_leaf, S1394_ROOT_TEXT_LEAF_SZ);
/* Destroy the config_rom structures */
(void) s1394_destroy_config_rom_structures(hal);
/* Unlock the Config ROM buffer */
mutex_exit(&hal->local_config_rom_mutex);
kmem_free((void *)hal->temp_config_rom_buf,
IEEE1394_CONFIG_ROM_SZ);
kmem_free((void *)hal->local_config_rom,
IEEE1394_CONFIG_ROM_SZ);
mutex_destroy(&hal->local_config_rom_mutex);
TNF_PROBE_1(s1394_init_local_config_rom_error,
S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
"Failure in kmem_zalloc");
TNF_PROBE_0_DEBUG(s1394_init_local_config_rom_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_FAILURE);
}
kmem_free((void *)text_leaf, S1394_ROOT_TEXT_LEAF_SZ);
/* Build the Node_Unique_Id leaf - IEEE 1394-1995, Sect. 8.3.2.5.7.1 */
node_unique_id_leaf = (uint32_t *)kmem_zalloc(S1394_NODE_UNIQUE_ID_SZ,
KM_SLEEP);
node_unique_id_leaf[1] = guid_hi;
node_unique_id_leaf[2] = guid_lo;
CRC = s1394_CRC16(&node_unique_id_leaf[1],
S1394_NODE_UNIQUE_ID_QUAD_SZ - 1);
node_unique_id_leaf[0] = (0x00020000) | CRC;
/* Do byte-swapping if necessary (x86) */
for (i = 0; i < S1394_NODE_UNIQUE_ID_QUAD_SZ; i++)
node_unique_id_leaf[i] = T1394_DATA32(node_unique_id_leaf[i]);
ret = s1394_add_config_rom_entry(hal, S1394_NODE_UNIQUE_ID_KEY,
node_unique_id_leaf, S1394_NODE_UNIQUE_ID_QUAD_SZ, &n_handle,
&status);
if (ret != DDI_SUCCESS) {
kmem_free((void *)node_unique_id_leaf,
S1394_NODE_UNIQUE_ID_SZ);
/* Destroy the config_rom structures */
(void) s1394_destroy_config_rom_structures(hal);
/* Unlock the Config ROM buffer */
mutex_exit(&hal->local_config_rom_mutex);
kmem_free((void *)hal->temp_config_rom_buf,
IEEE1394_CONFIG_ROM_SZ);
kmem_free((void *)hal->local_config_rom,
IEEE1394_CONFIG_ROM_SZ);
mutex_destroy(&hal->local_config_rom_mutex);
TNF_PROBE_1(s1394_init_local_config_rom_error,
S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
"Failure in kmem_zalloc");
TNF_PROBE_0_DEBUG(s1394_init_local_config_rom_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_FAILURE);
}
kmem_free((void *)node_unique_id_leaf, S1394_NODE_UNIQUE_ID_SZ);
/* Build the Unit_Directory for 1394 Framework */
unit_dir = (uint32_t *)kmem_zalloc(S1394_UNIT_DIR_SZ, KM_SLEEP);
unit_dir[1] = 0x12080020; /* Sun Microsystems */
unit_dir[2] = 0x13000001; /* Version 1 */
unit_dir[3] = 0x81000001; /* offset to the text leaf */
CRC = s1394_CRC16(&unit_dir[1], 3);
unit_dir[0] = (0x00030000) | CRC;
/* Do byte-swapping if necessary (x86) */
for (i = 0; i < 4; i++)
unit_dir[i] = T1394_DATA32(unit_dir[i]);
/* Build the Unit Directory text leaf */
unit_dir[5] = 0x00000000;
unit_dir[6] = 0x00000000;
unit_dir[7] = 0x536f6c61; /* "Sola" */
unit_dir[8] = 0x72697320; /* "ris " */
unit_dir[9] = 0x31333934; /* "1394" */
unit_dir[10] = 0x20535720; /* " SW " */
unit_dir[11] = 0x4672616d; /* "Fram" */
unit_dir[12] = 0x65576f72; /* "ewor" */
unit_dir[13] = 0x6b000000; /* "k" */
CRC = s1394_CRC16(&unit_dir[5], 9);
unit_dir[4] = (0x00090000) | CRC;
/* Do byte-swapping if necessary (x86) */
for (i = 4; i < S1394_UNIT_DIR_QUAD_SZ; i++)
unit_dir[i] = T1394_DATA32(unit_dir[i]);
ret = s1394_add_config_rom_entry(hal, S1394_UNIT_DIR_KEY, unit_dir,
S1394_UNIT_DIR_QUAD_SZ, &n_handle, &status);
if (ret != DDI_SUCCESS) {
kmem_free((void *)unit_dir, S1394_UNIT_DIR_SZ);
/* Destroy the config_rom structures */
(void) s1394_destroy_config_rom_structures(hal);
/* Unlock the Config ROM buffer */
mutex_exit(&hal->local_config_rom_mutex);
kmem_free((void *)hal->temp_config_rom_buf,
IEEE1394_CONFIG_ROM_SZ);
/* Free the 1K for the Config ROM buffer */
kmem_free((void *)hal->local_config_rom,
IEEE1394_CONFIG_ROM_SZ);
mutex_destroy(&hal->local_config_rom_mutex);
TNF_PROBE_1(s1394_init_local_config_rom_error,
S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
"Failure in kmem_zalloc");
TNF_PROBE_0_DEBUG(s1394_init_local_config_rom_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_FAILURE);
}
kmem_free((void *)unit_dir, S1394_UNIT_DIR_SZ);
hal->config_rom_update_amount = (IEEE1394_CONFIG_ROM_QUAD_SZ -
hal->free_space);
/* Unlock the Config ROM buffer */
mutex_exit(&hal->local_config_rom_mutex);
/*
* The update_config_rom() call can return DDI_FAILURE if the
* HAL is shutdown.
*/
(void) HAL_CALL(hal).update_config_rom(hal->halinfo.hal_private,
config_rom, IEEE1394_CONFIG_ROM_QUAD_SZ);
TNF_PROBE_0_DEBUG(s1394_init_local_config_rom_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_SUCCESS);
}
/*
* s1394_destroy_local_config_rom()
* is necessary for h1394_detach(). It undoes all the work that
* s1394_init_local_config_rom() had setup and more. By pulling
* everything out of the conig rom structures and freeing them and their
* associated mutexes, the Config ROM is completely cleaned up.
*/
void
s1394_destroy_local_config_rom(s1394_hal_t *hal)
{
TNF_PROBE_0_DEBUG(s1394_destroy_local_config_rom_enter,
S1394_TNF_SL_CFGROM_STACK, "");
/* Lock the Config ROM buffer */
mutex_enter(&hal->local_config_rom_mutex);
/* Destroy the config_rom structures */
(void) s1394_destroy_config_rom_structures(hal);
/* Unlock the Config ROM buffer */
mutex_exit(&hal->local_config_rom_mutex);
/* Free the 1K for the temporary buffer */
kmem_free((void *)hal->temp_config_rom_buf, IEEE1394_CONFIG_ROM_SZ);
/* Free the 1K for the Config ROM buffer */
kmem_free((void *)hal->local_config_rom, IEEE1394_CONFIG_ROM_SZ);
/* Setup Config ROM mutex */
mutex_destroy(&hal->local_config_rom_mutex);
TNF_PROBE_0_DEBUG(s1394_destroy_local_config_rom_exit,
S1394_TNF_SL_CFGROM_STACK, "");
}
/*
* s1394_init_config_rom_structures()
* initializes the structures that are used to maintain the local Config ROM.
* Callers must be holding the local_config_rom_mutex.
*/
static int
s1394_init_config_rom_structures(s1394_hal_t *hal)
{
s1394_config_rom_t *root_directory;
s1394_config_rom_t *rest_of_config_rom;
TNF_PROBE_0_DEBUG(s1394_init_config_rom_structures_enter,
S1394_TNF_SL_CFGROM_STACK, "");
ASSERT(MUTEX_HELD(&hal->local_config_rom_mutex));
root_directory = (s1394_config_rom_t *)kmem_zalloc(
sizeof (s1394_config_rom_t), KM_SLEEP);
root_directory->cfgrom_used = B_TRUE;
root_directory->cfgrom_addr_lo = IEEE1394_BIB_QUAD_SZ;
root_directory->cfgrom_addr_hi = IEEE1394_BIB_QUAD_SZ + 2;
rest_of_config_rom = (s1394_config_rom_t *)kmem_zalloc(
sizeof (s1394_config_rom_t), KM_SLEEP);
rest_of_config_rom->cfgrom_used = B_FALSE;
rest_of_config_rom->cfgrom_addr_lo = root_directory->cfgrom_addr_hi + 1;
rest_of_config_rom->cfgrom_addr_hi = IEEE1394_CONFIG_ROM_QUAD_SZ - 1;
root_directory->cfgrom_next = rest_of_config_rom;
root_directory->cfgrom_prev = NULL;
rest_of_config_rom->cfgrom_next = NULL;
rest_of_config_rom->cfgrom_prev = root_directory;
hal->root_directory = root_directory;
hal->free_space = IEEE1394_CONFIG_ROM_QUAD_SZ -
(rest_of_config_rom->cfgrom_addr_lo);
TNF_PROBE_0_DEBUG(s1394_init_config_rom_structures_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_SUCCESS);
}
/*
* s1394_destroy_config_rom_structures()
* is used to destroy the structures that maintain the local Config ROM.
* Callers must be holding the local_config_rom_mutex.
*/
static int
s1394_destroy_config_rom_structures(s1394_hal_t *hal)
{
s1394_config_rom_t *curr_blk;
s1394_config_rom_t *next_blk;
TNF_PROBE_0_DEBUG(s1394_destroy_config_rom_structures_enter,
S1394_TNF_SL_CFGROM_STACK, "");
ASSERT(MUTEX_HELD(&hal->local_config_rom_mutex));
curr_blk = hal->root_directory;
while (curr_blk != NULL) {
next_blk = curr_blk->cfgrom_next;
kmem_free(curr_blk, sizeof (s1394_config_rom_t));
curr_blk = next_blk;
}
TNF_PROBE_0_DEBUG(s1394_destroy_config_rom_structures_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_SUCCESS);
}
/*
* s1394_add_config_rom_entry()
* is used to add a new entry to the local host's config ROM. By
* specifying a key and a buffer, it is possible to update the Root
* Directory to point to the new entry (in buffer). Additionally, all
* of the relevant CRCs, lengths, and generations are updated as well.
* By returning a Config ROM "handle", we can allow targets to remove
* the corresponding entry.
* Callers must be holding the local_config_rom_mutex.
*/
int
s1394_add_config_rom_entry(s1394_hal_t *hal, uint8_t key, uint32_t *buffer,
uint_t size, void **handle, int *status)
{
s1394_config_rom_t *curr_blk;
s1394_config_rom_t *new_blk;
uint32_t *config_rom;
uint32_t *temp_buf;
uint32_t CRC;
uint_t tmp_offset;
uint_t tmp_size, temp;
uint_t last_entry_offset;
int i;
TNF_PROBE_0_DEBUG(s1394_add_config_rom_entry_enter,
"stacktrace 1394 s1394", "");
ASSERT(MUTEX_HELD(&hal->local_config_rom_mutex));
if (size > hal->free_space) {
/* Out of space */
*status = CMD1394_ERSRC_CONFLICT;
TNF_PROBE_0_DEBUG(s1394_add_config_rom_entry_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_FAILURE);
}
config_rom = hal->local_config_rom;
temp_buf = hal->temp_config_rom_buf;
/* Copy the Bus_Info_Block */
bcopy(&config_rom[0], &temp_buf[0], IEEE1394_BIB_SZ);
/* Copy and add to the Root_Directory */
tmp_offset = hal->root_directory->cfgrom_addr_lo;
tmp_size = (hal->root_directory->cfgrom_addr_hi - tmp_offset) + 1;
tmp_size = tmp_size + 1; /* For the new entry */
bcopy(&config_rom[tmp_offset], &temp_buf[tmp_offset], tmp_size << 2);
last_entry_offset = hal->root_directory->cfgrom_addr_hi + 1;
curr_blk = hal->root_directory;
curr_blk->cfgrom_addr_hi = curr_blk->cfgrom_addr_hi + 1;
while (curr_blk->cfgrom_next != NULL) {
if (curr_blk->cfgrom_next->cfgrom_used == B_TRUE) {
tmp_offset = curr_blk->cfgrom_next->cfgrom_addr_lo;
tmp_size = (curr_blk->cfgrom_next->cfgrom_addr_hi -
tmp_offset) + 1;
bcopy(&config_rom[tmp_offset],
&temp_buf[tmp_offset + 1], tmp_size << 2);
curr_blk->cfgrom_next->cfgrom_addr_lo++;
curr_blk->cfgrom_next->cfgrom_addr_hi++;
last_entry_offset =
curr_blk->cfgrom_next->cfgrom_addr_hi;
tmp_offset = curr_blk->cfgrom_next->root_dir_offset;
/* Swap... add one... then unswap */
temp = T1394_DATA32(temp_buf[tmp_offset]);
temp++;
temp_buf[tmp_offset] = T1394_DATA32(temp);
} else {
curr_blk->cfgrom_next->cfgrom_addr_lo++;
hal->free_space--;
break;
}
curr_blk = curr_blk->cfgrom_next;
}
/* Get the pointer to the "free" space */
curr_blk = curr_blk->cfgrom_next;
/* Is it an exact fit? */
if (hal->free_space == size) {
curr_blk->cfgrom_used = B_TRUE;
} else { /* Must break this piece */
new_blk = (s1394_config_rom_t *)kmem_zalloc(
sizeof (s1394_config_rom_t), KM_SLEEP);
if (new_blk == NULL) {
TNF_PROBE_0_DEBUG(s1394_add_config_rom_entry_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_FAILURE);
}
new_blk->cfgrom_addr_hi = curr_blk->cfgrom_addr_hi;
new_blk->cfgrom_addr_lo = curr_blk->cfgrom_addr_lo + size;
curr_blk->cfgrom_addr_hi = new_blk->cfgrom_addr_lo - 1;
new_blk->cfgrom_next = curr_blk->cfgrom_next;
curr_blk->cfgrom_next = new_blk;
new_blk->cfgrom_prev = curr_blk;
curr_blk->cfgrom_used = B_TRUE;
last_entry_offset = curr_blk->cfgrom_addr_hi;
}
hal->free_space = hal->free_space - size;
/* Copy in the new entry */
tmp_offset = curr_blk->cfgrom_addr_lo;
bcopy(buffer, &temp_buf[tmp_offset], size << 2);
/* Update root directory */
tmp_offset = hal->root_directory->cfgrom_addr_hi;
tmp_size = tmp_offset - hal->root_directory->cfgrom_addr_lo;
curr_blk->root_dir_offset = tmp_offset;
tmp_offset = curr_blk->cfgrom_addr_lo - tmp_offset;
temp_buf[hal->root_directory->cfgrom_addr_hi] =
T1394_DATA32((((uint32_t)key) << IEEE1212_KEY_VALUE_SHIFT) |
tmp_offset);
tmp_offset = hal->root_directory->cfgrom_addr_lo;
/* Do byte-swapping if necessary (x86) */
for (i = (tmp_offset + 1); i <= hal->root_directory->cfgrom_addr_hi;
i++)
temp_buf[i] = T1394_DATA32(temp_buf[i]);
CRC = s1394_CRC16(&temp_buf[tmp_offset + 1], tmp_size);
temp_buf[tmp_offset] = (tmp_size << IEEE1394_CFG_ROM_LEN_SHIFT) | CRC;
/* Redo byte-swapping if necessary (x86) */
for (i = tmp_offset; i <= hal->root_directory->cfgrom_addr_hi; i++)
temp_buf[i] = T1394_DATA32(temp_buf[i]);
/* Copy it back to config_rom buffer */
last_entry_offset++;
bcopy(&temp_buf[0], &config_rom[0], last_entry_offset << 2);
/* Return a handle to this block */
*handle = curr_blk;
*status = T1394_NOERROR;
TNF_PROBE_0_DEBUG(s1394_add_config_rom_entry_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_SUCCESS);
}
/*
* s1394_remove_config_rom_entry()
* is used to remove an entry from the local host's config ROM. By
* specifying the Config ROM "handle" that was given in the allocation,
* it is possible to remove the entry. Subsequently, the Config ROM is
* updated again.
* Callers must be holding the local_config_rom_mutex.
*/
int
s1394_remove_config_rom_entry(s1394_hal_t *hal, void **handle, int *status)
{
s1394_config_rom_t *del_blk;
s1394_config_rom_t *curr_blk;
s1394_config_rom_t *last_blk;
s1394_config_rom_t *free_blk;
uint32_t *config_rom;
uint32_t *temp_buf;
uint32_t entry;
uint_t CRC;
uint_t root_offset;
uint_t del_offset;
uint_t tmp_offset;
uint_t tmp_size;
int i;
TNF_PROBE_0_DEBUG(s1394_remove_config_rom_entry_enter,
S1394_TNF_SL_CFGROM_STACK, "");
ASSERT(MUTEX_HELD(&hal->local_config_rom_mutex));
del_blk = (s1394_config_rom_t *)(*handle);
config_rom = hal->local_config_rom;
temp_buf = hal->temp_config_rom_buf;
/* Copy the Bus_Info_Block */
bcopy(&config_rom[0], &temp_buf[0], IEEE1394_BIB_SZ);
root_offset = hal->root_directory->cfgrom_addr_lo;
del_offset = del_blk->root_dir_offset;
/* Update Root_Directory entries before the deleted one */
for (i = root_offset; i < del_offset; i++) {
entry = T1394_DATA32(config_rom[i]);
/* If entry is an offset address - update it */
if (entry & 0x80000000)
temp_buf[i] = T1394_DATA32(entry - 1);
else
temp_buf[i] = T1394_DATA32(entry);
}
/* Move all Unit_Directories prior to the deleted one */
curr_blk = hal->root_directory->cfgrom_next;
while (curr_blk != del_blk) {
tmp_offset = curr_blk->cfgrom_addr_lo;
tmp_size = (curr_blk->cfgrom_addr_hi - tmp_offset) + 1;
bcopy(&config_rom[tmp_offset], &temp_buf[tmp_offset - 1],
tmp_size << 2);
curr_blk->cfgrom_addr_lo--;
curr_blk->cfgrom_addr_hi--;
curr_blk = curr_blk->cfgrom_next;
}
/* Move all Unit_Directories after the deleted one */
curr_blk = del_blk->cfgrom_next;
last_blk = del_blk->cfgrom_prev;
del_offset = (del_blk->cfgrom_addr_hi - del_blk->cfgrom_addr_lo) + 1;
while ((curr_blk != NULL) && (curr_blk->cfgrom_used == B_TRUE)) {
tmp_offset = curr_blk->cfgrom_addr_lo;
tmp_size = (curr_blk->cfgrom_addr_hi - tmp_offset) + 1;
bcopy(&config_rom[tmp_offset],
&temp_buf[tmp_offset - (del_offset + 1)], tmp_size << 2);
root_offset = curr_blk->root_dir_offset;
temp_buf[root_offset - 1] =
config_rom[root_offset] - del_offset;
curr_blk->root_dir_offset--;
curr_blk->cfgrom_addr_lo = curr_blk->cfgrom_addr_lo -
(del_offset + 1);
curr_blk->cfgrom_addr_hi = curr_blk->cfgrom_addr_hi -
(del_offset + 1);
last_blk = curr_blk;
curr_blk = curr_blk->cfgrom_next;
}
/* Remove del_blk from the list */
if (del_blk->cfgrom_prev != NULL)
del_blk->cfgrom_prev->cfgrom_next = del_blk->cfgrom_next;
if (del_blk->cfgrom_next != NULL)
del_blk->cfgrom_next->cfgrom_prev = del_blk->cfgrom_prev;
del_blk->cfgrom_prev = NULL;
del_blk->cfgrom_next = NULL;
kmem_free((void *)del_blk, sizeof (s1394_config_rom_t));
/* Update and zero out the "free" block */
if (curr_blk != NULL) {
curr_blk->cfgrom_addr_lo = curr_blk->cfgrom_addr_lo -
(del_offset + 1);
} else {
free_blk = (s1394_config_rom_t *)kmem_zalloc(
sizeof (s1394_config_rom_t), KM_SLEEP);
if (free_blk == NULL) {
TNF_PROBE_0_DEBUG(s1394_remove_config_rom_entry_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_FAILURE);
}
free_blk->cfgrom_used = B_FALSE;
free_blk->cfgrom_addr_lo = (IEEE1394_CONFIG_ROM_QUAD_SZ - 1) -
(del_offset + 1);
free_blk->cfgrom_addr_hi = (IEEE1394_CONFIG_ROM_QUAD_SZ - 1);
free_blk->cfgrom_prev = last_blk;
free_blk->cfgrom_next = NULL;
curr_blk = free_blk;
}
hal->free_space = hal->free_space + (del_offset + 1);
tmp_offset = curr_blk->cfgrom_addr_lo;
tmp_size = (curr_blk->cfgrom_addr_hi - tmp_offset) + 1;
bzero(&temp_buf[tmp_offset], tmp_size << 2);
/* Update root directory */
hal->root_directory->cfgrom_addr_hi--;
tmp_offset = hal->root_directory->cfgrom_addr_lo;
tmp_size = hal->root_directory->cfgrom_addr_hi - tmp_offset;
/* Do byte-swapping if necessary (x86) */
for (i = (tmp_offset + 1); i <= hal->root_directory->cfgrom_addr_hi;
i++)
temp_buf[i] = T1394_DATA32(temp_buf[i]);
CRC = s1394_CRC16(&temp_buf[tmp_offset + 1], tmp_size);
temp_buf[tmp_offset] = (tmp_size << IEEE1394_CFG_ROM_LEN_SHIFT) | CRC;
/* Do byte-swapping if necessary (x86) */
for (i = (tmp_offset + 1); i <= hal->root_directory->cfgrom_addr_hi;
i++)
temp_buf[i] = T1394_DATA32(temp_buf[i]);
/* Copy it back to config_rom buffer */
tmp_size = IEEE1394_CONFIG_ROM_SZ - (hal->free_space << 2);
bcopy(&temp_buf[0], &config_rom[0], tmp_size);
/* Return a handle to this block */
*handle = NULL;
*status = T1394_NOERROR;
TNF_PROBE_0_DEBUG(s1394_remove_config_rom_entry_exit,
S1394_TNF_SL_CFGROM_STACK, "");
return (DDI_SUCCESS);
}
/*
* s1394_update_config_rom_callback()
* is the callback used by t1394_add_cfgrom_entry() and
* t1394_rem_cfgrom_entry(). After a target updates the Config ROM, a
* timer is set with this as its callback function. This is to reduce
* the number of bus resets that would be necessary if many targets
* wished to update the Config ROM simultaneously.
*/
void
s1394_update_config_rom_callback(void *arg)
{
s1394_hal_t *hal;
uint32_t *config_rom;
uint32_t bus_capabilities;
uint32_t g;
uint_t CRC;
uint_t last_entry_offset;
int i, ret;
TNF_PROBE_0_DEBUG(s1394_update_config_rom_callback_enter,
S1394_TNF_SL_CFGROM_STACK, "");
hal = (s1394_hal_t *)arg;
/* Lock the Config ROM buffer */
mutex_enter(&hal->local_config_rom_mutex);
config_rom = hal->local_config_rom;
/* Update Generation and CRC for Bus_Info_Block */
/* Do byte-swapping if necessary (x86) */
for (i = 0; i < IEEE1394_BIB_QUAD_SZ; i++)
config_rom[i] = T1394_DATA32(config_rom[i]);
bus_capabilities = config_rom[IEEE1212_NODE_CAP_QUAD];
g = ((bus_capabilities & IEEE1394_BIB_GEN_MASK) >>
IEEE1394_BIB_GEN_SHIFT) + 1;
if (g > 15)
g = 2;
g = g << IEEE1394_BIB_GEN_SHIFT;
bus_capabilities = (bus_capabilities & (~IEEE1394_BIB_GEN_MASK)) | g;
config_rom[IEEE1212_NODE_CAP_QUAD] = bus_capabilities;
CRC = s1394_CRC16(&config_rom[1], IEEE1394_BIB_QUAD_SZ - 1);
config_rom[0] = (0x04040000) | CRC;
/* Do byte-swapping if necessary (x86) */
for (i = 0; i < IEEE1394_BIB_QUAD_SZ; i++)
config_rom[i] = T1394_DATA32(config_rom[i]);
/* Make sure we update only what is necessary */
last_entry_offset = (IEEE1394_CONFIG_ROM_QUAD_SZ - hal->free_space);
if (last_entry_offset < hal->config_rom_update_amount)
last_entry_offset = hal->config_rom_update_amount;
hal->config_rom_update_amount = (IEEE1394_CONFIG_ROM_QUAD_SZ -
hal->free_space);
/* Clear the timer flag */
hal->config_rom_timer_set = B_FALSE;
/* Unlock the Config ROM buffer */
mutex_exit(&hal->local_config_rom_mutex);
/*
* The update_config_rom() call can return DDI_FAILURE if the
* HAL is shutdown.
*/
(void) HAL_CALL(hal).update_config_rom(hal->halinfo.hal_private,\
config_rom, last_entry_offset);
/* Initiate a bus reset */
ret = HAL_CALL(hal).bus_reset(hal->halinfo.hal_private);
if (ret != DDI_SUCCESS) {
TNF_PROBE_1(s1394_update_config_rom_callback_error,
S1394_TNF_SL_ERROR, "", tnf_string, msg,
"Error initiating bus reset");
}
TNF_PROBE_0_DEBUG(s1394_update_config_rom_callback_exit,
S1394_TNF_SL_CFGROM_STACK, "");
}