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 ターゲットドライバ

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

ホストバスアダプタドライバの概要

SCSI インタフェース

SCSA HBA インタフェース

SCSA HBA エントリポイントのサマリー

SCSA HBA データ構造体

scsi_hba_tran() 構造体

scsi_address 構造体

scsi_device 構造体

scsi_pkt 構造体 (HBA)

ターゲットインスタンスごとのデータ

トランスポート構造体の複製

SCSA HBA 関数

HBA ドライバの依存性と構成に関する問題

宣言と構造体

コマンド別構造体

モジュール初期化用のエントリポイント

_init() エントリポイント (SCSI HBA ドライバ)

_fini() エントリポイント (SCSI HBA ドライバ)

自動構成のエントリポイント

attach() エントリポイント (SCSI HBA ドライバ)

detach() エントリポイント (SCSI HBA ドライバ)

SCSA HBA ドライバのエントリポイント

ターゲットドライバインスタンスの初期化

tran_tgt_init() エントリポイント

tran_tgt_probe() エントリポイント

tran_tgt_free() エントリポイント

資源割り当て

tran_init_pkt() エントリポイント

scsi_pkt(9S) 構造体の割り当てと初期化

DMA 資源の割り当て

データ転送のための DMA 資源の再割り当て

tran_destroy_pkt() エントリポイント

tran_sync_pkt() エントリポイント

tran_dmafree() エントリポイント

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

tran_start() エントリポイント

割り込みハンドラとコマンドの完了

タイムアウトハンドラ

機能管理

tran_getcap() エントリポイント

tran_setcap() エントリポイント

中止およびリセット管理

tran_abort() エントリポイント

tran_reset() エントリポイント

tran_bus_reset() エントリポイント

tran_reset_notify() エントリポイント

動的再構成 (DR)

SCSI HBA ドライバに固有の問題

HBA ドライバのインストール

HBA の構成プロパティー

scsi-reset-delay プロパティー

scsi-options プロパティー

ターゲットごとの scsi-options

x86 ターゲットドライバの構成プロパティー

キューイングのサポート

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
貴重なご意見を有り難うございました!

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

HBA ドライバの依存性と構成に関する問題

開発者は、SCSA HBA のエントリポイント、構造体、および関数をドライバに組み込むだけでなく、ドライバの依存性と構成に関する問題にも対処する必要があります。これらの問題は、構成プロパティー、依存性宣言、状態構造体とコマンド別構造体、モジュール初期化用のエントリポイント、および自動構成エントリポイントに関係しています。

宣言と構造体

HBA ドライバには、次のヘッダーファイルを含める必要があります。

#include <sys/scsi/scsi.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>

モジュールが SCSA ルーチンに依存していることをシステムに通知するには、次のコマンドを使用してドライバのバイナリを生成する必要があります。SCSA ルーチンの詳細については、「SCSA HBA インタフェース」を参照してください。

% ld -r xx.o -o xx -N "misc/scsi"

サンプルコードは、QLogic Intelligent SCSI Peripheral デバイス用の簡略化された isp ドライバから入手できます。isp ドライバは、最大 15 台のターゲットデバイスを接続可能で、1 つのターゲットに 8 台までの論理ユニット (LUN) を接続できるワイド SCSI をサポートしています。

コマンド別構造体

HBA ドライバは通常、ターゲットドライバが実行するコマンドごとに状態を保持する構造体を定義する必要があります。このコマンド別構造体のレイアウトは、デバイスドライバの作成者がすべて管理します。レイアウトに必要なのは、ドライバで使用されるハードウェアの機能とソフトウェアのアルゴリズムを反映させることです。

コマンド別構造体の例を次に示します。この章の残りのコードフラグメントは、この構造体を使って HBA インタフェースを示しています。

