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