文章摘要
一顆 Samsung PM983 NF1 3.84TB 企業級 NVMe SSD(MZ4LB3T8HALS-00003)送進實驗室時,系統只認到 1GB,韌體版本欄位顯示「ERRORMOD」。本文記錄我們用 nvme-cli、原始 NVMe Admin 指令和 Samsung DC Toolkit 做的完整診斷:為什麼容量變 1GB、強制讀取為什麼讀不到東西、各種重置與韌體 Commit 的實測結果、從 Samsung 內部 Dump 看到的故障原因,以及拿 U.2 版韌體跨型號刷入被控制器拒絕的過程。最後整理遇到 ERRORMOD 時該怎麼做、不該做什麼。另外也逆向拆了 SSD Manager 的型號資料庫,找出它的替換式加密、補進 NF1 型號的方法,以及授權檢查的位置。
文章目錄
故障症狀:3.84TB 變成 1GB
這顆碟是 Samsung PM983 的 NF1(NGSFF,M.3 30110)版本,型號 MZ4LB3T8HALS-00003,屬於非 SED 的 3.84TB 企業碟。NF1 規格多半用在高密度全快閃伺服器,例如 Supermicro 的 1U NF1 機種。
接上測試機(Ubuntu 24.04,PCIe Gen3 x4)後的狀況:
- 作業系統和 GParted 看到的
/dev/nvme0n1只有 1.00 GiB。 - HardInfo2 顯示 3.5 TiB。
- openSeaChest 和
nvme list的韌體版本欄位寫的是 ERRORMOD,不是正常的版本號。
PCIe 鏈結本身正常,速度 8GT/s、寬度 x4,AER 沒有錯誤紀錄,控制器暫存器 CSTS.RDY=1、CFS=0。所以可以排除轉接卡接觸不良或插槽問題,問題在碟本身。
為什麼一個工具說 3.5TB、另一個說 1GB
兩個數字都是真的,只是讀的是 NVMe 不同層的資料:
| 工具 | 顯示 | 資料來源 |
|---|---|---|
| HardInfo2/UDisks2 | 3.5 TiB | Identify Controller 的 TNVMCAP(3,840,755,982,336 bytes),是控制器回報的標稱總容量 |
| 作業系統/GParted | 1.00 GiB | Identify Namespace 1 的 NSZE=2,097,152 個 512B 磁區,剛好 1 GiB |
也就是說,控制器還記得自己是 3.84TB 的碟,但對外開放的 Namespace 只剩一塊 1GiB 的空間。我們用 CNS=0x02、0x10、0x11 查過,整顆只有 NSID 1,未配置容量是 0,沒有被隱藏或卸載的第二個 Namespace。
韌體 Slot 資訊(Log Page 0x03)顯示 Slot 1 是唯讀槽,裡面的韌體是 EDA8100Q,Slot 2~8 都是空的。所以韌體程式本身還在,是它開機後進入了錯誤模式。
強制讀取實測
救資料最直覺的想法是「能不能硬讀」。我們做了幾種測試:
- 把整個 1GiB 掃完,非零位元組數是 0,全部都是
0x00。 - 用 NVMe I/O Passthrough 直接下 Read 指令,加上 FUA(強制讀取媒體),並刻意讀 1GiB 以外的位址,例如 LBA 100,000,000。
- 控制器對這些讀取一律在約 0.02 ms 內回傳成功,內容全是 0。正常 NAND 讀取至少要幾十微秒,這個速度代表控制器根本沒有去讀 NAND。
- Compare、Flush 等其他 I/O 指令直接回 Invalid Opcode。
結論是,在 ERRORMOD 下控制器沒有載入 FTL(邏輯位址對應到 NAND 實體位置的轉換表),不管用 ddrescue、R-Studio 還是自己下 Passthrough,讀到的都只是控制器回填的 0。拆 NAND 晶片直接讀也不可行,因為 PM983 寫入 NAND 的資料經過控制器內建的 AES 加密,金鑰不在 NAND 上。
nvme-cli 指令與重置測試
接著把 nvme-cli 和 Samsung plugin 可用的指令逐一試過,重點如下。
韌體 Commit(不帶新映像)
我們想試試看,能不能讓控制器重新啟用 Slot 1 的 EDA8100Q 再跑一次開機流程。把 fw-commit 的 action 0~7 和 slot 0~3 全部組合都送過:
- action 2、3(啟用既有 Slot)全部回
0x2002 Invalid Field,Error Log 直接指出是 CA 欄位不合法。ERRORMOD 不允許直接切換或重啟既有韌體。 - action 1 對 Slot 1 回
0x2106 Invalid Firmware Slot,因為 Slot 1 是唯讀。 - action 1 對 Slot 2、3 是唯一通過參數檢查的組合,只是因為沒有先下載映像,回
0x2107 Invalid Firmware Image。
也就是說,ERRORMOD 下只留一條路:先 fw-download 上傳韌體,再 fw-commit --slot=2 --action=1。
各層級重置
nvme reset(Controller Reset):瞬間完成,還是 ERRORMOD。nvme subsystem-reset(NSSR):一樣。- PCIe FLR 加上游 Root Port 的 Secondary Bus Reset:裝置短暫掉線後回來,不到 2 秒又是 ERRORMOD。
冷開機時,dmesg 可以看到控制器初始化卡了大約 15 秒才上線,熱重置則幾乎是立刻回到 ERRORMOD。只要 3.3V 電源沒有真正斷開,控制器就不會重跑完整的開機流程。
Samsung SSD Manager 與 DC Toolkit 工具測試
NF1 韌體在公開管道找不到,我們接著檢查手上能取得的 Samsung 企業碟工具,想確認兩件事:工具裡有沒有夾帶 NF1 韌體,以及有沒有工具能在 ERRORMOD 下跟碟溝通、抽出診斷資料。
Samsung SSD Manager 2.0.10.4(OEM 版)
SSD Manager 是 Samsung 提供給 OEM 與資料中心客戶的 Linux 命令列工具,不在 Samsung 官網公開下載。我們拿到的是網路上流傳的版本,無法跟原廠核對是否為原版,所以只放在隔離的測試機上使用。
- 型號資料庫:工具啟動時會讀取同目錄下的型號資料庫,只對資料庫裡有登記的型號開放功能。我們檢查的版本(2.142.OEM,2022-02 建立)收錄約 1,700 個型號,其中 PM983 有 21 筆,U.2(MZQLB)和 M.2(MZ1LB)都有,但完全沒有 NF1 的 MZ4LB 系列。
- 沒有夾帶韌體:資料庫裡記錄的是每個型號支援哪些功能、SMART 欄位怎麼解讀,例如 Log Page 0xCA 各欄位的位移,不含任何韌體映像。原本期待能從這裡找到 EDA8 韌體,結果落空。
- 在 ERRORMOD 碟上執行:我們嘗試讓工具辨識這顆 NF1 碟,但列碟和讀取 SMART 時程式直接 segfault,沒有送出任何指令到碟上。後來我們把型號資料庫解開、補進 NF1(見下一節),列碟與延伸 SMART 仍會 segfault,只有韌體 Slot 查詢沒崩潰。
- Vendor 指令的觀察:先前掃描 Admin Opcode 時,0xC1、0xC2 回成功、0xC0 卻失敗。從工具的行為來看,Samsung 的私有指令在送出時會依讀寫方向改成 0xC2(讀)或 0xC1(寫),這解釋了掃描結果。
Samsung DC Toolkit v2.1/v3.0(官方版)
DC Toolkit 是 Samsung 官網公開的工具,我們下載的檔案雜湊值跟官網原檔一致。
- v2.1 是官方列出支援 PM983 的版本,在 ERRORMOD 下仍能讀出 Error Log、SMART、Extended SMART 與韌體 Slot 資訊,但它的 Vendor Utility 只支援 SATA 碟。
- v3.0 的
-NV功能支援 NVMe,下一節的 SNOR Log 和 On-demand Dump 就是用它抽出來的。 - 工具裡內嵌的三份韌體映像都是 SATA/SAS 碟(PM863、PM1643 等)用的,跟 PM983 無關。
- 工具中處理 ERRORMOD 的功能名稱是
EscapeErrorModeUsingSecureErase,也就是說,連 Samsung 自己的工具,脫離 ERRORMOD 的方法都是安全抹除。這證實了用工具「救活」碟一定會清掉資料。
逆向 SSD Manager 型號資料庫:加密、NF1 收錄與授權檢查
上一節提到 SSD Manager 只對資料庫裡登記過的型號開放功能,而 2.142.OEM 版沒有 NF1 的 MZ4LB 系列。這一節記錄我們怎麼把型號資料庫解開、補進這顆 NF1,以及找到授權檢查的位置。
型號資料庫的格式與「加密」
工具啟動時會依序嘗試同目錄下的 DFDB_AWS.enc、DFDB_MSFT.enc、DFDB_Fujitsu.enc、DFDB_Basic.enc。這些 .enc 檔不是 AES 或其他區塊加密,而是一層 256 bytes 的位元組替換表:
- 替換表直接寫在執行檔的
.rodata,虛擬位址0x8cb620、檔案位移0x4cb620。 - 它只置換每個 byte 的高 4 bits,低 4 bits 不動;高 nibble 的對應順序是
0→1、1→3、2→5、3→7、4→9、5→11、6→13、7→15、8→14、9→12、10→10、11→8、12→6、13→4、14→2、15→0。 - 沒有金鑰、沒有 IV、沒有 block 或 chaining,所以每個 byte 都可以獨立解。解密就是查反表,加密就是查正表。
用 Python 重現(elf 是 SSDManager 執行檔):
tbl = elf[0x4cb620:0x4cb620 + 256]
inv = bytearray(256)
for i, b in enumerate(tbl):
inv[b] = i
plain = bytes(inv[b] for b in open("DFDB_Basic.enc", "rb").read())
open("DFDB_Basic.json", "wb").write(plain)
解出來的內容是一份 JSON 陣列:第 0 筆是資料庫版本(Version: 2.142.OEM、Created: 2022-02-18),其後 1,741 筆是各型號的功能對照表。每筆有 DO/IF/MD/CT/ND/BK/PN/SN/WA/DT/FT 等欄位,FT 裡記載這個型號支援哪些 vendor 指令,以及 SMART Log Page 0xCA 每個欄位的位移與長度。
例如 PM983 U.2 3.84TB 的 MZQLB3T8HALS-00003,SN 欄位只存前四碼 S481,不是完整序號。這也是為什麼補 NF1 條目時,SN 要填實際序號的前四碼。
把 NF1 補進資料庫
從資料庫結構與工具行為看,型號比對用的是 PN 加 SN 前四碼。資料庫裡沒有 MZ4LB3T8HALS-00003,所以這顆碟不會被視為支援的 Samsung 碟。補法是複製最接近的 U.2 3.84TB 條目當模板,改成 NF1 的型號與序號前四碼,再附加回陣列:
import json, copy
data = json.load(open("DFDB_Basic.json"))
tpl = copy.deepcopy(next(d for d in data[1:] if d["PN"] == "MZQLB3T8HALS-00003"))
tpl["PN"] = "MZ4LB3T8HALS-00003"
tpl["SN"] = "S40P" # 實際序號 S40PNE0M901977 的前四碼
tpl["FT"][0]["DSPD"] = ["SR"] # 原本空白,補上 PLP dump 能力
tpl["FT"][0]["PSID"] = "Y" # 讓工具知道這個型號支援 PSID Revert
data.append(tpl)
open("TestDB.json", "w").write(json.dumps(data, indent=4))
改完後有兩條路可以讓工具吃到新資料庫:
- 明文測試:把檔案存成執行檔同目錄的
TestDB.json。工具在0x609880會先找這個檔;存在就直接讀,完全跳過加密資料庫與授權檢查。我們在測試機上就是用這個方式。 - 正式替換:把 JSON 用同一張表加密回
DFDB_Basic.enc(enc = bytes(tbl[b] for b in plain)),覆蓋原檔。這樣不需要TestDB.json,但授權檢查仍然會跑。
實際在 ERRORMOD 碟上測試:-L -detail 和 -NG -d 0 -se 仍然 segfault,-NG -d 0 -f 沒有崩潰。也就是說,補條目解決了「型號不認得」這一層,但工具在讀 ERRORMOD 碟的 SMART/延伸 SMART 時還有第二個問題;這一層不是資料庫能修的。
授權檢查的位置
SSD Manager 的授權檢查不是連網,也不是硬體鎖,而是純本機的日期檢查。字串 DFDB license expired 在 .rodata 的 0x8cbfa8(檔案位移 0x4cbfa8),引用它的程式碼在 0x61a210(mov $0x8cbfa8,%esi),回傳錯誤碼 6。
載入流程在 0x60a0c0:
0x60a0c8先呼叫0x609880,也就是TestDB.json載入器;成功就直接 return,不進入加密資料庫流程。- 失敗才呼叫
0x608f90,解密並載入DFDB_Basic.enc。 0x60a0e8檢查回傳值;0x60a0f6失敗時設定錯誤碼 6,最後顯示DFDB license expired。
從資料庫內容與工具行為判斷,過期檢查比對的是資料庫裡的 Created: 2022-02-18:這個日期離執行當時(2026)已經超過工具允許的期限,所以判定授權過期。最簡單的繞法是放一份明文 TestDB.json,讓 0x609880 直接成功;不必改執行檔,也不必偽造系統時間。若要走加密資料庫,另一條路是把 JSON 裡的 Created 改成較新的日期,再用同一張替換表加密回去。
這也解釋了為什麼這支 2019 年編譯的工具在當時正常、到 2026 年卻說「license expired」:不是碟的問題,是資料庫的日期到了。
| 項目 | 位址/檔案位移 | 說明 |
|---|---|---|
| 替換表 | VA 0x8cb620/file 0x4cb620 | 256 bytes 的位元組替換表 |
| TestDB.json 載入器 | 0x609880 | 明文優先,成功即跳過加密與授權 |
| DFDB 解密/載入 | 0x608f90 | 讀取 DFDB_Basic.enc |
| 授權檢查呼叫 | 0x60a0c0 → 0x60a0f6 | 失敗設定錯誤碼 6 |
DFDB license expired |
VA 0x8cbfa8/file 0x4cbfa8 | 授權過期字串 |
Samsung DC Toolkit 內部 Dump 分析
Samsung 官方的 DC Toolkit for Linux v3.0 有 NVMe Vendor Unique 功能,可以抽出碟內部的狀態紀錄。在 ERRORMOD 下,SNOR Log 和 On-demand Dump 都抽得出來,Crash Dump 讀到一部分時控制器發生 fatal 錯誤被系統重置,所以沒有取得完整的 Crash Dump。
On-demand Dump 裡的健康紀錄是 JSON 格式,幾個關鍵欄位:
| 欄位 | 值 | 解讀 |
|---|---|---|
| DeviceMode | DeviceFail | 控制器自己判定故障 |
| OpenInfo.Type | SPO | 上一次關機是突然斷電(Sudden Power Off) |
| FTL/FIL 區段 | 空的 | 轉換表沒有載入 |
| 各核心 AssertType | CTrace_Type_FakeAssert | 五個 ARM 核心都停在 assert 狀態 |
| Cap.Health | true | 斷電保護(PLP)電容本身正常 |
| 溫度感測 0 | 77°C(最高 81°C) | 待機狀態就很燙,MeltDown 計數 3 次 |
另外,標準 SMART 在 ERRORMOD 下幾乎全部失效:溫度 0 K、Percentage Used 255%、Available Spare 0%、通電時數 0。這些值是因為 SMART 背景程式沒有運作,不代表碟真的用完壽命,判讀時不要被誤導。
把線索串起來,最可能的經過是:碟遭遇突然斷電,斷電當下 PLP 沒能把 FTL 的 Metadata 完整寫回,下次開機重建 FTL 失敗,控制器進入 DeviceFail,只開放一塊 1GiB 的假空間讓主機還認得到裝置。
韌體 Release Notes 裡的 ERRORMODE 修正
這顆碟的 EDA8100Q 是 NF1 版本早期的量產韌體。對照 Samsung PM983 U.2 和 M.2 的韌體 Release Notes,後續版本修掉了好幾個會讓碟進入 ERRORMODE 的問題:
- PLP Dump Fail due to Delay of Erase Recovery algorithm:斷電時 Erase abort 沒處理,PLP Dump 失敗後進入 Errormode。
- MapCache ECC Non L2P 1/2bit Guide Apply:DRAM 中存放韌體 Metadata 的區域發生單一位元翻轉時,就算 ECC 已經修正,舊韌體仍會進入 ERRORMODE。
- CS ODT setting change + DRAM VDD decrease:部分碟的 DRAM 訊號餘裕不足,調整 ODT 與 DRAM 電壓防止 Errormode。
- HW Assert Policy Change:溫度感測器重試或讀到異常值時不再 assert。
第一項跟這顆碟的 SPO 紀錄最吻合。理論上,換上修正過的新版韌體,有機會讓控制器在不清資料的前提下重新嘗試開機。問題是 NF1 版本的新韌體(EDA8xxxQ)沒有公開流通,我們查遍常見的韌體收集站、論壇和 OEM 下載頁都找不到。
跨型號刷入 U.2 韌體實測
既然 NF1 韌體找不到,我們試了同代 PM983 的其他版本韌體。它們是同一顆 Phoenix 控制器、同一代 NAND、同樣容量,差別在 PCB 和外形:
| 映像 | fw-download | fw-commit Slot 2 |
|---|---|---|
| EDA5900Q(U.2 非 SED,最接近的版本) | 成功 | 0x2107 Invalid Firmware Image |
| EDA5602Q、EDA5702Q(U.2 SED) | 成功 | 0x2107 |
| EDA7902Q(M.2 22110) | 成功 | 0x2107 |
| Lenovo OEM 版 U.2 韌體 | 成功 | 0x2107 |
| EDA5900Q,把明文 header 的版本字串改成 EDA8 | 成功 | 0x2107 |
| 用 Samsung DC Toolkit 官方流程刷 EDA5900Q | 成功 | 工具回報 firmware image is invalid |
換過不同的傳輸區塊大小,結果都一樣。每份韌體映像開頭都有一段 0x200 bytes、內容各不相同的資料,看起來是簽章。控制器在 Commit 時會驗證映像是否屬於 NF1 產品線,不符合就直接拒絕。改 header 字串沒用,因為簽章會跟著對不上。
值得一提的是,被拒絕不會有副作用。每次測試後,Slot 1 的 EDA8100Q 都沒變,碟也維持原本的狀態。
遇到 ERRORMOD 該怎麼辦
如果資料重要
- 不要 Format、不要 Sanitize、不要用工具的 Secure Erase。網路上很多「救活 ERRORMOD」的教學其實就是
nvme format,碟會變回正常容量,但 FTL 和加密金鑰會重建,資料永久消失。Samsung 自家工具裡處理這種狀態的功能,名稱就叫 EscapeErrorModeUsingSecureErase。 - 減少反覆開關機的次數,也不要讓碟在沒有散熱的情況下長時間通電。這顆碟停在 ERRORMOD 時控制器就有 77°C。
- 先抽 Samsung 的 On-demand Dump 留存,它能告訴你進入 ERRORMOD 的原因。
- 若要嘗試更新韌體,只能用同型號、同外形的官方韌體。NF1 版本要向整機廠(如 Supermicro)或 Samsung 企業支援索取。
如果資料不重要
對 NVMe Namespace 做 Format 有機會讓碟恢復 3.84TB 可用,但進過 ERRORMOD 的碟最好不要再放回正式環境,尤其是本來就使用早期韌體的碟。
預防
- 企業級 SSD 的韌體要跟著更新,PM983 早期韌體有多個已知的 ERRORMODE 問題。
- 避免突然斷電,伺服器要有 UPS 和正常的關機流程。
- NF1、U.2 這類高密度碟要確保機箱風流,高溫會讓 DRAM 和 NAND 的錯誤率上升。
這個案例我們仍在等待原廠的 NF1 韌體,後續有進展會再更新本文。如果你手上也有進入 ERRORMOD 的 Samsung 企業碟,在動手 Format 之前,歡迎先跟 OSSLab 聯繫評估。