struct isp_cmd {
     struct isp_request     cmd_isp_request;
     struct isp_response    cmd_isp_response;
     struct scsi_pkt        *cmd_pkt;
     struct isp_cmd         *cmd_forw;
     uint32_t               cmd_dmacount;
     ddi_dma_handle_t       cmd_dmahandle;
     uint_t                 cmd_cookie;
     uint_t                 cmd_ncookies;
     uint_t                 cmd_cookiecnt;
     uint_t                 cmd_nwin;
     uint_t                 cmd_curwin;
     off_t                  cmd_dma_offset;
     uint_t                 cmd_dma_len;
     ddi_dma_cookie_t       cmd_dmacookies[ISP_NDATASEGS];
     u_int                  cmd_flags;
     u_short                cmd_slot;
     u_int                  cmd_cdblen;
     u_int                  cmd_scblen;
 };

モジュール初期化用のエントリポイント

このセクションでは、SCSI HBA ドライバによって実行される操作のエントリポイントについて説明します。

次の SCSI HBA ドライバ用のコードは、代表的な dev_ops(9S) 構造体を示しています。ドライバは、この構造体の devo_bus_ops フィールドを NULL に初期化する必要があります。SCSI HBA ドライバは、特別な目的でリーフドライバインタフェースを提供することがあります。その場合、devo_cb_ops フィールドは cb_ops(9S) 構造体を指すことがあります。この例では、リーフドライバインタフェースはエクスポートされないため、devo_cb_ops フィールドは NULL に初期化されます。

_init() エントリポイント (SCSI HBA ドライバ)

_init(9E) 関数は、ロード可能なモジュールを初期化します。_init() は、ロード可能なモジュール内のほかのすべてのルーチンの前に呼び出されます。

SCSI HBA では、_init() 関数は、mod_install(9F) を呼び出す前に、scsi_hba_init(9F) を呼び出して、HBA ドライバの存在をフレームワークに通知する必要があります。scsi_hba__init() ルーチンがゼロ以外の値を返す場合、_init() はこの値を返します。それ以外の場合、_init()mod_install(9F) によって返された値を返す必要があります。

ドライバは、mod_install(9F) を呼び出す前に、必要なグローバル状態を初期化します。

mod_install() が失敗した場合、_init() 関数は割り当てられているグローバル資源をすべて解放する必要があります。_init() は、復帰する前に scsi_hba_fini(9F) を呼び出す必要があります。

次の例では、グローバルな mutex を使用して、ドライバのすべてのインスタンスにグローバルなデータの割り当て方法を示しています。このコードでは、グローバルな mutex とソフト状態構造体の情報を宣言しています。グローバルな mutex とソフト状態は、_init() の実行中に初期化されます。

_fini() エントリポイント (SCSI HBA ドライバ)

_fini(9E) 関数は、システムが SCSI HBA ドライバをアンロードしようとするときに呼び出されます。_fini() 関数は、mod_remove(9F) を呼び出して、ドライバがアンロード可能かどうかを判定する必要があります。mod_remove() が 0 を返した場合、このモジュールはアンロード可能です。HBA ドライバは、_init(9E) で割り当てられたグローバル資源をすべて解放する必要があります。また、scsi_hba_fini(9F) も呼び出す必要があります。

_fini() は、mod_remove() によって返された値を返す必要があります。


注 - HBA ドライバは、mod_remove(9F) が 0 を返さないかぎり、資源を解放したり、scsi_hba_fini(9F) を呼び出したりすることはできません。


例 18-1 は、SCSI HBA 用のモジュールの初期化を示しています。

例 18-1 SCSI HBA 用のモジュールの初期化

static struct dev_ops isp_dev_ops = {
    DEVO_REV,       /* devo_rev */
    0,              /* refcnt  */
    isp_getinfo,    /* getinfo */
    nulldev,        /* identify */
    nulldev,        /* probe */
    isp_attach,     /* attach */
    isp_detach,     /* detach */
    nodev,          /* reset */
    NULL,           /* driver operations */
    NULL,           /* bus operations */
    isp_power,      /* power management */
    isp_quiesce,    /* quiesce */
};

