歡迎您光臨本站 註冊首頁

linux bible 第八章 設備驅動

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0
第八章 設備驅動
操作系統的目的之一就是將系統硬體設備細節從用戶視線中隱藏起來.例如
虛擬文件系統對各種類型已安裝的文件系統提供了統一的視圖而屏蔽了具體
底層細節.本章將描敘Linux核心對系統中物理設備的管理.
CPU並不是系統中唯一的智能設備,每個物理設備都擁有自己的控制器.鍵
盤、滑鼠和串列口由一個高級I/O晶元統一管理,IDE控制器控制IDE硬碟而
SCSI控制器控制SCSI硬碟等等.每個硬體控制器都有各自的控制和狀態寄存
器(CSR)並且各不相同.例如Adaptec 2940 SCSI控制器的CSR與NCR 810
SCSI控制器完全不一樣.這些CSR被用來啟動和停止,初始化設備及對設備
進行診斷.在Linux中管理硬體設備控制器的代碼並沒有放置在每個應用程
序中而是由內核統一管理.這些處理和管理硬體控制器的軟體就是設備驅動.
Linux核心設備驅動是一組運行在特權級上的內存駐留底層硬體處理共享庫.
正是它們負責管理各個設備.
設備驅動的一個基本特徵是設備處理的抽象概念.所有硬體設備都被看成普
通文件;可以通過和操縱普通文件相同的標準系統調用來打開、關閉、讀取
和寫入設備.系統中每個設備都用一種特殊的設備相關文件來表示(device
special file),例如系統中第一個IDE硬碟被表示成/dev/hda.塊(磁碟)
設備和字元設備的設備相關文件可以通過mknod命令來創建,並使用主從設備
號來描敘此設備.網路設備也用設備相關文件來表示,但Linux尋找和初始化
網路設備時才建立這種文件.由同一個設備驅動控制的所有設備具有相同的
主設備號.從設備號則被用來區分具有相同主設備號且由相同設備驅動控制
的不同設備.例如主IDE硬碟的每個分區的從設備號都不相同.如/dev/hda2表


示主IDE硬碟的主設備號為3而從設備號為2.Linux通過使用主從設備號將包含
在系統調用中的(如將一個文件系統mount到一個塊設備)設備相關文件映射
到設備的設備驅動以及大量系統表格中,如字元設備表,chrdevs.
Linux支持三類硬體設備:字元、塊及網路設備.字元設備指那些無需緩衝直
接讀寫的設備,如系統的串口設備/dev/cua0和/dev/cua1.塊設備則僅能以塊
為單位讀寫,典型的塊大小為512或1024位元組.塊設備的存取是通過buffer
cache來進行並且可以進行隨機訪問,即不管塊位於設備中何處都可以對其進
行讀寫.塊設備可以通過其設備相關文件進行訪問,但更為平常的訪問方法是
通過文件系統.只有塊設備才能支持可安裝文件系統.網路設備可以通過BSD
套介面訪問,我們將在網路一章中討論網路子系統.
Linux核心中雖存在許多不同的設備驅動但它們具有一些共性:
核心代碼
設備驅動是核心的一部分,象核心中其它代碼一樣,出錯將導致系統的嚴
重損傷.一個編寫奇差的設備驅動甚至能使系統崩潰並導致文件系統的破
壞和數據丟失.
核心介面
設備驅動必須為Linux核心或者其從屬子系統提供一個標準介面.例如終
端驅動為Linux核心提供了一個文件I/O介面而SCSI設備驅動為SCSI子系統
提供了一個SCSI設備介面,同時此子系統為核心提供了文件I/O和buffer
cache介面.
核心機制與服務
設備驅動可以使用標準的核心服務如內存分配、中斷髮送和等待隊列等等.
動態可載入
多數Linux設備驅動可以在核心模塊發出載入請求時載入,同時在不再使用
時卸載.這樣核心能有效地利用系統資源.
可配置
Linux設備驅動可以連接到核心中.當核心被編譯時,哪些核心被連入核心


