reactos操作系统实现(105)

来源:互联网 发布:淘宝网刀具 编辑:程序博客网 时间:2024/05/01 03:08

AtapiFindController函数主要用来查找ATAPI控制器,也就是IDE控制器。同时收集IDE控制器相关配置信息,比如磁盘的访问方式。

#001  ULONG

#002  NTAPI

#003  AtapiFindController(

#004      IN PVOIDHwDeviceExtension,

#005      IN PVOID Context,

#006      IN PVOID BusInformation,

#007      IN PCHAR ArgumentString,

#008      IN OUTPPORT_CONFIGURATION_INFORMATION ConfigInfo,

#009      OUT PBOOLEAN Again

#010      )

#011  /*++

#012 

#013  Routine Description:

#014 

#015      This function is calledby the OS-specific port driver after

#016      the necessary storagehas been allocated, to gather information

#017      about the adapter'sconfiguration.

#018 

#019  Arguments:

#020 

#021      HwDeviceExtension - HBAminiport driver's adapter data storage

#022      Context - Address ofadapter count

#023      ArgumentString - Used todetermine whether driver is client of ntldr or crash dump utility.

#024      ConfigInfo -Configuration information structure describing HBA

#025      Again - Indicates searchfor adapters to continue

#026 

#027  Return Value:

#028 

#029      ULONG

#030 

#031  --*/

#032 

#033  {

#034      PHW_DEVICE_EXTENSIONdeviceExtension = 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 tablespecifies the ports to be checked when searching for

#049      // an IDEcontroller.  A zero entry terminates thesearch.

#050      //

#051 

 

IDE控制器的端口。

#052      CONST ULONGAdapterAddresses[5] = {0x1F0,0x170, 0x1e8, 0x168, 0};

#053 

#054      //

#055      // The following tablespecifies interrupt levels corresponding to the

#056      // port addresses in theprevious table.

#057      //

#058 

 

IDE控制器的中断号。

#059      CONST ULONGInterruptLevels[5] = {14, 15, 11, 10, 0};

#060 

#061      if (!deviceExtension) {

#062          returnSP_RETURN_ERROR;

#063      }

#064 

#065      //

#066      // Check to see if thisis 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 presentto proceed

#077              //

#078 

 

处理IDE控制器的基地址。

#079              portBase =AtapiParseArgumentString(ArgumentString, "BaseAddress");

 

如果端口为0,表示是非法的数据。

#080              if (!portBase) {

#081 

#082                  //

#083                  // Try adefault search for the part.

#084                  //

#085 

#086                  irq = 0;

#087              }

#088          }

#089      }

#090 

#091 

#092 

#093      //

#094      // Scan though theadapter 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 havepre-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 devicefields to ensure that if earlier devices were found,

#122              // but notclaimed, 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 systemphysical address for this IO range.

#130          //

#131 

#132 

#133          //

#134          // Check ifconfigInfo has the default information

#135          // if not, we go andfind ourselves

#136          //

#137 

 

获取相应IDEIO空间。

#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 theadapter count.

#159          //

#160 

 

处理下一个IDE控制器。

#161          (*adapterCount)++;

#162 

#163          //

#164          // Check if ioSpaceaccessible.

#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 atthis address.

#181          //

#182 

 

如果这里是一个IDE控制器,往柱面寄存器写入一个字节。

#183         ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow,0xAA);

#184 

#185          //

#186          // Check ifindentifier 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 bethe TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that

#203                  // warmboots 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                      gotoretryIdentifier;

#216                  }

#217              }

#218 

 

选从IDE控制器。

#219              //

#220              // Select slave.

#221              //

#222 

#223             ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect,0xB0);

#224 

#225              //

#226              // See if slaveis 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                  // Nocontroller at this base address.

#240                  //

#241 

#242                 ScsiPortFreeDeviceBase(HwDeviceExtension,

#243                                        ioSpace);

#244 

#245                  continue;

#246              }

#247          }

#248 

 

保存IDE控制器的IO地址。

#249          //

#250          // Record base IOaddress.

#251          //

#252 

#253         deviceExtension->BaseIoAddress1[0] = (PIDE_REGISTERS_1)(ioSpace);

#254 

#255          //

#256          // Fill in theaccess array information only if default params are not in there.

#257          //

#258          if (preConfig ==FALSE) {

#259 

#260              //

