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