/*
 * Local static data
 */
static kmutex_t      isp_global_mutex;
static void          *isp_state;

int
_init(void)
{
    int     err;
    
    if ((err = ddi_soft_state_init(&isp_state,
        sizeof (struct isp), 0)) != 0) {
        return (err);
    }
    if ((err = scsi_hba_init(&modlinkage)) == 0) {
        mutex_init(&isp_global_mutex, "isp global mutex",
        MUTEX_DRIVER, NULL);
        if ((err = mod_install(&modlinkage)) != 0) {
            mutex_destroy(&isp_global_mutex);
            scsi_hba_fini(&modlinkage);
            ddi_soft_state_fini(&isp_state);    
        }
    }
    return (err);
}

int
_fini(void)
{
    int     err;
    
    if ((err = mod_remove(&modlinkage)) == 0) {
        mutex_destroy(&isp_global_mutex);
        scsi_hba_fini(&modlinkage);
        ddi_soft_state_fini(&isp_state);
    }
    return (err);
}

自動構成のエントリポイント

各デバイスドライバには dev_ops(9S) 構造体が関連付けられています。この構造体により、カーネルはドライバの自動構成エントリポイントを見つけることができます。これらの自動構成ルーチンについては、第 6 章ドライバの自動構成に詳しく説明されています。このセクションでは、そのようなエントリポイントのうち、SCSI HBA ドライバで実行される操作に関連付けられたものについてのみ説明します。このようなエントリポイントには、attach(9E)detach(9E) があります。

attach() エントリポイント (SCSI HBA ドライバ)

SCSI HBA ドライバの attach(9E) エントリポイントは、デバイスに対してこのドライバのインスタンスを構成および接続するときにいくつかのタスクを実行します。実際のデバイスの一般的なドライバでは、次のオペレーティングシステムとハードウェアに関する問題に対処する必要があります。

ソフト状態構造体

デバイスインスタンスごとのソフト状態構造体を割り当てる際にエラーが発生した場合、ドライバは慎重にクリーンアップを行う必要があります。

DMA

HBA ドライバは、ddi_dma_attr_t 構造体を正しく初期化することで、その DMA エンジンの属性を記述する必要があります。

static ddi_dma_attr_t isp_dma_attr = {
     DMA_ATTR_V0,        /* ddi_dma_attr version */
     0,                  /* low address */
     0xffffffff,         /* high address */
     0x00ffffff,         /* counter upper bound */
     1,                  /* alignment requirements */
     0x3f,               /* burst sizes */
     1,                  /* minimum DMA access */
     0xffffffff,         /* maximum DMA access */
     (1<<24)-1,          /* segment boundary restrictions */
     1,                  /* scatter-gather list length */
     512,                /* device granularity */
     0                   /* DMA flags */
};

また、DMA を提供する場合は、そのハードウェアが DMA 対応スロットに取り付けられていることも確認するべきです。

if (ddi_slaveonly(dip) == DDI_SUCCESS) {
    return (DDI_FAILURE);
}
トランスポート構造体

HBA ドライバは、このインスタンスにさらにトランスポート構造体を割り当て、初期化します。tran_hba_private フィールドは、このインスタンスのソフト状態構造体を指すように設定します。特別なプローブカスタマイズが必要ない場合は、tran_tgt_probe フィールドを NULL に設定して、デフォルトの動作を実行できます。

tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);

isp->isp_tran                   = tran;
isp->isp_dip                    = dip;

tran->tran_hba_private          = isp;
tran->tran_tgt_private          = NULL;
tran->tran_tgt_init             = isp_tran_tgt_init;
tran->tran_tgt_probe            = scsi_hba_probe;
tran->tran_tgt_free             = (void (*)())NULL;

