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 ドライバの強化

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

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

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

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

ブロックドライバの構造の概要

ファイル入出力

ブロックデバイスの自動設定

デバイスアクセスの制御

open() エントリポイント (ブロックドライバ)

close() エントリポイント (ブロックドライバ)

strategy() エントリポイント

buf 構造体

bp_mapin 構造体

同期データ転送 (ブロックドライバ)

非同期データ転送 (ブロックドライバ)

無効な buf 要求のチェック

要求のキューへの入力

最初の転送の開始

割り込んでいるデバイスの処理

dump() エントリポイントと print() エントリポイント

dump() エントリポイント (ブロックドライバ)

print() エントリポイント (ブロックドライバ)

ディスク装置ドライバ

ディスクの ioctl

ディスクパフォーマンス

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

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

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

20.  USB ドライバ

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

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

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

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

パート IV 付録

A.  ハードウェアの概要

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

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

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

索引

デバイスアクセスの制御

ここでは、ブロックデバイスドライバ内の open() 関数と close() 関数のエントリポイントについて説明します。open(9E)close(9E) の詳細については、第 15 章文字デバイスのドライバを参照してください。

open() エントリポイント (ブロックドライバ)

open(9E) エントリポイントは、指定されたデバイスへのアクセスを取得するために使用されます。ブロックドライバの open(9E) ルーチンは、ユーザースレッドがマイナーデバイスに関連付けられたブロック型特殊ファイルに対して open(2) または mount(2) システムコールを発行したとき、または階層化ドライバが open(9E) を呼び出したときに呼び出されます。詳細については、「ファイル入出力」を参照してください。

open() エントリポイントは、次の条件を確認します。

次の例は、ブロックドライバの open(9E) エントリポイントを示しています。

例 16-2 ブロックドライバの open(9E) ルーチン

static int
xxopen(dev_t *devp, int flags, int otyp, cred_t *credp)
{
       minor_t         instance;
       struct xxstate        *xsp;

     instance = getminor(*devp);
     xsp = ddi_get_soft_state(statep, instance);
     if (xsp == NULL)
           return (ENXIO);
     mutex_enter(&xsp->mu);
     /*
    * only honor FEXCL. If a regular open or a layered open
    * is still outstanding on the device, the exclusive open
    * must fail.
    */
     if ((flags & FEXCL) && (xsp->open || xsp->nlayered)) {
       mutex_exit(&xsp->mu);
       return (EAGAIN);
     }
     switch (otyp) {
       case OTYP_LYR:
         xsp->nlayered++;
         break;
      case OTYP_BLK:
         xsp->open = 1;
         break;
     default:
         mutex_exit(&xsp->mu);
         return (EINVAL);
     }
   mutex_exit(&xsp->mu);
      return (0);
}

otyp 引数は、デバイスに対するオープンのタイプを指定するために使用されます。OTYP_BLK は、ブロックデバイスの標準的なオープンのタイプです。otypOTYP_BLK に設定されている場合は、デバイスを複数回開くことができます。close(9E) は、デバイスに対するタイプ OTYP_BLK の最後のクローズが実行されるときに 1 回だけ呼び出されます。デバイスが階層化デバイスとして使用されている場合、otypOTYP_LYR に設定されます。階層化ドライバは、タイプ OTYP_LYR のすべてのオープンに対してタイプ OTYP_LYR の対応するクローズを発行します。この例ではオープンの各タイプを常時監視しているため、ドライバはデバイスがいつ close(9E) で使用されていないかを判定できます。

close() エントリポイント (ブロックドライバ)

close(9E) エントリポイントは、1 つの例外を除いて open(9E) と同じ引数を使用します。dev はデバイス番号であり、デバイス番号へのポインタではありません。

close() ルーチンは、open(9E) エントリポイントについての説明と同じ方法で otyp を確認します。次の例では、close() は、実際にデバイスをいつ閉じることができるかを判定する必要があります。閉じる操作は、ブロックのオープンと階層化されたオープンの数によって影響を受けます。

例 16-3 ブロックデバイスの close(9E) ルーチン

static int
xxclose(dev_t dev, int flag, int otyp, cred_t *credp)
{
     minor_t instance;
     struct xxstate *xsp;

     instance = getminor(dev);
     xsp = ddi_get_soft_state(statep, instance);
       if (xsp == NULL)
          return (ENXIO);
     mutex_enter(&xsp->mu);
     switch (otyp) {
       case OTYP_LYR:
       xsp->nlayered--;
       break;
      case OTYP_BLK:
       xsp->open = 0;
       break;
     default:
       mutex_exit(&xsp->mu);
       return (EINVAL);
       }

     if (xsp->open || xsp->nlayered) {
       /* not done yet */
       mutex_exit(&xsp->mu);
       return (0);
     }
       /* cleanup (rewind tape, free memory, etc.) */
   /* wait for I/O to drain */
     mutex_exit(&xsp->mu);

     return (0);
}

strategy() エントリポイント

strategy(9E) エントリポイントは、ブロックデバイスとの間でのデータバッファーの読み取りと書き込みのために使用されます。strategy という名前は、このエントリポイントによって、デバイスへの要求を順序付けるための何らかの最適な方針が実装される可能性がある点を指しています。

