mc-opl.c revision 25cf1a301a396c38e8adf52c15f537b80d2483f7
/*
* 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
*/
/*
* All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/sysmacros.h>
#include <sys/machsystm.h>
/*
* Function prototypes
*/
int mc_get_mem_unum(int, uint64_t, char *, int, int *);
extern int plat_max_boards(void);
static void mc_get_mlist(mc_opl_t *);
#pragma weak opl_get_physical_board
extern int opl_get_physical_board(int);
static int mc_opl_get_physical_board(int);
/*
* Configuration data structures
*/
mc_open, /* open */
mc_close, /* close */
nulldev, /* strategy */
nulldev, /* print */
nodev, /* dump */
nulldev, /* read */
nulldev, /* write */
mc_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* cb_prop_op */
0, /* streamtab */
CB_REV, /* rev */
nodev, /* cb_aread */
nodev /* cb_awrite */
};
DEVO_REV, /* rev */
0, /* refcnt */
ddi_getinfo_1to1, /* getinfo */
nulldev, /* identify */
nulldev, /* probe */
mc_attach, /* attach */
mc_detach, /* detach */
nulldev, /* reset */
&mc_cb_ops, /* cb_ops */
(struct bus_ops *)0, /* bus_ops */
nulldev /* power */
};
/*
* Driver globals
*/
int mc_patrol_interval_sec = 10;
int inject_op_delay = 5;
void *mc_statep;
#ifdef DEBUG
int oplmc_debug = 1;
#endif
static int mc_debug_show_all;
extern struct mod_ops mod_driverops;
&mod_driverops, /* module type, this one is a driver */
"OPL Memory-controller 1.1", /* module name */
&mc_ops, /* driver ops */
};
static struct modlinkage modlinkage = {
MODREV_1, /* rev */
(void *)&modldrv,
};
#pragma weak opl_get_mem_unum
extern int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *);
/*
* pseudo-mc node portid format
*
* [10] = 0
* [9] = 1
* [8] = LSB_ID[4] = 0
* [7:4] = LSB_ID[3:0]
* [3:0] = 0
*
*/
/*
* These are the module initialization routines.
*/
int
_init(void)
{
int error;
sizeof (mc_opl_t), 1)) != 0)
return (error);
if (&opl_get_mem_unum)
if (error != 0) {
if (&opl_get_mem_unum)
}
return (error);
}
int
_fini(void)
{
int error;
return (error);
if (&opl_get_mem_unum)
return (0);
}
int
{
}
static int
{
int instance;
/* get the instance of this devi */
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
default:
return (DDI_FAILURE);
}
return (DDI_FAILURE);
goto bad;
}
/* set informations in mc state */
if (mc_board_add(mcp))
goto bad;
return (DDI_SUCCESS);
bad:
return (DDI_FAILURE);
}
/* ARGSUSED */
static int
{
int instance;
/* get the instance of this devi */
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_SUSPEND:
case DDI_DETACH:
break;
default:
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
/* free up the soft state */
return (DDI_SUCCESS);
}
/* ARGSUSED */
static int
{
return (0);
}
/* ARGSUSED */
static int
{
return (0);
}
/* ARGSUSED */
static int
int *rvalp)
{
return (ENXIO);
}
/*
* PA validity check:
* This function return 1 if the PA is valid, otherwise
* return 0.
*/
/* ARGSUSED */
static int
{
/*
* Check if the addr is on the board.
*/
return (0);
return (1);
}
return (0);
}
/*
* mac-pa translation routines.
*
* Input: mc driver state, (LSB#, Bank#, DIMM address)
* Output: physical address
*
* Valid - return value: 0
* Invalid - return value: -1
*/
static int
{
int i;
/* loc validity check */
/* Do translation */
for (i = 0; i < PA_BITS_FOR_MAC; i++) {
int pa_bit = 0;
if (mc_bit < MC_ADDRESS_BITS) {
pa_bit = 0;
}
}
return (-1);
}
} else {
}
/*
* there is no need to check ma_bd because it is generated from
* mcp. They are the same.
*/
return (0);
} else {
"PA %lx, target /LSB%d/B%d/%x\n",
return (-1);
}
}
/*
* PA to CS (used by pa_to_maddr).
*/
static int
{
int i;
int cs = 0;
for (i = 0; i < PA_BITS_FOR_MAC; i++) {
/* MAC address bit<29> is arranged on the same PA bit */
/* on both table. So we may use any table. */
break;
}
}
return (cs);
}
/*
* PA to DIMM (used by pa_to_maddr).
*/
/* ARGSUSED */
static uint32_t
{
int i;
for (i = 0; i < PA_BITS_FOR_MAC; i++) {
if (mc_bit < MC_ADDRESS_BITS) {
}
}
return (dimm_addr);
}
/*
* PA to Bank (used by pa_to_maddr).
*/
static int
{
int i;
for (i = 0; i < PA_BITS_FOR_MAC; i++) {
switch (mc_bit) {
case MP_BANK_0:
bankno |= pa_bit_value;
break;
case MP_BANK_1:
break;
case MP_BANK_2:
break;
}
}
return (bankno);
}
/*
* PA to MAC address translation
*
* Input: MAC driver state, physicall adress
* Output: LSB#, Bank id, mac address
*
* Valid - return value: 0
* Invalid - return value: -1
*/
int
{
/* PA validity check */
return (-1);
/* Do translation */
MC_LOG("pa %lx -> mcaddr /LSB%d/B%d/%x\n",
return (0);
}
static void
{
char buf[FM_MAX_CLASS];
char device_path[MAXPATHLEN];
int nflts;
int i, n, blen;
char *p;
if (panicstr) {
return;
} else {
}
/*
* Create the scheme "dev" FMRI.
*/
device_path, NULL);
/*
* Encode all the common data into the ereport.
*/
/*
* Set payload.
*/
}
for (i = 0; i < nflts; i++)
for (i = 0; i < nflts; i++)
for (i = 0; i < nflts; i++)
for (i = 0; i < nflts; i++)
for (i = 0; i < nflts; i++) {
if (flt_stat->mf_errlog_valid) {
} else {
synd[i] = 0;
dslot[i] = 0;
values[i] = 0;
}
}
blen = MAXPATHLEN;
device_path[0] = 0;
p = &device_path[0];
for (i = 0; i < nflts; i++) {
int psb = -1;
if (psb != -1) {
} else {
}
if (flt_stat->mf_errlog_valid) {
}
n = strlen(&device_path[0]);
blen = MAXPATHLEN - n;
p = &device_path[n];
if (i < (nflts - 1)) {
}
}
/*
* UNUM format /LSB#/B#/MEMxyZ
* where x is the MAC# = Bank#/2
* y is slot info = (Bank# & 0x1)*2 + {0, 1} 0 for DIMM-L, 1 for DIMM-H
* DIMM-L is 0 in bit 13, DIMM-H is 1 in bit 13.
* Z is A(CS0) or B(CS1) given by bit 14
*/
if (panicstr) {
} else {
}
}
static void
{
int rv;
MC_LOG("mc_err_drain: %s\n",
/*
* we come here only when we have:
* In mirror mode: CMPE, MUE, SUE
* In normal mode: UE, Permanent CE
*/
if (rv == 0)
else
if (rv == 0) {
if (pp) {
/*
* Don't keep retiring and make ereports
* on bad pages in PTRL case
*/
if (mc_aflt->mflt_is_ptrl) {
errors = 0;
MC_LOG("Page retired\n");
return;
}
MC_LOG("errors %lx, mflt_pr %x\n",
return;
}
}
}
}
}
#define DIMM_SIZE 0x80000000
#define INC_DIMM_ADDR(p, n) \
(p)->ma_dimm_addr += n; \
/*
* The restart address is actually defined in unit of PA[37:6]
* the mac patrol will convert that to dimm offset. If the
* address is not in the bank, it will continue to search for
* the next PA that is within the bank.
*
* Also the mac patrol scans the dimms based on PA, not
* dimm offset.
*/
static int
{
int rv;
int loop_count = 0;
/* already running, so we just return */
if (reg & MAC_CNTL_PTRL_START)
return (0);
return (0);
}
if (rv != 0) {
MC_LOG("cannot convert mcaddr to pa. use auto restart\n");
return (0);
}
/*
* pa is the last address scanned by the mac patrol
* we calculate the next restart address as follows:
* first we always advance it by 64 byte. Then begin the loop.
* loop {
* if it is not in phys_install, we advance to next 64 MB boundary
* if it is not backed by a page structure, done
* if the page is bad, advance to the next page boundary.
* else done
* if the new address exceeds the board, wrap around.
* } <stop if we come back to the same page>
*/
/* pa is not on this board, just retry */
return (0);
}
if (maddr_info->mi_advance) {
else
/* Isolation unit size is 64 MB */
MC_LOG("Invalid PA\n");
} else {
(errors == 0)) {
MC_LOG("Page has no error\n");
return (0);
}
/*
* skip bad pages
* and let the following loop to take care
*/
} else {
MC_LOG("Page has no page structure\n");
return (0);
}
}
}
/*
* if we wrap around twice, we just give up and let
* mac patrol decide.
*/
while (loop_count <= 1) {
MC_LOG("pa is not valid. round up to 64 MB\n");
} else {
(errors == 0)) {
MC_LOG("Page has no error\n");
break;
}
/* skip bad pages */
} else {
MC_LOG("Page has no page structure\n");
break;
}
}
MC_LOG("Wrap around\n");
loop_count++;
}
}
/* retstart MAC patrol: PA[37:6] */
return (0);
}
/*
* Rewriting is used for two purposes.
* - to correct the error in memory.
* - to determine whether the error is permanent or intermittent.
* It's done by writing the address in MAC_BANKm_REWRITE_ADD
* and issuing REW_REQ command in MAC_BANKm_PTRL_CNRL. After that,
* rewrite operation is done. See 4.7.3 and 4.7.11 in Columbus2 PRM.
*
* Note that rewrite operation doesn't change RAW_UE to Marked UE.
* Therefore, we use it only CE case.
*/
static uint32_t
{
int count = 0;
/* first wait to make sure PTRL_STATUS is 0 */
while (count++ < MAX_MC_LOOP_COUNT) {
if (!(cntl & MAC_CNTL_PTRL_STATUS))
break;
}
if (count >= MAX_MC_LOOP_COUNT)
goto bad;
count = 0;
do {
if (count++ >= MAX_MC_LOOP_COUNT) {
goto bad;
} else
/*
* If there are other MEMORY or PCI activities, this
* will be BUSY, else it should be set immediately
*/
} while (!(cntl & MAC_CNTL_REW_END));
return (cntl);
bad:
/* This is bad. Just reset the circuit */
return (cntl);
}
void
{
int count = 0;
scf_log_t *p;
int bank;
& MAC_STATIC_ERR_VLD)) {
if (count++ >= (MAX_MC_LOOP_COUNT)) {
break;
}
}
if (count < MAX_MC_LOOP_COUNT) {
p->sl_err_log);
} else {
/* if we try too many times, just drop the req */
return;
} else {
"Dropping the SCF LOG\n");
}
}
mcp->mc_scf_total--;
}
}
void
{
scf_log_t *p;
"Max# SCF logs excceded on /LSB%d/B%d\n",
return;
}
p->sl_next = 0;
/*
* we rely on mc_scf_log to detect NULL queue.
* mc_scf_log_tail is irrelevant is such case.
*/
} else {
mcp->mc_scf_log_tail = p;
}
mcp->mc_scf_total++;
}
/*
* This routine determines what kind of CE happens, intermittent
* or permanent as follows. (See 4.7.3 in Columbus2 PRM.)
* - Do rewrite by issuing REW_REQ command to MAC_PTRL_CNTL register.
* - If CE is still detected on the same address even after doing
* rewrite operation twice, it is determined as permanent error.
* - If error is not detected anymore, it is determined as intermittent
* error.
* - If UE is detected due to rewrite operation, it should be treated
* as UE.
*/
/* ARGSUSED */
static void
{
int i;
/*
* rewrite request 1st time reads and correct error data
* and write to DIMM. 2nd rewrite request must be issued
* if REW_CE = 1, then it is permanent CE.
*/
for (i = 0; i < 2; i++) {
/*
* If the error becomes UE or CMPE
* we return to the caller immediately.
*/
if (cntl & MAC_CNTL_REW_UE) {
if (ptrl_error)
else
return;
}
if (cntl & MAC_CNTL_REW_CMPE) {
if (ptrl_error)
else
return;
}
}
if (!(cntl & MAC_CNTL_REW_CE)) {
}
/* report PERMANENT_CE to SP via SCF */
}
}
}
static int
{
if (ptrl_error) {
} else {
}
}
void
{
}
static int
{
int count = 0;
if (reg & MAC_CNTL_PTRL_START)
while (count++ <= MAX_MC_LOOP_COUNT) {
if ((reg & MAC_CNTL_PTRL_STATUS) == 0)
return (0);
}
return (-1);
}
static void
{
}
static void
{
old_status = 0;
/* we keep reading until the status is stable */
while (old_status != status) {
old_status = status;
if (status == old_status) {
break;
}
}
}
/*
* Error philosophy for mirror mode:
*
* PTRL (The error address for both banks are same, since ptrl stops if it
* detects error.)
* - Compaire error Report CMPE.
*
* - UE-UE Report MUE. No rewrite.
*
*
* If CE is permanent, inform SCF. Once for each
* Dimm. If CE becomes UE or CMPE, go back to above.
*
*
* MI (The error addresses for each bank are the same or different.)
* - Compair error If addresses are the same. Just CMPE.
* If addresses are different (this could happen
* as a result of scrubbing. Report each seperately.
* Only report error info on each side.
*
* - UE-UE Addresses are the same. Report MUE.
* Addresses are different. Report SUE on each bank.
* Rewrite to clear UE.
*
* Rewrite to clear UE. Report SUE for the bank.
*
* If CE becomes UE or CMPE, go back to above.
*
*/
static int
{
int i;
int rv = 0;
MC_LOG("process mirror errors cntl[0] = %x, cntl[1] = %x\n",
if (ptrl_error) {
& MAC_CNTL_PTRL_ERRS) == 0)
return (0);
} else {
& MAC_CNTL_MI_ERRS) == 0)
return (0);
}
/*
* First we take care of the case of CE
* because they can become UE or CMPE
*/
for (i = 0; i < 2; i++) {
MC_LOG("CE detected on bank %d\n",
&flt_stat[i], ptrl_error);
rv = 1;
}
}
/* The above scrubbing can turn CE into UE or CMPE */
/*
* Now we distinguish two cases: same address or not
* the same address. It might seem more intuitive to
* distinguish PTRL v.s. MI error but it is more
* complicated that way.
*/
MC_LOG("cmpe error detected\n");
return (1);
}
/* Both side are UE's */
MAC_SET_ERRLOG_INFO(&flt_stat[0]);
MC_LOG("MUE detected\n");
return (1);
}
for (i = 0; i < 2; i++) {
/* If we have CE, we would have done REW */
(void) do_rewrite(mcp,
}
MAC_SET_ERRLOG_INFO(&flt_stat[i]);
return (1);
}
}
} else {
/*
* addresses are different. That means errors
* on the 2 banks are not related at all.
*/
for (i = 0; i < 2; i++) {
MC_LOG("cmpe error detected\n");
/* no more report on this bank */
rv = 1;
}
}
for (i = 0; i < 2; i++) {
(void) do_rewrite(mcp,
MAC_SET_ERRLOG_INFO(&flt_stat[i]);
rv = 1;
}
}
}
return (rv);
}
static void
{
int other_bank;
return;
}
/* Now read all the registers into flt_stat */
/* patrol registers */
MC_LOG("ptrl registers cntl %x add %x log %x\n",
flt_stat[0].mf_err_add,
flt_stat[0].mf_err_log);
/* MI registers */
MC_LOG("MI registers cntl %x add %x log %x\n",
mi_flt_stat[0].mf_cntl,
mi_flt_stat[0].mf_err_log);
MC_LOG("ptrl registers cntl %x add %x log %x\n",
/* MI registers */
MC_LOG("MI registers cntl %x add %x log %x\n",
/* clear errors once we read all the registers */
/* Process PTRL errors first */
/* if not error mode, cntl1 is 0 */
mc_aflt.mflt_is_ptrl = 0;
}
static int
{
int rv = 0;
MC_LOG("UE deteceted\n");
rv = 1;
MC_LOG("CE deteceted\n");
/* Error type can change after scrubing */
}
rv = 1;
}
MC_LOG("mc_process_error: fault type %x erpt %s\n",
if (mc_aflt->mflt_erpt_class) {
}
return (rv);
}
static void
{
return;
}
/* patrol registers */
MC_LOG("ptrl registers cntl %x add %x log %x\n",
/* MI registers */
MC_LOG("MI registers cntl %x add %x log %x\n",
/* clear errors once we read all the registers */
}
mc_aflt.mflt_is_ptrl = 0;
}
}
/*
* memory patrol error handling algorithm:
* timeout() is used to do periodic polling
* This is the flow chart.
* timeout ->
* mc_check_errors()
* if memory bank is installed, read the status register
* if any error bit is set,
* -> mc_error_handler()
* -> mc_stop()
* -> read all error regsiters
* -> mc_process_error()
* determine error type
* rewrite to clear error or scrub to determine CE type
* inform SCF on permanent CE
* -> mc_err_drain
* page offline processing
* -> mc_ereport_post()
*/
static void
{
int i, error_count = 0;
/*
* scan errors.
*/
for (i = 0; i < BANKNUM_PER_SB; i++) {
if (cntl & MAC_CNTL_PTRL_ADD_MAX) {
MC_LOG("mc period %ld on "
mcp->mc_board_num, i);
MAC_CLEAR_MAX(mcp, i);
}
if (mc_debug_show_all) {
MC_LOG("/LSB%d/B%d stat %x cntl %x\n",
mcp->mc_board_num, i,
}
maddr_info.mi_valid = 0;
&maddr_info);
else
error_count++;
} else {
}
}
}
if (error_count > 0)
else
mcp->mc_last_error = 0;
}
/* this is just a wrapper for the above func */
static void
mc_check_errors(void *arg)
{
/*
* scan errors.
*/
if (mcp->mc_last_error > 0) {
if (interval < 1)
interval = 1;
} else
interval);
}
}
static void
{
maddr->ma_dimm_addr = 0;
}
typedef struct mc_mem_range {
static int
{
int len;
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
struct mc_addr_spec {
};
static char *mc_tbl_name[] = {
"cs0-mc-pa-trans-table",
"cs1-mc-pa-trans-table"
};
static int
{
return (1);
}
return (0);
}
static void
{
}
}
static struct memlist *
{
return (NULL);
}
return (hl);
}
static struct memlist *
{
return (NULL);
return (mlist);
break;
else
} else {
/*
* splitting an memlist entry.
*/
KM_SLEEP);
}
}
break;
} else {
}
}
}
}
return (mlist);
}
static void
{
if (mlist) {
}
if (mlist) {
}
}
if (mlist) {
}
}
int
{
struct mc_addr_spec *macaddr;
/*
* Get configurations from "pseudo-mc" node which includes:
* board# : LSB number
* mac-addr : physical base address of MAC registers
* csX-mac-pa-trans-table: translation table from DIMM address
* to physical address or vice versa.
*/
/*
* Get start address in this CAB. It can be gotten from
* "sb-mem-ranges" property.
*/
return (DDI_FAILURE);
}
/* get mac-pa trans tables */
for (i = 0; i < MC_TT_CS; i++) {
len = MC_TT_ENTRIES;
if (cc != DDI_SUCCESS) {
}
}
/* initialize bank informations */
if (cc != DDI_SUCCESS) {
return (DDI_FAILURE);
}
for (i = 0; i < len / sizeof (struct mc_addr_spec); i++) {
/*
* setup bank
*/
/*
* check if mirror mode
*/
if (mirr & MAC_MIRR_MIRROR_MODE) {
MC_LOG("Mirror -> /LSB%d/B%d\n",
/*
* The following bit is only used for
* error injection. We should clear it
*/
if (mirr & MAC_MIRR_BANK_EXCLUSIVE)
0);
}
/*
* restart if not mirror mode or the other bank
* of the mirror is not running
*/
if (!(mirr & MAC_MIRR_MIRROR_MODE) ||
MC_LOG("Starting up /LSB%d/B%d\n",
maddr.mi_advance = 0;
} else {
MC_LOG("Not starting up /LSB%d/B%d\n",
}
}
/*
* set interval in HZ.
*/
for (i = 0; i < BANKNUM_PER_SB; i++) {
mcp->mc_scf_retry[i] = 0;
}
mcp->mc_last_error = 0;
/* restart memory patrol checking */
return (DDI_SUCCESS);
}
int
{
int i;
scf_log_t *p;
timeout_id_t tid = 0;
/*
* cleanup mac state
*/
for (i = 0; i < BANKNUM_PER_SB; i++) {
return (-1);
}
}
}
/* stop memory patrol checking */
}
/* just throw away all the scf logs */
mcp->mc_scf_total--;
}
if (tid)
return (DDI_SUCCESS);
}
int
{
timeout_id_t tid = 0;
int i;
/* stop memory patrol checking */
for (i = 0; i < BANKNUM_PER_SB; i++) {
return (-1);
}
}
}
}
if (tid)
return (DDI_SUCCESS);
}
/* caller must clear the SUSPEND bits or this will do nothing */
int
{
int i;
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
/* restart memory patrol checking */
for (i = 0; i < BANKNUM_PER_SB; i++) {
}
}
/* check error asap */
}
return (DDI_SUCCESS);
}
static mc_opl_t *
{
mc_inst_list_t *p;
for (p = mc_instances; p; p = p->next) {
/* if mac patrol is suspended, we cannot rely on it */
continue;
if ((p->mc_start_address <= pa) &&
return (p->mc_opl);
}
}
return (NULL);
}
/*
* Get Physical Board number from Logical one.
*/
static int
{
if (&opl_get_physical_board) {
return (opl_get_physical_board(sb));
}
return (-1);
}
/* ARGSUSED */
int
int *lenp)
{
int bank;
int sb;
return (ENOSPC);
} else {
if (lenp)
}
return (0);
}
if (sb == -1) {
return (ENXIO);
}
return (ENOSPC);
} else {
if (lenp)
}
return (0);
}
int
{
mc_inst_list_t *p;
for (p = mc_instances; p; p = p->next) {
}
return (0);
}
int
{
mc_inst_list_t *p;
for (p = mc_instances; p; p = p->next) {
}
return (0);
}
static void
{
mc_inst_list_t *p;
p->next = mc_instances;
mc_instances = p;
}
static void
{
mc_inst_list_t *p;
if (mc_instances == p) {
mc_instances = p->next;
kmem_free(p, sizeof (mc_inst_list_t));
return;
}
prev = mc_instances;
if (current == p) {
kmem_free(p, sizeof (mc_inst_list_t));
return;
}
}
}
/* Error injection interface */
/* ARGSUSED */
int
{
int bank;
int both_sides = 0;
extern void cpu_flush_ecache(void);
MC_LOG("mc_inject_error: invalid pa\n");
return (ENOTSUP);
}
MC_LOG("mc-opl has been suspended. No error injection.\n");
return (EBUSY);
}
/* convert pa to offset within the board */
return (EINVAL);
}
if (flags & MC_INJECT_FLAG_OTHER)
MC_LOG("Not mirror mode\n");
return (EINVAL);
}
MC_LOG("injecting error to /LSB%d/B%d/D%x\n",
switch (error_type) {
case MC_INJECT_PERMANENT_MCE:
case MC_INJECT_MUE:
both_sides = 1;
}
if (flags & MC_INJECT_FLAG_RESET)
if (both_sides) {
}
switch (error_type) {
case MC_INJECT_UE:
case MC_INJECT_SUE:
case MC_INJECT_MUE:
if (flags & MC_INJECT_FLAG_PATH) {
} else {
}
break;
if (flags & MC_INJECT_FLAG_PATH) {
} else {
}
break;
case MC_INJECT_PERMANENT_CE:
case MC_INJECT_PERMANENT_MCE:
if (flags & MC_INJECT_FLAG_PATH) {
} else {
}
break;
case MC_INJECT_CMPE:
data = 0xabcdefab;
cntl = 0;
break;
case MC_INJECT_NOP:
cntl = 0;
break;
default:
MC_LOG("mc_inject_error: invalid option\n");
cntl = 0;
}
if (cntl) {
if (both_sides) {
}
}
/*
* For all injection cases except compare error, we
* must write to the PA to trigger the error.
*/
if (flags & MC_INJECT_FLAG_ST) {
data = 0xf0e0d0c0;
}
if (flags & MC_INJECT_FLAG_LD) {
if (flags & MC_INJECT_FLAG_NO_TRAP) {
no_trap();
MC_LOG("Trap occurred\n");
} else {
no_trap();
}
} else {
}
}
if (flags & MC_INJECT_FLAG_RESTART) {
MC_LOG("Restart patrol\n");
return (EIO);
}
maddr.mi_advance = 0;
}
if (flags & MC_INJECT_FLAG_POLL) {
MC_LOG("Poll patrol error\n");
&maddr);
else
} else
}
return (0);
}
void
{
}
{
return (rv);
}