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

ドキュメントの情報

はじめに

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

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

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

3.  マルチスレッド

4.  プロパティー

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

6.  ドライバの自動構成

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

8.  割り込みハンドラ

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

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

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

12.  電源管理

13.  Oracle Solaris ドライバの強化

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

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

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

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

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

ターゲットデバイスの概要

Sun Common SCSI Architecture の概要

一般的な制御フロー

SCSA 関数

ハードウェア構成ファイル

宣言とデータ構造体

scsi_device 構造体

scsi_pkt 構造体 (ターゲットドライバ)

SCSI ターゲットドライバの自動構成

probe() エントリポイント (SCSI ターゲットドライバ)

attach() エントリポイント (SCSI ターゲットドライバ)

detach() エントリポイント (SCSI ターゲットドライバ)

getinfo() エントリポイント (SCSI ターゲットドライバ)

資源割り当て

scsi_init_pkt() 関数

scsi_sync_pkt() 関数

scsi_destroy_pkt() 関数

scsi_alloc_consistent_buf() 関数

scsi_free_consistent_buf() 関数

コマンドの構築とトランスポート

コマンドの構築

ターゲット機能の設定

コマンドのトランスポート

同期 scsi_transport() 関数

コマンドの完了

パケットの再利用

自動要求検知モード

ダンプの処理

SCSI オプション

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

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

20.  USB ドライバ

21.  SR-IOV ドライバ

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

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

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

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

パート IV 付録

A.  ハードウェアの概要

B.  Oracle Solaris DDI/DKI サービスのサマリー

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

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

E.  pci.conf ファイル

索引

ドキュメントの品質向上のためのご意見をください
簡潔すぎた
読みづらかった、または難し過ぎた
重要な情報が欠けていた
内容が間違っていた
翻訳版が必要
その他
Your rating has been updated
貴重なご意見を有り難うございました!

あなたの貴重なご意見はより良いドキュメント作成の手助けとなります 内容の品質向上と追加コメントのためのアンケートに参加されますか?

SCSI ターゲットドライバの自動構成

SCSI ターゲットドライバには、標準の自動構成ルーチン _init(9E)_fini(9E)、および _info(9E) を実装する必要があります。詳細については、「ロード可能なドライバインタフェース」を参照してください。

次のルーチンも必要ですが、これらのルーチンは特定の SCSI および SCSA の処理を実行する必要があります。

probe() エントリポイント (SCSI ターゲットドライバ)

SCSI ターゲットデバイスは自己識別しないため、ターゲットドライバが probe(9E) ルーチンを備えている必要があります。このルーチンは、予期される種類のデバイスが存在していて、応答しているかどうかを判定する必要があります。

probe(9E) ルーチンの一般的な構造とリターンコードは、ほかのデバイスドライバの構造およびリターンコードと同じです。SCSI ターゲットドライバは、probe(9E) エントリポイントで scsi_probe(9F) ルーチンを使用する必要があります。scsi_probe(9F) はデバイスに SCSI 照会コマンドを送信し、結果を示すコードを返します。SCSI 照会コマンドが成功すると、scsi_probe(9F)scsi_inquiry(9S) 構造体を割り当てて、構造体にデバイスの照会データを格納します。scsi_probe(9F) から復帰すると、scsi_device(9S) 構造体の sd_inq フィールドが、この scsi_inquiry(9S) 構造体を指します。

probe(9E) はステートレスである必要があるため、ターゲットドライバは、scsi_probe(9F) が失敗した場合でも、 probe(9E) が復帰する前に scsi_unprobe(9F) を呼び出す必要があります。

例 17-1 に、一般的な probe(9E) ルーチンを示します。この例のルーチンは、dev_info 構造体の非公開フィールドから scsi_device(9S) 構造体を取得しています。また、メッセージ内に出力するためのデバイスの SCSI ターゲットと論理ユニット番号を取得しています。probe(9E) ルーチンは次に scsi_probe(9F) を呼び出して、予期されるデバイス (この場合はプリンタ) が存在することを確認しています。

成功すると、scsi_probe(9F)scsi_inquiry(9S) 構造体内にあるデバイスの SCSI 照会データを、scsi_device(9S) 構造体の sd_inq フィールドに追加します。ドライバはその後、デバイスの種類がプリンタであるかどうかを判定できます。この情報は inq_dtype フィールドで報告されます。デバイスがプリンタである場合、scsi_dname(9F) を使用してデバイスの種類を文字列に変換し、scsi_log(9F) でその種類が報告されます。

例 17-1 SCSI ターゲットドライバの probe (9E) ルーチン

static int
xxprobe(dev_info_t *dip)
{
    struct scsi_device *sdp;
    int rval, target, lun;
    /*
     * Get a pointer to the scsi_device(9S) structure
     */
    sdp = (struct scsi_device *)ddi_get_driver_private(dip);

    target = sdp->sd_address.a_target;
    lun = sdp->sd_address.a_lun;
    /*
     * Call scsi_probe(9F) to send the Inquiry command. It will
     * fill in the sd_inq field of the scsi_device structure.
     */
    switch (scsi_probe(sdp, NULL_FUNC)) {
    case SCSIPROBE_FAILURE:
    case SCSIPROBE_NORESP:
    case SCSIPROBE_NOMEM:
        /*
         * In these cases, device might be powered off,
         * in which case we might be able to successfully
         * probe it at some future time - referred to
         * as `deferred attach'.
         */
        rval = DDI_PROBE_PARTIAL;
        break;
    case SCSIPROBE_NONCCS:
    default:
        /*
         * Device isn't of the type we can deal with,
         * and/or it will never be usable.
         */
        rval = DDI_PROBE_FAILURE;
        break;
    case SCSIPROBE_EXISTS:
        /*
         * There is a device at the target/lun address. Check
         * inq_dtype to make sure that it is the right device
         * type. See scsi_inquiry(9S)for possible device types.
         */
        switch (sdp->sd_inq->inq_dtype) {
        case DTYPE_PRINTER:
        scsi_log(sdp, "xx", SCSI_DEBUG,
            "found %s device at target%d, lun%d\n",
            scsi_dname((int)sdp->sd_inq->inq_dtype),
            target, lun);
        rval = DDI_PROBE_SUCCESS;
        break;
        case DTYPE_NOTPRESENT:
        default:
        rval = DDI_PROBE_FAILURE;
        break;     
        }    
    }
    scsi_unprobe(sdp);
    return (rval);
}

probe(9E) ルーチンをより詳細に記述すると、scsi_inquiry(9S) をチェックして、そのデバイスが特定のドライバで予期されている種類であることを確認できます。

attach() エントリポイント (SCSI ターゲットドライバ)

probe(9E) ルーチンで、予期されるデバイスが存在することを確認したら、attach(9E) が呼び出されます。attach() は次のタスクを実行します。

SCSI ターゲットドライバは scsi_probe(9F) をもう一度呼び出して、デバイスの照会データを取得する必要があります。ドライバは、SCSI 要求検知パケットを作成する必要もあります。アタッチが成功した場合、attach() 関数は scsi_unprobe(9F) を呼び出してはいけません。

要求検知パケットを作成するには、scsi_alloc_consistent_buf(9F)scsi_init_pkt(9F)、および scsi_setup_cdb(9F) の 3 つのルーチンが使用されます。scsi_alloc_consistent_buf(9F) は、変化しない DMA に適したバッファーを割り当てます。次に scsi_alloc_consistent_buf ()buf(9S) 構造体へのポインタを返します。変化しないバッファーの利点は、データを明示的に同期する必要がない点です。つまり、ターゲットドライバはコールバック後にデータにアクセスできます。検知バッファーのアドレスを使用して、デバイスの scsi_device(9S) 構造体の sd_sense 要素を初期化する必要があります。scsi_init_pkt(9F)scsi_pkt(9S) 構造体を作成し、部分的に初期化します。scsi_setup_cdb(9F) は SCSI コマンド記述子ブロックを作成します。この場合は、SCSI 要求検知コマンドを作成することで、それを行っています。

SCSI デバイスは自己識別しないため、reg プロパティーを持っていないことに注意してください。結果として、ドライバで pm-hardware-state プロパティーを設定する必要が生じます。pm-hardware-state を設定することで、このデバイスは一時停止してから再開する必要があることをフレームワークに通知します。

次の例では、SCSI ターゲットドライバの attach() ルーチンを示します。

例 17-2 SCSI ターゲットドライバの attach (9E) ルーチン

