NVIDIA Jetson TX2 NXにおけるSSD増設

## はじめに

最近、Jetson Nanoの上位機種のJetson TX2 NXを使い始めました([こちら参照](https://qiita.com/MakotoA67/items/8067cf79c038941e64e0))が、引き続きまして、SSDを増設して、元々のブートデバイスである内蔵eMMCとのデュアルブート環境を構築しましたので、その紹介をしてみます。

## SSDの装着とその認識

キャリーボードにSSDを装着したところ。

![TRANSCEND_128GB@A203.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/998321/17e50866-74dd-42d6-48cf-4433dbd3762a.jpeg)

使用しているSSDは[Transcendの128GB SSD(TS128GMTE452T)](https://jp.transcend-info.com/embedded/product/embedded-ssd-solutions/mte452t-mte452t-i)。購入サイトは[こちら](https://amzn.to/3qR8f52)。まず、装着したSSDがちゃんと認識されるかどうかがポイント。

```
$ dmesg | grep nvme
[    2.253370] nvme nvme0: pci function 0000:01:00.0
[    2.253397] nvme 0000:01:00.0: enabling device (0000 -> 0002)
[    2.375443]  nvme0n1:
$ ls -las /dev/nvme0n1
0 brw-rw---- 1 root disk 259, 2  1月 23 14:33 /dev/nvme0n1
```

先に、[TS120GMTS420S](https://jp.transcend-info.com/Products/No-766)を入手して、物理的に刺さるのは刺さったので刺してみたが、これは認識せず。M.2 2242でも、SATAとなっているものはダメなのだろう。

## SSDのパーティション作成及びフォーマット

主に、[Jetson Xavier NX 開発者キットに M.2 NVMe SSDを増設する方法](http://www.neko.ne.jp/~freewing/raspberry_pi/nvidia_jetson_xavier_nx_install_m2_nvme_ssd/)を参考にさせてもらった。

**parted**や**mke2fs**を用いてパーティションを作成してフォーマット。
[**rootOnNVMe.git**](https://github.com/jetsonhacks/rootOnNVMe.git)の**copy-rootfs-ssd.sh**を用いて、eMMC上のrootfsをSSDにコピーしてしまう。

内蔵eMMCをセットアップしたときと同様に、flash.shを用いて書き込んでもよいが、もちろん、コピーする方が速いだろう。

ここで、rootOnNVMe.gitにて用意されているsetup-service.shは使用せずに、U-BootからSSDでブートするようにした。

<details><summary>rootOnNVMe.gitの意義</summary><div>
L4T 32.5で、USBやSSDからブートできるようになっていて、USBメモリからのブートは、Jetson Nanoで一度試すだけ試したことがあったので、リリースノートを再度確認してみた。

https://developer.nvidia.com/embedded/l4t/r32_release_v5.0/jetson_linux_driver_package_release_notes_r32.5_ga.pdf

の、

> Loading  from  USB or  NVMe  drive:  Jetson  Nano,  Jetson  TX2,  and  Jetson  TX1  modules now support  loading kernel,  device  tree,  and  initrd from  the  root  file  system  on  a  USB or NVMe drive. 

という記述がそれ。ということで、SSDなどからのブートがまだできなかったときに、ルートファイルシステムをコピーして、そのSSD上のファイルシステムをルートファイルシステムとしてマウントしてシステムを実行する、というものだったわけだが、今は、SSDから直接ブートできるように対応されているため。</div></details>

## ブートの順序変更

シリアルコンソールから、U-Bootのautoboot中にEnterキーを押して、boot_devicesをnvme0 mmc0の順序に設定した上でSSDからブート。

```
setenv boot_targets nvme0 mmc0 usb0
saveenv
boot
```

ここで、saveenvすることで、今後は常にSSDから優先的に起動させる。逆に言うと、SSDでブートできなくなったときなどに、内蔵eMMCからブートしたくなった場合は、同様にautoboot中にmmc0からブートするように変更してブートすればよい。

## U-Bootのアップデート

ここで、急に、U-Bootのアップデートの話しになるが、その経緯を説明する。

これは、別にSSDだからというわけではなく、eMMCで検討中に遭遇したのだが、**Jetson I/O**にて生成したDevice Treeを用いてブートできない、という問題が発生。検索していたら、以下の投稿を見つけた。

[[L4T 32.6.1 TX2 NX] Loading default dtb trough extlinux FDT ...](https://forums.developer.nvidia.com/t/l4t-32-6-1-tx2-nx-loading-default-dtb-trough-extlinux-fdt-causes-kernel-to-hang/197775)

オリジナルのU-Bootだと、コンフィグファイルinclude/configs/p3636-0001.hが間違っていて、結果的に、カーネルが32GBに制限されてしまっているということだった。これはなかなか気づけない。。。

ということで、U-BootのTX2 NX用のコンフィグ(p3636-0001.h)を修正してビルド、そしてflash.shでU-Bootだけをアップデートしようとすると、、、

今度は、書き込みに失敗する。。
あれー、思って調べてると、同じようなことを言っている人が。

[problem flashing u-boot on to TX2 eMMC](https://forums.developer.nvidia.com/t/problem-flashing-u-boot-on-to-tx2-emmc/111601)

結論としては、flash.sh -r -k kernel ... とするとWriteできたみたい。

[NVIDIA Jetson Linux Driver Package Software Features](https://docs.nvidia.com/jetson/l4t/index.html)

の**Bootloader**の**U-Boot Customization**の**Flashing U-Boot Only**で説明されているとおり、

```
$ sudo ./flash.sh -k LNX <platform> mmcblk0p1
```

と実行していたのだが、**LNX**ではなく**kernel**と指定しないといけなかったみたい。(ちなみに、ここでは、SSDがターゲットなので、**mmcblk0p1**ではなく**nvme0n1**、そして、**\<platform\>**の部分は**jetson-xavier-nx-devkit-tx2-nx**を指定。)

## Jetson I/Oを使用した際の注意点など(2022/1/25追記)

カーネルに手を入れるなどした際の、Device Treeの更新には、NVIDIA提供のJetson I/Oというツールを使うのが便利だという話しは、[こちら](https://qiita.com/MakotoA67/items/8d2118e9a34eccb1cc6f#device-tree%E3%81%AE%E6%9B%B4%E6%96%B0)で書いたが、今回のようなデュアルブート環境で使用すると、ちょっと混乱する状況になったので、それについて書いておく。

SSDで起動したときに、この**Jetson I/O**を実行すると、SSD側の/etc/extlinux/extlinux.conf内でルートファイルシステムを指定しているところが、変に、eMMCのものに置き換わってしまい、普通にそのまま**Jetson I/O**に従ってリブートすると混乱する。

U-Boot的にはSSDから起動したのにも関わらず、rootfsがeMMC上のものとなっているためである。(該当箇所は以下の**mmcblk0p1**のところ。)

```extlinux.conf
APPEND ${cbootargs} quiet root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 isolcpus=1-2
```

**Save and reboot to reconfigure pins**ではなく、**Save and exit without rebooting**の方を選んで**Jetson I/O**から抜けて、/boot/extlinux/extlinux.confの内容を確認して、必要に応じて編集をした上でリブートする、などという手順をお勧めしたい。(具体的には、**mmcblk0p1**を**nvme0n1p1**に修正する。)

<details><summary>その原因など</summary><div>
jetson-ioのJetson/board.pyあたりに、結果的に、eMMC側のパーティション情報を参照して、マウントして、などという箇所がちらっと見えたが、それ以上の追跡はやめにして、上記のような運用で対応することとした。</div></details>

## おわりに

これで、デフォルトはSSDからの起動、SSDがブートしないなどのトラブル時には、eMMCからブートして対応、という、SSDとeMMCとのデュアルブート環境が構築できました。

色々とトラブルに遭遇しながら、ようやくたどりついた後に思い出しながら記述したので、足りていないところがあるかもしれません。思い出したら追記/修正します。