编写设备驱动程序

报告标准 I/O 控制器错误

针对 I/O 控制器的常见错误定义了一组标准的设备 ereport。只要检测到本节中所述的错误症状之一,便应生成这些 ereport。

本节中所述的 ereport 将分发给 eft 诊断引擎以进行诊断,eft 诊断引擎使用一组常用的标准规则来诊断这些 ereport。设备驱动程序检测的其他任何错误都必须在 Sun 事件注册表中定义为 ereport 事件,并必须伴有特定于设备的诊断软件或 eft 规则。

DDI_FM_DEVICE_INVAL_STATE

驱动程序已检测到设备处于无效状态。

当驱动程序检测到所传送或接收的数据看起来无效时,该驱动程序应发布错误。例如,在 bge 代码中,当 bge_chip_reset()bge_receive_ring() 例程检测到无效数据时,这些例程将生成 ereport.io.device.inval_state 错误。

/*
 * The SEND INDEX registers should be reset to zero by the
 * global chip reset; if they're not, there'll be trouble
 * later on.
 */
sx0 = bge_reg_get32(bgep, NIC_DIAG_SEND_INDEX_REG(0));
if (sx0 != 0) {
    BGE_REPORT((bgep, "SEND INDEX - device didn't RESET"));
    bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE);
    return (DDI_FAILURE);
}
/* ... */
/*
 * Sync (all) the receive ring descriptors
 * before accepting the packets they describe
 */
DMA_SYNC(rrp->desc, DDI_DMA_SYNC_FORKERNEL);
if (*rrp->prod_index_p >= rrp->desc.nslots) {
    bgep->bge_chip_state = BGE_CHIP_ERROR;
    bge_fm_ereport(bgep, DDI_FM_DEVICE_INVAL_STATE);
    return (NULL);
}
DDI_FM_DEVICE_INTERN_CORR

设备已报告自我纠正的内部错误。例如,设备的内部缓冲区中的硬件已检测到可纠正的 ECC 错误。

bge 驱动程序中未使用此错误标志。有关使用此错误的示例,请参见 OpenSolaris 中的 nxge_fm.c 文件。执行以下步骤来研究 nxge 驱动程序代码:

DDI_FM_DEVICE_INTERN_UNCORR

设备已报告无法纠正的内部错误。例如,设备的内部缓冲区中的硬件已检测到不可纠正的 ECC 错误。

bge 驱动程序中未使用此错误标志。有关使用此错误的示例,请参见 OpenSolaris 中的 nxge_fm.c 文件。

DDI_FM_DEVICE_STALL

驱动程序检测到数据传输已意外停顿。

bge_factotum_stall_check() 例程提供了停顿检测的示例。

dogval = bge_atomic_shl32(&bgep->watchdog, 1);
if (dogval < bge_watchdog_count)
    return (B_FALSE);

BGE_REPORT((bgep, "Tx stall detected, 
watchdog code 0x%x", dogval));
bge_fm_ereport(bgep, DDI_FM_DEVICE_STALL);
return (B_TRUE);
DDI_FM_DEVICE_NO_RESPONSE

设备未对驱动程序命令进行响应。

bge_chip_poll_engine(bge_t *bgep, bge_regno_t regno,
        uint32_t mask, uint32_t val)
{
        uint32_t regval;
        uint32_t n;

        for (n = 200; n; --n) {
                regval = bge_reg_get32(bgep, regno);
                if ((regval & mask) == val)
                        return (B_TRUE);
                drv_usecwait(100);
        }
        bge_fm_ereport(bgep, DDI_FM_DEVICE_NO_RESPONSE);
        return (B_FALSE);
}
DDI_FM_DEVICE_BADINT_LIMIT

设备引发了过多的连续性无效中断。

bge() 驱动程序内的 bge_intr 例程提供了有问题的中断检测的示例。bge_fm_ereport() 函数是 ddi_fm_ereport_post(9F) 函数的包装。请参见对错误事件排队中的 bge_fm_ereport() 示例。

if (bgep->missed_dmas >= bge_dma_miss_limit) {
    /*
     * If this happens multiple times in a row,
     * it means DMA is just not working.  Maybe
     * the chip has failed, or maybe there's a
     * problem on the PCI bus or in the host-PCI
     * bridge (Tomatillo).
     *
     * At all events, we want to stop further
     * interrupts and let the recovery code take
     * over to see whether anything can be done
     * about it ...
     */
    bge_fm_ereport(bgep,
        DDI_FM_DEVICE_BADINT_LIMIT);
    goto chip_stop;
}