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