# 通知設計書 39-CAM periph error

## 概要

本ドキュメントは、FreeBSDカーネルのCAM（Common Access Method）サブシステムにおけるCAM周辺デバイスのエラー通知（CAM periph error）の設計を記述する。CAMペリフェラルドライバ共通処理（cam_periph.c）が、SCSI/ATA/NVMeデバイスのI/Oエラーやタイムアウトを検出した際にdevctl経由でユーザランドへ通知を発行する仕組みを対象とする。

### 本通知の処理概要

本通知は、CAMペリフェラルドライバの共通エラー処理ルーチン（cam_periph_error）内で、I/Oコマンドのエラーや タイムアウトが発生した際に発行されるカーネルレベルの通知である。SCSI、ATA、NVMeの各プロトコルに対応したエラー情報が通知データに含まれる。

**業務上の目的・背景**：ストレージデバイスのI/Oエラーは、ディスク障害、ケーブル不良、コントローラ異常など、ハードウェア障害の重要な前兆指標である。この通知により、ストレージ監視システムがリアルタイムでエラーを検知し、予防的なデバイス交換やRAIDアレイの再構築判断を支援する。タイムアウトやセンスデータ付きエラーなど、詳細なエラー情報がデバイス診断に活用される。

**通知の送信タイミング**：cam_periph_error関数のエラー処理の終了段階で、devctl_errフラグが真であり、かつエラーが発生した場合またはSSQ_PRINT_SENSEアクションが設定されている場合にcam_periph_devctl_notify関数が呼び出される。

**通知の受信者**：devd(8)デーモンおよびdevctl(4)インターフェースを監視するユーザランドプロセス。

**通知内容の概要**：システム名「CAM」、サブシステム名「periph」、タイプは「timeout」または「error」。データにはデバイス名、シリアル番号、CAMステータス、プロトコル固有のエラー情報（CDB、ATA RES、NVMeステータス等）が含まれる。

**期待されるアクション**：SMART情報の確認、エラーログの記録、管理者への通知、デバイス交換の判断、RAIDアレイの状態確認。

## 通知種別

カーネルdevctl通知（devctl_notify経由）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（I/Oエラー処理コンテキストで発行） |
| 優先度 | 高（エラーイベント） |
| リトライ | 無し |

### 送信先決定ロジック

devctl_notifyによるブロードキャスト。

## 通知テンプレート

### devctl通知の場合

| 項目 | 内容 |
|-----|------|
| システム名 | CAM |
| サブシステム名 | periph |
| タイプ | timeout / error |
| データ | device=XXNN serial="..." cam_status="0x..." [プロトコル固有データ] |

### 本文テンプレート

```
!system=CAM subsystem=periph type=timeout device=da0 serial="ABC123" cam_status="0x44" timeout=30000
!system=CAM subsystem=periph type=error device=da0 serial="ABC123" cam_status="0x44" [SCSIセンスデータ] CDB="28 00 00 00 00 00 00 00 08 00"
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| system | 通知のシステム名 | ハードコード "CAM" | Yes |
| subsystem | サブシステム名 | ハードコード "periph" | Yes |
| type | エラータイプ | CAMステータスから決定 | Yes |
| device | デバイス名 | periph->periph_name + unit_number | Yes |
| serial | シリアル番号 | ccb_getdevで取得 | No |
| cam_status | CAMステータスコード | ccb->ccb_h.status | Yes |
| timeout | タイムアウト値（ms） | ccb->ccb_h.timeout（タイムアウト時） | No |
| CDB | SCSIコマンドCDB | csio.cdb（SCSI I/O時） | No |
| RES | ATAレスポンス | ataio.res（ATA I/O時） | No |
| sct/sc/cdw0 | NVMeステータス | nvmeio.cpl（NVMe I/O時） | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| I/Oエラー | CAM_CMD_TIMEOUT | devctl_err == true | コマンドタイムアウト |
| I/Oエラー | CAM_SCSI_STATUS_ERROR | devctl_err == true かつ (error != 0 または SSQ_PRINT_SENSE) | SCSIステータスエラー |
| I/Oエラー | CAM_ATA_STATUS_ERROR | devctl_err == true かつ (error != 0 または SSQ_PRINT_SENSE) | ATAステータスエラー |
| I/Oエラー | CAM_NVME_STATUS_ERROR | devctl_err == true かつ (error != 0 または SSQ_PRINT_SENSE) | NVMeステータスエラー |
| I/Oエラー | その他のCAMエラー | devctl_err == true かつ error != 0 | その他のCAMエラー |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| devctl_errがfalse | エラー処理ルーチンの判断でdevctl通知不要と判定された場合 |
| malloc失敗 | M_NOWAITでのメモリ確保に失敗した場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[I/Oエラー発生] --> B[cam_periph_error 呼び出し]
    B --> C[エラー分類・リトライ判定]
    C --> D{devctl_err && error/PRINT_SENSE?}
    D -->|Yes| E[cam_periph_devctl_notify 呼び出し]
    D -->|No| I[終了]
    E --> F[sbuf でメッセージ構築]
    F --> G[プロトコル別データ追加]
    G --> H["devctl_notify(CAM, periph, type, sbuf_data)"]
    H --> I
```

