Go to main content
Oracle® Solaris 11.3 デバイスドライバの記述

印刷ビューの終了

更新: 2016 年 11 月
 
 

Oracle 障害管理アーキテクチャーの入出力障害サービス

このセクションでは、障害管理のためのエラー報告、エラー処理、および診断の各機能を入出力デバイスドライバに統合する方法について説明します。このセクションでは、入出力障害サービスフレームワークの詳細な説明と、デバイスドライバの内部で入出力障害サービスの API を利用する方法を示します。

    このセクションの内容は次のとおりです。

  • 予測的自己修復とはでは、Oracle 障害管理アーキテクチャーの背景および概要を示します。

  • Oracle Solaris Fault Managerでは、Oracle Solaris Fault Manager (fmd(1M)) の概要を中心に、追加の背景を解説します。

  • エラー処理はドライバ開発者にとってもっとも重要なセクションです。このセクションでは、高可用性のための最適なコーディング手法と、ドライバコードで入出力障害サービスを使用して FMA と対話する方法を重点的に解説します。

予測的自己修復とは

従来、システムはハードウェアおよびソフトウェアのエラー情報を、syslog メッセージの形式で人間の管理者および管理ソフトウェアに直接エクスポートしていました。多くの場合、エラーの検出、診断、報告、および処理のロジックは各ドライバのコードに組み込まれていました。

Solaris OS の予測的自己修復システムは、最初に登場した最先端の自己診断機能です。自己診断とは、監視された症状から問題を自動的に診断するための技術をシステムが提供し、その診断結果を利用して自動的な応答および回復を開始できることを意味します。ハードウェアの障害またはソフトウェアの不具合は、エラーと呼ばれる、監視対象の一連の症状と関連付けることができます。エラーの監視結果としてシステムによって生成されるデータは、エラーレポートまたは ereport と呼ばれます。

自己修復機能を備えるシステムでは、ereport がシステムによって取り込まれ、名前と値のペアの集合としてエンコードされます。これらのペアは、ereport イベントを形成するために拡張イベントプロトコルによって記述されます。ereport イベントおよびその他のデータは自己修復を促進するために収集され、診断エンジンと呼ばれるソフトウェアコンポーネントにディスパッチされます。このエンジンは、システムによって監視されるエラーの症状に対応する根本的な問題を診断するように設計されています。診断エンジンはバックグラウンドで動作し、診断を生成または障害を予測できるまで、エラーリモート測定を暗黙のうちに使用します。

リモート測定の処理が完了して結論が得られたら、診断エンジンはフォルトイベントと呼ばれる別のイベントを生成します。生成されたフォルトイベントは、その特定のフォルトイベントの配信対象であるすべてのエージェントにブロードキャストされます。エージェントは、回復処理を開始し、特定のフォルトイベントに応答するソフトウェアコンポーネントです。Oracle Solaris Fault Manager (fmd(1M)) と呼ばれるソフトウェアコンポーネントは、ereport ジェネレータ、診断エンジン、およびエージェントソフトウェア間でのイベントの多重化を管理します。

Oracle Solaris Fault Manager

Oracle Solaris Fault Manager (fmd(1M)) は、インバウンドのエラーリモート測定イベントを適切な診断エンジンにディスパッチします。診断エンジンは、エラー症状の発生原因となっているハードウェアの障害またはソフトウェアの不具合を識別します。fmd(1M) デーモンは、Oracle Solaris OS による Falut Manager の実装です。このデーモンはブート時にブートし、システム上で利用可能なすべての診断エンジンおよびエージェントをロードします。Oracle Solaris Fault Manager は、システム管理者およびサービス担当者が障害管理アクティビティーを監視するためのインタフェースも提供します。

診断、疑いリスト、フォルトイベント

