#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/sunndi.h>
#include <sys/cmn_err.h>
#include <sys/types.h>
#include <sys/kmem.h>
#include <sys/thread.h>
#include <sys/proc.h>
#include <sys/disp.h>
#include <sys/time.h>
#include <sys/devctl.h>
#include <sys/1394/t1394.h>
#include <sys/1394/s1394.h>
#include <sys/1394/h1394.h>
#include <sys/1394/ieee1394.h>
extern struct bus_ops nx1394_busops;
extern int nx1394_define_events(s1394_hal_t *hal);
extern void nx1394_undefine_events(s1394_hal_t *hal);
extern int s1394_ignore_invalid_gap_cnt;
int
h1394_init(struct modlinkage *modlp)
{
struct dev_ops *devops;
devops = ((struct modldrv *)(modlp->ml_linkage[0]))->drv_dev_ops;
devops->devo_bus_ops = &nx1394_busops;
return (0);
}
void
h1394_fini(struct modlinkage *modlp)
{
struct dev_ops *devops;
devops = ((struct modldrv *)(modlp->ml_linkage[0]))->drv_dev_ops;
devops->devo_bus_ops = NULL;
}
int
h1394_attach(h1394_halinfo_t *halinfo, ddi_attach_cmd_t cmd, void **sl_private)
{
s1394_hal_t *hal;
int ret;
char buf[32];
uint_t cmd_size;
ASSERT(sl_private != NULL);
if (cmd == DDI_RESUME) {
hal = (s1394_hal_t *)(*sl_private);
if (hal->halinfo.phy == H1394_PHY_1394A)
(void) HAL_CALL(hal).set_contender_bit(
hal->halinfo.hal_private);
return (DDI_SUCCESS);
} else if (cmd != DDI_ATTACH) {
return (DDI_FAILURE);
}
hal = kmem_zalloc(sizeof (s1394_hal_t), KM_SLEEP);
hal->hal_state = S1394_HAL_INIT;
hal->halinfo = *halinfo;
mutex_init(&hal->topology_tree_mutex, NULL, MUTEX_DRIVER,
hal->halinfo.hw_interrupt);
mutex_init(&hal->cm_timer_mutex, NULL, MUTEX_DRIVER,
hal->halinfo.hw_interrupt);
hal->isoch_cec_list_head = NULL;
hal->isoch_cec_list_tail = NULL;
mutex_init(&hal->isoch_cec_list_mutex, NULL, MUTEX_DRIVER,
hal->halinfo.hw_interrupt);
mutex_init(&hal->bus_mgr_node_mutex, NULL, MUTEX_DRIVER,
hal->halinfo.hw_interrupt);
cv_init(&hal->bus_mgr_node_cv, NULL, CV_DRIVER,
hal->halinfo.hw_interrupt);
hal->bus_mgr_node = -1;
hal->incumbent_bus_mgr = B_FALSE;
hal->target_head = NULL;
hal->target_tail = NULL;
rw_init(&hal->target_list_rwlock, NULL, RW_DRIVER,
hal->halinfo.hw_interrupt);
hal->outstanding_q_head = NULL;
hal->outstanding_q_tail = NULL;
mutex_init(&hal->outstanding_q_mutex, NULL, MUTEX_DRIVER,
hal->halinfo.hw_interrupt);
hal->pending_q_head = NULL;
hal->pending_q_tail = NULL;
mutex_init(&hal->pending_q_mutex, NULL, MUTEX_DRIVER,
hal->halinfo.hw_interrupt);
(void) sprintf(buf, "hal%d_cache", ddi_get_instance(hal->halinfo.dip));
cmd_size = sizeof (cmd1394_cmd_t) + sizeof (s1394_cmd_priv_t) +
hal->halinfo.hal_overhead;
hal->hal_kmem_cachep = kmem_cache_create(buf, cmd_size, 8, NULL, NULL,
NULL, NULL, NULL, 0);
ret = nx1394_define_events(hal);
if (ret != DDI_SUCCESS) {
s1394_cleanup_for_detach(hal, H1394_CLEANUP_LEVEL0);
return (DDI_FAILURE);
}
mutex_init(&hal->br_thread_mutex, NULL, MUTEX_DRIVER,
hal->halinfo.hw_interrupt);
cv_init(&hal->br_thread_cv, NULL, CV_DRIVER, hal->halinfo.hw_interrupt);
mutex_init(&hal->br_cmplq_mutex, NULL, MUTEX_DRIVER,
hal->halinfo.hw_interrupt);
cv_init(&hal->br_cmplq_cv, NULL, CV_DRIVER, hal->halinfo.hw_interrupt);
hal->br_thread = thread_create((caddr_t)NULL, 0, s1394_br_thread,
hal, 0, &p0, TS_RUN, minclsyspri);
hal->number_of_nodes = 0;
hal->num_bus_reset_till_fail = NUM_BR_FAIL;
hal->current_buffer = 0;
hal->selfid_buf0 = kmem_zalloc(S1394_SELFID_BUF_SIZE, KM_SLEEP);
hal->selfid_buf1 = kmem_zalloc(S1394_SELFID_BUF_SIZE, KM_SLEEP);
ret = s1394_kstat_init(hal);
if (ret != DDI_SUCCESS) {
s1394_cleanup_for_detach(hal, H1394_CLEANUP_LEVEL3);
return (DDI_FAILURE);
}
hal->hal_kstats->guid = hal->halinfo.guid;
hal->old_tree = &hal->last_valid_tree[0];
hal->topology_tree = &hal->current_tree[0];
ret = s1394_init_local_config_rom(hal);
if (ret != DDI_SUCCESS) {
s1394_cleanup_for_detach(hal, H1394_CLEANUP_LEVEL4);
return (DDI_FAILURE);
}
ret = s1394_init_addr_space(hal);
if (ret != DDI_SUCCESS) {
s1394_cleanup_for_detach(hal, H1394_CLEANUP_LEVEL5);
return (DDI_FAILURE);
}
ret = s1394_fcp_hal_init(hal);
if (ret != DDI_SUCCESS) {
s1394_cleanup_for_detach(hal, H1394_CLEANUP_LEVEL6);
return (DDI_FAILURE);
}
hal->IRM_node = -1;
if (hal->halinfo.phy == H1394_PHY_1394A)
(void) HAL_CALL(hal).set_contender_bit(
hal->halinfo.hal_private);
mutex_enter(&s1394_statep->hal_list_mutex);
if ((s1394_statep->hal_head == NULL) &&
(s1394_statep->hal_tail == NULL)) {
s1394_statep->hal_head = hal;
s1394_statep->hal_tail = hal;
} else {
s1394_statep->hal_tail->hal_next = hal;
hal->hal_prev = s1394_statep->hal_tail;
s1394_statep->hal_tail = hal;
}
mutex_exit(&s1394_statep->hal_list_mutex);
*sl_private = (void *)hal;
return (DDI_SUCCESS);
}
int
h1394_detach(void **sl_private, ddi_detach_cmd_t cmd)
{
s1394_hal_t *hal;
hal = (s1394_hal_t *)(*sl_private);
switch (cmd) {
case DDI_DETACH:
s1394_cleanup_for_detach(hal, H1394_CLEANUP_LEVEL7);
*sl_private = NULL;
break;
case DDI_SUSPEND:
s1394_destroy_timers(hal);
hal->hal_was_suspended = B_TRUE;
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
h1394_alloc_cmd(void *sl_private, uint_t flags, cmd1394_cmd_t **cmdp,
h1394_cmd_priv_t **hal_priv_ptr)
{
s1394_hal_t *hal;
s1394_cmd_priv_t *s_priv;
hal = (s1394_hal_t *)sl_private;
if (s1394_alloc_cmd(hal, flags, cmdp) != DDI_SUCCESS) {
return (DDI_FAILURE);
}
s_priv = S1394_GET_CMD_PRIV(*cmdp);
*hal_priv_ptr = &s_priv->hal_cmd_private;
return (DDI_SUCCESS);
}
int
h1394_free_cmd(void *sl_private, cmd1394_cmd_t **cmdp)
{
s1394_hal_t *hal;
s1394_cmd_priv_t *s_priv;
hal = (s1394_hal_t *)sl_private;
s_priv = S1394_GET_CMD_PRIV(*cmdp);
if (s_priv->cmd_in_use == B_TRUE) {
ASSERT(s_priv->cmd_in_use == B_FALSE);
return (DDI_FAILURE);
}
kmem_cache_free(hal->hal_kmem_cachep, *cmdp);
*cmdp = NULL;
hal->hal_kstats->cmd_free++;
return (DDI_SUCCESS);
}
void
h1394_cmd_is_complete(void *sl_private, cmd1394_cmd_t *command_id,
uint32_t cmd_type, int status)
{
s1394_hal_t *hal;
dev_info_t *dip;
hal = (s1394_hal_t *)sl_private;
switch (cmd_type) {
case H1394_AT_REQ:
s1394_atreq_cmd_complete(hal, command_id, status);
break;
case H1394_AT_RESP:
s1394_atresp_cmd_complete(hal, command_id, status);
break;
default:
dip = hal->halinfo.dip;
cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
ddi_node_name(dip), ddi_get_instance(dip));
s1394_hal_shutdown(hal, B_TRUE);
break;
}
}
void
h1394_bus_reset(void *sl_private, void **selfid_buf_addr)
{
s1394_hal_t *hal;
hal = (s1394_hal_t *)sl_private;
mutex_enter(&hal->topology_tree_mutex);
if (hal->hal_state != S1394_HAL_SHUTDOWN) {
hal->hal_state = S1394_HAL_RESET;
} else {
mutex_exit(&hal->topology_tree_mutex);
return;
}
if (hal->initiated_bus_reset == B_TRUE) {
hal->initiated_bus_reset = B_FALSE;
if (hal->num_bus_reset_till_fail > 0) {
hal->num_bus_reset_till_fail--;
}
} else {
hal->num_bus_reset_till_fail = NUM_BR_FAIL;
}
hal->IRM_node = -1;
hal->slowest_node_speed = IEEE1394_S400;
if (hal->current_buffer == 0) {
*selfid_buf_addr = (void *)hal->selfid_buf1;
hal->current_buffer = 1;
} else {
*selfid_buf_addr = (void *)hal->selfid_buf0;
hal->current_buffer = 0;
}
s1394_CSR_topology_map_disable(hal);
mutex_exit(&hal->topology_tree_mutex);
mutex_enter(&hal->bus_mgr_node_mutex);
hal->bus_mgr_node = -1;
mutex_exit(&hal->bus_mgr_node_mutex);
}
void
h1394_self_ids(void *sl_private, void *selfid_buf_addr, uint32_t selfid_size,
uint32_t node_id, uint32_t generation_count)
{
s1394_hal_t *hal;
int diameter;
uint_t gen_diff, gen_rollover;
boolean_t tree_copied = B_FALSE;
ushort_t saved_number_of_nodes;
hal = (s1394_hal_t *)sl_private;
mutex_enter(&hal->topology_tree_mutex);
if (hal->hal_state == S1394_HAL_SHUTDOWN) {
mutex_exit(&hal->topology_tree_mutex);
return;
}
hal->hal_kstats->selfid_complete++;
if (generation_count > hal->generation_count) {
gen_diff = generation_count - hal->generation_count;
hal->hal_kstats->bus_reset += gen_diff;
} else {
gen_diff = hal->generation_count - generation_count;
hal->hal_kstats->bus_reset +=
(hal->halinfo.max_generation - gen_diff);
}
if ((hal->topology_tree_valid == B_TRUE) &&
(hal->topology_tree_processed == B_TRUE)) {
s1394_copy_old_tree(hal);
tree_copied = B_TRUE;
}
hal->node_id = node_id;
hal->generation_count = generation_count;
hal->topology_tree_valid = B_FALSE;
hal->topology_tree_processed = B_FALSE;
hal->cfgroms_being_read = 0;
saved_number_of_nodes = hal->number_of_nodes;
if (s1394_parse_selfid_buffer(hal, selfid_buf_addr, selfid_size) !=
DDI_SUCCESS) {
mutex_exit(&hal->topology_tree_mutex);
hal->hal_kstats->selfid_buffer_error++;
return;
}
if (hal->halinfo.phy == H1394_PHY_1995) {
s1394_sort_selfids(hal);
}
mutex_enter(&hal->cm_timer_mutex);
if ((hal->cm_timer_set == B_TRUE) &&
((hal->old_number_of_nodes - 1) ==
IEEE1394_NODE_NUM(hal->old_node_id)) &&
((hal->number_of_nodes - 1) !=
IEEE1394_NODE_NUM(hal->node_id))) {
mutex_exit(&hal->cm_timer_mutex);
(void) untimeout(hal->cm_timer);
} else {
mutex_exit(&hal->cm_timer_mutex);
}
s1394_init_topology_tree(hal, tree_copied, saved_number_of_nodes);
hal->gap_count = s1394_get_current_gap_count(hal);
if (hal->gap_count == -1) {
mutex_exit(&hal->topology_tree_mutex);
hal->hal_kstats->selfid_buffer_error++;
if (s1394_ignore_invalid_gap_cnt == 1) {
mutex_enter(&hal->topology_tree_mutex);
hal->gap_count = 0x3F;
} else {
return;
}
}
hal->IRM_node = s1394_get_isoch_rsrc_mgr(hal);
if (s1394_topology_tree_build(hal) != DDI_SUCCESS) {
mutex_exit(&hal->topology_tree_mutex);
hal->hal_kstats->selfid_buffer_error++;
return;
}
s1394_CSR_topology_map_update(hal);
diameter = s1394_topology_tree_calculate_diameter(hal);
hal->optimum_gap_count = s1394_gap_count_optimize(diameter);
s1394_speed_map_fill(hal);
s1394_topology_tree_mark_all_unvisited(hal);
s1394_old_tree_mark_all_unvisited(hal);
s1394_old_tree_mark_all_unmatched(hal);
if ((hal->old_tree_valid == B_TRUE) &&
(hal->topology_tree_valid == B_TRUE)) {
if (hal->hal_was_suspended == B_TRUE) {
hal->hal_was_suspended = B_FALSE;
} else {
gen_rollover = hal->halinfo.max_generation + 1;
if (((hal->old_generation_count + 1) % gen_rollover) ==
generation_count) {
s1394_match_tree_nodes(hal);
}
}
}
mutex_exit(&hal->topology_tree_mutex);
s1394_tickle_bus_reset_thread(hal);
}
void
h1394_read_request(void *sl_private, cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
s1394_cmd_priv_t *s_priv;
s1394_addr_space_blk_t *addr_blk;
dev_info_t *dip;
uint64_t end_of_request;
uint32_t offset;
size_t cmd_length;
uchar_t *bufp_addr;
uchar_t *begin_ptr;
uchar_t *end_ptr;
uchar_t *tmp_ptr;
void (*recv_read_req)(cmd1394_cmd_t *);
hal = (s1394_hal_t *)sl_private;
s_priv = S1394_GET_CMD_PRIV(req);
s_priv->cmd_priv_xfer_type = S1394_CMD_READ;
switch (req->cmd_type) {
case CMD1394_ASYNCH_RD_QUAD:
cmd_length = IEEE1394_QUADLET;
hal->hal_kstats->arreq_quad_rd++;
break;
case CMD1394_ASYNCH_RD_BLOCK:
cmd_length = req->cmd_u.b.blk_length;
hal->hal_kstats->arreq_blk_rd++;
break;
default:
dip = hal->halinfo.dip;
cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
ddi_node_name(dip), ddi_get_instance(dip));
s1394_hal_shutdown(hal, B_TRUE);
return;
}
mutex_enter(&hal->addr_space_used_mutex);
addr_blk = s1394_used_tree_search(hal, req->cmd_addr);
if (addr_blk == NULL) {
mutex_exit(&hal->addr_space_used_mutex);
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
(void) s1394_send_response(hal, req);
return;
}
end_of_request = (req->cmd_addr + cmd_length) - 1;
if (end_of_request > addr_blk->addr_hi) {
mutex_exit(&hal->addr_space_used_mutex);
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
(void) s1394_send_response(hal, req);
return;
}
if (!(addr_blk->addr_enable & T1394_ADDR_RDENBL)) {
mutex_exit(&hal->addr_space_used_mutex);
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
return;
}
offset = req->cmd_addr - addr_blk->addr_lo;
if ((req->cmd_type == CMD1394_ASYNCH_RD_QUAD) &&
((offset & 0x3) != 0)) {
mutex_exit(&hal->addr_space_used_mutex);
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
return;
}
if (addr_blk->kmem_bufp != NULL) {
offset = req->cmd_addr - addr_blk->addr_lo;
bufp_addr = (uchar_t *)addr_blk->kmem_bufp + offset;
switch (req->cmd_type) {
case CMD1394_ASYNCH_RD_QUAD:
bcopy((void *)bufp_addr,
(void *)&(req->cmd_u.q.quadlet_data), cmd_length);
break;
case CMD1394_ASYNCH_RD_BLOCK:
begin_ptr = req->cmd_u.b.data_block->b_wptr;
end_ptr = begin_ptr + cmd_length;
tmp_ptr = req->cmd_u.b.data_block->b_datap->db_lim;
if (end_ptr <= tmp_ptr) {
bcopy((void *)bufp_addr, (void *)begin_ptr,
cmd_length);
req->cmd_u.b.data_block->b_wptr = end_ptr;
} else {
dip = hal->halinfo.dip;
cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
ddi_node_name(dip), ddi_get_instance(dip));
mutex_exit(&hal->addr_space_used_mutex);
s1394_hal_shutdown(hal, B_TRUE);
return;
}
break;
default:
dip = hal->halinfo.dip;
cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
ddi_node_name(dip), ddi_get_instance(dip));
mutex_exit(&hal->addr_space_used_mutex);
s1394_hal_shutdown(hal, B_TRUE);
return;
}
}
s_priv->arreq_valid_addr = B_TRUE;
req->cmd_callback_arg = addr_blk->addr_arg;
recv_read_req = addr_blk->addr_events.recv_read_request;
mutex_exit(&hal->addr_space_used_mutex);
if (recv_read_req != NULL) {
recv_read_req(req);
} else {
req->cmd_result = IEEE1394_RESP_COMPLETE;
(void) s1394_send_response(hal, req);
return;
}
}
void
h1394_write_request(void *sl_private, cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
s1394_cmd_priv_t *s_priv;
h1394_cmd_priv_t *h_priv;
s1394_addr_space_blk_t *addr_blk;
dev_info_t *dip;
uint32_t offset;
size_t cmd_length;
uchar_t *bufp_addr;
uchar_t *begin_ptr;
uchar_t *end_ptr;
uchar_t *tmp_ptr;
uint64_t end_of_request;
boolean_t posted_write = B_FALSE;
boolean_t write_error = B_FALSE;
void (*recv_write_req)(cmd1394_cmd_t *);
hal = (s1394_hal_t *)sl_private;
s_priv = S1394_GET_CMD_PRIV(req);
s_priv->cmd_priv_xfer_type = S1394_CMD_WRITE;
switch (req->cmd_type) {
case CMD1394_ASYNCH_WR_QUAD:
cmd_length = IEEE1394_QUADLET;
hal->hal_kstats->arreq_quad_wr++;
break;
case CMD1394_ASYNCH_WR_BLOCK:
cmd_length = req->cmd_u.b.blk_length;
hal->hal_kstats->arreq_blk_wr++;
hal->hal_kstats->arreq_blk_wr_size += cmd_length;
break;
default:
dip = hal->halinfo.dip;
cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
ddi_node_name(dip), ddi_get_instance(dip));
s1394_hal_shutdown(hal, B_TRUE);
return;
}
mutex_enter(&hal->addr_space_used_mutex);
addr_blk = s1394_used_tree_search(hal, req->cmd_addr);
posted_write = s1394_is_posted_write(hal, req->cmd_addr);
if (addr_blk == NULL) {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
write_error = B_TRUE;
goto write_error_check;
}
end_of_request = (req->cmd_addr + cmd_length) - 1;
if (end_of_request > addr_blk->addr_hi) {
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
write_error = B_TRUE;
goto write_error_check;
}
if (!(addr_blk->addr_enable & T1394_ADDR_WRENBL)) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
write_error = B_TRUE;
goto write_error_check;
}
offset = req->cmd_addr - addr_blk->addr_lo;
if ((req->cmd_type == CMD1394_ASYNCH_WR_QUAD) &&
((offset & 0x3) != 0)) {
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
write_error = B_TRUE;
goto write_error_check;
}
write_error_check:
if (write_error == B_TRUE) {
mutex_exit(&hal->addr_space_used_mutex);
if (posted_write == B_TRUE) {
h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
hal->hal_kstats->arreq_posted_write_error++;
HAL_CALL(hal).response_complete(
hal->halinfo.hal_private, req, h_priv);
return;
} else {
(void) s1394_send_response(hal, req);
return;
}
}
if (addr_blk->kmem_bufp != NULL) {
offset = req->cmd_addr - addr_blk->addr_lo;
bufp_addr = (uchar_t *)addr_blk->kmem_bufp + offset;
switch (req->cmd_type) {
case CMD1394_ASYNCH_WR_QUAD:
bcopy((void *)&(req->cmd_u.q.quadlet_data),
(void *)bufp_addr, cmd_length);
break;
case CMD1394_ASYNCH_WR_BLOCK:
begin_ptr = req->cmd_u.b.data_block->b_rptr;
end_ptr = begin_ptr + cmd_length;
tmp_ptr = req->cmd_u.b.data_block->b_wptr;
if (end_ptr <= tmp_ptr) {
bcopy((void *)begin_ptr, (void *)bufp_addr,
cmd_length);
} else {
dip = hal->halinfo.dip;
cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
ddi_node_name(dip), ddi_get_instance(dip));
mutex_exit(&hal->addr_space_used_mutex);
s1394_hal_shutdown(hal, B_TRUE);
return;
}
break;
default:
dip = hal->halinfo.dip;
cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
ddi_node_name(dip), ddi_get_instance(dip));
mutex_exit(&hal->addr_space_used_mutex);
s1394_hal_shutdown(hal, B_TRUE);
return;
}
}
if (addr_blk->addr_type == T1394_ADDR_POSTED_WRITE)
s_priv->posted_write = B_TRUE;
s_priv->arreq_valid_addr = B_TRUE;
req->cmd_callback_arg = addr_blk->addr_arg;
recv_write_req = addr_blk->addr_events.recv_write_request;
mutex_exit(&hal->addr_space_used_mutex);
if (recv_write_req != NULL) {
recv_write_req(req);
} else {
req->cmd_result = IEEE1394_RESP_COMPLETE;
(void) s1394_send_response(hal, req);
return;
}
}
void
h1394_lock_request(void *sl_private, cmd1394_cmd_t *req)
{
s1394_hal_t *hal;
s1394_cmd_priv_t *s_priv;
s1394_addr_space_blk_t *addr_blk;
dev_info_t *dip;
uint64_t end_of_request;
uint32_t offset;
uchar_t *bufp_addr;
cmd1394_lock_type_t lock_type;
void (*recv_lock_req)(cmd1394_cmd_t *);
hal = (s1394_hal_t *)sl_private;
s_priv = S1394_GET_CMD_PRIV(req);
s_priv->cmd_priv_xfer_type = S1394_CMD_LOCK;
mutex_enter(&hal->addr_space_used_mutex);
addr_blk = s1394_used_tree_search(hal, req->cmd_addr);
if (addr_blk == NULL) {
mutex_exit(&hal->addr_space_used_mutex);
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
(void) s1394_send_response(hal, req);
return;
}
switch (req->cmd_type) {
case CMD1394_ASYNCH_LOCK_32:
end_of_request = (req->cmd_addr + IEEE1394_QUADLET) - 1;
hal->hal_kstats->arreq_lock32++;
break;
case CMD1394_ASYNCH_LOCK_64:
end_of_request = (req->cmd_addr + IEEE1394_OCTLET) - 1;
hal->hal_kstats->arreq_lock64++;
break;
default:
mutex_exit(&hal->addr_space_used_mutex);
dip = hal->halinfo.dip;
cmn_err(CE_WARN, HALT_ERROR_MESSAGE,
ddi_node_name(dip), ddi_get_instance(dip));
s1394_hal_shutdown(hal, B_TRUE);
return;
}
if (end_of_request > addr_blk->addr_hi) {
mutex_exit(&hal->addr_space_used_mutex);
req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
(void) s1394_send_response(hal, req);
return;
}
if (!(addr_blk->addr_enable & T1394_ADDR_LKENBL)) {
mutex_exit(&hal->addr_space_used_mutex);
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
return;
}
if (addr_blk->kmem_bufp != NULL) {
offset = req->cmd_addr - addr_blk->addr_lo;
bufp_addr = (uchar_t *)addr_blk->kmem_bufp + offset;
if (req->cmd_type == CMD1394_ASYNCH_LOCK_32) {
uint32_t old_value;
uint32_t arg_value;
uint32_t data_value;
uint32_t new_value;
arg_value = req->cmd_u.l32.arg_value;
data_value = req->cmd_u.l32.data_value;
lock_type = req->cmd_u.l32.lock_type;
bcopy((void *)bufp_addr, (void *)&old_value,
IEEE1394_QUADLET);
switch (lock_type) {
case CMD1394_LOCK_MASK_SWAP:
new_value = (data_value & arg_value) |
(old_value & ~arg_value);
bcopy((void *)&new_value, (void *)bufp_addr,
IEEE1394_QUADLET);
req->cmd_u.l32.old_value = old_value;
break;
case CMD1394_LOCK_COMPARE_SWAP:
if (old_value == arg_value) {
new_value = data_value;
bcopy((void *)&new_value,
(void *)bufp_addr,
IEEE1394_QUADLET);
}
req->cmd_u.l32.old_value = old_value;
break;
case CMD1394_LOCK_FETCH_ADD:
old_value = T1394_DATA32(old_value);
new_value = old_value + data_value;
new_value = T1394_DATA32(new_value);
bcopy((void *)&new_value, (void *)bufp_addr,
IEEE1394_QUADLET);
req->cmd_u.l32.old_value = old_value;
break;
case CMD1394_LOCK_LITTLE_ADD:
old_value = T1394_DATA32(old_value);
new_value = old_value + data_value;
new_value = T1394_DATA32(new_value);
bcopy((void *)&new_value, (void *)bufp_addr,
IEEE1394_QUADLET);
req->cmd_u.l32.old_value = old_value;
break;
case CMD1394_LOCK_BOUNDED_ADD:
old_value = T1394_DATA32(old_value);
if (old_value != arg_value) {
new_value = old_value + data_value;
new_value = T1394_DATA32(new_value);
bcopy((void *)&new_value,
(void *)bufp_addr,
IEEE1394_QUADLET);
}
req->cmd_u.l32.old_value = old_value;
break;
case CMD1394_LOCK_WRAP_ADD:
old_value = T1394_DATA32(old_value);
if (old_value != arg_value) {
new_value = old_value + data_value;
} else {
new_value = data_value;
}
new_value = T1394_DATA32(new_value);
bcopy((void *)&new_value, (void *)bufp_addr,
IEEE1394_QUADLET);
req->cmd_u.l32.old_value = old_value;
break;
default:
mutex_exit(&hal->addr_space_used_mutex);
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
return;
}
} else {
uint64_t old_value;
uint64_t arg_value;
uint64_t data_value;
uint64_t new_value;
arg_value = req->cmd_u.l64.arg_value;
data_value = req->cmd_u.l64.data_value;
lock_type = req->cmd_u.l64.lock_type;
bcopy((void *)bufp_addr, (void *)&old_value,
IEEE1394_OCTLET);
switch (lock_type) {
case CMD1394_LOCK_MASK_SWAP:
new_value = (data_value & arg_value) |
(old_value & ~arg_value);
bcopy((void *)&new_value, (void *)bufp_addr,
IEEE1394_OCTLET);
req->cmd_u.l64.old_value = old_value;
break;
case CMD1394_LOCK_COMPARE_SWAP:
if (old_value == arg_value) {
new_value = data_value;
bcopy((void *)&new_value,
(void *)bufp_addr,
IEEE1394_OCTLET);
}
req->cmd_u.l64.old_value = old_value;
break;
case CMD1394_LOCK_FETCH_ADD:
old_value = T1394_DATA64(old_value);
new_value = old_value + data_value;
new_value = T1394_DATA64(new_value);
bcopy((void *)&new_value, (void *)bufp_addr,
IEEE1394_OCTLET);
req->cmd_u.l64.old_value = old_value;
break;
case CMD1394_LOCK_LITTLE_ADD:
old_value = T1394_DATA64(old_value);
new_value = old_value + data_value;
new_value = T1394_DATA64(new_value);
bcopy((void *)&new_value, (void *)bufp_addr,
IEEE1394_OCTLET);
req->cmd_u.l64.old_value = old_value;
break;
case CMD1394_LOCK_BOUNDED_ADD:
old_value = T1394_DATA64(old_value);
if (old_value != arg_value) {
new_value = old_value + data_value;
new_value = T1394_DATA64(new_value);
bcopy((void *)&new_value,
(void *)bufp_addr,
IEEE1394_OCTLET);
}
req->cmd_u.l64.old_value = old_value;
break;
case CMD1394_LOCK_WRAP_ADD:
old_value = T1394_DATA64(old_value);
if (old_value != arg_value) {
new_value = old_value + data_value;
} else {
new_value = data_value;
}
new_value = T1394_DATA64(new_value);
bcopy((void *)&new_value, (void *)bufp_addr,
IEEE1394_OCTLET);
req->cmd_u.l64.old_value = old_value;
break;
default:
mutex_exit(&hal->addr_space_used_mutex);
req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
(void) s1394_send_response(hal, req);
return;
}
}
}
s_priv->arreq_valid_addr = B_TRUE;
req->cmd_callback_arg = addr_blk->addr_arg;
recv_lock_req = addr_blk->addr_events.recv_lock_request;
mutex_exit(&hal->addr_space_used_mutex);
if (recv_lock_req != NULL) {
recv_lock_req(req);
} else {
req->cmd_result = IEEE1394_RESP_COMPLETE;
(void) s1394_send_response(hal, req);
return;
}
}
int
h1394_ioctl(void *sl_private, int cmd, intptr_t arg, int mode, cred_t *cred_p,
int *rval_p)
{
int status;
if ((cmd & DEVCTL_IOC) != DEVCTL_IOC)
return (EINVAL);
status = s1394_ioctl((s1394_hal_t *)sl_private, cmd, arg, mode,
cred_p, rval_p);
return (status);
}
void
h1394_phy_packet(void *sl_private, uint32_t *packet_data, uint_t quadlet_count,
uint_t timestamp)
{
}
void
h1394_error_detected(void *sl_private, h1394_error_t type, void *arg)
{
s1394_hal_t *hal;
uint_t hal_node_num;
uint_t IRM_node_num;
hal = (s1394_hal_t *)sl_private;
switch (type) {
case H1394_LOCK_RESP_ERR:
mutex_enter(&hal->topology_tree_mutex);
hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
IRM_node_num = hal->IRM_node;
mutex_exit(&hal->topology_tree_mutex);
if (IRM_node_num == hal_node_num)
s1394_initiate_hal_reset(hal, NON_CRITICAL);
break;
case H1394_POSTED_WR_ERR:
break;
case H1394_SELF_INITIATED_SHUTDOWN:
s1394_hal_shutdown(hal, B_FALSE);
break;
case H1394_CYCLE_TOO_LONG:
mutex_enter(&hal->cm_timer_mutex);
hal->cm_timer_set = B_TRUE;
mutex_exit(&hal->cm_timer_mutex);
hal->cm_timer = timeout(s1394_cycle_too_long_callback, hal,
drv_usectohz(CYCLE_MASTER_TIMER * 1000));
break;
default:
break;
}
}