# 機能設計書 31-NVMeコントローラ管理

## 概要

本ドキュメントは、FreeBSDにおけるNVMe SSDデバイスの管理・制御を行うnvmecontrolコマンドの機能設計書である。NVMeコントローラおよびネームスペースに対する各種操作を、ユーザ空間からioctlインタフェースを通じて実行する。

### 本機能の処理概要

nvmecontrolは、NVMe (Non-Volatile Memory Express) SSDデバイスの管理・監視・制御をコマンドラインから行うためのユーティリティである。

**業務上の目的・背景**：NVMe SSDは現代のストレージシステムにおいて標準的な高速ストレージデバイスであり、デバイスの情報取得、ファームウェア更新、性能テスト、ヘルス監視などの管理操作が必要である。nvmecontrolはこれらの管理タスクを統一的なインタフェースで提供する。

**機能の利用シーン**：システム管理者がNVMe SSDのヘルスチェック、ファームウェアアップデート、デバイス情報の確認、性能ベンチマーク、ネームスペース管理などを行う場面で利用される。

**主要な処理内容**：
1. NVMeコントローラおよびネームスペースの識別情報取得（identify）
2. デバイス一覧の表示（devlist）
3. ログページの取得と表示（logpage）
4. ファームウェアの管理（firmware）
5. 性能テストの実行（perftest）
6. 電源状態の管理（power）
7. デバイスのリセット（reset）
8. フォーマット操作（format）
9. NVMe-oF Fabrics接続管理（connect/disconnect/reconnect）
10. パススルーコマンドの実行（passthru）
11. ネームスペースの管理（ns）
12. サニタイズ操作（sanitize）
13. 予約の管理（resv）
14. ディスカバリー（discover）

**関連システム・外部連携**：NVMeカーネルドライバ（sys/dev/nvme/）とioctlインタフェースを介して通信する。動的ロード可能なプラグインモジュールにより拡張可能である。

**権限による制御**：デバイスファイル（/dev/nvme*）へのアクセス権限に基づく。書き込み操作（ファームウェア更新、フォーマットなど）にはO_RDWRアクセスが必要であり、通常root権限が必要となる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLIツールのため該当する画面なし |

## 機能種別

デバイス管理（CRUD操作 / 状態取得 / ファームウェア管理 / 性能テスト）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| サブコマンド | string | Yes | 実行する操作（devlist, identify, logpage等） | 登録済みコマンド名と一致すること |
| デバイスパス | string | サブコマンドによる | NVMeデバイスのパス（例: nvme0, /dev/nvme0ns1） | デバイスファイルが存在しオープン可能であること |
| -x (hex) | flag | No | 16進数表示モード | - |
| -v (verbose) | flag | No | 詳細表示モード | - |
| -n nsid | uint32 | No | ネームスペースID | 有効なNSID範囲内であること |

### 入力データソース

コマンドライン引数、NVMeデバイスファイル（/dev/nvme*）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| デバイス情報 | text | コントローラ/ネームスペースの識別情報 |
| ログデータ | text/hex | SMART情報等のログページデータ |
| 性能結果 | text | perftest実行時のI/O性能データ |
| ステータス | int | コマンド実行結果（0=成功, 非0=失敗） |

### 出力先

標準出力（コンソール）、プロセス終了コード

## 処理フロー

### 処理シーケンス

