阿呆實戰NVMe之五

2021-02-07 SSDFans



 

提要

 

我們知道,一般的SSD控制器裡面分為前端,核心,後端,如上圖是希捷收購的SandForce SF3700控制器的架構,三星不少SSD主控也是類似,三個部分分別用三個CPU管理。功能分別為:

所以,跟NVMe相關的是前端部分,從本文開始,我們正式進入NVMe內容,開發一個NVMe SSD控制器的前端協議邏輯。

 

前戲

 

 

記得去年阿呆家小呆呆還沒出生,有人忽悠阿呆說胎教很管用。阿呆開始每天背唐詩宋詞,晚上睡前隔著妹子肚皮背給娃聽。不知道他有沒有聽進去,阿呆卻發現原來詩詞意境這麼美,夜裡躺床上聽到雨滴落在別人家的雨篷上,滴滴答答,整個世界在春雨聲中安靜了,從耳朵到內心。我就想起老年的陸遊進京面見宋孝宗,在客店裡聽了一夜的春雨,折騰了大半輩子,他已經不相信有人會派他去收復河山了,反而閒情逸緻寫了首詩,果然宋孝宗找他也沒什麼事。不過那時候的人重視文化,陸遊寫的這首詩很快傳遍了臨安,傳進了皇宮,宋孝宗反覆誦讀,讚嘆不已。所以我建議各位讀者晚上回家少刷朋友圈,看看詩詞,這樣睡得更香,第二天看ssdfans就有精神。

 

臨安春雨初霽

 

年代: 宋 作者: 陸遊

 

世味年來薄似紗,誰令騎馬客京華。

小樓一夜聽春雨,深巷明朝賣杏花。

矮紙斜行閒作草,晴窗細乳戲分茶。

素衣莫起風塵嘆,猶及清明可到家。

 

最近老是貼代碼,有點枯燥,蛋蛋沒有工作後休息的這幾周ssdfans公眾號訂閱人數增量看來不能達標了,希望大家多看看精華文章,分享一下蛋蛋的精品。不過別擔心,往後不會貼那麼多代碼了(這是真的嗎?)。

 

不知上次阿呆提醒之後,你有沒有掃一下《蛋蛋讀NVMe之x》系列文章,尤其是最後一篇。從本篇起我們要進入NVMe相關的內容了,冒出個名詞你得有心理準備,比如namespace,這個是《蛋蛋讀NVMe之六》裡面提到的。說牛逼一點,我們要開始做一件激動人心的事:開發一個NVMe  Controller了!儘管這個過程比較枯燥,但是只要你耐心看完,就一定有收穫。畢竟理論聯繫實踐才是王道。

 

NVMEState

 

今天的任務不重,只是看看NVMEState這個NVMe設備的數據結構。治大國如烹小鮮,NVMe協議很龐雜,但只要我們讀透NVMe的數據結構這把刀,後面看代碼就如庖丁解牛般遊刃有餘。

 

typedef
struct NVMEState {

   PCIDevice dev;


int mmio_index;


void
*bar0;


int bar0_size;

   uint8_t nvectors;

 


/* Space for NVME Ctrl Space except doorbells */

   uint8_t *cntrl_reg;


/* Masks for NVME Ctrl Registers */

   uint8_t *rw_mask;
/* RW/RO mask */

   uint8_t *rwc_mask;
/* RW1C mask */

   uint8_t *rws_mask;
/* RW1S mask */

   uint8_t *used_mask;
/* Used/Resv mask */

 


struct nvme_features feature;

 

   NVMEIOCQueue cq[NVME_MAX_QS_ALLOCATED];

   NVMEIOSQueue sq[NVME_MAX_QS_ALLOCATED];

 

   DiskInfo *disk;

   uint32_t ns_size;

   uint32_t num_namespaces;

   uint32_t instance;

 

   time_t start_time;

 


/* Used to store the AQA,ASQ,ACQ between resets */


struct AQState aqstate;

 


/* TODO

    * These pointers have been defined since

    * present code uses the older defined strucutres

    * which has been replaced by pointers.

    * Once each and every reference is replaced by

    * offset from cntrl_reg, remove these pointers

    * becasue bit field structures are not portable

    * especially when the memory locations of the bit fields

    * have importance

    */

   NVMECtrlCap *ctrlcap;

   NVMEVersion *ctrlv;

   NVMECtrlConf *cconf;
/* Ctrl configuration */

   NVMECtrlStatus *cstatus;
/* Ctrl status */