診断が完了すると、list.suspect イベントの形式で診断結果が出力されます。list.suspect イベントは、可能性のある 1 つ以上の障害または不具合イベントで構成されるイベントです。診断では、エラーの原因を 1 つの障害または不具合に絞り込めない場合があります。たとえば、コントローラをメインシステムバスに接続する配線の故障が根本的な問題である可能性があります。バス上の部品に問題がある可能性もあれば、バス自体に問題がある可能性もあります。この特定のケースでは、list.suspect イベントには複数のフォルトイベントが含まれています。バスに接続されたコントローラーごとのイベントと、バス自体に対応する 1 つのイベントです。

    フォルトイベントには、診断された障害の記述に加えて、診断の適用対象となる 4 種類のペイロードメンバーも含まれています。

  • リソースは障害があると診断されたコンポーネントです。fmdump(1M) コマンドでは、このペイロードメンバーは「Problem in」(問題の箇所) と表示されます。

  • 自動システム回復ユニット (ASRU) は、エラー症状の発生を止めるために無効化する必要があるハードウェアまたはソフトウェアコンポーネントです。fmdump(1M) コマンドでは、このペイロードメンバーは「Affects」(影響先) と表示されます。

  • 現場交換可能ユニット (FRU) は、エラーの原因となっている問題を解決するために交換または修理する必要があるコンポーネントです。

  • ラベルペイロードは、シャーシまたはマザーボードに (たとえば、DIMM スロットや PCI カードスロットの隣に) 印刷されているのと同じ形式で FRU の位置を示す文字列です。fmdump コマンドでは、このペイロードメンバーは「Location」(位置) と表示されます。

たとえば、特定のメモリー位置に関して一定時間内に一定数の訂正可能 ECC エラーを受信したあとに、CPU およびメモリーの診断エンジンは DIMM 障害の診断 (list.suspect イベント) を発行します。

# fmdump -v -u 38bd6f1b-a4de-4c21-db4e-ccd26fa8573c
TIME                 UUID                                 SUNW-MSG-ID
Oct 31 13:40:18.1864 38bd6f1b-a4de-4c21-db4e-ccd26fa8573c AMD-8000-8L
100%  fault.cpu.amd.icachetag

Problem in: hc:///motherboard=0/chip=0/cpu=0
Affects: cpu:///cpuid=0
FRU: hc:///motherboard=0/chip=0
Location: SLOT 2

この例では、fmd(1M) によってリソースの問題、具体的には CPU (hc:///motherboard=0/chip=0/cpu=0 ) の問題を特定しています。以後のエラー症状を抑制し、訂正不能エラーの発生を防ぐために、ASRU (cpu:///cpuid=0) がリタイアメントの対象として識別されます。交換が必要なコンポーネントは FRU (hc:///motherboard=0/chip=0) です。

応答エージェント

エージェントは、診断または修復に応答してアクションを実行するソフトウェアコンポーネントです。たとえば、CPU およびメモリーのリタイアエージェントは、fault.cpu.* イベントを含む list.suspect イベントに応答するように設計されています。cpumem-retire エージェントは、CPU のオフライン化、または物理メモリーページのサービスからのリタイアメントを試みます。エージェントが成功すると、リタイアメントに成功したページまたは CPU のエントリが Fault Manager の ASRU キャッシュに追加されます。次の例で示すように、fmadm(1M) ユーティリティーは、障害があると診断されたメモリーランクのエントリを表示します。システムによってオフライン化、リタイアメント、または無効化できない ASRU のエントリも ASRU キャッシュに存在しますが、これらの ASRU は縮退状態と認識されます。縮退とは、ASRU に関連付けられたリソースに障害があるが、その ASRU をサービスから除去できない状態のことです。Oracle Solaris のエージェントソフトウェアは現時点で、入出力 ASRU (デバイスインスタンス) を扱うことができません。キャッシュに存在する、障害のある入出力リソースのエントリはすべて縮退状態です。

# fmadm faulty
   STATE RESOURCE / UUID
-------- ----------------------------------------------------------------------
degraded mem:///motherboard=0/chip=1/memory-controller=0/dimm=3/rank=0
         ccae89df-2217-4f5c-add4-d920f78b4faf
-------- ----------------------------------------------------------------------

リタイアエージェントの第一の目的は、障害があると診断されたハードウェアまたはソフトウェアを切り離す (サービスから安全に除去する) ことです。

    エージェントはほかにも、次のような重要なアクションを実行します。

  • SNMP トラップを介してアラートを送信します。これにより、診断を SNMP 用のアラートに変換し、既存のソフトウェアメカニズムに組み込むことができます。

  • syslog メッセージを送信します。メッセージ固有の診断 (たとえば、syslog メッセージエージェント) では、診断結果を受け取ってそれを syslog メッセージに変換することができ、管理者はこのメッセージに基づいて特定のアクションを実行できます。

  • FRUID の更新などのその他のエージェントアクション。プラットフォームごとに固有の応答エージェントを用意できます。

メッセージ ID と辞書ファイル

syslog メッセージエージェントは、診断の出力 (list.suspect イベント) を取得し、個別のメッセージをコンソールまたは /var/adm/messages に出力します。コンソールのメッセージは理解しにくいことがよくあります。FMA にはこの問題に対処するために、list.suspect イベントが syslog メッセージに配信されるたびに生成される、定義済みのフォルトメッセージ構造体が用意されています。

syslog エージェントはメッセージ識別子 (MSG ID) を生成します。イベントレジストリが生成する辞書ファイル (.dict ファイル) は、list.suspect イベントと構造化メッセージ識別子を対応づけます。この識別子は、関連付けられたナレッジ記事を識別して表示するために使用されます。メッセージファイル (.po ファイル) は、診断エンジンが生成する可能性がある、障害疑いの全リストを対象に、メッセージ ID とローカライズされたメッセージを対応づけます。次に示すのは、テストシステム上で出力されるフォルトメッセージの例です。

SUNW-MSG-ID: AMD-8000-7U, TYPE: Fault, VER: 1, SEVERITY: Major
EVENT-TIME: Fri Jul 28 04:26:51 PDT 2006
PLATFORM: Sun Fire V40z, CSN: XG051535088, HOSTNAME: parity
SOURCE: eft, REV: 1.16
EVENT-ID: add96f65-5473-69e6-dbe1-8b3d00d5c47b
DESC: The number of errors associated with this CPU has exceeded 
acceptable levels. Refer to 

 http://support.oracle.com/msg/SMF-8000-05
 for more information.
AUTO-RESPONSE: An attempt will be made to remove this CPU from service.
IMPACT: Performance of this system may be affected.
REC-ACTION: Schedule a repair procedure to replace the affected CPU. 
Use fmdump -v -u <EVENT_ID> to identify the module.

システムトポロジ

障害が発生した可能性のある箇所を識別するために、診断エンジンは、特定のソフトウェアまたはハードウェアシステムを表現したトポロジを備える必要があります。fmd(1M) デーモンは、診断中に使用できるトポロジのスナップショットへのハンドルを診断エンジンに提供します。トポロジ情報は、個々のフォルトイベントで見つかったリソース、ASRU、および FRU を表現するために使用されます。トポロジはプラットフォームラベル、FRUID、およびシリアル番号 ID を格納する目的にも使用できます。

フォルトイベントのリソースペイロードメンバーは常に、外側のプラットフォームシャーシからの物理的なパス位置によって表されます。たとえば、メインシステムバスから PCI ローカルバスにブリッジされる PCI コントローラ機能は、次に示すように、その hc スキームパス名によって表されます。

hc:///motherboard=0/hostbridge=1/pcibus=0/pcidev=13/pcifn=0

フォルトイベントの ASRU ペイロードメンバーは通常、ハードウェアコントローラ、デバイス、または機能と結びついた Oracle Solaris デバイスツリーインスタンス名によって表されます。FMA では dev スキームを使用して、ASRU をそのネイティブ形式で表現します。この形式は、入出力デバイス専用に設計されたリタイアエージェントの将来の実装によって実行される可能性があるアクションに対応しています。

dev:////pci@1e,600000/ide@d

フォルトイベントの FRU ペイロードの表現は、障害と診断された入出力リソースにもっとも近い交換可能部品によって異なります。たとえば、組み込み PCI コントローラの故障のフォルトイベントでは、次のように、交換が必要な FRU としてシステムのマザーボードが指定される場合があります。

hc:///motherboard=0

ラベルペイロードは、シャーシまたはマザーボードに (たとえば、DIMM スロットや PCI カードスロットの隣に) 印刷されているのと同じ形式で FRU の位置を示す文字列です。

Label: SLOT 2

エラー処理

このセクションでは、ドライバの内部で入出力障害サービスの API を使用してエラーを処理する方法について説明します。このセクションでは、ドライバで障害管理機能を指定および初期化する方法、エラーレポートを生成する方法、および、ドライバのエラーハンドラルーチンを登録する方法を説明します。

FMA エラーレポートリモート測定を提供するように設計されたドライバは、エラーを検出し、それらのエラーがドライバによって提供されるサービスに及ぼす影響を判断します。ドライバが、エラーの検出後にそのサービスが影響を受けたタイミングと影響の程度を特定するようにしてください。

    入出力ドライバは、検出されたエラーにただちに応答する必要があります。適切な応答には次のものがあります。

  • 回復を試みる

  • 入出力トランザクションを再試行する

  • フェイルオーバー手法を試みる

  • 呼び出し側のアプリケーション/スタックにエラーを報告する

  • ほかのどの方法によってもエラーを抑制できない場合、パニック状態に移行する

ドライバによって検出されたエラーは ereport として障害管理デーモンに伝達されます。ereport は、FMA イベントプロトコルによって定義された構造化イベントです。イベントプロトコルは各種の共通データフィールドの仕様であり、障害疑いのリストだけでなく、すべてのエラーイベントおよびフォルトイベントはこのプロトコルを使用して記述する必要があります。ereport は収集されてエラーリモート測定のフローにまとめられ、診断エンジンにディスパッチされます。

障害管理機能の宣言

強化されたデバイスドライバでは、その障害管理機能を入出力障害管理フレームワークに宣言する必要があります。ドライバの障害管理機能を宣言するには、ddi_fm_init(9F) 関数を使用します。

void ddi_fm_init(dev_info_t *dip, int *fmcap, ddi_iblock_cookie_t *ibcp)

ddi_fm_init() 関数は、カーネルコンテキストからドライバの attach(9E) またはdetach(9E) エントリポイントで呼び出すことができます。ddi_fm_init() 関数は通常、attach() エントリポイントから呼び出されます。ddi_fm_init() 関数は、fmcap に従ってリソースを割り当てて初期化します。fmcap パラメータには、次に示す障害管理機能のビット単位の論理和を設定する必要があります。

  • DDI_FM_EREPORT_CAPABLE - ドライバはエラー条件を検出したときに FMA プロトコルのエラーイベント (ereport) を生成する必要があり、そのための能力を備えています。

  • DDI_FM_ACCCHK_CAPABLE - ドライバは 1 つ以上のアクセス入出力トランザクションが完了したときにエラーをチェックする必要があり、そのための能力を備えています。

  • DDI_FM_DMACHK_CAPABLE - ドライバは 1 つ以上の DMA 入出力トランザクションが完了したときにエラーをチェックする必要があり、そのための能力を備えています。

  • DDI_FM_ERRCB_CAPABLE - ドライバはエラーコールバック関数を備えています。

強化されたリーフドライバでは通常、これらすべての機能を設定します。ただし、そのドライバの親ネクサスが要求された機能をどれもサポートしない場合、機能に関連付けられたビットがクリアされてからドライバに返されます。ddi_fm_init(9F) から戻る前に、一連の障害管理機能プロパティー (fm-ereport-capable、fm-accchk-capable、fm-dmachk-capable、および fm-errcb-capable) を作成します。現在サポートされている障害管理機能のレベルは、prtconf(1M) コマンドを使用すると確認できます。

管理者が選択した障害管理機能をドライバでサポートするには、driver.conf(4) ファイルで障害管理機能レベルのプロパティーをエクスポートし、先に説明した値を設定します。fm-capable プロパティーの設定および読み取りは、目的の機能リストを指定して ddi_fm_init() を呼び出す前に行われる必要があります。

bge ドライバからの次の例では bge_fm_init() 関数が示されていますが、この関数から ddi_fm_init(9F) 関数が呼び出されています。bge_fm_init() 関数は bge_attach() 関数内で呼び出されます。

static void
bge_fm_init(bge_t *bgep)
{
        ddi_iblock_cookie_t iblk;

        /* Only register with IO Fault Services if we have some capability */
        if (bgep->fm_capabilities) {
                bge_reg_accattr.devacc_attr_access = DDI_FLAGERR_ACC;
                dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
                /* 
                 * Register capabilities with IO Fault Services
                 */
                ddi_fm_init(bgep->devinfo, &bgep->fm_capabilities, &iblk);
                /*
                 * Initialize pci ereport capabilities if ereport capable
                 */
                if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) ||
                    DDI_FM_ERRCB_CAP(bgep->fm_capabilities))
                        pci_ereport_setup(bgep->devinfo);
                /*
                 * Register error callback if error callback capable
                 */
                if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities))
                        ddi_fm_handler_register(bgep->devinfo,
                        bge_fm_error_cb, (void*) bgep);
        } else {
                /*
                 * These fields have to be cleared of FMA if there are no
                 * FMA capabilities at runtime.
                 */
                bge_reg_accattr.devacc_attr_access = DDI_DEFAULT_ACC;
                dma_attr.dma_attr_flags = 0;
        }
}

障害管理リソースのクリーンアップ

ddi_fm_fini(9F) 関数は、dip の障害管理をサポートするために割り当てられたリソースをクリーンアップします。

void ddi_fm_fini(dev_info_t *dip)

ddi_fm_fini() 関数は、カーネルコンテキストからドライバのattach(9E) またはdetach(9E) エントリポイントで呼び出すことができます。

bge ドライバからの次の例では bge_fm_fini() 関数が示されていますが、この関数から ddi_fm_fini(9F) 関数が呼び出されています。bge_fm_fini() 関数は bge_unattach() 関数内で呼び出され、この関数は bge_attach() および bge_detach() の両関数内で呼び出されます。

static void
bge_fm_fini(bge_t *bgep)
{
        /* Only unregister FMA capabilities if we registered some */
        if (bgep->fm_capabilities) {
                /*
                 * Release any resources allocated by pci_ereport_setup()
                 */
                if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities) ||
                    DDI_FM_ERRCB_CAP(bgep->fm_capabilities))
                        pci_ereport_teardown(bgep->devinfo);
                /*
                 * Un-register error callback if error callback capable
                 */
                if (DDI_FM_ERRCB_CAP(bgep->fm_capabilities))
                        ddi_fm_handler_unregister(bgep->devinfo);
                /*
                 * Unregister from IO Fault Services
                 */
                ddi_fm_fini(bgep->devinfo);
        }
}

