Linux內核中的設備模型及SCSI示例解析

關於硬件架構

想要了解Linux操作系統的內核設備和驅動模型,最好先了解一下現在計算機硬件的架構。對計算機硬件有一定了解之後,對理解Linux內核中的設備和驅動模型非常有幫助。如圖1是常規計算機的硬件架構簡圖。

Linux內核中的設備模型及SCSI示例解析

圖1 計算機硬件架構簡圖

這裡面需要重點理解的概念包括:總線、PCI橋和設備三個概念。我們下面大概介紹一下這幾個概念的含義:

總線: 我們知道計算機通常包括幾大件,CPU、內存、輸入設備和輸出設備等。這些設備之間進行通信需要依賴一種通道,這個通道就是總線。說的直白寫,總線就是傳輸數據的通道,可以類比日常生活中的馬路,各個不同的城市通過馬路來交換物資。總線有很多種,比如常見的PCI總線,ISA總線和I2C總線等等,我們這裡就不相信介紹。

PCI橋: PCI橋是連接PCI總線的紐帶,其作用與網絡領域的網橋類似。其實我們平時說的北橋,就包含PCI橋。PCI橋主要分3種,3種橋的具體含義如下:

  1. HOST/PCI橋:提供CPU和PCI設備相互訪問的通道,實現CPU空間和PCI空間的映射。
  2. PCI-PCI橋:實現PCI設備的級聯。
  3. PCI/ISA或LPC橋:實現對ISA設備的兼容。

設備:設備就是具體的設備了,比如網卡、鍵盤和鼠標等等。

Linux中的設備軟件模型

為了降低設備多樣性帶來的Linux驅動開發的複雜度,以及設備熱拔插處理、電源管理等,Linux內核提出了設備模型(也稱作Driver Model)的概念。設備模型將硬件設備歸納、分類,然後抽象出一套標準的數據結構和接口。驅動的開發,就簡化為對內核所規定的數據結構的填充和實現。Linux中的軟件概念與實際物理的概念有一個大致的對應關係,在內核中相關的概念主要包括Bus、Device、Device Driver和Class等。下面是Linux對上述概念的介紹:

Bus(總線):Linux認為(可以參考include/linux/device.h中struct bus_type的註釋)總線是CPU和一個或多個設備之間信息交互的通道。而為了方便設備模型的抽象,所有的設備都應連接到總線上。Linux總線是在上述物理總線基礎上做的抽象,它可以對應物理總線,也可以沒有對應物理總線。

Device(設備):抽象系統中所有的硬件設備,描述它的名字、屬性、從屬的Bus、從屬的Class等信息。

Device Driver(驅動):Linux設備模型用Driver抽象硬件設備的驅動程序,它包含設備初始化、電源管理相關的接口實現。而Linux內核中的驅動開發,基本都圍繞該抽象進行(實現所規定的接口函數)。

Class(分類):在Linux設備模型中,Class的概念非常類似面向對象程序設計中的Class(類),它主要是集合具有相似功能或屬性的設備,這樣就可以抽象出一套可以在多個設備之間共用的數據結構和接口函數。因而從屬於相同Class的設備的驅動程序,就不再需要重複定義這些公共資源,直接從Class中繼承即可。

設備模型的核心思想

前面介紹了Linux的設備軟件模型相關的概念,下面介紹一下各種概念間的關係。對於Linux來說,其軟件層面的模型與硬件基本是一致的。由圖1, 如果把CPU和內存開成一個樹根的話,整個計算機的設備間的關係其實類似一個樹,總線類似於樹枝。Linux內核在具體實現的時候也是按照此規律進行的,最底層的是根總線(bus),然後是各種具體類型的總線(bus_type),而其下則是設備(device)。

Linux內核中的設備模型及SCSI示例解析

圖2 Linux內核驅動關鍵數據結構

如圖2所示,Linux內核針對上面介紹的概念,實現了具體的數據結構。數據結構的名稱基本與硬件類型名稱一致。比如bus_type表示某種類型的總線,device表示一個物理設備等。

設備和驅動: 用Device(struct device)和Device Driver(struct device_driver)兩個數據結構,分別從“有什麼用”和“怎麼用”兩個角度描述硬件設備。這樣就統一了編寫設備驅動的格式,使驅動開發從論述題變為填空體,從而簡化了設備驅動的開發。