是可配置的.
動態性
當系統啟動及設備驅動初始化時將查找它所控制的硬體設備.如果某個設
備的驅動為一個空過程並不會有什麼問題.此時此設備驅動僅僅是一個冗餘
的程序,它除了會佔用少量系統內存外不會對系統造成什麼危害.
8.1 輪詢與中斷
設備被執行某個命令時,如「將讀取磁頭移動到軟盤的第42扇區上」,設備驅
動可以從輪詢方式和中斷方式中選擇一種以判斷設備是否已經完成此命令.
輪詢方式意味著需要經常讀取設備的狀態,一直到設備狀態表明請求已經完成
為止.如果設備驅動被連接進入核心,這時使用輪詢方式將會帶來災難性後果:
核心將在此過程中無所事事,直到設備完成此請求.但是輪詢設備驅動可以通
過使用系統定時器,使核心周期性調用設備驅動中的某個常式來檢查設備狀態.
定時器過程可以檢查命令狀態及Linux軟盤驅動的工作情況.使用定時器是輪詢
方式中最好的一種,但更有效的方法是使用中斷.
基於中斷的設備驅動會在它所控制的硬體設備需要服務時引發一個硬體中斷.
如乙太網設備驅動從網路上接收到一個以太數據報時都將引起中斷.Linux核
心需要將來自硬體設備的中斷傳遞到相應的設備驅動.這個過程由設備驅動向
核心註冊其使用的中斷來協助完成.此中斷處理常式的地址和中斷號都將被記
錄下來.在/proc/interrupts文件中你可以看到設備驅動所對應的中斷號及類
型:
0: 727432 timer
1: 20534 keyboard
2: 0 cascade
3: 79691 serial
4: 28258 serial
5: 1 sound blaster
11: 20868 aic7xxx
13: 1 math error
14: 247 ide0
15: 170 ide1
對中斷資源的請求在驅動初始化時就已經完成.作為IBM
PC體系結構的遺產,系統中有些中斷已經固定.例如軟盤控制器總是使用中斷6.


其它中斷,如PCI設備中斷,在啟動時進行動態分配.設備驅動必須在取得對此
中斷的所有權之前找到它所控制設備的中斷號(IRQ).Linux通過支持標準的PCI
BIOS回調函數來確定系統中PCI設備的中斷信息,包括其IRQ號.
如何將中斷髮送給CPU本身取決於體系結構,但是在多數體系結構中,中斷以
一種特殊模式發送同時還將阻止系統中其它中斷的產生.設備驅動在其中斷處
理過程中作的越少越好,這樣Linux核心將能很快的處理完中斷並返回中斷前的
狀態中.為了在接收中斷時完成大量工作,設備驅動必須能夠使用核心的底層處
理常式或者任務隊列來對以後需要調用的那些常式進行排隊.
8.2 直接內存訪問 (DMA)
數據量比較少時,使用中斷驅動設備驅動程序能順利地在硬體設備和內存之
間交換數據.例如波特率為9600的modem可以每毫秒傳輸一個字元.如果硬體
設備引起中斷和調用設備驅動中斷所消耗的中斷時延比較大(如2毫秒)則
系統的綜合數據傳輸率會很低.則9600波特率modem的數據傳輸只能利用0.002%
的CPU處理時間.高速設備如硬碟控制器或者乙太網設備數據傳輸率將更高.
SCSI設備的數據傳輸率可達到每秒40M位元組.
直接內存存取(DMA)是解決此類問題的有效方法.DMA控制器可以在不受處
理器干預的情況下在設備和系統內存之間高速傳輸數據.PC機的ISA DMA控
制器有8個DMA通道,其中七個可以由設備驅動使用.每個DMA通道具有一個
16位的地址寄存器和一個16位的記數寄存器.為了初始化數據傳輸,設備驅
動將設置DMA通道地址和記數寄存器以描敘數據傳輸方向以及讀寫類型.然
后通知設備可以在任何時候啟動DMA操作.傳輸結束時設備將中斷PC.在傳


輸過程中CPU可以轉去執行其他任務.
設備驅動使用DMA時必須十分小心.DMA控制器沒有任何虛擬內存的概念,
它只存取系統中的物理內存.同時用作DMA傳輸緩衝的內存空間必須是連續物
理內存塊.這意味著不能在進程虛擬地址空間內直接使用DMA.但是你可以將
進程的物理頁面加鎖以防止在DMA操作過程中被交換到交換設備上去.另外DMA
控制器所存取物理內存有限.DMA通道地址寄存器代表DMA地址的高16位而頁面
寄存器記錄的是其餘8位.DMA請求被限制到內存最低16M位元組中.
DMA通道是非常珍貴的資源,一共才有7個並且還不能夠在設備驅動間共享.
與中斷一樣,設備驅動必須找到它應該使用那個DMA通道.有些設備使用固
定的DMA通道.例如軟盤設備總使用DMA通道2.有時設備的DMA通道可以由跳
線來設置,許多乙太網設備使用這種技術.設計靈活的設備將告訴系統它將
使用哪個DMA通道,此時設備驅動僅需要從DMA通道中選取即可.
Linux通過dma_chan(每個DMA通道一個)數組來跟蹤DMA通道的使用情況.
dma_chan結構中包含有兩個域,一個是指向此DMA通道擁有者的指針,另一
個指示DMA通道是否已經被分配出去.當敲入cat/proc/dma列印出來的結果
就是dma_chan結構數組.
8.3 內存
設備驅動必須謹慎使用內存.由於它屬於核心,不能使用虛擬內存.系
統接收到中斷信號時或調度底層任務隊列處理過程時,設備驅動將開始運行,
而當前進程會發生改變.設備驅動不能依賴於任何運行的特定進程,即使當
前是為該進程工作.與核心的其它部分一樣,設備驅動使用數據結構來描敘
它所控制的設備.這些結構被設備驅動代碼以靜態方式分配,但會增大核心


