/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1999-2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* These routines manipulate the 1394 asynchronous dma engines. This
* includes incoming and outgoing reads, writes, and locks and their
* associated responses.
*/
/*
* ASYNC_ARRESP_ACK_ERROR is or'd into the error status when we get an ACK error
* errors, we use this to distinguish between the errors in process_arresp().
*/
/* Macro's to help extract 48-bit 1394 address into a uint64_t */
/*
* Macro to convert a byte stream into a big endian quadlet or octlet or back
* the other way. 1394 arithmetic lock operations are done on big endian
* quadlets or octlets. compare swaps and bit masks are done on a byte streams.
* All data is treated as byte streams over the bus. These macros will convert
* the data to a big endian "integer" on x86 plaforms if the operation is an
* arithmetic lock operation. It will do nothing if it is not on x86 or is not
* an arithmetic lock operation.
*/
#ifdef _LITTLE_ENDIAN
(((tcode) == CMD1394_LOCK_FETCH_ADD) || \
((tcode) == CMD1394_LOCK_BOUNDED_ADD) || \
((tcode) == CMD1394_LOCK_WRAP_ADD)) ? \
(((tcode) == CMD1394_LOCK_FETCH_ADD) || \
((tcode) == CMD1394_LOCK_BOUNDED_ADD) || \
((tcode) == CMD1394_LOCK_WRAP_ADD)) ? \
#else
#endif
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);
void *arg);
/*
* hci1394_async_init()
* Initialize the async DMA engines and state. We init the tlabels; ATREQ
* pending Q; and ATREQ, ARRESP, ARREQ, and ATRESP Q's. init() returns a
* handle to be used in rest of the functions.
*/
int
{
int status;
/* alloc the space to keep track of the list */
/* copy in parms to our local state */
/*
* Initialize the tlabels. Reclaim a bad tlabel after the split timeout
* has gone by. This time is in reference to the point the transaction
* has been marked as bad. Therefore the tlabel will be reclaimed at
* twice the split_timeout. (i.e. if the split timeout was set to 100mS
* and the transaction has timed out, 100mS has already gone by. We need
* to wait for 100mS more before we can reuse the tlabel. Therefore, the
* reclaim time is split_timeout and not split_timeout * 2. The split
* timeout is stored as the number of bus cycles. We need to convert
* this to nS since the reclaim time is passed as nS.
*/
/*
* Initialize ATREQ pending list. A pended ATREQ will be timed out after
* "split_timeout" has gone by. split timeout is in bus cycles so we
* need to convert that to nS for the tlist timer info. We will set the
* timer resolution to 1/2 of the timeout so that we will have a worst
* case timeout of split timeout + (1/2 * split timeout). See
* hci1394_tlist.h for more information about this.
*/
/* Initialize ATREQ Q */
&async->as_atreq_q);
if (status != DDI_SUCCESS) {
*async_handle = NULL;
"");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Initialize ARRESP Q */
&async->as_arresp_q);
if (status != DDI_SUCCESS) {
*async_handle = NULL;
"");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Initialize ARREQ Q */
&async->as_arreq_q);
if (status != DDI_SUCCESS) {
*async_handle = NULL;
"");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Initialize ATRESP Q */
&async->as_atresp_q);
if (status != DDI_SUCCESS) {
*async_handle = NULL;
"");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
*async_handle = async;
return (DDI_SUCCESS);
}
/*
* hci1394_async_fini()
* Free's up the space allocated in init(). Notice that a pointer to the
* handle is used for the parameter. fini() will set your handle to NULL
* before returning.
*/
void
{
/* set handle to null. This helps catch bugs. */
*async_handle = NULL;
}
/*
* hci1394_async_suspend()
* The system is getting ready to be suspended. Make sure that all of
* the Q's are clean and that the there are no scheduled timeouts in the
* pending Q.
*/
void
{
HCI1394_TNF_HAL_STACK, "");
/* Flush out async DMA Q's */
/* Cancel any scheduled pending timeouts */
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_resume()
* Re-setup the DMA Q's during a resume after a successful suspend. The
* tlabels will be re-initialized during the bus reset and the pending Q will
* be flushed during the suspend.
*/
int
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_cmd_overhead()
* Return the size of the HAL private area to attach to every alloced 1394
* framework command. This allows us to track command state without having
* to alloc memory every time a command comes down the pipe.
*/
{
return (sizeof (hci1394_async_cmd_t));
}
/*
* hci1394_async_flush()
* Flush out the Async Q's and the ATREQ pending list. This is called every
* bus reset so that we're sync'd up with the HW and when shutting down or
* suspending to make sure we cleanup after all commands.
*/
void
{
}
/*
* hci1394_async_pending_timeout_update()
* Update the timeout for the pending list. This updates both the pending
* list timeout and time we wait to reclaim bad tlabels. timeout is the
* time in nS so we do not have to do any conversions. This routine will be
* called when the CSR split timeout registers are updated.
*/
void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_atreq_process()
* Process an atreq, if one has completed. This is called during interrupt
* processing and will process a completed atreq. It returns status if an
* atreq was processed so that the ISR knows that it needs to be called
* again to see if another ATREQ has completed. flush_q set to B_TRUE tells
* this routine to process all commands regardless of their completion
* status. This is used during bus reset processing to remove all commands
* from the Q.
*
* They all have to do with pended responses so they are not applicable in
*
* Since the race conditions only exist for pended responses, we will only
* talk about that sequence here. We're also going to simplify the discussion
* so what the code does, so it won't exactly match what we say (e.g. we
* don't always setup a timeout for every single command, etc.)
*
* After Q'ing up an ATREQ, we will process the result of that command in
* one of a couple different paths. A normal condition would be that we Q up
* a command, we get an ATREQ complete interrupt and look at the ATREQ
* result. In the case it has been pended, we setup a timeout to wait for the
* response. If we receive the response before the timeout, the command is
* done and we send the response up the chain, if we do not, the command is
* done and we send a timeout notification up the chain.
*
* The first race condition is when we get the timeout at the same time as
* the response. At first glance a mutex around the command state would
* solve this problem. But on a multi-processor machine, we may have the
* ARRESP interrupt handler(ISR) running on one processor and the timeout on
* another. This means that the command state could change between two
* reads while in the ISR. This means we need to have a little more complex
* logic around changing the command state and have to be careful how and
* when we do this.
*
* The second race condition is that we could see the ARRESP before we
* process the ATREQ. We could be processing a few ARRESP from previous
* ATREQ's when the ATREQ completes and then the ARRESP comes in. Since we
* already are in the interrupt handler, the ATREQ complete will not preempt
* us.
*
* We will never see a race condition between the ATREQ interrupt for a
* command and the pending timeout since the command is not being timed until
* this routine is run for that command.
*/
int
{
int cmd_status;
HCI1394_TNF_HAL_STACK, "");
/*
* Get the next ATREQ that has completed (if one has). Space is free'd
* up in atreq_q and atreq_data_q as part of this function call.
*/
/*
* See if there were anymore requests on ATREQ Q. A NULL means there
* were no completed commands left on the Q
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/* There is a completed ATREQ, setup the HAL command pointer */
/* save away the command completed timestamp for the services layer */
/*
* Make sure this command has not already been processed. This command
* may have already received a response. If the ACK was not an ACK
* pending, we have a HW error (i.e. The target HW sent a response to a
* non-pended request). There is a race condition where the software
* will see and complete a response before processing it's ACK Pending.
* This can only happen for ACK pendings. We have seen this race
* condition and response to a non-pended request during real-world
* testing :-)
*/
/*
* we already processed the ARRESP in arresp_process(), it
* better have been ACK pended. Otherwise the target device
* performed an illegal action.
*/
/*
* Tell source that their command has completed. We're
* done with this command.
* NOTE: We use ac_status which was set in
* process_arresp()
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
/*
* This is a HW error. Process the ACK like we never saw the
* response. We will do this below.
*/
} else {
"response sent to non-pended ack");
}
}
/*
* if we got an ack pending, add it to the pending list and leave. We
* will either get an ARRESP or the pending list will timeout the
* response.
*/
/* Add this command to the pending list */
&hcicmd->ac_plist_node);
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* setup our return command status based on the ACK from the HW. See the
* OpenHCI 1.0 spec (table 3.2 on pg. 18) for more information about
*/
case OHCI_ACK_COMPLETE:
break;
/*
* we can get a nostatus during a bus reset (i.e. we shutdown the AT
* engine before it flushed all the commands)
*/
case OHCI_EVT_FLUSHED:
case OHCI_EVT_NO_STATUS:
break;
case OHCI_EVT_MISSING_ACK:
case OHCI_EVT_TIMEOUT:
break;
case OHCI_ACK_BUSY_X:
case OHCI_ACK_BUSY_A:
case OHCI_ACK_BUSY_B:
break;
case OHCI_ACK_TARDY:
break;
case OHCI_ACK_DATA_ERROR:
break;
case OHCI_ACK_TYPE_ERROR:
break;
case OHCI_ACK_CONFLICT_ERROR:
break;
case OHCI_ACK_ADDRESS_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:
break;
}
/*
* Free the tlabel that was used for this transfer. We will not try and
* free the tlabel in the case that we already received a response or if
* we did not allocate one (PHY packet). If we already received a
* response, the tlabel would have been free'd in
* hci1394_async_arresp_process().
*/
}
/*
* if we got anything other than and ACK pending, we are done w/ this
* transaction.
*/
/* tell the services layer that the command has completed */
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_arresp_process()
* Process an arresp, if one has completed. This is called during interrupt
* processing and will process a completed arresp. It returns status if an
* arresp was processed so that the ISR knows that it needs to be called
* again to see if another ARRESP has completed.
*/
int
{
int cmd_status;
int status;
HCI1394_TNF_HAL_STACK, "");
/*
* See if there were any responses on ARRESP Q. A NULL means there
* were no responses on the Q. This call does NOT free up space. We
* need to do that later after we figure out how much space the
* response takes up.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* We got a response. Lock out pending timeout callback from marking
* tlabel bad.
*/
/*
* Read in the response into the 1394 framework command. We could get a
* NULL for a command if we got a response with an error (i.e. tlabel
* that didn't match a request) This would be a successful read but with
* a NULL hcicmd returned. If we ever get a DDI_FAILURE, we will
* shutdown.
*/
if (status != DDI_SUCCESS) {
"unrecoverable error interrupt detected",
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Free up the arresp Q space, we are done with the data */
/*
* if we did not get a valid command response (i.e. we got a bad tlabel
* or something like that) we don't have anything else to do. We will
* say that we processed a response and will return successfully. We
* still may have other responses on the Q.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* Make sure this is in the pending list. There is a small chance that
* we will see the response before we see the ACK PENDING. If it is the
* expected case, it is in the pending list. We will remove it since
* we are done with the command.
*
* NOTE: there is a race condition here with the pending timeout. Look
* at the comments before hci1394_async_atreq_process() for more info.
*/
/* remove this transfer from our the pending list */
&hcicmd->ac_plist_node);
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
}
/* allow pending timeout callback to mark tlabel as bad */
/*
* We got a valid response that we were able to read in. Free the tlabel
* that was used for this transfer.
*/
/*
* Setup our return command status based on the RESP or ACK or SW error.
* See the IEEE1394-1995 spec (6.2.4.10 on pg. 159) for more information
* on response codes. See the OpenHCI 1.0 spec (table 3.2 on pg. 18) for
* device error caught in SW (e.g. for a block read request that got a
* quadlet read response). We use a special mask to separate the
*/
case IEEE1394_RESP_COMPLETE:
break;
case IEEE1394_RESP_DATA_ERROR:
break;
case IEEE1394_RESP_TYPE_ERROR:
break;
break;
break;
case H1394_CMD_EDEVICE_ERROR:
break;
break;
break;
break;
default:
break;
}
/*
* if we have already processed the atreq and put it on the pending Q
* (normal case), tell the services layer it completed.
*/
/* Set state indicating that we are done with this cmd */
/* tell the services lyaer the command has completed */
/*
* We have not seen the atreq status yet. We will call
* h1394_command_is_complete() in atreq_process() in case we did not get
* an ack pending (target HW error -> this is based on real world
* experience :-))
*/
} else {
/* Set state indicating that we are done with this cmd */
/* save away the status for atreq_process() */
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_arreq_process()
* Process an arreq, if one has arrived. This is called during interrupt
* processing and will process an arreq that has arrived. It returns status
* if an arreq was processed so that the ISR knows that it needs to be
* called again to see if another ARREQ has arrived.
*/
int
{
int status;
HCI1394_TNF_HAL_STACK, "");
/*
* See if there were any requests on ARREQ Q. A NULL means there
* were no requests on the Q. This call does NOT free up space. We
* need to do that later after we figure out how much space the
* request takes up.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* We got a request. Read the request into a 1394 framework command.
* We could get a NULL for a command if we got a request with an error
* (i.e. ARREQ ACK was not ack pending or ack complete). This would be a
* successful read but with a NULL hcicmd returned. If we ever get a
* DDI_FAILURE, we will shutdown.
*/
if (status != DDI_SUCCESS) {
"unrecoverable error interrupt detected",
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Free up the arreq Q space, we are done with the data */
/*
* if we did not get a valid request (i.e. The ARREQ had a bad ACK
* or something like that) we don't have anything else to do. We will
* say that we processed a request and will return successfully. We
* still may have other requests on the Q.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* If as_flushing_arreq is set, we do not want to send any requests up
* to the Services Layer. We are flushing the ARREQ until we see a bus
* reset token that matches the current bus generation. Free up the
* alloc'd command and return success.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* We got a valid request that we were able to read in. Call into the
* services layer based on the type of request.
*/
switch (tcode) {
break;
break;
case IEEE1394_TCODE_LOCK:
break;
case IEEE1394_TCODE_PHY:
/*
* OpenHCI only handles 1 PHY quadlet at a time. If a selfid
* packet was received with multiple quadlets, we will treat
* each quadlet as a separate call. We do not notify the
* services layer through the normal command interface, we will
* treat it like a command internally and then free up the
* command ourselves when we are done with it.
*/
/* free alloc'd command */
break;
default:
/* free alloc'd command */
break;
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_atresp_process()
* Process an atresp, if one has completed. This is called during interrupt
* processing and will process a completed atresp. It returns status if an
* atresp was processed so that the ISR knows that it needs to be called
* again to see if another ATRESP has completed. flush_q set to B_TRUE tells
* this routine to process all commands regardless of their completion
* status. This is used during bus reset processing to remove all commands
* from the Q.
*/
int
{
int cmd_status;
HCI1394_TNF_HAL_STACK, "");
/*
* Get the next ATRESP that has completed (if one has). Space is free'd
* up in atresp_q and atresp_data_q as part of this function call.
*/
/*
* See if there were anymore requests on ATRESP Q. A NULL means there
* were no completed commands left on the Q.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/* There is a completed ATRESP, setup the HAL command pointer */
/* save away the command completed timestamp for the services layer */
/*
* setup our return command status based on the ACK from the HW. See the
* OpenHCI 1.0 spec (table 3.2 on pg. 18) for more information about
*/
case OHCI_ACK_COMPLETE:
break;
/*
* we can get a nostatus during a bus reset (i.e. we shutdown the AT
* engine before it flushed all the commands)
*/
case OHCI_EVT_FLUSHED:
case OHCI_EVT_NO_STATUS:
break;
case OHCI_EVT_MISSING_ACK:
case OHCI_EVT_TIMEOUT:
break;
case OHCI_ACK_BUSY_X:
case OHCI_ACK_BUSY_A:
case OHCI_ACK_BUSY_B:
break;
case OHCI_ACK_TARDY:
break;
case OHCI_ACK_DATA_ERROR:
break;
case OHCI_ACK_TYPE_ERROR:
break;
case OHCI_ACK_CONFLICT_ERROR:
break;
case OHCI_ACK_ADDRESS_ERROR:
break;
case OHCI_EVT_UNKNOWN:
break;
case OHCI_EVT_UNDERRUN:
case OHCI_EVT_DATA_READ:
case OHCI_EVT_TCODE_ERR:
case OHCI_EVT_DESCRIPTOR_READ:
default:
break;
}
/* tell the services layer that the command has completed */
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_arresp_read()
* Read ARRESP in from memory into 1394 Framework command. We read the tcode
* which tells us which kind of arresp the packet is, get the size of the
* response, read in the sender, tlabel, and response code, and then
* lookup the command based on the sender and tlabel. Once we get the command
* (corresponding to the ATREQ), we will copy the rest of the response into
* that command.
*
* The only time this routine should return DDI_FAILURE is if it was unable
* to maintain a good state in the ARRESP Q (i.e. an unknown response was
* received and we can not cleanup after it.) If we detect a recoverable
* error, and it doesn't make sense to pass the response up to the Services
* Layer, we should return DDI_SUCCESS with hcicmd = NULL.
*/
static int
{
void *command;
int status;
HCI1394_TNF_HAL_STACK, "");
/* read in the arresp tcode */
/* Get the size of the arresp */
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Read in the tlabel, destination, and rcode (response code) */
/* Lookup the ATREQ framework command this response goes with */
/*
* If there is not a cooresponding ATREQ command, this is an error. We
* will ignore this response but still return success so we cleanup
* after it and go on with other arresp's. This could happend if a
* response was sent after the command has timed out or if the target
* device is misbehaving. (we have seen both cases)
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* copy the response code into the hal private command space. Setup
* area (cmd_priv). A command is made up of 4 parts. There is the public
* part which is accessable to the target driver, there is the Services
* Layer private part which is only accessible to the services layer,
* information about a particular command, and there is the HAL private
* area where we keep track of our command specific state information.
*/
/*
* Calculate the address where the status of the ARRESP and timestamp is
* kept at. It is the last quadlet in the response. Save away the
* timestamp.
*/
/*
* if we did not get an ACK_COMPLETE, we will use the ack error instead
* of the response in the packet for our status. We use special mask to
* separate the reponses from the ACKs (ASYNC_ARRESP_ACK_ERROR). We will
* return success with hcicmd set to the command so that this error gets
* sent up to the Services Layer.
*/
if (ack != OHCI_ACK_COMPLETE) {
/* use the ack error instead of rcode for the command status */
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
arresp_resp, rcode);
/*
* If we get to this point we have gotten a valid ACK on the response
* and have matched up the response with an ATREQ. Now we check the
* response code. If it is not resp_complete, we do not have anything
* left to look at in the response. Return successfully.
*/
if (rcode != IEEE1394_RESP_COMPLETE) {
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* Read the rest of the response (based on which kind of response it is)
* into the 1394 framework command. In all of the different responses,
* we check to make sure the response matches the original request. We
* originally did not have this check but found a device or two which
* did not behave very well and would cause us to corrupt our commands.
* Now we check :-) We will return success when we get this error since
* we can recover from it.
*/
switch (*tcode) {
/*
* response is sent back for those two type of ATREQs.
*/
"Invalid response sent for write request", tnf_uint,
arresp_tcode, *tcode);
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
break;
/* make sure the ATREQ was a quadlet read */
"Invalid response sent for qrd request", tnf_uint,
arresp_tcode, *tcode);
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* read the quadlet read response in. Data is treated as a byte
* stream.
*/
break;
/* make sure the ATREQ was a block read */
"Invalid response sent for brd request", tnf_uint,
arresp_tcode, *tcode);
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* read in the data length. Make sure the data length is the
* same size as the read block request size that went out.
*/
errmsg, "Block read response size is bad",
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/* Copy the read block data into the command mblk */
break;
case IEEE1394_TCODE_LOCK_RESP:
/* read in the data length */
/*
* read in the data length. Make sure the data length
* is the valid for a lock32 response (1 quadlet)
*/
if (data_length != IEEE1394_QUADLET) {
errmsg, "Invalid size for lock32 response",
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* read the lock32 response in. Data is treated as a
* byte stream unless it is an arithmetic lock
* operation. In that case we treat data like a 32-bit
* word.
*/
/*
* read in the data length. Make sure the data length
* is the valid for a lock64 response (1 octlet)
*/
if (data_length != IEEE1394_OCTLET) {
errmsg, "Invalid size for lock64 response",
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* read the lock64 response in. Data is treated as a
* byte stream unless it is an arithmetic lock
* operation. In that case we treat data like a 64-bit
* word.
*/
/*
* we sent out a request that was NOT a lock request and got
* back a lock response.
*/
} else {
"Invalid response sent for lock request", tnf_uint,
arresp_tcode, *tcode);
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
break;
default:
/* we got a tcode that we don't know about. Return error */
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_arreq_read()
* Read ARREQ in from memory into a 1394 Framework command. Allocate a 1394
* framework command, read in the ARREQ, and before passing it up to the
* services layer, see if it was a valid broadcast request.
*
* The only time this routine should return DDI_FAILURE is if it was unable
* to maintain a good state in the ARREQ Q (i.e. an unknown request was
* received and we can not cleanup after it.) If we detect a recoverable
* error we should return DDI_SUCCESS with hcicmd = NULL.
*/
static int
{
int status;
HCI1394_TNF_HAL_STACK, "");
/* read in the arresp tcode */
/*
* Allocated 1394 framework command. The Services layer takes care of
* cacheing commands. This is called during interrupt processing so we
* do not want to sleep.
*/
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Initialize the HAL private command info */
/*
* There are two generations in the command structure, one in the public
* both. We only use the private one internally.
*/
/*
* Read the request (based on which kind of request it is) into the 1394
* framework command.
*/
switch (*tcode) {
/*
* We got a ARREQ quadlet read request. Read in the packet.
* If there is a problem with the packet (i.e. we don't get
* DDI_SUCCESS), we will free up the command and return NULL in
* hcicmd to indicate that we did not get a valid ARREQ to
* process.
*/
if (status != DDI_SUCCESS) {
cmd_priv);
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
break;
/*
* We got a ARREQ quadlet write request. Read in the packet.
* If there is a problem with the packet (i.e. we don't get
* DDI_SUCCESS), we will free up the command and return NULL in
* hcicmd to indicate that we did not get a valid ARREQ to
* process.
*/
if (status != DDI_SUCCESS) {
cmd_priv);
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
break;
/*
* We got a ARREQ block read request. Read in the packet.
* If there is a problem with the packet (i.e. we don't get
* DDI_SUCCESS), we will free up the command and return NULL in
* hcicmd to indicate that we did not get a valid ARREQ to
* process.
*/
if (status != DDI_SUCCESS) {
cmd_priv);
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
break;
/*
* We got a ARREQ block write request. Read in the packet.
* If there is a problem with the packet (i.e. we don't get
* DDI_SUCCESS), we will free up the command and return NULL in
* hcicmd to indicate that we did not get a valid ARREQ to
* process.
*/
if (status != DDI_SUCCESS) {
cmd_priv);
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
break;
case IEEE1394_TCODE_LOCK:
/*
* We got a ARREQ lock request. Read in the packet.
* If there is a problem with the packet (i.e. we don't get
* DDI_SUCCESS), we will free up the command and return NULL in
* hcicmd to indicate that we did not get a valid ARREQ to
* process.
*/
if (status != DDI_SUCCESS) {
cmd_priv);
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
break;
case IEEE1394_TCODE_PHY:
/*
* We got a PHY packet in the ARREQ buffer. Read in the packet.
* If there is a problem with the packet (i.e. we don't get
* DDI_SUCCESS), we will free up the command and return NULL in
* hcicmd to indicate that we did not get a valid ARREQ to
* process.
*/
if (status != DDI_SUCCESS) {
cmd_priv);
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* If we got a bus reset token, free up the command and return
* NULL in hcicmd to indicate that we did not get a valid ARREQ
* to process.
*/
if (is_reset_token == B_TRUE) {
cmd_priv);
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
break;
default:
/* we got a tcode that we don't know about. Return error */
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* If this command was broadcast and it was not a write, drop the
* command since it's an invalid request. We will free up the command
* and return NULL in hcicmd to indicate that we did not get a valid
* ARREQ to process.
*/
IEEE1394_BROADCAST_NODEID) && ((*tcode !=
IEEE1394_TCODE_WRITE_QUADLET) && (*tcode !=
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
/*
* It is a valid broadcast command, set that field in the public
* command structure.
*/
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_arreq_read_qrd()
* Read ARREQ quadlet read into the 1394 Framework command. This routine will
* return DDI_FAILURE if it was not able to read the request succesfully.
*/
static int
{
HCI1394_TNF_HAL_STACK, "");
/* Setup shortcuts, command type, and size of request */
/*
* calculate the ATRESP timeout for when we send it.
*/
/*
* if the ARREQ ACK was bad, we were unable to successfully read in this
* request. Return failure.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* Read in the tlabel and destination. We don't use an mblk for this
* request.
*/
/*
* Read in the sender so we know who to send the ATRESP to and read in
* the 1394 48-bit address for this request.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_arreq_read_qwr()
* Read ARREQ quadlet write into the 1394 Framework command. This routine
* will return DDI_FAILURE if it was not able to read the request
* succesfully.
*/
static int
{
HCI1394_TNF_HAL_STACK, "");
/* Setup shortcuts, command type, and size of request */
/*
* calculate the ATRESP timeout for when we send it.
*/
/*
* if the ARREQ ACK was bad, we were unable to successfully read in this
* request. Return failure.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* Read in the tlabel and destination. We don't use an mblk for this
* request.
*/
/*
* Read in the sender so we know who to send the ATRESP to. Read in
* the 1394 48-bit address for this request. Copy the data quadlet into
* the command. The data quadlet is treated like a byte stream.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_arreq_read_brd()
* Read ARREQ block read into the 1394 Framework command. This routine will
* return DDI_FAILURE if it was not able to read the request succesfully.
*/
static int
{
HCI1394_TNF_HAL_STACK, "");
/* Setup shortcuts, command type, and size of request */
/*
* calculate the ATRESP timeout for when we send it.
*/
/*
* if the ARREQ ACK was bad, we were unable to successfully read in this
* request. Return failure.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Read in the tlabel and destination */
/*
* Read in the sender so we know who to send the ATRESP to. Read in
* the 1394 48-bit address for this request. Read in the block data size
* and allocate an mblk of that size.
*/
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_arreq_read_bwr()
* Read ARREQ block write into the 1394 Framework command. This routine will
* return DDI_FAILURE if it was not able to read the request succesfully.
*/
static int
{
HCI1394_TNF_HAL_STACK, "");
/*
* Setup shortcuts, command type, and size of request. The size of the
* request is in quadlets, therefore we need to make sure we count in
* the padding when figureing out the size (i.e. data may be in bytes
* but the HW always pads to quadlets)
*/
/*
* calculate the ATRESP timeout for when we send it. The status word is
* the last quadlet in the packet.
*/
/*
* if the ARREQ ACK was bad, we were unable to successfully read in this
* request. Return failure.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Read in the tlabel and destination */
/*
* Read in the sender so we know who to send the ATRESP to. Read in
* the 1394 48-bit address for this request. Read in the block data size
* and allocate an mblk of that size.
*/
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Copy ARREQ write data into mblk_t */
/* Update mblk_t wptr */
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_arreq_read_lck()
* Read ARREQ lock request into the 1394 Framework command. This routine will
* return DDI_FAILURE if it was not able to read the request succesfully.
*/
static int
{
HCI1394_TNF_HAL_STACK, "");
/*
* Setup shortcuts, command type, and size of request. The size of the
* request is in quadlets, therefore we need to make sure we count in
* the padding when figuring out the size (i.e. data may be in bytes
* but the HW always pads to quadlets)
*/
/* make sure the length is a valid lock request length */
if (length == DESC_TWO_QUADS) {
} else if (length == DESC_TWO_OCTLETS) {
} else {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* calculate the ATRESP timeout for when we send it. The status word is
* the last quadlet in the packet.
*/
/*
* if the ARREQ ACK was bad, we were unable to successfully read in this
* request. Return failure.
*/
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Read in the tlabel and destination */
/*
* Read in the sender so we know who to send the ATRESP to. Read in
* the 1394 48-bit address for this request.
*/
/* Copy ARREQ lock data into 1394 framework command */
/*
* swap these for our correct architecture if we are doing
* arithmetic lock operations
*/
/*
* swap these for our correct architecture if we are doing
* arithmetic lock operations
*/
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_arreq_read_phy()
* Read ARREQ PHY quadlet into the 1394 Framework command. This routine will
* return DDI_FAILURE if it was not able to read the request succesfully.
*/
static int
{
HCI1394_TNF_HAL_STACK, "");
/* Setup shortcuts, command type, and size of request */
*size = DESC_SZ_AR_PHY;
/*
* set state that we do not use an mblk for this request.
*/
/* Read in the PHY packet quadlet and its check quadlet */
/*
* if this is a bus reset token, save away the generation. If the bus
* reset token is for the current generation, we do not need to flush
* the ARREQ Q anymore.
*/
async_handle->as_ohci)) {
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/* if there is a data error in the PHY packet, return failure */
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Copy the PHY quadlet to the command */
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_phy()
* Queue up ATREQ phy packet.
*/
int
{
int status;
/*
* make sure this call is during the current bus generation (i.e. no
* bus resets have occured since this request was made.
*/
async_handle->as_ohci)) {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Initialize the private HAL command structure */
/* We do not allocate a tlabel for a PHY packet */
/*
* Setup the packet header information for a ATREQ PHY packet Add in
* the tcode, phy quadlet, and it's 1's complement.
*/
/* Write request into the ATREQ Q. If we fail, we're out of space */
if (status != DDI_SUCCESS) {
"");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hci1394_async_write()
* Queue up ATREQ write. This could be either a block write or a quadlet
* write.
*/
int
{
int status;
/*
* make sure this call is during the current bus generation (i.e. no
* bus resets have occured since this request was made.
*/
async_handle->as_ohci)) {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Initialize the private HAL command structure */
/* allocate a tlabel for this request */
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* Setup the packet header information for a ATREQ write packet. We
* will set the tcode later on since this could be a block write or
* a quadlet write. Set SRCBusId if this write is not a local bus
* access. Copy in the speed, tlabel, and destination address.
*/
}
/* Register this command w/ its tlabel */
hcicmd);
/* If this is a quadlet write ATREQ */
/*
* setup the tcode for a quadlet write request and copy in
* the quadlet data. Endian issues will be taken care of in
* hci1394_q_at().
*/
/*
* Write the request into the ATREQ Q. If we fail, we are out
* of space.
*/
result);
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* This is a block write ATREQ */
} else {
/* setup the tcode and the length of the block write */
/*
* Write the request into the ATREQ Q. If we fail, we are out
* of space. The data is in a mblk(s). We use a special
* partial transfers out of the mblk due to packet size
* restrictions.
*/
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/*
* hci1394_async_read()
* Queue up ATREQ read. This could be either a block read or a quadlet
* read.
*/
int
{
int status;
/*
* make sure this call is during the current bus generation (i.e. no
* bus resets have occured since this request was made.
*/
async_handle->as_ohci)) {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Initialize the private HAL command structure */
/* allocate a tlabel for this request */
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* Setup the packet header information for a ATREQ read packet. We
* will set the tcode later on since this could be a block read or
* a quadlet read. Set SRCBusId if this read is not a local bus
* access. Copy in the speed, tlabel, and destination address.
*/
}
/* Register this command w/ its tlabel */
hcicmd);
/* If this is a quadlet read ATREQ */
/* setup the tcode for a quadlet read request */
/*
* Write the request into the ATREQ Q. If we fail, we are out
* of space.
*/
result);
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
} else {
/* setup the tcode and the length of the block read */
/*
* Write the request into the ATREQ Q. If we fail, we are out
* of space.
*/
result);
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/*
* hci1394_async_lock()
* Queue up ATREQ lock. This could be either a 32-bit or 64-bit lock
* request.
*/
int
{
int status;
/*
* make sure this call is during the current bus generation (i.e. no
* bus resets have occured since this request was made.
*/
async_handle->as_ohci)) {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Initialize the private HAL command structure */
/* allocate a tlabel for this request */
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Register this command w/ its tlabel */
hcicmd);
/*
* Setup the packet header information for a ATREQ lock packet. Set
* the tcode up as a lock request. Set SRCBusId if this lock is not a
* local bus access. Copy in the speed, tlabel, and destination
* address.
*/
}
/*
* Setup the lock length based on what size lock operation we are
* performing. If it isn't a lock32 or lock64, we have encountered an
* internal error. Copy the lock data into a local data buffer. Perform
* a byte swap if it is an arithmetic lock operation and we are on a
* little endian machine.
*/
} else {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/* Write request into the ATREQ Q. If we fail, we're out of space */
result);
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* hci1394_async_write_response()
* Send a write ATRESP. This routine should be called from the Services
* layer to send a response to a received write request (ARREQ). The same
* response is sent to a quadlet and block write request.
*/
int
{
int status;
HCI1394_TNF_HAL_STACK, "");
/*
* make sure this call is during the current bus generation (i.e. no
* bus resets have occured since this request was made.
*/
async_handle->as_ohci)) {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* setup a shortcut to the hal private command area. Copy the generation
* to the Q area so that we can check the generation when the AT Q is
* locked. This prevents us from loosing commands due to race
* conditions.
*/
/*
* Setup the packet header information for a ATRESP write packet. Set
* the tcode for a write response. Set SRCBusId if the addr is not a
* local bus address. Copy in the speed, tlabel, and response code.
*/
}
/* Write response into the ATRESP Q. If we fail, we're out of space */
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_read_response()
* Send a read ATRESP. This routine should be called from the Services
* layer to send a response to a received read request (ARREQ). The
*/
int
{
int status;
HCI1394_TNF_HAL_STACK, "");
/*
* make sure this call is during the current bus generation (i.e. no
* bus resets have occured since this request was made.
*/
async_handle->as_ohci)) {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* setup a shortcut to the hal private command area. Copy the generation
* to the Q area so that we can check the generation when the AT Q is
* locked. This prevents us from loosing commands due to race
* conditions.
*/
/*
* Setup the packet header information for a ATRESP read packet. we
* will set the tcode later based on type of read response. Set
* SRCBusId if the addr is not a local bus address. Copy in the
* speed, tlabel, and response code.
*/
}
/* if the response is a read quadlet response */
/*
* setup the tcode for a quadlet read response, If the
* response code is not resp complete.
*/
} else {
}
/*
* Write response into the ATRESP Q. If we fail, we're out of
* space.
*/
result);
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* the response is a block read response. If the result is not a
* resp complete, we are not going to send any data back.
*/
/*
* Setup the tcode for a block read response, set the data
* length to zero since we had an error.
*/
/*
* Write response into the ATRESP Q. If we fail, we're out of
* space.
*/
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* the response is a block read response with a resp complete for the
* response code. Send back the read data.
*/
} else {
/*
* Setup the tcode for a block read response, setup the data
* length.
*/
/*
* Write response into the ATRESP Q. If we fail, we're out of
* space. Use the data in the mblk.
*/
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_lock_response()
* Send a lock ATRESP. This routine should be called from the Services
* layer to send a response to a received lock request (ARREQ). The
* response will differ between 32-bit/64-bit lock requests.
*/
int
{
int status;
HCI1394_TNF_HAL_STACK, "");
/*
* make sure this call is during the current bus generation (i.e. no
* bus resets have occured since this request was made.
*/
async_handle->as_ohci)) {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* setup a shortcut to the hal private command area. Copy the generation
* to the Q area so that we can check the generation when the AT Q is
* locked. This prevents us from loosing commands due to race
* conditions.
*/
/*
* Setup the packet header information for a ATRESP lock packet. Set
* the tcode for a lock response. Set SRCBusId if the addr is not a
* local bus address. Copy in the speed, tlabel, and response code.
*/
}
/*
* If the lock result is not a resp complete, we are not going to send
* any data back.with the response.
*/
/* set response size to 0 for error. Set the extended tcode */
size = 0;
} else {
}
/*
* Write response into the ATRESP Q. If we fail, we're out of
* space.
*/
result);
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* if the lock result is resp complete, setup the size of the response
* depending on the lock size and copy the lock response data into a
* local buffer. If the lock response is an arithmetic operation, swap
* the data on little endian machines. If we don't know what type of
* lock operation it is, someone has corrupted the command since we
* had received the ARREQ.
*/
} else {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
/*
* Write response into the ATRESP Q. If we fail, we're out of space.
* Use the local data buffer that we copied the data to above.
*/
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_response_complete()
* Free up space allocted during an ARREQ. This is called when the target
* driver and Services Layer are done with a command which was by the HAL
* during ARREQ processing. This routine will also free up any allocated
* mblks.
*
* NOTE: a target driver can hold on to a block write ARREQ mblk by setting
* the mblk pointer to NULL. This ONLY applies to block write ARREQs. The
* HAL will no longer track the mblk for this case.
*/
void
{
HCI1394_TNF_HAL_STACK, "");
/* If we allocated an mblk for this command */
/*
* Don't free mblk if it is set to NULL. This allows a target
* driver to hold on to it in the case of a block write ARREQ.
*/
}
}
/* free up the 1394 framework command */
&cmd);
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_pending_timeout()
* This is the ARREQ Pending timeout callback routine. It is called from
* the tlist code. There is a race condition with the ARRESP interrupt
* handler (hci1394_async_arresp_process) which requires a mutex to
* lock around the mark of the bad tlabel.
*
* Once we enter this routine, the command has timed out. If the command is
* in both the ARRESP handler and here, we will consider it to have timed
* out. That code path handles the race condition more easily.
*/
static void
{
HCI1394_TNF_HAL_STACK, "");
/*
* We do NOT want to set the command state here. That should only be
* done in the ISR. The state does nothing for us here.
*/
/*
* We want a lock around tlabel_lookup/reading data into the cmd in the
* ARRESP ISR processing and a lock around the tlabel_bad in this
* routine. This ensures that we will not be touching the command
* structure after we pass it up to the Services Layer. If we mark it as
* bad first, the lookup will fail. If we get to the lookup first, the
* pending list delete will fail in arresp_process() which will tell
* that guy that we are in the middle of doing the timeout processing
* for this command. The ARRESP logic will just drop the response and
* continue on.
*/
/* Tell the Services Layer that the command has timed out */
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_timeout_calc()
* Calculate the timeout for an ATRESP. When an ARREQ is received, this
* routine is called with the time the ARREQ was received. It returns the
* time when the ATRESP is considered to have timed out. We timeout after
* split_timeout has gone by. Split timeout and the returned value are in bus
* cycles.
*/
static uint_t
{
uint_t z;
HCI1394_TNF_HAL_STACK, "");
/* Get the current split timeout */
/*
* The cycle count is broken up into two sections, the 3-bit seconds
* field and the 13-bit cycle count. The cycle count is in 125uS
* increments. The maximum value of cycle count is 7999 (8000 is one
* second). With 13-bits, we could store up to 8191. Therefore, we don't
* have a simple 16-bit addition. Hence, the code we see below.
*/
/*
* calculate the new cycle count based on the cycle count from current
* time and the split timeout. If this new value is not greater than the
* maximum cycle count, we don't have a carry. Go to the next step.
*/
if (temp < OHCI_MAX_CYCLE_CNT) {
carry = 0;
/*
* the new cycle count adds up to more than the maximum cycle count,
* set the carry state and adjust the total accordingly.
*/
} else {
carry = 1;
}
/*
* The timeout time equals the seconds added with the carry (1 or 0
* seconds), added with the adjusted (if necessary) cycle count.
* Mask the final value to get rid of any second rollovers.
*/
z = z & OHCI_TIMESTAMP_MASK;
HCI1394_TNF_HAL_STACK, "");
return (z);
}
/*
* hci1394_async_arresp_size_get()
* Return the size of the arresp that was received in q_handle at addr.
*/
static int
{
HCI1394_TNF_HAL_STACK, "");
if (tcode == IEEE1394_TCODE_WRITE_RESP) {
} else if (tcode == IEEE1394_TCODE_READ_QUADLET_RESP) {
} else if (tcode == IEEE1394_TCODE_READ_BLOCK_RESP) {
/*
* response size is in quadlets, therefore we need to
* make sure we count in the padding when figuring out
* the size used up for this response
*/
} else if (tcode == IEEE1394_TCODE_LOCK_RESP) {
/*
* response size is in quadlets, therefore we need to
* make sure we count in the padding when figuring out
* the size used up for this response
*/
} else {
HCI1394_TNF_HAL_STACK, "");
return (DDI_FAILURE);
}
HCI1394_TNF_HAL_STACK, "");
return (DDI_SUCCESS);
}
/*
* hci1394_async_pending_list_flush()
* Flush out the ATREQ pending list. All commands still on the ATREQ pending
* list are considered to be completed due to a bus reset. The ATREQ and
* ARRESP Q's should be flushed before the pending Q is flushed. The ATREQ
* could have more ACK pendings and the ARRESP could have valid responses to
* pended requests.
*/
void
{
HCI1394_TNF_HAL_STACK, "");
do {
/*
* get the first node on the pending list. This routine also
* removes the node from the list.
*/
/* set the command state to completed */
/*
* Send the command up to the Services Layer with
* completed due to the bus reset for status.
*/
}
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_atreq_start()
* Setup the command pointer for the first descriptor to be fetched and
* then set the run bit. This routine will be called the first time
* a descriptor is added to the Q.
*/
static void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_atreq_wake()
* Set the wake bit for the ATREQ DMA engine. This routine will be called
* from the Q logic after placing a descriptor on the Q.
*/
static void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_atreq_reset()
* Reset the atreq Q. The AT DMA engines must be stopped every bus reset.
* They will restart when the next descriptor is added to the Q. We will stop
* the DMA engine and then notify the Q logic that it has been stopped so it
* knows to do a start next time it puts a descriptor on the Q.
*/
void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_atreq_flush()
* Flush out the atreq Q. This routine is called during bus reset processing.
* it should be called before arresp_flush() and pending_list_flush().
*/
static void
{
int status;
HCI1394_TNF_HAL_STACK, "");
/* Clear reqTxComplete interrupt */
/*
* Processes all Q'd AT requests. If the request is pended, it is
* considered complete relative the the atreq engine.
* flush_pending_list() will finish up the required processing for
* pended requests.
*/
do {
/* Flush the atreq Q. Process all Q'd commands */
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
}
} while (request_available == B_TRUE);
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_arresp_start()
* Setup the command pointer for the first descriptor to be fetched and
* then set the run bit. This routine will be called the first time
* a descriptor is added to the Q.
*/
static void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_arresp_wake()
* Set the wake bit for the ARRESP DMA engine. This routine will be called
* from the Q logic after placing a descriptor on the Q.
*/
static void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_arresp_flush()
* Flush out the arresp Q. This routine is called during bus reset
* processing. This should be called before pending_list_flush(). All
* receive responses will be processed normally. The tlabels should
* not be reset until after the ARRESP Q has been flushed. Otherwise
* we would reject valid responses.
*/
static void
{
int status;
HCI1394_TNF_HAL_STACK, "");
/* Clear reqTxComplete interrupt */
do {
/* Flush the arresp Q. Process all received commands */
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
}
} while (response_available == B_TRUE);
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_arreq_start()
* Setup the command pointer for the first descriptor to be fetched and
* then set the run bit. This routine will be called the first time
* a descriptor is added to the Q.
*/
static void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_arreq_wake()
* Set the wake bit for the ARREQ DMA engine. This routine will be called
* from the Q logic after placing a descriptor on the Q.
*/
static void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_arreq_flush()
* Flush the ARREQ Q. This will flush up to the bus reset token in the
* ARREQ. There is no order dependency for when routine should get called
* (relative to the other Q flushing routines)
*/
static void
{
int status;
HCI1394_TNF_HAL_STACK, "");
/*
* If the last bus reset token we have seen in
* hci1394_async_arreq_read_phy() matches the current generation, the
* ARREQ is already flushed. We have nothing further to do here so
* return. This can happen if we are processing ARREQ's and a bus reset
* occurs. Since we are already in the ISR, we will see the token before
* the bus reset handler gets to run.
*/
async_handle->as_ohci)) {
HCI1394_TNF_HAL_STACK, "");
return;
}
/*
* set flag to tell hci1394_async_arreq_process() that we should not
* pass ARREQ's up to the Services Layer. This will be set to B_FALSE
* in hci1394_async_arreq_read_phy() when a bus reset token matching
* the current generation is found.
*/
/*
* Process all requests that have been received or until we find the
* correct bus reset token.
*/
do {
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
}
} while ((request_available == B_TRUE) &&
/*
* Clear the asserted interrupt if there are no more ARREQ's to process.
* We could have ARREQ's in the Q after the bus reset token since we
* will set as_flushing_arreq to FALSE when we see the correct bus reset
* token in hci1394_async_arreq_read_phy(). If there are more ARREQ's,
* we will process them later after finishing the reset of bus reset
* processing. That is why we will leave the interrupt asserted.
*/
if (request_available == B_FALSE) {
}
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_atresp_start()
* Setup the command pointer for the first descriptor to be fetched and
* then set the run bit. This routine will be called the first time
* a descriptor is added to the Q.
*/
static void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_atresp_wake()
* Set the wake bit for the ATRESP DMA engine. This routine will be called
* from the Q logic after placing a descriptor on the Q.
*/
static void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_atresp_reset()
* Reset the atresp Q. The AT DMA engines must be stopped every bus reset.
* They will restart when the next descriptor is added to the Q. We will stop
* the DMA engine and then notify the Q logic that it has been stopped so it
* knows to do a start next time it puts a descriptor on the Q.
*/
void
{
HCI1394_TNF_HAL_STACK, "");
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_atresp_flush()
* Flush all commands out of the atresp Q. This routine will be called
* during bus reset processing. There is no order dependency for when
* routine should get called (relative to the other Q flushing routines)
*/
static void
{
int status;
HCI1394_TNF_HAL_STACK, "");
/* Clear respTxComplete interrupt */
/* Processes all AT responses */
do {
/* Flush the atresp Q. Process all Q'd commands */
if (status != DDI_SUCCESS) {
HCI1394_TNF_HAL_ERROR, "");
}
} while (response_available == B_TRUE);
HCI1394_TNF_HAL_STACK, "");
}
/*
* hci1394_async_hcicmd_init()
* Initialize the private HAL command structure. This should be called from
* ATREQ and ARREQ routines.
*/
static void
{
}