# 通知設計書 41-NVMeコントローラRECONNECT通知

## 概要

本ドキュメントは、FreeBSD カーネルの NVMe over Fabrics (NVMf) ホストドライバが、コントローラとの接続が切断された際に再接続を要求するために発行する devctl 通知「nvme / controller / RECONNECT」の設計を記述する。

### 本通知の処理概要

NVMe over Fabrics ホストドライバにおいて、リモートの NVMe コントローラとの通信接続が失われた場合に、ユーザーランドの再接続デーモン（nvmecontrol 等）へ再接続が必要であることを通知する。

**業務上の目的・背景**：NVMe over Fabrics 環境では、ネットワーク障害やリモートコントローラの一時的な停止により接続が切断される可能性がある。この通知は、ユーザーランドのデーモン（devd 経由）に再接続の必要性を伝え、自動的な再接続処理を開始させるために必要である。手動介入なしにストレージ接続を復旧させることで、サービスのダウンタイムを最小化する。

**通知の送信タイミング**：NVMf ホストドライバが接続切断を検知し、再接続遅延（reconnect_delay）が設定されている場合に、最初の切断時と、その後 reconnect_delay 秒ごとの再接続試行タイミングで送信される。

**通知の受信者**：devd(8) デーモンを経由して、ユーザーランドの NVMe 管理ツール（nvmecontrol reconnect）が受信する。

**通知内容の概要**：通知には、再接続が必要な NVMf コントローラのデバイス名（例: nvme0）が含まれる。

**期待されるアクション**：受信したデーモンは、該当コントローラに対して NVMF_RECONNECT_HOST ioctl を発行し、新しいファブリック接続を確立して再接続を完了させる。

## 通知種別

devctl カーネル通知（devd(8) 経由のシステムイベント通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（カーネル内 devctl_notify） |
| 優先度 | 高 |
| リトライ | 有（reconnect_delay 秒間隔で定期的に再送信、controller_loss_timeout まで） |

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

devctl_notify() によりカーネルの devctl キューに投入され、/dev/devctl を監視する devd(8) デーモンがイベントを受信する。devd.conf の設定に基づき、マッチするアクションが実行される。

## 通知テンプレート

### devctl 通知フォーマット

| 項目 | 内容 |
|-----|------|
| system | nvme |
| subsystem | controller |
| type | RECONNECT |
| data | name="nvmeN"（N はデバイスユニット番号） |

### 本文テンプレート

```
!system=nvme subsystem=controller type=RECONNECT
name="nvme0"
```

### 添付ファイル

該当なし（カーネル内通知のため添付ファイルの概念なし）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| name | NVMf コントローラのデバイス名 | device_get_nameunit(sc->dev) | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| カーネルイベント | NVMf 接続切断検知 | reconnect_delay != 0 | 最初の切断時に発行 |
| タイマー | reconnect_delay タイマー満了 | admin == NULL かつ未デタッチ かつ controller_timedout == false | 再接続試行のたびに定期発行 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| reconnect_delay == 0 | 再接続遅延が未設定の場合は通知しない |
| sc->admin != NULL | 既に再接続済みの場合は送信しない |
| sc->detaching == true | デバイスがデタッチ中の場合は送信しない |
| sc->controller_timedout == true | コントローラロスタイムアウトに達した場合は送信しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[NVMf 接続切断検知] --> B[nvmf_disconnect_task 実行]
    B --> C{reconnect_delay != 0 ?}
    C -->|Yes| D[nvmf_request_reconnect 呼び出し]
    C -->|No| E[再接続通知なし]
    D --> F[devctl_notify 発行]
    F --> G[reconnect_delay 秒後にタスク再スケジュール]
    G --> H{再接続済み or デタッチ中 or タイムアウト?}
    H -->|No| D
    H -->|Yes| I[定期通知停止]
    E --> J[終了]
    I --> J
