首先nvme sq和cq基础知识需要知道以下几点:
(1)sq 和 cq 分别作为command request 和command response 存取的地方;
nvme 中发送command request 和 command response,都采用queue机制,host 发送command 使用SQ(submission queue), controller 返回command response状态使用CQ(completion queue)。每个SQ 最大能放(sq_depth-1)个command request entry,每个CQ最多能放(cq_depth-1)个command response entry.
(2)sq 和 cq 都是放在一个存储空间的,可以是host 分配的一块存储空间,也可以是controller 上划分出来的DRAM空间。
(3)sq 和 cq 结对使用, 一个sq只能指定一个cq与其绑定,多个sq可以与同一个cq绑定。
(4)nvme分为admin queue和 IO queue
admin queue 的sq与cq是一一对应,其创建不需要发送command来,只需要分配空间,并把admin sq,cq基地址告知controller,IO sq,cq则通过admin queue 来创建和删除。
sq,cq是如何判断满与空机制
必须要说明的是,sq和cq 分别判断满与空的机制不一样
(1)对于sq ,采用head 与 tail 比较
根据生产者-消费者模式,head 表示下一次消费者要消耗entry的index, tail 表示下一次生产者产生的entry要存放的index.
queue empty
当head == tail的时候,下一次要消耗entry的index 等于下一次生产者产生entry存放的index时,也就是空
queue full
首先要指出:预留位置为reserv = head - 1,是不使用的。
当head == tail + 1时,表示预留的entry的下一个index 的就是head,也就是满
(2)对于cq,采用的是phase tag
cq的每一个entry有一个专门的bit,host 与controller会协商好,host会给每个cq维护一个phase tag, 两边都将phase 初始状态是该bit是0, controller返回一个cq entry时,会将phase tag 翻转,表示一个新entry,需要host 去处理,host 就是根据自己维护的phase tag与cq中的每一个entry的phase tag比较,如果不相等,表示是一个新的entry,当cq的tail 翻转到queue的最开始时,host 和controller 都将phase tag bit 反转,这样第二轮controller push command 到cq, 每个新到的entry的 phase tag bit 是 0 。这样host 就知道需要哪些entry,