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