Linux SCSI 子系統(tǒng)剖析
Small Computer Systems Interface (SCSI) 是一組標(biāo)準(zhǔn)集,它定義了與大量設(shè)備(主要是與存儲(chǔ)相關(guān)的設(shè)備)通信所需的接口和協(xié)議。 Linux® 提供了一種 SCSI 子系統(tǒng),用于與這些設(shè)備通信。Linux 是分層架構(gòu)的一個(gè)很好的例子,它將高層的驅(qū)動(dòng)器(比如磁盤驅(qū)動(dòng)器或光驅(qū))連接到物理接口,比如 Fibre Channel 或 Serial Attached SCSI(SAS)。本文向您介紹了 Linux SCSI 子系統(tǒng),并且討論了這些子系統(tǒng)將來的發(fā)展方向。
GNU/Linux 和 SCSI 是很好的一個(gè)組合,因?yàn)槎咴诟髯缘沫h(huán)境中具有類似的特征。GNU/Linux 是一種安全可靠的操作系統(tǒng),可以不間斷地運(yùn)行。SCSI 適合于可靠和高性能存儲(chǔ)。二者都是開源的。您可以下載和查閱 International Committee on Information Technology Standards (INCITS) T10 Technical Committee 的各種 SCSI 規(guī)范。同樣地,您也可以下載 GNU/Linux 源代碼以理解其實(shí)現(xiàn)。它們?cè)诟髯缘男袠I(yè)都具有主導(dǎo)性,所以相對(duì)其他操作系統(tǒng)而言,GNU/Linux 能更好地支持 SCSI,這一點(diǎn)就不足為奇了。
SCSI 的演化
SCSI 是一種很有趣的接口,它是早期的接口之一,如今還在不斷演化。第一種 SCSI 標(biāo)準(zhǔn)稱為 SCSI-1,是由 Shugart Associates 在 1979 年前后創(chuàng)建的。SCSI-1 定義了一種具有 5MHz 數(shù)據(jù)時(shí)鐘的 8-bit 并行接口,能提供最高 5 兆字節(jié)每秒(5 MB/s)的數(shù)據(jù)傳輸速率。
SCSI-2 標(biāo)準(zhǔn)出現(xiàn)于 1985 年,它的出現(xiàn)使數(shù)據(jù)速率更快(10MHz),總線也更寬(16 位)。被稱為 Fast/Wide 的 SCSI-2 允許的數(shù)據(jù)傳輸速率高達(dá) 20 MB/s,并具有與 SCSI-1 的向后兼容性,但是速率也會(huì)限制到 SCSI-1 的數(shù)據(jù)速率。
SCSI-3 的開發(fā)開始于 1993 年,現(xiàn)已成為了一組標(biāo)準(zhǔn)集,可以定義協(xié)議、命令集和信令方法。在 SCSI-3 中,包含一組命名為 Ultra 的并行 SCSI 標(biāo)準(zhǔn)和基于串行 SCSI 的協(xié)議,比如 IEEE 1394 (FireWire)、Fibre Channel, 、Internet SCSI (iSCSI) 和新興的 SAS。這些標(biāo)準(zhǔn)通過引入存儲(chǔ)網(wǎng)絡(luò)技術(shù)(比如 FC-AL 或 iSCSI)改變了傳統(tǒng)的存儲(chǔ)理念,將數(shù)據(jù)速率擴(kuò)展到了 1 Gbit/s,將最大的可尋址設(shè)備數(shù)增加到了 100 以上,并將最大的電纜長(zhǎng)度擴(kuò)展到了 25 米。圖 1 展示了從 1986 至 2007 年 SCSI 的數(shù)據(jù)速率的變化
圖1SCSI 數(shù)據(jù)速率的演化
SCSI 工作原理
SCSI 實(shí)現(xiàn)了一種客戶機(jī)/服務(wù)器風(fēng)格的通信架構(gòu)。發(fā)起者向目標(biāo)設(shè)備發(fā)送命令請(qǐng)求。該目標(biāo)處理此請(qǐng)求并向發(fā)起者返回響應(yīng)。發(fā)起者可以是托管計(jì)算機(jī)中的一個(gè) SCSI 設(shè)備,而 SCSI 目標(biāo)則可以是一個(gè)磁盤、光盤和磁帶設(shè)備或特殊設(shè)備(比如箱體設(shè)備)。
SCSI 命令
SCSI 傳輸所采用的協(xié)議已經(jīng)時(shí)過境遷,SCSI 命令卻保持了最初的元素。SCSI 命令是在 Command Descriptor Block (CDB) 中定義的。CDB 包含了用來定義要執(zhí)行的特定操作的操作代碼,以及大量特定于操作的參數(shù)。
SCSI 命令支持讀寫數(shù)據(jù)(各有四個(gè)變量)以及很多非數(shù)據(jù)命令,比如 test-unit-ready(設(shè)備是否已就緒)、inquiry(檢索有關(guān)目標(biāo)設(shè)備的基本信息)、read-capacity(檢索目標(biāo)設(shè)備的存儲(chǔ)容量)等等。目標(biāo)設(shè)備支持何種命令取決于設(shè)備的類型。發(fā)起者通過 inquiry 命令識(shí)別設(shè)備類型。表 1 列出了最常用的 SCSI 命令。
表 1. 常見 SCSI 命令
命令 用途
Test unit ready 查詢?cè)O(shè)備是否已經(jīng)準(zhǔn)備好進(jìn)行傳輸
Inquiry 請(qǐng)求設(shè)備基本信息
Request sense 請(qǐng)求之前命令的錯(cuò)誤信息
Read capacity 請(qǐng)求存儲(chǔ)容量信息
Read 從設(shè)備讀取數(shù)據(jù)
Write 向設(shè)備寫入數(shù)據(jù)
Mode sense 請(qǐng)求模式頁面(設(shè)備參數(shù))
Mode select 在模式頁面配置設(shè)備參數(shù)
借助大約 60 種可用命令,SCSI 可適用于許多設(shè)備(包括隨機(jī)存取設(shè)備,比如磁盤和像磁帶這樣的順序存儲(chǔ)設(shè)備)。SCSI 也提供了專門的命令以訪問箱體服務(wù)(比如存儲(chǔ)箱體內(nèi)部當(dāng)前的傳感和溫度)。更多信息,請(qǐng)參見 參考資料 部分。
Linux 內(nèi)核中的 SCSI 架構(gòu)
圖2 顯示了 SCSI 子系統(tǒng)在 Linux 內(nèi)核中的位置。內(nèi)核的頂部是系統(tǒng)調(diào)用接口,處理用戶空間調(diào)用到內(nèi)核中合適的目的地的路由(例如 open、read 或 write)。而虛擬文件系統(tǒng)(VFS) 是內(nèi)核中支持的大多數(shù)文件系統(tǒng)的抽象層。它負(fù)責(zé)將請(qǐng)求路由到合適的文件系統(tǒng)。大多數(shù)文件系統(tǒng)都通過緩沖區(qū)緩存來相互通信,這種緩存通過緩存最近使用的數(shù)據(jù)來優(yōu)化對(duì)物理設(shè)備的訪問。接下來是塊設(shè)備驅(qū)動(dòng)器層,它包括針對(duì)底層設(shè)備的各種塊驅(qū)動(dòng)器。SCSI 子系統(tǒng)是這種塊設(shè)備驅(qū)動(dòng)器之一。
圖 2. SCSI 子系統(tǒng)在 Linux 內(nèi)核中的位置
與 Linux 內(nèi)核中的其他主流子系統(tǒng)不同,SCSI 子系統(tǒng)是一種分層的架構(gòu),共分為三層。頂部的那層叫做較高層,代表的是內(nèi)核針對(duì) SCSI 和主要設(shè)備類型的驅(qū)動(dòng)器的最高接口。接下來的是中間層,也稱為公共層或統(tǒng)一層。在這一層包含 SCSI 堆棧的較高層和較低層的一些公共服務(wù)。最后是較低層,代表的是適用于 SCSI 的物理接口的實(shí)際驅(qū)動(dòng)器(參見圖 3)。
圖 3. Linux SCSI 子系統(tǒng)的分層架構(gòu)
在 ./linux/drivers/scsi 可以找到 SCSI 子系統(tǒng)(SCSI 較高層、中間層和各種驅(qū)動(dòng)器)的源代碼。SCSI 數(shù)據(jù)結(jié)構(gòu)則位于 SCSI 源目錄,在 ./linux/include/scsi 也可以找到。
SCSI 較高層
SCSI 子系統(tǒng)的較高層代表的是內(nèi)核(設(shè)備級(jí))最高級(jí)別的接口。它由一組驅(qū)動(dòng)器組成,比如塊設(shè)備(SCSI 磁盤和 SCSI CD-ROM)和字符設(shè)備(SCSI 磁帶和 SCSI generic)。較高層接受來自上層(比如 VFS)的請(qǐng)求并將其轉(zhuǎn)換成 SCSI 請(qǐng)求。較高層負(fù)責(zé)完成 SCSI 命令并將狀態(tài)信息通知上層。
SCSI 磁盤驅(qū)動(dòng)器在 ./linux/drivers/scsi/sd.c 內(nèi)實(shí)現(xiàn)。SCSI 磁盤驅(qū)動(dòng)器通過調(diào)用 register_blkdev(作為塊驅(qū)動(dòng)器)進(jìn)行自初始化并通過 scsi_register_driver 提供一組函數(shù)以表示所有 SCSI 設(shè)備。其中 sd_probe 和 sd_init_command 這兩個(gè)函數(shù)很重要。只要有新的 SCSI 設(shè)備附加到系統(tǒng), SCSI 中間層就會(huì)調(diào)用 sd_probe 函數(shù)。sd_probe 函數(shù)可決定此設(shè)備是否由 SCSI 磁盤驅(qū)動(dòng)器管理,如果是,就創(chuàng)建新的 scsi_disk 結(jié)構(gòu)來表示它。sd_init_command 函數(shù)將來自文件系統(tǒng)層的請(qǐng)求轉(zhuǎn)變成 SCSI 讀或?qū)懨睿橥瓿蛇@個(gè) I/O 請(qǐng)求,sd_rw_intr 會(huì)被調(diào)用)。
SCSI 磁帶驅(qū)動(dòng)器在 ./linux/drivers/scsi/st.c 內(nèi)實(shí)現(xiàn)。磁帶驅(qū)動(dòng)器是順序存取設(shè)備,會(huì)通過 register_chrdev_region 將自身注冊(cè)為字符設(shè)備。SCSI 磁帶驅(qū)動(dòng)器還提供了一個(gè) probe 函數(shù),稱為 st_probe。該函數(shù)會(huì)創(chuàng)建一種新磁帶設(shè)備并將其添加到稱為 scsi_tapes 的向量。SCSI 磁帶驅(qū)動(dòng)器的獨(dú)特之處在于,如果可能,它可以直接從用戶空間執(zhí)行 I/O 傳輸。否則,數(shù)據(jù)會(huì)通過驅(qū)動(dòng)器緩沖被分段。
SCSI CD-ROM 驅(qū)動(dòng)器在 ./linux/drivers/scsi/sr.c 內(nèi)實(shí)現(xiàn)。CD-ROM 驅(qū)動(dòng)器是另一種塊設(shè)備并為 SCSI 磁盤驅(qū)動(dòng)器提供類似的函數(shù)集。sr_probe 函數(shù)可用來創(chuàng)建 scsi_sd 結(jié)構(gòu)以表示 CD-ROM 設(shè)備,并用 register_cdrom 注冊(cè)此 CD-ROM。SCSI 磁帶驅(qū)動(dòng)器還會(huì)導(dǎo)出 sr_init_command,以將請(qǐng)求轉(zhuǎn)換成 SCSI CD-ROM 讀或?qū)懻?qǐng)求。
SCSI generic 驅(qū)動(dòng)器在 ./linux/drivers/scsi/sg.c 內(nèi)實(shí)現(xiàn)。該驅(qū)動(dòng)器允許用戶應(yīng)用程序向設(shè)備發(fā)送 SCSI 命令(比如格式化、模式感知或診斷命令)。通過 sg3utils 包還可以從用戶空間利用 SCSI generic 驅(qū)動(dòng)器。這個(gè)用戶空間包包括多種實(shí)用工具,可用來發(fā)送 SCSI 命令和解析這些命令的響應(yīng)。
SCSI 中間層
SCSI 中間層是 SCSI 較高層和較低層的公共服務(wù)層(可以在 ./linux/drivers/scsi/scsi.c 內(nèi)部分地實(shí)現(xiàn))。它提供了很多可供較高層和較低層驅(qū)動(dòng)器使用的函數(shù),因而可以充當(dāng)這兩層間的連接層。中間層很重要,原因是它抽象化了較低層驅(qū)動(dòng)器(LLD)的實(shí)現(xiàn),可以在 ./linux/drivers/scsi/hosts.c 中部分地實(shí)現(xiàn)。這意味著可以以同樣的方式使用帶不同接口的 Fibre Channel 主機(jī)總線適配器(HBA)。
低層驅(qū)動(dòng)器注冊(cè)和錯(cuò)誤處理都由 SCSI 中間層提供。中間層還提供了較高層和較低層間的 SCSI 命令排隊(duì)。SCSI 中間層的一個(gè)重要功能是將來自較高層的命令請(qǐng)求轉(zhuǎn)換成 SCSI 請(qǐng)求。它也負(fù)責(zé)管理特定于 SCSI 的錯(cuò)誤恢復(fù)。
中間層可以連接 SCSI 子系統(tǒng)的較高層和較低層。它接受對(duì) SCSI 事務(wù)的請(qǐng)求并對(duì)這些請(qǐng)求進(jìn)行排隊(duì)以便處理 (如 ./linux/drivers/scsi/scsi_lib.c 中所示)。當(dāng)這些命令完成后,它接受來自 LLD 的 SCSI 響應(yīng)并通知較較高層此請(qǐng)求已經(jīng)完成。
中間層最重要的職責(zé)之一是錯(cuò)誤和超時(shí)處理。如果 SCSI 命令沒有在合理的時(shí)間內(nèi)完成或者 SCSI 請(qǐng)求返回錯(cuò)誤,中間層就會(huì)管理錯(cuò)誤或重新發(fā)送此請(qǐng)求。中間層還可管理較高層恢復(fù),比如請(qǐng)求 HBA (LLD) 或 SCSI 設(shè)備重置。SCSI 錯(cuò)誤和超時(shí)處理程序在 ./linux/drivers/scsi/scsi_error.c 內(nèi)實(shí)現(xiàn)。
SCSI 較低層
在最低層的是一組驅(qū)動(dòng)器,稱為 SCSI 低層驅(qū)動(dòng)器。它們是一些可與物理設(shè)備(比如 HBA)鏈接的特定驅(qū)動(dòng)器。LLD 提供了自公共中間層到特定于設(shè)備的 HBA 的一種抽象。每個(gè) LLD 都提供了到特定底層硬件的接口,但所使用的到中間層的接口卻是一組標(biāo)準(zhǔn)接口。
較低層包含大量代碼,原因是它要負(fù)責(zé)處理各種不同的 SCSI 適配器類型。例如,F(xiàn)ibre Channel 協(xié)議包含了針對(duì) Emulex 和 QLogic 的各種適配器的 LLD。面向 Adaptec 和 LSI 的 SAS 適配器的 LLD 也包括在內(nèi)。
Linux 和 SCSI 的未來展望
毫無疑問,SCSI 的發(fā)展前景很好,并且它會(huì)與 Linux 緊密相關(guān)。隨著 SCSI 的演化,Linux 將會(huì)一如既往地為不斷發(fā)展的技術(shù)提供支持。Linux 借助面向 HBA 的驅(qū)動(dòng)器為新的 SAS 協(xié)議提供支持。隨著協(xié)議向更快的速度發(fā)展(比如 6 Gb SAS 或 8 Gb FC),Linux 必將處在發(fā)展和部署的前沿。
您還會(huì)發(fā)現(xiàn) Linux 恰恰就是新 SCSI 協(xié)議的先進(jìn)之處。FCoE(Fibre Channel over Ethernet)頗值得一提。FCoE 是全雙工 Ethernet 網(wǎng)絡(luò)(通常是 1Gb 或 10Gb Ethernet)上的一種 Fibre Channel 框架的映射。FCoE 之所以重要,是因?yàn)樗鼘⒅髁鞯木W(wǎng)絡(luò)媒介與主流的企業(yè)存儲(chǔ)協(xié)議連接起來。這種新技術(shù)必然受人矚目,而且 Linux 也將不會(huì)例外。
針對(duì) SCSI 的端到端數(shù)據(jù)保護(hù)也在開發(fā)中,它源于 T10 的新數(shù)據(jù)完整性標(biāo)準(zhǔn)。這個(gè)標(biāo)準(zhǔn)為每扇區(qū)都增加了一個(gè)數(shù)據(jù)完整性字段(DIF)以保護(hù)介質(zhì)上的數(shù)據(jù)。這個(gè)新的 8 字節(jié) DIF 字段包括一個(gè)循環(huán)冗余代碼(CRC)用以保護(hù)數(shù)據(jù),一個(gè)參考標(biāo)簽用以保護(hù)數(shù)據(jù)免遭誤導(dǎo)寫入,以及一個(gè)應(yīng)用程序標(biāo)簽。應(yīng)用程序標(biāo)簽特定于應(yīng)用程序,并且可以定義數(shù)據(jù)的用途,例如,一個(gè) PDF 文件的一部分。請(qǐng)參見 參考資料 部分以獲取更多信息。
結(jié)束語
Linux 內(nèi)核是抽象的分層結(jié)構(gòu)的另一個(gè)典型示例。它將各種文件系統(tǒng)連接到不同的物理存儲(chǔ)介質(zhì)。若這些存儲(chǔ)介質(zhì)與 SCSI 相關(guān),SCSI 子系統(tǒng)會(huì)將公共 Linux 塊請(qǐng)求轉(zhuǎn)化為針對(duì)特定底層設(shè)備的 SCSI 請(qǐng)求。SCSI 子系統(tǒng)本身在過去若干年中經(jīng)歷了很多變化,而且這些變化還在繼續(xù)。諸如端到端數(shù)據(jù)保護(hù)這樣的新技術(shù),與 FCoE 這樣的新協(xié)議一樣,都在想方設(shè)法尋找與 Linux 建立關(guān)系的途徑。
評(píng)論