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