   NVMEAQA *admqattrs;
/* Admin queues attributes. */

 

   QEMUTimer *sq_processing_timer;

   int64_t sq_processing_timer_target;


/* Used for PIN based and MSI interrupts */

   uint32_t intr_vect;


/* Page Size used by the hardware */

   uint32_t page_size;


/* Pointer to Identify Controller Strucutre */

   NVMEIdentifyController *idtfy_ctrl;


/* Pointer to Firmware slot info log page */

   NVMEFwSlotInfoLog fw_slot_log;

   uint8_t last_fw_slot;

 

   uint8_t temp_warn_issued;

 

   QEMUTimer *async_event_timer;

 

   uint16_t async_cid[ASYNC_EVENT_REQ_LIMIT +
1];

   uint16_t outstanding_asyncs;

 

   QSIMPLEQ_HEAD(async_queue, AsyncEvent) async_queue;


/* Masks for async event requests */

   uint8_t err_sts_mask;
/* error status event mask */

   uint8_t smart_mask;
/* smart/health status event mask */

} NVMEState;

 

一個個來看。

PCIDevice dev

int mmio_index

void
*bar0

int bar0_size

uint8_t nvectors

uint8_t *cntrl_reg

顧名思義,這就是NVMe的控制寄存器指針了。後面四個小兄弟是寄存器的MASK,啥意思,就是每個bit加了個限制。

   uint8_t *rw_mask;
/* RW/RO mask */ 可讀寫或只讀

   uint8_t *rwc_mask;
/* RW1C mask */ 寫1清零

   uint8_t *rws_mask;
/* RW1S mask */ 寫1置1

   uint8_t *used_mask;
/* Used/Resv mask */ 是否在用

 

struct nvme_features {

   uint32_t arbitration;

   uint32_t power_management;

   uint32_t LBA_range_type;
/* uses memory buffer */

   uint32_t temperature_threshold;

   uint32_t error_recovery;

   uint32_t volatile_write_cache;

   uint32_t number_of_queues;

   uint32_t interrupt_coalescing;

   uint32_t interrupt_vector_configuration;

   uint32_t write_atomicity;

   uint32_t asynchronous_event_configuration;

   uint32_t software_progress_marker;

};

 

   NVMEIOSQueue sq[NVME_MAX_QS_ALLOCATED];

   uint32_t num_namespaces;

    namespace大小和個數。不知道namespace為何物的請查看精華文章,查看《蛋蛋讀NVMe之六》。

 

 

 

   NVMEVersion *ctrlv;

   NVMECtrlConf *cconf;
/* Ctrl configuration */

   NVMECtrlStatus *cstatus;
/* Ctrl status */

   NVMEAQA *admqattrs;
/* Admin queues attributes. */

    這是NVMe設備5個寄存器的指針,設備初始化的時候把寄存器內存地址賦給它們。不過注釋裡也說了,這種指針表示法可移植性差。以後會直接用控制寄存器的偏移來訪問。

 

   int64_t sq_processing_timer_target;

    sq_processing_timer是處理SQ所用的timer,裡面註冊了回調函數,sq_processing_timer_target是觸發timer的時間,當時間到了target之後,timer裡面註冊的回調函數就會被調用。timer的用途很廣,比如讓NVMe控制器定期處理SQ隊列裡的新命令,就可以每次檢查完把target設置為一定時間以後再次觸發,這樣無窮無盡循環下去。

 

uint32_t intr_vect;

NVMe設備中斷向量。

 

uint32_t page_size;

NVMe控制器和Host數據交互的頁大小。

 

NVMe控制器Identify Controller的指針。裡面就是設備相關的一些參數,比如vendor id, subsystem vendor id等,具體定義請參考NVM Express 1.0b Chapter 5.11 Identify command。

 

NVMe控制器Firmware slot info log的指針。裡面是固件相關的一些參數,比如固件版本。last_fw_slot是上次固件的slot值。

 

 

QEMUTimer *async_event_timer;

uint16_t async_cid[ASYNC_EVENT_REQ_LIMIT +
1];

uint16_t outstanding_asyncs;

QSIMPLEQ_HEAD(async_queue, AsyncEvent) async_queue;

 

