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