而引起空間的浪費.多數設備驅動使用核心中非頁面內存來存儲數據.
Linux為設備驅動提供了一組核心內存分配與回收過程.核心內存以2的次冪
大小的塊來分配.如512或128位元組,此時即使設備驅動的需求小於這個數量
也會分配這麼多.設備驅動的內存分配請求可得到以塊大小為邊界的內
存.這樣核心進行空閑塊組合更加容易.
請求分配核心內存時Linux需要完成許多額外的工作.如果系統中空閑內存數
量較少,則可能需要丟棄些物理頁面或將其寫入交換設備.一般情況下Linux
將掛起請求者並將此進程放置到等待隊列中直到系統中有足夠的物理內存為止.
不是所有的設備驅動(或者真正的Linux核心代碼)都會經歷這個過程,
如分配核心內存的請求不能立刻得到滿足,則此請求可能會失敗.如果設備驅
動希望在此內存中進行DMA,那麼它必須將此內存設置為DMA使能的.這也是為
什麼是Linux核心而不是設備驅動需要了解系統中的DMA使能內存的原因.
8.4 設備驅動與核心的介面
Linux核心與設備驅動之間必須有一個以標準方式進行互操作的介面.每一類
設備驅動:字元設備、塊設備及網路設備都提供了通用介面以便在需要時為核
心提供服務.這種通用介面是的核心可以以相同的方式來對待不同的設備及設
備驅動.如SCSI和IDE硬碟的區別很大但Linux對它們使用相同的介面.
Linux動態性很強.每次Linux核心啟動時如遇到不同的物理設備將需要不同的
物理設備驅動.Linux允許通過配置腳本在核心重建時將設備驅動包含在內.設
備驅動在啟動初始化時可能會發現系統中根本沒有任何硬體需要控制.其它設
備驅動可以在必要時作為核心模塊動態載入到.為了處理設備驅動的動態屬性,


設備驅動在初始化時將其註冊到核心中去.Linux維護著已註冊設備驅動表作為
和設備驅動的介面.這些表中包含支持此類設備常式的指針和相關信息.
8.4.1 字元設備
字元設備是Linux設備中最簡單的一種.應用程序可以和存取文件相同的
系統調用來打開、讀寫及關閉它.即使此設備是將Linux系統連接到網路
中的PPP後台進程的modem也是如此.字元設備初始化時,它的設備驅動通
過在device_struct結構的chrdevs數組中添加一個入口來將其註冊到Linux
核心上.設備的主設備標誌符用來對此數組進行索引(如對tty設備的索引
4).設備的主設備標誌符是固定的.
chrdevs數組每個入口中的device_struct數據結構包含兩個元素;一個指
向已註冊的設備驅動名稱,另一個則是指向一組文件操作指針.它們是位
於此字元設備驅動內部的文件操作常式的地址指針,用來處理相關的文件
操作如打開、讀寫與關閉./proc/devices中字元設備的內容來自chrdevs
數組.
當打開代表字元設備的字元特殊文件時(如/dev/cua0),核心必須作好准
備以便調用相應字元設備驅動的文件操作常式.與普通的目錄和文件一樣,
每個字元特殊文件用一個VFS節點表示.每個字元特殊文件使用的VFS inode
和所有設備特殊文件一樣,包含著設備的主從標誌符.這個VFS inode由底
層的文件系統來建立(比如EXT2),其信息來源於設備相關文件名稱所在文
件系統.
每個VFS inode和一組文件操作相關聯,它們根據inode代表的文件系統對
象變化而不同.當創建一個代表字元相關文件的VFS inode時,其文件操
作被設置為預設的字元設備操作.
字元設備只有一個文件操作:打開文件操作.當應用打開字元特殊文件時,


