JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
デバイスドライバの記述     Oracle Solaris 10 8/11 Information Library (日本語)
search filter icon
search icon

ドキュメントの情報

はじめに

パート I Solaris プラットフォーム用デバイスドライバの設計

1.  Solaris デバイスドライバの概要

2.  Solaris カーネルとデバイスツリー

3.  マルチスレッド

4.  プロパティー

5.  イベントの管理とタスクのキュー

6.  ドライバの自動設定

7.  デバイスアクセス: プログラム式入出力

8.  割り込みハンドラ

9.  ダイレクトメモリーアクセス (DMA)

10.  デバイスメモリーおよびカーネルメモリーのマッピング

11.  デバイスコンテキスト管理

12.  電源管理

13.  Solaris ドライバの強化

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

予測的自己修復とは

Solaris Fault Manager

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

応答エージェント

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

システムトポロジ

エラー処理

障害管理機能の宣言

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

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

エラーの報告

アクセス属性構造体

DMA 属性構造体

エラー状態の取得

エラーのクリア

エラーハンドラの登録

障害管理のデータおよび状態の構造体

障害の診断

標準リーフデバイス診断

特殊なデバイス診断

イベントレジストリ

用語集

関連資料

Solaris デバイスドライバの防御的プログラミング手法

別個のデバイスドライバインスタンスの使用

DDI アクセスハンドルの排他的使用

破壊されたデータの検出

デバイス管理データおよび制御データの破壊

受信データの破壊

DMA 遮断

問題のある割り込みの処理

プログラミングのその他の考慮事項

スレッドの対話

トップダウン要求の脅威

適応型戦略

ドライバ強化テストハーネス

障害投入

テストハーネスの設定

テストハーネスのインストール

テストハーネスの設定

ドライバのテスト

障害の作成

障害の投入

障害投入プロセス

テストハーネスの警告

スクリプトによるテストプロセスの自動化

自動テストプロセス

14.  階層化ドライバインタフェース (LDI)

パート II 特定の種類のデバイスドライバの設計

15.  文字デバイスのドライバ

16.  ブロックデバイスのドライバ

17.  SCSI ターゲットドライバ

18.  SCSI ホストバスアダプタドライバ

19.  ネットワークデバイスのドライバ

20.  USB ドライバ

パート III デバイスドライバの構築

21.  ドライバのコンパイル、ロード、パッケージ化、およびテスト

22.  デバイスドライバのデバッグ、テスト、およびチューニング

23.  推奨されるコーティング方法

パート IV 付録

A.  ハードウェアの概要

B.  Solaris DDI/DKI サービスの概要

C.  64 ビットデバイスドライバの準備

D.  コンソールフレームバッファードライバ

索引

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

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

この節の内容は次のとおりです。

予測的自己修復とは

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

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

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

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

Solaris Fault Manager

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

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

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

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

たとえば、特定のメモリー位置に関して一定時間内に一定数の訂正可能 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
-------- ----------------------------------------------------------------------

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

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

メッセージ 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://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 ドライバのコード全体を入手するには、次の手順に従います。

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_init(9F) から戻る前に、一連の障害管理機能プロパティー (fm-ereport-capablefm-accchk-capablefm-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) ルールとともに 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 関連エラーの検出と報告

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 イベントレジストリで定義されている必要があります。

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 ドライバのコードを入手するには、次の手順に従います。

  • OpenSolaris プロジェクトのサイトに移動します。

  • ページの右上隅にある「Source Browser」をクリックします。

  • 「File Path」フィールドに nxge と入力します。

  • 「Search」ボタンをクリックします。

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

障害管理機能を備えたドライバは、デバイスによって提供されるサービスにエラーが影響を及ぼしたかどうかを示す必要があります。エラーの検出 (および、必要に応じたサービスのシャットダウン) 後に、ドライバが 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 が生成されます。

次に示す 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_DEFAULT_ACC

このフラグは、エラーが発生したときにシステムがデフォルトのアクション (必要であればパニック状態に移行) を実行することを示します。この属性は DDI_FM_ACCCHK_CAPABLE ドライバでは使用できません。

DDI_FLAGERR_ACC

このフラグは、アクセスハンドルと関連付けられたエラーの処理およびエラーからの回復をシステムが試みることを示します。ドライバでは、「Solaris デバイスドライバの防御的プログラミング手法」で説明されている手法を使用し、呼び出し側アプリケーションにデータを返却することをドライバで許可する前に ddi_fm_acc_err_get(9F) を使用して定期的にエラーをチェックするようにしてください。

DDI_FLAGERR_ACC フラグを指定すると、次のことが可能になります。

  • ドライバコールバックを介したエラー通知

  • 次の関数によるエラー条件の監視: ddi_fm_acc_err_get(9F)

DDI_CAUTIOUS_ACC

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 に設定する必要があります。

DMA 属性構造体

アクセスハンドル設定と同様に、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 を使用すると、次のことが可能になります。

エラー状態の取得

障害が発生し、ハンドルによって対応づけられたリソースにその影響が及ぶ場合、バスによる、または入出力データパス上のその他のデバイスドライバによるエラー処理中に取り込まれたエラー情報を反映して、エラー状態構造体が

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) エントリポイントで呼び出されるようにしてください。

エラーハンドラのコールバック関数は次の処理を実行する必要があります。

ドライバのエラーハンドラは次の情報を受け取ります。

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 ハンドルです。

fme_ena

このフィールドは呼び出し側の親ネクサスによって初期化され、ドライバの登録済みコールバックルーチンに到達する前に、エラー処理伝播チェーンの途中で増分されている可能性があります。ドライバが独自に関連エラーを検出した場合、ddi_fm_ereport_post() を呼び出す前にドライバでこの ENA を増分してください。

fme_acc_handlefme_dma_handle

親のレベルで検出されたエラーを、デバイスドライバによって対応づけまたはバインドされたハンドルに親が関連付けることができた場合、これらのフィールドには有効なアクセスハンドルまたは DMA ハンドルが格納されています。

fme_flag

DDI_CAUTIOUS_ACC 保護操作の結果としてエラーが発生したと呼び出し側の親が判断した場合、fme_flag フラグは DDI_FM_ERR_EXPECTED に設定されます。この場合、fme_acc_handle は有効であり、ドライバでは DDI_CAUTIOUS_ACC 保護操作と関連付けられていないエラーのみをチェックして報告するようにしてください。それ以外の場合、fme_flag は DDI_FM_ERR_UNEXPECTED に設定され、ドライバはすべての範囲のエラー処理タスクを実行する必要があります。

fme_status

そのエラーハンドルコールバックから戻るときに、ドライバは 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 の検出および生成により、次のフォルトイベントが生成されます。

fault.io.pci.bus-linkerr

PCI バス上のハードウェア障害

fault.io.pci.device-interr

デバイス内部のハードウェア障害

fault.io.pci.device-invreq

デバイスが無効な要求を送信する原因である、デバイスのハードウェア障害またはドライバの不具合

fault.io.pci.device-noresp

ドライバが有効な要求に応答しない原因である、デバイスのハードウェア障害

fault.io.pciex.bus-linkerr

リンク上のハードウェア障害

fault.io.pciex.bus-noresp

リンクがダウンしているためデバイスが有効な要求に応答できない

fault.io.pciex.device-interr

デバイス内部のハードウェア障害

fault.io.pciex.device-invreq

デバイスが無効な要求を送信する原因である、デバイスのハードウェア障害またはドライバの不具合

fault.io.pciex.device-noresp

有効な要求に応答しない原因である、デバイスのハードウェア障害

特殊なデバイス診断

追加の ereport を生成したり、より特殊な診断ソフトウェアまたは eft ルールを提供したりする必要があるドライバ開発者は、C ベースの DE または eft 診断ルールセットを記述することによってこれを行えます。詳細は、OpenSolaris プロジェクトの「Fault Management community」を参照してください。

イベントレジストリ

Sun イベントレジストリは、すべてのクラス名、ereport、障害、不具合、アップセット、および疑いリスト (list.suspect) イベントの集中リポジトリです。イベントレジストリには、すべてのイベントメンバーペイロードの現在の定義に加えて、内部ドキュメント、疑いリスト、辞書、ナレッジ記事など、ペイロード関連以外の重要情報も格納されます。たとえば、ereport.iofault.io は、入出力ドライバの開発者にとって特に重要な意味を持つ基底クラス名の中の 2 つです。

FMA イベントプロトコルは、登録される個々のイベントに付随するペイロードメンバーの基本セットを定義します。開発者は、診断エンジン (または eft ルール) が疑いリストを特定の障害に絞り込むために役立つ追加のイベントを定義することもできます。

用語集

この節では次の用語を使用します。

エージェント

fault.* または list.* イベントを購読する障害管理モジュールを指して使用される一般的な用語です。エージェントは、障害を起こしたリソースをリタイアさせたり、診断結果を管理者に通知したり、より上位の管理フレームワークに処理を引き継いだりするために使用されます。

ASRU (自動システム再構成ユニット)

ASRU は、問題をシステムから切り離して、以降のエラーレポートを抑制するために、ソフトウェアまたはハードウェアによって無効化できるリソースです。

DE (診断エンジン)

障害管理モジュールの 1 つで、その目的は、1 つ以上の着信エラーイベントのクラスを登録することによって問題を診断し、これらのイベントを使って、システム上の各問題と関連付けられたケースを解決することです。

ENA (エラー数値関連付け)

エラー数値関連付け (ENA) は、特定の障害領域および期間の範囲内でエラーレポートを一意に識別する符号化整数です。また ENA は、以前のエラーに対する、副次的影響としてのエラーの関係性も示します。

エラー

予期しない状況、結果、シグナル、またはデータ。エラーはシステム上の問題の兆候です。1 つ 1 つの問題から、多くの異なる種類のエラーが発生するのが一般的です。

ereport (エラーレポート)

特定のエラーに関して取り込まれるデータ。エラーレポートの形式は事前に定義されます。これは、エラーレポートに名前を付けるクラスを作成し、Sun イベントレジストリを使用してスキーマを定義することによって行います。

ereport イベント (エラーイベント)

エラーレポートのインスタンスを表現するデータ構造。エラーイベントは名前-値ペアのリストとして表されます。

障害

ハードウェアコンポーネントの異常な動作。

障害境界

特定の障害が列挙される、ハードウェアまたはソフトウェア要素の論理区分。

フォルトイベント

プロトコルでエンコードされた障害診断のインスタンス。

Fault Manager

1 つ以上の診断エンジンと状態管理による障害診断の役割を担うソフトウェアコンポーネント。

FMRI (障害管理対象リソース識別子)

FMRI は URL のような識別子であり、障害管理システム内の特定リソースの正規名として機能します。個々の FMRI には、リソースの種類を識別するスキーマと、そのスキーマに固有の 1 つ以上の値が含まれています。FMRI は URL のような文字列として、または名前-値ペアのリストからなるデータ構造として表現できます。

FRU (現場交換可能ユニット)

FRU は、顧客またはサービスプロバイダが現場で交換できるリソースです。FRU はハードウェア (例: システムボード) またはソフトウェア (例: ソフトウェアパッケージ、パッチ) に対して定義できます。

関連資料

次の関連資料で追加情報を提供します。