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,好比一家机构,挂多个牌子,有的时候,一块卡有两条通道,好比一家公司,有两套人马。