通用文件打開操作使用設備的主標誌符來索引此chrdevs數組,以便得到那
些文件操作函數指針.同時建立起描敘此字元特殊文件的file結構,使其文
件操作指針指向此設備驅動中的文件操作指針集合.這樣所有應用對它進行
的文件操作都被映射到此字元設備的文件操作集合上.
8.4.2 塊設備
塊設備也支持以文件方式訪問.系統對塊設備特殊文件提供了非常類似於
字元特殊文件的文件操作機制.Linux在blkdevs數組中維護所有已註冊的
塊設備.象chrdevs數組一樣,blkdevs也使用設備的主設備號進行索引.
其入口也是device_struct結構.和字元設備不同的是系統有幾類塊設備.
SCSI設備是一類而IDE設備則是另外一類.它們將以各自類別登記到Linux
核心中並為核心提供文件操作功能.某類塊設備的設備驅動為此類型設備
提供了類別相關的介面.如SCSI設備驅動必須為SCSI子系統提供介面以便
SCSI子系統能用它來為核心提供對此設備的文件操作.
和普通文件操作介面一樣, 每個塊設備驅動必須為buffer
cache提供介面.每個塊設備驅動將填充其在blk_dev數組中的blk_dev_struct
結構入口.數組的索引值還是此設備的主設備號.這個blk_dev_struct結
構包含請求過程的地址以及指向請求數據結構鏈表的指針,每個代表一個
從buffercache中來讓設備進行數據讀寫的請求.
每當buffer cache希望從一個已註冊設備中讀寫數據塊時,它會將request
結構添加到其blk_dev_struct中.圖8.2表示每個請求有指向一個或多個
buffer_hear結構的指針,每個請求讀寫一塊數據.如buffer cache對
buffer_head結構上鎖,則進程會等待到對此緩衝的塊操作完成.每個
request結構都從靜態鏈表all_requests中分配.如果此請求被加入到空


請求鏈表中,則將調用驅動請求函數以啟動此請求隊列的處理,否則該設備
驅動將簡單地處理請求鏈表上的request.
一旦設備驅動完成了請求則它必須將每個buffer_heard結構從request結
構中清除,將它們標記成已更新狀態並解鎖之.對buffer_head的解鎖將
喚醒所有等待此塊操作完成的睡眠進程.如解析文件名稱時,EXT2文件系
統必須從包含此文件系統的設備中讀取包含下個EXT2目錄入口的數據塊.
在buffer_head上睡眠的進程在設備驅動被喚醒后將包含此目錄入口.
request數據結構被標記成空閑以便被其它塊請求使用.
8.5 硬碟
磁碟驅動器提供了一個永久性存儲數據的方式,將數據保存在旋轉的碟片
上.寫入數據時磁頭將磁化碟片上的一個小微粒.這些碟片被連接到一個
中軸上並以3000到10,000RPM(每分鐘多少轉)的恆定速度旋轉.而軟盤
的轉速僅為360RPM.磁碟的讀/寫磁頭負責讀寫數據,每個碟片的兩側各
有一個磁頭.磁頭讀寫時並不接觸碟片表面而是浮在距表面非常近的空氣
墊中(百萬分之一英寸).磁頭由一個馬達驅動在碟片表面移動.所有的
磁頭被連在一起,它們同時穿過碟片的表面.
碟片的每個表面都被劃分成為叫做磁軌的狹窄同心圓.0磁軌位於最外面
而最大磁軌位於最靠近中央主軸.柱面指一組相同磁軌號的磁軌.
個碟片上的第五磁軌組成了磁碟的第五柱面.由於柱面號與磁軌號相等所
以我們經常可以看到以柱面描敘的磁碟布局.每個磁軌可進一步劃分成扇
區.它是硬碟數據讀寫的最小單元同時也是磁碟的塊大小.一般的扇區大
小為512位元組並且這個大小可以磁碟製造出來后格式化時設置.
一個磁碟經常被描繪成有多少各柱面、磁頭以及扇區.例如系統啟動時


Linux將這樣描敘一個IDE硬碟:
hdb: Conner Peripherals 540MB - CFS540A, 516MB w/64kB Cache,
CHS=1050/16/63
這表示此磁碟有1050各柱面(磁軌),16個磁頭(8個碟片)且每磁軌包
含63個扇區.這樣我們可以通過扇區數、塊數以及512位元組扇區大小計算
出磁碟的存儲容量為529200位元組.這個容量和磁碟自身聲稱的516M位元組並
不相同,這是有些扇區被用來存放磁碟分區信息.有些磁碟還能自動
尋找壞扇區並重新索引磁碟以正常使用.
物理硬碟可進一步劃分成分區.一個分區是一大組為特殊目的而分配的扇
區.對磁碟進行分區是的磁碟可以同時被幾個操作系統或不同目的使用.
許多Linux系統具有三個分區:DOS文件系統分區,EXT2文件系統分區和交
換分區.硬碟分區用分區表來描敘;表中每個入口用磁頭、扇區及柱面號
來表示分區的起始與結束.對於用DOS格式化的硬碟有4個主分區表.但不
一定所有的四個入口都被使用.fdisk支持3中分區類型:主分區、擴展分
區及邏輯分區.擴展分區並不是真正的分區,它只不過包含了幾個邏輯分
區.擴展和邏輯分區用來打破四個主分區的限制.以下是一個包含兩個主
分區的fdisk命令的輸出:
Disk /dev/sda: 64 heads, 32 sectors, 510 cylinders
Units = cylinders of 2048 * 512 bytes
Device Boot Begin Start End Blocks Id System
/dev/sda1 1 1 478 489456 83 Linux native
/dev/sda2 479 479 510 32768 82 Linux swap
Expert command (m for help): p
Disk /dev/sda: 64 heads, 32 sectors, 510 cylinders
Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID
1 00 1 1 0 63 32 477 32 978912 83
2 00 0 1 478 63 32 509 978944 65536 82
3 00 0 0 0 0 0 0 0 0 00
4 00 0 0 0 0 0 0 0 0 00
這些內容表明第一個分區從柱面(或者磁軌)0,頭1和扇區1開始一直


