分層 SCSI 架構簡介
Small Computer Systems Interface (SCSI) 是一組标準集,它定義了與大量裝置(主要是與存儲相關的裝置)通信所需的接口和協定。 Linux 提供了一種 SCSI 子系統,用于與這些裝置通信。Linux 是分層架構的一個很好的例子,它将高層的驅動器(比如磁盤驅動器或光驅)連接配接到實體接口,比如 Fibre Channel 或 Serial Attached SCSI(SAS)。本文向您介紹了 Linux SCSI 子系統,并且讨論了這些子系統将來的發展方向。
GNU/Linux 和 SCSI 是很好的一個組合,因為二者在各自的環境中具有類似的特征。GNU/Linux 是一種安全可靠的作業系統,可以不間斷地運作。SCSI 适合于可靠和高性能存儲。二者都是開源的。您可以下載下傳和查閱 International Committee on Information Technology Standards (INCITS) T10 Technical Committee 的各種 SCSI 規範。同樣地,您也可以下載下傳 GNU/Linux 源代碼以了解其實作。它們在各自的行業都具有主導性,是以相對其他作業系統而言,GNU/Linux 能更好地支援 SCSI,這一點就不足為奇了。
SCSI 是一種很有趣的接口,它是早期的接口之一,如今還在不斷演化。第一種 SCSI 标準稱為 SCSI-1,是由 Shugart Associates 在 1979 年前後建立的。SCSI-1 定義了一種具有 5MHz 資料時鐘的 8-bit 并行接口,能提供最高 5 兆位元組每秒(5 MB/s)的資料傳輸速率。
SCSI-2 标準出現于 1985 年,它的出現使資料速率更快(10MHz),總線也更寬(16 位)。被稱為 Fast/Wide 的 SCSI-2 允許的資料傳輸速率高達 20 MB/s,并具有與 SCSI-1 的向後相容性,但是速率也會限制到 SCSI-1 的資料速率。
SCSI-3 的開發開始于 1993 年,現已成為了一組标準集,可以定義協定、指令集和信令方法。在 SCSI-3 中,包含一組命名為 Ultra 的并行 SCSI 标準和基于串行 SCSI 的協定,比如 IEEE 1394 (FireWire)、Fibre Channel, 、Internet SCSI (iSCSI) 和新興的 SAS。這些标準通過引入存儲網絡技術(比如 FC-AL 或 iSCSI)改變了傳統的存儲理念,将資料速率擴充到了 1 Gbit/s,将最大的可尋址裝置數增加到了 100 以上,并将最大的電纜長度擴充到了 25 米。圖 1 展示了從 1986 至 2007 年 SCSI 的資料速率的變化
圖 1. SCSI 資料速率的演化