障害管理機能ビットマスクの取得

ddi_fm_capable(9F) 関数は、dip に現在設定されている機能ビットマスクを返します。

void ddi_fm_capable(dev_info_t *dip)

エラーの報告

キューへのエラーイベントの送信

ddi_fm_ereport_post(9F) 関数は、障害管理デーモン fmd(1M) に配信する ereport イベントをキューに入れます。

void ddi_fm_ereport_post(dev_info_t *dip, 
                         const char *error_class, 
                         uint64_t ena, 
                         int sflag, ...)

sflag パラメータは、システムメモリーリソースおよびイベントチャネルリソースが利用可能になるまで呼び出し側が待機するかどうかを示します。

ENA はこのエラーレポートに対するエラー数値関連付け (Error Numeric Association) を意味します。ENA は、バスネクサスドライバのような別のエラー検出ソフトウェアモジュールから初期化および取得されている可能性があります。ENA を 0 に設定した場合、ENA は ddi_fm_ereport_post() によって初期化されます。

名前-値ペア (nvpair) 変数の引数リストの内容は、配列以外の data_type_t 型の場合は 1 つ以上の名前、型、値ポインタの nvpair 組であり、data_type_t 配列型の場合は 1 つ以上の名前、型、要素数、値ポインタの組です。nvpair 組は、診断のために必要な ereport イベントペイロードを構成します。引数リストの終了は NULL によって指定されます。

error_class には、入出力コントローラに関して標準入出力コントローラのエラーの報告で説明されている ereport クラス名およびペイロードが適宜使用されます。その他の ereport クラス名およびペイロードも定義できますが、これらは、ドライバ固有の診断エンジンソフトウェアまたは Eversholt フォルトツリー (eft) ルールとともに Oracle イベントレジストリに登録する必要があります。