到柱面477,扇區22和頭63結束.由於每磁軌有32個扇區且有64個讀寫
磁頭則此分區在大小上等於柱面數.fdisk使分區在柱面邊界上對齊.
它從最外面的柱面0開始並向中間擴展478個柱面.第二個分區:交換分
區從478號柱面開始並擴展到磁碟的最內圈.
在初始化過程中Linux取得系統中硬碟的拓撲結構映射.它找出有多少
中硬碟以及是什麼類型.另外Linux還要找到每個硬碟的分區方式.所
有這些都用由gendisk_head鏈指針指向的gendisk結構鏈表來表示.每
個磁碟子系統如IDE在初始化時產生表示磁碟結構的gendisk結構.同
時它將註冊其文件操作常式並將此入口添加到blk_dev數據結構中.每
個gendisk結構包含唯一的主設備號,它與塊相關設備的主設備號相同.
例如SCSI磁碟子系統創建了一個主設備號為8的gendisk入口("sd"),
這也是所有SCSI硬碟設備的主設備號.圖8.3給出了兩個gendisk入口,
一個表示SCSI磁碟子系統而另一個表示IDE磁碟控制器.ide0表示主IDE
控制器.
儘管磁碟子系統在其初始化過程中就建立了gendisk入口,但是只有Linux
作分區檢查時才使用.每個磁碟子系統通過維護一組數據結構將物理
硬碟上的分區與某個特殊主從特殊設備互相映射.無論何時通過buffer
cache或文件操作對塊設備的讀寫都將被核心定向到對具有某個特定主
設備號的設備文件上(如/dev/sda2).而從設備號的定位由各自設備
驅動或子系統來映射.
8.5.1 IDE 硬碟
Linux系統上使用得最廣泛的硬碟是集成電子磁碟或者IDE硬碟.IDE是
一個硬碟介面而不是類似SCSI的I/O匯流排介面.每個IDE控制器支持兩
個硬碟,一個為主另一個為從.主從硬碟可以通過盤上的跳線來設置.
系統中的第一個IDE控制器成為主IDE控制器而另一個為從屬控制器.


IDE可以以每秒3.3M位元組的傳輸率傳輸數據且最大容量為538M位元組.EIDE
或增強式IDE可以將磁碟容量擴展到8.6G位元組而數據傳輸率為16.6M位元組/秒.
由於IDE和EIDE都比SCSI硬碟便宜,大多現代PC機在包含一個或幾個
板上IDE控制器.
Linux以其發現控制器的順序來對IDE硬碟進行命名.在主控制器中的主
盤為/dev/hda而從盤為/dev/hdb./dev/hdc用來表示從屬IDE控制器中的
主盤.IDE子系統將向Linux核心註冊IDE控制器而不是IDE硬碟.主IDE控
制器的主標誌符為3而從屬IDE控制器的主標誌符為22.如果系統中包含兩
個IDE控制器則IDE子系統的入口在blk_dev和blkdevs數組的第2和第22處.
IDE的塊設備文件反應了這種編號方式,硬碟/dev/hda和/dev/hdb都連接
到主IDE控制器上,其主標誌符為3.對IDE子系統上這些塊相關文件的文
件或者buffercache的操作都通過核心使用主設備標誌符作為索引定向到
IDE子系統上.當發出請求時,此請求由哪個IDE硬碟來完成取決於IDE子
系統.為了作到這一點IDE子系統使用從設備編號對應的設備特殊標誌符,
由它包含的信息來將請求發送到正確的硬碟上.位於主IDE控制器上的IDE
從盤/dev/hdb的設備標誌符為(3,64).而此盤中第一個分區(/dev/hdb1)
的設備標誌符為(3,65).
8.5.2 初始化IDE子系統
IDE磁碟與IBM
PC關係非常密切.在這麼多年中這些設備的介面發生了變化.這是的IDE
子系統的初始化過程比看上去要複雜得多.
Linux可以支持的最多IDE控制器個數為4.每個控制器用ide_hwifs數組
中的ide_hwif_t結構來表示.每個ide_hwif_t結構包含兩個ide_drive_t
結構以支持主從IDE驅動器.在IDE子系統的初始化過程中Linux通過訪問
系統CMOS來判斷是否有關於硬碟的信息.這種CMOS由電池供電系統斷