#261              // An adapterhas 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 theinterrupt 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 systemphysical 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 maximumtransfer 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, theatdisk driver gets the first shot at the

#332          // primary andsecondary controllers.

#333          //

#334 

#335          if (preConfig ==FALSE) {

#336 

#337 

#338              if(*adapterCount - 1 < 2) {

#339 

#340                  //

#341                  // Determinewhether this driver is being initialized by the

#342                  // system oras 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 aPCI 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 ondoing this, until a reliable method

#391                  // ofdetermining 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 theInterrupe Mode for later use

#411          //

#412          deviceExtension->InterruptMode= ConfigInfo->InterruptMode;

#413 

#414          //

#415          // Search fordevices on this controller.

#416          //

#417 

 

查找IDE控制器上所有设备。

#418          if(FindDevices(HwDeviceExtension,

#419                         atapiOnly,

#420                          0)){

#421 

#422              //

#423              // Claim primaryor 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 hasbeen searched and no adapters have been found.

#455      // There is no need tocall again and the device base can now be freed.

#456      // Clear the adaptercount for the next bus.

#457      //

#458 

#459      *Again = FALSE;

#460      *(adapterCount) = 0;

#461 

#462     return(SP_RETURN_NOT_FOUND);

#463 

#464  } // endAtapiFindController()

 

 

HBA的全称为Host Bus Adapter,即主机总线适配器。

 

a、总线适配器是个什么东西呢?

我们首先要了解一下主机的结构,一台计算机内部多半由两条总线串在起来(当然实际情况会有不同,这里只讨论常见的,简单的情况),一条总线叫系统总线,一条叫I/O总线。系统总线上接了CPUMEmorycache什么的,I/O总线上接的就是外围设备,现如今最常见的就是PCI总线了。这两条总线之间用桥接的芯片或者说电路连接起来。举个形象的例子,就好比一个城市里,有两条主干道,一条属于行政区,一条属于商业区,中间有个环岛,将两条主干道连接到了一起,系统总线就好比行政区里的主干道,而I/O总线就好比商业区的主干道。系统总线和I/O总线的带宽的单位都是以Gbyte来记,但是显而易见的是,行政区的主干道和商业区的主干道相比的话,前者肯定更“核心”,更宽,更顺畅,设计的要求也高。

我们知道,在向公仆部门要求服务的时候,是要有一些接口的部门和程序的,而桥接芯片的作用就是连接和协调两条总线的工作的。

虽然I/O总线的速度和系统总线的带宽相比要低很多,但是好歹也是以G来计量的,而我们知道外围设备的速度,往往只有几百兆,甚至几十k而已,怎么协调工作呢?好比卖煎饼果子摊子不能直接戳到城市主干道上,怎么办?好办,在主干道边上开个2000平米的小吃城,把摊子都收进去好了。那么主机总线适配器的作用也就是这个,我们就是要把外设组织起来,连接到I/O总线上去!HBA就是指HostI/O BUS直接的一个适配器,也好比一个水管工常说的“双通”。

 

 

b、常见的HBA有哪些呢?

比如显卡,网卡,scsi卡,1394卡等等。我要拿出来说的就是FCHBAATA&IDE。我们通常说的什么EmulexLP9002,什么QlogicQLA2340都是FCHBA卡,就是将FibreChannel的设备和IO总线连接起来的适配器。ATA也是一种适配器技术,我们PC主板上的ATA接口,就是一个磁盘适配器的对外接口,要强调的就是,ATA说的是适配器技术,IDE是说得存储外设技术,比如我们可以说IDE硬盘,IDE光驱,说ATA接口,但是说IDE接口,ATA硬盘就不时那么合适了,虽然很多情况下,大家都习惯把他们混在一起说。

描述HBA的时候,有几个主要的规范要说一下

  > 一个承上,就是说,HBAIOBUS怎么连,我们经常说的PCI接口卡,就是指这个HBA卡是要插在PCI BUS上的PCIslot上的,但是现在的计算机上,不仅仅只有PCI总线而已,大家碰到的时候留意。

  >一个启下,就是说HBA要和外设怎么连,这样的规范就很多了。

  >再说HBA本身,比如带宽,比如运行机制(protocol),独立处理能力等等

Tips:有时候我们看到的一块卡,看到的实际是一个物理的卡,有的时候实际上是多个Adapter,好比一家机构,挂多个牌子,有的时候,一块卡有两条通道,好比一家公司,有两套人马。

原创粉丝点击