strategy(9E) は、一度に 1 つの要求を処理する、つまり、同期転送を行うように記述できます。strategy() はまた、非同期転送のように、デバイスへの複数の要求をキューに入れるように記述することもできます。これらの方法を選択する場合は、デバイスの機能や制限事項を考慮に入れるべきです。

strategy(9E) ルーチンには、buf(9S) 構造体へのポインタが渡されます。この構造体には転送要求を記述しますが、復帰したときには状態情報が含まれています。buf(9S)strategy(9E) が、ブロックデバイス操作の焦点です。

buf 構造体

ブロックドライバには、次の buf 構造体メンバーが重要です。

int           b_flags;       /* Buffer status */
struct buf    *av_forw;      /* Driver work list link */
struct buf    *av_back;      /* Driver work list link */
size_t        b_bcount;      /* # of bytes to transfer */
union {
    caddr_t   b_addr;        /* Buffer's virtual address */
} b_un;
daddr_t       b_blkno;       /* Block number on device */
diskaddr_t    b_lblkno;      /* Expanded block number on device */
size_t        b_resid;       /* # of bytes not transferred after error */
int           b_error;       /* Expanded error field */
void          *b_private;    /* "opaque" driver private area */
dev_t         b_edev;        /* expanded dev field */

各表記の意味は次のとおりです。

av_forwav_back

ドライバでバッファーのリストを管理するためにドライバが使用できるポインタ。av_forw ポインタと av_back ポインタの説明については、「非同期データ転送 (ブロックドライバ)」を参照してください。

b_bcount

デバイスによって転送されるバイト数を指定します。

b_un.b_addr

データバッファーのカーネル仮想アドレス。bp_mapin(9F) の呼び出しのあとでのみ有効です。

b_blkno

512 バイトの DEV_BSIZE の単位で表された、データ転送用にデバイス上に存在する、先頭の 32 ビット論理ブロック番号。ドライバは、b_blknob_lblkno の両方ではなく、このどちらかを使用します。

b_lblkno

512 バイトの DEV_BSIZE の単位で表された、データ転送用にデバイス上に存在する、先頭の 64 ビット論理ブロック番号。ドライバは、b_blknob_lblkno の両方ではなく、このどちらかを使用します。

b_resid

エラーのために転送されなかったバイト数を示すためにドライバによって設定されます。b_resid の設定の例については、例 16-7 を参照してください。b_resid メンバーはオーバーロードされます。b_resid はまた、disksort(9F) によっても使用されます。

b_error

転送エラーが発生した場合、ドライバによってエラー番号が設定されます。b_error は、b_flagsB_ERROR ビットとともに設定されます。エラー値の詳細については、Intro(9E) のマニュアルページを参照してください。ドライバは、b_error を直接設定するのではなく、bioerror(9F) を使用します。

b_flags

buf 構造体の状態と転送の属性を含むフラグ。B_READ が設定されている場合、buf 構造体は、デバイスからメモリーへの転送を示します。それ以外の場合、この構造体はメモリーからデバイスへの転送を示します。データ転送中にドライバでエラーが発生した場合、ドライバは、b_flags メンバーの B_ERROR フィールドを設定します。さらに、ドライバは、b_error でより具体的なエラー値を提供します。ドライバは、B_ERROR を設定するのではなく、bioerror(9F) を使用します。


注意

注意 - ドライバが b_flags をクリアしないようにしてください。


b_private

ドライバの非公開データを格納するために、ドライバによって排他的に使用されます。

b_edev

転送で使用されたデバイスのデバイス番号が含まれています。

bp_mapin 構造体

デバイスドライバの strategy(9E) ルーチンには、buf 構造体ポインタを渡すことができます。ただし、b_un.b_addr によって参照されるデータバッファーは、必ずしもカーネルのアドレス空間内にマッピングされるわけではありません。そのため、ドライバはデータに直接アクセスできません。ほとんどのブロック指向のデバイスは DMA 機能を備えているため、データバッファーに直接アクセスする必要はありません。代わりに、これらのデバイスは DMA マッピングルーチンを使用して、そのデバイスの DMA エンジンがデータ転送を実行できるようにします。DMA の使用の詳細については、第 9 章ダイレクトメモリーアクセス (DMA)を参照してください。

ドライバがデータバッファーに直接アクセスする必要がある場合、そのドライバはまず、bp_mapin(9F) を使用してそのバッファーをカーネルのアドレス空間内にマッピングする必要があります。ドライバがそのデータに直接アクセスする必要がなくなった場合は、bp_mapout(9F) を使用するべきです。


注意

注意 - bp_mapout(9F) は、そのデバイスドライバによって割り当てられ、かつ所有されているバッファーに対してのみ呼び出すべきです。ファイルシステムなどの、strategy(9E) エントリポイントを介してドライバに渡されたバッファーに対しては bp_mapout() を呼び出してはいけません。bp_mapin(9F) は参照カウントを保持しません。bp_mapout(9F) は、デバイスドライバ上のレイヤーが依存している可能性のあるカーネルマッピングをすべて削除します。