Linux 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 目標則可以是一個磁盤、光盤和磁帶設備或特殊設備(比如箱體設備)。






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 也提供了專門的命令以訪問箱體服務(比如存儲箱體內部當前的傳感和溫度)。更多信息,請參見 參考資料 部分。






圖 2 顯示了 SCSI 子系統在 Linux 內核中的位置。內核的頂部是系統調用接口,處理用戶空間調用到內核中合適的目的地的路由(例如 open、read 或 write)。而虛擬文件系統(VFS) 是內核中支持的大多數文件系統的抽象層。它負責將請求路由到合適的文件系統。大多數文件系統都通過緩衝區緩存來相互通信,這種緩存通過緩存最近使用的數據來優化對物理設備的訪問。接下來是塊設備驅動器層,它包括針對底層設備的各種塊驅動器。SCSI 子系統是這種塊設備驅動器之一。

圖 2. SCSI 子系統在 Linux 內核中的位置
SCSI
與 Linux 內核中的其他主流子系統不同,SCSI 子系統是一種分層的架構,共分爲三層。頂部的那層叫做較高層,代表的是內核針對 SCSI 和主要設備類型的驅動器的最高接口。接下來的是中間層,也稱爲公共層或統一層。在這一層包含 SCSI 堆棧的較高層和較低層的一些公共服務。最後是較低層,代表的是適用於 SCSI 的物理接口的實際驅動器(參見圖 3)。

圖 3. Linux SCSI 子系統的分層架構
 Linux SCSI 子系统的分层架构
在 ./linux/drivers/scsi 可以找到 SCSI 子系統(SCSI 較高層、中間層和各種驅動器)的源代碼。SCSI 數據結構則位於 SCSI 源目錄,在 ./linux/include/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_probesd_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 較高層和較低層的公共服務層(可以在 ./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 低層驅動器。它們是一些可與物理設備(比如 HBA)鏈接的特定驅動器。LLD 提供了自公共中間層到特定於設備的 HBA 的一種抽象。每個 LLD 都提供了到特定底層硬件的接口,但所使用的到中間層的接口卻是一組標準接口。
較低層包含大量代碼,原因是它要負責處理各種不同的 SCSI 適配器類型。例如,Fibre Channel 協議包含了針對 Emulex 和 QLogic 的各種適配器的 LLD。面向 Adaptec 和 LSI 的 SAS 適配器的 LLD 也包括在內。





毫無疑問,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 也將不會例外。
針對 SCSI 的端到端數據保護也在開發中,它源於 T10 的新數據完整性標準。這個標準爲每扇區都增加了一個數據完整性字段(DIF)以保護介質上的數據。這個新的 8 字節 DIF 字段包括一個循環冗餘代碼(CRC)用以保護數據,一個參考標籤用以保護數據免遭誤導寫入,以及一個應用程序標籤。應用程序標籤特定於應用程序,並且可以定義數據的用途,例如,一個 PDF 文件的一部分。請參見 參考資料 部分以獲取更多信息。






Linux 內核是抽象的分層結構的另一個典型示例。它將各種文件系統連接到不同的物理存儲介質。若這些存儲介質與 SCSI 相關,SCSI 子系統會將公共 Linux 塊請求轉化爲針對特定底層設備的 SCSI 請求。SCSI 子系統本身在過去若干年中經歷了很多變化,而且這些變化還在繼續。諸如端到端數據保護這樣的新技術,與 FCoE 這樣的新協議一樣,都在想方設法尋找與 Linux 建立關係的途徑。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章