static int
xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
    struct xxstate         *xsp;
    struct scsi_pkt        *rqpkt = NULL;
    struct scsi_device     *sdp;
    struct buf         *bp = NULL;
    int            instance;
    instance = ddi_get_instance(dip);
    switch (cmd) {
      case DDI_ATTACH:
          break;
      case DDI_RESUME:
          /* For information, see the "Directory Memory Access (DMA)" */
          /* chapter in this book. */
      default:
          return (DDI_FAILURE);
    }
    /*
     * Allocate a state structure and initialize it.
     */
    xsp = ddi_get_soft_state(statep, instance);
    sdp = (struct scsi_device *)ddi_get_driver_private(dip);
    /*
     * Cross-link the state and scsi_device(9S) structures.
     */
    sdp->sd_private = (caddr_t)xsp;
    xsp->sdp = sdp;
    /*
     * Call scsi_probe(9F) again to get and validate inquiry data.
     * Allocate a request sense buffer. The buf(9S) structure
     * is set to NULL to tell the routine to allocate a new one.
     * The callback function is set to NULL_FUNC to tell the
     * routine to return failure immediately if no
     * resources are available.
     */
    bp = scsi_alloc_consistent_buf(&sdp->sd_address, NULL,
    SENSE_LENGTH, B_READ, NULL_FUNC, NULL);
    if (bp == NULL)
        goto failed;
    /*
     * Create a Request Sense scsi_pkt(9S) structure.
     */
    rqpkt = scsi_init_pkt(&sdp->sd_address, NULL, bp,
    CDB_GROUP0, 1, 0, PKT_CONSISTENT, NULL_FUNC, NULL);
    if (rqpkt == NULL)
        goto failed;
    /*
     * scsi_alloc_consistent_buf(9F) returned a buf(9S) structure.
     * The actual buffer address is in b_un.b_addr.
     */
    sdp->sd_sense = (struct scsi_extended_sense *)bp->b_un.b_addr;
    /*
     * Create a Group0 CDB for the Request Sense command
     */
    if (scsi_setup_cdb((union scsi_cdb *)rqpkt->pkt_cdbp,
        SCMD_REQUEST_SENSE, 0, SENSE__LENGTH, 0) == 0)
        goto failed;;
    /*
     * Fill in the rest of the scsi_pkt structure.
     * xxcallback() is the private command completion routine.
     */
    rqpkt->pkt_comp = xxcallback;
    rqpkt->pkt_time = 30; /* 30 second command timeout */
    rqpkt->pkt_flags |= FLAG_SENSING;
    xsp->rqs = rqpkt;
    xsp->rqsbuf = bp;
    /*
     * Create minor nodes, report device, and do any other initialization. */
     * Since the device does not have the 'reg' property,
     * cpr will not call its DDI_SUSPEND/DDI_RESUME entries.
     * The following code is to tell cpr that this device
     * needs to be suspended and resumed.
     */
    (void) ddi_prop_update_string(device, dip,
        "pm-hardware-state", "needs-suspend-resume");
    xsp->open = 0;
    return (DDI_SUCCESS);
failed:
    if (bp)
        scsi_free_consistent_buf(bp);
    if (rqpkt)
        scsi_destroy_pkt(rqpkt);
    sdp->sd_private = (caddr_t)NULL;
    sdp->sd_sense = NULL;
    scsi_unprobe(sdp);
    /* Free any other resources, such as the state structure. */
    return (DDI_FAILURE);
}

detach() エントリポイント (SCSI ターゲットドライバ)

detach(9E) エントリポイントは、attach(9E) の逆の操作を行うものです。detach() では、attach () で割り当てられたすべての資源を解放する必要があります。成功した場合、detach は scsi_unprobe(9F) を呼び出す必要があります。次の例では、ターゲットドライバの detach() ルーチンを示します。

例 17-3 SCSI ターゲットドライバの detach (9E) ルーチン

static int
xxdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
    struct xxstate *xsp;
    switch (cmd) {
      case DDI_DETACH:
          /*
           * Normal detach(9E) operations, such as getting a
           * pointer to the state structure
           */
          scsi_free_consistent_buf(xsp->rqsbuf);
          scsi_destroy_pkt(xsp->rqs);
          xsp->sdp->sd_private = (caddr_t)NULL;
          xsp->sdp->sd_sense = NULL;
          scsi_unprobe(xsp->sdp);
          /*
           * Remove minor nodes.
           * Free resources, such as the state structure and properties.
           */
          return (DDI_SUCCESS);
      case DDI_SUSPEND:
          /* For information, see the "Directory Memory Access (DMA)" */
          /* chapter in this book. */
      default:
          return (DDI_FAILURE);
    }
}

getinfo() エントリポイント (SCSI ターゲットドライバ)

SCSI ターゲットドライバの getinfo(9E) ルーチンは、ほかのドライバとほぼ同じです (DDI_INFO_DEVT2INSTANCE の場合の詳細については getinfo() エントリポイント」を参照してください)。ただし、getinfo() ルーチンの DDI_INFO_DEVT2DEVINFO の場合、ターゲットドライバは dev_info ノードへのポインタを返す必要があります。このポインタは、ドライバの状態構造体に保存することも、scsi_device(9S) 構造体の sd_dev フィールドから取得することもできます。次の例は、代替の SCSI ターゲットドライバの getinfo() コードフラグメントを示しています。

例 17-4 代替 SCSI ターゲットドライバの getinfo() コードフラグメント

case DDI_INFO_DEVT2DEVINFO:
    dev = (dev_t)arg;
    instance = getminor(dev);
    xsp = ddi_get_soft_state(statep, instance);
    if (xsp == NULL)
        return (DDI_FAILURE);
    *result = (void *)xsp->sdp->sd_dev;
    return (DDI_SUCCESS);