NanoPi NEO / NanoPi NEO2 NASキットで内蔵SSDのUASPを無効にする

# はじめに

NanoPi NEO / NanoPi NEO2 NASキットに搭載したSATA SSDが不安定なので切り分けのため、UASPを無効にしようとした。OSの違いで手順が異なり、若干ハマったのでまとめた。

# 環境

+ NanoPi NEO2
+ NanoPi NEO / NanoPi NEO2 NASキット（[1-bay NAS Kit v1.2 for NanoPi NEO&NEO2](https://www.friendlyelec.com/index.php?route=product/product&product_id=222)）
+ debian for NAS（NanoPi NEO2用、nanopi-neo2_debian-nas-jessie_4.14.0_20171208.img.zip）
+ Armbian 22.11.1 Bullseye (Kernel 5.15.80)

# 事前確認

１. NASキットに搭載されているUSB-eSATA変換チップ（`JMS567`）のベンダーIDが「`0x152d`」、プロダクトIDが「`0x0578`」になっている

`debian for NAS`の場合
```
# lsusb
：
Bus 004 Device 002: ID 152d:0578 JMicron Technology Corp. / JMicron USA Technology Corp.
：
```

`armbian`の場合
```
# lsusb
：
Bus 004 Device 002: ID 152d:0578 JMicron Technology Corp. / JMicron USA Technology Corp. JMS578 SATA 6Gb/s
：
```
※`lsusb`コマンドの出力が`JMS578`になっているが気にしないでよい
 

２．`lsusb -t`コマンドで対象のSSDのドライバーが`uas`になっている
```
# lsusb -t
：
/:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=ehci-platform/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Mass Storage, Driver=uas, 480M
：
```

# 手順
## debian for NASの場合
１. `root`ユーザーで`/boot/boot.cmd`を編集して、`setenv bootargs`で始まる行に「`usb-storage.quirks=152d:0578:u`」を追加する。（他のパラメータとは「` `（半角スペース）」で区切る）
```/boot/boot.cmd（編集前）
:
setenv bootargs <・・・>
:
```
```/boot/boot.cmd（編集後）
:
setenv bootargs <・・・> usb-storage.quirks=152d:0578:u
:
```

２. `/boot/boot.scr`を再構築
```
# mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scrImage Name:
Created:      aaa bbb dd hh:mm:ss yyyy
Image Type:   ARM Linux Script (uncompressed)
Data Size:    817 Bytes = 0.80 kB = 0.00 MB
Load Address: 00000000
Entry Point:  00000000
Contents:
   Image 0: 809 Bytes = 0.79 kB = 0.00 MB
```

３. システムを再起動

## armbianの場合

１. `root`ユーザーで`/boot/armbianEnv.txt`を編集して、`usbstoragequirks`で始まる行に「`0x152d:0x0578:u`」を追加する。（他のパラメータとは「`,`（半角カンマ）」で区切る）

```/boot/armbianEnv.txt（編集前）
:
usbstoragequirks <・・・>
:
```
```/boot/armbianEnv.txt（編集後）
:
usbstoragequirks <・・・>,0x152d:0x0578:u
:
```
２. システムを再起動

# 確認方法

１. 実行されたコマンドラインを確認（該当ファイルの編集した部分が出ているか？）

`debian for NAS`の場合
```
# cat /proc/cmdline
<・・・> usb-storage.quirks=152d:0578:u
#
```

`armbian`の場合
```
# cat /proc/cmdline
<・・・> usb-storage.quirks=<・・・>,0x152d:0x0578:u <・・・>
#
```


２．`lsusb -t`コマンドで対象のSSDのドライバーが`usb-storage`になっているか確認
```
#lsusb -t
：
/:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=ehci-platform/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Mass Storage, Driver=usb-storage, 480M
：
```

# 結果
正確な性能テストが難しいので性能の違いは評価しづらいが、UASPの有効/無効で`hdparm -t --direct`による**性能テストの結果はあまり変わりはなかった**（約30～40MB/s程度[^性能評価]）。

また、UASPを無効にして**長時間/連続IOが安定した**。IOを続けていくと発生していたUSBのリセットやセクターエラーが発生しないようになった。（`armbian`環境、約半日[^期間備考]、約240GB以上の書込み[^書込量備考]）

[^性能評価]: USB2.0接続なので理論上のバス性能は480Mbps（60MB/s）だが、いろいろなオーバーヘッドのため30～40MB/s程度は普通
[^期間備考]: 期間中はインターネットからだらだらとファイルを連続ダウンロード（平均数MB/s程度？）
[^書込量備考]: S.M.A.R.Tの値（249:NAND_Writes_1GiB）の増加量から推定。また、起動時からのデータを取り忘れたため「以上」と記載

【USBのリセット（例）】
```/var/log/kern.log
Jan 14 22:46:56 nanopineo2 kernel: [157733.566683] sd 0:0:0:0: [sda] tag#18 uas_eh_abort_handler 0 uas-tag 3 inflight: IN
Jan 14 22:46:56 nanopineo2 kernel: [157733.566765] sd 0:0:0:0: [sda] tag#18 CDB: opcode=0x28 28 00 07 79 10 00 00 04 00 00
Jan 14 22:46:56 nanopineo2 kernel: [157733.586734] scsi host0: uas_eh_device_reset_handler start
Jan 14 22:46:56 nanopineo2 kernel: [157733.714656] usb 4-1: reset high-speed USB device number 2 using ehci-platform
Jan 14 22:46:56 nanopineo2 kernel: [157733.872136] scsi host0: uas_eh_device_reset_handler success
```

# 懸念点
NASキットには外部接続用のUSBポート（USB 2.0接続）が2個ついている。
UASPの無効はベンダーIDとプロダクトIDの組み合わせで設定してるため、**同じベンダーIDとプロダクトIDを返す外付けHDD/SSD製品（ケース含む）を使うと強制的にUASPが無効になってしまう**。JMicron JMS567/JMS578搭載の一部の製品がこれに該当する。