VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxIdeBusDxe/Ide.c@ 33114

Last change on this file since 33114 was 33114, checked in by vboxsync, 14 years ago

EFI: some code restructure.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette