ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
デバイスドライバの記述 Oracle Solaris 10 8/11 Information Library (日本語) |
この節では、障害管理のためのエラー報告、エラー処理、および診断の各機能を入出力デバイスドライバに統合する方法について説明します。入出力障害サービスフレームワークの詳細な説明と、デバイスドライバの内部で入出力障害サービスの API を利用する方法を示します。
この節の内容は次のとおりです。
「予測的自己修復とは」では、Sun 障害管理アーキテクチャーの技術的背景および概要を示します。
「Solaris Fault Manager」では、Solaris Fault Manager (fmd(1M)) の概要を中心に、追加の技術的背景を解説します。
「エラー処理」はドライバ開発者にとってもっとも重要な節です。この節では、高可用性のための最適なコーディング手法と、ドライバコードで入出力障害サービスを使用して FMA と対話する方法を重点的に解説します。
「障害の診断」では、ドライバによって検出されるエラーをもとに障害が診断されるしくみについて説明します。
「イベントレジストリ」では、Sun のイベントレジストリについての情報を提供します。
従来、システムはハードウェアおよびソフトウェアのエラー情報を、syslog メッセージの形式で人間の管理者および管理ソフトウェアに直接エクスポートしていました。多くの場合、エラーの検出、診断、報告、および処理のロジックは各ドライバのコードに組み込まれていました。
Solaris OS の予測的自己修復システムは、最初に登場した最先端の自己診断機能です。自己診断とは、監視された症状から問題を自動的に診断するための技術をシステムが提供し、その診断結果を利用して自動的な応答および回復を開始できることを意味します。ハードウェアの障害またはソフトウェアの不具合は、エラーと呼ばれる、監視対象の一連の症状と関連付けることができます。エラーの監視結果としてシステムによって生成されるデータは、エラーレポートまたは ereport と呼ばれます。
自己修復機能を備えるシステムでは、ereport がシステムによって取り込まれ、名前と値のペアの集合としてエンコードされます。これらのペアは、ereport イベントを形成するために拡張イベントプロトコルによって記述されます。ereport イベントおよびその他のデータは自己修復を促進するために収集され、診断エンジンと呼ばれるソフトウェアコンポーネントにディスパッチされます。このエンジンは、システムによって監視されるエラーの症状に対応する根本的な問題を診断するように設計されています。診断エンジンはバックグラウンドで動作し、診断を生成または障害を予測できるまで、エラー遠隔測定を暗黙のうちに使用します。
遠隔測定の処理が完了して結論が得られたら、診断エンジンはフォルトイベントと呼ばれる別のイベントを生成します。生成されたフォルトイベントは、その特定のフォルトイベントの配信対象であるすべてのエージェントにブロードキャストされます。エージェントは、回復処理を開始し、特定のフォルトイベントに応答するソフトウェアコンポーネントです。Solaris Fault Manager (fmd(1M)) と呼ばれるソフトウェアコンポーネントは、ereport ジェネレータ、診断エンジン、およびエージェントソフトウェア間でのイベントの多重化を管理します。
Solaris Fault Manager (fmd(1M)) は、インバウンドのエラー遠隔測定イベントを適切な診断エンジンにディスパッチします。診断エンジンは、エラー症状の発生原因となっているハードウェアの障害またはソフトウェアの不具合を識別します。fmd(1M) デーモンは、Solaris OS による Falut Manager の実装です。このデーモンはブート時に起動し、システム上で利用可能なすべての診断エンジンおよびエージェントをロードします。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 をサービスから除去できない状態のことです。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 の更新などのその他のエージェントアクション。プラットフォームごとに固有の応答エージェントを用意できます。
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://sun.com/msg/AMD-8000-7U 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 ペイロードメンバーは通常、ハードウェアコントローラ、デバイス、または機能と結びついた Solaris デバイスツリーインスタンス名によって表されます。FMA では dev スキーマを使用して、ASRU をそのネイティブ形式で表現します。この形式は、入出力デバイス専用に設計されたリタイアエージェントの将来の実装によって実行される可能性があるアクションに対応しています。
dev:////pci@1e,600000/ide@d
フォルトイベントの FRU ペイロードの表現は、障害と診断された入出力リソースにもっとも近い交換可能部品によって異なります。たとえば、組み込み PCI コントローラの故障のフォルトイベントでは、次のように、交換が必要な FRU としてシステムのマザーボードが指定される場合があります。
hc:///motherboard=0
ラベルペイロードは、シャーシまたはマザーボードに (たとえば、DIMM スロットや PCI カードスロットの隣に) 印刷されているのと同じ形式で FRU の位置を示す文字列です。
Label: SLOT 2
この節では、ドライバの内部で入出力障害サービスの API を使用してエラーを処理する方法について説明します。ドライバで障害管理機能を指定および初期化する方法、エラーレポートを生成する方法、および、ドライバのエラーハンドラルーチンを登録する方法を説明します。
ここでは、入出力障害サービス API の使用方法の例として、Broadcom 1Gb NIC ドライバ (bge) のソースコードを抜粋して示しています。これから開発するドライバに障害管理機能を統合する方法のモデルとして、これらの例を参考にしてください。bge ドライバのコード全体を入手するには、次の手順に従います。
ON (OS/Net) Sources にアクセスします。
「File Path」フィールドに bge と入力します。
「Search」ボタンをクリックします。
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)
この節では、次のトピックについての情報を提供します。
「キューへのエラーイベントの送信」では、エラーイベントをキューに入れる方法について説明します。
「PCI 関連エラーの検出と報告」では、PCI 関連のエラーを報告する方法について説明します。
「標準入出力コントローラのエラーの報告」では、標準入出力コントローラのエラーを報告する方法について説明します。
「サービス影響関数」では、デバイスによって提供されるサービスにエラーが影響を及ぼしたかどうかを報告する方法について説明します。
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) ルールとともに Sun イベントレジストリに登録する必要があります。Sun イベントレジストリおよび Eversholt フォルトツリールールの詳細は、OpenSolaris プロジェクトの「Fault Management community」を参照してください。
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_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() を使用する場合、以前に pci_ereport_setup(9F) がドライバの attach(9E) ルーチン内で呼び出され、その後 pci_ereport_teardown(9F) がドライバの detach(9E) ルーチン内で呼び出されている必要があります。
次に示す 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 イベントレジストリで定義されている必要があります。
ドライバはデバイスが無効な状態であることを検出しました。
ドライバでは、送信または受信するデータが無効と思われることを検出した時点でエラーを送信するようにしてください。たとえば、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); }
デバイスは自己訂正内部エラーを報告しました。たとえば、デバイスの内部バッファーで、訂正可能な ECC エラーがハードウェアによって検出されました。
bge ドライバではこのエラーフラグは使用されていません。このエラーの使用例については、OpenSolaris の nxge_fm.c ファイルを参照してください。 nxge ドライバのコードを入手するには、次の手順に従います。
OpenSolaris プロジェクトのサイトに移動します。
ページの右上隅にある「Source Browser」をクリックします。
「File Path」フィールドに nxge と入力します。
「Search」ボタンをクリックします。
デバイスは訂正不能な内部エラーを報告しました。たとえば、デバイスの内部バッファーで、訂正不能な ECC エラーがハードウェアによって検出されました。
bge ドライバではこのエラーフラグは使用されていません。このエラーの使用例については、OpenSolaris の nxge_fm.c ファイルを参照してください。
ドライバは、データ転送が予期せずストールしたことを検出しました。
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);
デバイスはドライバのコマンドに応答していません。
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); }
デバイスが連続で発生させた無効な割り込みの数が多すぎます。
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_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() 関数を呼び出さないでください。
DDI_FM_ACCCHK_CAPABLE デバイスドライバは、レジスタの読み取りまたは書き込み中に発生するプログラム式入出力 (PIO) アクセスエラーを処理できることを示すように、そのアクセス属性を設定する必要があります。ddi_device_acc_attr(9S) 構造体の devacc_attr_access フィールドは、ドライバがデータパスエラーのチェックと処理を実行できることをシステムに知らせるために設定します。ddi_device_acc_attr 構造体には次のメンバーがあります。
ushort_t devacc_attr_version; uchar_t devacc_attr_endian_flags; uchar_t devacc_attr_dataorder; uchar_t devacc_attr_access; /* access error protection */
デバイスとの間のデータパスで検出されるエラーは、デバイスドライバの親ネクサスのうちの 1 つ以上によって処理できます。
devacc_attr_version フィールドは DDI_DEVICE_ATTR_V1 以上に設定する必要があります。devacc_attr_version フィールドが DDI_DEVICE_ATTR_V1 以上に設定されていない場合、devacc_attr_access フィールドは無視されます。
devacc_attr_access フィールドには次の値を設定できます。
このフラグは、エラーが発生したときにシステムがデフォルトのアクション (必要であればパニック状態に移行) を実行することを示します。この属性は DDI_FM_ACCCHK_CAPABLE ドライバでは使用できません。
このフラグは、アクセスハンドルと関連付けられたエラーの処理およびエラーからの回復をシステムが試みることを示します。ドライバでは、「Solaris デバイスドライバの防御的プログラミング手法」で説明されている手法を使用し、呼び出し側アプリケーションにデータを返却することをドライバで許可する前に ddi_fm_acc_err_get(9F) を使用して定期的にエラーをチェックするようにしてください。
DDI_FLAGERR_ACC フラグを指定すると、次のことが可能になります。
ドライバコールバックを介したエラー通知
次の関数によるエラー条件の監視: ddi_fm_acc_err_get(9F)
DDI_CAUTIOUS_ACC フラグを指定すると、ドライバによって行われる毎回のプログラム式入出力アクセスの保護レベルが高まります。
DDI_CAUTIOUS_ACC フラグは、アクセスする側のドライバがエラーを予期していることを示します。システムはこのハンドルと関連付けられたエラーを、できるかぎり正常に処理してエラーから回復することを試みます。結果としてエラーレポートは生成されませんが、ハンドルの fme_status フラグは DDI_FM_NONFATAL に設定されます。このフラグは機能的には ddi_peek(9F) および ddi_poke(9F) と同等です。
DDI_CAUTIOUS_ACC を使用すると、次のことが可能になります。
バスへの排他的アクセス
オントラップ保護 - (ddi_peek() および ddi_poke())
ddi_fm_handler_register(9F) によって登録されるドライバコールバックを介したエラー通知
次の関数によるエラー条件の監視: ddi_fm_acc_err_get(9F)
ドライバでは通常、データの一貫性を保証するため、また入出力ソフトウェアスタックで適正なエラー状態が提示されることを保証するために、コードパス内の適切な分岐点でデータパスエラーをチェックするようにしてください。
DDI_FM_ACCCHK_CAPABLE デバイスドライバでは、その devacc_attr_access フィールドを DDI_FLAGERR_ACC または DDI_CAUTIOUS_ACC に設定する必要があります。
アクセスハンドル設定と同様に、DDI_FM_DMACHK_CAPABLE デバイスドライバはその ddi_dma_attr(9S) 構造体の dma_attr_flag フィールドを DDI_DMA_FLAGERR フラグに設定する必要があります。システムは、DDI_DMA_FLAGERR が設定されたハンドルと関連付けられているエラーからの回復を試みます。ddi_dma_attr 構造体には次のメンバーが含まれています。
uint_t dma_attr_version; /* version number */ uint64_t dma_attr_addr_lo; /* low DMA address range */ uint64_t dma_attr_addr_hi; /* high DMA address range */ uint64_t dma_attr_count_max; /* DMA counter register */ uint64_t dma_attr_align; /* DMA address alignment */ uint_t dma_attr_burstsizes; /* DMA burstsizes */ uint32_t dma_attr_minxfer; /* min effective DMA size */ uint64_t dma_attr_maxxfer; /* max DMA xfer size */ uint64_t dma_attr_seg; /* segment boundary */ int dma_attr_sgllen; /* s/g length */ uint32_t dma_attr_granular; /* granularity of device */ uint_t dma_attr_flags; /* Bus specific DMA flags */
DDI_DMA_FLAGERR フラグを設定するドライバでは、「Solaris デバイスドライバの防御的プログラミング手法」で説明されている手法を使用し、DMA トランザクションが完了するたびに、またはコードパス内の重要なポイントで ddi_fm_dma_err_get(9F) を使用してデータパスエラーをチェックするようにしてください。これにより、一貫したデータと適正なエラー状態が入出力ソフトウェアスタックに提示されるようになります。
DDI_DMA_FLAGERR を使用すると、次のことが可能になります。
ddi_fm_handler_register() によって登録されるドライバコールバックを介したエラー通知
ddi_fm_dma_err_get() の呼び出しによるエラー条件の監視
障害が発生し、ハンドルによって対応づけられたリソースにその影響が及ぶ場合、バスによる、または入出力データパス上のその他のデバイスドライバによるエラー処理中に取り込まれたエラー情報を反映して、エラー状態構造体が
void ddi_fm_dma_err_get(ddi_dma_handle_t handle, ddi_fm_error_t *de, int version) void ddi_fm_acc_err_get(ddi_acc_handle_t handle, ddi_fm_error_t *de, int version)
更新されます。 ddi_fm_dma_err_get(9F) 関数は DMA のエラー状態を返し、ddi_fm_acc_err_get(9F) 関数はアクセスハンドルのエラー状態を返します。version フィールドは DDI_FME_VERSION に設定してください。
アクセスハンドルのエラーは、そのアクセスハンドルを使用して行われる、デバイスとの間の PIO トランザクションに影響するエラーが検出されたことを意味します。最近の ddi_get8(9F) の呼び出しなどを介してドライバが受信したデータが部分的に破壊されているとみなすようにしてください。また、最近の ddi_put32(9F) の呼び出しなどを介してデバイスに送信されたデータも、破壊されているか、またはまったく受信されていない可能性があります。ただし、原因となっている障害は一時的である可能性があるため、ドライバでは ddi_fm_acc_err_clear(9F) を呼び出し、デバイスをリセットして既知の状態に戻し、失敗した可能性があるすべてのトランザクションを再試行することによって回復を試みることができます。
DMA ハンドルのエラーが示された場合、そのハンドルに現在バインドされている (または、その時点でバインドされていない場合は最近バインドされた) メモリーとデバイスの間の DMA トランザクションに影響するエラーが検出されたことを意味します。考えられる原因には、DMA データパス上のコンポーネントの障害や、デバイスが無効な DMA アクセスを試みたことなどがあります。ドライバでは、再試行してメモリーを再割り当てすることによって処理を継続できる可能性があります。ハンドルに現在バインドされている (または以前にバインドされていた) メモリーの内容を不定とみなし、そのメモリーを解放してシステムに返却するようにしてください。現在のトランザクションと関連付けられている障害の指示は、ハンドルがバインドまたは再バインドされた時点で失われますが、障害は持続する可能性があり、以後の DMA 操作も成功しない可能性があります。
ハンドルによってエラーが検出されたあとに、ドライバで ddi_fm_acc_err_clear() および ddi_fm_dma_err_clear(9F) ルーチンを呼び出すと、ハンドルを解放して再割り当てしなくても要求を再試行できます。
void ddi_fm_acc_err_clear(ddi_acc_handle_t handle, int version) void ddi_fm_dma_err_clear(ddi_dma_handle_t handle, int version)
エラー処理アクティビティーは、トラップまたはエラー割り込みを介してオペレーティングシステムがエラーを検出した時点で開始される可能性があります。エラー処理を担うソフトウェア (エラーハンドラ) が、失敗した入出力操作に関与していたデバイスをただちに切り離すことができない場合、そのソフトウェアは、エラーの分離を実行できるソフトウェアモジュールをデバイスツリーから探すことを試みる必要があります。Solaris のデバイスツリーは、ネクサスドライバのエラー処理アクティビティーを下位ノードに伝播するための構造的手段を提供します。その際、下位ノードがエラーをより詳しく把握し、エラー状態を取り込んで問題のデバイスを切り離すことができる可能性があります。
ドライバでは、エラーハンドラコールバックを入出力障害サービスフレームワークに登録できます。エラーハンドラは、エラーの種類ごとに、またエラー検出が発生したサブシステムごとに固有のものとしてください。ドライバのエラーハンドラルーチンが呼び出されたとき、ドライバではデバイストランザクションと関連付けられた未処理のエラーをすべてチェックして、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) ルーチンは、エラーハンドラを入出力障害サービスフレームワークに登録します。コールバック登録のための ddi_fm_handler_register() 関数は、ドライバの障害管理機能の初期化 (ddi_fm_init()) よりもあとに、ドライバの attach(9E) エントリポイントで呼び出されるようにしてください。
エラーハンドラのコールバック関数は次の処理を実行する必要があります。
デバイストランザクションと関連付けられている未処理のハードウェアエラーをすべてチェックし、診断のための ereport イベントを生成します。PCI、PCI-x、または PCI Express デバイスの場合、これは通常、「PCI 関連エラーの検出と報告」で説明されているように pci_ereport_post() を使用すると実行できます。
次に示すエラーハンドラの状態を、その ddi_fm_error 構造体で返します。
DDI_FM_OK
DDI_FM_FATAL
DDI_FM_NONFATAL
DDI_FM_UNKNOWN
ドライバのエラーハンドラは次の情報を受け取ります。
ドライバの制御下にあるデバイスインスタンスへのポインタ (dip)
エラー処理のための共通の障害管理データおよび状態を格納したデータ構造体 (ddi_fm_error)
ハンドラの登録時に指定された実装固有データへのポインタ (impl_data)
ddi_fm_handler_register() および ddi_fm_handler_unregister(9F) ルーチンは、カーネルコンテキストから、ドライバの attach(9E) または detach(9E) エントリポイントで呼び出す必要があります。登録済みのエラーハンドルコールバックは、カーネル、割り込み、または高レベル割り込みの各コンテキストから呼び出すことができます。そのため、エラーハンドラには次の条件があります。
ロックを保持してはならない
休眠状態でリソースを待機してはならない
デバイスドライバは次の処理を担います。
エラーを引き起こした可能性があるデバイスインスタンスの切り離し
エラーと関連付けられたトランザクションの回復
エラーがサービスに及ぼす影響の報告
エラーが致命的とみなされた場合の、デバイスのシャットダウンのスケジューリング
これらのアクションはエラーハンドラ関数の内部で実行できます。ただし、ロックに関する制限と、障害発生の時点でドライバが実行していた処理のコンテキストをエラーハンドラ関数が常に認識しているとは限らないことが原因で、すでに説明したように、ドライバの通常パスの内部で 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); }
ドライバのエラー処理コールバックには、エラー処理のための共通の障害管理データおよび状態が格納されたデータ構造へのポインタが渡されます。
データ構造 ddi_fm_error に格納されるのは、FMA プロトコルによる現在のエラーの ENA、エラーハンドラコールバックの状態、エラー予測フラグ、および、親ネクサスによって検出されたエラーと関連付けられているすべてのアクセスハンドルまたは DMA ハンドルです。
このフィールドは呼び出し側の親ネクサスによって初期化され、ドライバの登録済みコールバックルーチンに到達する前に、エラー処理伝播チェーンの途中で増分されている可能性があります。ドライバが独自に関連エラーを検出した場合、ddi_fm_ereport_post() を呼び出す前にドライバでこの ENA を増分してください。
親のレベルで検出されたエラーを、デバイスドライバによって対応づけまたはバインドされたハンドルに親が関連付けることができた場合、これらのフィールドには有効なアクセスハンドルまたは DMA ハンドルが格納されています。
DDI_CAUTIOUS_ACC 保護操作の結果としてエラーが発生したと呼び出し側の親が判断した場合、fme_flag フラグは DDI_FM_ERR_EXPECTED に設定されます。この場合、fme_acc_handle は有効であり、ドライバでは DDI_CAUTIOUS_ACC 保護操作と関連付けられていないエラーのみをチェックして報告するようにしてください。それ以外の場合、fme_flag は DDI_FM_ERR_UNEXPECTED に設定され、ドライバはすべての範囲のエラー処理タスクを実行する必要があります。
そのエラーハンドルコールバックから戻るときに、ドライバは fme_status を次のいずれかの値に設定する必要があります。
DDI_FM_OK – エラーは検出されませんでした。このデバイスインスタンスの動作状態は同じままです。
DDI_FM_FATAL – エラーが発生しました。ドライバはそのエラーがシステムにとって致命的であると認識しています。たとえば、 pci_ereport_post(9F) の呼び出しが致命的なシステムエラーを検出した可能性があります。この場合、ドライバがドライバのコンテキストで保持している補足的なエラー情報をすべて報告するようにしてください。
DDI_FM_NONFATAL – ドライバによってエラーが検出されましたが、エラーはシステムにとって致命的であるとは認識されていません。ドライバはエラーを識別し、エラーを分離したか、または今後エラーを分離することを確定しています。
DDI_FM_UNKNOWN – エラーが検出されましたが、ドライバはデバイスを切り離すことができないか、またはエラーがシステムの稼働状態に及ぼす影響を特定できません。
障害管理デーモン fmd(1M) は、診断エンジン (DE) プラグインモジュールの開発のためのプログラミングインタフェースを提供します。任意または特定のエラー遠隔測定を使用して診断するように DE を記述できます。eft DE は、Eversholt 言語で指定された診断ルールに基づいて、多数の ereport クラスを診断するように設計されました。
ほとんどの入出力サブシステムは eft DE およびルールセットを使用して、デバイスおよびデバイスドライバ関連の問題を診断します。PCI リーフデバイス向けとしては、「標準入出力コントローラのエラーの報告」の一覧に示した標準 ereport のセットが定義されています。これらの ereport に付随する eft 診断ルールは、遠隔測定を使用し、関連付けられたデバイス障害を識別します。これらの ereport を生成するドライバでは、追加の診断ソフトウェアまたは eft ルールを配布する必要は一切ありません。
これらの ereport の検出および生成により、次のフォルトイベントが生成されます。
PCI バス上のハードウェア障害
デバイス内部のハードウェア障害
デバイスが無効な要求を送信する原因である、デバイスのハードウェア障害またはドライバの不具合
ドライバが有効な要求に応答しない原因である、デバイスのハードウェア障害
リンク上のハードウェア障害
リンクがダウンしているためデバイスが有効な要求に応答できない
デバイス内部のハードウェア障害
デバイスが無効な要求を送信する原因である、デバイスのハードウェア障害またはドライバの不具合
有効な要求に応答しない原因である、デバイスのハードウェア障害
追加の ereport を生成したり、より特殊な診断ソフトウェアまたは eft ルールを提供したりする必要があるドライバ開発者は、C ベースの DE または eft 診断ルールセットを記述することによってこれを行えます。詳細は、OpenSolaris プロジェクトの「Fault Management community」を参照してください。
Sun イベントレジストリは、すべてのクラス名、ereport、障害、不具合、アップセット、および疑いリスト (list.suspect) イベントの集中リポジトリです。イベントレジストリには、すべてのイベントメンバーペイロードの現在の定義に加えて、内部ドキュメント、疑いリスト、辞書、ナレッジ記事など、ペイロード関連以外の重要情報も格納されます。たとえば、ereport.io と fault.io は、入出力ドライバの開発者にとって特に重要な意味を持つ基底クラス名の中の 2 つです。
FMA イベントプロトコルは、登録される個々のイベントに付随するペイロードメンバーの基本セットを定義します。開発者は、診断エンジン (または eft ルール) が疑いリストを特定の障害に絞り込むために役立つ追加のイベントを定義することもできます。
この節では次の用語を使用します。
エージェントfault.* または list.* イベントを購読する障害管理モジュールを指して使用される一般的な用語です。エージェントは、障害を起こしたリソースをリタイアさせたり、診断結果を管理者に通知したり、より上位の管理フレームワークに処理を引き継いだりするために使用されます。
ASRU は、問題をシステムから切り離して、以降のエラーレポートを抑制するために、ソフトウェアまたはハードウェアによって無効化できるリソースです。
障害管理モジュールの 1 つで、その目的は、1 つ以上の着信エラーイベントのクラスを登録することによって問題を診断し、これらのイベントを使って、システム上の各問題と関連付けられたケースを解決することです。
エラー数値関連付け (ENA) は、特定の障害領域および期間の範囲内でエラーレポートを一意に識別する符号化整数です。また ENA は、以前のエラーに対する、副次的影響としてのエラーの関係性も示します。
予期しない状況、結果、シグナル、またはデータ。エラーはシステム上の問題の兆候です。1 つ 1 つの問題から、多くの異なる種類のエラーが発生するのが一般的です。
特定のエラーに関して取り込まれるデータ。エラーレポートの形式は事前に定義されます。これは、エラーレポートに名前を付けるクラスを作成し、Sun イベントレジストリを使用してスキーマを定義することによって行います。
エラーレポートのインスタンスを表現するデータ構造。エラーイベントは名前-値ペアのリストとして表されます。
ハードウェアコンポーネントの異常な動作。
特定の障害が列挙される、ハードウェアまたはソフトウェア要素の論理区分。
プロトコルでエンコードされた障害診断のインスタンス。
1 つ以上の診断エンジンと状態管理による障害診断の役割を担うソフトウェアコンポーネント。
FMRI は URL のような識別子であり、障害管理システム内の特定リソースの正規名として機能します。個々の FMRI には、リソースの種類を識別するスキーマと、そのスキーマに固有の 1 つ以上の値が含まれています。FMRI は URL のような文字列として、または名前-値ペアのリストからなるデータ構造として表現できます。
FRU は、顧客またはサービスプロバイダが現場で交換できるリソースです。FRU はハードウェア (例: システムボード) またはソフトウェア (例: ソフトウェアパッケージ、パッチ) に対して定義できます。
次の関連資料で追加情報を提供します。