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