reactos操作系统实现(107)
IssueIdentify函数主要是发送IDENTIFY命令给一个ATAPI设备,并且获取这个设备相关信息,比如磁头的个数。
#001 BOOLEAN
#002 NTAPI
#003 IssueIdentify(
#004 IN PVOID HwDeviceExtension,
#005 IN ULONG DeviceNumber,
#006 IN ULONG Channel,
#007 IN UCHAR Command
#008 )
#009
#010 /*++
#011
#012 Routine Description:
#013
#014 Issue IDENTIFY command to a device.
#015
#016 Arguments:
#017
#018 HwDeviceExtension - HBA miniport driver's adapter data storage
#019 DeviceNumber - Indicates which device.
#020 Command - Either the standard (EC) or the ATAPI packet (A1) IDENTIFY.
#021
#022 Return Value:
#023
#024 TRUE if all goes well.
#025
#026 --*/
#027
#028 {
获取IDE控制器的IO基地址。
#029 PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
#030 PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel] ;
#031 PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel];
#032 ULONG waitCount = 20000;
#033 ULONG i,j;
#034 UCHAR statusByte;
#035 UCHAR signatureLow,
#036 signatureHigh;
#037
#038 //
#039 // Select device 0 or 1.
#040 //
#041
选择设备0,或者设备1。
#042 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
#043 (UCHAR)((DeviceNumber << 4) | 0xA0));
#044
#045 //
#046 // Check that the status register makes sense.
#047 //
#048
获取选择设备的状态。
#049 GetBaseStatus(baseIoAddress1, statusByte);
#050
如果发送命令不是IDENTIFY,就不进入处理。
#051 if (Command == IDE_COMMAND_IDENTIFY) {
#052
#053 //
#054 // Mask status byte ERROR bits.
#055 //
#056
获取错误状态位。
#057 statusByte &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX);
#058
#059 DebugPrint((1,
#060 "IssueIdentify: Checking for IDE. Status (%x)/n",
#061 statusByte));
#062
#063 //
#064 // Check if register value is reasonable.
#065 //
#066
如果IDE控制器不空闲,就不复位它。
#067 if (statusByte != IDE_STATUS_IDLE) {
#068
#069 //
#070 // Reset the controller.
#071 //
#072
复位IDE控制器。
#073 AtapiSoftReset(baseIoAddress1,DeviceNumber);
#074
重新选择控制器。
#075 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
#076 (UCHAR)((DeviceNumber << 4) | 0xA0));
#077
获取执行命令完成。
#078 WaitOnBusy(baseIoAddress2,statusByte);
#079
读取ATAPI标识,如果还是ATAPI就返回出错。
#080 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
#081 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
#082
#083 if (signatureLow == 0x14 && signatureHigh == 0xEB) {
#084
#085 //
#086 // Device is Atapi.
#087 //
#088
#089 return FALSE;
#090 }
#091
发送IDE_DC_RESET_CONTROLLER命令。
#092 DebugPrint((1,
#093 "IssueIdentify: Resetting controller./n"));
#094
#095 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER );
#096 ScsiPortStallExecution(500 * 1000);
#097 ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);
#098
#099
#100 // We really should wait up to 31 seconds
#101 // The ATA spec. allows device 0 to come back from BUSY in 31 seconds!
#102 // (30 seconds for device 1)
等IDE控制器准备好。
#103 do {
#104
#105 //
#106 // Wait for Busy to drop.
#107 //
#108
#109 ScsiPortStallExecution(100);
#110 GetStatus(baseIoAddress2, statusByte);
#111
#112 } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
#113
#114 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
#115 (UCHAR)((DeviceNumber << 4) | 0xA0));
#116
#117 //
#118 // Another check for signature, to deal with one model Atapi that doesn't assert signature after
#119 // a soft reset.
#120 //
#121
如果读取IDE标识,还是ATAPI就返回出错。
#122 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
#123 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
#124
#125 if (signatureLow == 0x14 && signatureHigh == 0xEB) {
#126
#127 //
#128 // Device is Atapi.
#129 //
#130
#131 return FALSE;
#132 }
#133
#134 statusByte &= ~IDE_STATUS_INDEX;
#135
如果读取不成功,还是忙等,那么说明这个控制器有问题返回。
#136 if (statusByte != IDE_STATUS_IDLE) {
#137
#138 //
#139 // Give up on this.
#140 //
#141
#142 return FALSE;
#143 }
#144
#145 }
#146
#147 } else {
#148
#149 DebugPrint((1,
#150 "IssueIdentify: Checking for ATAPI. Status (%x)/n",
#151 statusByte));
#152
#153 }
#154
#155 //
#156 // Load CylinderHigh and CylinderLow with number bytes to transfer.
#157 //
#158
#159 ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh, (0x200 >> 8));
#160 ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow, (0x200 & 0xFF));
#161
#162 for (j = 0; j < 2; j++) {
#163
#164 //
#165 // Send IDENTIFY command.
#166 //
#167
#168 WaitOnBusy(baseIoAddress2,statusByte);
#169
发送一个IDENTIFY命令。
#170 ScsiPortWritePortUchar(&baseIoAddress1->Command, Command);
#171
#172 //
#173 // Wait for DRQ.
#174 //
#175
等DRQ状态出现。
#176 for (i = 0; i < 4; i++) {
#177
#178 WaitForDrq(baseIoAddress2, statusByte);
#179
如果出现DRQ状态,说明回应数据已经准备好。
#180 if (statusByte & IDE_STATUS_DRQ) {
#181
#182 //
#183 // Read status to acknowledge any interrupts generated.
#184 //
#185
#186 GetBaseStatus(baseIoAddress1, statusByte);
#187
#188 //
#189 // One last check for Atapi.
#190 //
#191
#192
如果读取还是ATAPI标识,说明出错。
#193 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
#194 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
#195
#196 if (signatureLow == 0x14 && signatureHigh == 0xEB) {
#197
#198 //
#199 // Device is Atapi.
#200 //
#201
#202 return FALSE;
#203 }
#204
#205 break;
#206 }
#207
如果读取还是ATAPI标识,说明出错。
#208 if (Command == IDE_COMMAND_IDENTIFY) {
#209
#210 //
#211 // Check the signature. If DRQ didn't come up it's likely Atapi.
#212 //
#213
#214 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
#215 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
#216
#217 if (signatureLow == 0x14 && signatureHigh == 0xEB) {
#218
#219 //
#220 // Device is Atapi.
#221 //
#222
#223 return FALSE;
#224 }
#225 }
#226
#227 WaitOnBusy(baseIoAddress2,statusByte);
#228 }
#229
进行第二次尝试复位。
#230 if (i == 4 && j == 0) {
#231
#232 //
#233 // Device didn't respond correctly. It will be given one more chances.
#234 //
#235
#236 DebugPrint((1,
#237 "IssueIdentify: DRQ never asserted (%x). Error reg (%x)/n",
#238 statusByte,
#239 ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1)));
#240
#241 AtapiSoftReset(baseIoAddress1,DeviceNumber);
#242
#243 GetStatus(baseIoAddress2,statusByte);
#244
#245 DebugPrint((1,
#246 "IssueIdentify: Status after soft reset (%x)/n",
#247 statusByte));
#248
#249 } else {
#250
#251 break;
#252
#253 }
#254 }
#255
#256 //
#257 // Check for error on really stupid master devices that assert random
#258 // patterns of bits in the status register at the slave address.
#259 //
#260
如果状态出错,说明不认识这个命令。
#261 if ((Command == IDE_COMMAND_IDENTIFY) && (statusByte & IDE_STATUS_ERROR)) {
#262 return FALSE;
#263 }
#264
#265 DebugPrint((1,
#266 "IssueIdentify: Status before read words %x/n",
#267 statusByte));
#268
#269 //
#270 // Suck out 256 words. After waiting for one model that asserts busy
#271 // after receiving the Packet Identify command.
#272 //
#273
等准备好数据。
#274 WaitOnBusy(baseIoAddress2,statusByte);
#275
#276 if (!(statusByte & IDE_STATUS_DRQ)) {
#277 return FALSE;
#278 }
#279
读IDE的IDE_COMMAND_IDENTIFY命令返回的512个字节。
#280 ReadBuffer(baseIoAddress1,
#281 (PUSHORT)&deviceExtension->FullIdentifyData,
#282 256);
#283
#284 //
#285 // Check out a few capabilities / limitations of the device.
#286 //
#287
检查IDE控制器兼容性。
#288 if (deviceExtension->FullIdentifyData.SpecialFunctionsEnabled & 1) {
#289
#290 //
#291 // Determine if this drive supports the MSN functions.
#292 //
#293
查看是否支持可移动特性。
#294 DebugPrint((2,"IssueIdentify: Marking drive %d as removable. SFE = %d/n",
#295 Channel * 2 + DeviceNumber,
#296 deviceExtension->FullIdentifyData.SpecialFunctionsEnabled));
#297
#298
#299 deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_REMOVABLE_DRIVE;
#300 }
#301
设置最大块传送参数。
#302 if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) {
#303
#304 //
#305 // Determine max. block transfer for this device.
#306 //
#307
#308 deviceExtension->MaximumBlockXfer[(Channel * 2) + DeviceNumber] =
#309 (UCHAR)(deviceExtension->FullIdentifyData.MaximumBlockTransfer & 0xFF);
#310 }
#311
#312 ScsiPortMoveMemory(&deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber],&deviceExtension->FullIdentifyData,sizeof(IDENTIFY_DATA2));
#313
#314 if (deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0x20 &&
#315 Command != IDE_COMMAND_IDENTIFY) {
#316
#317 //
#318 // This device interrupts with the assertion of DRQ after receiving
#319 // Atapi Packet Command
#320 //
#321
#322 deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_INT_DRQ;
#323
#324 DebugPrint((2,
#325 "IssueIdentify: Device interrupts on assertion of DRQ./n"));
#326
#327 } else {
#328
#329 DebugPrint((2,
#330 "IssueIdentify: Device does not interrupt on assertion of DRQ./n"));
#331 }
判断这个是否磁带设备。
#332
#333 if (((deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0xF00) == 0x100) &&
#334 Command != IDE_COMMAND_IDENTIFY) {
#335
#336 //
#337 // This is a tape.
#338 //
#339
这是一个TAPE设备。
#340 deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_TAPE_DEVICE;
#341
#342 DebugPrint((2,
#343 "IssueIdentify: Device is a tape drive./n"));
#344
#345 } else {
#346
#347 DebugPrint((2,
#348 "IssueIdentify: Device is not a tape drive./n"));
#349 }
#350
#351 //
#352 // Work around for some IDE and one model Atapi that will present more than
#353 // 256 bytes for the Identify data.
#354 //
#355
#356 WaitOnBusy(baseIoAddress2,statusByte);
#357
读取超过256个字节IDE传送的数据。
#358 for (i = 0; i < 0x10000; i++) {
#359
#360 GetStatus(baseIoAddress2,statusByte);
#361
#362 if (statusByte & IDE_STATUS_DRQ) {
#363
#364 //
#365 // Suck out any remaining bytes and throw away.
#366 //
#367
#368 ScsiPortReadPortUshort(&baseIoAddress1->Data);
#369
#370 } else {
#371
#372 break;
#373
#374 }
#375 }
#376
#377 DebugPrint((3,
#378 "IssueIdentify: Status after read words (%x)/n",
#379 statusByte));
#380
#381 return TRUE;
#382
#383 } // end IssueIdentify()