```
1. main()でcmd_init()を呼び出し、コマンドテーブルを初期化
   └─ SLISTベースのコマンドツリーを構築
2. cmd_load_dir()で/lib/nvmecontrolおよびlocalbase配下のプラグインをロード
   └─ 動的ライブラリ(.so)を読み込み、コンストラクタでコマンド登録
3. cmd_dispatch()でコマンドライン引数を解析しサブコマンドをディスパッチ
   └─ 引数をパースし、該当するcmd構造体のfn関数ポインタを呼び出し
4. 各サブコマンドがopen_dev()でデバイスをオープン
   └─ /dev/パス解決後、O_RDONLYまたはO_RDWRでオープン
5. ioctl()経由でNVMEドライバにコマンドを送信
   └─ NVME_PASSTHROUGH_CMD等のioctl番号を使用
6. レスポンスデータを整形して出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始: main] --> B[cmd_init: コマンドテーブル初期化]
    B --> C[cmd_load_dir: プラグインロード]
    C --> D[cmd_dispatch: サブコマンド解析]
    D --> E{サブコマンド特定}
    E -->|identify| F[open_dev + read_controller_data]
    E -->|devlist| G[全NVMeデバイス列挙]
    E -->|logpage| H[read_logpage]
    E -->|firmware| I[ファームウェア操作]
    E -->|perftest| J[性能テスト実行]
    E -->|その他| K[対応するサブコマンド処理]
    F --> L[結果表示]
    G --> L
    H --> L
    I --> L
    J --> L
    K --> L
    L --> M[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-31-01 | デバイスアクセス権 | 書き込み操作はO_RDWRでデバイスをオープンする必要がある | firmware, format, sanitize, reset等の破壊的操作時 |
| BR-31-02 | エンディアン変換 | NVMeデバイスからのデータはリトルエンディアンで返されるため、ホストバイトオーダーに変換する | 全てのidentify/logpage取得時 |
| BR-31-03 | プラグイン拡張 | /lib/nvmecontrolおよびlocalbase配下の共有ライブラリを自動ロードする | main()起動時 |

### 計算ロジック

特になし（デバイスI/O性能の測定結果はperftestサブコマンド内で計算）

## データベース操作仕様

### 操作別データベース影響一覧

該当なし（カーネルデバイスドライバとのioctl通信のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| EX_OSFILE | ファイルエラー | デバイスファイルをオープンできない | デバイスパスの確認、権限の確認 |
| EX_OSERR | OSエラー | ioctlが失敗した場合 | デバイスの状態確認、ドライバのロード確認 |
| EIO | I/Oエラー | NVMe完了ステータスがエラーの場合 | デバイスのヘルス状態を確認 |
| ERRNO | システムエラー | ioctl呼び出し時のerrno | errnoに応じた対処 |

### リトライ仕様

明示的なリトライ機構は実装されていない。

## トランザクション仕様

該当なし（各ioctl呼び出しはアトミックに実行される）

## パフォーマンス要件

perftestサブコマンドはNVMeデバイスの読み書き性能を測定するための機能であり、性能要件は測定対象のデバイス性能に依存する。

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

- デバイスファイルへのアクセス権限によりコマンド実行可否が制御される
- フォーマットやサニタイズはデータ消失を伴う破壊的操作であり、root権限が必要
- パススルーコマンドは任意のNVMeコマンドを送信可能であるため、誤操作に注意が必要

## 備考

nvmecontrolはプラグインアーキテクチャを採用しており、共有ライブラリによるサブコマンド拡張が可能である。NVMe-oF (NVMe over Fabrics) のconnect/disconnect/reconnect機能もサポートしている。

---

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

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

### 推奨読解順序

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

NVMeデバイスとの通信に使用されるデータ構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | nvmecontrol.h | `sbin/nvmecontrol/nvmecontrol.h` | logpage_function構造体、print_fn_t型定義、NVME_LOGPAGEマクロによる自動登録機構 |
| 1-2 | comnd.h | `sbin/nvmecontrol/comnd.h` | cmd構造体（サブコマンドツリー）、opts/args構造体（引数定義）、CMD_COMMANDマクロ |
| 1-3 | nvme.h | `sys/dev/nvme/nvme.h` | nvme_controller_data, nvme_namespace_data, nvme_pt_command等のカーネルインタフェース |

**読解のコツ**: `CMD_COMMAND`/`CMD_SUBCOMMAND`マクロは`__attribute__((constructor))`を使用して、プログラム起動時に自動的にコマンドをSLISTに登録する。各サブコマンドファイルの末尾にあるこれらのマクロ呼び出しを確認すると、コマンドの登録方法が理解できる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | nvmecontrol.c | `sbin/nvmecontrol/nvmecontrol.c` | main関数、コマンドディスパッチの流れ |

**主要処理フロー**:
1. **204-217行目**: main()関数 - cmd_init(), cmd_load_dir(), cmd_dispatch()の3ステップ
2. **98-119行目**: read_controller_data() - NVME_OPC_IDENTIFY ioctlの送信とエンディアン変換
3. **169-188行目**: open_dev() - デバイスパスの解決とオープン

#### Step 3: コマンドフレームワークを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | comnd.c | `sbin/nvmecontrol/comnd.c` | cmd_register()によるコマンド登録、cmd_dispatch()による引数解析とサブコマンド呼び出し |

**主要処理フロー**:
- **48行目**: top - トップレベルコマンドのSLIST
- **69-79行目**: gen_usage() - サブコマンド一覧のヘルプ出力

#### Step 4: 各サブコマンドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | identify.c | `sbin/nvmecontrol/identify.c` | コントローラ/ネームスペース識別情報の取得と表示 |
| 4-2 | devlist.c | `sbin/nvmecontrol/devlist.c` | NVMeデバイス一覧の取得 |
| 4-3 | logpage.c | `sbin/nvmecontrol/logpage.c` | SMART情報等のログページ取得 |
| 4-4 | firmware.c | `sbin/nvmecontrol/firmware.c` | ファームウェアダウンロード/アクティベート |
| 4-5 | perftest.c | `sbin/nvmecontrol/perftest.c` | I/O性能テスト |
| 4-6 | power.c | `sbin/nvmecontrol/power.c` | 電源状態管理 |

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

```
main() [nvmecontrol.c:204]
    |
    +-- cmd_init() [comnd.c]
    |
    +-- cmd_load_dir("/lib/nvmecontrol") [comnd.c]
    |       +-- dlopen() で共有ライブラリをロード
    |       +-- constructor属性でcmd_register()が自動呼出
    |
    +-- cmd_dispatch(argc, argv) [comnd.c]
            +-- サブコマンド名で検索
            +-- arg_parse() で引数を解析
            +-- cmd->fn() でサブコマンド実行
                    |
                    +-- open_dev() [nvmecontrol.c:170]
                    |       +-- open(/dev/nvmeX, O_RDONLY|O_RDWR)
                    |
                    +-- read_controller_data() [nvmecontrol.c:98]
                    |       +-- ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)
                    |       +-- nvme_controller_data_swapbytes()
                    |
                    +-- read_namespace_data() [nvmecontrol.c:121]
                            +-- ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)
                            +-- nvme_namespace_data_swapbytes()
