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