]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c
Enhance error handle of BuildDevicePath for it is possible to receive other errors.
[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
3 \r
03417d8d 4 Copyright (c) 2006 - 2008, Intel Corporation\r
ead42efc 5 All rights reserved. This program and the accompanying materials\r
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
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
273 \r
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
cd57e888 354 \r
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
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
cd57e888 596 \r
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
701\r
702 @retval EFI_SUCCESS Completed Successfully.\r
703\r
704**/\r
705EFI_STATUS\r
706InitializeIDEChannelData (\r
707 VOID\r
708 )\r
709{\r
710 ChannelDeviceDetected = FALSE;\r
711 MasterDeviceExist = FALSE;\r
712 MasterDeviceType = 0xff;\r
713 SlaveDeviceExist = FALSE;\r
714 SlaveDeviceType = 0xff;\r
715 return EFI_SUCCESS;\r
716}\r
ead42efc 717/**\r
718 This function is used to poll for the DRQ bit clear in the Status\r
719 Register. DRQ is cleared when the device is finished transferring data.\r
720 So this function is called after data transfer is finished.\r
721\r
630d580d 722 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used \r
723 to record all the information of the IDE device.\r
724 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.\r
ead42efc 725\r
630d580d 726 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
ead42efc 727\r
630d580d 728 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
ead42efc 729\r
730 @note\r
731 Read Status Register will clear interrupt status.\r
732\r
733**/\r
734EFI_STATUS\r
735DRQClear (\r
736 IN IDE_BLK_IO_DEV *IdeDev,\r
737 IN UINTN TimeoutInMilliSeconds\r
738 )\r
ead42efc 739{\r
740 UINT32 Delay;\r
741 UINT8 StatusRegister;\r
742 UINT8 ErrorRegister;\r
743\r
744 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
745 do {\r
746\r
747 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
748\r
749 //\r
750 // wait for BSY == 0 and DRQ == 0\r
751 //\r
1e23bd8d 752 if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
ead42efc 753 break;\r
754 }\r
755\r
1e23bd8d 756 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 757\r
758 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 759 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 760 return EFI_ABORTED;\r
761 }\r
762 }\r
763\r
764 //\r
765 // Stall for 30 us\r
766 //\r
767 gBS->Stall (30);\r
768\r
769 Delay--;\r
770\r
97404058 771 } while (Delay > 0);\r
ead42efc 772\r
773 if (Delay == 0) {\r
774 return EFI_TIMEOUT;\r
775 }\r
776\r
777 return EFI_SUCCESS;\r
778}\r
ead42efc 779/**\r
780 This function is used to poll for the DRQ bit clear in the Alternate\r
781 Status Register. DRQ is cleared when the device is finished\r
782 transferring data. So this function is called after data transfer\r
783 is finished.\r
784\r
630d580d 785 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used \r
786 to record all the information of the IDE device.\r
ead42efc 787\r
630d580d 788 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.\r
ead42efc 789\r
630d580d 790 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
ead42efc 791\r
630d580d 792 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
793 @note Read Alternate Status Register will not clear interrupt status.\r
ead42efc 794\r
795**/\r
796EFI_STATUS\r
797DRQClear2 (\r
798 IN IDE_BLK_IO_DEV *IdeDev,\r
799 IN UINTN TimeoutInMilliSeconds\r
800 )\r
ead42efc 801{\r
802 UINT32 Delay;\r
803 UINT8 AltRegister;\r
804 UINT8 ErrorRegister;\r
805\r
806 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
807 do {\r
808\r
809 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
810\r
811 //\r
812 // wait for BSY == 0 and DRQ == 0\r
813 //\r
1e23bd8d 814 if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
ead42efc 815 break;\r
816 }\r
817\r
1e23bd8d 818 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 819\r
820 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 821 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 822 return EFI_ABORTED;\r
823 }\r
824 }\r
825\r
826 //\r
827 // Stall for 30 us\r
828 //\r
829 gBS->Stall (30);\r
830\r
831 Delay--;\r
832\r
97404058 833 } while (Delay > 0);\r
ead42efc 834\r
835 if (Delay == 0) {\r
836 return EFI_TIMEOUT;\r
837 }\r
838\r
839 return EFI_SUCCESS;\r
840}\r
841\r
842/**\r
843 This function is used to poll for the DRQ bit set in the\r
844 Status Register.\r
845 DRQ is set when the device is ready to transfer data. So this function\r
846 is called after the command is sent to the device and before required\r
847 data is transferred.\r
848\r
630d580d 849 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to\r
850 record all the information of the IDE device.\r
851 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 852\r
630d580d 853 @retval EFI_SUCCESS DRQ bit set within the time out.\r
854 @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
855 @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
ead42efc 856\r
630d580d 857 @note Read Status Register will clear interrupt status.\r
ead42efc 858\r
859**/\r
860EFI_STATUS\r
861DRQReady (\r
862 IN IDE_BLK_IO_DEV *IdeDev,\r
863 IN UINTN TimeoutInMilliSeconds\r
864 )\r
ead42efc 865{\r
866 UINT32 Delay;\r
867 UINT8 StatusRegister;\r
868 UINT8 ErrorRegister;\r
869\r
870 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
871 do {\r
872 //\r
873 // read Status Register will clear interrupt\r
874 //\r
875 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
876\r
877 //\r
878 // BSY==0,DRQ==1\r
879 //\r
1e23bd8d 880 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
ead42efc 881 break;\r
882 }\r
883\r
1e23bd8d 884 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 885\r
886 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 887 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 888 return EFI_ABORTED;\r
889 }\r
890 }\r
891\r
892 //\r
893 // Stall for 30 us\r
894 //\r
895 gBS->Stall (30);\r
896\r
897 Delay--;\r
97404058 898 } while (Delay > 0);\r
ead42efc 899\r
900 if (Delay == 0) {\r
901 return EFI_TIMEOUT;\r
902 }\r
903\r
904 return EFI_SUCCESS;\r
905}\r
ead42efc 906/**\r
630d580d 907 This function is used to poll for the DRQ bit set in the Alternate Status Register.\r
908 DRQ is set when the device is ready to transfer data. So this function is called after \r
909 the command is sent to the device and before required data is transferred.\r
ead42efc 910\r
630d580d 911 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to \r
912 record all the information of the IDE device.\r
ead42efc 913\r
630d580d 914 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 915\r
630d580d 916 @retval EFI_SUCCESS DRQ bit set within the time out.\r
917 @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
918 @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
919 @note Read Alternate Status Register will not clear interrupt status.\r
ead42efc 920\r
921**/\r
922EFI_STATUS\r
923DRQReady2 (\r
924 IN IDE_BLK_IO_DEV *IdeDev,\r
925 IN UINTN TimeoutInMilliSeconds\r
926 )\r
ead42efc 927{\r
928 UINT32 Delay;\r
929 UINT8 AltRegister;\r
930 UINT8 ErrorRegister;\r
931\r
932 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
933\r
934 do {\r
935 //\r
936 // Read Alternate Status Register will not clear interrupt status\r
937 //\r
938 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
939 //\r
940 // BSY == 0 , DRQ == 1\r
941 //\r
1e23bd8d 942 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
ead42efc 943 break;\r
944 }\r
945\r
1e23bd8d 946 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 947\r
948 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 949 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 950 return EFI_ABORTED;\r
951 }\r
952 }\r
953\r
954 //\r
955 // Stall for 30 us\r
956 //\r
957 gBS->Stall (30);\r
958\r
959 Delay--;\r
97404058 960 } while (Delay > 0);\r
ead42efc 961\r
962 if (Delay == 0) {\r
963 return EFI_TIMEOUT;\r
964 }\r
965\r
966 return EFI_SUCCESS;\r
967}\r
968\r
969/**\r
630d580d 970 This function is used to poll for the BSY bit clear in the Status Register. BSY\r
971 is clear when the device is not busy. Every command must be sent after device is not busy.\r
ead42efc 972\r
630d580d 973 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used \r
974 to record all the information of the IDE device.\r
975 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 976\r
630d580d 977 @retval EFI_SUCCESS BSY bit clear within the time out.\r
978 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
ead42efc 979\r
630d580d 980 @note Read Status Register will clear interrupt status.\r
ead42efc 981**/\r
982EFI_STATUS\r
983WaitForBSYClear (\r
984 IN IDE_BLK_IO_DEV *IdeDev,\r
985 IN UINTN TimeoutInMilliSeconds\r
986 )\r
ead42efc 987{\r
988 UINT32 Delay;\r
989 UINT8 StatusRegister;\r
990\r
991 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
992 do {\r
993\r
994 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1e23bd8d 995 if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
ead42efc 996 break;\r
997 }\r
998\r
999 //\r
1000 // Stall for 30 us\r
1001 //\r
1002 gBS->Stall (30);\r
1003\r
1004 Delay--;\r
1005\r
97404058 1006 } while (Delay > 0);\r
ead42efc 1007\r
1008 if (Delay == 0) {\r
1009 return EFI_TIMEOUT;\r
1010 }\r
1011\r
1012 return EFI_SUCCESS;\r
1013}\r
ead42efc 1014/**\r
630d580d 1015 This function is used to poll for the BSY bit clear in the Alternate Status Register. \r
1016 BSY is clear when the device is not busy. Every command must be sent after device is \r
1017 not busy.\r
ead42efc 1018\r
630d580d 1019 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r
1020 all the information of the IDE device.\r
cd57e888 1021 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 1022\r
630d580d 1023 @retval EFI_SUCCESS BSY bit clear within the time out.\r
1024 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
1025 @note Read Alternate Status Register will not clear interrupt status.\r
ead42efc 1026\r
1027**/\r
1028EFI_STATUS\r
1029WaitForBSYClear2 (\r
1030 IN IDE_BLK_IO_DEV *IdeDev,\r
1031 IN UINTN TimeoutInMilliSeconds\r
1032 )\r
ead42efc 1033{\r
1034 UINT32 Delay;\r
1035 UINT8 AltRegister;\r
1036\r
1037 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1038 do {\r
1039 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1e23bd8d 1040 if ((AltRegister & ATA_STSREG_BSY) == 0x00) {\r
ead42efc 1041 break;\r
1042 }\r
1043\r
1044 gBS->Stall (30);\r
1045\r
1046 Delay--;\r
1047\r
97404058 1048 } while (Delay > 0);\r
ead42efc 1049\r
1050 if (Delay == 0) {\r
1051 return EFI_TIMEOUT;\r
1052 }\r
1053\r
1054 return EFI_SUCCESS;\r
1055}\r
ead42efc 1056/**\r
630d580d 1057 This function is used to poll for the DRDY bit set in the Status Register. DRDY\r
1058 bit is set when the device is ready to accept command. Most ATA commands must be \r
1059 sent after DRDY set except the ATAPI Packet Command.\r
ead42efc 1060\r
630d580d 1061 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1062 to record all the information of the IDE device.\r
1063 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 1064\r
630d580d 1065 @retval EFI_SUCCESS DRDY bit set within the time out.\r
1066 @retval EFI_TIMEOUT DRDY bit not set within the time out.\r
ead42efc 1067\r
630d580d 1068 @note Read Status Register will clear interrupt status.\r
ead42efc 1069**/\r
1070EFI_STATUS\r
1071DRDYReady (\r
1072 IN IDE_BLK_IO_DEV *IdeDev,\r
1073 IN UINTN DelayInMilliSeconds\r
1074 )\r
ead42efc 1075{\r
1076 UINT32 Delay;\r
1077 UINT8 StatusRegister;\r
1078 UINT8 ErrorRegister;\r
1079\r
1080 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1081 do {\r
1082 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1083 //\r
1084 // BSY == 0 , DRDY == 1\r
1085 //\r
1e23bd8d 1086 if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
ead42efc 1087 break;\r
1088 }\r
1089\r
1e23bd8d 1090 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 1091\r
1092 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 1093 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 1094 return EFI_ABORTED;\r
1095 }\r
1096 }\r
1097\r
1098 gBS->Stall (30);\r
1099\r
1100 Delay--;\r
97404058 1101 } while (Delay > 0);\r
ead42efc 1102\r
1103 if (Delay == 0) {\r
1104 return EFI_TIMEOUT;\r
1105 }\r
1106\r
1107 return EFI_SUCCESS;\r
1108}\r
ead42efc 1109/**\r
630d580d 1110 This function is used to poll for the DRDY bit set in the Alternate Status Register. \r
1111 DRDY bit is set when the device is ready to accept command. Most ATA commands must \r
1112 be sent after DRDY set except the ATAPI Packet Command.\r
ead42efc 1113\r
630d580d 1114 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1115 to record all the information of the IDE device.\r
1116 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.\r
ead42efc 1117\r
630d580d 1118 @retval EFI_SUCCESS DRDY bit set within the time out.\r
1119 @retval EFI_TIMEOUT DRDY bit not set within the time out.\r
ead42efc 1120\r
630d580d 1121 @note Read Alternate Status Register will clear interrupt status.\r
ead42efc 1122\r
1123**/\r
1124EFI_STATUS\r
1125DRDYReady2 (\r
1126 IN IDE_BLK_IO_DEV *IdeDev,\r
1127 IN UINTN DelayInMilliSeconds\r
1128 )\r
ead42efc 1129{\r
1130 UINT32 Delay;\r
1131 UINT8 AltRegister;\r
1132 UINT8 ErrorRegister;\r
1133\r
1134 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1135 do {\r
1136 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1137 //\r
1138 // BSY == 0 , DRDY == 1\r
1139 //\r
1e23bd8d 1140 if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
ead42efc 1141 break;\r
1142 }\r
1143\r
1e23bd8d 1144 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 1145\r
1146 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 1147 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 1148 return EFI_ABORTED;\r
1149 }\r
1150 }\r
1151\r
1152 gBS->Stall (30);\r
1153\r
1154 Delay--;\r
97404058 1155 } while (Delay > 0);\r
ead42efc 1156\r
1157 if (Delay == 0) {\r
1158 return EFI_TIMEOUT;\r
1159 }\r
1160\r
1161 return EFI_SUCCESS;\r
1162}\r
ead42efc 1163/**\r
1164 Release resources of an IDE device before stopping it.\r
1165\r
630d580d 1166 @param IdeBlkIoDevice Standard IDE device private data structure\r
ead42efc 1167\r
1168**/\r
1169VOID\r
1170ReleaseIdeResources (\r
1171 IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
1172 )\r
1173{\r
1174 if (IdeBlkIoDevice == NULL) {\r
1175 return ;\r
1176 }\r
1177\r
1178 //\r
1179 // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
1180 //\r
1181\r
1182 if (IdeBlkIoDevice->SenseData != NULL) {\r
1183 gBS->FreePool (IdeBlkIoDevice->SenseData);\r
1184 IdeBlkIoDevice->SenseData = NULL;\r
1185 }\r
1186\r
1187 if (IdeBlkIoDevice->Cache != NULL) {\r
1188 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1189 IdeBlkIoDevice->Cache = NULL;\r
1190 }\r
1191\r
e72ca438 1192 if (IdeBlkIoDevice->IdData != NULL) {\r
1193 gBS->FreePool (IdeBlkIoDevice->IdData);\r
1194 IdeBlkIoDevice->IdData = NULL;\r
ead42efc 1195 }\r
1196\r
e72ca438 1197 if (IdeBlkIoDevice->InquiryData != NULL) {\r
1198 gBS->FreePool (IdeBlkIoDevice->InquiryData);\r
1199 IdeBlkIoDevice->InquiryData = NULL;\r
ead42efc 1200 }\r
1201\r
1202 if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
1203 FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
1204 IdeBlkIoDevice->ControllerNameTable = NULL;\r
1205 }\r
1206\r
1207 if (IdeBlkIoDevice->IoPort != NULL) {\r
1208 gBS->FreePool (IdeBlkIoDevice->IoPort);\r
1209 }\r
1210\r
1211 if (IdeBlkIoDevice->DevicePath != NULL) {\r
1212 gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
1213 }\r
1214\r
1215 if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
1216 gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
1217 IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
1218 }\r
1219\r
1220 gBS->FreePool (IdeBlkIoDevice);\r
1221 IdeBlkIoDevice = NULL;\r
1222\r
1223 return ;\r
1224}\r
ead42efc 1225/**\r
cd57e888 1226 Set the calculated Best transfer mode to a detected device.\r
ead42efc 1227\r
630d580d 1228 @param IdeDev Standard IDE device private data structure\r
1229 @param TransferMode The device transfer mode to be set\r
97404058 1230 @return Set transfer mode Command execute status.\r
ead42efc 1231\r
1232**/\r
1233EFI_STATUS\r
1234SetDeviceTransferMode (\r
1235 IN IDE_BLK_IO_DEV *IdeDev,\r
1236 IN ATA_TRANSFER_MODE *TransferMode\r
1237 )\r
ead42efc 1238{\r
1239 EFI_STATUS Status;\r
1240 UINT8 DeviceSelect;\r
1241 UINT8 SectorCount;\r
1242\r
1243 DeviceSelect = 0;\r
1244 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1245 SectorCount = *((UINT8 *) TransferMode);\r
1246\r
1247 //\r
1248 // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
1249 //\r
1250 Status = AtaNonDataCommandIn (\r
1251 IdeDev,\r
1e23bd8d 1252 ATA_CMD_SET_FEATURES,\r
ead42efc 1253 DeviceSelect,\r
1254 0x03,\r
1255 SectorCount,\r
1256 0,\r
1257 0,\r
1258 0\r
1259 );\r
1260\r
1261 return Status;\r
1262}\r
ead42efc 1263/**\r
cd57e888 1264 Set drive parameters for devices not support PACKETS command.\r
ead42efc 1265\r
630d580d 1266 @param IdeDev Standard IDE device private data structure\r
1267 @param DriveParameters The device parameters to be set into the disk\r
97404058 1268 @return SetParameters Command execute status.\r
ead42efc 1269\r
1270**/\r
1271EFI_STATUS\r
1272SetDriveParameters (\r
1273 IN IDE_BLK_IO_DEV *IdeDev,\r
1274 IN ATA_DRIVE_PARMS *DriveParameters\r
1275 )\r
1276{\r
1277 EFI_STATUS Status;\r
1278 UINT8 DeviceSelect;\r
1279\r
1280 DeviceSelect = 0;\r
1281 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1282\r
1283 //\r
1284 // Send Init drive parameters\r
1285 //\r
1286 Status = AtaNonDataCommandIn (\r
1287 IdeDev,\r
1e23bd8d 1288 ATA_CMD_INIT_DRIVE_PARAM,\r
ead42efc 1289 (UINT8) (DeviceSelect + DriveParameters->Heads),\r
1290 0,\r
1291 DriveParameters->Sector,\r
1292 0,\r
1293 0,\r
1294 0\r
1295 );\r
1296\r
1297 //\r
1298 // Send Set Multiple parameters\r
1299 //\r
1300 Status = AtaNonDataCommandIn (\r
1301 IdeDev,\r
1e23bd8d 1302 ATA_CMD_SET_MULTIPLE_MODE,\r
ead42efc 1303 DeviceSelect,\r
1304 0,\r
1305 DriveParameters->MultipleSector,\r
1306 0,\r
1307 0,\r
1308 0\r
1309 );\r
1310 return Status;\r
1311}\r
1312\r
1313/**\r
cd57e888 1314 Enable Interrupt on IDE controller.\r
ead42efc 1315\r
630d580d 1316 @param IdeDev Standard IDE device private data structure\r
ead42efc 1317\r
630d580d 1318 @retval EFI_SUCCESS Enable Interrupt successfully\r
ead42efc 1319**/\r
1320EFI_STATUS\r
1321EnableInterrupt (\r
1322 IN IDE_BLK_IO_DEV *IdeDev\r
1323 )\r
1324{\r
1325 UINT8 DeviceControl;\r
1326\r
1327 //\r
1328 // Enable interrupt for DMA operation\r
1329 //\r
1330 DeviceControl = 0;\r
1331 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
1332\r
1333 return EFI_SUCCESS;\r
1334}\r