]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c
IntelFrameworkModulePkg: Clean up source files
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / IdeBusDxe / Ide.c
CommitLineData
ead42efc 1/** @file\r
630d580d 2 The file ontaining the helper functions implement of the Ide Bus driver\r
0a6f4824
LG
3\r
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
180a5a35 5 This program and the accompanying materials\r
ead42efc 6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
03417d8d 15#include "IdeBus.h"\r
ead42efc 16\r
17BOOLEAN ChannelDeviceDetected = FALSE;\r
18BOOLEAN SlaveDeviceExist = FALSE;\r
19UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;\r
20BOOLEAN MasterDeviceExist = FALSE;\r
21UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;\r
22\r
23/**\r
cd57e888 24 read a one-byte data from a IDE port.\r
ead42efc 25\r
630d580d 26 @param PciIo The PCI IO protocol instance\r
0a6f4824 27 @param Port the IDE Port number\r
ead42efc 28\r
cd57e888 29 @return the one-byte data read from IDE port\r
ead42efc 30**/\r
31UINT8\r
32IDEReadPortB (\r
33 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
34 IN UINT16 Port\r
35 )\r
36{\r
37 UINT8 Data;\r
38\r
39 Data = 0;\r
40 //\r
41 // perform 1-byte data read from register\r
42 //\r
43 PciIo->Io.Read (\r
44 PciIo,\r
45 EfiPciIoWidthUint8,\r
46 EFI_PCI_IO_PASS_THROUGH_BAR,\r
47 (UINT64) Port,\r
48 1,\r
49 &Data\r
50 );\r
51 return Data;\r
52}\r
ead42efc 53/**\r
54 Reads multiple words of data from the IDE data port.\r
55 Call the IO abstraction once to do the complete read,\r
56 not one word at a time\r
57\r
58 @param PciIo Pointer to the EFI_PCI_IO instance\r
59 @param Port IO port to read\r
60 @param Count No. of UINT16's to read\r
61 @param Buffer Pointer to the data buffer for read\r
62\r
63**/\r
64VOID\r
65IDEReadPortWMultiple (\r
66 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
67 IN UINT16 Port,\r
68 IN UINTN Count,\r
97404058 69 OUT VOID *Buffer\r
ead42efc 70 )\r
71{\r
72 UINT16 *AlignedBuffer;\r
73 UINT16 *WorkingBuffer;\r
74 UINTN Size;\r
75\r
76 //\r
77 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
78 // not perform actual I/O operations if buffer pointer passed in is not at\r
79 // natural boundary. The "Buffer" argument is passed in by user and may not\r
80 // at 16-bit natural boundary.\r
81 //\r
82 Size = sizeof (UINT16) * Count;\r
83\r
84 gBS->AllocatePool (\r
85 EfiBootServicesData,\r
86 Size + 1,\r
87 (VOID**)&WorkingBuffer\r
88 );\r
89\r
90 AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
91\r
92 //\r
93 // Perform UINT16 data read from FIFO\r
94 //\r
95 PciIo->Io.Read (\r
96 PciIo,\r
97 EfiPciIoWidthFifoUint16,\r
98 EFI_PCI_IO_PASS_THROUGH_BAR,\r
99 (UINT64) Port,\r
100 Count,\r
101 (UINT16*)AlignedBuffer\r
102 );\r
103\r
104 //\r
105 // Copy data to user buffer\r
106 //\r
107 CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);\r
108 gBS->FreePool (WorkingBuffer);\r
109}\r
110\r
111/**\r
cd57e888 112 write a 1-byte data to a specific IDE port.\r
ead42efc 113\r
630d580d 114 @param PciIo PCI IO protocol instance\r
115 @param Port The IDE port to be writen\r
116 @param Data The data to write to the port\r
ead42efc 117**/\r
118VOID\r
119IDEWritePortB (\r
120 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
121 IN UINT16 Port,\r
122 IN UINT8 Data\r
123 )\r
124{\r
125 //\r
126 // perform 1-byte data write to register\r
127 //\r
128 PciIo->Io.Write (\r
129 PciIo,\r
130 EfiPciIoWidthUint8,\r
131 EFI_PCI_IO_PASS_THROUGH_BAR,\r
132 (UINT64) Port,\r
133 1,\r
134 &Data\r
135 );\r
136\r
137}\r
138\r
139/**\r
cd57e888 140 write a 1-word data to a specific IDE port.\r
ead42efc 141\r
630d580d 142 @param PciIo PCI IO protocol instance\r
143 @param Port The IDE port to be writen\r
144 @param Data The data to write to the port\r
ead42efc 145**/\r
146VOID\r
147IDEWritePortW (\r
148 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
149 IN UINT16 Port,\r
150 IN UINT16 Data\r
151 )\r
152{\r
153 //\r
154 // perform 1-word data write to register\r
155 //\r
156 PciIo->Io.Write (\r
157 PciIo,\r
158 EfiPciIoWidthUint16,\r
159 EFI_PCI_IO_PASS_THROUGH_BAR,\r
160 (UINT64) Port,\r
161 1,\r
162 &Data\r
163 );\r
164}\r
165\r
166/**\r
167 Write multiple words of data to the IDE data port.\r
168 Call the IO abstraction once to do the complete read,\r
169 not one word at a time\r
170\r
171 @param PciIo Pointer to the EFI_PCI_IO instance\r
172 @param Port IO port to read\r
173 @param Count No. of UINT16's to read\r
174 @param Buffer Pointer to the data buffer for read\r
175\r
176**/\r
177VOID\r
178IDEWritePortWMultiple (\r
179 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
180 IN UINT16 Port,\r
181 IN UINTN Count,\r
182 IN VOID *Buffer\r
183 )\r
184{\r
185 UINT16 *AlignedBuffer;\r
186 UINT32 *WorkingBuffer;\r
187 UINTN Size;\r
188\r
189 //\r
190 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
191 // not perform actual I/O operations if buffer pointer passed in is not at\r
192 // natural boundary. The "Buffer" argument is passed in by user and may not\r
193 // at 16-bit natural boundary.\r
194 //\r
195 Size = sizeof (UINT16) * Count;\r
196\r
197 gBS->AllocatePool (\r
198 EfiBootServicesData,\r
199 Size + 1,\r
200 (VOID **) &WorkingBuffer\r
201 );\r
202\r
203 AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
204\r
205 //\r
206 // Copy data from user buffer to working buffer\r
207 //\r
208 CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);\r
209\r
210 //\r
211 // perform UINT16 data write to the FIFO\r
212 //\r
213 PciIo->Io.Write (\r
214 PciIo,\r
215 EfiPciIoWidthFifoUint16,\r
216 EFI_PCI_IO_PASS_THROUGH_BAR,\r
217 (UINT64) Port,\r
218 Count,\r
219 (UINT16 *) AlignedBuffer\r
220 );\r
221\r
222 gBS->FreePool (WorkingBuffer);\r
223}\r
ead42efc 224/**\r
225 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
226 use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
227 the PCI IDE controller's Configuration Space.\r
228\r
229 The steps to get IDE IO port registers' base addresses for each channel\r
230 as follows:\r
231\r
232 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
233 controller's Configuration Space to determine the operating mode.\r
234\r
235 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
236 <pre>\r
237 ___________________________________________\r
238 | | Command Block | Control Block |\r
239 | Channel | Registers | Registers |\r
240 |___________|_______________|_______________|\r
241 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
242 |___________|_______________|_______________|\r
243 | Secondary | 170h - 177h | 376h - 377h |\r
244 |___________|_______________|_______________|\r
245\r
246 Table 1. Compatibility resource mappings\r
247 </pre>\r
248\r
249 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
250 in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
251 <pre>\r
252 ___________________________________________________\r
253 | | Command Block | Control Block |\r
254 | Channel | Registers | Registers |\r
255 |___________|___________________|___________________|\r
256 | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
257 |___________|___________________|___________________|\r
258 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
259 |___________|___________________|___________________|\r
260\r
261 Table 2. BARs for Register Mapping\r
262 </pre>\r
263 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for\r
264 primary, 0374h for secondary. So 2 bytes extra offset should be\r
265 added to the base addresses read from BARs.\r
266\r
267 For more details, please refer to PCI IDE Controller Specification and Intel\r
268 ICH4 Datasheet.\r
269\r
270 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
271 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to\r
cd57e888 272 receive IDE IO port registers' base addresses\r
0a6f4824 273\r
cd57e888 274 @retval EFI_UNSUPPORTED return this value when the BARs is not IO type\r
275 @retval EFI_SUCCESS Get the Base address successfully\r
276 @retval other read the pci configureation data error\r
ead42efc 277\r
278**/\r
279EFI_STATUS\r
280GetIdeRegistersBaseAddr (\r
281 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
282 OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
283 )\r
ead42efc 284{\r
285 EFI_STATUS Status;\r
286 PCI_TYPE00 PciData;\r
287\r
288 Status = PciIo->Pci.Read (\r
289 PciIo,\r
290 EfiPciIoWidthUint8,\r
291 0,\r
292 sizeof (PciData),\r
293 &PciData\r
294 );\r
295\r
296 if (EFI_ERROR (Status)) {\r
297 return Status;\r
298 }\r
299\r
300 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
301 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;\r
302 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;\r
303 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
304 (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
305 } else {\r
306 //\r
307 // The BARs should be of IO type\r
308 //\r
1e23bd8d 309 if ((PciData.Device.Bar[0] & BIT0) == 0 ||\r
310 (PciData.Device.Bar[1] & BIT0) == 0) {\r
ead42efc 311 return EFI_UNSUPPORTED;\r
312 }\r
313\r
314 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =\r
315 (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
316 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =\r
317 (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
318 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
319 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
320 }\r
321\r
322 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
323 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;\r
324 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;\r
325 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
326 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
327 } else {\r
328 //\r
329 // The BARs should be of IO type\r
330 //\r
1e23bd8d 331 if ((PciData.Device.Bar[2] & BIT0) == 0 ||\r
332 (PciData.Device.Bar[3] & BIT0) == 0) {\r
ead42efc 333 return EFI_UNSUPPORTED;\r
334 }\r
335\r
336 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =\r
337 (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
338 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =\r
339 (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
340 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
341 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
342 }\r
343\r
344 return EFI_SUCCESS;\r
345}\r
346\r
347/**\r
348 This function is used to requery IDE resources. The IDE controller will\r
349 probably switch between native and legacy modes during the EFI->CSM->OS\r
350 transfer. We do this everytime before an BlkIo operation to ensure its\r
351 succeess.\r
352\r
353 @param IdeDev The BLK_IO private data which specifies the IDE device\r
0a6f4824 354\r
cd57e888 355 @retval EFI_INVALID_PARAMETER return this value when the channel is invalid\r
356 @retval EFI_SUCCESS reassign the IDE IO resource successfully\r
357 @retval other get the IDE current base address effor\r
ead42efc 358\r
359**/\r
360EFI_STATUS\r
361ReassignIdeResources (\r
362 IN IDE_BLK_IO_DEV *IdeDev\r
363 )\r
ead42efc 364{\r
365 EFI_STATUS Status;\r
366 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];\r
367 UINT16 CommandBlockBaseAddr;\r
368 UINT16 ControlBlockBaseAddr;\r
369\r
aa950314 370 if (IdeDev->Channel >= IdeMaxChannel) {\r
371 return EFI_INVALID_PARAMETER;\r
372 }\r
0a6f4824 373\r
ead42efc 374 //\r
375 // Requery IDE IO port registers' base addresses in case of the switch of\r
376 // native and legacy modes\r
377 //\r
378 Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);\r
379 if (EFI_ERROR (Status)) {\r
380 return Status;\r
381 }\r
382\r
383 ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));\r
384 CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;\r
385 ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;\r
386\r
387 IdeDev->IoPort->Data = CommandBlockBaseAddr;\r
388 (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
389 IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
390 IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
391 IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
392 IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
393 IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
394\r
395 (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
396 (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;\r
397 IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
398 IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);\r
399\r
400 IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;\r
401 return EFI_SUCCESS;\r
402}\r
403\r
ead42efc 404/**\r
405 This function is called by DiscoverIdeDevice(). It is used for detect\r
406 whether the IDE device exists in the specified Channel as the specified\r
407 Device Number.\r
408\r
409 There is two IDE channels: one is Primary Channel, the other is\r
410 Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
411 Different channel has different register group.\r
412\r
413 On each IDE channel, at most two IDE devices attach,\r
414 one is called Device 0 (Master device), the other is called Device 1\r
415 (Slave device). The devices on the same channel co-use the same register\r
416 group, so before sending out a command for a specified device via command\r
417 register, it is a must to select the current device to accept the command\r
418 by set the device number in the Head/Device Register.\r
419\r
630d580d 420 @param IdeDev pointer to IDE_BLK_IO_DEV data structure, used to record all the\r
421 information of the IDE device.\r
ead42efc 422\r
630d580d 423 @retval EFI_SUCCESS successfully detects device.\r
ead42efc 424\r
630d580d 425 @retval other any failure during detection process will return this value.\r
ead42efc 426\r
427**/\r
428EFI_STATUS\r
429DetectIDEController (\r
430 IN IDE_BLK_IO_DEV *IdeDev\r
431 )\r
432{\r
433 EFI_STATUS Status;\r
434 UINT8 SectorCountReg;\r
435 UINT8 LBALowReg;\r
436 UINT8 LBAMidReg;\r
437 UINT8 LBAHighReg;\r
438 UINT8 InitStatusReg;\r
439 UINT8 StatusReg;\r
440\r
441 //\r
442 // Select slave device\r
443 //\r
444 IDEWritePortB (\r
445 IdeDev->PciIo,\r
446 IdeDev->IoPort->Head,\r
447 (UINT8) ((1 << 4) | 0xe0)\r
448 );\r
449 gBS->Stall (100);\r
450\r
451 //\r
452 // Save the init slave status register\r
453 //\r
454 InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
455\r
456 //\r
457 // Select Master back\r
458 //\r
459 IDEWritePortB (\r
460 IdeDev->PciIo,\r
461 IdeDev->IoPort->Head,\r
462 (UINT8) ((0 << 4) | 0xe0)\r
463 );\r
464 gBS->Stall (100);\r
465\r
466 //\r
467 // Send ATA Device Execut Diagnostic command.\r
468 // This command should work no matter DRDY is ready or not\r
469 //\r
470 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
471\r
472 Status = WaitForBSYClear (IdeDev, 3500);\r
473 if (EFI_ERROR (Status)) {\r
474 DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
475 return Status;\r
476 }\r
477 //\r
478 // Read device signature\r
479 //\r
480 //\r
481 // Select Master\r
482 //\r
483 IDEWritePortB (\r
484 IdeDev->PciIo,\r
485 IdeDev->IoPort->Head,\r
486 (UINT8) ((0 << 4) | 0xe0)\r
487 );\r
488 gBS->Stall (100);\r
489 SectorCountReg = IDEReadPortB (\r
490 IdeDev->PciIo,\r
491 IdeDev->IoPort->SectorCount\r
492 );\r
493 LBALowReg = IDEReadPortB (\r
494 IdeDev->PciIo,\r
495 IdeDev->IoPort->SectorNumber\r
496 );\r
497 LBAMidReg = IDEReadPortB (\r
498 IdeDev->PciIo,\r
499 IdeDev->IoPort->CylinderLsb\r
500 );\r
501 LBAHighReg = IDEReadPortB (\r
502 IdeDev->PciIo,\r
503 IdeDev->IoPort->CylinderMsb\r
504 );\r
505 if ((SectorCountReg == 0x1) &&\r
506 (LBALowReg == 0x1) &&\r
507 (LBAMidReg == 0x0) &&\r
508 (LBAHighReg == 0x0)) {\r
509 MasterDeviceExist = TRUE;\r
510 MasterDeviceType = ATA_DEVICE_TYPE;\r
511 } else {\r
512 if ((LBAMidReg == 0x14) &&\r
513 (LBAHighReg == 0xeb)) {\r
514 MasterDeviceExist = TRUE;\r
515 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
516 }\r
517 }\r
518\r
519 //\r
520 // For some Hard Drive, it takes some time to get\r
521 // the right signature when operating in single slave mode.\r
522 // We stall 20ms to work around this.\r
523 //\r
524 if (!MasterDeviceExist) {\r
525 gBS->Stall (20000);\r
526 }\r
527\r
528 //\r
529 // Select Slave\r
530 //\r
531 IDEWritePortB (\r
532 IdeDev->PciIo,\r
533 IdeDev->IoPort->Head,\r
534 (UINT8) ((1 << 4) | 0xe0)\r
535 );\r
536 gBS->Stall (100);\r
537 SectorCountReg = IDEReadPortB (\r
538 IdeDev->PciIo,\r
539 IdeDev->IoPort->SectorCount\r
540 );\r
541 LBALowReg = IDEReadPortB (\r
542 IdeDev->PciIo,\r
543 IdeDev->IoPort->SectorNumber\r
544 );\r
545 LBAMidReg = IDEReadPortB (\r
546 IdeDev->PciIo,\r
547 IdeDev->IoPort->CylinderLsb\r
548 );\r
549 LBAHighReg = IDEReadPortB (\r
550 IdeDev->PciIo,\r
551 IdeDev->IoPort->CylinderMsb\r
552 );\r
553 StatusReg = IDEReadPortB (\r
554 IdeDev->PciIo,\r
555 IdeDev->IoPort->Reg.Status\r
556 );\r
557 if ((SectorCountReg == 0x1) &&\r
558 (LBALowReg == 0x1) &&\r
559 (LBAMidReg == 0x0) &&\r
560 (LBAHighReg == 0x0)) {\r
561 SlaveDeviceExist = TRUE;\r
562 SlaveDeviceType = ATA_DEVICE_TYPE;\r
563 } else {\r
564 if ((LBAMidReg == 0x14) &&\r
565 (LBAHighReg == 0xeb)) {\r
566 SlaveDeviceExist = TRUE;\r
567 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
568 }\r
569 }\r
570\r
571 //\r
572 // When single master is plugged, slave device\r
573 // will be wrongly detected. Here's the workaround\r
574 // for ATA devices by detecting DRY bit in status\r
575 // register.\r
576 // NOTE: This workaround doesn't apply to ATAPI.\r
577 //\r
578 if (MasterDeviceExist && SlaveDeviceExist &&\r
1e23bd8d 579 (StatusReg & ATA_STSREG_DRDY) == 0 &&\r
580 (InitStatusReg & ATA_STSREG_DRDY) == 0 &&\r
ead42efc 581 MasterDeviceType == SlaveDeviceType &&\r
582 SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
583 SlaveDeviceExist = FALSE;\r
584 }\r
585\r
586 //\r
587 // Indicate this channel has been detected\r
588 //\r
589 ChannelDeviceDetected = TRUE;\r
590 return EFI_SUCCESS;\r
591}\r
630d580d 592/**\r
593 Detect if there is disk attached to this port\r
594\r
595 @param IdeDev The BLK_IO private data which specifies the IDE device.\r
0a6f4824 596\r
cd57e888 597 @retval EFI_NOT_FOUND The device or channel is not found\r
598 @retval EFI_SUCCESS The device is found\r
630d580d 599\r
600**/\r
601EFI_STATUS\r
602DiscoverIdeDevice (\r
603 IN IDE_BLK_IO_DEV *IdeDev\r
604 )\r
605{\r
606 EFI_STATUS Status;\r
607 EFI_STATUS LongPhyStatus;\r
608\r
609 //\r
610 // If a channel has not been checked, check it now. Then set it to "checked" state\r
611 // After this step, all devices in this channel have been checked.\r
612 //\r
613 if (!ChannelDeviceDetected) {\r
614 Status = DetectIDEController (IdeDev);\r
615 if (EFI_ERROR (Status)) {\r
616 return EFI_NOT_FOUND;\r
617 }\r
618 }\r
619\r
620 Status = EFI_NOT_FOUND;\r
621\r
622 //\r
623 // Device exists. test if it is an ATA device.\r
624 // Prefer the result from DetectIDEController,\r
625 // if failed, try another device type to handle\r
626 // devices that not follow the spec.\r
627 //\r
628 if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
629 if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
630 Status = ATAIdentify (IdeDev);\r
631 if (EFI_ERROR (Status)) {\r
632 Status = ATAPIIdentify (IdeDev);\r
633 if (!EFI_ERROR (Status)) {\r
634 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
635 }\r
636 }\r
637 } else {\r
638 Status = ATAPIIdentify (IdeDev);\r
639 if (EFI_ERROR (Status)) {\r
640 Status = ATAIdentify (IdeDev);\r
641 if (!EFI_ERROR (Status)) {\r
642 MasterDeviceType = ATA_DEVICE_TYPE;\r
643 }\r
644 }\r
645 }\r
646 }\r
647 if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
648 if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
649 Status = ATAIdentify (IdeDev);\r
650 if (EFI_ERROR (Status)) {\r
651 Status = ATAPIIdentify (IdeDev);\r
652 if (!EFI_ERROR (Status)) {\r
653 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
654 }\r
655 }\r
656 } else {\r
657 Status = ATAPIIdentify (IdeDev);\r
658 if (EFI_ERROR (Status)) {\r
659 Status = ATAIdentify (IdeDev);\r
660 if (!EFI_ERROR (Status)) {\r
661 SlaveDeviceType = ATA_DEVICE_TYPE;\r
662 }\r
663 }\r
664 }\r
665 }\r
666 if (EFI_ERROR (Status)) {\r
667 return EFI_NOT_FOUND;\r
668 }\r
669 //\r
670 // Init Block I/O interface\r
671 //\r
672 LongPhyStatus = AtaEnableLongPhysicalSector (IdeDev);\r
673 if (!EFI_ERROR (LongPhyStatus)) {\r
674 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
675 } else {\r
676 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
677 }\r
678 IdeDev->BlkIo.Reset = IDEBlkIoReset;\r
679 IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;\r
680 IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;\r
681 IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;\r
682\r
683 IdeDev->BlkMedia.LogicalPartition = FALSE;\r
684 IdeDev->BlkMedia.WriteCaching = FALSE;\r
ead42efc 685\r
630d580d 686 //\r
687 // Init Disk Info interface\r
688 //\r
689 gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));\r
690 IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;\r
691 IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;\r
692 IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;\r
693 IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;\r
694\r
695 return EFI_SUCCESS;\r
696}\r
697\r
698/**\r
699 This interface is used to initialize all state data related to the detection of one\r
700 channel.\r
630d580d 701**/\r
9b906315 702VOID\r
630d580d 703InitializeIDEChannelData (\r
704 VOID\r
705 )\r
706{\r
707 ChannelDeviceDetected = FALSE;\r
708 MasterDeviceExist = FALSE;\r
709 MasterDeviceType = 0xff;\r
710 SlaveDeviceExist = FALSE;\r
711 SlaveDeviceType = 0xff;\r
630d580d 712}\r
ead42efc 713/**\r
714 This function is used to poll for the DRQ bit clear in the Status\r
715 Register. DRQ is cleared when the device is finished transferring data.\r
716 So this function is called after data transfer is finished.\r
717\r
0a6f4824 718 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
630d580d 719 to record all the information of the IDE device.\r
720 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.\r
ead42efc 721\r
630d580d 722 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
ead42efc 723\r
630d580d 724 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
ead42efc 725\r
726 @note\r
727 Read Status Register will clear interrupt status.\r
728\r
729**/\r
730EFI_STATUS\r
731DRQClear (\r
732 IN IDE_BLK_IO_DEV *IdeDev,\r
733 IN UINTN TimeoutInMilliSeconds\r
734 )\r
ead42efc 735{\r
736 UINT32 Delay;\r
737 UINT8 StatusRegister;\r
738 UINT8 ErrorRegister;\r
739\r
740 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
741 do {\r
742\r
743 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
744\r
745 //\r
746 // wait for BSY == 0 and DRQ == 0\r
747 //\r
1e23bd8d 748 if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
ead42efc 749 break;\r
750 }\r
751\r
1e23bd8d 752 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 753\r
754 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 755 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 756 return EFI_ABORTED;\r
757 }\r
758 }\r
759\r
760 //\r
761 // Stall for 30 us\r
762 //\r
763 gBS->Stall (30);\r
764\r
765 Delay--;\r
766\r
97404058 767 } while (Delay > 0);\r
ead42efc 768\r
769 if (Delay == 0) {\r
770 return EFI_TIMEOUT;\r
771 }\r
772\r
773 return EFI_SUCCESS;\r
774}\r
ead42efc 775/**\r
776 This function is used to poll for the DRQ bit clear in the Alternate\r
777 Status Register. DRQ is cleared when the device is finished\r
778 transferring data. So this function is called after data transfer\r
779 is finished.\r
780\r
0a6f4824 781 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
630d580d 782 to record all the information of the IDE device.\r
ead42efc 783\r
630d580d 784 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.\r
ead42efc 785\r
630d580d 786 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
ead42efc 787\r
630d580d 788 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
789 @note Read Alternate Status Register will not clear interrupt status.\r
ead42efc 790\r
791**/\r
792EFI_STATUS\r
793DRQClear2 (\r
794 IN IDE_BLK_IO_DEV *IdeDev,\r
795 IN UINTN TimeoutInMilliSeconds\r
796 )\r
ead42efc 797{\r
798 UINT32 Delay;\r
799 UINT8 AltRegister;\r
800 UINT8 ErrorRegister;\r
801\r
802 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
803 do {\r
804\r
805 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
806\r
807 //\r
808 // wait for BSY == 0 and DRQ == 0\r
809 //\r
1e23bd8d 810 if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
ead42efc 811 break;\r
812 }\r
813\r
1e23bd8d 814 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 815\r
816 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 817 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 818 return EFI_ABORTED;\r
819 }\r
820 }\r
821\r
822 //\r
823 // Stall for 30 us\r
824 //\r
825 gBS->Stall (30);\r
826\r
827 Delay--;\r
828\r
97404058 829 } while (Delay > 0);\r
ead42efc 830\r
831 if (Delay == 0) {\r
832 return EFI_TIMEOUT;\r
833 }\r
834\r
835 return EFI_SUCCESS;\r
836}\r
837\r
838/**\r
839 This function is used to poll for the DRQ bit set in the\r
840 Status Register.\r
841 DRQ is set when the device is ready to transfer data. So this function\r
842 is called after the command is sent to the device and before required\r
843 data is transferred.\r
844\r
630d580d 845 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to\r
846 record all the information of the IDE device.\r
847 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 848\r
630d580d 849 @retval EFI_SUCCESS DRQ bit set within the time out.\r
850 @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
851 @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
ead42efc 852\r
630d580d 853 @note Read Status Register will clear interrupt status.\r
ead42efc 854\r
855**/\r
856EFI_STATUS\r
857DRQReady (\r
858 IN IDE_BLK_IO_DEV *IdeDev,\r
859 IN UINTN TimeoutInMilliSeconds\r
860 )\r
ead42efc 861{\r
862 UINT32 Delay;\r
863 UINT8 StatusRegister;\r
864 UINT8 ErrorRegister;\r
865\r
866 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
867 do {\r
868 //\r
869 // read Status Register will clear interrupt\r
870 //\r
871 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
872\r
873 //\r
874 // BSY==0,DRQ==1\r
875 //\r
1e23bd8d 876 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
ead42efc 877 break;\r
878 }\r
879\r
1e23bd8d 880 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 881\r
882 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 883 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 884 return EFI_ABORTED;\r
885 }\r
886 }\r
887\r
888 //\r
889 // Stall for 30 us\r
890 //\r
891 gBS->Stall (30);\r
892\r
893 Delay--;\r
97404058 894 } while (Delay > 0);\r
ead42efc 895\r
896 if (Delay == 0) {\r
897 return EFI_TIMEOUT;\r
898 }\r
899\r
900 return EFI_SUCCESS;\r
901}\r
ead42efc 902/**\r
630d580d 903 This function is used to poll for the DRQ bit set in the Alternate Status Register.\r
0a6f4824 904 DRQ is set when the device is ready to transfer data. So this function is called after\r
630d580d 905 the command is sent to the device and before required data is transferred.\r
ead42efc 906\r
0a6f4824 907 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to\r
630d580d 908 record all the information of the IDE device.\r
ead42efc 909\r
630d580d 910 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 911\r
630d580d 912 @retval EFI_SUCCESS DRQ bit set within the time out.\r
913 @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
914 @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
915 @note Read Alternate Status Register will not clear interrupt status.\r
ead42efc 916\r
917**/\r
918EFI_STATUS\r
919DRQReady2 (\r
920 IN IDE_BLK_IO_DEV *IdeDev,\r
921 IN UINTN TimeoutInMilliSeconds\r
922 )\r
ead42efc 923{\r
924 UINT32 Delay;\r
925 UINT8 AltRegister;\r
926 UINT8 ErrorRegister;\r
927\r
928 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
929\r
930 do {\r
931 //\r
932 // Read Alternate Status Register will not clear interrupt status\r
933 //\r
934 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
935 //\r
936 // BSY == 0 , DRQ == 1\r
937 //\r
1e23bd8d 938 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
ead42efc 939 break;\r
940 }\r
941\r
1e23bd8d 942 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 943\r
944 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 945 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 946 return EFI_ABORTED;\r
947 }\r
948 }\r
949\r
950 //\r
951 // Stall for 30 us\r
952 //\r
953 gBS->Stall (30);\r
954\r
955 Delay--;\r
97404058 956 } while (Delay > 0);\r
ead42efc 957\r
958 if (Delay == 0) {\r
959 return EFI_TIMEOUT;\r
960 }\r
961\r
962 return EFI_SUCCESS;\r
963}\r
964\r
965/**\r
630d580d 966 This function is used to poll for the BSY bit clear in the Status Register. BSY\r
967 is clear when the device is not busy. Every command must be sent after device is not busy.\r
ead42efc 968\r
0a6f4824 969 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
630d580d 970 to record all the information of the IDE device.\r
971 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 972\r
630d580d 973 @retval EFI_SUCCESS BSY bit clear within the time out.\r
974 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
ead42efc 975\r
630d580d 976 @note Read Status Register will clear interrupt status.\r
ead42efc 977**/\r
978EFI_STATUS\r
979WaitForBSYClear (\r
980 IN IDE_BLK_IO_DEV *IdeDev,\r
981 IN UINTN TimeoutInMilliSeconds\r
982 )\r
ead42efc 983{\r
984 UINT32 Delay;\r
985 UINT8 StatusRegister;\r
986\r
987 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
988 do {\r
989\r
990 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1e23bd8d 991 if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
ead42efc 992 break;\r
993 }\r
994\r
995 //\r
996 // Stall for 30 us\r
997 //\r
998 gBS->Stall (30);\r
999\r
1000 Delay--;\r
1001\r
97404058 1002 } while (Delay > 0);\r
ead42efc 1003\r
1004 if (Delay == 0) {\r
1005 return EFI_TIMEOUT;\r
1006 }\r
1007\r
1008 return EFI_SUCCESS;\r
1009}\r
ead42efc 1010/**\r
0a6f4824
LG
1011 This function is used to poll for the BSY bit clear in the Alternate Status Register.\r
1012 BSY is clear when the device is not busy. Every command must be sent after device is\r
630d580d 1013 not busy.\r
ead42efc 1014\r
0a6f4824 1015 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
630d580d 1016 all the information of the IDE device.\r
cd57e888 1017 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 1018\r
630d580d 1019 @retval EFI_SUCCESS BSY bit clear within the time out.\r
1020 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
1021 @note Read Alternate Status Register will not clear interrupt status.\r
ead42efc 1022\r
1023**/\r
1024EFI_STATUS\r
1025WaitForBSYClear2 (\r
1026 IN IDE_BLK_IO_DEV *IdeDev,\r
1027 IN UINTN TimeoutInMilliSeconds\r
1028 )\r
ead42efc 1029{\r
1030 UINT32 Delay;\r
1031 UINT8 AltRegister;\r
1032\r
1033 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1034 do {\r
1035 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1e23bd8d 1036 if ((AltRegister & ATA_STSREG_BSY) == 0x00) {\r
ead42efc 1037 break;\r
1038 }\r
1039\r
1040 gBS->Stall (30);\r
1041\r
1042 Delay--;\r
1043\r
97404058 1044 } while (Delay > 0);\r
ead42efc 1045\r
1046 if (Delay == 0) {\r
1047 return EFI_TIMEOUT;\r
1048 }\r
1049\r
1050 return EFI_SUCCESS;\r
1051}\r
ead42efc 1052/**\r
630d580d 1053 This function is used to poll for the DRDY bit set in the Status Register. DRDY\r
0a6f4824 1054 bit is set when the device is ready to accept command. Most ATA commands must be\r
630d580d 1055 sent after DRDY set except the ATAPI Packet Command.\r
ead42efc 1056\r
630d580d 1057 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1058 to record all the information of the IDE device.\r
1059 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 1060\r
630d580d 1061 @retval EFI_SUCCESS DRDY bit set within the time out.\r
1062 @retval EFI_TIMEOUT DRDY bit not set within the time out.\r
ead42efc 1063\r
630d580d 1064 @note Read Status Register will clear interrupt status.\r
ead42efc 1065**/\r
1066EFI_STATUS\r
1067DRDYReady (\r
1068 IN IDE_BLK_IO_DEV *IdeDev,\r
1069 IN UINTN DelayInMilliSeconds\r
1070 )\r
ead42efc 1071{\r
1072 UINT32 Delay;\r
1073 UINT8 StatusRegister;\r
1074 UINT8 ErrorRegister;\r
1075\r
1076 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1077 do {\r
1078 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1079 //\r
1080 // BSY == 0 , DRDY == 1\r
1081 //\r
1e23bd8d 1082 if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
ead42efc 1083 break;\r
1084 }\r
1085\r
1e23bd8d 1086 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 1087\r
1088 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 1089 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 1090 return EFI_ABORTED;\r
1091 }\r
1092 }\r
1093\r
1094 gBS->Stall (30);\r
1095\r
1096 Delay--;\r
97404058 1097 } while (Delay > 0);\r
ead42efc 1098\r
1099 if (Delay == 0) {\r
1100 return EFI_TIMEOUT;\r
1101 }\r
1102\r
1103 return EFI_SUCCESS;\r
1104}\r
ead42efc 1105/**\r
0a6f4824
LG
1106 This function is used to poll for the DRDY bit set in the Alternate Status Register.\r
1107 DRDY bit is set when the device is ready to accept command. Most ATA commands must\r
630d580d 1108 be sent after DRDY set except the ATAPI Packet Command.\r
ead42efc 1109\r
630d580d 1110 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1111 to record all the information of the IDE device.\r
1112 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 1113\r
630d580d 1114 @retval EFI_SUCCESS DRDY bit set within the time out.\r
1115 @retval EFI_TIMEOUT DRDY bit not set within the time out.\r
ead42efc 1116\r
630d580d 1117 @note Read Alternate Status Register will clear interrupt status.\r
ead42efc 1118\r
1119**/\r
1120EFI_STATUS\r
1121DRDYReady2 (\r
1122 IN IDE_BLK_IO_DEV *IdeDev,\r
1123 IN UINTN DelayInMilliSeconds\r
1124 )\r
ead42efc 1125{\r
1126 UINT32 Delay;\r
1127 UINT8 AltRegister;\r
1128 UINT8 ErrorRegister;\r
1129\r
1130 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1131 do {\r
1132 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1133 //\r
1134 // BSY == 0 , DRDY == 1\r
1135 //\r
1e23bd8d 1136 if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
ead42efc 1137 break;\r
1138 }\r
1139\r
1e23bd8d 1140 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 1141\r
1142 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 1143 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 1144 return EFI_ABORTED;\r
1145 }\r
1146 }\r
1147\r
1148 gBS->Stall (30);\r
1149\r
1150 Delay--;\r
97404058 1151 } while (Delay > 0);\r
ead42efc 1152\r
1153 if (Delay == 0) {\r
1154 return EFI_TIMEOUT;\r
1155 }\r
1156\r
1157 return EFI_SUCCESS;\r
1158}\r
ead42efc 1159/**\r
1160 Release resources of an IDE device before stopping it.\r
1161\r
630d580d 1162 @param IdeBlkIoDevice Standard IDE device private data structure\r
ead42efc 1163\r
1164**/\r
1165VOID\r
1166ReleaseIdeResources (\r
1167 IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
1168 )\r
1169{\r
1170 if (IdeBlkIoDevice == NULL) {\r
1171 return ;\r
1172 }\r
1173\r
1174 //\r
1175 // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
1176 //\r
1177\r
1178 if (IdeBlkIoDevice->SenseData != NULL) {\r
1179 gBS->FreePool (IdeBlkIoDevice->SenseData);\r
1180 IdeBlkIoDevice->SenseData = NULL;\r
1181 }\r
1182\r
1183 if (IdeBlkIoDevice->Cache != NULL) {\r
1184 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1185 IdeBlkIoDevice->Cache = NULL;\r
1186 }\r
1187\r
e72ca438 1188 if (IdeBlkIoDevice->IdData != NULL) {\r
1189 gBS->FreePool (IdeBlkIoDevice->IdData);\r
1190 IdeBlkIoDevice->IdData = NULL;\r
ead42efc 1191 }\r
1192\r
e72ca438 1193 if (IdeBlkIoDevice->InquiryData != NULL) {\r
1194 gBS->FreePool (IdeBlkIoDevice->InquiryData);\r
1195 IdeBlkIoDevice->InquiryData = NULL;\r
ead42efc 1196 }\r
1197\r
1198 if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
1199 FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
1200 IdeBlkIoDevice->ControllerNameTable = NULL;\r
1201 }\r
1202\r
1203 if (IdeBlkIoDevice->IoPort != NULL) {\r
1204 gBS->FreePool (IdeBlkIoDevice->IoPort);\r
1205 }\r
1206\r
1207 if (IdeBlkIoDevice->DevicePath != NULL) {\r
1208 gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
1209 }\r
1210\r
1211 if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
1212 gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
1213 IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
1214 }\r
1215\r
1216 gBS->FreePool (IdeBlkIoDevice);\r
1217 IdeBlkIoDevice = NULL;\r
1218\r
1219 return ;\r
1220}\r
ead42efc 1221/**\r
cd57e888 1222 Set the calculated Best transfer mode to a detected device.\r
ead42efc 1223\r
630d580d 1224 @param IdeDev Standard IDE device private data structure\r
1225 @param TransferMode The device transfer mode to be set\r
97404058 1226 @return Set transfer mode Command execute status.\r
ead42efc 1227\r
1228**/\r
1229EFI_STATUS\r
1230SetDeviceTransferMode (\r
1231 IN IDE_BLK_IO_DEV *IdeDev,\r
1232 IN ATA_TRANSFER_MODE *TransferMode\r
1233 )\r
ead42efc 1234{\r
1235 EFI_STATUS Status;\r
1236 UINT8 DeviceSelect;\r
1237 UINT8 SectorCount;\r
1238\r
1239 DeviceSelect = 0;\r
1240 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1241 SectorCount = *((UINT8 *) TransferMode);\r
1242\r
1243 //\r
1244 // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
1245 //\r
1246 Status = AtaNonDataCommandIn (\r
1247 IdeDev,\r
1e23bd8d 1248 ATA_CMD_SET_FEATURES,\r
ead42efc 1249 DeviceSelect,\r
1250 0x03,\r
1251 SectorCount,\r
1252 0,\r
1253 0,\r
1254 0\r
1255 );\r
1256\r
1257 return Status;\r
1258}\r
ead42efc 1259/**\r
cd57e888 1260 Set drive parameters for devices not support PACKETS command.\r
ead42efc 1261\r
630d580d 1262 @param IdeDev Standard IDE device private data structure\r
1263 @param DriveParameters The device parameters to be set into the disk\r
97404058 1264 @return SetParameters Command execute status.\r
ead42efc 1265\r
1266**/\r
1267EFI_STATUS\r
1268SetDriveParameters (\r
1269 IN IDE_BLK_IO_DEV *IdeDev,\r
1270 IN ATA_DRIVE_PARMS *DriveParameters\r
1271 )\r
1272{\r
1273 EFI_STATUS Status;\r
1274 UINT8 DeviceSelect;\r
1275\r
1276 DeviceSelect = 0;\r
1277 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1278\r
1279 //\r
1280 // Send Init drive parameters\r
1281 //\r
1282 Status = AtaNonDataCommandIn (\r
1283 IdeDev,\r
1e23bd8d 1284 ATA_CMD_INIT_DRIVE_PARAM,\r
ead42efc 1285 (UINT8) (DeviceSelect + DriveParameters->Heads),\r
1286 0,\r
1287 DriveParameters->Sector,\r
1288 0,\r
1289 0,\r
1290 0\r
1291 );\r
1292\r
1293 //\r
1294 // Send Set Multiple parameters\r
1295 //\r
1296 Status = AtaNonDataCommandIn (\r
1297 IdeDev,\r
1e23bd8d 1298 ATA_CMD_SET_MULTIPLE_MODE,\r
ead42efc 1299 DeviceSelect,\r
1300 0,\r
1301 DriveParameters->MultipleSector,\r
1302 0,\r
1303 0,\r
1304 0\r
1305 );\r
1306 return Status;\r
1307}\r
1308\r
1309/**\r
cd57e888 1310 Enable Interrupt on IDE controller.\r
ead42efc 1311\r
630d580d 1312 @param IdeDev Standard IDE device private data structure\r
ead42efc 1313\r
630d580d 1314 @retval EFI_SUCCESS Enable Interrupt successfully\r
ead42efc 1315**/\r
1316EFI_STATUS\r
1317EnableInterrupt (\r
1318 IN IDE_BLK_IO_DEV *IdeDev\r
1319 )\r
1320{\r
1321 UINT8 DeviceControl;\r
1322\r
1323 //\r
1324 // Enable interrupt for DMA operation\r
1325 //\r
1326 DeviceControl = 0;\r
1327 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
1328\r
1329 return EFI_SUCCESS;\r
1330}\r