/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Tavor Interrupt and Event Processing Routines
*
* Implements all the routines necessary for allocating, freeing, and
* handling all of the various event types that the Tavor hardware can
* generate.
* These routines include the main Tavor interrupt service routine
* (tavor_isr()) as well as all the code necessary to setup and handle
* events from each of the many event queues used by the Tavor device.
*/
/*
* tavor_eq_init_all
* Context: Only called from attach() path context
*/
int
{
int status, i;
char *errormsg;
/*
* For now, all Event Queues default to the same size (pulled from
* the current configuration profile) and are all assigned to the
* same interrupt or MSI. In the future we may support assigning
* EQs to specific interrupts or MSIs XXX
*/
/*
* If MSI is to be used, then set intr_num to the MSI number
* (currently zero because we're using only one) or'd with the
* MSI enable flag. Otherwise, for regular (i.e. 'legacy') interrupt,
* use the 'inta_pin' value returned by QUERY_ADAPTER.
*/
intr_num = TAVOR_EQ_MSI_ENABLE_FLAG | 0;
} else {
}
/*
* Total number of supported EQs is hardcoded. Tavor hardware
* supports up to 64 EQs. We are currently using only 45 of them
* We will set aside the first 32 for use with Completion Queues (CQ)
* and reserve a few of the other 32 for each specific class of event
* (see below for more details).
*/
/*
* The "num_eq_unmap" variable is used in any possible failure
* cleanup (below) to indicate which events queues might require
* possible event class unmapping.
*/
num_eq_unmap = 0;
/*
* Allocate and initialize all the Event Queues. If any of these
* EQ allocations fail then jump to the end, cleanup what had been
* successfully initialized, and return an error.
*/
for (i = 0; i < num_eq; i++) {
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
num_eq_init = i;
goto all_eq_init_fail;
}
}
/*
* Setup EQ0-EQ31 for use with Completion Queues. Note: We can
* cast the return value to void here because, when we use the
* TAVOR_EVT_NO_MASK flag, it is not possible for
* tavor_eq_handler_init() to return an error.
*/
for (i = 0; i < 32; i++) {
}
num_eq_unmap = 32;
/*
* Setup EQ32 for handling Completion Queue Error Events.
*
* These events include things like CQ overflow or CQ access
* violation errors. If this setup fails for any reason (which, in
* general, it really never should), then jump to the end, cleanup
* everything that has been successfully initialized, and return an
* error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 33;
/*
* Setup EQ33 for handling Port State Change Events
*
* These events include things like Port Up and Port Down events.
* If this setup fails for any reason (which, in general, it really
* never should), then undo all previous EQ mapping, jump to the end,
* cleanup everything that has been successfully initialized, and
* return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 34;
/*
* Setup EQ34 for handling Communication Established Events
*
* These events correspond to the IB affiliated asynchronous events
* that are used for connection management. If this setup fails for
* any reason (which, in general, it really never should), then undo
* all previous EQ mapping, jump to the end, cleanup everything that
* has been successfully initialized, and return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 35;
/*
* Setup EQ35 for handling Command Completion Events
*
* These events correspond to the Tavor generated events that are used
* to indicate Tavor firmware command completion. These events are
* only generated when Tavor firmware commands are posted using the
* asynchronous completion mechanism. If this setup fails for any
* reason (which, in general, it really never should), then undo all
* previous EQ mapping, jump to the end, cleanup everything that has
* been successfully initialized, and return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 36;
/*
* Setup EQ36 for handling Local WQ Catastrophic Error Events
*
* These events correspond to the similarly-named IB affiliated
* asynchronous error type. If this setup fails for any reason
* (which, in general, it really never should), then undo all previous
* EQ mapping, jump to the end, cleanup everything that has been
* successfully initialized, and return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 37;
/*
* Setup EQ37 for handling Invalid Req Local WQ Error Events
*
* These events also correspond to the similarly-named IB affiliated
* asynchronous error type. If this setup fails for any reason
* (which, in general, it really never should), then undo all previous
* EQ mapping, jump to the end, cleanup everything that has been
* successfully initialized, and return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 38;
/*
* Setup EQ38 for handling Local Access Violation WQ Error Events
*
* These events also correspond to the similarly-named IB affiliated
* asynchronous error type. If this setup fails for any reason
* (which, in general, it really never should), then undo all previous
* EQ mapping, jump to the end, cleanup everything that has been
* successfully initialized, and return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 39;
/*
* Setup EQ39 for handling Send Queue Drained Events
*
* These events correspond to the IB affiliated asynchronous events
* that are used to indicate completion of a Send Queue Drained QP
* state transition. If this setup fails for any reason (which, in
* general, it really never should), then undo all previous EQ
* mapping, jump to the end, cleanup everything that has been
* successfully initialized, and return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 40;
/*
* Setup EQ40 for handling Path Migration Succeeded Events
*
* These events correspond to the IB affiliated asynchronous events
* that are used to indicate successful completion of a path
* migration. If this setup fails for any reason (which, in general,
* it really never should), then undo all previous EQ mapping, jump
* to the end, cleanup everything that has been successfully
* initialized, and return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 41;
/*
* Setup EQ41 for handling Path Migration Failed Events
*
* These events correspond to the IB affiliated asynchronous events
* that are used to indicate that path migration was not successful.
* If this setup fails for any reason (which, in general, it really
* never should), then undo all previous EQ mapping, jump to the end,
* cleanup everything that has been successfully initialized, and
* return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 42;
/*
* Setup EQ42 for handling Local Catastrophic Error Events
*
* These events correspond to the similarly-named IB unaffiliated
* asynchronous error type. If this setup fails for any reason
* (which, in general, it really never should), then undo all previous
* EQ mapping, jump to the end, cleanup everything that has been
* successfully initialized, and return an error.
*
* This error is unique, in that an EQE is not generated if this event
* occurs. Instead, an interrupt is called and we must poll the
* Catastrophic Error buffer in CR-Space. This mapping is setup simply
* to enable this error reporting. We pass in a NULL handler since it
* will never be called.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 43;
/*
* Setup EQ43 for handling SRQ Catastrophic Error Events
*
* These events correspond to the similarly-named IB affiliated
* asynchronous error type. If this setup fails for any reason
* (which, in general, it really never should), then undo all previous
* EQ mapping, jump to the end, cleanup everything that has been
* successfully initialized, and return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 44;
/*
* Setup EQ44 for handling SRQ Last WQE Reached Events
*
* These events correspond to the similarly-named IB affiliated
* asynchronous event type. If this setup fails for any reason
* (which, in general, it really never should), then undo all previous
* EQ mapping, jump to the end, cleanup everything that has been
* successfully initialized, and return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 45;
/*
* Setup EQ45 for handling ECC error detection events
*
* These events correspond to the similarly-named IB affiliated
* asynchronous event type. If this setup fails for any reason
* (which, in general, it really never should), then undo all previous
* EQ mapping, jump to the end, cleanup everything that has been
* successfully initialized, and return an error.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto all_eq_init_fail;
}
num_eq_unmap = 46;
/*
* Setup EQ46 to catch all other types of events. Specifically, we
* do not catch the "Local EEC Catastrophic Error Event" because we
* should have no EEC (the Tavor driver does not support RD). We also
* choose not to handle any of the address translation page fault
* event types. Since we are not doing any page fault handling (and
* since the Tavor firmware does not currently support any such
* handling), we allow these events to go to the catch-all handler.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
TAVOR_TNF_ERROR, "");
goto all_eq_init_fail;
}
return (DDI_SUCCESS);
/* Unmap any of the partially mapped EQs from above */
for (i = 0; i < num_eq_unmap; i++) {
}
/* Free up any of the partially allocated EQs from above */
for (i = 0; i < num_eq_init; i++) {
}
return (status);
}
/*
* tavor_eq_fini_all
*/
int
{
int status, i;
/*
* Grab the total number of supported EQs again. This is the same
* hardcoded value that was used above (during the event queue
* initialization.)
*/
/*
* For each of the event queues that we initialized and mapped
* earlier, attempt to unmap the events from the EQ.
*/
for (i = 0; i < num_eq; i++) {
if (status != DDI_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
}
/*
* Teardown and free up all the Event Queues that were allocated
* earlier.
*/
for (i = 0; i < num_eq; i++) {
if (status != DDI_SUCCESS) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/*
* tavor_eq_arm_all
*/
void
{
int i;
/*
* Grab the total number of supported EQs again. This is the same
* hardcoded value that was used above (during the event queue
* initialization.)
*/
/*
* For each of the event queues that we initialized and mapped
* earlier, attempt to arm it for event generation.
*/
for (i = 0; i < num_eq; i++) {
}
}
/*
* tavor_isr()
* Context: Only called from interrupt context (and during panic)
*/
/* ARGSUSED */
{
int i;
/*
* Grab the Tavor softstate pointer from the input parameter
*/
/*
* Find the pointers to the ECR and clr_INT registers
*/
/*
* Read the ECR register. Each of the 64 bits in the ECR register
* corresponds to an event queue. If a bit is set, then the
* corresponding event queue has fired.
*/
/*
* As long as there are bits set (i.e. as long as there are still
* EQs in the "fired" state), call tavor_eq_poll() to process each
* fired EQ. If no ECR bits are set, do not claim the interrupt.
*/
do {
i = 0;
while (ecrreg != 0x0) {
if (ecrreg & 0x1) {
}
i++;
}
/*
* Clear the interrupt. Note: Depending on the type of
* event (interrupt or MSI), we need to use a different
* mask to clear the event. In the case of MSI, the bit
* to clear corresponds to the MSI number, and for legacy
* interrupts the bit corresponds to the value in 'inta_pin'.
*/
} else {
}
/* Reread the ECR register */
} while (ecrreg != 0x0);
return (status);
}
/*
* tavor_eq_doorbell
* Context: Only called from interrupt context
*/
void
{
/* Build the doorbell from the parameters */
/* Write the doorbell to UAR */
doorbell);
}
/*
* tavor_eq_poll
* Context: Only called from interrupt context (and during panic)
*/
static void
{
/* Find the pointer to the clr_ECR register */
/*
* Check for Local Catastrophic Error If we have this kind of error,
* then we don't need to do anything else here, as this kind of
* catastrophic error is handled separately. So we call the
* catastrophic handler, clear the ECR and then return.
*/
/*
* Call Catastrophic Error handler
*/
/*
* Clear the ECR. Specifically, clear the bit corresponding
* to the event queue just processed.
*/
return;
}
/* Get the consumer pointer index */
/*
* Calculate the wrap around mask. Note: This operation only works
* because all Tavor event queues have power-of-2 sizes
*/
/* Calculate the pointer to the first EQ entry */
/*
* Sync the current EQE to read
* We need to force a ddi_dma_sync() here (independent of how the
* EQ was mapped) because it is possible for us to receive the
* interrupt, do a read of the ECR, and have each of these
* operations complete successfully even though the hardware's DMA
* to the EQ has not yet completed.
*/
/*
* Pull the handler function for this EQ from the Tavor Event Queue
* handle
*/
/*
* Keep pulling entries from the EQ until we find an entry owner by
* the hardware. As long as there the EQE's owned by SW, process
* each entry by calling its handler function and updating the EQ
* consumer index.
*/
do {
/*
* Call the EQ handler function. But only call if we
* are not in polled I/O mode (i.e. not processing
* because of a system panic). Note: We don't call
* the EQ handling functions from a system panic
* because we are primarily concerned only with
* ensuring that the event queues do not overflow (or,
* more specifically, the event queue associated with
* Also, we don't want to make any upcalls (to the
* calls would ever return. And, if we're in panic,
* then we reached here through a PollCQ() call (from
* tavor_cq_poll()), and we need to ensure that we
* successfully return any work completions to the
* caller.
*/
if (ddi_in_panic() == 0) {
}
/* Reset entry to hardware ownership */
/* Sync the current EQE for device */
/* Increment the consumer index */
/* Update the pointer to the next EQ entry */
/* Sync the next EQE to read */
}
/*
* Clear the ECR. Specifically, clear the bit corresponding
* to the event queue just processed.
*/
/* Write an EQ doorbell to update the consumer index */
/* Write another EQ doorbell to rearm */
/*
* NOTE: Due to the nature of Mellanox hardware, we do not have
* to do an explicit PIO read to ensure that the doorbell write
* has been flushed to the hardware. There is state encoded in
* the doorbell information we write which makes this
* unnecessary. We can be assured that if an event needs to be
* generated, the hardware will make sure that it is, solving
* the possible race condition.
*/
/* Sync the next EQE to read */
}
/*
* tavor_eq_catastrophic
* Context: Only called from interrupt context (and during panic)
*/
static void
{
int i;
switch (err_type) {
err_type);
break;
err_type);
break;
err_type);
break;
err_type);
break;
default:
/* Unknown type of Catastrophic error */
err_type);
break;
}
/*
* Read in the catastrophic error buffer from the hardware, printing
* only to the log file only
*/
for (i = 0; i < buf_size; i += 4) {
}
/*
* We also call the IBTF here to inform it of the catastrophic error.
* Note: Since no event information (i.e. QP handles, CQ handles,
* etc.) is necessary, we pass a NULL pointer instead of a pointer to
* an empty ibc_async_event_t struct.
*
* But we also check if "ts_ibtfpriv" is NULL. If it is then it
* means that we've have either received this event before we
* finished attaching to the IBTF or we've received it while we
* are in the process of detaching.
*/
}
}
/*
* tavor_eq_alloc()
* Context: Only called from attach() path context
*/
static int
{
int status, i;
char *errormsg;
/* Use the internal protection domain (PD) for setting up EQs */
/* Increment the reference count on the protection domain (PD) */
/*
* Allocate an EQ context entry. This will be filled in with all
* the necessary parameters to define the Event Queue. And then
* ownership will be passed to the hardware in the final step
* below. If we fail here, we must undo the protection domain
* reference count.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto eqalloc_fail1;
}
/*
* Allocate the software structure for tracking the event queue (i.e.
* the Tavor Event Queue handle). If we fail here, we must undo the
* protection domain reference count and the previous resource
* allocation.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto eqalloc_fail2;
}
/*
* Allocate the memory for Event Queue. Note: Although we use the
* common queue allocation routine, we always specify
* TAVOR_QUEUE_LOCATION_NORMAL (i.e. EQ located in system memory)
* because it would be inefficient to have EQs located in DDR memory.
* This is primarily because EQs are read from (by software) more
* than they are written to. Also note that, unlike Tavor QP work
* queues, event queues do not have the same strict alignment
* requirements. It is sufficient for the EQ memory to be both
* aligned to and bound to addresses which are a multiple of EQE size.
*/
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto eqalloc_fail3;
}
/*
* Initialize each of the Event Queue Entries (EQE) by setting their
* ownership to hardware ("owner" bit set to HW). This is in
* preparation for the final transfer of ownership (below) of the
* EQ context itself.
*/
for (i = 0; i < (1 << log_eq_size); i++) {
}
/*
* Register the memory for the EQ. The memory for the EQ must
* be registered in the Tavor TPT tables. This gives us the LKey
* to specify in the EQ context below.
*
* Because we are in the attach path we use NOSLEEP here so that we
* SPIN in the HCR since the event queues are not setup yet, and we
* cannot NOSPIN at this point in time.
*/
if (dma_xfer_mode == DDI_DMA_STREAMING) {
}
op.mro_bind_override_addr = 0;
if (status != DDI_SUCCESS) {
/* Set "status" and "errormsg" and goto failure */
goto eqalloc_fail4;
}
/* Determine if later ddi_dma_sync will be necessary */
/* Sync entire EQ for use by the hardware (if necessary) */
}
/*
* Fill in the EQC entry. This is the final step before passing
* ownership of the EQC entry to the Tavor hardware. We use all of
* the information collected/calculated above to fill in the
* requisite portions of the EQC. Note: We create all EQs in the
* "fired" state. We will arm them later (after our interrupt
* routine had been registered.)
*/
/*
* Write the EQC entry to hardware. Lastly, we pass ownership of
* the entry to the hardware (using the Tavor SW2HW_EQ firmware
* command). Note: in general, this operation shouldn't fail. But
* if it does, we have to undo everything we've done above before
* returning error.
*/
if (status != TAVOR_CMD_SUCCESS) {
status);
/* Set "status" and "errormsg" and goto failure */
goto eqalloc_fail5;
}
/*
* Fill in the rest of the Tavor Event Queue handle. Having
* successfully transferred ownership of the EQC, we can update the
* following fields for use in further operations on the EQ.
*/
eq->eq_consindx = 0;
return (DDI_SUCCESS);
/*
* The following is cleanup for all possible failure cases in this routine
*/
TAVOR_NOSLEEP) != DDI_SUCCESS) {
}
return (status);
}
/*
* tavor_eq_free()
*/
static int
{
int status;
/*
* Pull all the necessary information from the Tavor Event Queue
* handle. This is necessary here because the resource for the
* EQ handle is going to be freed up as part of this operation.
*/
/*
* Reclaim EQC entry from hardware (using the Tavor HW2SW_EQ
* firmware command). If the ownership transfer fails for any reason,
* then it is an indication that something (either in HW or SW) has
* gone seriously wrong.
*/
if (status != TAVOR_CMD_SUCCESS) {
status);
return (DDI_FAILURE);
}
/*
* Deregister the memory for the Event Queue. If this fails
* for any reason, then it is an indication that something (either
* in HW or SW) has gone seriously wrong. So we print a warning
* message and continue.
*/
if (status != DDI_SUCCESS) {
}
/* Free the memory for the EQ */
/* Free the Tavor Event Queue handle */
/* Free up the EQC entry resource */
/* Decrement the reference count on the protection domain (PD) */
/* Set the eqhdl pointer to NULL and return success */
return (DDI_SUCCESS);
}
/*
* tavor_eq_handler_init
* Context: Only called from attach() path context
*/
static int
{
int status;
/*
* Save away the EQ handler function and the event type mask. These
* will be used later during interrupt and event queue processing.
*/
/*
* Map the EQ to a specific class of event (or events) depending
* on the mask value passed in. The TAVOR_EVT_NO_MASK means not
* to attempt associating the EQ with any specific class of event.
* This is particularly useful when initializing the events queues
* used for CQ events. The mapping is done using the Tavor MAP_EQ
* firmware command. Note: This command should not, in general, fail.
* If it does, then something (probably HW related) has gone seriously
* wrong.
*/
if (evt_type_mask != TAVOR_EVT_NO_MASK) {
if (status != TAVOR_CMD_SUCCESS) {
"%08x\n", status);
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/*
* tavor_eq_handler_fini
*/
static int
{
int status;
/*
* Unmap the EQ from the event class to which it had been previously
* mapped. The unmapping is done using the Tavor MAP_EQ (in much
* the same way that the initial mapping was done). The difference,
* however, is in the TAVOR_EQ_EVT_UNMAP flag that is passed to the
* MAP_EQ firmware command. The TAVOR_EVT_NO_MASK (which may have
* been passed in at init time) still means that no association has
* been made between the EQ and any specific class of event (and,
* hence, no unmapping is necessary). Note: This command should not,
* in general, fail. If it does, then something (probably HW related)
* has gone seriously wrong.
*/
if (status != TAVOR_CMD_SUCCESS) {
"%08x\n", status);
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/*
* tavor_eqe_sync()
* Context: Can be called from interrupt or base context.
*
* Typically, this routine does nothing unless the EQ memory is
* mapped as DDI_DMA_STREAMING. However, there is a condition where
* ddi_dma_sync() is necessary even if the memory was mapped in
* consistent mode. The "force_sync" parameter is used here to force
* the call to ddi_dma_sync() independent of how the EQ memory was
* mapped.
*/
static void
{
int status;
/* Determine if EQ needs to be synced or not */
return;
}
/* Get the DMA handle from EQ context */
/* Calculate offset of next EQE */
if (status != DDI_SUCCESS) {
TAVOR_TNF_ERROR, "");
return;
}
}
/*
* tavor_port_state_change_handler()
* Context: Only called from interrupt context
*/
static int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/*
* Depending on the type of Port State Change event, pass the
* appropriate asynch event to the IBTF.
*/
/* Check for valid port number in event */
"change event");
return (DDI_FAILURE);
}
if (subtype == TAVOR_PORT_LINK_ACTIVE) {
} else if (subtype == TAVOR_PORT_LINK_DOWN) {
} else {
"event");
return (DDI_FAILURE);
}
/*
* Deliver the event to the IBTF. Note: If "ts_ibtfpriv" is NULL,
* then we have either received this event before we finished
* attaching to the IBTF or we've received it while we are in the
* process of detaching.
*/
}
return (DDI_SUCCESS);
}
/*
* tavor_comm_estbl_handler()
* Context: Only called from interrupt context
*/
static int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/* Get the QP handle from QP number in event descriptor */
/*
* If the QP handle is NULL, this is probably an indication
* that the QP has been freed already. In which case, we
* should not deliver this event.
*
* We also check that the QP number in the handle is the
* same as the QP number in the event queue entry. This
* extra check allows us to handle the case where a QP was
* freed and then allocated again in the time it took to
* handle the event queue processing. By constantly incrementing
* the non-constrained portion of the QP number every time
* a new QP is allocated, we mitigate (somewhat) the chance
* that a stale event could be passed to the client's QP
* handler.
*
* Lastly, we check if "ts_ibtfpriv" is NULL. If it is then it
* means that we've have either received this event before we
* finished attaching to the IBTF or we've received it while we
* are in the process of detaching.
*/
} else {
}
return (DDI_SUCCESS);
}
/*
* tavor_local_wq_cat_err_handler()
* Context: Only called from interrupt context
*/
static int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/* Get the QP handle from QP number in event descriptor */
/*
* If the QP handle is NULL, this is probably an indication
* that the QP has been freed already. In which case, we
* should not deliver this event.
*
* We also check that the QP number in the handle is the
* same as the QP number in the event queue entry. This
* extra check allows us to handle the case where a QP was
* freed and then allocated again in the time it took to
* handle the event queue processing. By constantly incrementing
* the non-constrained portion of the QP number every time
* a new QP is allocated, we mitigate (somewhat) the chance
* that a stale event could be passed to the client's QP
* handler.
*
* Lastly, we check if "ts_ibtfpriv" is NULL. If it is then it
* means that we've have either received this event before we
* finished attaching to the IBTF or we've received it while we
* are in the process of detaching.
*/
} else {
}
return (DDI_SUCCESS);
}
/*
* tavor_invreq_local_wq_err_handler()
* Context: Only called from interrupt context
*/
static int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/* Get the QP handle from QP number in event descriptor */
/*
* If the QP handle is NULL, this is probably an indication
* that the QP has been freed already. In which case, we
* should not deliver this event.
*
* We also check that the QP number in the handle is the
* same as the QP number in the event queue entry. This
* extra check allows us to handle the case where a QP was
* freed and then allocated again in the time it took to
* handle the event queue processing. By constantly incrementing
* the non-constrained portion of the QP number every time
* a new QP is allocated, we mitigate (somewhat) the chance
* that a stale event could be passed to the client's QP
* handler.
*
* Lastly, we check if "ts_ibtfpriv" is NULL. If it is then it
* means that we've have either received this event before we
* finished attaching to the IBTF or we've received it while we
* are in the process of detaching.
*/
} else {
}
return (DDI_SUCCESS);
}
/*
* tavor_local_acc_vio_wq_err_handler()
* Context: Only called from interrupt context
*/
static int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/* Get the QP handle from QP number in event descriptor */
/*
* If the QP handle is NULL, this is probably an indication
* that the QP has been freed already. In which case, we
* should not deliver this event.
*
* We also check that the QP number in the handle is the
* same as the QP number in the event queue entry. This
* extra check allows us to handle the case where a QP was
* freed and then allocated again in the time it took to
* handle the event queue processing. By constantly incrementing
* the non-constrained portion of the QP number every time
* a new QP is allocated, we mitigate (somewhat) the chance
* that a stale event could be passed to the client's QP
* handler.
*
* Lastly, we check if "ts_ibtfpriv" is NULL. If it is then it
* means that we've have either received this event before we
* finished attaching to the IBTF or we've received it while we
* are in the process of detaching.
*/
} else {
}
return (DDI_SUCCESS);
}
/*
* tavor_sendq_drained_handler()
* Context: Only called from interrupt context
*/
static int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/* Get the QP handle from QP number in event descriptor */
/*
* If the QP handle is NULL, this is probably an indication
* that the QP has been freed already. In which case, we
* should not deliver this event.
*
* We also check that the QP number in the handle is the
* same as the QP number in the event queue entry. This
* extra check allows us to handle the case where a QP was
* freed and then allocated again in the time it took to
* handle the event queue processing. By constantly incrementing
* the non-constrained portion of the QP number every time
* a new QP is allocated, we mitigate (somewhat) the chance
* that a stale event could be passed to the client's QP
* handler.
*
* And then we check if "ts_ibtfpriv" is NULL. If it is then it
* means that we've have either received this event before we
* finished attaching to the IBTF or we've received it while we
* are in the process of detaching.
*/
/*
* Grab the QP lock and update the QP state to reflect that
* the Send Queue Drained event has arrived. Also determine
* whether the event is intended to be forwarded on to the
* consumer or not. This information is used below in
* determining whether or not to call the IBTF.
*/
qp->qp_forward_sqd_event = 0;
qp->qp_sqd_still_draining = 0;
if (forward_sqd_event != 0) {
}
} else {
}
return (DDI_SUCCESS);
}
/*
* tavor_path_mig_handler()
* Context: Only called from interrupt context
*/
static int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/* Get the QP handle from QP number in event descriptor */
/*
* If the QP handle is NULL, this is probably an indication
* that the QP has been freed already. In which case, we
* should not deliver this event.
*
* We also check that the QP number in the handle is the
* same as the QP number in the event queue entry. This
* extra check allows us to handle the case where a QP was
* freed and then allocated again in the time it took to
* handle the event queue processing. By constantly incrementing
* the non-constrained portion of the QP number every time
* a new QP is allocated, we mitigate (somewhat) the chance
* that a stale event could be passed to the client's QP
* handler.
*
* Lastly, we check if "ts_ibtfpriv" is NULL. If it is then it
* means that we've have either received this event before we
* finished attaching to the IBTF or we've received it while we
* are in the process of detaching.
*/
} else {
}
return (DDI_SUCCESS);
}
/*
* tavor_path_mig_err_handler()
* Context: Only called from interrupt context
*/
static int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/* Get the QP handle from QP number in event descriptor */
/*
* If the QP handle is NULL, this is probably an indication
* that the QP has been freed already. In which case, we
* should not deliver this event.
*
* We also check that the QP number in the handle is the
* same as the QP number in the event queue entry. This
* extra check allows us to handle the case where a QP was
* freed and then allocated again in the time it took to
* handle the event queue processing. By constantly incrementing
* the non-constrained portion of the QP number every time
* a new QP is allocated, we mitigate (somewhat) the chance
* that a stale event could be passed to the client's QP
* handler.
*
* Lastly, we check if "ts_ibtfpriv" is NULL. If it is then it
* means that we've have either received this event before we
* finished attaching to the IBTF or we've received it while we
* are in the process of detaching.
*/
} else {
}
return (DDI_SUCCESS);
}
/*
* tavor_srq_catastrophic_handler()
* Context: Only called from interrupt context
*/
static int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/* Get the QP handle from QP number in event descriptor */
/*
* If the QP handle is NULL, this is probably an indication
* that the QP has been freed already. In which case, we
* should not deliver this event.
*
* We also check that the QP number in the handle is the
* same as the QP number in the event queue entry. This
* extra check allows us to handle the case where a QP was
* freed and then allocated again in the time it took to
* handle the event queue processing. By constantly incrementing
* the non-constrained portion of the QP number every time
* a new QP is allocated, we mitigate (somewhat) the chance
* that a stale event could be passed to the client's QP
* handler.
*
* Lastly, we check if "ts_ibtfpriv" is NULL. If it is then it
* means that we've have either received this event before we
* finished attaching to the IBTF or we've received it while we
* are in the process of detaching.
*/
} else {
}
return (DDI_SUCCESS);
}
/*
* tavor_srq_last_wqe_reached_handler()
* Context: Only called from interrupt context
*/
static int
{
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/* Get the QP handle from QP number in event descriptor */
/*
* If the QP handle is NULL, this is probably an indication
* that the QP has been freed already. In which case, we
* should not deliver this event.
*
* We also check that the QP number in the handle is the
* same as the QP number in the event queue entry. This
* extra check allows us to handle the case where a QP was
* freed and then allocated again in the time it took to
* handle the event queue processing. By constantly incrementing
* the non-constrained portion of the QP number every time
* a new QP is allocated, we mitigate (somewhat) the chance
* that a stale event could be passed to the client's QP
* handler.
*
* Lastly, we check if "ts_ibtfpriv" is NULL. If it is then it
* means that we've have either received this event before we
* finished attaching to the IBTF or we've received it while we
* are in the process of detaching.
*/
} else {
}
return (DDI_SUCCESS);
}
/*
* tavor_ecc_detection_handler()
* Context: Only called from interrupt context
*/
static int
{
int i;
if (eqe_evttype == TAVOR_EVT_EQ_OVERFLOW) {
TAVOR_TNF_ERROR, "");
return (DDI_FAILURE);
}
/*
* The "ECC Detection Event" indicates that a correctable single-bit
* has occurred with the attached DDR. The EQE provides some
* additional information about the errored EQ. So we print a warning
* message here along with that additional information.
*/
for (i = 0; i < sizeof (tavor_hw_eqe_t) >> 2; i++) {
}
return (DDI_SUCCESS);
}
/*
* tavor_eq_overflow_handler()
* Context: Only called from interrupt context
*/
void
{
/*
* The "Event Queue Overflow Event" indicates that something has
* probably gone seriously wrong with some hardware (or, perhaps,
* with the software... though it's unlikely in this case). The EQE
* provides some additional information about the errored EQ. So we
* print a warning message here along with that additional information.
*/
}
/*
* tavor_no_eqhandler
* Context: Only called from interrupt context
*/
/* ARGSUSED */
static int
{
int i;
/*
* This "unexpected event" handler (or "catch-all" handler) will
* receive all events for which no other handler has been registered.
* If we end up here, then something has probably gone seriously wrong
* with the Tavor hardware (or, perhaps, with the software... though
* it's unlikely in this case). The EQE provides all the information
* about the event. So we print a warning message here along with
* the contents of the EQE.
*/
for (i = 0; i < sizeof (tavor_hw_eqe_t) >> 2; i++) {
}
return (DDI_SUCCESS);
}