電時也不會遺失其中的內容.它位於永不停止的系統實時時鐘設備中.
此CMOS內存的位置由系統BIOS來設置,它將通知Linux系統中有多少個IDE
控制器與驅動器.Linux使用這些從BIOS中發現的磁碟數據來建立對應此
驅動器的ide_hwif_t結構.
許多現代PC系統使用PCI晶元組如Intel 82430 VX晶元組將PCIEIDE控制器
封裝在內.IDE子系統使用PCI BIOS回調函數來定位系統中PCI(E)IDE控
制器.然後對這些晶元組調用PCI特定查詢常式.
每次找到一個IDE介面或控制器就有建立一個ide_hwif_t結構來表示控制
器和與之相連的硬碟.在操作過程中IDE驅動器對I/O內存空間中的IDE命
令寄存器寫入命令.主IDE控制器的預設控制和狀態寄存器是0x1F0- 0x1F7.
這個地址由早期的IBM PC規範設定.IDE驅動器為每個控制器向Linux注
冊塊緩衝cache和VFS節點並將其加入到blk_dev和blkdevs數組中.IDE驅
動器需要申請某個中斷.一般主IDE控制器中斷號為14而從屬IDE控制器為
15.然而這些都可以通過命令行選項由核心來重載.IDE驅動器同時還將
gendisk入口加入到啟動時發現的每個IDE控制器的gendisk鏈表中去.分
區檢查代碼知道每個IDE控制器可能包含兩個IDE硬碟.
8.5.3 SCSI 硬碟
SCSI(小型計算機系統介面)匯流排是一種高效的點對點數據匯流排,它最
多可以支持8個設備,其中包括多個主設備.每個設備有唯一的標誌符並
可以通過盤上的跳線來設置.在匯流排上的兩個設備間數據可以以同步或異
步方式,在32位數據寬度下傳輸率為40M位元組來交換數據.SCSI匯流排上可
以在設備間同時傳輸數據與狀態信息.initiator設備和target設備間的
執行步驟最多可以包括8個不同的階段.你可以從匯流排上5個信號來分辨SCSI
匯流排的當前階段.這8個階段是:


BUS FREE
當前沒有設備在控制匯流排且匯流排上無事務發生.
ARBITRATION
一個SCSI設備試圖取得SCSI匯流排的控制權,這時它將其SCSI標誌符
放置到地址引腳上.具有最高SCSI標誌符編號的設備將獲得匯流排控制權.
SELECTION
當設備通過仲裁成功地取得了對SCSI匯流排的控制權后它必須向它準備
發送命令的那個SCSI設備發出信號.具體做法是將目標設備的SCSI標誌
符放置在地址引腳上進行聲明.
RESELECTION
在一個請求的處理過程中SCSI設備可能會斷開連接.目標(target)
設備將再次選擇啟動設備(initiator).不是所有的SCSI設備都支
持此階段.
COMMAND
此階段中initiator設備將向target設備發送6、10或12位元組命令.
DATA IN, DATA OUT
此階段中數據將在initiator設備和target設備間傳輸.
STATUS
所有命令完畢后將進入此階段,此時允許target設備向initiator
設備發送狀態信息以指示操作成功與否.
MESSAGE IN, MESSAGE OUT
此階段附加信息將在initiator設備和target設備間傳輸.
Linux SCSI子系統由兩個基本部分組成,每個由一個數據結構來表示.
host 一個SCSI host即一個硬體設備:SCSI控制權.NCR 810 PCI
SCSI控制權即一種SCSI host.在Linux
系統中可以存在相同類型的多個SCSI控制權,每個由一個單獨的
SCSI host來表示.這意味著一個SCSI設備驅動可以控制多個控制
權實例.SCSI host總是SCSI命令的initiator設備.
Device
雖然SCSI支持多種類型設備如磁帶機、CD-ROM等等,但最常見的
SCSI設備是SCSI磁碟.SCSI設備總是SCSI命令的target.這些設備
必須區別對待,例如象CD-ROM或者磁帶機這種可移動設備,Linux
必須檢測介質是否已經移動.不同的磁碟類型有不同的主設備號,
這樣Linux可以將塊設備請求發送到正確的SCSI設備.


