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