## データベース参照・更新仕様

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| メモリ確保失敗 | malloc(M_NOWAIT)がNULL返却 | return で通知をスキップ |
| CCB取得失敗 | xpt_alloc_ccb_nowaitがNULL返却 | シリアル番号なしで通知を続行 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0 |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし

## セキュリティ考慮事項

/dev/devctlへのアクセスはrootのみ。通知にはデバイスのシリアル番号とエラー情報が含まれるが、I/Oデータの内容は含まれない。

## 備考

- 通知バッファサイズはCAM_PERIPH_DEVD_MSG_SIZE（1024バイト）
- タイプ名はCAMステータスに応じて "timeout" または "error" が選択される
- SCSI、ATA、NVMeの3プロトコルに対応したエラー情報フォーマット
- シリアル番号の取得にはxpt_alloc_ccb_nowaitとxpt_gdev_typeが使用される
- NVMeエラーの場合、SCT（Status Code Type）、SC（Status Code）、CDW0が含まれる

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | cam_periph.c | `sys/cam/cam_periph.c` | cam_periph_devctl_notify関数のプロトタイプ（93行目） |
| 1-2 | cam.h | `sys/cam/cam.h` | CAMステータスコード定義（CAM_CMD_TIMEOUT等） |

**読解のコツ**: ccb->ccb_h.status & CAM_STATUS_MASKでステータスコードを抽出し、それに応じてtypeとプロトコル固有データが決定される。

#### Step 2: エラー処理パスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | cam_periph.c | `sys/cam/cam_periph.c` | cam_periph_error関数の2038-2040行目でcam_periph_devctl_notifyを呼び出し |

**主要処理フロー**:
1. **2039行目**: devctl_errが真 かつ (error != 0 または SSQ_PRINT_SENSE) の条件判定
2. **2040行目**: cam_periph_devctl_notify(orig_ccb) 呼び出し

#### Step 3: 通知データ構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | cam_periph.c | `sys/cam/cam_periph.c` | cam_periph_devctl_notify関数（2114-2205行目） |

**主要処理フロー**:
- **2127-2129行目**: device名の構築
- **2131-2138行目**: シリアル番号の取得と構築
- **2139行目**: cam_statusの追加
- **2141-2168行目**: ステータスに応じたtypeとプロトコル固有データの追加
- **2172-2196行目**: func_codeに応じたコマンド情報（CDB/ACB/NVMeコマンド）の追加
- **2202行目**: devctl_notify("CAM", "periph", type, sbuf_data(&sb))

### プログラム呼び出し階層図

```
CAMペリフェラルドライバ（エラー処理）
    |
    +-- cam_periph_error(ccb, ...)                [sys/cam/cam_periph.c]
            |
            +-- cam_periph_devctl_notify(ccb)     [2040]
                    |
                    +-- xpt_alloc_ccb_nowait()     [2132]
                    +-- xpt_gdev_type()            [2133]
                    +-- sbuf_printf (device, serial, cam_status) [2128-2139]
                    +-- scsi_format_sense_devd / ata_res_sbuf   [2147-2165]
                    +-- scsi_cdb_sbuf / ata_cmd_sbuf            [2173-2196]
                    +-- devctl_notify("CAM","periph",type,...)  [2202]
```

### データフロー図

```
[入力]                     [処理]                        [出力]

CCB (I/Oコマンド結果)    cam_periph_devctl_notify() /dev/devctl
ccb->ccb_h.status ----> ステータス判定 -----------> devctl_notify()
ccb->csio/ataio/nvmeio  プロトコル別データ構築     devdデーモン
                        sbufで通知データ組立
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| cam_periph.c | `sys/cam/cam_periph.c` | ソース | CAMペリフェラル共通処理、devctl_notify発行 |
| cam.h | `sys/cam/cam.h` | ヘッダ | CAMステータスコード定義 |
| cam_ccb.h | `sys/cam/cam_ccb.h` | ヘッダ | CCB構造体定義 |
| scsi_all.c | `sys/cam/scsi/scsi_all.c` | ソース | SCSIセンスデータフォーマット関数 |
| subr_bus.c | `sys/kern/subr_bus.c` | ソース | devctl_notify関数の実装 |
