当操作系统通过陷阱或错误中断检测到错误时,错误处理活动可能会开始。如果负责处理错误的软件(错误处理程序)无法立即隔离出现故障的 I/O 操作中涉及的设备,它必须尝试在设备树内查找可以执行错误隔离的软件模块。Solaris 设备树提供了向子级传播结点驱动程序错误处理活动的结构化方法,这些子级可能对错误具有更详细的了解,并可捕获错误状态和隔离问题设备。
驱动程序可以使用 I/O 故障服务框架注册错误处理程序回调。错误处理程序应特定于错误的类型以及进行错误检测的子系统。调用驱动程序的错误处理程序例程时,驱动程序必须检查与设备事务关联的任何未解决的错误并生成 ereport 事件。驱动程序还必须在其 ddi_fm_error(9S) 结构中返回错误处理程序状态。例如,如果已经确定系统的完整性受到威胁,则错误处理程序可能采取的最合适的操作是使系统进入紧急状态。
当错误可能与特定的设备实例关联时,父结点驱动程序会调用回调。注册错误处理程序的设备驱动程序必须为 DDI_FM_ERRCB_CAPABLE。
void ddi_fm_handler_register(dev_info_t *dip, ddi_err_func_t handler, void *impl_data)
ddi_fm_handler_register(9F) 例程向 I/O 故障服务框架注册错误处理程序回调。应在驱动程序故障管理初始化 (ddi_fm_init()) 之后在驱动程序的 attach(9E) 入口点中调用 ddi_fm_handler_register() 函数,以便进行回调注册。
检查与设备事务关联的任何未解决的硬件错误,并生成 ereport 事件以便进行诊断。对于 PCI、PCI-x 或 PCI Express 设备,通常使用 pci_ereport_post() 执行此操作,如检测和报告与 PCI 相关的错误中所述。
在其 ddi_fm_error 结构中返回错误处理程序状态:
DDI_FM_OK
DDI_FM_FATAL
DDI_FM_NONFATAL
DDI_FM_UNKNOWN
驱动程序错误处理程序会接收以下内容:
在驱动程序的控制下接收指向设备实例 (dip) 的指针
包含常见故障管理数据和错误处理状态的数据结构 (ddi_fm_error)
指向在处理程序注册时指定的任何特定于实现的数据 (impl_data) 的指针
必须在驱动程序的 attach(9E) 或 detach(9E) 入口点的内核上下文中调用 ddi_fm_handler_register() 和 ddi_fm_handler_unregister(9F) 例 程。可以从内核、中断或高级别中断上下文中调用注册的错误处理程序回调。因此,错误处理程序:
不得持有锁
等待资源时不得处于休眠状态
设备驱动程序负责:
隔离可能已导致错误的设备实例
恢复与错误关联的事务
报告错误对服务的影响
针对视为致命的错误调度设备关闭
可在错误处理程序函数内执行这些操作。但是,由于对锁定的限制以及错误处理程序函数并非始终了解故障发生时驱动程序所执行操作的上下文,因此,更通常的做法是,如前所述在驱动程序的正常路径内内联调用 ddi_fm_acc_err_get(9F) 和 ddi_fm_dma_err_get(9F) 之后执行这些操作。
/* * The I/O fault service error handling callback function */ /*ARGSUSED*/ static int bge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) { /* * as the driver can always deal with an error * in any dma or access handle, we can just return * the fme_status value. */ pci_ereport_post(dip, err, NULL); return (err->fme_status); }