1
0
Files
irix-657m-src/irix/kern/ml/SN/error_io_force.c
2022-09-29 17:59:04 +03:00

851 lines
22 KiB
C

/**************************************************************************
* *
* Copyright (C) 1992-1996, Silicon Graphics, Inc. *
* *
* These coded instructions, statements, and computer programs contain *
* unpublished proprietary information of Silicon Graphics, Inc., and *
* are protected by Federal copyright law. They may not be disclosed *
* to third parties or copied or duplicated in any form, in whole or *
* in part, without the prior written consent of Silicon Graphics, Inc. *
* *
**************************************************************************/
#if defined (SN) && defined (FORCE_ERRORS)
/*
* File: error_force.c
*/
#include <sys/types.h>
#include <sys/systm.h>
#include "sn_private.h"
#include "error_private.h"
#include <sys/errno.h>
#include <sys/cmn_err.h>
#include <sys/SN/module.h>
#include <sys/SN/SN0/slotnum.h>
#include <sys/SN/addrs.h>
#include <sys/debug.h>
#include <sys/PCI/bridge.h>
#include <sys/SN/SN1/snacioregs.h>
#include <sys/SN/SN0/ip27config.h>
#include <sys/runq.h>
#include <sys/SN/io.h>
#include <sys/PCI/pciio.h>
#define A64_BIT_OPERATION
#include <sys/ql.h>
typedef struct ef_device_s {
void * mem_base;
xwidgetnum_t widget;
cnodeid_t master_node;
vertex_hdl_t vertex;
} ef_device_t;
/* This is a global used to insert arbitrary addresses we select into
the q-logic interface. */
__int64_t ef_dma_addr = NULL;
extern vertex_hdl_t base_io_scsi_ctlr_vhdl[];
#define IS_ROOT_DEVICE(_dev) \
((_dev) == base_io_scsi_ctlr_vhdl[0] || (_dev) == base_io_scsi_ctlr_vhdl[1])
/*
* Function : error_force_node_to_dev
*
* Purpose : To retrieve the needed information on a device and insure
* the device exists, based on node and widget.
* Returns : 0 for success (found device)
* -1 for failure (no device)
* retVal will hold all information needed on the device.
*/
int
error_force_node_to_dev(cnodeid_t node, xwidgetnum_t widget, ef_device_t *retVal)
{
char buff[1024];
sprintf(buff,"/hw/nodenum/%d/xtalk/%d",node,widget);
retVal->vertex = hwgraph_path_to_vertex(buff);
if (retVal->vertex == GRAPH_VERTEX_NONE) {
printf("Error: Did not find device on Node %d, with widgetNum %d\n",
node, widget);
return -1;
}
if (is_headless_node(node)) {
printf("Error: Node %d is disabled\n",node);
return -1;
}
retVal->master_node = node;
retVal->widget = widget;
/* Masking out the higher bits, since widgetnum_t stores extra
info there */
retVal->mem_base = (void*)(NODE_SWIN_BASE(retVal->master_node,
retVal->widget & 0xf));
return 0;
}
/*
* Function : error_force_modNslot_to_dev
*
* Purpose : To retrieve the needed information on a device and insure
* the device exists, based on module and slot
* Returns : 0 for success (found device)
* -1 for failure (no device)
* retVal will hold all information needed on the device.
*/
int
error_force_modNslot_to_dev(moduleid_t module,slotid_t slot, ef_device_t *retVal)
{
char buff[1024];
/* check our parameters */
if ( module > MODULE_MAX+1 || slot > MAX_IO_SLOT_NUM+1) {
printf("ef_get_device: Invalid input. Module %d Slot %d\n",
module, slot);
return -1;
}
if (SN00) {
sprintf(buff,"/hw/module/%d/slot/MotherBoard/node/xtalk/8/pci/%d",
module,slot);
} else {
sprintf(buff,"/hw/module/%d/slot/io%d",module,slot);
}
EF_PRINT(("Passing this path to hwgraph %s\n",buff));
retVal->vertex = hwgraph_path_to_vertex(buff);
/* Is the device even present? */
if(retVal->vertex == GRAPH_VERTEX_NONE){
printf("ef_get_device:did not find Module %d Slot %d\n",
module, slot);
return -2;
}
/* Does it have a master? */
retVal->master_node = master_node_get(retVal->vertex);
if (is_headless_node(retVal->master_node)) {
printf("ef_get_device:did not find NODE from vertex, or node disabled."
" Module %d Slot %d\n", module, slot);
return -3;
}
retVal->widget = slot_to_widget((slot & 0xf) -1);
EF_PRINT(("ef_get_device: WidgetNum:0x%x\n",retVal->widget));
/* Masking out the higher bits, since widgetnum_t stores extra
info there */
retVal->mem_base = (void*)(NODE_SWIN_BASE(retVal->master_node,
retVal->widget & 0xf));
return 0;
}
/*
* Function : error_force_get_device
*
* Purpose : To retrieve the needed information on a device and insure
* the device exists, based on a error_params_t, which could
* have specifications for module & slot, or widget & node
* Returns : 0 for success (found device)
* -1 for failure (no device)
* retVal will hold all information needed on the device.
*/
int
error_force_get_device(io_error_params_t *params, ef_device_t *retVal)
{
/* IF the user is specifying by module and slot */
if (params->module && params->slot) {
return error_force_modNslot_to_dev(params->module, params->slot,
retVal);
}
/* If the user is specifying by node and widget num */
if (params->widget && params->node != CNODEID_NONE) {
return error_force_node_to_dev(params->node, params->widget,
retVal);
}
return -1;
}
/*
* Function : error_force_set_read_access
*
* Purpose : Sets or clears the IIWA register for the specified device.
* Returns : 0 - success, -1 failure
*/
int
error_force_set_read_access(io_error_params_t *params,int val, rval_t *rvp)
{
__int64_t access = 0;
int rv;
ef_device_t ef_dev;
EF_PRINT(("Made it to function illegal_read_access\n"));
rv = error_force_get_device(params,&ef_dev);
if (rv) {
EF_PRINT(("EF::Cannot find device Error %d\n",rv));
rvp->r_val1 = rv;
return -1;
}
/* Retrieve the current access state */
access = REMOTE_HUB_L(ef_dev.master_node,II_IIWA);
EF_PRINT(("Device is widget %d\n", ef_dev.widget));
EF_PRINT(("Read IIWA bits on node %d for value of 0x%llx\n",
ef_dev.master_node,access));
if (val) {
/* Set the access bit */
access = access | (1 << ef_dev.widget);
} else {
/* Clear the access bit for this widget */
access = access & ~(1 << ef_dev.widget);
}
EF_PRINT(("About to write back 0x%llx\n",access));
REMOTE_HUB_S(ef_dev.master_node,II_IIWA,access);
return 0;
}
/*
* Function : error_force_pio_write_absent_reg
*
* Purpose : To issue a PIO write to an absent register on a device.
* Returns : 0 - success, -1 - failure
*/
int
error_force_pio_write_absent_reg(io_error_params_t *params, int response,
int twice,rval_t *rvp)
{
ef_device_t ef_dev;
char *addr;
int rv;
__uint64_t iprb_val;
EF_PRINT(("Made it to function pio_write_absent_reg\n"));
rv = error_force_get_device(params,&ef_dev);
if (rv) {
EF_PRINT(("EF::Cannot find device. Error %d\n",rv));
rvp->r_val1 = rv;
return -1;
}
/* Find a non-exsitent register on the device. */
addr = (char*)ef_dev.mem_base;
/* needed to get to the pci bus */
addr += 0x27000;
/* If we need a response we must tell the hub to use a NAK
protocol on the LLP level */
if (response) {
iprb_val = REMOTE_HUB_L(ef_dev.master_node,IIO_IOPRB(ef_dev.widget));
EF_PRINT(("Read IPRB%d (0x%llX) bits on node %d for value of 0x%llx\n",
ef_dev.widget,IIO_IOPRB(ef_dev.widget),
ef_dev.master_node,iprb_val));
/* Set the access bit */
iprb_val &= ~(UINT64_CAST (1) << 42);
/* Now store the register value */
EF_PRINT(("About to write back 0x%llx\n",iprb_val));
REMOTE_HUB_S(ef_dev.master_node,IIO_IOPRB(ef_dev.widget),iprb_val);
}
/* DO the PIO write to the non-existent register */
EF_PRINT(("PIO write to address 0x%llX\n", addr));
*addr= 3;
/* Certain errors need more than one access */
if (twice) {
EF_PRINT(("Second PIO write to address 0x%llX\n", addr));
*addr= 3;
}
EF_PRINT(("Handled the error\n"));
return 0;
}
/*
* Function : error_force_absent_widget
*
* Purpose : Issues a PIO read from an absent widget
* Searches the hwgraph for an absent widget and then reads from it.
* Returns : 0 - success, -1 - failure
*/
int
error_force_absent_widget(rval_t *rvp)
{
vertex_hdl_t deviceVertex;
char buff[1024];
int *mem_base;
int widget,testVal,node;
EF_PRINT(("Made it to function ef_absent_widget\n"));
/* We are looking for an absent widget. A place without a
device, a place inside the twilight zone */
for (node = 0; node < MAX_COMPACT_NODES; node++) {
for (widget=8; widget < 0x10; widget++) {
/* Accessing the hw graph */
sprintf(buff,"/hw/nodenum/%d/xtalk/%d",node,widget);
deviceVertex = hwgraph_path_to_vertex(buff);
/* We found a blank spot! */
if (deviceVertex == GRAPH_VERTEX_NONE) {
EF_PRINT(("Found absence on node %d widget 0%x\n",
node, widget));
/* Masking out the higher bits, to
prevent memory scribbles */
mem_base = (int*)(NODE_SWIN_BASE(node, widget & 0xf));
EF_PRINT(("ABout to read from Addr 0x%llx\n",
mem_base));
/* Now to do the read, from an absent widget */
testVal = *mem_base;
testVal ++;
EF_PRINT(("Handled the error\n"));
return 0;
}
}
}
printf("No absent widgets on this machine\n");
rvp->r_val1 = -1;
return -1;
}
/*
* Function : error_force_forge_widgetId
*
* Purpose : To give a widget an incorrect widget ID and then perform
* some access to the widget.
* Parameters : params -> device to select
* action -> Whether the widget access is read/write or spurious.
* where spurious is an attempt to generate a
* spurious error, which appears to not work.
* Returns : 0 - success, -1 - failure
*
*/
int
error_force_forge_widgetId(io_error_params_t *params, int action, rval_t *rvp)
{
ef_device_t ef_dev;
widgetreg_t ctrl_reg, test_read;
int rv,ii;
cpu_cookie_t was_running;
volatile widgetreg_t *addr;
EF_PRINT(("Made it to ef_forge_widgetId\n"));
rv = error_force_get_device(params,&ef_dev);
if (rv) {
EF_PRINT(("EF::Cannot find device. Error %d\n",rv));
rvp->r_val1 = rv;
return -1;
}
/* First we find the first device's widget id. */
ctrl_reg = ((bridge_t*)ef_dev.mem_base)->b_wid_control;
EF_PRINT(("EF::Original Widget Control 0x%x\n", ctrl_reg));
/* Clear the bottom four bits */
ctrl_reg = ctrl_reg & ~(0xf);
/* If we are attempting a spurious message error set it to 0x3 */
if (action == EF_FORGE_SPURIOUS) {
/* If it was 0xf then we should make it something else */
ctrl_reg = ctrl_reg | 0x3;
} else {
if (ef_dev.widget != 0xf) {
/* If the widget was not widget 0xf then make it think
it is! */
ctrl_reg = ctrl_reg | 0xf;
} else {
/* If it was 0xf then we should make it something else */
ctrl_reg = ctrl_reg | 0x8;
}
}
EF_PRINT(("EF::Widget Control changed to 0x%x\n", ctrl_reg));
/* Now we make the widget believe it is another witdget. THis
is so sneaky. */
((bridge_t*)ef_dev.mem_base)->b_wid_control = ctrl_reg;
/* Make sure we are running on Node B */
EF_PRINT(("Setting process to run on node %d\n",ef_dev.master_node));
was_running = setmustrun(NODEPDA(ef_dev.master_node)->node_first_cpu);
addr = &(((bridge_t*)ef_dev.mem_base)->b_wid_control);
EF_PRINT(("About to acccess Addr 0x%llX\n",addr));
/* Now we do either a PIO read or write to see what happens. */
switch(action) {
case EF_FORGE_SPURIOUS:
for (ii=0; ii < 10; ii++) {
*addr = 5;
}
break;
case EF_FORGE_WRITE:
*addr = 5;
break;
case EF_FORGE_READ:
test_read = *(addr);
break;
default:
printf("EF::Unknown action code %d in ef_forge_widgetId\n",action);
}
/* Go back to our former processor */
EF_PRINT(("Returing back to old processor\n"));
restoremustrun(was_running);
test_read++;
EF_PRINT(("Handled error\n"));
return 0;
}
/*
* Function : error_xtalk_hdr_sideband.
*
* Purpose : This one is complicated. The goal is to allocate memory on nodeA,
* corrupt the memory and then access it through nodeB via the Xbow.
* This is done in a few steps:
*
* 1) Allocate the memory from a specific node.
* 2) Corrupt the memory.
* 3) Open a big window on nodeB to access the memory in nodeA.
* We have to do this since the memory offset may be larger than a
* small window
* 4) Do a PIO read of the memory from a cpu on nodeB
* through the big window.
*
* Returns : 0 - success, -1 - failure
*
* Note : This function does not recognize the devices supplied to it
* by the paramters. Everything is hardcoded, due to the
* fact I have been unable to figure out how to
* generalize the fourth arguement to ITTE_PUT.
*/
error_force_xtalk_sideband(io_error_params_t *params, rval_t *rvp)
{
paddr_t nodeA_mem,phys_addr, nodeB_access;
md_error_params_t md_params;
cpu_cookie_t was_running;
int test_read = 0;
cnodeid_t nodeA, nodeB;
test_read = params->node;
nodeA = 2;
nodeB = 0;
if (SN00) {
printf("Cannot run test on Speedo\n");
rvp->r_val1 = -1;
return -1;
}
/* insuring we are ntop the same node or on the same xbow */
if (nodeA == nodeB) {
printf("Error:: Nodes cannot be equal\n");
rvp->r_val1 = -1;
return -1;
}
/* If the nodes are on the same xbow this test will not work */
if (NODEPDA(nodeA)->xbow_peer != nodeB) {
printf("Error:: Nodes must share a xbow.\n");
rvp->r_val1 = -1;
return -1;
}
/* Is node B valid? */
if (!error_force_nodeValid(nodeA) || !error_force_nodeValid(nodeB)) {
printf("Node %d or %d is not valid\n",nodeA, nodeB);
rvp->r_val1 = -1;
return -1;
}
/* Grab memory from Node A */
nodeA_mem = (paddr_t)kmem_alloc_node(4096, VM_DIRECT | VM_CACHEALIGN | KM_NOSLEEP,
nodeA);
if (nodeA_mem == NULL) {
printf("Cannot allocate enough memory for test\n");
rvp->r_val1 = -1;
return -1;
}
/* translate it to a physical address */
phys_addr = kvtophys((void*)nodeA_mem);
/* Set up the ecc error */
md_params.sub_code = ETYPE_MEMERR;
md_params.read_write = ERRF_NO_ACTION;
/* Corrupt ecc on node A */
EF_PRINT(("EF::Corrupting Addr 0x%llx , Phys 0x%llx\n",nodeA_mem,phys_addr));
if (kl_force_memecc(phys_addr,&md_params, rvp)) {
printf("Error: Cannot corrupt Node 0 memory 0x:llx\n",nodeA_mem);
kmem_free((void*)nodeA_mem,4096);
rvp->r_val1 = -1;
return -1;
}
EF_PRINT(("ITTE1 State: 0x%llx\n",*(IIO_ITTE_GET(nodeB,0)) ));
/* Now prepare the big window, this will allow us to use the big
window form me on xbow slot 0xa (or N3) at our corrupted physical
address */
IIO_ITTE_PUT(nodeB,0,HUB_PIO_MAP_TO_IO, 0xa, TO_NODE_ADDRSPACE(phys_addr));
EF_PRINT(("ITTE1 State(after meddling): 0x%llx\n",*(IIO_ITTE_GET(nodeB,0))));
/* construct an xtalk addres that will reference that page */
nodeB_access = NODE_BWIN_BASE(nodeB,0);
EF_PRINT(("nodeB:NODE_BWIN_BASE 0x%llx\n",nodeB_access));
nodeB_access += (0xFFFFFFFF & phys_addr);
EF_PRINT(("nodeB:With phys_addr 0x%llx\n",nodeB_access));
/* Make sure we are running on Node B */
EF_PRINT(("About to run on Node: %d CPU %d\n",nodeB,
NODEPDA(nodeB)->node_first_cpu));
was_running = setmustrun(NODEPDA(nodeB)->node_first_cpu);
/* A PIO READ from node B */
EF_PRINT(("About to read from 0x%llx\n",nodeB_access));
test_read = *((int*)nodeB_access);
/* Go back to our former processor */
restoremustrun (was_running);
EF_PRINT(("Handled Error. Read %d\n", test_read));
kmem_free((void*)nodeA_mem, 4096);
return 0;
}
/*
* Function : error_force_clr_outbound_access
*
* Purpose : To clear the IOWA register field for the specified device and
* then execute a PIO write
* Returns : 0 - for success, -1 for failure
*/
int
error_force_clr_outbound_access(io_error_params_t *params, rval_t *rvp)
{
__int64_t access = 0;
int rv;
ef_device_t ef_dev;
EF_PRINT(("Made it to function illegal_read_access\n"));
rv = error_force_get_device(params,&ef_dev);
if (rv) {
EF_PRINT(("EF::Cannot find device Error %d\n",rv));
rvp->r_val1 = rv;
return -1;
}
/* Retrieve the current access state */
access = REMOTE_HUB_L(ef_dev.master_node,II_IOWA);
EF_PRINT(("Device is widget 0x%X\n", ef_dev.widget));
EF_PRINT(("Read IOWA(0x%llX) bits on node %d for value of 0x%llx\n",
II_IOWA,ef_dev.master_node,access));
/* Set the access bit */
access = access & ~(1 << ef_dev.widget);
/* Now store the register value */
EF_PRINT(("About to write back 0x%llx\n",access));
REMOTE_HUB_S(ef_dev.master_node,II_IOWA,access);
/* Now we execute a PIO write to the widget */
ef_dev.mem_base = ((char*)ef_dev.mem_base) + WIDGET_CONTROL;
EF_PRINT(("PIO write to Addr:0x%llX\n",ef_dev.mem_base));
*((int*)ef_dev.mem_base) = 0xff;
EF_PRINT(("Error Handled\n"));
return 0;
}
/*
* Function : error_force_clr_local_access
*
* Purpose : To clear the access bit of the ILAPR register then issue a PIO write
* Returns : 0 - success, -1 - failure
*/
error_force_clr_local_access(io_error_params_t *params, rval_t *rvp)
{
ef_device_t ef_dev;
int *addr;
int rv, test_val;
__uint64_t ilapr_val;
EF_PRINT(("Made it to function ef_clr_local_access\n"));
rv = error_force_get_device(params,&ef_dev);
if (rv) {
EF_PRINT(("EF::Cannot find device Error %d\n",rv));
rvp->r_val1 = rv;
return -1;
}
addr = ((int*)ef_dev.mem_base) + 1;
EF_PRINT(("First PIO read from address 0x%llX\n", addr));
test_val = *addr;
ilapr_val = REMOTE_HUB_L(params->node,IIO_ILAPR);
EF_PRINT(("Read ILAPR (0x%llX) on node %d for value of 0x%llx\n",
IIO_ILAPR,params->node,ilapr_val));
/* Set the access bit */
ilapr_val &= ~(UINT64_CAST (1) << params->node);
/* Now store the register value */
EF_PRINT(("About to write back 0x%llx\n",ilapr_val));
REMOTE_HUB_S(params->node,IIO_ILAPR,ilapr_val);
/* DO the PIO write to the non-existent register */
EF_PRINT(("Second PIO read from address 0x%llX\n", addr));
test_val = *addr;
test_val++;
EF_PRINT(("Handled the error\n"));
return 0;
}
/*
* Function : error_force_xtalk_credit_timeout
*
* Purpose : To Set the IXCC timeout value to 1, then issue a tone of
* PIO reads to force a harware error
* Returns : 0 - success, -1 - failure
*/
int
error_force_xtalk_credit_timeout(io_error_params_t *params, rval_t *rvp)
{
ef_device_t ef_dev;
int *addr;
int rv,ii,test_val;
__uint64_t ixcc_val;
cpu_cookie_t was_running;
EF_PRINT(("Made it to function ef_xtalk_credit_timeout\n"));
rv = error_force_get_device(params,&ef_dev);
if (rv) {
EF_PRINT(("EF::Cannot find device Error %d\n",rv));
rvp->r_val1 = rv;
return -1;
}
ixcc_val = REMOTE_HUB_L(params->node,IIO_IXCC);
EF_PRINT(("Read IXCC (0x%llX) on node %d for value of 0x%llx\n",
IIO_IXCC,params->node,ixcc_val));
/* Set the access bit */
ixcc_val &= 0xFFFFFFFFFA000000;
ixcc_val += 0x1;
/* Now store the register value */
EF_PRINT(("About to write back 0x%llx\n",ixcc_val));
REMOTE_HUB_S(params->node,IIO_IXCC,ixcc_val);
addr = ((int*)ef_dev.mem_base) + 1;
/* Make sure we are running on Node B */
was_running = setmustrun(NODEPDA(params->node)->node_first_cpu);
/* Do the PIO read in a loop to insure we create the error */
EF_PRINT(("PIO reading from address 0x%llX\n", addr));
for (ii=0; ii < 50; ii++) {
test_val = *addr;
test_val++;
}
/* Go back to our former processor */
restoremustrun(was_running);
EF_PRINT(("Handled the error\n"));
return 0;
}
/*
* Function : error_force_set_CRB_timeout
*
* Purpose : To set the ICTO timeout to whatever the caller passes in as <val>
* Returns : 0 - success, -1 - failure
*/
error_force_set_CRB_timeout(io_error_params_t *params, int count,rval_t *rvp)
{
__uint64_t icto_val;
EF_PRINT(("Made it to function ef_set_CRB_timeout\n"));
if (!error_force_nodeValid(params->node)) {
printf("Node %d or %d is not valid\n",params->node);
rvp->r_val1 = -1;
return -1;
}
icto_val = REMOTE_HUB_L(params->node,IIO_ICTO);
EF_PRINT(("Read ICTO (0x%llX) on node %d for value of 0x%llx\n",
IIO_ICTO,params->node,icto_val));
/* Set the access bit */
icto_val &= ~(0xFF);
icto_val += (count & 0xFF);
/* Now store the register value */
EF_PRINT(("About to write back 0x%llx\n",icto_val));
REMOTE_HUB_S(params->node,IIO_ICTO,icto_val);
return 0;
}
/*
* Function : error_force_redirect_dma
*
* Purpose : If #FORCE_ERRORS is defined than the drivers in io/ql.c
* will operate slightly differently. Instead of passing
* in the values needed for a DMA_READ or DMA_WRITE
* directly, they will check through this function first
* to see if the error system has addresses it should use
* instead.
* Returns : <none>
*/
void
error_force_redirect_dma(pHA_INFO ha,data_seg *dsp, command_entry *q_ptr, int i)
{
/* If this device is the root device than we do not want to
mess with it. */
if (IS_ROOT_DEVICE(ha->ctlr_vhdl) || ef_dma_addr == NULL) {
q_ptr->dseg[i].base_high_32 = dsp->base >>32;
q_ptr->dseg[i].base_low_32 = dsp->base;
} else {
q_ptr->dseg[i].base_high_32 = ef_dma_addr >> 32;
q_ptr->dseg[i].base_low_32 = ef_dma_addr;
ef_dma_addr = NULL;
}
}
/*
* Function : error_force_xtallk_force_addr
*
* Purpose : To inject invalid addresses into the q-logic driver,
* using the global, ef_dma_addr, referenced in the
* function error_force_redirect_dma. Currently we can
* inject addresses from an absent node, and from an
* absent widget (based on the type parameter).
* Returns : 0 - success, -1 - failure
*/
int
error_force_xtalk_force_addr(io_error_params_t *params, int type,rval_t *rvp)
{
ef_device_t ef_dev;
int rv;
EF_PRINT(("Made it to function ef_xtalk_force_addr\n"));
rv = error_force_get_device(params,&ef_dev);
if (rv) {
EF_PRINT(("EF::Cannot find device Error %d\n",rv));
rvp->r_val1 = rv;
return -1;
}
if(IS_ROOT_DEVICE(ef_dev.vertex)) {
printf("Cannot perform tests on root device\n");
rvp->r_val1 = -1;
return -1;
}
switch(type) {
case EF_ABSENT_MEM_BANK:
ef_dma_addr = EF_MEMBANK_ADDR(ef_dev.master_node,7);
break;
case EF_ABSENT_NODE:
ef_dma_addr = error_force_absent_node_mem();
if(ef_dma_addr == NULL) {
rvp->r_val1 = -1;
}
break;
default:
printf("Illegal ef_xtalk_force_addr %d\n",type);
rvp->r_val1 = -1;
return -1;
}
EF_PRINT(("DMA will access:0x%llX\n",ef_dma_addr));
return 0;
}
#endif /* SN0 && FORCE_ERRORS */