E.1. 中間レベル

カーネルソースにある下記のヘッダファイルは、中間レベルに関連しています。

        /usr/src/linux/include/scsi/scsi.h
        /usr/src/linux/include/scsi/scsi_ioctl.h

これらのファイルは、アプリケーションから用いるためのものです(__KERNEL__ 条件 内部のコンパイルブロック以外の部分)。これらは /usr/include/scsi ディレクトリ にもありますが、そちらは glibc ライブラリとともにメンテナンスされており、 カーネルのバージョンに追随していないので、信じない方が賢明です。 Linux システムでは、 /usr/include/linuxがカーネルソースの include 領域 にシンボリックリンクされています(普通は、 /usr/src/linux/include/linux)。このシンボリックリンク を使うと、#include <linux/../scsi/scsi_ioctl.h> という技によって、 正確なscsi_ioctl.hをインクルードできます。

この /usr/src/linux/drivers/scsi/scsi.h は、SCSI サブ システムの鍵となる内部ヘッダーファイルです。同名の(ただし、別ディレクトリに 存在する)ファイル名があり、それはこのセクションの最初で注目したファイルである という点だけ指摘しておきます。これはときどき混乱の原因になります。

中間レベルのファイル drivers/scsi/scsi_scan.c には、 既知の SCSI デバイスの多くが特徴ある記述方法で載って います。(これは「ブラックリスト」として知られていましたが、あまりに断定的と みなされていました)。この配列の名前は「デバイスリスト」です。 次のようにいろいろな値があります。

E.1.1. 中間レベルのコンパイルオプション

ありません。

E.1.2. 中間レベルの ioctl

次のファイルを見てください。

/usr/src/linux/include/scsi/scsi.h

include/scsi/scsi.h で定義してある SCSI の状態定数は、SCSI 規格で定義 してある値に比べて、1 ビット右にシフトしている点に注意してください。


scsi.h 定数           値       SCSI 2 規格の値
----------------------------------------------------
CHECK_CONDITION       0x1           0x2
CHECK_GOOD            0x2           0x4
BUSY                  0x4           0x8
....

ioctl()の概要は下記の通りです。

SCSI_IOCTL_SEND_COMMAND

  このインタフェースは旧方式です。かわりに汎用 SCSI(sg)インタフェース
  を利用してください。汎用 SCSI(sg)インタフェースを使った方が、デバイス
  をより柔軟に扱えます。

  これまで触れて来ませんでしたが、構造体は下記のようになります。
  struct sdata {
   
   unsigned int inlen;     [i] デバイスに書き込んだデータ長
   unsigned int outlen;    [i] デバイスから読み込んだデータ長
   unsigned char cmd[x];   [i] SCSI コマンド(6 <= x <= 16)
                           [o] デバイスから読み込んだデータはここから開始
                           [o] エラー時には、センスバッファはここから開始
   unsigned char wdata[y]; [i] デバイスに書き込んだデータはここから開始
  };

  注意:
    ・SCSI コマンド長は、コマンドの最初のバイトでわかります。これを上書き
      する方法はありません。
    ・データ転送は、PAGE_SIZE(i386 で 4 K、alpha で 8 K)に制限されます。
    ・(x + y)の長さは、エラーが起こった時にセンスバッファ用に、
      最低 OMAX_SB_LEN バイトなければなりません。センスバッファは 
      OMAX_SB_LEN (16)バイトに縮められているので、古いコードでも支障はでません。
    ・Unix でエラーが発生した場合(例えば ENOMEM)、ユーザは負の返り値と
      「errno」にある Unix のエラーコードを受け取ります。
      SCSI コマンドが成功すると 0 が返ります。正の数を受け取ると、それは
      SCSI のエラーコードの集まりになっています(4 バイトが int ひとつにまとめ
      られている)。下位バイトが SCSI の状態を表しています。詳しい情報は
      drivers/scsi/scsi.h ファイルを見てください。
SCSI_IOCTL_GET_IDLUN

  この ioctl は 3 番目の引数として「struct scsi_idlun」オブジェクト
  へのポインタをとります。「struct scsi_idlun」の定義は、<scsi/scsi.h>
  にあります。これには、そのデバイスの SCSI ホスト、チャネル、デバイス ID、
  LUN データが入っています。
  あいにく、ヘッダファイルは構造体を「#ifdef __KERNEL__」ブロックで
 「隠して」います。これを利用するには、構造体をユーザのプログラムにコピー
  しなければなりません。
  このようになります。
  typedef struct my_scsi_idlun {
      
      int four_in_one;    /* 4 つの独立したバイトを 
                             1 つの int にまとめてある */
      int host_unique_id; /* 同じメーカー製カードと区別 */
  } My_scsi_idlun;
  
     「four_in_one」は、下記のように構成されています。
      (scsi_device_id | (lun << 8) | (channel << 16) |
      (host << 24))
  これら 4 つの部分はそれぞれ 1 バイトである(でマスクしてある)ことが
  前提になっています。
SCSI_IOCTL_GET_BUS_NUMBER
  
  Linux カーネル 2.2 以前では、この ioctl にはホスト番号が必要でした。
  Linux カーネル 2.3 開発版になって、SCSI_IOCTL_GET_IDLUN ioctl が変更に
  なり、この情報が入るようになりました。したがって、この ioctl は下位互換性
  のためにだけ必要です。
SCSI_IOCTL_TAGGED_ENABLE
  
  おそらく、中間レベルが以前扱っていた時の名残りです。現状この機能は、
  低レベルのドライバが制御しています。無視するのが一番です。
SCSI_IOCTL_TAGGED_DISABLE
  
  SCSI_IOCTL_TAGGED_ENABLE のコメントを見てください。
SCSI_IOCTL_PROBE_HOST
  
  この ioctl は 3 番目の引数に下記のような共用体へのポインタを要求します。
  union probe_host {
    
    unsigned int length;  /* [i] ASCII 文字列出力の最大長 */
    char str[length];     /* [o] 注意。'\0' を加える必要があるかも
                                 しれない */
  };
  
  デバイスの fd に対応したホストは、ホストに依存した情報の文字列か、
  それがなければホストの名前が与えられた構造体に出力されます。出力は与えられた
  構造体の先頭から出力が行われることに注意してください(入力の length は上書き
  される)。「注意」出力文字列が length に切り詰められた場合は、末尾に「\0」を
  加える必要があるかもしれません。返り値が 1 の場合はホストが存在することを
  表し、0 の場合はホストが存在しないことを表します(どのような場合?)。負の値
  はエラーを意味します。

SCSI_IOCTL_DOORLOCK
SCSI_IOCTL_DOORUNLOCK
SCSI_IOCTL_TEST_UNIT_READY

  ユニット(デバイス)が準備できていれば 0 が返り、準備ができていなければ
  正の値が返り、OS のエラーが発生した場合は負の値が返ります。

SCSI_IOCTL_START_UNIT
SCSI_IOCTL_STOP_UNIT

SCSI_EMULATED_HOST          {SG_EMULATED_HOST <new>と同じ}

SCSI_IOCTL_GET_PCI

  低レベル(アダプタ)に対応したPCI のスロット名(pci_dev::slot_name)のうち、
  現在デバイスを制御しているものを表示します。最大 8 文字が「引数」で指定
  された場所に出力されます。現在のデバイスが PCI デバイスによって制御されて
  いなければ、errno に ENXIO が設定されます。(この ioctl()は、Linux カーネル 
  2.4.4 で導入されました)。