#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/modctl.h>
#include <sys/stat.h>
#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#include <sys/kmem.h>
#include <sys/types.h>
#include <sys/note.h>
#include <sys/1394/h1394.h>
#include <sys/1394/adapters/hci1394.h>
#define ASYNC_ARRESP_ACK_ERROR 0x8000
#define HCI1394_TO_ADDR_HI(data) (((uint64_t)((data) & 0xFFFF)) << 32)
#define HCI1394_TO_ADDR_LO(data) ((uint64_t)((data) & 0xFFFFFFFF))
#ifdef _LITTLE_ENDIAN
#define HCI1394_ARITH_LOCK_SWAP32(tcode, data) \
(((tcode) == CMD1394_LOCK_FETCH_ADD) || \
((tcode) == CMD1394_LOCK_BOUNDED_ADD) || \
((tcode) == CMD1394_LOCK_WRAP_ADD)) ? \
(ddi_swap32(data)) : (data)
#define HCI1394_ARITH_LOCK_SWAP64(tcode, data) \
(((tcode) == CMD1394_LOCK_FETCH_ADD) || \
((tcode) == CMD1394_LOCK_BOUNDED_ADD) || \
((tcode) == CMD1394_LOCK_WRAP_ADD)) ? \
(ddi_swap64(data)) : (data)
#else
#define HCI1394_ARITH_LOCK_SWAP32(tcode, data) (data)
#define HCI1394_ARITH_LOCK_SWAP64(tcode, data) (data)
#endif
static int hci1394_async_arresp_read(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, uint_t *tcode, hci1394_async_cmd_t **hcicmd,
uint_t *size);
static int hci1394_async_arresp_size_get(uint_t tcode, hci1394_q_handle_t q,
uint32_t *addr, uint_t *size);
static int hci1394_async_arreq_read(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, uint_t *tcode, hci1394_async_cmd_t **hcicmd,
uint_t *size);
static int hci1394_async_arreq_read_qrd(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size);
static int hci1394_async_arreq_read_qwr(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size);
static int hci1394_async_arreq_read_brd(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size);
static int hci1394_async_arreq_read_bwr(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size);
static int hci1394_async_arreq_read_lck(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size);
static int hci1394_async_arreq_read_phy(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size,
boolean_t *bus_reset_token);
static void hci1394_async_hcicmd_init(hci1394_async_handle_t async_handle,
cmd1394_cmd_t *cmd, h1394_cmd_priv_t *cmd_priv,
hci1394_async_cmd_t **hcicmd);
static void hci1394_async_atreq_start(void *async, uint32_t command_ptr);
static void hci1394_async_arresp_start(void *async, uint32_t command_ptr);
static void hci1394_async_arreq_start(void *async, uint32_t command_ptr);
static void hci1394_async_atresp_start(void *async, uint32_t command_ptr);
static void hci1394_async_atreq_wake(void *async);
static void hci1394_async_arresp_wake(void *async);
static void hci1394_async_arreq_wake(void *async);
static void hci1394_async_atresp_wake(void *async);
static void hci1394_async_atreq_flush(hci1394_async_handle_t async_handle);
static void hci1394_async_arresp_flush(hci1394_async_handle_t async_handle);
static void hci1394_async_arreq_flush(hci1394_async_handle_t async_handle);
static void hci1394_async_atresp_flush(hci1394_async_handle_t async_handle);
static void hci1394_async_pending_list_flush(hci1394_async_handle_t
async_handle);
static void hci1394_async_pending_timeout(hci1394_tlist_node_t *node,
void *arg);
static uint_t hci1394_async_timeout_calc(hci1394_async_handle_t async_handle,
uint_t current_time);
_NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
int
hci1394_async_init(hci1394_drvinfo_t *drvinfo,
hci1394_ohci_handle_t ohci_handle, hci1394_csr_handle_t csr_handle,
hci1394_async_handle_t *async_handle)
{
hci1394_tlist_timer_t timer_info;
hci1394_q_info_t qinfo;
hci1394_async_t *async;
int status;
ASSERT(drvinfo != NULL);
ASSERT(ohci_handle != NULL);
ASSERT(csr_handle != NULL);
ASSERT(async_handle != NULL);
async = kmem_alloc(sizeof (hci1394_async_t), KM_SLEEP);
async->as_drvinfo = drvinfo;
async->as_ohci = ohci_handle;
async->as_csr = csr_handle;
async->as_flushing_arreq = B_FALSE;
async->as_phy_reset = 0xFFFFFFFF;
mutex_init(&async->as_atomic_lookup, NULL, MUTEX_DRIVER,
drvinfo->di_iblock_cookie);
hci1394_tlabel_init(drvinfo, OHCI_BUS_CYCLE_TO_nS(
hci1394_csr_split_timeout_get(csr_handle)), &async->as_tlabel);
timer_info.tlt_timeout =
OHCI_BUS_CYCLE_TO_nS(hci1394_csr_split_timeout_get(csr_handle));
timer_info.tlt_timer_resolution = timer_info.tlt_timeout / 2;
timer_info.tlt_callback = hci1394_async_pending_timeout;
timer_info.tlt_callback_arg = async;
hci1394_tlist_init(drvinfo, &timer_info, &async->as_pending_list);
qinfo.qi_desc_size = ASYNC_ATREQ_DESC_SIZE;
qinfo.qi_data_size = ASYNC_ATREQ_DATA_SIZE;
qinfo.qi_mode = HCI1394_ATQ;
qinfo.qi_start = hci1394_async_atreq_start;
qinfo.qi_wake = hci1394_async_atreq_wake;
qinfo.qi_callback_arg = async;
status = hci1394_q_init(drvinfo, async->as_ohci, &qinfo,
&async->as_atreq_q);
if (status != DDI_SUCCESS) {
mutex_destroy(&async->as_atomic_lookup);
hci1394_tlist_fini(&async->as_pending_list);
hci1394_tlabel_fini(&async->as_tlabel);
kmem_free(async, sizeof (hci1394_async_t));
*async_handle = NULL;
return (DDI_FAILURE);
}
qinfo.qi_desc_size = ASYNC_ARRESP_DESC_SIZE;
qinfo.qi_data_size = ASYNC_ARRESP_DATA_SIZE;
qinfo.qi_mode = HCI1394_ARQ;
qinfo.qi_start = hci1394_async_arresp_start;
qinfo.qi_wake = hci1394_async_arresp_wake;
qinfo.qi_callback_arg = async;
status = hci1394_q_init(drvinfo, async->as_ohci, &qinfo,
&async->as_arresp_q);
if (status != DDI_SUCCESS) {
mutex_destroy(&async->as_atomic_lookup);
hci1394_tlist_fini(&async->as_pending_list);
hci1394_tlabel_fini(&async->as_tlabel);
hci1394_q_fini(&async->as_atreq_q);
kmem_free(async, sizeof (hci1394_async_t));
*async_handle = NULL;
return (DDI_FAILURE);
}
qinfo.qi_desc_size = ASYNC_ARREQ_DESC_SIZE;
qinfo.qi_data_size = ASYNC_ARREQ_DATA_SIZE;
qinfo.qi_mode = HCI1394_ARQ;
qinfo.qi_start = hci1394_async_arreq_start;
qinfo.qi_wake = hci1394_async_arreq_wake;
qinfo.qi_callback_arg = async;
status = hci1394_q_init(drvinfo, async->as_ohci, &qinfo,
&async->as_arreq_q);
if (status != DDI_SUCCESS) {
mutex_destroy(&async->as_atomic_lookup);
hci1394_tlist_fini(&async->as_pending_list);
hci1394_tlabel_fini(&async->as_tlabel);
hci1394_q_fini(&async->as_atreq_q);
hci1394_q_fini(&async->as_arresp_q);
kmem_free(async, sizeof (hci1394_async_t));
*async_handle = NULL;
return (DDI_FAILURE);
}
qinfo.qi_desc_size = ASYNC_ATRESP_DESC_SIZE;
qinfo.qi_data_size = ASYNC_ATRESP_DATA_SIZE;
qinfo.qi_mode = HCI1394_ATQ;
qinfo.qi_start = hci1394_async_atresp_start;
qinfo.qi_wake = hci1394_async_atresp_wake;
qinfo.qi_callback_arg = async;
status = hci1394_q_init(drvinfo, async->as_ohci, &qinfo,
&async->as_atresp_q);
if (status != DDI_SUCCESS) {
mutex_destroy(&async->as_atomic_lookup);
hci1394_tlist_fini(&async->as_pending_list);
hci1394_tlabel_fini(&async->as_tlabel);
hci1394_q_fini(&async->as_atreq_q);
hci1394_q_fini(&async->as_arresp_q);
hci1394_q_fini(&async->as_arreq_q);
kmem_free(async, sizeof (hci1394_async_t));
*async_handle = NULL;
return (DDI_FAILURE);
}
*async_handle = async;
return (DDI_SUCCESS);
}
void
hci1394_async_fini(hci1394_async_handle_t *async_handle)
{
hci1394_async_t *async;
ASSERT(async_handle != NULL);
async = (hci1394_async_t *)*async_handle;
mutex_destroy(&async->as_atomic_lookup);
hci1394_tlabel_fini(&async->as_tlabel);
hci1394_tlist_fini(&async->as_pending_list);
hci1394_q_fini(&async->as_atreq_q);
hci1394_q_fini(&async->as_atresp_q);
hci1394_q_fini(&async->as_arreq_q);
hci1394_q_fini(&async->as_arresp_q);
kmem_free(async, sizeof (hci1394_async_t));
*async_handle = NULL;
}
void
hci1394_async_suspend(hci1394_async_handle_t async_handle)
{
ASSERT(async_handle != NULL);
hci1394_async_flush(async_handle);
hci1394_tlist_timeout_cancel(async_handle->as_pending_list);
}
int
hci1394_async_resume(hci1394_async_handle_t async_handle)
{
ASSERT(async_handle != NULL);
hci1394_q_resume(async_handle->as_atreq_q);
hci1394_q_resume(async_handle->as_atresp_q);
hci1394_q_resume(async_handle->as_arreq_q);
hci1394_q_resume(async_handle->as_arresp_q);
return (DDI_SUCCESS);
}
uint_t
hci1394_async_cmd_overhead()
{
return (sizeof (hci1394_async_cmd_t));
}
void
hci1394_async_flush(hci1394_async_handle_t async_handle)
{
ASSERT(async_handle != NULL);
hci1394_async_atreq_flush(async_handle);
hci1394_async_arresp_flush(async_handle);
hci1394_async_pending_list_flush(async_handle);
hci1394_async_arreq_flush(async_handle);
hci1394_async_atresp_flush(async_handle);
hci1394_tlabel_reset(async_handle->as_tlabel);
}
void
hci1394_async_pending_timeout_update(hci1394_async_handle_t async_handle,
hrtime_t timeout)
{
ASSERT(async_handle != NULL);
hci1394_tlist_timeout_update(async_handle->as_pending_list, timeout);
hci1394_tlabel_set_reclaim_time(async_handle->as_tlabel, timeout);
}
int
hci1394_async_atreq_process(hci1394_async_handle_t async_handle,
boolean_t flush_q, boolean_t *request_available)
{
hci1394_async_cmd_t *hcicmd;
hci1394_q_cmd_t *qcmd;
int cmd_status;
ASSERT(async_handle != NULL);
ASSERT(request_available != NULL);
hci1394_q_at_next(async_handle->as_atreq_q, flush_q, &qcmd);
if (qcmd == NULL) {
*request_available = B_FALSE;
return (DDI_SUCCESS);
}
*request_available = B_TRUE;
hcicmd = (hci1394_async_cmd_t *)qcmd->qc_arg;
hcicmd->ac_priv->ack_tstamp = qcmd->qc_timestamp;
if (hcicmd->ac_state != HCI1394_CMD_STATE_IN_PROGRESS) {
if (qcmd->qc_status == OHCI_ACK_PENDING) {
h1394_cmd_is_complete(
async_handle->as_drvinfo->di_sl_private,
hcicmd->ac_cmd, H1394_AT_REQ,
hcicmd->ac_status);
return (DDI_SUCCESS);
}
}
if (qcmd->qc_status == OHCI_ACK_PENDING) {
hcicmd->ac_state = HCI1394_CMD_STATE_PENDING;
hcicmd->ac_plist_node.tln_addr = hcicmd;
hci1394_tlist_add(async_handle->as_pending_list,
&hcicmd->ac_plist_node);
return (DDI_SUCCESS);
}
switch (qcmd->qc_status) {
case OHCI_ACK_COMPLETE:
cmd_status = H1394_CMD_SUCCESS;
break;
case OHCI_EVT_FLUSHED:
case OHCI_EVT_NO_STATUS:
cmd_status = H1394_CMD_EBUSRESET;
break;
case OHCI_EVT_MISSING_ACK:
case OHCI_EVT_TIMEOUT:
cmd_status = H1394_CMD_ETIMEOUT;
break;
case OHCI_ACK_BUSY_X:
case OHCI_ACK_BUSY_A:
case OHCI_ACK_BUSY_B:
cmd_status = H1394_CMD_EDEVICE_BUSY;
break;
case OHCI_ACK_TARDY:
cmd_status = H1394_CMD_EDEVICE_POWERUP;
break;
case OHCI_ACK_DATA_ERROR:
cmd_status = H1394_CMD_EDATA_ERROR;
break;
case OHCI_ACK_TYPE_ERROR:
cmd_status = H1394_CMD_ETYPE_ERROR;
break;
case OHCI_ACK_CONFLICT_ERROR:
cmd_status = H1394_CMD_ERSRC_CONFLICT;
break;
case OHCI_ACK_ADDRESS_ERROR:
cmd_status = H1394_CMD_EADDR_ERROR;
break;
case OHCI_EVT_UNDERRUN:
case OHCI_EVT_DATA_READ:
case OHCI_EVT_TCODE_ERR:
case OHCI_EVT_DESCRIPTOR_READ:
case OHCI_EVT_UNKNOWN:
default:
cmd_status = H1394_CMD_EUNKNOWN_ERROR;
break;
}
if ((hcicmd->ac_state == HCI1394_CMD_STATE_IN_PROGRESS) &&
(hcicmd->ac_tlabel_alloc == B_TRUE)) {
hci1394_tlabel_free(async_handle->as_tlabel,
&hcicmd->ac_tlabel);
}
hcicmd->ac_state = HCI1394_CMD_STATE_COMPLETED;
h1394_cmd_is_complete(async_handle->as_drvinfo->di_sl_private,
hcicmd->ac_cmd, H1394_AT_REQ, cmd_status);
return (DDI_SUCCESS);
}
int
hci1394_async_arresp_process(hci1394_async_handle_t async_handle,
boolean_t *response_available)
{
hci1394_async_cmd_t *hcicmd;
uint32_t *addr;
int cmd_status;
uint_t tcode;
uint_t size;
int status;
ASSERT(async_handle != NULL);
ASSERT(response_available != NULL);
hci1394_q_ar_next(async_handle->as_arresp_q, &addr);
if (addr == NULL) {
*response_available = B_FALSE;
return (DDI_SUCCESS);
}
*response_available = B_TRUE;
mutex_enter(&async_handle->as_atomic_lookup);
status = hci1394_async_arresp_read(async_handle,
(hci1394_basic_pkt_t *)addr, &tcode, &hcicmd, &size);
if (status != DDI_SUCCESS) {
mutex_exit(&async_handle->as_atomic_lookup);
h1394_error_detected(async_handle->as_drvinfo->di_sl_private,
H1394_SELF_INITIATED_SHUTDOWN, NULL);
cmn_err(CE_WARN, "hci1394(%d): driver shutdown: "
"unrecoverable error interrupt detected",
async_handle->as_drvinfo->di_instance);
hci1394_shutdown(async_handle->as_drvinfo->di_dip);
return (DDI_FAILURE);
}
hci1394_q_ar_free(async_handle->as_arresp_q, size);
if (hcicmd == NULL) {
mutex_exit(&async_handle->as_atomic_lookup);
return (DDI_SUCCESS);
}
if (hcicmd->ac_state == HCI1394_CMD_STATE_PENDING) {
status = hci1394_tlist_delete(async_handle->as_pending_list,
&hcicmd->ac_plist_node);
if (status != DDI_SUCCESS) {
mutex_exit(&async_handle->as_atomic_lookup);
return (DDI_SUCCESS);
}
}
mutex_exit(&async_handle->as_atomic_lookup);
hci1394_tlabel_free(async_handle->as_tlabel, &hcicmd->ac_tlabel);
switch (hcicmd->ac_status) {
case IEEE1394_RESP_COMPLETE:
cmd_status = H1394_CMD_SUCCESS;
break;
case IEEE1394_RESP_DATA_ERROR:
cmd_status = H1394_CMD_EDATA_ERROR;
break;
case IEEE1394_RESP_TYPE_ERROR:
cmd_status = H1394_CMD_ETYPE_ERROR;
break;
case IEEE1394_RESP_CONFLICT_ERROR:
cmd_status = H1394_CMD_ERSRC_CONFLICT;
break;
case IEEE1394_RESP_ADDRESS_ERROR:
cmd_status = H1394_CMD_EADDR_ERROR;
break;
case H1394_CMD_EDEVICE_ERROR:
cmd_status = H1394_CMD_EDEVICE_ERROR;
break;
case OHCI_ACK_DATA_ERROR | ASYNC_ARRESP_ACK_ERROR:
cmd_status = H1394_CMD_EDATA_ERROR;
break;
case OHCI_ACK_TYPE_ERROR | ASYNC_ARRESP_ACK_ERROR:
cmd_status = H1394_CMD_ETYPE_ERROR;
break;
case OHCI_EVT_UNDERRUN | ASYNC_ARRESP_ACK_ERROR:
case OHCI_EVT_DATA_READ | ASYNC_ARRESP_ACK_ERROR:
case OHCI_EVT_TCODE_ERR | ASYNC_ARRESP_ACK_ERROR:
cmd_status = H1394_CMD_EUNKNOWN_ERROR;
break;
default:
cmd_status = H1394_CMD_EUNKNOWN_ERROR;
break;
}
if (hcicmd->ac_state == HCI1394_CMD_STATE_PENDING) {
hcicmd->ac_state = HCI1394_CMD_STATE_COMPLETED;
h1394_cmd_is_complete(async_handle->as_drvinfo->di_sl_private,
hcicmd->ac_cmd, H1394_AT_REQ, cmd_status);
} else {
hcicmd->ac_state = HCI1394_CMD_STATE_COMPLETED;
hcicmd->ac_status = cmd_status;
}
return (DDI_SUCCESS);
}
int
hci1394_async_arreq_process(hci1394_async_handle_t async_handle,
boolean_t *request_available)
{
hci1394_async_cmd_t *hcicmd;
uint32_t *addr;
uint_t tcode;
uint_t size;
int status;
ASSERT(async_handle != NULL);
ASSERT(request_available != NULL);
hci1394_q_ar_next(async_handle->as_arreq_q, &addr);
if (addr == NULL) {
*request_available = B_FALSE;
return (DDI_SUCCESS);
}
*request_available = B_TRUE;
status = hci1394_async_arreq_read(async_handle,
(hci1394_basic_pkt_t *)addr, &tcode, &hcicmd, &size);
if (status != DDI_SUCCESS) {
h1394_error_detected(async_handle->as_drvinfo->di_sl_private,
H1394_SELF_INITIATED_SHUTDOWN, NULL);
cmn_err(CE_WARN, "hci1394(%d): driver shutdown: "
"unrecoverable error interrupt detected",
async_handle->as_drvinfo->di_instance);
hci1394_shutdown(async_handle->as_drvinfo->di_dip);
return (DDI_FAILURE);
}
hci1394_q_ar_free(async_handle->as_arreq_q, size);
if (hcicmd == NULL) {
return (DDI_SUCCESS);
}
if (async_handle->as_flushing_arreq == B_TRUE) {
hci1394_async_response_complete(async_handle, hcicmd->ac_cmd,
hcicmd->ac_priv);
return (DDI_SUCCESS);
}
switch (tcode) {
case IEEE1394_TCODE_READ_QUADLET:
case IEEE1394_TCODE_READ_BLOCK:
h1394_read_request(async_handle->as_drvinfo->di_sl_private,
hcicmd->ac_cmd);
break;
case IEEE1394_TCODE_WRITE_QUADLET:
case IEEE1394_TCODE_WRITE_BLOCK:
h1394_write_request(async_handle->as_drvinfo->di_sl_private,
hcicmd->ac_cmd);
break;
case IEEE1394_TCODE_LOCK:
h1394_lock_request(async_handle->as_drvinfo->di_sl_private,
hcicmd->ac_cmd);
break;
case IEEE1394_TCODE_PHY:
h1394_phy_packet(async_handle->as_drvinfo->di_sl_private,
&hcicmd->ac_cmd->cmd_u.q.quadlet_data, 1,
hcicmd->ac_priv->recv_tstamp);
hci1394_async_response_complete(async_handle, hcicmd->ac_cmd,
hcicmd->ac_priv);
break;
default:
hci1394_async_response_complete(async_handle, hcicmd->ac_cmd,
hcicmd->ac_priv);
break;
}
return (DDI_SUCCESS);
}
int
hci1394_async_atresp_process(hci1394_async_handle_t async_handle,
boolean_t flush_q, boolean_t *response_available)
{
hci1394_async_cmd_t *hcicmd;
hci1394_q_cmd_t *qcmd;
int cmd_status;
ASSERT(async_handle != NULL);
ASSERT(response_available != NULL);
hci1394_q_at_next(async_handle->as_atresp_q, flush_q, &qcmd);
if (qcmd == NULL) {
*response_available = B_FALSE;
return (DDI_SUCCESS);
}
*response_available = B_TRUE;
hcicmd = (hci1394_async_cmd_t *)qcmd->qc_arg;
hcicmd->ac_priv->ack_tstamp = qcmd->qc_timestamp;
switch (qcmd->qc_status) {
case OHCI_ACK_COMPLETE:
cmd_status = H1394_CMD_SUCCESS;
break;
case OHCI_EVT_FLUSHED:
case OHCI_EVT_NO_STATUS:
cmd_status = H1394_CMD_EBUSRESET;
break;
case OHCI_EVT_MISSING_ACK:
case OHCI_EVT_TIMEOUT:
cmd_status = H1394_CMD_ETIMEOUT;
break;
case OHCI_ACK_BUSY_X:
case OHCI_ACK_BUSY_A:
case OHCI_ACK_BUSY_B:
cmd_status = H1394_CMD_EDEVICE_BUSY;
break;
case OHCI_ACK_TARDY:
cmd_status = H1394_CMD_EDEVICE_POWERUP;
break;
case OHCI_ACK_DATA_ERROR:
cmd_status = H1394_CMD_EDATA_ERROR;
break;
case OHCI_ACK_TYPE_ERROR:
cmd_status = H1394_CMD_ETYPE_ERROR;
break;
case OHCI_ACK_CONFLICT_ERROR:
cmd_status = H1394_CMD_ERSRC_CONFLICT;
break;
case OHCI_ACK_ADDRESS_ERROR:
cmd_status = H1394_CMD_EADDR_ERROR;
break;
case OHCI_EVT_UNKNOWN:
cmd_status = H1394_CMD_EUNKNOWN_ERROR;
break;
case OHCI_EVT_UNDERRUN:
case OHCI_EVT_DATA_READ:
case OHCI_EVT_TCODE_ERR:
case OHCI_EVT_DESCRIPTOR_READ:
default:
cmd_status = H1394_CMD_EUNKNOWN_ERROR;
break;
}
h1394_cmd_is_complete(async_handle->as_drvinfo->di_sl_private,
hcicmd->ac_cmd, H1394_AT_RESP, cmd_status);
return (DDI_SUCCESS);
}
static int
hci1394_async_arresp_read(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, uint_t *tcode, hci1394_async_cmd_t **hcicmd,
uint_t *size)
{
hci1394_tlabel_info_t ac_tlabel;
h1394_cmd_priv_t *cmd_priv;
cmd1394_cmd_t *cmd;
uint32_t *status_addr;
uint_t data_length;
uint32_t quadlet;
void *command;
uint_t rcode;
uint_t ack;
int status;
ASSERT(async_handle != NULL);
ASSERT(pkt != NULL);
ASSERT(tcode != NULL);
ASSERT(hcicmd != NULL);
ASSERT(size != NULL);
quadlet = hci1394_q_ar_get32(async_handle->as_arresp_q, &pkt->q1);
*tcode = HCI1394_DESC_TCODE_GET(quadlet);
status = hci1394_async_arresp_size_get(*tcode,
async_handle->as_arresp_q, &pkt->q1, size);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
quadlet = hci1394_q_ar_get32(async_handle->as_arresp_q, &pkt->q1);
ac_tlabel.tbi_tlabel = HCI1394_DESC_TLABEL_GET(quadlet);
quadlet = hci1394_q_ar_get32(async_handle->as_arresp_q, &pkt->q2);
ac_tlabel.tbi_destination = HCI1394_DESC_DESTID_GET(quadlet);
rcode = HCI1394_DESC_RCODE_GET(quadlet);
hci1394_tlabel_lookup(async_handle->as_tlabel, &ac_tlabel, &command);
*hcicmd = (hci1394_async_cmd_t *)command;
if ((*hcicmd) == NULL) {
return (DDI_SUCCESS);
}
(*hcicmd)->ac_status = rcode;
cmd = (*hcicmd)->ac_cmd;
cmd_priv = (*hcicmd)->ac_priv;
status_addr = (uint32_t *)((uintptr_t)pkt + (uintptr_t)*size -
(uintptr_t)IEEE1394_QUADLET);
quadlet = hci1394_q_ar_get32(async_handle->as_arresp_q, status_addr);
cmd_priv->recv_tstamp = HCI1394_DESC_TIMESTAMP_GET(quadlet);
ack = HCI1394_DESC_EVT_GET(quadlet);
if (ack != OHCI_ACK_COMPLETE) {
(*hcicmd)->ac_status = ack | ASYNC_ARRESP_ACK_ERROR;
return (DDI_SUCCESS);
}
if (rcode != IEEE1394_RESP_COMPLETE) {
return (DDI_SUCCESS);
}
switch (*tcode) {
case IEEE1394_TCODE_WRITE_RESP:
if ((cmd->cmd_type != CMD1394_ASYNCH_WR_QUAD) &&
(cmd->cmd_type != CMD1394_ASYNCH_WR_BLOCK)) {
(*hcicmd)->ac_status = H1394_CMD_EDEVICE_ERROR;
return (DDI_SUCCESS);
}
break;
case IEEE1394_TCODE_READ_QUADLET_RESP:
if (cmd->cmd_type != CMD1394_ASYNCH_RD_QUAD) {
(*hcicmd)->ac_status = H1394_CMD_EDEVICE_ERROR;
return (DDI_SUCCESS);
}
hci1394_q_ar_rep_get8(async_handle->as_arresp_q,
(uint8_t *)&cmd->cmd_u.q.quadlet_data,
(uint8_t *)&pkt->q4, IEEE1394_QUADLET);
break;
case IEEE1394_TCODE_READ_BLOCK_RESP:
if (cmd->cmd_type != CMD1394_ASYNCH_RD_BLOCK) {
(*hcicmd)->ac_status = H1394_CMD_EDEVICE_ERROR;
return (DDI_SUCCESS);
}
quadlet = hci1394_q_ar_get32(async_handle->as_arresp_q,
&pkt->q4);
data_length = HCI1394_DESC_DATALEN_GET(quadlet);
if (data_length != cmd_priv->mblk.length) {
(*hcicmd)->ac_status = H1394_CMD_EDEVICE_ERROR;
return (DDI_SUCCESS);
}
hci1394_q_ar_copy_to_mblk(async_handle->as_arresp_q,
(uint8_t *)&pkt->q5, &cmd_priv->mblk);
break;
case IEEE1394_TCODE_LOCK_RESP:
quadlet = hci1394_q_ar_get32(async_handle->as_arresp_q,
&pkt->q4);
data_length = HCI1394_DESC_DATALEN_GET(quadlet);
if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
if (data_length != IEEE1394_QUADLET) {
(*hcicmd)->ac_status = H1394_CMD_EDEVICE_ERROR;
return (DDI_SUCCESS);
}
hci1394_q_ar_rep_get8(async_handle->as_arresp_q,
(uint8_t *)&cmd->cmd_u.l32.old_value,
(uint8_t *)&pkt->q5, IEEE1394_QUADLET);
cmd->cmd_u.l32.old_value = HCI1394_ARITH_LOCK_SWAP32(
cmd->cmd_u.l32.lock_type, cmd->cmd_u.l32.old_value);
} else if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) {
if (data_length != IEEE1394_OCTLET) {
(*hcicmd)->ac_status = H1394_CMD_EDEVICE_ERROR;
return (DDI_SUCCESS);
}
hci1394_q_ar_rep_get8(async_handle->as_arresp_q,
(uint8_t *)&cmd->cmd_u.l64.old_value,
(uint8_t *)&pkt->q5, IEEE1394_OCTLET);
cmd->cmd_u.l64.old_value = HCI1394_ARITH_LOCK_SWAP64(
cmd->cmd_u.l64.lock_type, cmd->cmd_u.l64.old_value);
} else {
(*hcicmd)->ac_status = H1394_CMD_EDEVICE_ERROR;
return (DDI_SUCCESS);
}
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static int
hci1394_async_arreq_read(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, uint_t *tcode, hci1394_async_cmd_t **hcicmd,
uint_t *size)
{
h1394_cmd_priv_t *cmd_priv;
boolean_t is_reset_token;
cmd1394_cmd_t *cmd;
uint32_t quadlet;
int status;
ASSERT(async_handle != NULL);
ASSERT(pkt != NULL);
ASSERT(tcode != NULL);
ASSERT(hcicmd != NULL);
ASSERT(size != NULL);
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q1);
*tcode = HCI1394_DESC_TCODE_GET(quadlet);
status = h1394_alloc_cmd(async_handle->as_drvinfo->di_sl_private,
H1394_ALLOC_CMD_NOSLEEP, &cmd, &cmd_priv);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
hci1394_async_hcicmd_init(async_handle, cmd, cmd_priv, hcicmd);
cmd_priv->bus_generation = async_handle->as_drvinfo->di_gencnt;
cmd->bus_generation = async_handle->as_drvinfo->di_gencnt;
switch (*tcode) {
case IEEE1394_TCODE_READ_QUADLET:
status = hci1394_async_arreq_read_qrd(async_handle, pkt,
*hcicmd, size);
if (status != DDI_SUCCESS) {
hci1394_async_response_complete(async_handle, cmd,
cmd_priv);
*hcicmd = NULL;
return (DDI_SUCCESS);
}
break;
case IEEE1394_TCODE_WRITE_QUADLET:
status = hci1394_async_arreq_read_qwr(async_handle, pkt,
*hcicmd, size);
if (status != DDI_SUCCESS) {
hci1394_async_response_complete(async_handle, cmd,
cmd_priv);
*hcicmd = NULL;
return (DDI_SUCCESS);
}
break;
case IEEE1394_TCODE_READ_BLOCK:
status = hci1394_async_arreq_read_brd(async_handle, pkt,
*hcicmd, size);
if (status != DDI_SUCCESS) {
hci1394_async_response_complete(async_handle, cmd,
cmd_priv);
*hcicmd = NULL;
return (DDI_SUCCESS);
}
break;
case IEEE1394_TCODE_WRITE_BLOCK:
status = hci1394_async_arreq_read_bwr(async_handle, pkt,
*hcicmd, size);
if (status != DDI_SUCCESS) {
hci1394_async_response_complete(async_handle, cmd,
cmd_priv);
*hcicmd = NULL;
return (DDI_SUCCESS);
}
break;
case IEEE1394_TCODE_LOCK:
status = hci1394_async_arreq_read_lck(async_handle, pkt,
*hcicmd, size);
if (status != DDI_SUCCESS) {
hci1394_async_response_complete(async_handle, cmd,
cmd_priv);
*hcicmd = NULL;
return (DDI_SUCCESS);
}
break;
case IEEE1394_TCODE_PHY:
status = hci1394_async_arreq_read_phy(async_handle, pkt,
*hcicmd, size, &is_reset_token);
if (status != DDI_SUCCESS) {
hci1394_async_response_complete(async_handle, cmd,
cmd_priv);
*hcicmd = NULL;
return (DDI_SUCCESS);
}
if (is_reset_token == B_TRUE) {
hci1394_async_response_complete(async_handle, cmd,
cmd_priv);
*hcicmd = NULL;
return (DDI_SUCCESS);
}
break;
default:
return (DDI_FAILURE);
}
if ((((*hcicmd)->ac_dest & IEEE1394_NODE_NUM_MASK) ==
IEEE1394_BROADCAST_NODEID) && ((*tcode !=
IEEE1394_TCODE_WRITE_QUADLET) && (*tcode !=
IEEE1394_TCODE_WRITE_BLOCK))) {
hci1394_async_response_complete(async_handle, cmd, cmd_priv);
*hcicmd = NULL;
return (DDI_SUCCESS);
} else if ((((*hcicmd)->ac_dest & IEEE1394_NODE_NUM_MASK) ==
IEEE1394_BROADCAST_NODEID)) {
cmd->broadcast = 1;
}
return (DDI_SUCCESS);
}
static int
hci1394_async_arreq_read_qrd(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size)
{
h1394_cmd_priv_t *cmd_priv;
cmd1394_cmd_t *cmd;
uint32_t quadlet;
ASSERT(async_handle != NULL);
ASSERT(pkt != NULL);
ASSERT(hcicmd != NULL);
ASSERT(size != NULL);
cmd = hcicmd->ac_cmd;
cmd_priv = hcicmd->ac_priv;
cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD;
*size = DESC_SZ_AR_READQUAD_REQ;
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q4);
hcicmd->ac_status = HCI1394_DESC_EVT_GET(quadlet);
cmd_priv->speed = HCI1394_DESC_AR_SPD_GET(quadlet);
cmd_priv->recv_tstamp = HCI1394_DESC_TIMESTAMP_GET(quadlet);
hcicmd->ac_qcmd.qc_timestamp = hci1394_async_timeout_calc(async_handle,
cmd_priv->recv_tstamp);
if ((hcicmd->ac_status != OHCI_ACK_COMPLETE) &&
(hcicmd->ac_status != OHCI_ACK_PENDING)) {
return (DDI_FAILURE);
}
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q1);
hcicmd->ac_dest = HCI1394_DESC_DESTID_GET(quadlet);
hcicmd->ac_tlabel.tbi_tlabel = HCI1394_DESC_TLABEL_GET(quadlet);
hcicmd->ac_mblk_alloc = B_FALSE;
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q2);
cmd->nodeID = HCI1394_DESC_SRCID_GET(quadlet);
cmd->cmd_addr = HCI1394_TO_ADDR_HI(quadlet);
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q3);
cmd->cmd_addr |= HCI1394_TO_ADDR_LO(quadlet);
return (DDI_SUCCESS);
}
static int
hci1394_async_arreq_read_qwr(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size)
{
h1394_cmd_priv_t *cmd_priv;
cmd1394_cmd_t *cmd;
uint32_t quadlet;
ASSERT(async_handle != NULL);
ASSERT(pkt != NULL);
ASSERT(hcicmd != NULL);
ASSERT(size != NULL);
cmd = hcicmd->ac_cmd;
cmd_priv = hcicmd->ac_priv;
cmd->cmd_type = CMD1394_ASYNCH_WR_QUAD;
*size = DESC_SZ_AR_WRITEQUAD_REQ;
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q5);
hcicmd->ac_status = HCI1394_DESC_EVT_GET(quadlet);
cmd_priv->speed = HCI1394_DESC_AR_SPD_GET(quadlet);
cmd_priv->recv_tstamp = HCI1394_DESC_TIMESTAMP_GET(quadlet);
hcicmd->ac_qcmd.qc_timestamp = hci1394_async_timeout_calc(async_handle,
cmd_priv->recv_tstamp);
if ((hcicmd->ac_status != OHCI_ACK_COMPLETE) &&
(hcicmd->ac_status != OHCI_ACK_PENDING)) {
return (DDI_FAILURE);
}
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q1);
hcicmd->ac_dest = HCI1394_DESC_DESTID_GET(quadlet);
hcicmd->ac_tlabel.tbi_tlabel = HCI1394_DESC_TLABEL_GET(quadlet);
hcicmd->ac_mblk_alloc = B_FALSE;
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q2);
cmd->nodeID = HCI1394_DESC_SRCID_GET(quadlet);
cmd->cmd_addr = HCI1394_TO_ADDR_HI(quadlet);
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q3);
cmd->cmd_addr |= HCI1394_TO_ADDR_LO(quadlet);
hci1394_q_ar_rep_get8(async_handle->as_arreq_q,
(uint8_t *)&cmd->cmd_u.q.quadlet_data, (uint8_t *)&pkt->q4,
IEEE1394_QUADLET);
return (DDI_SUCCESS);
}
static int
hci1394_async_arreq_read_brd(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size)
{
h1394_cmd_priv_t *cmd_priv;
cmd1394_cmd_t *cmd;
uint32_t quadlet;
ASSERT(async_handle != NULL);
ASSERT(pkt != NULL);
ASSERT(hcicmd != NULL);
ASSERT(size != NULL);
cmd = hcicmd->ac_cmd;
cmd_priv = hcicmd->ac_priv;
cmd->cmd_type = CMD1394_ASYNCH_RD_BLOCK;
*size = DESC_SZ_AR_READBLOCK_REQ;
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q5);
hcicmd->ac_status = HCI1394_DESC_EVT_GET(quadlet);
cmd_priv->speed = HCI1394_DESC_AR_SPD_GET(quadlet);
cmd_priv->recv_tstamp = HCI1394_DESC_TIMESTAMP_GET(quadlet);
hcicmd->ac_qcmd.qc_timestamp = hci1394_async_timeout_calc(async_handle,
cmd_priv->recv_tstamp);
if ((hcicmd->ac_status != OHCI_ACK_COMPLETE) &&
(hcicmd->ac_status != OHCI_ACK_PENDING)) {
return (DDI_FAILURE);
}
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q1);
hcicmd->ac_dest = HCI1394_DESC_DESTID_GET(quadlet);
hcicmd->ac_tlabel.tbi_tlabel = HCI1394_DESC_TLABEL_GET(quadlet);
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q2);
cmd->nodeID = HCI1394_DESC_SRCID_GET(quadlet);
cmd->cmd_addr = HCI1394_TO_ADDR_HI(quadlet);
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q3);
cmd->cmd_addr |= HCI1394_TO_ADDR_LO(quadlet);
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q4);
cmd->cmd_u.b.blk_length = HCI1394_DESC_DATALEN_GET(quadlet);
cmd->cmd_u.b.data_block = allocb(cmd->cmd_u.b.blk_length, 0);
if (cmd->cmd_u.b.data_block == NULL) {
return (DDI_FAILURE);
}
hcicmd->ac_mblk_alloc = B_TRUE;
return (DDI_SUCCESS);
}
static int
hci1394_async_arreq_read_bwr(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size)
{
h1394_cmd_priv_t *cmd_priv;
uint32_t *local_addr;
cmd1394_cmd_t *cmd;
uint32_t quadlet;
ASSERT(async_handle != NULL);
ASSERT(pkt != NULL);
ASSERT(hcicmd != NULL);
ASSERT(size != NULL);
cmd = hcicmd->ac_cmd;
cmd_priv = hcicmd->ac_priv;
cmd->cmd_type = CMD1394_ASYNCH_WR_BLOCK;
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q4);
cmd->cmd_u.b.blk_length = HCI1394_DESC_DATALEN_GET(quadlet);
*size = DESC_SZ_AR_WRITEBLOCK_REQ +
HCI1394_ALIGN_QUAD(cmd->cmd_u.b.blk_length);
local_addr = (uint32_t *)(((uintptr_t)(&pkt->q5)) +
((uintptr_t)HCI1394_ALIGN_QUAD(cmd->cmd_u.b.blk_length)));
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, local_addr);
hcicmd->ac_status = HCI1394_DESC_EVT_GET(quadlet);
cmd_priv->speed = HCI1394_DESC_AR_SPD_GET(quadlet);
cmd_priv->recv_tstamp = HCI1394_DESC_TIMESTAMP_GET(quadlet);
hcicmd->ac_qcmd.qc_timestamp = hci1394_async_timeout_calc(async_handle,
cmd_priv->recv_tstamp);
if ((hcicmd->ac_status != OHCI_ACK_COMPLETE) &&
(hcicmd->ac_status != OHCI_ACK_PENDING)) {
return (DDI_FAILURE);
}
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q1);
hcicmd->ac_dest = HCI1394_DESC_DESTID_GET(quadlet);
hcicmd->ac_tlabel.tbi_tlabel = HCI1394_DESC_TLABEL_GET(quadlet);
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q2);
cmd->nodeID = HCI1394_DESC_SRCID_GET(quadlet);
cmd->cmd_addr = HCI1394_TO_ADDR_HI(quadlet);
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q3);
cmd->cmd_addr |= HCI1394_TO_ADDR_LO(quadlet);
cmd->cmd_u.b.data_block = allocb(cmd->cmd_u.b.blk_length, 0);
if (cmd->cmd_u.b.data_block == NULL) {
return (DDI_FAILURE);
}
hcicmd->ac_mblk_alloc = B_TRUE;
hci1394_q_ar_rep_get8(async_handle->as_arreq_q,
(uint8_t *)cmd->cmd_u.b.data_block->b_wptr,
(uint8_t *)&pkt->q5, cmd->cmd_u.b.blk_length);
cmd->cmd_u.b.data_block->b_wptr += cmd->cmd_u.b.blk_length;
return (DDI_SUCCESS);
}
static int
hci1394_async_arreq_read_lck(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size)
{
h1394_cmd_priv_t *cmd_priv;
uint32_t *local_addr;
cmd1394_cmd_t *cmd;
uint8_t *data_addr;
uint32_t quadlet;
uint32_t length;
ASSERT(async_handle != NULL);
ASSERT(pkt != NULL);
ASSERT(hcicmd != NULL);
ASSERT(size != NULL);
cmd = hcicmd->ac_cmd;
cmd_priv = hcicmd->ac_priv;
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q4);
length = HCI1394_DESC_DATALEN_GET(quadlet);
*size = DESC_SZ_AR_LOCK_REQ + HCI1394_ALIGN_QUAD(length);
if (length == DESC_TWO_QUADS) {
cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
cmd->cmd_u.l32.lock_type = HCI1394_DESC_EXTTCODE_GET(quadlet);
} else if (length == DESC_TWO_OCTLETS) {
cmd->cmd_type = CMD1394_ASYNCH_LOCK_64;
cmd->cmd_u.l64.lock_type = HCI1394_DESC_EXTTCODE_GET(quadlet);
} else {
return (DDI_FAILURE);
}
local_addr = (uint32_t *)(((uintptr_t)(&pkt->q5)) +
((uintptr_t)HCI1394_ALIGN_QUAD(length)));
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, local_addr);
hcicmd->ac_status = HCI1394_DESC_EVT_GET(quadlet);
cmd_priv->speed = HCI1394_DESC_AR_SPD_GET(quadlet);
cmd_priv->recv_tstamp = HCI1394_DESC_TIMESTAMP_GET(quadlet);
hcicmd->ac_qcmd.qc_timestamp = hci1394_async_timeout_calc(async_handle,
cmd_priv->recv_tstamp);
if ((hcicmd->ac_status != OHCI_ACK_COMPLETE) &&
(hcicmd->ac_status != OHCI_ACK_PENDING)) {
return (DDI_FAILURE);
}
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q1);
hcicmd->ac_dest = HCI1394_DESC_DESTID_GET(quadlet);
hcicmd->ac_tlabel.tbi_tlabel = HCI1394_DESC_TLABEL_GET(quadlet);
hcicmd->ac_mblk_alloc = B_FALSE;
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q2);
cmd->nodeID = HCI1394_DESC_SRCID_GET(quadlet);
cmd->cmd_addr = HCI1394_TO_ADDR_HI(quadlet);
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q3);
cmd->cmd_addr |= HCI1394_TO_ADDR_LO(quadlet);
if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
data_addr = (uint8_t *)&pkt->q5;
hci1394_q_ar_rep_get8(async_handle->as_arreq_q,
(uint8_t *)&cmd->cmd_u.l32.arg_value, data_addr,
IEEE1394_QUADLET);
data_addr = (uint8_t *)((uintptr_t)data_addr +
(uintptr_t)IEEE1394_QUADLET);
hci1394_q_ar_rep_get8(async_handle->as_arreq_q,
(uint8_t *)&cmd->cmd_u.l32.data_value, data_addr,
IEEE1394_QUADLET);
cmd->cmd_u.l32.arg_value = HCI1394_ARITH_LOCK_SWAP32(
cmd->cmd_u.l32.lock_type, cmd->cmd_u.l32.arg_value);
cmd->cmd_u.l32.data_value = HCI1394_ARITH_LOCK_SWAP32(
cmd->cmd_u.l32.lock_type, cmd->cmd_u.l32.data_value);
} else if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) {
data_addr = (uint8_t *)&pkt->q5;
hci1394_q_ar_rep_get8(async_handle->as_arreq_q,
(uint8_t *)&cmd->cmd_u.l64.arg_value, data_addr,
IEEE1394_OCTLET);
data_addr = (uint8_t *)((uintptr_t)data_addr +
(uintptr_t)IEEE1394_OCTLET);
hci1394_q_ar_rep_get8(async_handle->as_arreq_q,
(uint8_t *)&cmd->cmd_u.l64.data_value, data_addr,
IEEE1394_OCTLET);
cmd->cmd_u.l64.arg_value = HCI1394_ARITH_LOCK_SWAP64(
cmd->cmd_u.l64.lock_type, cmd->cmd_u.l64.arg_value);
cmd->cmd_u.l64.data_value = HCI1394_ARITH_LOCK_SWAP64(
cmd->cmd_u.l64.lock_type, cmd->cmd_u.l64.data_value);
}
return (DDI_SUCCESS);
}
static int
hci1394_async_arreq_read_phy(hci1394_async_handle_t async_handle,
hci1394_basic_pkt_t *pkt, hci1394_async_cmd_t *hcicmd, uint_t *size,
boolean_t *bus_reset_token)
{
cmd1394_cmd_t *cmd;
uint32_t quadlet;
uint32_t data1;
uint32_t data2;
ASSERT(async_handle != NULL);
ASSERT(pkt != NULL);
ASSERT(hcicmd != NULL);
ASSERT(size != NULL);
cmd = hcicmd->ac_cmd;
cmd->cmd_type = CMD1394_ASYNCH_WR_QUAD;
*size = DESC_SZ_AR_PHY;
quadlet = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q4);
hcicmd->ac_status = HCI1394_DESC_EVT_GET(quadlet);
hcicmd->ac_priv->speed = HCI1394_DESC_AR_SPD_GET(quadlet);
hcicmd->ac_priv->recv_tstamp = HCI1394_DESC_TIMESTAMP_GET(quadlet);
hcicmd->ac_mblk_alloc = B_FALSE;
data1 = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q2);
data2 = hci1394_q_ar_get32(async_handle->as_arreq_q, &pkt->q3);
if (hcicmd->ac_status == OHCI_EVT_BUS_RESET) {
*bus_reset_token = B_TRUE;
async_handle->as_phy_reset = HCI1394_DESC_PHYGEN_GET(data2);
if (async_handle->as_phy_reset == hci1394_ohci_current_busgen(
async_handle->as_ohci)) {
async_handle->as_flushing_arreq = B_FALSE;
}
return (DDI_SUCCESS);
}
*bus_reset_token = B_FALSE;
if (data1 != ~data2) {
return (DDI_FAILURE);
}
cmd->cmd_u.q.quadlet_data = data1;
return (DDI_SUCCESS);
}
int
hci1394_async_phy(hci1394_async_handle_t async_handle, cmd1394_cmd_t *cmd,
h1394_cmd_priv_t *cmd_priv, int *result)
{
hci1394_basic_pkt_t header;
hci1394_async_cmd_t *hcicmd;
int status;
ASSERT(async_handle != NULL);
ASSERT(cmd != NULL);
ASSERT(cmd_priv != NULL);
ASSERT(result != NULL);
if (cmd_priv->bus_generation != hci1394_ohci_current_busgen(
async_handle->as_ohci)) {
*result = H1394_STATUS_INVALID_BUSGEN;
return (DDI_FAILURE);
}
hci1394_async_hcicmd_init(async_handle, cmd, cmd_priv, &hcicmd);
hcicmd->ac_tlabel_alloc = B_FALSE;
header.q1 = DESC_ATREQ_Q1_PHY;
header.q2 = cmd->cmd_u.q.quadlet_data;
header.q3 = ~header.q2;
status = hci1394_q_at(async_handle->as_atreq_q, &hcicmd->ac_qcmd,
&header, DESC_PKT_HDRLEN_AT_PHY, result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
hci1394_async_write(hci1394_async_handle_t async_handle, cmd1394_cmd_t *cmd,
h1394_cmd_priv_t *cmd_priv, int *result)
{
hci1394_async_cmd_t *hcicmd;
hci1394_basic_pkt_t header;
int status;
ASSERT(async_handle != NULL);
ASSERT(cmd != NULL);
ASSERT(cmd_priv != NULL);
ASSERT(result != NULL);
if (cmd_priv->bus_generation != hci1394_ohci_current_busgen(
async_handle->as_ohci)) {
*result = H1394_STATUS_INVALID_BUSGEN;
return (DDI_FAILURE);
}
hci1394_async_hcicmd_init(async_handle, cmd, cmd_priv, &hcicmd);
hcicmd->ac_dest = (uint_t)(cmd->cmd_addr >> IEEE1394_ADDR_PHY_ID_SHIFT);
status = hci1394_tlabel_alloc(async_handle->as_tlabel, hcicmd->ac_dest,
&hcicmd->ac_tlabel);
if (status != DDI_SUCCESS) {
*result = H1394_STATUS_EMPTY_TLABEL;
return (DDI_FAILURE);
}
header.q1 = 0;
if ((hcicmd->ac_dest & IEEE1394_BUS_NUM_MASK) !=
IEEE1394_BUS_NUM_MASK) {
header.q1 |= DESC_AT_SRCBUSID;
}
header.q1 |= HCI1394_DESC_AT_SPD_SET(cmd_priv->speed) |
HCI1394_DESC_TLABEL_SET(hcicmd->ac_tlabel.tbi_tlabel);
header.q2 = (uint32_t)(cmd->cmd_addr >> 32);
header.q3 = (uint32_t)(cmd->cmd_addr & DESC_PKT_DESTOFFLO_MASK);
hci1394_tlabel_register(async_handle->as_tlabel, &hcicmd->ac_tlabel,
hcicmd);
if (cmd->cmd_type == CMD1394_ASYNCH_WR_QUAD) {
header.q1 |= DESC_ATREQ_Q1_QWR;
header.q4 = cmd->cmd_u.q.quadlet_data;
status = hci1394_q_at(async_handle->as_atreq_q,
&hcicmd->ac_qcmd, &header, DESC_PKT_HDRLEN_AT_WRITEQUAD,
result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
} else {
header.q1 |= DESC_ATREQ_Q1_BWR;
header.q4 = HCI1394_DESC_DATALEN_SET(cmd_priv->mblk.length);
status = hci1394_q_at_with_mblk(async_handle->as_atreq_q,
&hcicmd->ac_qcmd, &header, DESC_PKT_HDRLEN_AT_WRITEBLOCK,
&cmd_priv->mblk, result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
int
hci1394_async_read(hci1394_async_handle_t async_handle, cmd1394_cmd_t *cmd,
h1394_cmd_priv_t *cmd_priv, int *result)
{
hci1394_basic_pkt_t header;
int status;
hci1394_async_cmd_t *hcicmd;
ASSERT(async_handle != NULL);
ASSERT(cmd != NULL);
ASSERT(cmd_priv != NULL);
ASSERT(result != NULL);
if (cmd_priv->bus_generation != hci1394_ohci_current_busgen(
async_handle->as_ohci)) {
*result = H1394_STATUS_INVALID_BUSGEN;
return (DDI_FAILURE);
}
hci1394_async_hcicmd_init(async_handle, cmd, cmd_priv, &hcicmd);
hcicmd->ac_dest = (uint_t)(cmd->cmd_addr >> IEEE1394_ADDR_PHY_ID_SHIFT);
status = hci1394_tlabel_alloc(async_handle->as_tlabel, hcicmd->ac_dest,
&hcicmd->ac_tlabel);
if (status != DDI_SUCCESS) {
*result = H1394_STATUS_EMPTY_TLABEL;
return (DDI_FAILURE);
}
header.q1 = 0;
if ((hcicmd->ac_dest & IEEE1394_BUS_NUM_MASK) !=
IEEE1394_BUS_NUM_MASK) {
header.q1 |= DESC_AT_SRCBUSID;
}
header.q1 |= HCI1394_DESC_AT_SPD_SET(cmd_priv->speed) |
HCI1394_DESC_TLABEL_SET(hcicmd->ac_tlabel.tbi_tlabel);
header.q2 = (uint32_t)(cmd->cmd_addr >> 32);
header.q3 = (uint32_t)(cmd->cmd_addr & DESC_PKT_DESTOFFLO_MASK);
hci1394_tlabel_register(async_handle->as_tlabel, &hcicmd->ac_tlabel,
hcicmd);
if (cmd->cmd_type == CMD1394_ASYNCH_RD_QUAD) {
header.q1 |= DESC_ATREQ_Q1_QRD;
header.q4 = 0;
status = hci1394_q_at(async_handle->as_atreq_q,
&hcicmd->ac_qcmd, &header, DESC_PKT_HDRLEN_AT_READQUAD,
result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
} else {
header.q1 |= DESC_ATREQ_Q1_BRD;
header.q4 = HCI1394_DESC_DATALEN_SET(cmd_priv->mblk.length);
status = hci1394_q_at(async_handle->as_atreq_q,
&hcicmd->ac_qcmd, &header, DESC_PKT_HDRLEN_AT_READBLOCK,
result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
int
hci1394_async_lock(hci1394_async_handle_t async_handle, cmd1394_cmd_t *cmd,
h1394_cmd_priv_t *cmd_priv, int *result)
{
hci1394_basic_pkt_t header;
hci1394_async_cmd_t *hcicmd;
uint32_t data32[2];
uint64_t data64[2];
uint8_t *datap;
uint_t size;
int status;
ASSERT(async_handle != NULL);
ASSERT(cmd != NULL);
ASSERT(cmd_priv != NULL);
ASSERT(result != NULL);
if (cmd_priv->bus_generation != hci1394_ohci_current_busgen(
async_handle->as_ohci)) {
*result = H1394_STATUS_INVALID_BUSGEN;
return (DDI_FAILURE);
}
hci1394_async_hcicmd_init(async_handle, cmd, cmd_priv, &hcicmd);
hcicmd->ac_dest = (uint_t)(cmd->cmd_addr >> IEEE1394_ADDR_PHY_ID_SHIFT);
status = hci1394_tlabel_alloc(async_handle->as_tlabel, hcicmd->ac_dest,
&hcicmd->ac_tlabel);
if (status != DDI_SUCCESS) {
*result = H1394_STATUS_EMPTY_TLABEL;
return (DDI_FAILURE);
}
hci1394_tlabel_register(async_handle->as_tlabel, &hcicmd->ac_tlabel,
hcicmd);
header.q1 = DESC_ATREQ_Q1_LCK;
if ((hcicmd->ac_dest & IEEE1394_BUS_NUM_MASK) !=
IEEE1394_BUS_NUM_MASK) {
header.q1 |= DESC_AT_SRCBUSID;
}
header.q1 |= HCI1394_DESC_AT_SPD_SET(cmd_priv->speed) |
HCI1394_DESC_TLABEL_SET(hcicmd->ac_tlabel.tbi_tlabel);
header.q2 = (uint32_t)(cmd->cmd_addr >> 32);
header.q3 = (uint32_t)(cmd->cmd_addr & DESC_PKT_DESTOFFLO_MASK);
if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
size = DESC_TWO_QUADS;
header.q4 = HCI1394_DESC_DATALEN_SET(size) |
HCI1394_DESC_EXTTCODE_SET(cmd->cmd_u.l32.lock_type);
data32[0] = HCI1394_ARITH_LOCK_SWAP32(
cmd->cmd_u.l32.lock_type, cmd->cmd_u.l32.arg_value);
data32[1] = HCI1394_ARITH_LOCK_SWAP32(
cmd->cmd_u.l32.lock_type, cmd->cmd_u.l32.data_value);
datap = (uint8_t *)data32;
} else if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) {
size = DESC_TWO_OCTLETS;
header.q4 = HCI1394_DESC_DATALEN_SET(size) |
HCI1394_DESC_EXTTCODE_SET(cmd->cmd_u.l64.lock_type);
data64[0] = HCI1394_ARITH_LOCK_SWAP64(
cmd->cmd_u.l64.lock_type, cmd->cmd_u.l64.arg_value);
data64[1] = HCI1394_ARITH_LOCK_SWAP64(
cmd->cmd_u.l64.lock_type, cmd->cmd_u.l64.data_value);
datap = (uint8_t *)data64;
} else {
*result = H1394_STATUS_INTERNAL_ERROR;
return (DDI_FAILURE);
}
status = hci1394_q_at_with_data(async_handle->as_atreq_q,
&hcicmd->ac_qcmd, &header, DESC_PKT_HDRLEN_AT_LOCK, datap, size,
result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
hci1394_async_write_response(hci1394_async_handle_t async_handle,
cmd1394_cmd_t *cmd, h1394_cmd_priv_t *cmd_priv, int *result)
{
hci1394_basic_pkt_t header;
int status;
hci1394_async_cmd_t *hcicmd;
ASSERT(async_handle != NULL);
ASSERT(cmd != NULL);
ASSERT(cmd_priv != NULL);
ASSERT(result != NULL);
if (cmd_priv->bus_generation != hci1394_ohci_current_busgen(
async_handle->as_ohci)) {
*result = H1394_STATUS_INVALID_BUSGEN;
return (DDI_FAILURE);
}
hcicmd = (hci1394_async_cmd_t *)cmd_priv->hal_overhead;
hcicmd->ac_qcmd.qc_generation = cmd_priv->bus_generation;
header.q1 = DESC_ATRESP_Q1_WR;
if ((cmd->nodeID & IEEE1394_BUS_NUM_MASK) != IEEE1394_BUS_NUM_MASK) {
header.q1 |= DESC_AT_SRCBUSID;
}
header.q1 |= HCI1394_DESC_AT_SPD_SET(cmd_priv->speed) |
HCI1394_DESC_TLABEL_SET(hcicmd->ac_tlabel.tbi_tlabel);
header.q2 = (HCI1394_DESC_DESTID_SET(cmd->nodeID) |
HCI1394_DESC_RCODE_SET(cmd->cmd_result));
header.q3 = 0;
status = hci1394_q_at(async_handle->as_atresp_q, &hcicmd->ac_qcmd,
&header, DESC_PKT_HDRLEN_AT_WRITE_RESP, result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
hci1394_async_read_response(hci1394_async_handle_t async_handle,
cmd1394_cmd_t *cmd, h1394_cmd_priv_t *cmd_priv, int *result)
{
hci1394_basic_pkt_t header;
int status;
hci1394_async_cmd_t *hcicmd;
ASSERT(async_handle != NULL);
ASSERT(cmd != NULL);
ASSERT(cmd_priv != NULL);
ASSERT(result != NULL);
if (cmd_priv->bus_generation != hci1394_ohci_current_busgen(
async_handle->as_ohci)) {
*result = H1394_STATUS_INVALID_BUSGEN;
return (DDI_FAILURE);
}
hcicmd = (hci1394_async_cmd_t *)cmd_priv->hal_overhead;
hcicmd->ac_qcmd.qc_generation = cmd_priv->bus_generation;
header.q1 = 0;
if ((cmd->nodeID & IEEE1394_BUS_NUM_MASK) != IEEE1394_BUS_NUM_MASK) {
header.q1 |= DESC_AT_SRCBUSID;
}
header.q1 |= HCI1394_DESC_AT_SPD_SET(cmd_priv->speed) |
HCI1394_DESC_TLABEL_SET(hcicmd->ac_tlabel.tbi_tlabel);
header.q2 = (uint32_t)(HCI1394_DESC_DESTID_SET(cmd->nodeID) |
HCI1394_DESC_RCODE_SET(cmd->cmd_result));
header.q3 = 0;
if (cmd->cmd_type == CMD1394_ASYNCH_RD_QUAD) {
header.q1 |= DESC_ATRESP_Q1_QRD;
if (cmd->cmd_result == IEEE1394_RESP_COMPLETE) {
header.q4 = cmd->cmd_u.q.quadlet_data;
} else {
header.q4 = 0x0;
}
status = hci1394_q_at(async_handle->as_atresp_q,
&hcicmd->ac_qcmd, &header, DESC_PKT_HDRLEN_AT_READQUAD_RESP,
result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
} else if ((cmd->cmd_type == CMD1394_ASYNCH_RD_BLOCK) &&
(cmd->cmd_result != IEEE1394_RESP_COMPLETE)) {
header.q1 |= DESC_ATRESP_Q1_BRD;
header.q4 = 0x0;
status = hci1394_q_at(async_handle->as_atresp_q,
&hcicmd->ac_qcmd, &header,
DESC_PKT_HDRLEN_AT_READBLOCK_RESP, result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
} else {
header.q1 |= DESC_ATRESP_Q1_BRD;
header.q4 = HCI1394_DESC_DATALEN_SET(cmd->cmd_u.b.blk_length);
status = hci1394_q_at_with_mblk(async_handle->as_atresp_q,
&hcicmd->ac_qcmd, &header,
DESC_PKT_HDRLEN_AT_READBLOCK_RESP, &cmd_priv->mblk, result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
int
hci1394_async_lock_response(hci1394_async_handle_t async_handle,
cmd1394_cmd_t *cmd, h1394_cmd_priv_t *cmd_priv, int *result)
{
hci1394_basic_pkt_t header;
hci1394_async_cmd_t *hcicmd;
uint32_t data32;
uint64_t data64;
uint8_t *datap;
uint_t size;
int status;
ASSERT(async_handle != NULL);
ASSERT(cmd != NULL);
ASSERT(cmd_priv != NULL);
ASSERT(result != NULL);
if (cmd_priv->bus_generation != hci1394_ohci_current_busgen(
async_handle->as_ohci)) {
*result = H1394_STATUS_INVALID_BUSGEN;
return (DDI_FAILURE);
}
hcicmd = (hci1394_async_cmd_t *)cmd_priv->hal_overhead;
hcicmd->ac_qcmd.qc_generation = cmd_priv->bus_generation;
header.q1 = DESC_ATRESP_Q1_LCK;
if ((cmd->nodeID & IEEE1394_BUS_NUM_MASK) != IEEE1394_BUS_NUM_MASK) {
header.q1 |= DESC_AT_SRCBUSID;
}
header.q1 |= HCI1394_DESC_AT_SPD_SET(cmd_priv->speed) |
HCI1394_DESC_TLABEL_SET(hcicmd->ac_tlabel.tbi_tlabel);
header.q2 = (uint32_t)(HCI1394_DESC_DESTID_SET(cmd->nodeID) |
HCI1394_DESC_RCODE_SET(cmd->cmd_result));
header.q3 = 0;
if (cmd->cmd_result != IEEE1394_RESP_COMPLETE) {
size = 0;
if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
header.q4 = HCI1394_DESC_DATALEN_SET(size) |
HCI1394_DESC_EXTTCODE_SET(cmd->cmd_u.l32.lock_type);
} else {
header.q4 = HCI1394_DESC_DATALEN_SET(size) |
HCI1394_DESC_EXTTCODE_SET(cmd->cmd_u.l64.lock_type);
}
status = hci1394_q_at(async_handle->as_atresp_q,
&hcicmd->ac_qcmd, &header, DESC_PKT_HDRLEN_AT_LOCK_RESP,
result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
size = IEEE1394_QUADLET;
header.q4 = HCI1394_DESC_DATALEN_SET(size) |
HCI1394_DESC_EXTTCODE_SET(cmd->cmd_u.l32.lock_type);
data32 = HCI1394_ARITH_LOCK_SWAP32(
cmd->cmd_u.l32.lock_type, cmd->cmd_u.l32.old_value);
datap = (uint8_t *)&data32;
} else if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) {
size = IEEE1394_OCTLET;
header.q4 = HCI1394_DESC_DATALEN_SET(size) |
HCI1394_DESC_EXTTCODE_SET(cmd->cmd_u.l64.lock_type);
data64 = HCI1394_ARITH_LOCK_SWAP64(
cmd->cmd_u.l64.lock_type, cmd->cmd_u.l64.old_value);
datap = (uint8_t *)&data64;
} else {
*result = H1394_STATUS_INTERNAL_ERROR;
return (DDI_FAILURE);
}
status = hci1394_q_at_with_data(async_handle->as_atresp_q,
&hcicmd->ac_qcmd, &header, DESC_PKT_HDRLEN_AT_LOCK_RESP, datap,
size, result);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
hci1394_async_response_complete(hci1394_async_handle_t async_handle,
cmd1394_cmd_t *cmd, h1394_cmd_priv_t *cmd_priv)
{
hci1394_async_cmd_t *hcicmd;
ASSERT(async_handle != NULL);
ASSERT(cmd != NULL);
ASSERT(cmd_priv != NULL);
hcicmd = (hci1394_async_cmd_t *)cmd_priv->hal_overhead;
if (hcicmd->ac_mblk_alloc == B_TRUE) {
if (cmd->cmd_u.b.data_block != NULL) {
freeb(cmd->cmd_u.b.data_block);
}
}
(void) h1394_free_cmd((void *)async_handle->as_drvinfo->di_sl_private,
&cmd);
}
static void
hci1394_async_pending_timeout(hci1394_tlist_node_t *node, void *arg)
{
hci1394_async_handle_t async_handle;
hci1394_async_cmd_t *hcicmd;
async_handle = (hci1394_async_handle_t)arg;
ASSERT(async_handle != NULL);
ASSERT(node != NULL);
hcicmd = (hci1394_async_cmd_t *)node->tln_addr;
mutex_enter(&hcicmd->ac_async->as_atomic_lookup);
hci1394_tlabel_bad(async_handle->as_tlabel, &hcicmd->ac_tlabel);
mutex_exit(&hcicmd->ac_async->as_atomic_lookup);
h1394_cmd_is_complete(async_handle->as_drvinfo->di_sl_private,
hcicmd->ac_cmd, H1394_AT_REQ, H1394_CMD_ETIMEOUT);
}
static uint_t
hci1394_async_timeout_calc(hci1394_async_handle_t async_handle,
uint_t current_time)
{
uint_t split_timeout;
uint_t temp;
uint_t carry;
uint_t z;
split_timeout = hci1394_csr_split_timeout_get(async_handle->as_csr);
temp = (current_time & OHCI_CYCLE_CNT_MASK) + (split_timeout &
OHCI_CYCLE_CNT_MASK);
if (temp < OHCI_MAX_CYCLE_CNT) {
carry = 0;
} else {
temp = temp - OHCI_MAX_CYCLE_CNT;
carry = 1;
}
z = (current_time & OHCI_CYCLE_SEC_MASK) + (split_timeout &
OHCI_CYCLE_SEC_MASK) + (carry << OHCI_CYCLE_SEC_SHIFT) + temp;
z = z & OHCI_TIMESTAMP_MASK;
return (z);
}
static int
hci1394_async_arresp_size_get(uint_t tcode, hci1394_q_handle_t q_handle,
uint32_t *addr, uint_t *size)
{
uint_t data_length;
uint32_t quadlet;
ASSERT(q_handle != NULL);
ASSERT(addr != NULL);
ASSERT(size != NULL);
if (tcode == IEEE1394_TCODE_WRITE_RESP) {
*size = DESC_PKT_HDRLEN_AT_WRITE_RESP + IEEE1394_QUADLET;
} else if (tcode == IEEE1394_TCODE_READ_QUADLET_RESP) {
*size = DESC_PKT_HDRLEN_AT_READQUAD_RESP + IEEE1394_QUADLET;
} else if (tcode == IEEE1394_TCODE_READ_BLOCK_RESP) {
quadlet = hci1394_q_ar_get32(q_handle, &addr[3]);
data_length = HCI1394_DESC_DATALEN_GET(quadlet);
*size = DESC_PKT_HDRLEN_AT_READBLOCK_RESP +
HCI1394_ALIGN_QUAD(data_length) + IEEE1394_QUADLET;
} else if (tcode == IEEE1394_TCODE_LOCK_RESP) {
quadlet = hci1394_q_ar_get32(q_handle, &addr[3]);
data_length = HCI1394_DESC_DATALEN_GET(quadlet);
*size = DESC_PKT_HDRLEN_AT_LOCK_RESP +
HCI1394_ALIGN_QUAD(data_length) + IEEE1394_QUADLET;
} else {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
hci1394_async_pending_list_flush(hci1394_async_handle_t async_handle)
{
hci1394_tlist_node_t *node;
hci1394_async_cmd_t *hcicmd;
ASSERT(async_handle != NULL);
do {
hci1394_tlist_get(async_handle->as_pending_list, &node);
if (node != NULL) {
hcicmd = (hci1394_async_cmd_t *)node->tln_addr;
hcicmd->ac_state = HCI1394_CMD_STATE_COMPLETED;
h1394_cmd_is_complete(
async_handle->as_drvinfo->di_sl_private,
hcicmd->ac_cmd, H1394_AT_REQ,
H1394_CMD_EBUSRESET);
}
} while (node != NULL);
}
static void
hci1394_async_atreq_start(void *async, uint32_t command_ptr)
{
hci1394_async_handle_t async_handle;
ASSERT(async != NULL);
async_handle = (hci1394_async_handle_t)async;
hci1394_ohci_atreq_start(async_handle->as_ohci, command_ptr);
}
static void
hci1394_async_atreq_wake(void *async)
{
hci1394_async_handle_t async_handle;
ASSERT(async != NULL);
async_handle = (hci1394_async_handle_t)async;
hci1394_ohci_atreq_wake(async_handle->as_ohci);
}
void
hci1394_async_atreq_reset(hci1394_async_handle_t async_handle)
{
ASSERT(async_handle != NULL);
hci1394_ohci_atreq_stop(async_handle->as_ohci);
hci1394_q_stop(async_handle->as_atreq_q);
}
static void
hci1394_async_atreq_flush(hci1394_async_handle_t async_handle)
{
boolean_t request_available;
ASSERT(async_handle != NULL);
hci1394_ohci_intr_clear(async_handle->as_ohci, OHCI_INTR_REQ_TX_CMPLT);
do {
(void) hci1394_async_atreq_process(async_handle,
B_TRUE, &request_available);
} while (request_available == B_TRUE);
}
static void
hci1394_async_arresp_start(void *async, uint32_t command_ptr)
{
hci1394_async_handle_t async_handle;
ASSERT(async != NULL);
async_handle = (hci1394_async_handle_t)async;
hci1394_ohci_arresp_start(async_handle->as_ohci, command_ptr);
}
static void
hci1394_async_arresp_wake(void *async)
{
hci1394_async_handle_t async_handle;
ASSERT(async != NULL);
async_handle = (hci1394_async_handle_t)async;
hci1394_ohci_arresp_wake(async_handle->as_ohci);
}
static void
hci1394_async_arresp_flush(hci1394_async_handle_t async_handle)
{
boolean_t response_available;
ASSERT(async_handle != NULL);
hci1394_ohci_intr_clear(async_handle->as_ohci, OHCI_INTR_RSPKT);
do {
(void) hci1394_async_arresp_process(async_handle,
&response_available);
} while (response_available == B_TRUE);
}
static void
hci1394_async_arreq_start(void *async, uint32_t command_ptr)
{
hci1394_async_handle_t async_handle;
ASSERT(async != NULL);
async_handle = (hci1394_async_handle_t)async;
hci1394_ohci_arreq_start(async_handle->as_ohci, command_ptr);
}
static void
hci1394_async_arreq_wake(void *async)
{
hci1394_async_handle_t async_handle;
ASSERT(async != NULL);
async_handle = (hci1394_async_handle_t)async;
hci1394_ohci_arreq_wake(async_handle->as_ohci);
}
static void
hci1394_async_arreq_flush(hci1394_async_handle_t async_handle)
{
boolean_t request_available;
ASSERT(async_handle != NULL);
if (async_handle->as_phy_reset == hci1394_ohci_current_busgen(
async_handle->as_ohci)) {
return;
}
async_handle->as_flushing_arreq = B_TRUE;
do {
(void) hci1394_async_arreq_process(async_handle,
&request_available);
} while ((request_available == B_TRUE) &&
(async_handle->as_flushing_arreq == B_TRUE));
if (request_available == B_FALSE) {
hci1394_ohci_intr_clear(async_handle->as_ohci, OHCI_INTR_RQPKT);
}
}
static void
hci1394_async_atresp_start(void *async, uint32_t command_ptr)
{
hci1394_async_handle_t async_handle;
ASSERT(async != NULL);
async_handle = (hci1394_async_handle_t)async;
hci1394_ohci_atresp_start(async_handle->as_ohci, command_ptr);
}
static void
hci1394_async_atresp_wake(void *async)
{
hci1394_async_handle_t async_handle;
ASSERT(async != NULL);
async_handle = (hci1394_async_handle_t)async;
hci1394_ohci_atresp_wake(async_handle->as_ohci);
}
void
hci1394_async_atresp_reset(hci1394_async_handle_t async_handle)
{
ASSERT(async_handle != NULL);
hci1394_ohci_atresp_stop(async_handle->as_ohci);
hci1394_q_stop(async_handle->as_atresp_q);
}
static void
hci1394_async_atresp_flush(hci1394_async_handle_t async_handle)
{
boolean_t response_available;
ASSERT(async_handle != NULL);
hci1394_ohci_intr_clear(async_handle->as_ohci, OHCI_INTR_RESP_TX_CMPLT);
do {
(void) hci1394_async_atresp_process(async_handle,
B_TRUE, &response_available);
} while (response_available == B_TRUE);
}
static void
hci1394_async_hcicmd_init(hci1394_async_handle_t async_handle,
cmd1394_cmd_t *cmd, h1394_cmd_priv_t *cmd_priv,
hci1394_async_cmd_t **hcicmd)
{
*hcicmd = (hci1394_async_cmd_t *)cmd_priv->hal_overhead;
(*hcicmd)->ac_cmd = cmd;
(*hcicmd)->ac_priv = cmd_priv;
(*hcicmd)->ac_async = async_handle;
(*hcicmd)->ac_state = HCI1394_CMD_STATE_IN_PROGRESS;
(*hcicmd)->ac_dest = 0;
(*hcicmd)->ac_tlabel_alloc = B_TRUE;
(*hcicmd)->ac_tlabel.tbi_tlabel = 0;
(*hcicmd)->ac_tlabel.tbi_destination = 0;
(*hcicmd)->ac_status = 0;
(*hcicmd)->ac_qcmd.qc_timestamp = 0;
(*hcicmd)->ac_qcmd.qc_arg = *hcicmd;
(*hcicmd)->ac_qcmd.qc_generation = cmd_priv->bus_generation;
(*hcicmd)->ac_mblk_alloc = B_FALSE;
}