SCSI 指令
SCSI 傳輸所采用的協定已經時過境遷,SCSI 指令卻保持了最初的元素。SCSI 指令是在 Command Descriptor Block (CDB) 中定義的。CDB 包含了用來定義要執行的特定操作的操作代碼,以及大量特定于操作的參數。
SCSI 指令支援讀寫資料(各有四個變量)以及很多非資料指令,比如 test-unit-ready(裝置是否已就緒)、inquiry(檢索有關目标裝置的基本資訊)、read-capacity(檢索目标裝置的存儲容量)等等。目标裝置支援何種指令取決于裝置的類型。發起者通過 inquiry 指令識别裝置類型。表 1 列出了最常用的 SCSI 指令。
表 1. 常見 SCSI 指令
指令 | 用途 |
---|---|
Test unit ready | 查詢裝置是否已經準備好進行傳輸 |
Inquiry | 請求裝置基本資訊 |
Request sense | 請求之前指令的錯誤資訊 |
Read capacity | 請求存儲容量資訊 |
Read | 從裝置讀取資料 |
Write | 向裝置寫入資料 |
Mode sense | 請求模式頁面(裝置參數) |
Mode select | 在模式頁面配置裝置參數 |
借助大約 60 種可用指令,SCSI 可适用于許多裝置(包括随機存取裝置,比如磁盤和像錄音帶這樣的順序儲存設備)。SCSI 也提供了專門的指令以通路箱體服務(比如存儲箱體内部目前的傳感和溫度)。
Linux 核心中的 SCSI 架構
圖 2 顯示了 SCSI 子系統在 Linux 核心中的位置。核心的頂部是系統調用接口,處理使用者空間調用到核心中合适的目的地的路由(例如 open、read 或 write)。而虛拟檔案系統(VFS) 是核心中支援的大多數檔案系統的抽象層。它負責将請求路由到合适的檔案系統。大多數檔案系統都通過緩沖區緩存來互相通信,這種緩存通過緩存最近使用的資料來優化對實體裝置的通路。接下來是塊裝置驅動器層,它包括針對底層裝置的各種塊驅動器。SCSI 子系統是這種塊裝置驅動器之一。
圖 2. SCSI 子系統在 Linux 核心中的位置
與 Linux 核心中的其他主流子系統不同,SCSI 子系統是一種分層的架構,共分為三層。頂部的那層叫做較高層,代表的是核心針對 SCSI 和主要裝置類型的驅動器的最高接口。接下來的是中間層,也稱為公共層或統一層。在這一層包含 SCSI 堆棧的較高層和較低層的一些公共服務。最後是較低層,代表的是适用于 SCSI 的實體接口的實際驅動器(參見圖 3)。
圖 3. Linux SCSI 子系統的分層架構
在 ./linux/drivers/scsi 可以找到 SCSI 子系統(SCSI 較高層、中間層和各種驅動器)的源代碼。SCSI 資料結構則位于 SCSI 源目錄,在 ./linux/include/scsi 也可以找到。
SCSI 較高層
SCSI 子系統的較高層代表的是核心(裝置級)最進階别的接口。它由一組驅動器組成,比如塊裝置(SCSI 磁盤和 SCSI CD-ROM)和字元裝置(SCSI 錄音帶和 SCSI generic)。較高層接受來自上層(比如 VFS)的請求并将其轉換成 SCSI 請求。較高層負責完成 SCSI 指令并将狀态資訊通知上層。
SCSI 磁盤驅動器在 ./linux/drivers/scsi/sd.c 内實作。SCSI 磁盤驅動器通過調用
register_blkdev
(作為塊驅動器)進行自初始化并通過
scsi_register_driver
提供一組函數以表示所有 SCSI 裝置。其中
sd_probe
和
sd_init_command
這兩個函數很重要。隻要有新的 SCSI 裝置附加到系統, SCSI 中間層就會調用
sd_probe
函數。
sd_probe
函數可決定此裝置是否由 SCSI 磁盤驅動器管理,如果是,就建立新的
scsi_disk
結構來表示它。
sd_init_command
函數将來自檔案系統層的請求轉變成 SCSI 讀或寫指令(為完成這個 I/O 請求,
sd_rw_intr
會被調用)。
SCSI 錄音帶驅動器在 ./linux/drivers/scsi/st.c 内實作。錄音帶驅動器是順序存取裝置,會通過
register_chrdev_region
将自身注冊為字元裝置。SCSI 錄音帶驅動器還提供了一個 probe 函數,稱為
st_probe
。該函數會建立一種新錄音帶裝置并将其添加到稱為
scsi_tapes
的向量。SCSI 錄音帶驅動器的獨特之處在于,如果可能,它可以直接從使用者空間執行 I/O 傳輸。否則,資料會通過驅動器緩沖被分段。
SCSI CD-ROM 驅動器在 ./linux/drivers/scsi/sr.c 内實作。CD-ROM 驅動器是另一種塊裝置并為 SCSI 磁盤驅動器提供類似的函數集。
sr_probe
函數可用來建立
scsi_sd
結構以表示 CD-ROM 裝置,并用
register_cdrom
注冊此 CD-ROM。SCSI 錄音帶驅動器還會導出
sr_init_command
,以将請求轉換成 SCSI CD-ROM 讀或寫請求。
SCSI generic 驅動器在 ./linux/drivers/scsi/sg.c 内實作。該驅動器允許使用者應用程式向裝置發送 SCSI 指令(比如格式化、模式感覺或診斷指令)。通過 sg3utils 包還可以從使用者空間利用 SCSI generic 驅動器。這個使用者空間包包括多種實用工具,可用來發送 SCSI 指令和解析這些指令的響應。
SCSI 中間層
SCSI 中間層是 SCSI 較高層和較低層的公共服務層(可以在 ./linux/drivers/scsi/scsi.c 内部分地實作)。它提供了很多可供較高層和較低層驅動器使用的函數,因而可以充當這兩層間的連接配接層。中間層很重要,原因是它抽象化了較低層驅動器(LLD)的實作,可以在 ./linux/drivers/scsi/hosts.c 中部分地實作。這意味着可以以同樣的方式使用帶不同接口的 Fibre Channel 主機總線擴充卡(HBA)。
低層驅動器注冊和錯誤處理都由 SCSI 中間層提供。中間層還提供了較高層和較低層間的 SCSI 指令排隊。SCSI 中間層的一個重要功能是将來自較高層的指令請求轉換成 SCSI 請求。它也負責管理特定于 SCSI 的錯誤恢複。
中間層可以連接配接 SCSI 子系統的較高層和較低層。它接受對 SCSI 事務的請求并對這些請求進行排隊以便處理 (如 ./linux/drivers/scsi/scsi_lib.c 中所示)。當這些指令完成後,它接受來自 LLD 的 SCSI 響應并通知較較高層此請求已經完成。
中間層最重要的職責之一是錯誤和逾時處理。如果 SCSI 指令沒有在合理的時間内完成或者 SCSI 請求傳回錯誤,中間層就會管理錯誤或重新發送此請求。中間層還可管理較高層恢複,比如請求 HBA (LLD) 或 SCSI 裝置重置。SCSI 錯誤和逾時處理程式在 ./linux/drivers/scsi/scsi_error.c 内實作。
SCSI 較低層
在最低層的是一組驅動器,稱為 SCSI 低層驅動器。它們是一些可與實體裝置(比如 HBA)連結的特定驅動器。LLD 提供了自公共中間層到特定于裝置的 HBA 的一種抽象。每個 LLD 都提供了到特定底層硬體的接口,但所使用的到中間層的接口卻是一組标準接口。
較低層包含大量代碼,原因是它要負責處理各種不同的 SCSI 擴充卡類型。例如,Fibre Channel 協定包含了針對 Emulex 和 QLogic 的各種擴充卡的 LLD。面向 Adaptec 和 LSI 的 SAS 擴充卡的 LLD 也包括在内。
Linux 和 SCSI 的未來展望
毫無疑問,SCSI 的發展前景很好,并且它會與 Linux 緊密相關。随着 SCSI 的演化,Linux 将會一如既往地為不斷發展的技術提供支援。Linux 借助面向 HBA 的驅動器為新的 SAS 協定提供支援。随着協定向更快的速度發展(比如 6 Gb SAS 或 8 Gb FC),Linux 必将處在發展和部署的前沿。
您還會發現 Linux 恰恰就是新 SCSI 協定的先進之處。FCoE(Fibre Channel over Ethernet)頗值得一提。FCoE 是全雙工 Ethernet 網絡(通常是 1Gb 或 10Gb Ethernet)上的一種 Fibre Channel 架構的映射。FCoE 之是以重要,是因為它将主流的網絡媒介與主流的企業存儲協定連接配接起來。這種新技術必然受人矚目,而且 Linux 也将不會例外。