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