這又是一個timer,搞蝦米用的呢?顧名思義,NVMe Admin命令有一個叫Asynchronous Event Request,這個timer就是為這類異步請求設置的。Host有時候給NVMe控制器打招呼:小弟,有個人幫大哥盯著,出現了就報告。NVMe小弟趕快記下來,就是這個異步事件,有空了就留心一下。初始化註冊回調函數,事件發生了就會調用回調函數。不相信?請看《蛋蛋讀NVMe之一》,阿呆幫你把圖貼過來。async_cid是異步請求的command id。outstanding_asyncs是NVMe控制器還沒完成的異步事件數。async_queue就是異步事件隊列。


uint8_t err_sts_mask;
/* error status event mask */

   uint8_t smart_mask;
/* smart/health status event mask */

    當NVMe出現了error或者smart事件,對應的mask置1.

 

你是不是還很疑惑PCI的bar和mmio到底是怎麼用的?下期為你解惑。

 

引用

 

https://github.com/nvmeqemu

微信搜索ssdfans,掃描或長按下面二維碼圖片關注ssdfans微信公眾號,每天看一篇SSD好文!

你想在SSD領域積累更多人脈、學習核心技術、掌握最新動態?我們建了一個微信群,方便SSD Fans們討論SSD,快閃記憶體和存儲相關的話題。群友既包括各大公司SSD、存儲方面的技術精英,行業大牛,也有很多SSD愛好者。歡迎各位SSD行業人士、使用者和愛好者加入,謝絕獵頭,廣告(可聯繫contact@ssdfans.com通過公眾平臺發布)。 加入後請修改暱稱為:姓名(或暱稱)-公司(或領域)-職業例如:張三-Marvell-SSD FW QA蛋蛋-SSD Controller-FW開發微信加nanoarch為好友拉你入群。
轉載請註明來自SSD技術學習網,本文地址:http://www.ssdfans.com/?p=2092除非註明,SSD Fans網站文章均為原創,歡迎轉載,轉載必須註明出處,作者和連結,並保留二維碼圖片!

相關焦點

  • 阿呆實戰NVMe之九
    萬事開頭難,前面我們花了8篇文章來寫NVMe在QEMU中的初始化,一方面說明初始化的重要和瑣碎,另一方面也暴露了阿呆的水平不夠,要是真完全掌握的人必然是高屋建瓴,言簡意賅。阿呆學藝不精,只能一個函數一個函數來帶你逛NVMe的集市了。 本篇我們來看看NVMe設備在QEMU的Doorbell如何實現,探探蛋蛋說過的大寶,阿呆改名成貼心暖男——大白。
  • 阿呆實戰NVMe之一:QEMU和KVM
    其實阿呆也沒跑過分,只知道蛋蛋家族有高智商基因,出了不少高考狀元。鄉親們因為有了這樣一家鄰居,教育孩子不得不格外賣力氣: 天賦不如人已經輸在了起跑線上,後天可得加倍努力啊! 阿呆以前搞不懂NVMe,都是英文文檔,好不容易看完也不能消化,花個把星期很多也是雲裡霧裡。但是,看了蛋蛋寫的NVMe系列,通俗易懂,最多半天就能掌握精髓。
  • 《阿呆的世界》第一季48
    大家是怎麼了,為什麼都這樣帶著莫名的欣喜之色看著我,難道說我做了什麼好事自己卻不知道嗎?還是說本小姐精神分裂了,其實晚上都在像超級英雄一樣行俠仗義?拜託,真希望老天別作弄我了,我真是受不了四周那猶如發現了蜘蛛俠真實身份的那個個表情。「季節同學!你真是太厲害了,想不到你竟然會是Tellnow!」一個我不認識的女孩從我面前穿過和我熱情地打了個招呼。
  • 《阿呆的世界》第一季61
    閱讀之前的章節請【關注公眾號】點擊菜單中【阿呆的世界】鄭重聲明:
  • NVMe學習筆記8 NVMe設備驅動
    其他的文件包括zns和lightnvm我們之前都有提到過(Zoned Namespace的簡單介紹 和 Open Channel SSD和lightNVM(1)),這裡僅僅就nvme標準設備的初始化和基本操作對照nvme spec進行學習了解。
  • Linux nvme驅動初探
    塊層多隊列之引入內核),小編的SUSE 11.3也正好能編譯這個相對比較低的版本。(隨後再看最新版本內核上nvme驅動的實現)通過nvme_alloc_ns可知,nvme設備通過nvme_make_request()函數進入快層:nvme_alloc_ns() blk_queue_make_request(ns->queue, nvme_make_request);快速看一下nvme_make_request
  • NVMe驅動之I/O請求詳解
    創建NVMe Queue驅動程序在創建隊列之前首先通過內核函數num_online_cpus獲取當前系統中運行的CPU數量m,然後通過nvme_set_queue_count對於Submission Queue來說,使用Tail表示最後操作的Command Index(nvmeq->sq_tail)。每存入一個Command,Host就會更新Queue對應的Doorbell寄存器中的Tail值。Doorbell定義在BAR空間,通過QID可以索引到。
  • NVMe驅動解析-註冊設備
    nvme驅動中,將010802h放入pci_driver nvme_driver的id_table,之後當nvme_driver註冊到PCI Bus後,PCI Bus就知道這個驅動是給class code=010802h的設備使用的。這裡還有一個地方值得注意,nvme_driver中還有一個probe函數,nvme_probe(),這個函數才是真正加載設備的處理函數。
  • 實戰pynvme
    首先下載原始碼:git clone https://github.com/cranechu/pynvme然後編譯:cd pynvme./install.sh最終能得到類似nvme.cpython-37m-x86_64-linux-gnu.so的二進位庫文件,我們稱之為nvme驅動庫。
  • NVMe驅動解析-DMA傳輸
    NVMe Command的DMA地址分配NVMe驅動中分配NVMe queue的函數nvme_alloc_queue(),其中用來存放Completion Command( nvmeq->cqes )和Submit Command ( nvmeq->sq_cmds )的地址都是通過內核函數dma_alloc_coherent()分配的。
  • nvme固態硬碟需要加裝散熱嗎?
    ~       如今nvme固態硬碟的價格已經相當親民,幾乎成為裝機的標配,細心的用戶可能會發現,nvme固態硬碟在運行時的溫度要比sata固態硬碟高,因此一些用戶會考慮給nvme固態硬碟加裝散熱片,那麼對於nvme固態硬碟加裝散熱到底有沒有必要呢?         一、為什麼nvme固態硬碟的溫度會更高?
  • NVMe接口學習筆記4 其餘數據結構
    Nvme 的drive也很好寫:731 static irqreturn_t nvme_process_cq(struct nvme_queue *nvmeq)732 {733         u16 head, phase;734 735         head = nvmeq->cq_head;
  • NVME高速固態 安裝win7系統圖文說明.
    大家都知道或者有了解過,nvme固態硬碟為什麼不能安裝win7和win8系統,原因聽起來很簡單也就下面三點內容。       第一、因為Win7沒有集成USB3驅動,如今清一色XHCI-USB控制器的新款晶片組主板裝Win7很可能會無法識別鍵鼠,以及無法識別U盤安裝盤,而新主板往往沒有PS2接口,導致難以安裝Win7系統!
  • PCIe Switch之SR-IOV
    作者:阿呆 SR-IOV只有一個根想要和
  • 使用 Linux 命令行工具來了解你的 NVMe 驅動器 | Linux 中國
    它被稱為 nvme-cli🔗 github.com。安裝 nvme-cli你可以從你的發行版的包管理器中安裝 nvme-cli。例如,在 Fedora、CentOS 或類似系統上:$ sudo dnf install nvme-cli在 Debian、Mint、Elementary 和類似系統上:$ sudo apt install nvme-cli探索 NVMe 驅動器在安裝 nvme-cli 後,我想探索我的驅動器。
  • 安裝win7系統怎麼注入USB3.0驅動和NVME驅動
    現在安裝win7系統經常有網友遇到usb3.0設備不能使用和nvme固態硬碟安裝win7出現藍屏的問題,為什麼會出現這些問題呢,下面就給大家講下為什麼會出現這些情況以及安裝
  • 眾神之戰-大亂鬥(二)
    在四座山峰上,阿呆,雷翔,海龍,唐三,他們四人相立對望,眼神中儘是決然,唐三率先開口,道:「各位,對不起,為了小舞,我必須全力以赴。」海龍看向唐三,目光閃爍,道:「唐三,你是我第三個可以讓我心服口服的人,但多說無益,我們拳腳上見真章。」可是當海龍話音剛落,山峰腳下閃耀起了璀璨的金色的光芒,唐三嘴角微微上揚,道:「來的真是時候。」此人是誰?
  • 硬體資訊 | NVMe 2.0 規範標準正式發布:新增支持 HDD 機械硬碟
    本文轉自IT之家,作者玄隱。外媒報導,NVM Express(NVMe)聯盟今天正式推出了最新的 NVMe 規範 2.0 版本。
  • 逆向入門分析實戰(五)
    文章共計1549個詞預計閱讀8分鐘來和我一起閱讀吧相關閱讀:逆向入門分析實戰