初始化SCSI子系統
SCSI子系統的初始化非常複雜,它必須反映處SCSI匯流排及其設備的動態
性.Linux在啟動時初始化SCSI子系統.
如果它找到一個SCSI控制器(即SCSI hosts)則會掃描此SCSI匯流排來找
出匯流排上的所有設備.然後初始化這些設備並通過普通文件和buffer
cache塊設備操作使Linux核心的其它部分能使用這些設備.初始化過程
分成四個階段:
Linux將找出在系統核心連接時被連入核心的哪種類型的SCSI主機適
配器或控制器有硬體需要控制.每個核心中的SCSI host在builtin_scsi_hosts
數組中有一個Scsi_Host_Template入口.而Scsi_Host_Template結構中包
含執行特定SCSIhost操作, 如檢測連到此SCSI host的SCSI設備的常式的入
口指針.這些常式在SCSI子系統進行自我配置時使用同時它們還是支持
此host類型的SCSI設備驅動的一部分.每個被檢測的SCSI host,即與真
正SCSI設備連接的host將其自身的Scsi_Host_Template結構添加到活動
SCSIhosts的scsi_hosts結構鏈表中去.每個被檢測host類型的實例用一
個scsi_hostlist鏈表中的Scsi_Host結構來表示.例如一個包含兩個NCR810
PCI SCSI控制器的系統的鏈表中將有兩個Scsi_Host入口,每個控制器對
應一個.每個Scsi_Host指向一個代表器設備驅動的Scsi_Host_Template.
現在每個SCSI host已經找到,SCSI子系統必須找出哪些SCSI設備連接哪
個host的匯流排.SCSI設備的編號是從0到7,對於一條SCSI匯流排上連接的各
個設備,其設備編號或SCSI標誌符是唯一的.SCSI標誌符可以通過設備上
的跳線來設置.SCSI初始化代碼通過在SCSI匯流排上發送一個TEST_UNIT_READY
命令來找出每個SCSI設備.當設備作出相應時其標誌符通過一個ENQUIRY命
令來讀取.Linux將從中得到生產廠商的名稱和設備模式以及修訂版本號.


SCSI命令由一個Scsi_Cmnd結構來表示同時這些命令通過調用Scsi_Host_Template
結構中的設備驅動常式傳遞到此SCSIhost的設備驅動中.被找到的每個SCSI
設備用一個Scsi_Device結構來表示,每個指向其父Scsi_Host結構.所有
這些Scsi_Device結構被添加到scsi_device鏈表中.圖8.4給出了這些主要
數據結構間的關係.
一共有四種SCSI設備類型:磁碟,磁帶機,CD-ROM和普通SCSI設備.每種類
型的SCSI設備以不同的主塊設備類型單獨登記到核心中.如果有多個類型的
SCSI設備存在則它們只登記自身.每個SCSI設備類型,如SCSI磁碟維護著其
自身的設備列表.它使用這些表將核心塊操作(file或者buffer cache)定
向到正確的設備驅動或 SCSI host上.每種SCSI設備類型用一個
Scsi_Device_Template結構來表示.此結構中包含此類型SCSI設備的信息以
及執行各種任務的常式的入口地址.換句話說,如果SCSI子系統希望連接一
個SCSI磁碟設備它將調用SCSI磁碟類型連接常式.如果有多個該種類型的SCSI
設備被檢測到則此Scsi_Type_Template結構將被添加到scsi_devicelist鏈表中.
SCSI子系統的一個階段是為每個已登記的Scsi_Device_Template結構調用
finish函數.對於SCSI磁碟類型設備它將驅動所有SCSI磁碟並記錄其磁碟布局.
同時還將添加一個表示所有連接在一起的SCSI磁碟的gendisk結構.
發送塊設備請求
一旦SCSI子系統初始化完成這些SCSI設備就可以使用了.每個活動的SCSI設備
類型將其自身登記到核心以便Linux正確定向塊設備請求.這些請求可以是通
過blk_dev的buffercache請求也可以是通過blkdevs的文件操作.以一個包含
多個EXT2文件系統分區的SCSI磁碟驅動器為例,當安裝其中一個EXT2分區時系
統是怎樣將核心緩衝請求定向到正確的SCSI磁碟的呢?


每個對SCSI磁碟分區的塊讀寫請求將導致一個新的request結構被添加到對應
此SCSI磁碟的blk_dev數組中的current_request鏈表中.如果此request正在
被處理則buffercache無需作任何工作;否則它必須通知SCSI磁碟子系統去處
理它的請求隊列.系統中每個SCSI磁碟用一個Scsi_Disk結構來表示.例如
/dev/sdb1的主設備號為8而從設備號為17;這樣產生一個索引值1.每個
Scsi_Disk結構包含一個指向表示此設備的Scsi_Device結構.這樣反過來又
指向擁有它的Scsi_Host結果.這個來自buffer cache的request結構將被轉
換成一個描敘SCSI命令的Scsi_Cmd結構,這個SCSI命令將發送到此SCSI設備
同時被排入表示此設備的Scsi_Host結構.一旦有適當的數據塊需要讀寫,這
些請求將被獨立的SCSI設備驅動來處理.
8.6 網路設備
網路設備,即Linux的網路子系統,是一個發送與接收數據包的實體.它一般
是一個象乙太網卡的物理設備.有些網路設備如loopback設備僅僅是一個用
來向自身發送數據的軟體.每個網路設備都用一個device結構來表示.網路
設備驅動在核心啟動初始化網路時將這些受控設備登記到Linux中.device數
據結構中包含有有關設備的信息以及用來支持各種網路協議的函數地址指針.
這些函數主要用來使用網路設備傳輸數據.設備使用標準網路支持機制來將接
收到的數據傳遞到適當的協議層.所有傳輸與接收到的網路數據用一個sk_buff
結構來表示,這些靈活的數據結構是的網路協議頭可以更容易的添加與刪除.
網路協議層如何使用網路設備以及如何使用sk_buff來交換數據將在網路一章
中詳細描敘.本章只討論device數據結構及如何發現與初始化網路.
device數據結構包含以下有關網路設備的信息:


Name
與使用mknod命令創建的塊設備特殊文件與字元設備特殊文件不同,網路
設備特殊文件僅在於系網路設備發現與初始化時建.它們使用標立 準的命名
方法
每個名字代表一種類型的設備.?nbsp;個相同類型設備將從
0開始記數.這樣乙太網設備被命名為/dev/eth0,/dev/eth1,/dev/eth2
等等. 一些常見的網路設備如下:
/dev/ethN
乙太網設備
/dev/slN
SLIP設備
/dev/pppN
PPP 設備
/dev/lo
Loopback 設備
Bus Information
這些信息被設備驅動用來控制設備.irq號表示設備使用的中斷號.base
address指任何設備在I/O內存中的控制與狀態寄存器地址.DMA通道
指此網路設備使用的DMA通道號.所有這些信息在設備初始化時設置.
Interface Flags
它們描敘了網路設備的屬性與功能:
IFF_UP
介面已經建立並運行
IFF_BROADCAST
設備中的廣播地址有效
IFF_DEBUG
設備調試被使能
IFF_LOOPBACK
這是一個loopback設備
IFF_POINTTOPOINT
這是點到點連接(SLIP和PPP)
IFF_NOTRAILERS
無網路追蹤者
IFF_RUNNING
資源已被分配
IFF_NOARP
不支持ARP協議
IFF_PROMISC
設備處於混亂的接收模式,無論包地址怎樣它都將接收
IFF_ALLMULTI
接收所有的IP多播幀
IFF_MULTICAST
可以接收IP多播幀
Protocol Information
每個設備描敘它可以被網路協議層如何使用:
mtu
指不包括任何鏈路層頭在內的,網路可傳送的最大包大小.
這個值被協議層用來選擇適當大小的包進行發送.
Family
這個family域表示設備支持的協議族.所有Linux網路設
備的族是AF_INET,互聯網地址族.
Type
這個硬體介面類型描敘網路設備連接的介質類型.Linux
網路設備可以支持多種不同類型的介質.包括乙太網、X.25,


令牌環,Slip,PPP和Apple Localtalk.
Addresses
結構中包含大量網路設備相關的地址,包括IP地址.
Packet Queue
指網路設備上等待傳輸的sk_buff包隊列.
Support Functions
每個設備支持一組標準的常式,它們被協議層作為設備鏈路層
的介面而調用.如傳輸建立和幀傳輸常式以及添加標準幀頭以
及收集統計數據的常式.這些統計數據可以使用ifconfig命令
來觀察.
8.6.1 初始化網路設備
網路設備驅動可以象其它Linux設備驅動一樣建立到Linux核心中來.
每個潛在的網路設備由一個被dev_base鏈表指針指向的網路設備鏈表
內部的device結構表示.當網路層需要某個特定工作執行時.它將調
用大量網路服務常式中的一個,這些常式的地址被保存在device結構
內部.初始化時每個device結構僅包含一個初始化或者檢測常式的地
址.
對於網路設備驅動有兩個問題需要解決.是不是每個連接到核心
中的網路設備驅動都有設備要控制.其次雖然底層的設備驅動迥然不
同,但系統中的乙太網設備總是命名為/dev/eth0和/dev/eth1.混淆
網路設備這個問題很容易解決.當每個網路設備的初始化常式被調用
時,將得到一個指示是否存在當前控制器實例的狀態信息.如果驅動
找不到任何設備,它那個由dev_base指向的device鏈表將被刪除.如
果驅動找到了設備則它將用設備相關信息以及網路設備驅動中支撐函
數的地址指針來填充此device數據結構.
第二個問題,即為乙太網設備動態分配標準名稱/dev/ethN設備特殊
文件的工作的解決方法十分巧妙.在設備鏈表中有8個標準入口;從
eth0到eth7.它們使用相同的初始化常式,此初始化過程將依次嘗試
這些被建立到核心中的乙太網設備驅動直到找到一個設備.當驅動


找到其乙太網設備時它將填充對應的ethN設備結構.同時此網路設備
驅動初始化其控制的物理硬體並找出使用的IRQ號以及DMA通道等信息.
如果驅動找到了此網路設備的多個實例它將建立多個/dev/ethN
device數據結構.一旦所有8個標準/dev/ethN被分配完畢則不會在檢測
其它的乙太網設備.


[火星人 ] linux bible 第八章 設備驅動已經有750次圍觀

http://coctec.com/docs/linux/show-post-57933.html