reactos操作系统实现(105)
AtapiFindController函数主要用来查找ATAPI控制器,也就是IDE控制器。同时收集IDE控制器相关配置信息,比如磁盘的访问方式。 #001 ULONG #002 NTAPI #003 AtapiFindController( #004 IN PVOID HwDeviceExtension, #005 IN PVOID Context, #006 IN PVOID BusInformation, #007 IN PCHAR ArgumentString, #008 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, #009 OUT PBOOLEAN Again #010 ) #011 /*++ #012 #013 Routine Description: #014 #015 This function is called by the OS-specific port driver after #016 the necessary storage has been allocated,to gather information #017 about the adapter's configuration. #018 #019 Arguments: #020 #021 HwDeviceExtension - HBA miniport driver's adapter data storage #022 Context - Address of adapter count #023 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility. #024 ConfigInfo - Configuration information structure describing HBA #025 Again - Indicates search for adapters to continue #026 #027 Return Value: #028 #029 ULONG #030 #031 --*/ #032 #033 { #034 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension; #035 PULONG adapterCount = (PULONG)Context; #036 PUCHAR ioSpace = NULL; #037 ULONG i; #038 ULONG irq; #039 ULONG portBase; #040 ULONG retryCount; #041 PCI_SLOT_NUMBER slotData; #042 PPCI_COMMON_CONFIG pciData; #043 ULONG pciBuffer; #044 BOOLEAN atapiOnly; #045 UCHAR statusByte; #046 BOOLEAN preConfig = FALSE; #047 // #048 // The following table specifies the ports to be checked when searching for #049 // an IDE controller. A zero entry terminates the search. #050 // #051
IDE控制器的端口。 #052 CONST ULONG AdapterAddresses[5] = {0x1F0,0x170,0x1e8,0x168,0}; #053 #054 // #055 // The following table specifies interrupt levels corresponding to the #056 // port addresses in the previous table. #057 // #058
IDE控制器的中断号。 #059 CONST ULONG InterruptLevels[5] = {14,15,11,10,0}; #060 #061 if (!deviceExtension) { #062 return SP_RETURN_ERROR; #063 } #064 #065 // #066 // Check to see if this is a special configuration environment. #067 // #068
设置端口和中断都为0。 #069 portBase = irq = 0; #070 if (ArgumentString) { #071
分析字符串中的中断号,并转换为数字表示。 #072 irq = AtapiParseArgumentString(ArgumentString,"Interrupt"); #073 if (irq ) { #074 #075 // #076 // Both parameters must be present to proceed #077 // #078
处理IDE控制器的基地址。 #079 portBase = AtapiParseArgumentString(ArgumentString,"BaseAddress");
如果端口为0,表示是非法的数据。 #080 if (!portBase) { #081 #082 // #083 // Try a default search for the part. #084 // #085 #086 irq = 0; #087 } #088 } #089 } #090 #091 #092 #093 // #094 // Scan though the adapter address looking for adapters. #095 //
如果访问范围不为空,说明这个PCI空间有设备。 #096 if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart) != 0) {
获取这个PCI空间的IO空间。 #097 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, #098 ConfigInfo->AdapterInterfaceType, #099 ConfigInfo->SystemIoBusNumber, #100 (*ConfigInfo->AccessRanges)[0].RangeStart, #101 (*ConfigInfo->AccessRanges)[0].RangeLength, #102 (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory)); #103 *Again = FALSE; #104 // #105 // Since we have pre-configured information we only need to go through this loop once #106 // #107 preConfig = TRUE; #108 portBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart); #109 #110 } #111 #112 #113
循环地查找四个IDE控制器。 #114 while (AdapterAddresses[*adapterCount] != 0) { #115 #116 retryCount = 4; #117 #118 for (i = 0; i < 4; i++) { #119 #120 // #121 // Zero device fields to ensure that if earlier devices were found, #122 // but not claimed,the fields are cleared. #123 // #124
清空设备标志。 #125 deviceExtension->DeviceFlags[i] &= ~(DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT | DFLAGS_TAPE_DEVICE); #126 } #127 #128 // #129 // Get the system physical address for this IO range. #130 // #131 #132 #133 // #134 // Check if configInfo has the default information #135 // if not,we go and find ourselves #136 // #137
获取相应IDE的IO空间。 #138 if (preConfig == FALSE) { #139 #140 if (portBase) { #141 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, #142 ConfigInfo->AdapterInterfaceType, #143 ConfigInfo->SystemIoBusNumber, #144 ScsiPortConvertUlongToPhysicalAddress(portBase), #145 8, #146 TRUE); #147 } else { #148 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, #149 ConfigInfo->AdapterInterfaceType, #150 ConfigInfo->SystemIoBusNumber, #151 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]), #152 8, #153 TRUE); #154 } #155 #156 }// ConfigInfo check #157 // #158 // Update the adapter count. #159 // #160
处理下一个IDE控制器。 #161 (*adapterCount)++; #162 #163 // #164 // Check if ioSpace accessible. #165 // #166
如果没有读取IO空间成功,就尝试读取下一个。 #167 if (!ioSpace) { #168 continue; #169 } #170 #171 retryIdentifier: #172 #173 // #174 // Select master. #175 // #176
处理主控制器。 选择IDE主控制器命令。 #177 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect,0xA0); #178 #179 // #180 // Check if card at this address. #181 // #182
如果这里是一个IDE控制器,往柱面寄存器写入一个字节。 #183 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow,0xAA); #184 #185 // #186 // Check if indentifier can be read back. #187 // #188
再读取柱面寄存器的字节,如果不等于写入的,说明有问题。然后进入循环读取命令端口是否写入成功,如果尝试多次都不成功,说明这个不是IDE控制器。 #189 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { #190 #191 DebugPrint((2, #192 "AtapiFindController: Identifier read back from Master (%x)/n", #193 statusByte)); #194 #195 statusByte = ScsiPortReadPortUchar(&((PATAPI_REGISTERS_2)ioSpace)->AlternateStatus); #196 #197 if (statusByte & IDE_STATUS_BUSY) { #198 #199 i = 0; #200 #201 // #202 // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that #203 // warm boots don't clear. #204 // #205 #206 do { #207 ScsiPortStallExecution(1000); #208 statusByte = ScsiPortReadPortUchar(&((PATAPI_REGISTERS_1)ioSpace)->Command); #209 DebugPrint((3, #210 "AtapiFindController: First access to status %x/n", #211 statusByte)); #212 } while ((statusByte & IDE_STATUS_BUSY) && ++i < 10); #213 #214 if (retryCount-- && (!(statusByte & IDE_STATUS_BUSY))) { #215 goto retryIdentifier; #216 } #217 } #218
选从IDE控制器。 #219 // #220 // Select slave. #221 // #222 #223 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect,0xB0); #224 #225 // #226 // See if slave is present. #227 // #228
如果这里是一个IDE控制器,往柱面寄存器写入一个字节。
#229 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow,0xAA); #230
再读取柱面寄存器的字节,如果不等于写入的,说明有问题。然后进入循环读取命令端口是否写入成功,如果尝试多次都不成功,说明这个不是IDE控制器。
#231 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) { #232 #233 DebugPrint((2, #234 "AtapiFindController: Identifier read back from Slave (%x)/n", #235 statusByte)); #236 #237 // #238 // #239 // No controller at this base address. #240 // #241 #242 ScsiPortFreeDeviceBase(HwDeviceExtension, #243 ioSpace); #244 #245 continue; #246 } #247 } #248
保存IDE控制器的IO地址。 #249 // #250 // Record base IO address. #251 // #252 #253 deviceExtension->BaseIoAddress1[0] = (PIDE_REGISTERS_1)(ioSpace); #254 #255 // #256 // Fill in the access array information only if default params are not in there. #257 // #258 if (preConfig == FALSE) { #259 #260 // #261 // An adapter has been found request another call,only if we didn't get preconfigured info. #262 // #263 *Again = TRUE; #264 #265 if (portBase) { #266 (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(portBase); #267 } else { #268 (*ConfigInfo->AccessRanges)[0].RangeStart = #269 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]); #270 } #271 #272 (*ConfigInfo->AccessRanges)[0].RangeLength = 8; #273 (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE; #274
保存这个IDE控制器的中断号。 #275 // #276 // Indicate the interrupt level corresponding to this IO range. #277 // #278 #279 if (irq) { #280 ConfigInfo->BusInterruptLevel = irq; #281 } else { #282 ConfigInfo->BusInterruptLevel = InterruptLevels[*adapterCount - 1]; #283 } #284 #285 if (ConfigInfo->AdapterInterfaceType == MicroChannel) { #286 ConfigInfo->InterruptMode = LevelSensitive; #287 } else { #288 ConfigInfo->InterruptMode = Latched; #289 } #290 } #291 // #292 // Get the system physical address for the second IO range. #293 // #294 #295 #296 if (portBase) { #297 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, #298 ConfigInfo->AdapterInterfaceType, #299 ConfigInfo->SystemIoBusNumber, #300 ScsiPortConvertUlongToPhysicalAddress(portBase + 0x206), #301 1, #302 TRUE); #303 } else { #304 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension, #305 ConfigInfo->AdapterInterfaceType, #306 ConfigInfo->SystemIoBusNumber, #307 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1] + 0x206), #308 1, #309 TRUE); #310 } #311 #312 deviceExtension->BaseIoAddress2[0] = (PIDE_REGISTERS_2)(ioSpace); #313 #314 deviceExtension->NumberChannels = 1; #315 #316 ConfigInfo->NumberOfBuses = 1; #317 ConfigInfo->MaximumNumberOfTargets = 2; #318 #319 // #320 // Indicate maximum transfer length is 64k. #321 // #322 #323 ConfigInfo->MaximumTransferLength = 0x10000; #324 #325 DebugPrint((1, #326 "AtapiFindController: Found IDE at %x/n", #327 deviceExtension->BaseIoAddress1[0])); #328 #329 #330 // #331 // For Daytona,the atdisk driver gets the first shot at the #332 // primary and secondary controllers. #333 // #334 #335 if (preConfig == FALSE) { #336 #337 #338 if (*adapterCount - 1 < 2) { #339 #340 // #341 // Determine whether this driver is being initialized by the #342 // system or as a crash dump driver. #343 // #344 #345 if (ArgumentString) { #346 #347 if (AtapiParseArgumentString(ArgumentString,"dump") == 1) { #348 DebugPrint((3, #349 "AtapiFindController: Crash dump/n")); #350 atapiOnly = FALSE; #351 deviceExtension->DriverMustPoll = TRUE; #352 } else { #353 DebugPrint((3, #354 "AtapiFindController: Atapi Only/n")); #355 atapiOnly = TRUE; #356 deviceExtension->DriverMustPoll = FALSE; #357 } #358 } else { #359 #360 DebugPrint((3, #361 "AtapiFindController: Atapi Only/n")); #362 atapiOnly = TRUE; #363 deviceExtension->DriverMustPoll = FALSE; #364 } #365 #366 } else { #367 atapiOnly = FALSE; #368 } #369 #370 // #371 // If this is a PCI machine,pick up all devices. #372 // #373
如果是PCI的机器里,就保存所有IDE设备。 #374 #375 pciData = (PPCI_COMMON_CONFIG)&pciBuffer; #376 #377 slotData.u.bits.DeviceNumber = 0; #378 slotData.u.bits.FunctionNumber = 0; #379 #380 if (ScsiPortGetBusData(deviceExtension, #381 PCIConfiguration, #382 0, // BusNumber #383 slotData.u.AsULONG, #384 pciData, #385 sizeof(ULONG))) { #386 #387 atapiOnly = FALSE; #388 #389 // #390 // Wait on doing this,until a reliable method #391 // of determining support is found. #392 // #393 #394 #if 0 #395 deviceExtension->DWordIO = TRUE; #396 #endif #397 #398 } else { #399 deviceExtension->DWordIO = FALSE; #400 } #401 #402 } else { #403 #404 atapiOnly = FALSE; #405 deviceExtension->DriverMustPoll = FALSE; #406 #407 }// preConfig check #408 #409 // #410 // Save the Interrupe Mode for later use #411 // #412 deviceExtension->InterruptMode = ConfigInfo->InterruptMode; #413 #414 // #415 // Search for devices on this controller. #416 // #417
查找IDE控制器上所有设备。 #418 if (FindDevices(HwDeviceExtension, #419 atapiOnly, #420 0)) { #421 #422 // #423 // Claim primary or secondary ATA IO range. #424 // #425 #426 if (portBase) { #427 switch (portBase) {
如果配置这个IO,说明它是主控制器。 #428 case 0x170: #429 ConfigInfo->AtdiskSecondaryClaimed = TRUE; #430 deviceExtension->PrimaryAddress = FALSE; #431 break;
如果配置这个IO,说明它是从控制器。 #432 case 0x1f0: #433 ConfigInfo->AtdiskPrimaryClaimed = TRUE; #434 deviceExtension->PrimaryAddress = TRUE; #435 break; #436 default: #437 break; #438 } #439 } else { #440 if (*adapterCount == 1) { #441 ConfigInfo->AtdiskPrimaryClaimed = TRUE; #442 deviceExtension->PrimaryAddress = TRUE; #443 } else if (*adapterCount == 2) { #444 ConfigInfo->AtdiskSecondaryClaimed = TRUE; #445 deviceExtension->PrimaryAddress = FALSE; #446 } #447 } #448
这里返回成功找到的IDE控制器和IDE设备。 #449 return(SP_RETURN_FOUND); #450 } #451 } #452
下面是返回什么都没有找到的结果。 #453 // #454 // The entire table has been searched and no adapters have been found. #455 // There is no need to call again and the device base can now be freed. #456 // Clear the adapter count for the next bus. #457 // #458 #459 *Again = FALSE; #460 *(adapterCount) = 0; #461 #462 return(SP_RETURN_NOT_FOUND); #463 #464 } // end AtapiFindController()
HBA的全称为Host Bus Adapter,即主机总线适配器。
a、总线适配器是个什么东西呢? 我们首先要了解一下主机的结构,一台计算机内部多半由两条总线串在起来(当然实际情况会有不同,这里只讨论常见的,简单的情况),一条总线叫系统总线,一条叫I/O总线。系统总线上接了CPU,MEmory,cache什么的,I/O总线上接的就是外围设备,现如今最常见的就是PCI总线了。这两条总线之间用桥接的芯片或者说电路连接起来。举个形象的例子,就好比一个城市里,有两条主干道,一条属于行政区,一条属于商业区,中间有个环岛,将两条主干道连接到了一起,系统总线就好比行政区里的主干道,而I/O总线就好比商业区的主干道。系统总线和I/O总线的带宽的单位都是以Gbyte来记,但是显而易见的是,行政区的主干道和商业区的主干道相比的话,前者肯定更“核心”,更宽,更顺畅,设计的要求也高。 我们知道,在向公仆部门要求服务的时候,是要有一些接口的部门和程序的,而桥接芯片的作用就是连接和协调两条总线的工作的。 虽然I/O总线的速度和系统总线的带宽相比要低很多,但是好歹也是以G来计量的,而我们知道外围设备的速度,往往只有几百兆,甚至几十k而已,怎么协调工作呢?好比卖煎饼果子摊子不能直接戳到城市主干道上,怎么办?好办,在主干道边上开个2000平米的小吃城,把摊子都收进去好了。那么主机总线适配器的作用也就是这个,我们就是要把外设组织起来,连接到I/O总线上去!HBA就是指Host和I/O BUS直接的一个适配器,也好比一个水管工常说的“双通”。
b、常见的HBA有哪些呢? 比如显卡,网卡,scsi卡,1394卡等等。我要拿出来说的就是FCHBA和ATA&IDE。我们通常说的什么Emulex的LP9002,什么Qlogic的QLA2340都是FCHBA卡,就是将Fibre Channel的设备和IO总线连接起来的适配器。ATA也是一种适配器技术,我们PC主板上的ATA接口,就是一个磁盘适配器的对外接口,要强调的就是,ATA说的是适配器技术,IDE是说得存储外设技术,比如我们可以说IDE硬盘,IDE光驱,说ATA接口,但是说IDE接口,ATA硬盘就不时那么合适了,虽然很多情况下,大家都习惯把他们混在一起说。 描述HBA的时候,有几个主要的规范要说一下 > 一个承上,就是说,HBA和IOBUS怎么连,我们经常说的PCI接口卡,就是指这个HBA卡是要插在PCI BUS上的PCI slot上的,但是现在的计算机上,不仅仅只有PCI总线而已,大家碰到的时候留意。 >一个启下,就是说HBA要和外设怎么连,这样的规范就很多了。 >再说HBA本身,比如带宽,比如运行机制(protocol等),独立处理能力等等 Tips:有时候我们看到的一块卡,看到的实际是一个物理的卡,有的时候实际上是多个Adapter,好比一家机构,挂多个牌子,有的时候,一块卡有两条通道,好比一家公司,有两套人马。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |