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