]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c
Add ReadMe.txt to specify that the EFI image FatBinPkg provides does not contain...
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / IdeBus / Dxe / ide.c
CommitLineData
ead42efc 1/** @file\r
2 Copyright (c) 2006, Intel Corporation\r
3 All rights reserved. This program and the accompanying materials\r
4 are licensed and made available under the terms and conditions of the BSD License\r
5 which accompanies this distribution. The full text of the license may be found at\r
6 http://opensource.org/licenses/bsd-license.php\r
7\r
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
10\r
11**/\r
12\r
13#include "idebus.h"\r
14\r
15BOOLEAN ChannelDeviceDetected = FALSE;\r
16BOOLEAN SlaveDeviceExist = FALSE;\r
17UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;\r
18BOOLEAN MasterDeviceExist = FALSE;\r
19UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;\r
20\r
21/**\r
22 TODO: Add function description\r
23\r
24 @param PciIo TODO: add argument description\r
25 @param Port TODO: add argument description\r
26\r
27 TODO: add return values\r
28\r
29**/\r
30UINT8\r
31IDEReadPortB (\r
32 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
33 IN UINT16 Port\r
34 )\r
35{\r
36 UINT8 Data;\r
37\r
38 Data = 0;\r
39 //\r
40 // perform 1-byte data read from register\r
41 //\r
42 PciIo->Io.Read (\r
43 PciIo,\r
44 EfiPciIoWidthUint8,\r
45 EFI_PCI_IO_PASS_THROUGH_BAR,\r
46 (UINT64) Port,\r
47 1,\r
48 &Data\r
49 );\r
50 return Data;\r
51}\r
52\r
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
69 IN VOID *Buffer\r
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
112 TODO: Add function description\r
113\r
114 @param PciIo TODO: add argument description\r
115 @param Port TODO: add argument description\r
116 @param Data TODO: add argument description\r
117\r
118 TODO: add return values\r
119\r
120**/\r
121VOID\r
122IDEWritePortB (\r
123 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
124 IN UINT16 Port,\r
125 IN UINT8 Data\r
126 )\r
127{\r
128 //\r
129 // perform 1-byte data write to register\r
130 //\r
131 PciIo->Io.Write (\r
132 PciIo,\r
133 EfiPciIoWidthUint8,\r
134 EFI_PCI_IO_PASS_THROUGH_BAR,\r
135 (UINT64) Port,\r
136 1,\r
137 &Data\r
138 );\r
139\r
140}\r
141\r
142/**\r
143 TODO: Add function description\r
144\r
145 @param PciIo TODO: add argument description\r
146 @param Port TODO: add argument description\r
147 @param Data TODO: add argument description\r
148\r
149 TODO: add return values\r
150\r
151**/\r
152VOID\r
153IDEWritePortW (\r
154 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
155 IN UINT16 Port,\r
156 IN UINT16 Data\r
157 )\r
158{\r
159 //\r
160 // perform 1-word data write to register\r
161 //\r
162 PciIo->Io.Write (\r
163 PciIo,\r
164 EfiPciIoWidthUint16,\r
165 EFI_PCI_IO_PASS_THROUGH_BAR,\r
166 (UINT64) Port,\r
167 1,\r
168 &Data\r
169 );\r
170}\r
171\r
172/**\r
173 Write multiple words of data to the IDE data port.\r
174 Call the IO abstraction once to do the complete read,\r
175 not one word at a time\r
176\r
177 @param PciIo Pointer to the EFI_PCI_IO instance\r
178 @param Port IO port to read\r
179 @param Count No. of UINT16's to read\r
180 @param Buffer Pointer to the data buffer for read\r
181\r
182**/\r
183VOID\r
184IDEWritePortWMultiple (\r
185 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
186 IN UINT16 Port,\r
187 IN UINTN Count,\r
188 IN VOID *Buffer\r
189 )\r
190{\r
191 UINT16 *AlignedBuffer;\r
192 UINT32 *WorkingBuffer;\r
193 UINTN Size;\r
194\r
195 //\r
196 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
197 // not perform actual I/O operations if buffer pointer passed in is not at\r
198 // natural boundary. The "Buffer" argument is passed in by user and may not\r
199 // at 16-bit natural boundary.\r
200 //\r
201 Size = sizeof (UINT16) * Count;\r
202\r
203 gBS->AllocatePool (\r
204 EfiBootServicesData,\r
205 Size + 1,\r
206 (VOID **) &WorkingBuffer\r
207 );\r
208\r
209 AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
210\r
211 //\r
212 // Copy data from user buffer to working buffer\r
213 //\r
214 CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);\r
215\r
216 //\r
217 // perform UINT16 data write to the FIFO\r
218 //\r
219 PciIo->Io.Write (\r
220 PciIo,\r
221 EfiPciIoWidthFifoUint16,\r
222 EFI_PCI_IO_PASS_THROUGH_BAR,\r
223 (UINT64) Port,\r
224 Count,\r
225 (UINT16 *) AlignedBuffer\r
226 );\r
227\r
228 gBS->FreePool (WorkingBuffer);\r
229}\r
230\r
231//\r
232// GetIdeRegistersBaseAddr\r
233//\r
234/**\r
235 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
236 use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
237 the PCI IDE controller's Configuration Space.\r
238\r
239 The steps to get IDE IO port registers' base addresses for each channel\r
240 as follows:\r
241\r
242 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
243 controller's Configuration Space to determine the operating mode.\r
244\r
245 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
246 <pre>\r
247 ___________________________________________\r
248 | | Command Block | Control Block |\r
249 | Channel | Registers | Registers |\r
250 |___________|_______________|_______________|\r
251 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
252 |___________|_______________|_______________|\r
253 | Secondary | 170h - 177h | 376h - 377h |\r
254 |___________|_______________|_______________|\r
255\r
256 Table 1. Compatibility resource mappings\r
257 </pre>\r
258\r
259 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
260 in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
261 <pre>\r
262 ___________________________________________________\r
263 | | Command Block | Control Block |\r
264 | Channel | Registers | Registers |\r
265 |___________|___________________|___________________|\r
266 | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
267 |___________|___________________|___________________|\r
268 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
269 |___________|___________________|___________________|\r
270\r
271 Table 2. BARs for Register Mapping\r
272 </pre>\r
273 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for\r
274 primary, 0374h for secondary. So 2 bytes extra offset should be\r
275 added to the base addresses read from BARs.\r
276\r
277 For more details, please refer to PCI IDE Controller Specification and Intel\r
278 ICH4 Datasheet.\r
279\r
280 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
281 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to\r
282 receive IDE IO port registers' base addresses\r
283\r
284**/\r
285EFI_STATUS\r
286GetIdeRegistersBaseAddr (\r
287 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
288 OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
289 )\r
290// TODO: EFI_UNSUPPORTED - add return value to function comment\r
291// TODO: EFI_UNSUPPORTED - add return value to function comment\r
292// TODO: EFI_SUCCESS - add return value to function comment\r
293{\r
294 EFI_STATUS Status;\r
295 PCI_TYPE00 PciData;\r
296\r
297 Status = PciIo->Pci.Read (\r
298 PciIo,\r
299 EfiPciIoWidthUint8,\r
300 0,\r
301 sizeof (PciData),\r
302 &PciData\r
303 );\r
304\r
305 if (EFI_ERROR (Status)) {\r
306 return Status;\r
307 }\r
308\r
309 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
310 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;\r
311 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;\r
312 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
313 (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
314 } else {\r
315 //\r
316 // The BARs should be of IO type\r
317 //\r
318 if ((PciData.Device.Bar[0] & bit0) == 0 ||\r
319 (PciData.Device.Bar[1] & bit0) == 0) {\r
320 return EFI_UNSUPPORTED;\r
321 }\r
322\r
323 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =\r
324 (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
325 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =\r
326 (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
327 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
328 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
329 }\r
330\r
331 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
332 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;\r
333 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;\r
334 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
335 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
336 } else {\r
337 //\r
338 // The BARs should be of IO type\r
339 //\r
340 if ((PciData.Device.Bar[2] & bit0) == 0 ||\r
341 (PciData.Device.Bar[3] & bit0) == 0) {\r
342 return EFI_UNSUPPORTED;\r
343 }\r
344\r
345 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =\r
346 (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
347 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =\r
348 (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
349 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
350 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
351 }\r
352\r
353 return EFI_SUCCESS;\r
354}\r
355\r
356/**\r
357 This function is used to requery IDE resources. The IDE controller will\r
358 probably switch between native and legacy modes during the EFI->CSM->OS\r
359 transfer. We do this everytime before an BlkIo operation to ensure its\r
360 succeess.\r
361\r
362 @param IdeDev The BLK_IO private data which specifies the IDE device\r
363\r
364**/\r
365EFI_STATUS\r
366ReassignIdeResources (\r
367 IN IDE_BLK_IO_DEV *IdeDev\r
368 )\r
369// TODO: EFI_SUCCESS - add return value to function comment\r
370{\r
371 EFI_STATUS Status;\r
372 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];\r
373 UINT16 CommandBlockBaseAddr;\r
374 UINT16 ControlBlockBaseAddr;\r
375\r
376 //\r
377 // Requery IDE IO port registers' base addresses in case of the switch of\r
378 // native and legacy modes\r
379 //\r
380 Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);\r
381 if (EFI_ERROR (Status)) {\r
382 return Status;\r
383 }\r
384\r
385 ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));\r
386 CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;\r
387 ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;\r
388\r
389 IdeDev->IoPort->Data = CommandBlockBaseAddr;\r
390 (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
391 IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
392 IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
393 IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
394 IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
395 IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
396\r
397 (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
398 (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;\r
399 IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
400 IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);\r
401\r
402 IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;\r
403 return EFI_SUCCESS;\r
404}\r
405\r
406//\r
407// DiscoverIdeDevice\r
408//\r
409/**\r
410 Detect if there is disk connected to this port\r
411\r
412 @param IdeDev The BLK_IO private data which specifies the IDE device\r
413\r
414**/\r
415EFI_STATUS\r
416DiscoverIdeDevice (\r
417 IN IDE_BLK_IO_DEV *IdeDev\r
418 )\r
419// TODO: EFI_NOT_FOUND - add return value to function comment\r
420// TODO: EFI_NOT_FOUND - add return value to function comment\r
421// TODO: EFI_SUCCESS - add return value to function comment\r
422{\r
423 EFI_STATUS Status;\r
424\r
425 //\r
426 // If a channel has not been checked, check it now. Then set it to "checked" state\r
427 // After this step, all devices in this channel have been checked.\r
428 //\r
429 if (ChannelDeviceDetected == FALSE) {\r
430 Status = DetectIDEController (IdeDev);\r
431 if (EFI_ERROR (Status)) {\r
432 return EFI_NOT_FOUND;\r
433 }\r
434 }\r
435\r
436 Status = EFI_NOT_FOUND;\r
437\r
438 //\r
439 // Device exists. test if it is an ATA device.\r
440 // Prefer the result from DetectIDEController,\r
441 // if failed, try another device type to handle\r
442 // devices that not follow the spec.\r
443 //\r
444 if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
445 if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
446 Status = ATAIdentify (IdeDev);\r
447 if (EFI_ERROR (Status)) {\r
448 Status = ATAPIIdentify (IdeDev);\r
449 if (!EFI_ERROR (Status)) {\r
450 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
451 }\r
452 }\r
453 } else {\r
454 Status = ATAPIIdentify (IdeDev);\r
455 if (EFI_ERROR (Status)) {\r
456 Status = ATAIdentify (IdeDev);\r
457 if (!EFI_ERROR (Status)) {\r
458 MasterDeviceType = ATA_DEVICE_TYPE;\r
459 }\r
460 }\r
461 }\r
462 }\r
463 if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
464 if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
465 Status = ATAIdentify (IdeDev);\r
466 if (EFI_ERROR (Status)) {\r
467 Status = ATAPIIdentify (IdeDev);\r
468 if (!EFI_ERROR (Status)) {\r
469 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
470 }\r
471 }\r
472 } else {\r
473 Status = ATAPIIdentify (IdeDev);\r
474 if (EFI_ERROR (Status)) {\r
475 Status = ATAIdentify (IdeDev);\r
476 if (!EFI_ERROR (Status)) {\r
477 SlaveDeviceType = ATA_DEVICE_TYPE;\r
478 }\r
479 }\r
480 }\r
481 }\r
482 if (EFI_ERROR (Status)) {\r
483 return EFI_NOT_FOUND;\r
484 }\r
485 //\r
486 // Init Block I/O interface\r
487 //\r
488 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
489 IdeDev->BlkIo.Reset = IDEBlkIoReset;\r
490 IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;\r
491 IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;\r
492 IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;\r
493\r
494 IdeDev->BlkMedia.LogicalPartition = FALSE;\r
495 IdeDev->BlkMedia.WriteCaching = FALSE;\r
496\r
497 //\r
498 // Init Disk Info interface\r
499 //\r
500 gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));\r
501 IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;\r
502 IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;\r
503 IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;\r
504 IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;\r
505\r
506 return EFI_SUCCESS;\r
507}\r
508\r
509/**\r
510 This interface is used to initialize all state data related to the detection of one\r
511 channel.\r
512\r
513 @retval EFI_SUCCESS Completed Successfully.\r
514\r
515**/\r
516EFI_STATUS\r
517InitializeIDEChannelData (\r
518 VOID\r
519 )\r
520{\r
521 ChannelDeviceDetected = FALSE;\r
522 MasterDeviceExist = FALSE;\r
523 MasterDeviceType = 0xff;\r
524 SlaveDeviceExist = FALSE;\r
525 SlaveDeviceType = 0xff;\r
526 return EFI_SUCCESS;\r
527}\r
528\r
529/**\r
530 This function is called by DiscoverIdeDevice(). It is used for detect\r
531 whether the IDE device exists in the specified Channel as the specified\r
532 Device Number.\r
533\r
534 There is two IDE channels: one is Primary Channel, the other is\r
535 Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
536 Different channel has different register group.\r
537\r
538 On each IDE channel, at most two IDE devices attach,\r
539 one is called Device 0 (Master device), the other is called Device 1\r
540 (Slave device). The devices on the same channel co-use the same register\r
541 group, so before sending out a command for a specified device via command\r
542 register, it is a must to select the current device to accept the command\r
543 by set the device number in the Head/Device Register.\r
544\r
545 @param[in] *IdeDev\r
546 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
547 to record all the information of the IDE device.\r
548\r
549 @retval TRUE\r
550 successfully detects device.\r
551\r
552 @retval FALSE\r
553 any failure during detection process will return this\r
554 value.\r
555\r
556 @note\r
557 TODO: EFI_SUCCESS - add return value to function comment\r
558 TODO: EFI_NOT_FOUND - add return value to function comment\r
559\r
560**/\r
561EFI_STATUS\r
562DetectIDEController (\r
563 IN IDE_BLK_IO_DEV *IdeDev\r
564 )\r
565{\r
566 EFI_STATUS Status;\r
567 UINT8 SectorCountReg;\r
568 UINT8 LBALowReg;\r
569 UINT8 LBAMidReg;\r
570 UINT8 LBAHighReg;\r
571 UINT8 InitStatusReg;\r
572 UINT8 StatusReg;\r
573\r
574 //\r
575 // Select slave device\r
576 //\r
577 IDEWritePortB (\r
578 IdeDev->PciIo,\r
579 IdeDev->IoPort->Head,\r
580 (UINT8) ((1 << 4) | 0xe0)\r
581 );\r
582 gBS->Stall (100);\r
583\r
584 //\r
585 // Save the init slave status register\r
586 //\r
587 InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
588\r
589 //\r
590 // Select Master back\r
591 //\r
592 IDEWritePortB (\r
593 IdeDev->PciIo,\r
594 IdeDev->IoPort->Head,\r
595 (UINT8) ((0 << 4) | 0xe0)\r
596 );\r
597 gBS->Stall (100);\r
598\r
599 //\r
600 // Send ATA Device Execut Diagnostic command.\r
601 // This command should work no matter DRDY is ready or not\r
602 //\r
603 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
604\r
605 Status = WaitForBSYClear (IdeDev, 3500);\r
606 if (EFI_ERROR (Status)) {\r
607 DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
608 return Status;\r
609 }\r
610 //\r
611 // Read device signature\r
612 //\r
613 //\r
614 // Select Master\r
615 //\r
616 IDEWritePortB (\r
617 IdeDev->PciIo,\r
618 IdeDev->IoPort->Head,\r
619 (UINT8) ((0 << 4) | 0xe0)\r
620 );\r
621 gBS->Stall (100);\r
622 SectorCountReg = IDEReadPortB (\r
623 IdeDev->PciIo,\r
624 IdeDev->IoPort->SectorCount\r
625 );\r
626 LBALowReg = IDEReadPortB (\r
627 IdeDev->PciIo,\r
628 IdeDev->IoPort->SectorNumber\r
629 );\r
630 LBAMidReg = IDEReadPortB (\r
631 IdeDev->PciIo,\r
632 IdeDev->IoPort->CylinderLsb\r
633 );\r
634 LBAHighReg = IDEReadPortB (\r
635 IdeDev->PciIo,\r
636 IdeDev->IoPort->CylinderMsb\r
637 );\r
638 if ((SectorCountReg == 0x1) &&\r
639 (LBALowReg == 0x1) &&\r
640 (LBAMidReg == 0x0) &&\r
641 (LBAHighReg == 0x0)) {\r
642 MasterDeviceExist = TRUE;\r
643 MasterDeviceType = ATA_DEVICE_TYPE;\r
644 } else {\r
645 if ((LBAMidReg == 0x14) &&\r
646 (LBAHighReg == 0xeb)) {\r
647 MasterDeviceExist = TRUE;\r
648 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
649 }\r
650 }\r
651\r
652 //\r
653 // For some Hard Drive, it takes some time to get\r
654 // the right signature when operating in single slave mode.\r
655 // We stall 20ms to work around this.\r
656 //\r
657 if (!MasterDeviceExist) {\r
658 gBS->Stall (20000);\r
659 }\r
660\r
661 //\r
662 // Select Slave\r
663 //\r
664 IDEWritePortB (\r
665 IdeDev->PciIo,\r
666 IdeDev->IoPort->Head,\r
667 (UINT8) ((1 << 4) | 0xe0)\r
668 );\r
669 gBS->Stall (100);\r
670 SectorCountReg = IDEReadPortB (\r
671 IdeDev->PciIo,\r
672 IdeDev->IoPort->SectorCount\r
673 );\r
674 LBALowReg = IDEReadPortB (\r
675 IdeDev->PciIo,\r
676 IdeDev->IoPort->SectorNumber\r
677 );\r
678 LBAMidReg = IDEReadPortB (\r
679 IdeDev->PciIo,\r
680 IdeDev->IoPort->CylinderLsb\r
681 );\r
682 LBAHighReg = IDEReadPortB (\r
683 IdeDev->PciIo,\r
684 IdeDev->IoPort->CylinderMsb\r
685 );\r
686 StatusReg = IDEReadPortB (\r
687 IdeDev->PciIo,\r
688 IdeDev->IoPort->Reg.Status\r
689 );\r
690 if ((SectorCountReg == 0x1) &&\r
691 (LBALowReg == 0x1) &&\r
692 (LBAMidReg == 0x0) &&\r
693 (LBAHighReg == 0x0)) {\r
694 SlaveDeviceExist = TRUE;\r
695 SlaveDeviceType = ATA_DEVICE_TYPE;\r
696 } else {\r
697 if ((LBAMidReg == 0x14) &&\r
698 (LBAHighReg == 0xeb)) {\r
699 SlaveDeviceExist = TRUE;\r
700 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
701 }\r
702 }\r
703\r
704 //\r
705 // When single master is plugged, slave device\r
706 // will be wrongly detected. Here's the workaround\r
707 // for ATA devices by detecting DRY bit in status\r
708 // register.\r
709 // NOTE: This workaround doesn't apply to ATAPI.\r
710 //\r
711 if (MasterDeviceExist && SlaveDeviceExist &&\r
712 (StatusReg & DRDY) == 0 &&\r
713 (InitStatusReg & DRDY) == 0 &&\r
714 MasterDeviceType == SlaveDeviceType &&\r
715 SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
716 SlaveDeviceExist = FALSE;\r
717 }\r
718\r
719 //\r
720 // Indicate this channel has been detected\r
721 //\r
722 ChannelDeviceDetected = TRUE;\r
723 return EFI_SUCCESS;\r
724}\r
725\r
726/**\r
727 This function is used to poll for the DRQ bit clear in the Status\r
728 Register. DRQ is cleared when the device is finished transferring data.\r
729 So this function is called after data transfer is finished.\r
730\r
731 @param[in] *IdeDev\r
732 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
733 to record all the information of the IDE device.\r
734\r
735 @param[in] TimeoutInMilliSeconds\r
736 used to designate the timeout for the DRQ clear.\r
737\r
738 @retval EFI_SUCCESS\r
739 DRQ bit clear within the time out.\r
740\r
741 @retval EFI_TIMEOUT\r
742 DRQ bit not clear within the time out.\r
743\r
744 @note\r
745 Read Status Register will clear interrupt status.\r
746\r
747**/\r
748EFI_STATUS\r
749DRQClear (\r
750 IN IDE_BLK_IO_DEV *IdeDev,\r
751 IN UINTN TimeoutInMilliSeconds\r
752 )\r
753// TODO: function comment is missing 'Routine Description:'\r
754// TODO: function comment is missing 'Arguments:'\r
755// TODO: IdeDev - add argument and description to function comment\r
756// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
757// TODO: EFI_ABORTED - add return value to function comment\r
758{\r
759 UINT32 Delay;\r
760 UINT8 StatusRegister;\r
761 UINT8 ErrorRegister;\r
762\r
763 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
764 do {\r
765\r
766 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
767\r
768 //\r
769 // wait for BSY == 0 and DRQ == 0\r
770 //\r
771 if ((StatusRegister & (DRQ | BSY)) == 0) {\r
772 break;\r
773 }\r
774\r
775 if ((StatusRegister & (BSY | ERR)) == ERR) {\r
776\r
777 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
778 if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
779 return EFI_ABORTED;\r
780 }\r
781 }\r
782\r
783 //\r
784 // Stall for 30 us\r
785 //\r
786 gBS->Stall (30);\r
787\r
788 Delay--;\r
789\r
790 } while (Delay);\r
791\r
792 if (Delay == 0) {\r
793 return EFI_TIMEOUT;\r
794 }\r
795\r
796 return EFI_SUCCESS;\r
797}\r
798\r
799/**\r
800 This function is used to poll for the DRQ bit clear in the Alternate\r
801 Status Register. DRQ is cleared when the device is finished\r
802 transferring data. So this function is called after data transfer\r
803 is finished.\r
804\r
805 @param[in] *IdeDev\r
806 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
807 to record all the information of the IDE device.\r
808\r
809 @param[in] TimeoutInMilliSeconds\r
810 used to designate the timeout for the DRQ clear.\r
811\r
812 @retval EFI_SUCCESS\r
813 DRQ bit clear within the time out.\r
814\r
815 @retval EFI_TIMEOUT\r
816 DRQ bit not clear within the time out.\r
817\r
818 @note\r
819 Read Alternate Status Register will not clear interrupt status.\r
820\r
821**/\r
822EFI_STATUS\r
823DRQClear2 (\r
824 IN IDE_BLK_IO_DEV *IdeDev,\r
825 IN UINTN TimeoutInMilliSeconds\r
826 )\r
827// TODO: function comment is missing 'Routine Description:'\r
828// TODO: function comment is missing 'Arguments:'\r
829// TODO: IdeDev - add argument and description to function comment\r
830// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
831// TODO: EFI_ABORTED - add return value to function comment\r
832{\r
833 UINT32 Delay;\r
834 UINT8 AltRegister;\r
835 UINT8 ErrorRegister;\r
836\r
837 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
838 do {\r
839\r
840 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
841\r
842 //\r
843 // wait for BSY == 0 and DRQ == 0\r
844 //\r
845 if ((AltRegister & (DRQ | BSY)) == 0) {\r
846 break;\r
847 }\r
848\r
849 if ((AltRegister & (BSY | ERR)) == ERR) {\r
850\r
851 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
852 if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
853 return EFI_ABORTED;\r
854 }\r
855 }\r
856\r
857 //\r
858 // Stall for 30 us\r
859 //\r
860 gBS->Stall (30);\r
861\r
862 Delay--;\r
863\r
864 } while (Delay);\r
865\r
866 if (Delay == 0) {\r
867 return EFI_TIMEOUT;\r
868 }\r
869\r
870 return EFI_SUCCESS;\r
871}\r
872\r
873/**\r
874 This function is used to poll for the DRQ bit set in the\r
875 Status Register.\r
876 DRQ is set when the device is ready to transfer data. So this function\r
877 is called after the command is sent to the device and before required\r
878 data is transferred.\r
879\r
880 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
881 pointer pointing to IDE_BLK_IO_DEV data structure,used\r
882 to record all the information of the IDE device.\r
883\r
884 @param[in] UINTN IN TimeoutInMilliSeconds\r
885 used to designate the timeout for the DRQ ready.\r
886\r
887 @retval EFI_SUCCESS\r
888 DRQ bit set within the time out.\r
889\r
890 @retval EFI_TIMEOUT\r
891 DRQ bit not set within the time out.\r
892\r
893 @retval EFI_ABORTED\r
894 DRQ bit not set caused by the command abort.\r
895\r
896 @note\r
897 Read Status Register will clear interrupt status.\r
898\r
899**/\r
900EFI_STATUS\r
901DRQReady (\r
902 IN IDE_BLK_IO_DEV *IdeDev,\r
903 IN UINTN TimeoutInMilliSeconds\r
904 )\r
905// TODO: function comment is missing 'Routine Description:'\r
906// TODO: function comment is missing 'Arguments:'\r
907// TODO: IdeDev - add argument and description to function comment\r
908// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
909{\r
910 UINT32 Delay;\r
911 UINT8 StatusRegister;\r
912 UINT8 ErrorRegister;\r
913\r
914 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
915 do {\r
916 //\r
917 // read Status Register will clear interrupt\r
918 //\r
919 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
920\r
921 //\r
922 // BSY==0,DRQ==1\r
923 //\r
924 if ((StatusRegister & (BSY | DRQ)) == DRQ) {\r
925 break;\r
926 }\r
927\r
928 if ((StatusRegister & (BSY | ERR)) == ERR) {\r
929\r
930 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
931 if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
932 return EFI_ABORTED;\r
933 }\r
934 }\r
935\r
936 //\r
937 // Stall for 30 us\r
938 //\r
939 gBS->Stall (30);\r
940\r
941 Delay--;\r
942 } while (Delay);\r
943\r
944 if (Delay == 0) {\r
945 return EFI_TIMEOUT;\r
946 }\r
947\r
948 return EFI_SUCCESS;\r
949}\r
950\r
951/**\r
952 This function is used to poll for the DRQ bit set in the\r
953 Alternate Status Register. DRQ is set when the device is ready to\r
954 transfer data. So this function is called after the command\r
955 is sent to the device and before required data is transferred.\r
956\r
957 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
958 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
959 to record all the information of the IDE device.\r
960\r
961 @param[in] UINTN IN TimeoutInMilliSeconds\r
962 used to designate the timeout for the DRQ ready.\r
963\r
964 @retval EFI_SUCCESS\r
965 DRQ bit set within the time out.\r
966\r
967 @retval EFI_TIMEOUT\r
968 DRQ bit not set within the time out.\r
969\r
970 @retval EFI_ABORTED\r
971 DRQ bit not set caused by the command abort.\r
972\r
973 @note\r
974 Read Alternate Status Register will not clear interrupt status.\r
975\r
976**/\r
977EFI_STATUS\r
978DRQReady2 (\r
979 IN IDE_BLK_IO_DEV *IdeDev,\r
980 IN UINTN TimeoutInMilliSeconds\r
981 )\r
982// TODO: function comment is missing 'Routine Description:'\r
983// TODO: function comment is missing 'Arguments:'\r
984// TODO: IdeDev - add argument and description to function comment\r
985// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
986{\r
987 UINT32 Delay;\r
988 UINT8 AltRegister;\r
989 UINT8 ErrorRegister;\r
990\r
991 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
992\r
993 do {\r
994 //\r
995 // Read Alternate Status Register will not clear interrupt status\r
996 //\r
997 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
998 //\r
999 // BSY == 0 , DRQ == 1\r
1000 //\r
1001 if ((AltRegister & (BSY | DRQ)) == DRQ) {\r
1002 break;\r
1003 }\r
1004\r
1005 if ((AltRegister & (BSY | ERR)) == ERR) {\r
1006\r
1007 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1008 if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
1009 return EFI_ABORTED;\r
1010 }\r
1011 }\r
1012\r
1013 //\r
1014 // Stall for 30 us\r
1015 //\r
1016 gBS->Stall (30);\r
1017\r
1018 Delay--;\r
1019 } while (Delay);\r
1020\r
1021 if (Delay == 0) {\r
1022 return EFI_TIMEOUT;\r
1023 }\r
1024\r
1025 return EFI_SUCCESS;\r
1026}\r
1027\r
1028/**\r
1029 This function is used to poll for the BSY bit clear in the\r
1030 Status Register. BSY is clear when the device is not busy.\r
1031 Every command must be sent after device is not busy.\r
1032\r
1033 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1034 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1035 to record all the information of the IDE device.\r
1036\r
1037 @param[in] UINTN IN TimeoutInMilliSeconds\r
1038 used to designate the timeout for the DRQ ready.\r
1039\r
1040 @retval EFI_SUCCESS\r
1041 BSY bit clear within the time out.\r
1042\r
1043 @retval EFI_TIMEOUT\r
1044 BSY bit not clear within the time out.\r
1045\r
1046 @note\r
1047 Read Status Register will clear interrupt status.\r
1048\r
1049**/\r
1050EFI_STATUS\r
1051WaitForBSYClear (\r
1052 IN IDE_BLK_IO_DEV *IdeDev,\r
1053 IN UINTN TimeoutInMilliSeconds\r
1054 )\r
1055// TODO: function comment is missing 'Routine Description:'\r
1056// TODO: function comment is missing 'Arguments:'\r
1057// TODO: IdeDev - add argument and description to function comment\r
1058// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
1059{\r
1060 UINT32 Delay;\r
1061 UINT8 StatusRegister;\r
1062\r
1063 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1064 do {\r
1065\r
1066 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1067 if ((StatusRegister & BSY) == 0x00) {\r
1068 break;\r
1069 }\r
1070\r
1071 //\r
1072 // Stall for 30 us\r
1073 //\r
1074 gBS->Stall (30);\r
1075\r
1076 Delay--;\r
1077\r
1078 } while (Delay);\r
1079\r
1080 if (Delay == 0) {\r
1081 return EFI_TIMEOUT;\r
1082 }\r
1083\r
1084 return EFI_SUCCESS;\r
1085}\r
1086//\r
1087// WaitForBSYClear2\r
1088//\r
1089/**\r
1090 This function is used to poll for the BSY bit clear in the\r
1091 Alternate Status Register. BSY is clear when the device is not busy.\r
1092 Every command must be sent after device is not busy.\r
1093\r
1094 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1095 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1096 to record all the information of the IDE device.\r
1097\r
1098 @param[in] UINTN IN TimeoutInMilliSeconds\r
1099 used to designate the timeout for the DRQ ready.\r
1100\r
1101 @retval EFI_SUCCESS\r
1102 BSY bit clear within the time out.\r
1103\r
1104 @retval EFI_TIMEOUT\r
1105 BSY bit not clear within the time out.\r
1106\r
1107 @note\r
1108 Read Alternate Status Register will not clear interrupt status.\r
1109\r
1110**/\r
1111EFI_STATUS\r
1112WaitForBSYClear2 (\r
1113 IN IDE_BLK_IO_DEV *IdeDev,\r
1114 IN UINTN TimeoutInMilliSeconds\r
1115 )\r
1116// TODO: function comment is missing 'Routine Description:'\r
1117// TODO: function comment is missing 'Arguments:'\r
1118// TODO: IdeDev - add argument and description to function comment\r
1119// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
1120{\r
1121 UINT32 Delay;\r
1122 UINT8 AltRegister;\r
1123\r
1124 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1125 do {\r
1126 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1127 if ((AltRegister & BSY) == 0x00) {\r
1128 break;\r
1129 }\r
1130\r
1131 gBS->Stall (30);\r
1132\r
1133 Delay--;\r
1134\r
1135 } while (Delay);\r
1136\r
1137 if (Delay == 0) {\r
1138 return EFI_TIMEOUT;\r
1139 }\r
1140\r
1141 return EFI_SUCCESS;\r
1142}\r
1143\r
1144//\r
1145// DRDYReady\r
1146//\r
1147/**\r
1148 This function is used to poll for the DRDY bit set in the\r
1149 Status Register. DRDY bit is set when the device is ready\r
1150 to accept command. Most ATA commands must be sent after\r
1151 DRDY set except the ATAPI Packet Command.\r
1152\r
1153 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1154 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1155 to record all the information of the IDE device.\r
1156\r
1157 @param[in] UINTN IN TimeoutInMilliSeconds\r
1158 used to designate the timeout for the DRQ ready.\r
1159\r
1160 @retval EFI_SUCCESS\r
1161 DRDY bit set within the time out.\r
1162\r
1163 @retval EFI_TIMEOUT\r
1164 DRDY bit not set within the time out.\r
1165\r
1166 @note\r
1167 Read Status Register will clear interrupt status.\r
1168\r
1169**/\r
1170EFI_STATUS\r
1171DRDYReady (\r
1172 IN IDE_BLK_IO_DEV *IdeDev,\r
1173 IN UINTN DelayInMilliSeconds\r
1174 )\r
1175// TODO: function comment is missing 'Routine Description:'\r
1176// TODO: function comment is missing 'Arguments:'\r
1177// TODO: IdeDev - add argument and description to function comment\r
1178// TODO: DelayInMilliSeconds - add argument and description to function comment\r
1179// TODO: EFI_ABORTED - add return value to function comment\r
1180{\r
1181 UINT32 Delay;\r
1182 UINT8 StatusRegister;\r
1183 UINT8 ErrorRegister;\r
1184\r
1185 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1186 do {\r
1187 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1188 //\r
1189 // BSY == 0 , DRDY == 1\r
1190 //\r
1191 if ((StatusRegister & (DRDY | BSY)) == DRDY) {\r
1192 break;\r
1193 }\r
1194\r
1195 if ((StatusRegister & (BSY | ERR)) == ERR) {\r
1196\r
1197 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1198 if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
1199 return EFI_ABORTED;\r
1200 }\r
1201 }\r
1202\r
1203 gBS->Stall (30);\r
1204\r
1205 Delay--;\r
1206 } while (Delay);\r
1207\r
1208 if (Delay == 0) {\r
1209 return EFI_TIMEOUT;\r
1210 }\r
1211\r
1212 return EFI_SUCCESS;\r
1213}\r
1214\r
1215//\r
1216// DRDYReady2\r
1217//\r
1218/**\r
1219 This function is used to poll for the DRDY bit set in the\r
1220 Alternate Status Register. DRDY bit is set when the device is ready\r
1221 to accept command. Most ATA commands must be sent after\r
1222 DRDY set except the ATAPI Packet Command.\r
1223\r
1224 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1225 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1226 to record all the information of the IDE device.\r
1227\r
1228 @param[in] UINTN IN TimeoutInMilliSeconds\r
1229 used to designate the timeout for the DRQ ready.\r
1230\r
1231 @retval EFI_SUCCESS\r
1232 DRDY bit set within the time out.\r
1233\r
1234 @retval EFI_TIMEOUT\r
1235 DRDY bit not set within the time out.\r
1236\r
1237 @note\r
1238 Read Alternate Status Register will clear interrupt status.\r
1239\r
1240**/\r
1241EFI_STATUS\r
1242DRDYReady2 (\r
1243 IN IDE_BLK_IO_DEV *IdeDev,\r
1244 IN UINTN DelayInMilliSeconds\r
1245 )\r
1246// TODO: function comment is missing 'Routine Description:'\r
1247// TODO: function comment is missing 'Arguments:'\r
1248// TODO: IdeDev - add argument and description to function comment\r
1249// TODO: DelayInMilliSeconds - add argument and description to function comment\r
1250// TODO: EFI_ABORTED - add return value to function comment\r
1251{\r
1252 UINT32 Delay;\r
1253 UINT8 AltRegister;\r
1254 UINT8 ErrorRegister;\r
1255\r
1256 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1257 do {\r
1258 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1259 //\r
1260 // BSY == 0 , DRDY == 1\r
1261 //\r
1262 if ((AltRegister & (DRDY | BSY)) == DRDY) {\r
1263 break;\r
1264 }\r
1265\r
1266 if ((AltRegister & (BSY | ERR)) == ERR) {\r
1267\r
1268 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1269 if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {\r
1270 return EFI_ABORTED;\r
1271 }\r
1272 }\r
1273\r
1274 gBS->Stall (30);\r
1275\r
1276 Delay--;\r
1277 } while (Delay);\r
1278\r
1279 if (Delay == 0) {\r
1280 return EFI_TIMEOUT;\r
1281 }\r
1282\r
1283 return EFI_SUCCESS;\r
1284}\r
1285\r
1286//\r
1287// SwapStringChars\r
1288//\r
1289/**\r
1290 This function is a helper function used to change the char order in a\r
1291 string. It is designed specially for the PrintAtaModuleName() function.\r
1292 After the IDE device is detected, the IDE driver gets the device module\r
1293 name by sending ATA command called ATA Identify Command or ATAPI\r
1294 Identify Command to the specified IDE device. The module name returned\r
1295 is a string of ASCII characters: the first character is bit8--bit15\r
1296 of the first word, the second character is bit0--bit7 of the first word\r
1297 and so on. Thus the string can not be print directly before it is\r
1298 preprocessed by this func to change the order of characters in\r
1299 each word in the string.\r
1300\r
1301 @param[in] CHAR8 IN *Destination\r
1302 Indicates the destination string.\r
1303\r
1304 @param[in] CHAR8 IN *Source\r
1305 Indicates the source string.\r
1306\r
1307 @param[in] UINT8 IN Size\r
1308 the length of the string\r
1309\r
1310**/\r
1311VOID\r
1312SwapStringChars (\r
1313 IN CHAR8 *Destination,\r
1314 IN CHAR8 *Source,\r
1315 IN UINT32 Size\r
1316 )\r
1317{\r
1318 UINT32 Index;\r
1319 CHAR8 Temp;\r
1320\r
1321 for (Index = 0; Index < Size; Index += 2) {\r
1322\r
1323 Temp = Source[Index + 1];\r
1324 Destination[Index + 1] = Source[Index];\r
1325 Destination[Index] = Temp;\r
1326 }\r
1327}\r
1328\r
1329//\r
1330// ReleaseIdeResources\r
1331//\r
1332/**\r
1333 Release resources of an IDE device before stopping it.\r
1334\r
1335 @param[in] *IdeBlkIoDevice Standard IDE device private data structure\r
1336\r
1337**/\r
1338VOID\r
1339ReleaseIdeResources (\r
1340 IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
1341 )\r
1342{\r
1343 if (IdeBlkIoDevice == NULL) {\r
1344 return ;\r
1345 }\r
1346\r
1347 //\r
1348 // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
1349 //\r
1350\r
1351 if (IdeBlkIoDevice->SenseData != NULL) {\r
1352 gBS->FreePool (IdeBlkIoDevice->SenseData);\r
1353 IdeBlkIoDevice->SenseData = NULL;\r
1354 }\r
1355\r
1356 if (IdeBlkIoDevice->Cache != NULL) {\r
1357 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1358 IdeBlkIoDevice->Cache = NULL;\r
1359 }\r
1360\r
1361 if (IdeBlkIoDevice->pIdData != NULL) {\r
1362 gBS->FreePool (IdeBlkIoDevice->pIdData);\r
1363 IdeBlkIoDevice->pIdData = NULL;\r
1364 }\r
1365\r
1366 if (IdeBlkIoDevice->pInquiryData != NULL) {\r
1367 gBS->FreePool (IdeBlkIoDevice->pInquiryData);\r
1368 IdeBlkIoDevice->pInquiryData = NULL;\r
1369 }\r
1370\r
1371 if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
1372 FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
1373 IdeBlkIoDevice->ControllerNameTable = NULL;\r
1374 }\r
1375\r
1376 if (IdeBlkIoDevice->IoPort != NULL) {\r
1377 gBS->FreePool (IdeBlkIoDevice->IoPort);\r
1378 }\r
1379\r
1380 if (IdeBlkIoDevice->DevicePath != NULL) {\r
1381 gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
1382 }\r
1383\r
1384 if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
1385 gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
1386 IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
1387 }\r
1388\r
1389 gBS->FreePool (IdeBlkIoDevice);\r
1390 IdeBlkIoDevice = NULL;\r
1391\r
1392 return ;\r
1393}\r
1394\r
1395//\r
1396// SetDeviceTransferMode\r
1397//\r
1398/**\r
1399 Set the calculated Best transfer mode to a detected device\r
1400\r
1401 @param[in] *IdeDev Standard IDE device private data structure\r
1402 @param[in] *TransferMode The device transfer mode to be set\r
1403\r
1404 @return Set transfer mode Command execute status\r
1405\r
1406**/\r
1407EFI_STATUS\r
1408SetDeviceTransferMode (\r
1409 IN IDE_BLK_IO_DEV *IdeDev,\r
1410 IN ATA_TRANSFER_MODE *TransferMode\r
1411 )\r
1412// TODO: function comment is missing 'Routine Description:'\r
1413{\r
1414 EFI_STATUS Status;\r
1415 UINT8 DeviceSelect;\r
1416 UINT8 SectorCount;\r
1417\r
1418 DeviceSelect = 0;\r
1419 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1420 SectorCount = *((UINT8 *) TransferMode);\r
1421\r
1422 //\r
1423 // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
1424 //\r
1425 Status = AtaNonDataCommandIn (\r
1426 IdeDev,\r
1427 SET_FEATURES_CMD,\r
1428 DeviceSelect,\r
1429 0x03,\r
1430 SectorCount,\r
1431 0,\r
1432 0,\r
1433 0\r
1434 );\r
1435\r
1436 return Status;\r
1437}\r
1438\r
1439/**\r
1440 Send ATA command into device with NON_DATA protocol\r
1441\r
1442 @param IdeDev Standard IDE device private data structure\r
1443 @param AtaCommand The ATA command to be sent\r
1444 @param Device The value in Device register\r
1445 @param Feature The value in Feature register\r
1446 @param SectorCount The value in SectorCount register\r
1447 @param LbaLow The value in LBA_LOW register\r
1448 @param LbaMiddle The value in LBA_MIDDLE register\r
1449 @param LbaHigh The value in LBA_HIGH register\r
1450\r
1451 @retval EFI_SUCCESS Reading succeed\r
1452 @retval EFI_ABORTED Command failed\r
1453 @retval EFI_DEVICE_ERROR Device status error\r
1454\r
1455**/\r
1456EFI_STATUS\r
1457AtaNonDataCommandIn (\r
1458 IN IDE_BLK_IO_DEV *IdeDev,\r
1459 IN UINT8 AtaCommand,\r
1460 IN UINT8 Device,\r
1461 IN UINT8 Feature,\r
1462 IN UINT8 SectorCount,\r
1463 IN UINT8 LbaLow,\r
1464 IN UINT8 LbaMiddle,\r
1465 IN UINT8 LbaHigh\r
1466 )\r
1467{\r
1468 EFI_STATUS Status;\r
1469 UINT8 StatusRegister;\r
1470\r
1471 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1472 if (EFI_ERROR (Status)) {\r
1473 return EFI_DEVICE_ERROR;\r
1474 }\r
1475\r
1476 //\r
1477 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
1478 //\r
1479 IDEWritePortB (\r
1480 IdeDev->PciIo,\r
1481 IdeDev->IoPort->Head,\r
1482 (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
1483 );\r
1484\r
1485 //\r
1486 // ATA commands for ATA device must be issued when DRDY is set\r
1487 //\r
1488 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
1489 if (EFI_ERROR (Status)) {\r
1490 return EFI_DEVICE_ERROR;\r
1491 }\r
1492\r
1493 //\r
1494 // Pass parameter into device register block\r
1495 //\r
1496 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
1497 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);\r
1498 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
1499 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1500 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);\r
1501 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1502\r
1503 //\r
1504 // Send command via Command Register\r
1505 //\r
1506 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
1507\r
1508 //\r
1509 // Wait for command completion\r
1510 // For ATA_SMART_CMD, we may need more timeout to let device\r
1511 // adjust internal states.\r
1512 //\r
1513 if (AtaCommand == ATA_SMART_CMD) {\r
1514 Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r
1515 } else {\r
1516 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1517 }\r
1518 if (EFI_ERROR (Status)) {\r
1519 return EFI_DEVICE_ERROR;\r
1520 }\r
1521\r
1522 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1523 if ((StatusRegister & ERR) == ERR) {\r
1524 //\r
1525 // Failed to execute command, abort operation\r
1526 //\r
1527 return EFI_ABORTED;\r
1528 }\r
1529\r
1530 return EFI_SUCCESS;\r
1531}\r
1532\r
1533/**\r
1534 Send ATA Ext command into device with NON_DATA protocol\r
1535\r
1536 @param IdeDev Standard IDE device private data structure\r
1537 @param AtaCommand The ATA command to be sent\r
1538 @param Device The value in Device register\r
1539 @param Feature The value in Feature register\r
1540 @param SectorCount The value in SectorCount register\r
1541 @param LbaAddress The LBA address in 48-bit mode\r
1542\r
1543 @retval EFI_SUCCESS Reading succeed\r
1544 @retval EFI_ABORTED Command failed\r
1545 @retval EFI_DEVICE_ERROR Device status error\r
1546\r
1547**/\r
1548EFI_STATUS\r
1549AtaNonDataCommandInExt (\r
1550 IN IDE_BLK_IO_DEV *IdeDev,\r
1551 IN UINT8 AtaCommand,\r
1552 IN UINT8 Device,\r
1553 IN UINT16 Feature,\r
1554 IN UINT16 SectorCount,\r
1555 IN EFI_LBA LbaAddress\r
1556 )\r
1557{\r
1558 EFI_STATUS Status;\r
1559 UINT8 StatusRegister;\r
1560 UINT8 SectorCount8;\r
1561 UINT8 Feature8;\r
1562 UINT8 LbaLow;\r
1563 UINT8 LbaMid;\r
1564 UINT8 LbaHigh;\r
1565\r
1566 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1567 if (EFI_ERROR (Status)) {\r
1568 return EFI_DEVICE_ERROR;\r
1569 }\r
1570\r
1571 //\r
1572 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
1573 //\r
1574 IDEWritePortB (\r
1575 IdeDev->PciIo,\r
1576 IdeDev->IoPort->Head,\r
1577 (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
1578 );\r
1579\r
1580 //\r
1581 // ATA commands for ATA device must be issued when DRDY is set\r
1582 //\r
1583 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
1584 if (EFI_ERROR (Status)) {\r
1585 return EFI_DEVICE_ERROR;\r
1586 }\r
1587\r
1588 //\r
1589 // Pass parameter into device register block\r
1590 //\r
1591 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
1592\r
1593 //\r
1594 // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
1595 //\r
1596 Feature8 = (UINT8) (Feature >> 8);\r
1597 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
1598\r
1599 Feature8 = (UINT8) Feature;\r
1600 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
1601\r
1602 //\r
1603 // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
1604 //\r
1605 SectorCount8 = (UINT8) (SectorCount >> 8);\r
1606 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
1607\r
1608 SectorCount8 = (UINT8) SectorCount;\r
1609 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
1610\r
1611 //\r
1612 // Fill the start LBA registers, which are also two-byte FIFO\r
1613 //\r
1614 LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
1615 LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
1616 LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
1617 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1618 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
1619 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1620\r
1621 LbaLow = (UINT8) LbaAddress;\r
1622 LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
1623 LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
1624 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1625 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
1626 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1627\r
1628 //\r
1629 // Send command via Command Register\r
1630 //\r
1631 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
1632\r
1633 //\r
1634 // Wait for command completion\r
1635 //\r
1636 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1637 if (EFI_ERROR (Status)) {\r
1638 return EFI_DEVICE_ERROR;\r
1639 }\r
1640\r
1641 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1642 if ((StatusRegister & ERR) == ERR) {\r
1643 //\r
1644 // Failed to execute command, abort operation\r
1645 //\r
1646 return EFI_ABORTED;\r
1647 }\r
1648\r
1649 return EFI_SUCCESS;\r
1650}\r
1651\r
1652//\r
1653// SetDriveParameters\r
1654//\r
1655/**\r
1656 Set drive parameters for devices not support PACKETS command\r
1657\r
1658 @param[in] IdeDev Standard IDE device private data structure\r
1659 @param[in] DriveParameters The device parameters to be set into the disk\r
1660\r
1661 @return SetParameters Command execute status\r
1662\r
1663**/\r
1664EFI_STATUS\r
1665SetDriveParameters (\r
1666 IN IDE_BLK_IO_DEV *IdeDev,\r
1667 IN ATA_DRIVE_PARMS *DriveParameters\r
1668 )\r
1669{\r
1670 EFI_STATUS Status;\r
1671 UINT8 DeviceSelect;\r
1672\r
1673 DeviceSelect = 0;\r
1674 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1675\r
1676 //\r
1677 // Send Init drive parameters\r
1678 //\r
1679 Status = AtaNonDataCommandIn (\r
1680 IdeDev,\r
1681 INIT_DRIVE_PARAM_CMD,\r
1682 (UINT8) (DeviceSelect + DriveParameters->Heads),\r
1683 0,\r
1684 DriveParameters->Sector,\r
1685 0,\r
1686 0,\r
1687 0\r
1688 );\r
1689\r
1690 //\r
1691 // Send Set Multiple parameters\r
1692 //\r
1693 Status = AtaNonDataCommandIn (\r
1694 IdeDev,\r
1695 SET_MULTIPLE_MODE_CMD,\r
1696 DeviceSelect,\r
1697 0,\r
1698 DriveParameters->MultipleSector,\r
1699 0,\r
1700 0,\r
1701 0\r
1702 );\r
1703 return Status;\r
1704}\r
1705\r
1706/**\r
1707 TODO: Add function description\r
1708\r
1709 @param IdeDev TODO: add argument description\r
1710\r
1711 @retval EFI_SUCCESS TODO: Add description for return value\r
1712\r
1713**/\r
1714EFI_STATUS\r
1715EnableInterrupt (\r
1716 IN IDE_BLK_IO_DEV *IdeDev\r
1717 )\r
1718{\r
1719 UINT8 DeviceControl;\r
1720\r
1721 //\r
1722 // Enable interrupt for DMA operation\r
1723 //\r
1724 DeviceControl = 0;\r
1725 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
1726\r
1727 return EFI_SUCCESS;\r
1728}\r
1729\r
1730/**\r
1731 Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.\r
1732\r
1733 @param[in] Event Pointer to this event\r
1734 @param[in] Context Event hanlder private data\r
1735\r
1736**/\r
1737VOID\r
1738EFIAPI\r
1739ClearInterrupt (\r
1740 IN EFI_EVENT Event,\r
1741 IN VOID *Context\r
1742 )\r
1743{\r
1744 EFI_STATUS Status;\r
1745 UINT64 IoPortForBmis;\r
1746 UINT8 RegisterValue;\r
1747 IDE_BLK_IO_DEV *IdeDev;\r
1748\r
1749 //\r
1750 // Get our context\r
1751 //\r
1752 IdeDev = (IDE_BLK_IO_DEV *) Context;\r
1753\r
1754 //\r
1755 // Obtain IDE IO port registers' base addresses\r
1756 //\r
1757 Status = ReassignIdeResources (IdeDev);\r
1758 if (EFI_ERROR (Status)) {\r
1759 return;\r
1760 }\r
1761\r
1762 //\r
1763 // Check whether interrupt is pending\r
1764 //\r
1765\r
1766 //\r
1767 // Reset IDE device to force it de-assert interrupt pin\r
1768 // Note: this will reset all devices on this IDE channel\r
1769 //\r
1770 AtaSoftReset (IdeDev);\r
1771 if (EFI_ERROR (Status)) {\r
1772 return;\r
1773 }\r
1774\r
1775 //\r
1776 // Get base address of IDE Bus Master Status Regsiter\r
1777 //\r
1778 if (IdePrimary == IdeDev->Channel) {\r
1779 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
1780 } else {\r
1781 if (IdeSecondary == IdeDev->Channel) {\r
1782 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
1783 } else {\r
1784 return;\r
1785 }\r
1786 }\r
1787 //\r
1788 // Read BMIS register and clear ERROR and INTR bit\r
1789 //\r
1790 IdeDev->PciIo->Io.Read (\r
1791 IdeDev->PciIo,\r
1792 EfiPciIoWidthUint8,\r
1793 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1794 IoPortForBmis,\r
1795 1,\r
1796 &RegisterValue\r
1797 );\r
1798\r
1799 RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
1800\r
1801 IdeDev->PciIo->Io.Write (\r
1802 IdeDev->PciIo,\r
1803 EfiPciIoWidthUint8,\r
1804 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1805 IoPortForBmis,\r
1806 1,\r
1807 &RegisterValue\r
1808 );\r
1809\r
1810 //\r
1811 // Select the other device on this channel to ensure this device to release the interrupt pin\r
1812 //\r
1813 if (IdeDev->Device == 0) {\r
1814 RegisterValue = (1 << 4) | 0xe0;\r
1815 } else {\r
1816 RegisterValue = (0 << 4) | 0xe0;\r
1817 }\r
1818 IDEWritePortB (\r
1819 IdeDev->PciIo,\r
1820 IdeDev->IoPort->Head,\r
1821 RegisterValue\r
1822 );\r
1823\r
1824}\r