void
bge_fm_ereport(bge_t *bgep, char *detail)
{
        uint64_t ena;
        char buf[FM_MAX_CLASS];
        (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
        ena = fm_ena_generate(0, FM_ENA_FMT1);
        if (DDI_FM_EREPORT_CAP(bgep->fm_capabilities)) {
                ddi_fm_ereport_post(bgep->devinfo, buf, ena, DDI_NOSLEEP,
                    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
        }
}
PCI 関連エラーの検出と報告

pci_ereport_post(9F) を使用する場合、PCI、PCI-X、PCI-E を含む PCI 関連のエラーが自動的に検出および報告されます。

void pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status)

PCI ローカルバス構成ステータスレジスタで発生するエラーについては、ドライバ固有の ereport をドライバで生成する必要はありません。pci_ereport_post() 関数は、データパリティーエラー、マスターアボート、ターゲットアボート、シグナル付きシステムエラーなどを報告できます。

ドライバ内で pci_ereport_post() を使用する場合は、ドライバの attach(9E) ルーチンで pci_ereport_setup(9F) が事前に呼び出されており、なおかつ、使用後にドライバの detach(9E) ルーチンで pci_ereport_teardown(9F) が呼び出される必要があります。

次に示す bge ドライバのコード例では、ドライバのエラーハンドラから pci_ereport_post() 関数を呼び出しています。

/*
 * 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);
}
標準入出力コントローラのエラーの報告

入出力コントローラでよく発生するエラーに対応した、デバイス ereport の標準セットが定義されています。これらの ereport は、このセクションで説明するいずれかのエラー症状が検出されるたびに生成されます。

このセクションで説明する ereport は、標準ルールの共通セットを使用して ereport を診断する eft 診断エンジンにディスパッチされます。その他のエラーをデバイスドライバで検出する場合、そのエラーは ereport イベントの形式で、デバイス固有の診断ソフトウェアまたは eft ルールとともに Sun イベントレジストリで定義されている必要があります。

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 ドライバではこのエラーフラグは使用されていません。

DDI_FM_DEVICE_INTERN_UNCORR

デバイスは訂正不能な内部エラーを報告しました。たとえば、デバイスの内部バッファーで、訂正不能な ECC エラーがハードウェアによって検出されました。

bge ドライバではこのエラーフラグは使用されていません。

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;
}
サービス影響関数

障害管理機能を備えたドライバは、デバイスによって提供されるサービスにエラーが影響を及ぼしたかどうかを示す必要があります。エラーの検出 (および、必要に応じたサービスのシャットダウン) 後に、ドライバが ddi_fm_service_impact(9F) ルーチンを呼び出して、デバイスインスタンスの現在のサービス状態を反映するようにしてください。診断および回復ソフトウェアでは、サービス状態を利用することにより、問題の識別または問題への対応が容易になります。

ドライバ自体がエラーを検出したときも、フレームワークがエラーを検出してアクセスハンドルまたは DMA ハンドルに障害のマークを付けたときも、ddi_fm_service_impact() ルーチンが呼び出されるようにしてください。

void ddi_fm_service_impact(dev_info_t *dip, int svc_impact)

ddi_fm_service_impact() に渡すことのできるサービス影響値 (svc_impact) は次のとおりです。

DDI_SERVICE_LOST

デバイスによって提供されるサービスが、デバイスの障害またはソフトウェアの不具合のために利用できません。

DDI_SERVICE_DEGRADED

ドライバは通常のサービスを提供できませんが、部分的または縮退レベルのサービスを提供できます。たとえば、ドライバは目的の操作が成功するまで操作を繰り返し試行する必要があるか、または構成された速度よりも低速に動作しています。

DDI_SERVICE_UNAFFECTED

ドライバはエラーを検出しましたが、デバイスインスタンスによって提供されるサービスは影響を受けません。

DDI_SERVICE_RESTORED

デバイスのすべてのサービスは復元されました。

ddi_fm_service_impact() を呼び出すと、サービス影響ルーチンに渡されたサービス影響引数に基づいて、ドライバの代わりに次の ereport が生成されます。

  • ereport.io.service.lost

  • ereport.io.service.degraded

  • ereport.io.service.unaffected

  • ereport.io.service.restored

次に示す bge のコードでは、ドライバはエラーの結果としてパケットの送受信を正常に再開できないと判断します。デバイスのサービス状態は DDI_SERVICE_LOST に遷移します。

/*
 * All OK, reinitialize hardware and kick off GLD scheduling
 */
mutex_enter(bgep->genlock);
if (bge_restart(bgep, B_TRUE) != DDI_SUCCESS) {
    (void) bge_check_acc_handle(bgep, bgep->cfg_handle);
    (void) bge_check_acc_handle(bgep, bgep->io_handle);
    ddi_fm_service_impact(bgep->devinfo, DDI_SERVICE_LOST);
    mutex_exit(bgep->genlock);
    return (DDI_FAILURE);
}

注 - 登録済みのコールバックルーチンから ddi_fm_service_impact() 関数を呼び出さないでください。