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