```

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

### 参照テーブル一覧

カーネルドライバのため、データベーステーブルへのアクセスはない。ドライバ内部の softc 構造体のフィールドを参照する。

| 構造体フィールド | 用途 | 備考 |
|-----------|------|------|
| sc->reconnect_delay | 再接続遅延秒数 | nvlist から取得 |
| sc->controller_loss_timeout | コントローラロスタイムアウト | nvlist から取得 |
| sc->admin | 管理キューの状態 | NULL の場合は切断状態 |
| sc->detaching | デタッチ状態フラグ | デタッチ中は通知抑止 |

### 更新テーブル一覧

該当なし（カーネルドライバのためデータベース更新はない）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| devctl キュー満杯 | devctl キューが一杯の場合 | 通知は破棄される（カーネル内で自動処理） |
| 再接続タイムアウト | controller_loss_timeout 到達 | デバイスが自動デタッチされる |
| 再接続失敗 | NVMF_RECONNECT_HOST ioctl 失敗 | 次の reconnect_delay で再度通知が発行される |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | controller_loss_timeout / reconnect_delay 回（設定値依存） |
| リトライ間隔 | reconnect_delay 秒 |
| リトライ対象エラー | 再接続が完了しない全てのケース |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | reconnect_delay に依存（明示的な制限なし） |
| 1日あたり上限 | controller_loss_timeout に依存（明示的な制限なし） |

### 配信時間帯

制限なし（カーネルイベントのため 24 時間発行可能）

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

- devctl 通知にはデバイス名のみが含まれ、機密情報は含まれない
- /dev/devctl の読み取りには root 権限が必要
- 再接続処理（NVMF_RECONNECT_HOST ioctl）にはデバイスファイルへの書き込み権限が必要

## 備考

- 本通知は NVMe over Fabrics 固有の機能であり、ローカル NVMe デバイスでは発行されない
- devd.conf に適切なルールを設定することで、自動再接続のワークフローを構築可能
- controller_loss_timeout が 0 の場合、コントローラロスによる自動デタッチは行われず、無期限に再接続を試み続ける

---

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

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

### 推奨読解順序

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

NVMf ホストドライバの softc 構造体と、再接続に関連するフィールドを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | nvmf_var.h | `sys/dev/nvmf/host/nvmf_var.h` | nvmf_softc 構造体の定義。reconnect_delay, controller_loss_timeout, admin, detaching フィールドに注目 |

**読解のコツ**: FreeBSD デバイスドライバでは softc 構造体がデバイスの状態を一元管理する。タスクキュー（TASK_INIT, TIMEOUT_TASK_INIT）によるイベント駆動設計を理解すること。

#### Step 2: エントリーポイントを理解する

接続切断を検知し、再接続通知を発行するまでの流れを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | nvmf.c | `sys/dev/nvmf/host/nvmf.c` | nvmf_disconnect() 関数（行634）が切断のエントリーポイント |

**主要処理フロー**:
1. **行634**: `nvmf_disconnect()` - タスクキューに切断タスクをエンキュー
2. **行640**: `nvmf_disconnect_task()` - 実際の切断処理を実行
3. **行699**: reconnect_delay != 0 の場合に `nvmf_request_reconnect()` を呼び出し
4. **行742**: `nvmf_request_reconnect()` - devctl_notify() を発行し、定期再試行タスクをスケジュール

#### Step 3: 再接続要求の定期発行を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | nvmf.c | `sys/dev/nvmf/host/nvmf.c` | nvmf_request_reconnect_task()（行755）が定期的に再接続要求を発行 |

**主要処理フロー**:
- **行748-749**: `devctl_notify("nvme", "controller", "RECONNECT", buf)` で通知発行
- **行750-751**: タスクキューに reconnect_delay 秒後の再実行をスケジュール
- **行760**: admin != NULL（再接続済み）またはデタッチ中/タイムアウトの場合は停止

#### Step 4: 再接続処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | nvmf.c | `sys/dev/nvmf/host/nvmf.c` | nvmf_reconnect_host()（行771）がユーザーランドからの再接続処理 |

**主要処理フロー**:
- **行816**: 新しい接続を確立（nvmf_establish_connection）
- **行837-838**: 再接続成功時に定期通知タスクをキャンセル

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

```
nvmf_disconnect()                          [行634: 切断要求]
    |
    +-- nvmf_disconnect_task()             [行640: 切断タスク実行]
           |
           +-- nvmf_request_reconnect()    [行742: 再接続要求]
           |       |
           |       +-- devctl_notify()     [行749: 通知発行]
           |       +-- taskqueue_enqueue_timeout()  [行750: 定期タスク登録]
           |
           +-- nvmf_request_reconnect_task()  [行755: 定期再実行タスク]
                   |
                   +-- nvmf_request_reconnect()  [行766: 再度通知発行]

nvmf_reconnect_host()                      [行771: ユーザーランドからの再接続]
    |
    +-- nvmf_establish_connection()         [行816: 新接続確立]
    +-- taskqueue_cancel_timeout()          [行837: 定期通知停止]
```

### データフロー図

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

トランスポートエラー -----> nvmf_disconnect_task() ------> devctl キューへ通知投入
                                 |                              |
                           reconnect_delay               devd(8) が受信
                           タイマー満了                         |
                                 |                        nvmecontrol reconnect
                           nvmf_request_reconnect()            |
                                 |                        NVMF_RECONNECT_HOST ioctl
                           devctl_notify() ---------> /dev/devctl
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| nvmf.c | `sys/dev/nvmf/host/nvmf.c` | ソース | NVMf ホストドライバ本体。通知発行元 |
| nvmf_var.h | `sys/dev/nvmf/host/nvmf_var.h` | ヘッダー | nvmf_softc 構造体定義 |
| nvmf_transport.h | `sys/dev/nvmf/nvmf_transport.h` | ヘッダー | NVMf トランスポート層インターフェース |
| nvme.h | `sys/dev/nvme/nvme.h` | ヘッダー | NVMe 共通データ構造定義 |
| subr_bus.c | `sys/kern/subr_bus.c` | ソース | devctl_notify() 実装 |
