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