```

### データフロー図

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

コマンドライン引数 ───> cmd_dispatch()
                            |
                       arg_parse() ───> サブコマンド特定
                            |
                       open_dev() ───> /dev/nvmeXデバイスオープン
                            |
                       ioctl(NVME_PASSTHROUGH_CMD)
                            |
                       NVMeカーネルドライバ ───> NVMe SSD
                            |
                       エンディアン変換 ───> ホストバイトオーダー
                            |
                       print/display関数 ───> 標準出力（テキスト/HEX）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| nvmecontrol.c | `sbin/nvmecontrol/nvmecontrol.c` | ソース | メインエントリーポイント、共通関数 |
| nvmecontrol.h | `sbin/nvmecontrol/nvmecontrol.h` | ヘッダ | 型定義、関数宣言、マクロ |
| comnd.c | `sbin/nvmecontrol/comnd.c` | ソース | コマンドフレームワーク |
| comnd.h | `sbin/nvmecontrol/comnd.h` | ヘッダ | コマンド構造体定義 |
| identify.c | `sbin/nvmecontrol/identify.c` | ソース | identify サブコマンド |
| devlist.c | `sbin/nvmecontrol/devlist.c` | ソース | devlist サブコマンド |
| logpage.c | `sbin/nvmecontrol/logpage.c` | ソース | logpage サブコマンド |
| firmware.c | `sbin/nvmecontrol/firmware.c` | ソース | firmware サブコマンド |
| perftest.c | `sbin/nvmecontrol/perftest.c` | ソース | perftest サブコマンド |
| power.c | `sbin/nvmecontrol/power.c` | ソース | power サブコマンド |
| format.c | `sbin/nvmecontrol/format.c` | ソース | format サブコマンド |
| reset.c | `sbin/nvmecontrol/reset.c` | ソース | reset サブコマンド |
| sanitize.c | `sbin/nvmecontrol/sanitize.c` | ソース | sanitize サブコマンド |
| ns.c | `sbin/nvmecontrol/ns.c` | ソース | namespace サブコマンド |
| passthru.c | `sbin/nvmecontrol/passthru.c` | ソース | passthru サブコマンド |
| connect.c | `sbin/nvmecontrol/connect.c` | ソース | NVMe-oF connect |
| disconnect.c | `sbin/nvmecontrol/disconnect.c` | ソース | NVMe-oF disconnect |
| reconnect.c | `sbin/nvmecontrol/reconnect.c` | ソース | NVMe-oF reconnect |
| discover.c | `sbin/nvmecontrol/discover.c` | ソース | NVMe-oF discover |
| resv.c | `sbin/nvmecontrol/resv.c` | ソース | reservation サブコマンド |
| nvmecontrol.8 | `sbin/nvmecontrol/nvmecontrol.8` | manページ | マニュアル |
| nvme.h | `sys/dev/nvme/nvme.h` | ヘッダ | NVMeカーネルインタフェース定義 |
