]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c
IntelFrameworkModulePkg: Clean up source files
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / IdeBusDxe / Ide.c
1 /** @file
2 The file ontaining the helper functions implement of the Ide Bus driver
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "IdeBus.h"
16
17 BOOLEAN ChannelDeviceDetected = FALSE;
18 BOOLEAN SlaveDeviceExist = FALSE;
19 UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;
20 BOOLEAN MasterDeviceExist = FALSE;
21 UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;
22
23 /**
24 read a one-byte data from a IDE port.
25
26 @param PciIo The PCI IO protocol instance
27 @param Port the IDE Port number
28
29 @return the one-byte data read from IDE port
30 **/
31 UINT8
32 IDEReadPortB (
33 IN EFI_PCI_IO_PROTOCOL *PciIo,
34 IN UINT16 Port
35 )
36 {
37 UINT8 Data;
38
39 Data = 0;
40 //
41 // perform 1-byte data read from register
42 //
43 PciIo->Io.Read (
44 PciIo,
45 EfiPciIoWidthUint8,
46 EFI_PCI_IO_PASS_THROUGH_BAR,
47 (UINT64) Port,
48 1,
49 &Data
50 );
51 return Data;
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 OUT 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 write a 1-byte data to a specific IDE port.
113
114 @param PciIo PCI IO protocol instance
115 @param Port The IDE port to be writen
116 @param Data The data to write to the port
117 **/
118 VOID
119 IDEWritePortB (
120 IN EFI_PCI_IO_PROTOCOL *PciIo,
121 IN UINT16 Port,
122 IN UINT8 Data
123 )
124 {
125 //
126 // perform 1-byte data write to register
127 //
128 PciIo->Io.Write (
129 PciIo,
130 EfiPciIoWidthUint8,
131 EFI_PCI_IO_PASS_THROUGH_BAR,
132 (UINT64) Port,
133 1,
134 &Data
135 );
136
137 }
138
139 /**
140 write a 1-word data to a specific IDE port.
141
142 @param PciIo PCI IO protocol instance
143 @param Port The IDE port to be writen
144 @param Data The data to write to the port
145 **/
146 VOID
147 IDEWritePortW (
148 IN EFI_PCI_IO_PROTOCOL *PciIo,
149 IN UINT16 Port,
150 IN UINT16 Data
151 )
152 {
153 //
154 // perform 1-word data write to register
155 //
156 PciIo->Io.Write (
157 PciIo,
158 EfiPciIoWidthUint16,
159 EFI_PCI_IO_PASS_THROUGH_BAR,
160 (UINT64) Port,
161 1,
162 &Data
163 );
164 }
165
166 /**
167 Write multiple words of data to the IDE data port.
168 Call the IO abstraction once to do the complete read,
169 not one word at a time
170
171 @param PciIo Pointer to the EFI_PCI_IO instance
172 @param Port IO port to read
173 @param Count No. of UINT16's to read
174 @param Buffer Pointer to the data buffer for read
175
176 **/
177 VOID
178 IDEWritePortWMultiple (
179 IN EFI_PCI_IO_PROTOCOL *PciIo,
180 IN UINT16 Port,
181 IN UINTN Count,
182 IN VOID *Buffer
183 )
184 {
185 UINT16 *AlignedBuffer;
186 UINT32 *WorkingBuffer;
187 UINTN Size;
188
189 //
190 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
191 // not perform actual I/O operations if buffer pointer passed in is not at
192 // natural boundary. The "Buffer" argument is passed in by user and may not
193 // at 16-bit natural boundary.
194 //
195 Size = sizeof (UINT16) * Count;
196
197 gBS->AllocatePool (
198 EfiBootServicesData,
199 Size + 1,
200 (VOID **) &WorkingBuffer
201 );
202
203 AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));
204
205 //
206 // Copy data from user buffer to working buffer
207 //
208 CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);
209
210 //
211 // perform UINT16 data write to the FIFO
212 //
213 PciIo->Io.Write (
214 PciIo,
215 EfiPciIoWidthFifoUint16,
216 EFI_PCI_IO_PASS_THROUGH_BAR,
217 (UINT64) Port,
218 Count,
219 (UINT16 *) AlignedBuffer
220 );
221
222 gBS->FreePool (WorkingBuffer);
223 }
224 /**
225 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
226 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
227 the PCI IDE controller's Configuration Space.
228
229 The steps to get IDE IO port registers' base addresses for each channel
230 as follows:
231
232 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
233 controller's Configuration Space to determine the operating mode.
234
235 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
236 <pre>
237 ___________________________________________
238 | | Command Block | Control Block |
239 | Channel | Registers | Registers |
240 |___________|_______________|_______________|
241 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
242 |___________|_______________|_______________|
243 | Secondary | 170h - 177h | 376h - 377h |
244 |___________|_______________|_______________|
245
246 Table 1. Compatibility resource mappings
247 </pre>
248
249 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
250 in IDE controller's PCI Configuration Space, shown in the Table 2 below.
251 <pre>
252 ___________________________________________________
253 | | Command Block | Control Block |
254 | Channel | Registers | Registers |
255 |___________|___________________|___________________|
256 | Primary | BAR at offset 0x10| BAR at offset 0x14|
257 |___________|___________________|___________________|
258 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
259 |___________|___________________|___________________|
260
261 Table 2. BARs for Register Mapping
262 </pre>
263 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
264 primary, 0374h for secondary. So 2 bytes extra offset should be
265 added to the base addresses read from BARs.
266
267 For more details, please refer to PCI IDE Controller Specification and Intel
268 ICH4 Datasheet.
269
270 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
271 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
272 receive IDE IO port registers' base addresses
273
274 @retval EFI_UNSUPPORTED return this value when the BARs is not IO type
275 @retval EFI_SUCCESS Get the Base address successfully
276 @retval other read the pci configureation data error
277
278 **/
279 EFI_STATUS
280 GetIdeRegistersBaseAddr (
281 IN EFI_PCI_IO_PROTOCOL *PciIo,
282 OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
283 )
284 {
285 EFI_STATUS Status;
286 PCI_TYPE00 PciData;
287
288 Status = PciIo->Pci.Read (
289 PciIo,
290 EfiPciIoWidthUint8,
291 0,
292 sizeof (PciData),
293 &PciData
294 );
295
296 if (EFI_ERROR (Status)) {
297 return Status;
298 }
299
300 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {
301 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;
302 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;
303 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =
304 (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));
305 } else {
306 //
307 // The BARs should be of IO type
308 //
309 if ((PciData.Device.Bar[0] & BIT0) == 0 ||
310 (PciData.Device.Bar[1] & BIT0) == 0) {
311 return EFI_UNSUPPORTED;
312 }
313
314 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =
315 (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);
316 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =
317 (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);
318 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =
319 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
320 }
321
322 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {
323 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;
324 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;
325 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =
326 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
327 } else {
328 //
329 // The BARs should be of IO type
330 //
331 if ((PciData.Device.Bar[2] & BIT0) == 0 ||
332 (PciData.Device.Bar[3] & BIT0) == 0) {
333 return EFI_UNSUPPORTED;
334 }
335
336 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =
337 (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);
338 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =
339 (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);
340 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =
341 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
342 }
343
344 return EFI_SUCCESS;
345 }
346
347 /**
348 This function is used to requery IDE resources. The IDE controller will
349 probably switch between native and legacy modes during the EFI->CSM->OS
350 transfer. We do this everytime before an BlkIo operation to ensure its
351 succeess.
352
353 @param IdeDev The BLK_IO private data which specifies the IDE device
354
355 @retval EFI_INVALID_PARAMETER return this value when the channel is invalid
356 @retval EFI_SUCCESS reassign the IDE IO resource successfully
357 @retval other get the IDE current base address effor
358
359 **/
360 EFI_STATUS
361 ReassignIdeResources (
362 IN IDE_BLK_IO_DEV *IdeDev
363 )
364 {
365 EFI_STATUS Status;
366 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];
367 UINT16 CommandBlockBaseAddr;
368 UINT16 ControlBlockBaseAddr;
369
370 if (IdeDev->Channel >= IdeMaxChannel) {
371 return EFI_INVALID_PARAMETER;
372 }
373
374 //
375 // Requery IDE IO port registers' base addresses in case of the switch of
376 // native and legacy modes
377 //
378 Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);
379 if (EFI_ERROR (Status)) {
380 return Status;
381 }
382
383 ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));
384 CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;
385 ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;
386
387 IdeDev->IoPort->Data = CommandBlockBaseAddr;
388 (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
389 IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
390 IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
391 IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
392 IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
393 IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);
394
395 (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);
396 (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;
397 IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);
398 IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);
399
400 IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;
401 return EFI_SUCCESS;
402 }
403
404 /**
405 This function is called by DiscoverIdeDevice(). It is used for detect
406 whether the IDE device exists in the specified Channel as the specified
407 Device Number.
408
409 There is two IDE channels: one is Primary Channel, the other is
410 Secondary Channel.(Channel is the logical name for the physical "Cable".)
411 Different channel has different register group.
412
413 On each IDE channel, at most two IDE devices attach,
414 one is called Device 0 (Master device), the other is called Device 1
415 (Slave device). The devices on the same channel co-use the same register
416 group, so before sending out a command for a specified device via command
417 register, it is a must to select the current device to accept the command
418 by set the device number in the Head/Device Register.
419
420 @param IdeDev pointer to IDE_BLK_IO_DEV data structure, used to record all the
421 information of the IDE device.
422
423 @retval EFI_SUCCESS successfully detects device.
424
425 @retval other any failure during detection process will return this value.
426
427 **/
428 EFI_STATUS
429 DetectIDEController (
430 IN IDE_BLK_IO_DEV *IdeDev
431 )
432 {
433 EFI_STATUS Status;
434 UINT8 SectorCountReg;
435 UINT8 LBALowReg;
436 UINT8 LBAMidReg;
437 UINT8 LBAHighReg;
438 UINT8 InitStatusReg;
439 UINT8 StatusReg;
440
441 //
442 // Select slave device
443 //
444 IDEWritePortB (
445 IdeDev->PciIo,
446 IdeDev->IoPort->Head,
447 (UINT8) ((1 << 4) | 0xe0)
448 );
449 gBS->Stall (100);
450
451 //
452 // Save the init slave status register
453 //
454 InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
455
456 //
457 // Select Master back
458 //
459 IDEWritePortB (
460 IdeDev->PciIo,
461 IdeDev->IoPort->Head,
462 (UINT8) ((0 << 4) | 0xe0)
463 );
464 gBS->Stall (100);
465
466 //
467 // Send ATA Device Execut Diagnostic command.
468 // This command should work no matter DRDY is ready or not
469 //
470 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);
471
472 Status = WaitForBSYClear (IdeDev, 3500);
473 if (EFI_ERROR (Status)) {
474 DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));
475 return Status;
476 }
477 //
478 // Read device signature
479 //
480 //
481 // Select Master
482 //
483 IDEWritePortB (
484 IdeDev->PciIo,
485 IdeDev->IoPort->Head,
486 (UINT8) ((0 << 4) | 0xe0)
487 );
488 gBS->Stall (100);
489 SectorCountReg = IDEReadPortB (
490 IdeDev->PciIo,
491 IdeDev->IoPort->SectorCount
492 );
493 LBALowReg = IDEReadPortB (
494 IdeDev->PciIo,
495 IdeDev->IoPort->SectorNumber
496 );
497 LBAMidReg = IDEReadPortB (
498 IdeDev->PciIo,
499 IdeDev->IoPort->CylinderLsb
500 );
501 LBAHighReg = IDEReadPortB (
502 IdeDev->PciIo,
503 IdeDev->IoPort->CylinderMsb
504 );
505 if ((SectorCountReg == 0x1) &&
506 (LBALowReg == 0x1) &&
507 (LBAMidReg == 0x0) &&
508 (LBAHighReg == 0x0)) {
509 MasterDeviceExist = TRUE;
510 MasterDeviceType = ATA_DEVICE_TYPE;
511 } else {
512 if ((LBAMidReg == 0x14) &&
513 (LBAHighReg == 0xeb)) {
514 MasterDeviceExist = TRUE;
515 MasterDeviceType = ATAPI_DEVICE_TYPE;
516 }
517 }
518
519 //
520 // For some Hard Drive, it takes some time to get
521 // the right signature when operating in single slave mode.
522 // We stall 20ms to work around this.
523 //
524 if (!MasterDeviceExist) {
525 gBS->Stall (20000);
526 }
527
528 //
529 // Select Slave
530 //
531 IDEWritePortB (
532 IdeDev->PciIo,
533 IdeDev->IoPort->Head,
534 (UINT8) ((1 << 4) | 0xe0)
535 );
536 gBS->Stall (100);
537 SectorCountReg = IDEReadPortB (
538 IdeDev->PciIo,
539 IdeDev->IoPort->SectorCount
540 );
541 LBALowReg = IDEReadPortB (
542 IdeDev->PciIo,
543 IdeDev->IoPort->SectorNumber
544 );
545 LBAMidReg = IDEReadPortB (
546 IdeDev->PciIo,
547 IdeDev->IoPort->CylinderLsb
548 );
549 LBAHighReg = IDEReadPortB (
550 IdeDev->PciIo,
551 IdeDev->IoPort->CylinderMsb
552 );
553 StatusReg = IDEReadPortB (
554 IdeDev->PciIo,
555 IdeDev->IoPort->Reg.Status
556 );
557 if ((SectorCountReg == 0x1) &&
558 (LBALowReg == 0x1) &&
559 (LBAMidReg == 0x0) &&
560 (LBAHighReg == 0x0)) {
561 SlaveDeviceExist = TRUE;
562 SlaveDeviceType = ATA_DEVICE_TYPE;
563 } else {
564 if ((LBAMidReg == 0x14) &&
565 (LBAHighReg == 0xeb)) {
566 SlaveDeviceExist = TRUE;
567 SlaveDeviceType = ATAPI_DEVICE_TYPE;
568 }
569 }
570
571 //
572 // When single master is plugged, slave device
573 // will be wrongly detected. Here's the workaround
574 // for ATA devices by detecting DRY bit in status
575 // register.
576 // NOTE: This workaround doesn't apply to ATAPI.
577 //
578 if (MasterDeviceExist && SlaveDeviceExist &&
579 (StatusReg & ATA_STSREG_DRDY) == 0 &&
580 (InitStatusReg & ATA_STSREG_DRDY) == 0 &&
581 MasterDeviceType == SlaveDeviceType &&
582 SlaveDeviceType != ATAPI_DEVICE_TYPE) {
583 SlaveDeviceExist = FALSE;
584 }
585
586 //
587 // Indicate this channel has been detected
588 //
589 ChannelDeviceDetected = TRUE;
590 return EFI_SUCCESS;
591 }
592 /**
593 Detect if there is disk attached to this port
594
595 @param IdeDev The BLK_IO private data which specifies the IDE device.
596
597 @retval EFI_NOT_FOUND The device or channel is not found
598 @retval EFI_SUCCESS The device is found
599
600 **/
601 EFI_STATUS
602 DiscoverIdeDevice (
603 IN IDE_BLK_IO_DEV *IdeDev
604 )
605 {
606 EFI_STATUS Status;
607 EFI_STATUS LongPhyStatus;
608
609 //
610 // If a channel has not been checked, check it now. Then set it to "checked" state
611 // After this step, all devices in this channel have been checked.
612 //
613 if (!ChannelDeviceDetected) {
614 Status = DetectIDEController (IdeDev);
615 if (EFI_ERROR (Status)) {
616 return EFI_NOT_FOUND;
617 }
618 }
619
620 Status = EFI_NOT_FOUND;
621
622 //
623 // Device exists. test if it is an ATA device.
624 // Prefer the result from DetectIDEController,
625 // if failed, try another device type to handle
626 // devices that not follow the spec.
627 //
628 if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {
629 if (MasterDeviceType == ATA_DEVICE_TYPE) {
630 Status = ATAIdentify (IdeDev);
631 if (EFI_ERROR (Status)) {
632 Status = ATAPIIdentify (IdeDev);
633 if (!EFI_ERROR (Status)) {
634 MasterDeviceType = ATAPI_DEVICE_TYPE;
635 }
636 }
637 } else {
638 Status = ATAPIIdentify (IdeDev);
639 if (EFI_ERROR (Status)) {
640 Status = ATAIdentify (IdeDev);
641 if (!EFI_ERROR (Status)) {
642 MasterDeviceType = ATA_DEVICE_TYPE;
643 }
644 }
645 }
646 }
647 if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {
648 if (SlaveDeviceType == ATA_DEVICE_TYPE) {
649 Status = ATAIdentify (IdeDev);
650 if (EFI_ERROR (Status)) {
651 Status = ATAPIIdentify (IdeDev);
652 if (!EFI_ERROR (Status)) {
653 SlaveDeviceType = ATAPI_DEVICE_TYPE;
654 }
655 }
656 } else {
657 Status = ATAPIIdentify (IdeDev);
658 if (EFI_ERROR (Status)) {
659 Status = ATAIdentify (IdeDev);
660 if (!EFI_ERROR (Status)) {
661 SlaveDeviceType = ATA_DEVICE_TYPE;
662 }
663 }
664 }
665 }
666 if (EFI_ERROR (Status)) {
667 return EFI_NOT_FOUND;
668 }
669 //
670 // Init Block I/O interface
671 //
672 LongPhyStatus = AtaEnableLongPhysicalSector (IdeDev);
673 if (!EFI_ERROR (LongPhyStatus)) {
674 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;
675 } else {
676 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
677 }
678 IdeDev->BlkIo.Reset = IDEBlkIoReset;
679 IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;
680 IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;
681 IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;
682
683 IdeDev->BlkMedia.LogicalPartition = FALSE;
684 IdeDev->BlkMedia.WriteCaching = FALSE;
685
686 //
687 // Init Disk Info interface
688 //
689 gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));
690 IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;
691 IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;
692 IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;
693 IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;
694
695 return EFI_SUCCESS;
696 }
697
698 /**
699 This interface is used to initialize all state data related to the detection of one
700 channel.
701 **/
702 VOID
703 InitializeIDEChannelData (
704 VOID
705 )
706 {
707 ChannelDeviceDetected = FALSE;
708 MasterDeviceExist = FALSE;
709 MasterDeviceType = 0xff;
710 SlaveDeviceExist = FALSE;
711 SlaveDeviceType = 0xff;
712 }
713 /**
714 This function is used to poll for the DRQ bit clear in the Status
715 Register. DRQ is cleared when the device is finished transferring data.
716 So this function is called after data transfer is finished.
717
718 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
719 to record all the information of the IDE device.
720 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
721
722 @retval EFI_SUCCESS DRQ bit clear within the time out.
723
724 @retval EFI_TIMEOUT DRQ bit not clear within the time out.
725
726 @note
727 Read Status Register will clear interrupt status.
728
729 **/
730 EFI_STATUS
731 DRQClear (
732 IN IDE_BLK_IO_DEV *IdeDev,
733 IN UINTN TimeoutInMilliSeconds
734 )
735 {
736 UINT32 Delay;
737 UINT8 StatusRegister;
738 UINT8 ErrorRegister;
739
740 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
741 do {
742
743 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
744
745 //
746 // wait for BSY == 0 and DRQ == 0
747 //
748 if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
749 break;
750 }
751
752 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
753
754 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
755 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
756 return EFI_ABORTED;
757 }
758 }
759
760 //
761 // Stall for 30 us
762 //
763 gBS->Stall (30);
764
765 Delay--;
766
767 } while (Delay > 0);
768
769 if (Delay == 0) {
770 return EFI_TIMEOUT;
771 }
772
773 return EFI_SUCCESS;
774 }
775 /**
776 This function is used to poll for the DRQ bit clear in the Alternate
777 Status Register. DRQ is cleared when the device is finished
778 transferring data. So this function is called after data transfer
779 is finished.
780
781 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
782 to record all the information of the IDE device.
783
784 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
785
786 @retval EFI_SUCCESS DRQ bit clear within the time out.
787
788 @retval EFI_TIMEOUT DRQ bit not clear within the time out.
789 @note Read Alternate Status Register will not clear interrupt status.
790
791 **/
792 EFI_STATUS
793 DRQClear2 (
794 IN IDE_BLK_IO_DEV *IdeDev,
795 IN UINTN TimeoutInMilliSeconds
796 )
797 {
798 UINT32 Delay;
799 UINT8 AltRegister;
800 UINT8 ErrorRegister;
801
802 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
803 do {
804
805 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
806
807 //
808 // wait for BSY == 0 and DRQ == 0
809 //
810 if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
811 break;
812 }
813
814 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
815
816 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
817 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
818 return EFI_ABORTED;
819 }
820 }
821
822 //
823 // Stall for 30 us
824 //
825 gBS->Stall (30);
826
827 Delay--;
828
829 } while (Delay > 0);
830
831 if (Delay == 0) {
832 return EFI_TIMEOUT;
833 }
834
835 return EFI_SUCCESS;
836 }
837
838 /**
839 This function is used to poll for the DRQ bit set in the
840 Status Register.
841 DRQ is set when the device is ready to transfer data. So this function
842 is called after the command is sent to the device and before required
843 data is transferred.
844
845 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to
846 record all the information of the IDE device.
847 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
848
849 @retval EFI_SUCCESS DRQ bit set within the time out.
850 @retval EFI_TIMEOUT DRQ bit not set within the time out.
851 @retval EFI_ABORTED DRQ bit not set caused by the command abort.
852
853 @note Read Status Register will clear interrupt status.
854
855 **/
856 EFI_STATUS
857 DRQReady (
858 IN IDE_BLK_IO_DEV *IdeDev,
859 IN UINTN TimeoutInMilliSeconds
860 )
861 {
862 UINT32 Delay;
863 UINT8 StatusRegister;
864 UINT8 ErrorRegister;
865
866 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
867 do {
868 //
869 // read Status Register will clear interrupt
870 //
871 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
872
873 //
874 // BSY==0,DRQ==1
875 //
876 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
877 break;
878 }
879
880 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
881
882 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
883 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
884 return EFI_ABORTED;
885 }
886 }
887
888 //
889 // Stall for 30 us
890 //
891 gBS->Stall (30);
892
893 Delay--;
894 } while (Delay > 0);
895
896 if (Delay == 0) {
897 return EFI_TIMEOUT;
898 }
899
900 return EFI_SUCCESS;
901 }
902 /**
903 This function is used to poll for the DRQ bit set in the Alternate Status Register.
904 DRQ is set when the device is ready to transfer data. So this function is called after
905 the command is sent to the device and before required data is transferred.
906
907 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to
908 record all the information of the IDE device.
909
910 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
911
912 @retval EFI_SUCCESS DRQ bit set within the time out.
913 @retval EFI_TIMEOUT DRQ bit not set within the time out.
914 @retval EFI_ABORTED DRQ bit not set caused by the command abort.
915 @note Read Alternate Status Register will not clear interrupt status.
916
917 **/
918 EFI_STATUS
919 DRQReady2 (
920 IN IDE_BLK_IO_DEV *IdeDev,
921 IN UINTN TimeoutInMilliSeconds
922 )
923 {
924 UINT32 Delay;
925 UINT8 AltRegister;
926 UINT8 ErrorRegister;
927
928 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
929
930 do {
931 //
932 // Read Alternate Status Register will not clear interrupt status
933 //
934 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
935 //
936 // BSY == 0 , DRQ == 1
937 //
938 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
939 break;
940 }
941
942 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
943
944 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
945 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
946 return EFI_ABORTED;
947 }
948 }
949
950 //
951 // Stall for 30 us
952 //
953 gBS->Stall (30);
954
955 Delay--;
956 } while (Delay > 0);
957
958 if (Delay == 0) {
959 return EFI_TIMEOUT;
960 }
961
962 return EFI_SUCCESS;
963 }
964
965 /**
966 This function is used to poll for the BSY bit clear in the Status Register. BSY
967 is clear when the device is not busy. Every command must be sent after device is not busy.
968
969 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
970 to record all the information of the IDE device.
971 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
972
973 @retval EFI_SUCCESS BSY bit clear within the time out.
974 @retval EFI_TIMEOUT BSY bit not clear within the time out.
975
976 @note Read Status Register will clear interrupt status.
977 **/
978 EFI_STATUS
979 WaitForBSYClear (
980 IN IDE_BLK_IO_DEV *IdeDev,
981 IN UINTN TimeoutInMilliSeconds
982 )
983 {
984 UINT32 Delay;
985 UINT8 StatusRegister;
986
987 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
988 do {
989
990 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
991 if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {
992 break;
993 }
994
995 //
996 // Stall for 30 us
997 //
998 gBS->Stall (30);
999
1000 Delay--;
1001
1002 } while (Delay > 0);
1003
1004 if (Delay == 0) {
1005 return EFI_TIMEOUT;
1006 }
1007
1008 return EFI_SUCCESS;
1009 }
1010 /**
1011 This function is used to poll for the BSY bit clear in the Alternate Status Register.
1012 BSY is clear when the device is not busy. Every command must be sent after device is
1013 not busy.
1014
1015 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
1016 all the information of the IDE device.
1017 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
1018
1019 @retval EFI_SUCCESS BSY bit clear within the time out.
1020 @retval EFI_TIMEOUT BSY bit not clear within the time out.
1021 @note Read Alternate Status Register will not clear interrupt status.
1022
1023 **/
1024 EFI_STATUS
1025 WaitForBSYClear2 (
1026 IN IDE_BLK_IO_DEV *IdeDev,
1027 IN UINTN TimeoutInMilliSeconds
1028 )
1029 {
1030 UINT32 Delay;
1031 UINT8 AltRegister;
1032
1033 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
1034 do {
1035 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
1036 if ((AltRegister & ATA_STSREG_BSY) == 0x00) {
1037 break;
1038 }
1039
1040 gBS->Stall (30);
1041
1042 Delay--;
1043
1044 } while (Delay > 0);
1045
1046 if (Delay == 0) {
1047 return EFI_TIMEOUT;
1048 }
1049
1050 return EFI_SUCCESS;
1051 }
1052 /**
1053 This function is used to poll for the DRDY bit set in the Status Register. DRDY
1054 bit is set when the device is ready to accept command. Most ATA commands must be
1055 sent after DRDY set except the ATAPI Packet Command.
1056
1057 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
1058 to record all the information of the IDE device.
1059 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
1060
1061 @retval EFI_SUCCESS DRDY bit set within the time out.
1062 @retval EFI_TIMEOUT DRDY bit not set within the time out.
1063
1064 @note Read Status Register will clear interrupt status.
1065 **/
1066 EFI_STATUS
1067 DRDYReady (
1068 IN IDE_BLK_IO_DEV *IdeDev,
1069 IN UINTN DelayInMilliSeconds
1070 )
1071 {
1072 UINT32 Delay;
1073 UINT8 StatusRegister;
1074 UINT8 ErrorRegister;
1075
1076 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
1077 do {
1078 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
1079 //
1080 // BSY == 0 , DRDY == 1
1081 //
1082 if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {
1083 break;
1084 }
1085
1086 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
1087
1088 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
1089 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
1090 return EFI_ABORTED;
1091 }
1092 }
1093
1094 gBS->Stall (30);
1095
1096 Delay--;
1097 } while (Delay > 0);
1098
1099 if (Delay == 0) {
1100 return EFI_TIMEOUT;
1101 }
1102
1103 return EFI_SUCCESS;
1104 }
1105 /**
1106 This function is used to poll for the DRDY bit set in the Alternate Status Register.
1107 DRDY bit is set when the device is ready to accept command. Most ATA commands must
1108 be sent after DRDY set except the ATAPI Packet Command.
1109
1110 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
1111 to record all the information of the IDE device.
1112 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
1113
1114 @retval EFI_SUCCESS DRDY bit set within the time out.
1115 @retval EFI_TIMEOUT DRDY bit not set within the time out.
1116
1117 @note Read Alternate Status Register will clear interrupt status.
1118
1119 **/
1120 EFI_STATUS
1121 DRDYReady2 (
1122 IN IDE_BLK_IO_DEV *IdeDev,
1123 IN UINTN DelayInMilliSeconds
1124 )
1125 {
1126 UINT32 Delay;
1127 UINT8 AltRegister;
1128 UINT8 ErrorRegister;
1129
1130 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
1131 do {
1132 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
1133 //
1134 // BSY == 0 , DRDY == 1
1135 //
1136 if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {
1137 break;
1138 }
1139
1140 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
1141
1142 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
1143 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
1144 return EFI_ABORTED;
1145 }
1146 }
1147
1148 gBS->Stall (30);
1149
1150 Delay--;
1151 } while (Delay > 0);
1152
1153 if (Delay == 0) {
1154 return EFI_TIMEOUT;
1155 }
1156
1157 return EFI_SUCCESS;
1158 }
1159 /**
1160 Release resources of an IDE device before stopping it.
1161
1162 @param IdeBlkIoDevice Standard IDE device private data structure
1163
1164 **/
1165 VOID
1166 ReleaseIdeResources (
1167 IN IDE_BLK_IO_DEV *IdeBlkIoDevice
1168 )
1169 {
1170 if (IdeBlkIoDevice == NULL) {
1171 return ;
1172 }
1173
1174 //
1175 // Release all the resourses occupied by the IDE_BLK_IO_DEV
1176 //
1177
1178 if (IdeBlkIoDevice->SenseData != NULL) {
1179 gBS->FreePool (IdeBlkIoDevice->SenseData);
1180 IdeBlkIoDevice->SenseData = NULL;
1181 }
1182
1183 if (IdeBlkIoDevice->Cache != NULL) {
1184 gBS->FreePool (IdeBlkIoDevice->Cache);
1185 IdeBlkIoDevice->Cache = NULL;
1186 }
1187
1188 if (IdeBlkIoDevice->IdData != NULL) {
1189 gBS->FreePool (IdeBlkIoDevice->IdData);
1190 IdeBlkIoDevice->IdData = NULL;
1191 }
1192
1193 if (IdeBlkIoDevice->InquiryData != NULL) {
1194 gBS->FreePool (IdeBlkIoDevice->InquiryData);
1195 IdeBlkIoDevice->InquiryData = NULL;
1196 }
1197
1198 if (IdeBlkIoDevice->ControllerNameTable != NULL) {
1199 FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);
1200 IdeBlkIoDevice->ControllerNameTable = NULL;
1201 }
1202
1203 if (IdeBlkIoDevice->IoPort != NULL) {
1204 gBS->FreePool (IdeBlkIoDevice->IoPort);
1205 }
1206
1207 if (IdeBlkIoDevice->DevicePath != NULL) {
1208 gBS->FreePool (IdeBlkIoDevice->DevicePath);
1209 }
1210
1211 if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {
1212 gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);
1213 IdeBlkIoDevice->ExitBootServiceEvent = NULL;
1214 }
1215
1216 gBS->FreePool (IdeBlkIoDevice);
1217 IdeBlkIoDevice = NULL;
1218
1219 return ;
1220 }
1221 /**
1222 Set the calculated Best transfer mode to a detected device.
1223
1224 @param IdeDev Standard IDE device private data structure
1225 @param TransferMode The device transfer mode to be set
1226 @return Set transfer mode Command execute status.
1227
1228 **/
1229 EFI_STATUS
1230 SetDeviceTransferMode (
1231 IN IDE_BLK_IO_DEV *IdeDev,
1232 IN ATA_TRANSFER_MODE *TransferMode
1233 )
1234 {
1235 EFI_STATUS Status;
1236 UINT8 DeviceSelect;
1237 UINT8 SectorCount;
1238
1239 DeviceSelect = 0;
1240 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
1241 SectorCount = *((UINT8 *) TransferMode);
1242
1243 //
1244 // Send SET FEATURE command (sub command 0x03) to set pio mode.
1245 //
1246 Status = AtaNonDataCommandIn (
1247 IdeDev,
1248 ATA_CMD_SET_FEATURES,
1249 DeviceSelect,
1250 0x03,
1251 SectorCount,
1252 0,
1253 0,
1254 0
1255 );
1256
1257 return Status;
1258 }
1259 /**
1260 Set drive parameters for devices not support PACKETS command.
1261
1262 @param IdeDev Standard IDE device private data structure
1263 @param DriveParameters The device parameters to be set into the disk
1264 @return SetParameters Command execute status.
1265
1266 **/
1267 EFI_STATUS
1268 SetDriveParameters (
1269 IN IDE_BLK_IO_DEV *IdeDev,
1270 IN ATA_DRIVE_PARMS *DriveParameters
1271 )
1272 {
1273 EFI_STATUS Status;
1274 UINT8 DeviceSelect;
1275
1276 DeviceSelect = 0;
1277 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
1278
1279 //
1280 // Send Init drive parameters
1281 //
1282 Status = AtaNonDataCommandIn (
1283 IdeDev,
1284 ATA_CMD_INIT_DRIVE_PARAM,
1285 (UINT8) (DeviceSelect + DriveParameters->Heads),
1286 0,
1287 DriveParameters->Sector,
1288 0,
1289 0,
1290 0
1291 );
1292
1293 //
1294 // Send Set Multiple parameters
1295 //
1296 Status = AtaNonDataCommandIn (
1297 IdeDev,
1298 ATA_CMD_SET_MULTIPLE_MODE,
1299 DeviceSelect,
1300 0,
1301 DriveParameters->MultipleSector,
1302 0,
1303 0,
1304 0
1305 );
1306 return Status;
1307 }
1308
1309 /**
1310 Enable Interrupt on IDE controller.
1311
1312 @param IdeDev Standard IDE device private data structure
1313
1314 @retval EFI_SUCCESS Enable Interrupt successfully
1315 **/
1316 EFI_STATUS
1317 EnableInterrupt (
1318 IN IDE_BLK_IO_DEV *IdeDev
1319 )
1320 {
1321 UINT8 DeviceControl;
1322
1323 //
1324 // Enable interrupt for DMA operation
1325 //
1326 DeviceControl = 0;
1327 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
1328
1329 return EFI_SUCCESS;
1330 }