tran->tran_start                = isp_scsi_start;
tran->tran_abort                = isp_scsi_abort;
tran->tran_reset                = isp_scsi_reset;
tran->tran_getcap               = isp_scsi_getcap;
tran->tran_setcap               = isp_scsi_setcap;
tran->tran_init_pkt             = isp_scsi_init_pkt;
tran->tran_destroy_pkt          = isp_scsi_destroy_pkt;
tran->tran_dmafree              = isp_scsi_dmafree;
tran->tran_sync_pkt             = isp_scsi_sync_pkt;
tran->tran_reset_notify         = isp_scsi_reset_notify;
tran->tran_bus_quiesce          = isp_tran_bus_quiesce
tran->tran_bus_unquiesce        = isp_tran_bus_unquiesce
tran->tran_bus_reset            = isp_tran_bus_reset
tran->tran_interconnect_type    = isp_tran_interconnect_type
HBA ドライバの接続

HBA ドライバは、デバイスのこのインスタンスを接続し、必要があれば、エラーのクリーンアップを実行します。

i = scsi_hba_attach_setup(dip, &isp_dma_attr, tran, 0);
if (i != DDI_SUCCESS) {
    /* do error recovery */
    return (DDI_FAILURE);
}
レジスタマッピング

HBA ドライバは、そのデバイスのレジスタをマップします。ドライバでは次の項目を指定する必要があります。

ddi_device_acc_attr_t    dev_attributes;

     dev_attributes.devacc_attr_version = DDI_DEVICE_ATTR_V0;
     dev_attributes.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
     dev_attributes.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;

     if (ddi_regs_map_setup(dip, 0, (caddr_t *)&isp->isp_reg,
     0, sizeof (struct ispregs), &dev_attributes,
     &isp->isp_acc_handle) != DDI_SUCCESS) {
        /* do error recovery */
        return (DDI_FAILURE);
     }
割り込みハンドラの追加

ドライバはまず、iblock cookie を取得して、ドライバハンドラで使用される mutex をすべて初期化する必要があります。それらの mutex の初期化が完了している場合にのみ、割り込みハンドラを追加できます。

i = ddi_get_iblock_cookie(dip, 0, &isp->iblock_cookie};
if (i != DDI_SUCCESS) {
    /* do error recovery */
    return (DDI_FAILURE);
}

mutex_init(&isp->mutex, "isp_mutex", MUTEX_DRIVER,
(void *)isp->iblock_cookie);
i = ddi_add_intr(dip, 0, &isp->iblock_cookie,
0, isp_intr, (caddr_t)isp);
if (i != DDI_SUCCESS) {
    /* do error recovery */
    return (DDI_FAILURE);
}

高レベルのハンドラが必要な場合、そのようなハンドラを提供するようにドライバをコーディングします。それ以外の場合、ドライバはその接続に失敗できる必要があります。高レベルの割り込み処理については、「高レベルの割り込みの処理」を参照してください。

電源管理可能なコンポーネントの作成

電源管理を使用すると、すべてのターゲットアダプタの電源レベルが 0 のときにホストバスアダプタの電源のみを切る必要がある場合、HBA ドライバは power(9E) エントリポイントを提供するだけで済みます。第 12 章電源管理を参照してください。HBA ドライバは、デバイスが実装するコンポーネントについて記述するための pm-components(9P) プロパティーも作成する必要があります。

これ以上は何も必要ありません。コンポーネントがデフォルトでアイドル状態になり、電源管理フレームワークのデフォルトの依存性処理によって、ターゲットアダプタの電源が入ると、ホストバスアダプタの電源も確実に入るようになるためです。自動電源管理が自動的に使用可能になる場合、この処理では、すべてのターゲットアダプタの電源が切れると、ホストバスアダプタの電源も切れます。

接続ステータスのレポート

最後に、HBA ドライバは、デバイスのこのインスタンスが接続され、成功を返すことをレポートします。

ddi_report_dev(dip);
    return (DDI_SUCCESS);

detach() エントリポイント (SCSI HBA ドライバ)

HBA ドライバは、scsi_hba_detach(9F) の呼び出しなど、標準的な切り離し操作を実行します。