總線與設備: 通過"Bus-->Device”類型的樹狀結構解決設備之間的依賴,而這種依賴在開關機、電源管理等過程中尤為重要。

試想,一個設備掛載在一條總線上,要啟動這個設備,必須先啟動它所掛載的總線。很顯然,如果系統中設備非常多、依賴關係非常複雜的時候,無論是內核還是驅動的開發人員,都無力維護這種關係。

而設備模型中的這種樹狀結構,可以自動處理這種依賴關係。啟動某一個設備前,內核會檢查該設備是否依賴其它設備或者總線,如果依賴,則檢查所依賴的對象是否已經啟動,如果沒有,則會先啟動它們,直到啟動該設備的條件具備為止。而驅動開發人員需要做的,就是在編寫設備驅動時,告知內核該設備的依賴關係即可。

: 使用Class結構,在設備模型中引入面向對象的概念,這樣可以最大限度地抽象共性,減少驅動開發過程中的重複勞動,降低工作量。在Linux內核驅動中,類是對具有共性的設備的抽象,比如顯示設備類,音頻設備類和SCSI設備類等等。比如SCSI設備類包括磁盤設備、光驅設備和USB設備等。

即插即用: 在現代操作系統中即插即用成為常態,我們普通PC的U盤、光驅等都是即插即用的。而對於企業級的服務器甚至要求CPU和內存等組件都是可以即插即用的。

即插即用的實現同樣借用Device和Device Driver兩個數據結構。在Linux內核中,只要任何Device和Device Driver具有相同的名字,內核就會執行Device Driver結構中的初始化函數(probe),該函數會初始化設備,使其為可用狀態。

而對大多數熱拔插設備而言,它們的Device Driver一直存在內核中。當設備沒有插入時,其Device結構不存在,因而其Driver也就不執行初始化操作。當設備插入時,內核會創建一個Device結構(名稱和Driver相同),此時就會觸發Driver的執行。這就是即插即用的概念。

SCSI設備示例

SCSI設備是Linux內核中支持的眾多設備中的一種。SCSI設備也遵循上面介紹的設備、驅動和總線的結構,但略有不同。Linux內核中抽象了一個稱謂SCSI總線的虛擬總線。而在SCSI總線上又包含SCSI的驅動和設備。

Linux內核中的設備模型及SCSI示例解析

圖3 SCSI體系結構

SCSI整個架構分為3層,其中中間是中間層,用於實現SCSI的公共功能,比如錯誤處理等。而上面一層稱謂高層,它代表各種scsi設備類型的驅動,如scsi磁盤驅動,scsi磁帶驅動,高層驅動認領低層驅動發現的scsi設備,為這些設備分配名稱,將對設備的IO轉換為scsi命令,交由低層驅動處理。而最下面的稱謂底層,它代表與SCSI的物理接口的實際驅動器,主要為各個廠商為其特定的主機適配器(Host Bus Adapter, HBA)驅動,例如: FC卡驅動、SAS卡驅動和iSCSI(iSCSI可以使硬件HBA卡或者基於普通網卡的軟件實現)等。

在圖3中,Disk Driver就是一個SCSI磁盤驅動,通過該驅動對用戶呈現一個普通的磁盤。中間層的驅動是必須第一個被內核加載的,如果編譯成內核模塊的話,該內核模塊為scsi_mod。然後是上層的驅動和底層的驅動。以SCSI磁盤為例,加載的模塊是sd_mod。

在SCSI中實現對應上述概念的結構體包括scsi_driver、scsi_device和SCSI類型的總線(bus)。其中SCSI類型的總線並沒有定義一個特別的數據結構體,而是對bus_type數據結構的實例化。

需要說明的是對於SCSI設備,其實現又是比較複雜的。我們以光纖適配卡為例,其中一個適配卡又包含多個通路,而每個通路同網絡的方式可以跟多個存儲設備連接。因此,對於SCSI設備來說,實現上要複雜很多。

Linux內核中的設備模型及SCSI示例解析

圖4 光纖適配卡

在內核中通過Scsi_Host、scsi_target等結構體表示上述概念。具體細節本文不再詳述,後面我們再詳細介紹SCSI體系架構、FC相關流程和iSCSI相關流程。

相關推薦

推薦中...