]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
MdeModulePkg/PciBus: Correct typos
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / IdeMode.c
CommitLineData
a41b5272 1/** @file\r
2 Header file for AHCI mode of ATA host controller.\r
1aff716a 3\r
51492422 4 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>\r
1aff716a 5 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
a41b5272 9\r
1aff716a 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
a41b5272 12\r
13**/\r
14\r
15#include "AtaAtapiPassThru.h"\r
16\r
17/**\r
18 read a one-byte data from a IDE port.\r
19\r
8536cc4b 20 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure\r
1aff716a 21 @param Port The IDE Port number\r
a41b5272 22\r
23 @return the one-byte data read from IDE port\r
24**/\r
25UINT8\r
26EFIAPI\r
27IdeReadPortB (\r
28 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
29 IN UINT16 Port\r
30 )\r
31{\r
32 UINT8 Data;\r
33\r
34 ASSERT (PciIo != NULL);\r
35\r
36 Data = 0;\r
37 //\r
38 // perform 1-byte data read from register\r
39 //\r
40 PciIo->Io.Read (\r
41 PciIo,\r
42 EfiPciIoWidthUint8,\r
43 EFI_PCI_IO_PASS_THROUGH_BAR,\r
44 (UINT64) Port,\r
45 1,\r
46 &Data\r
47 );\r
48 return Data;\r
49}\r
50\r
51/**\r
52 write a 1-byte data to a specific IDE port.\r
53\r
8536cc4b 54 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure\r
a41b5272 55 @param Port The IDE port to be writen\r
56 @param Data The data to write to the port\r
57**/\r
58VOID\r
59EFIAPI\r
60IdeWritePortB (\r
61 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
62 IN UINT16 Port,\r
63 IN UINT8 Data\r
64 )\r
65{\r
66 ASSERT (PciIo != NULL);\r
67\r
68 //\r
69 // perform 1-byte data write to register\r
70 //\r
71 PciIo->Io.Write (\r
72 PciIo,\r
73 EfiPciIoWidthUint8,\r
74 EFI_PCI_IO_PASS_THROUGH_BAR,\r
75 (UINT64) Port,\r
76 1,\r
77 &Data\r
78 );\r
79}\r
80\r
81/**\r
82 write a 1-word data to a specific IDE port.\r
83\r
8536cc4b 84 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure\r
a41b5272 85 @param Port The IDE port to be writen\r
86 @param Data The data to write to the port\r
87**/\r
88VOID\r
89EFIAPI\r
90IdeWritePortW (\r
91 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
92 IN UINT16 Port,\r
93 IN UINT16 Data\r
94 )\r
95{\r
96 ASSERT (PciIo != NULL);\r
97\r
98 //\r
99 // perform 1-word data write to register\r
100 //\r
101 PciIo->Io.Write (\r
102 PciIo,\r
103 EfiPciIoWidthUint16,\r
104 EFI_PCI_IO_PASS_THROUGH_BAR,\r
105 (UINT64) Port,\r
106 1,\r
107 &Data\r
108 );\r
109}\r
110\r
111/**\r
112 write a 2-word data to a specific IDE port.\r
113\r
8536cc4b 114 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure\r
a41b5272 115 @param Port The IDE port to be writen\r
116 @param Data The data to write to the port\r
117**/\r
118VOID\r
119EFIAPI\r
120IdeWritePortDW (\r
121 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
122 IN UINT16 Port,\r
123 IN UINT32 Data\r
124 )\r
125{\r
126 ASSERT (PciIo != NULL);\r
127\r
128 //\r
129 // perform 2-word data write to register\r
130 //\r
131 PciIo->Io.Write (\r
132 PciIo,\r
133 EfiPciIoWidthUint32,\r
134 EFI_PCI_IO_PASS_THROUGH_BAR,\r
135 (UINT64) Port,\r
136 1,\r
137 &Data\r
138 );\r
139}\r
140\r
141/**\r
142 Write multiple words of data to the IDE data port.\r
143 Call the IO abstraction once to do the complete read,\r
144 not one word at a time\r
145\r
8536cc4b 146 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure\r
a41b5272 147 @param Port IO port to read\r
148 @param Count No. of UINT16's to read\r
149 @param Buffer Pointer to the data buffer for read\r
150\r
151**/\r
152VOID\r
153EFIAPI\r
154IdeWritePortWMultiple (\r
155 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
156 IN UINT16 Port,\r
157 IN UINTN Count,\r
158 IN VOID *Buffer\r
159 )\r
160{\r
161 ASSERT (PciIo != NULL);\r
162 ASSERT (Buffer != NULL);\r
163\r
164 //\r
165 // perform UINT16 data write to the FIFO\r
166 //\r
167 PciIo->Io.Write (\r
168 PciIo,\r
169 EfiPciIoWidthFifoUint16,\r
170 EFI_PCI_IO_PASS_THROUGH_BAR,\r
171 (UINT64) Port,\r
172 Count,\r
173 (UINT16 *) Buffer\r
174 );\r
175\r
176}\r
177\r
178/**\r
179 Reads multiple words of data from the IDE data port.\r
180 Call the IO abstraction once to do the complete read,\r
181 not one word at a time\r
182\r
8536cc4b 183 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure\r
a41b5272 184 @param Port IO port to read\r
185 @param Count Number of UINT16's to read\r
186 @param Buffer Pointer to the data buffer for read\r
187\r
188**/\r
189VOID\r
190EFIAPI\r
191IdeReadPortWMultiple (\r
192 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
193 IN UINT16 Port,\r
194 IN UINTN Count,\r
195 IN VOID *Buffer\r
196 )\r
197{\r
198 ASSERT (PciIo != NULL);\r
199 ASSERT (Buffer != NULL);\r
200\r
201 //\r
202 // Perform UINT16 data read from FIFO\r
203 //\r
204 PciIo->Io.Read (\r
205 PciIo,\r
206 EfiPciIoWidthFifoUint16,\r
207 EFI_PCI_IO_PASS_THROUGH_BAR,\r
208 (UINT64) Port,\r
209 Count,\r
210 (UINT16 *) Buffer\r
211 );\r
212\r
213}\r
214\r
215/**\r
216 This function is used to analyze the Status Register and print out\r
217 some debug information and if there is ERR bit set in the Status\r
218 Register, the Error Register's value is also be parsed and print out.\r
219\r
8536cc4b 220 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
a41b5272 221 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
222 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
223\r
224**/\r
225VOID\r
226EFIAPI\r
227DumpAllIdeRegisters (\r
228 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
229 IN EFI_IDE_REGISTERS *IdeRegisters,\r
230 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
231 )\r
232{\r
233 EFI_ATA_STATUS_BLOCK StatusBlock;\r
234\r
235 ASSERT (PciIo != NULL);\r
236 ASSERT (IdeRegisters != NULL);\r
237\r
238 ZeroMem (&StatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
239\r
240 StatusBlock.AtaStatus = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
241 StatusBlock.AtaError = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
242 StatusBlock.AtaSectorCount = IdeReadPortB (PciIo, IdeRegisters->SectorCount);\r
243 StatusBlock.AtaSectorCountExp = IdeReadPortB (PciIo, IdeRegisters->SectorCount);\r
244 StatusBlock.AtaSectorNumber = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);\r
245 StatusBlock.AtaSectorNumberExp = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);\r
246 StatusBlock.AtaCylinderLow = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
247 StatusBlock.AtaCylinderLowExp = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
248 StatusBlock.AtaCylinderHigh = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);\r
249 StatusBlock.AtaCylinderHighExp = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);\r
250 StatusBlock.AtaDeviceHead = IdeReadPortB (PciIo, IdeRegisters->Head);\r
251\r
252 if (AtaStatusBlock != NULL) {\r
253 //\r
254 // Dump the content of all ATA registers.\r
255 //\r
256 CopyMem (AtaStatusBlock, &StatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
257 }\r
258\r
259 DEBUG_CODE_BEGIN ();\r
260 if ((StatusBlock.AtaStatus & ATA_STSREG_DWF) != 0) {\r
261 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Write Fault\n", StatusBlock.AtaStatus));\r
262 }\r
263\r
264 if ((StatusBlock.AtaStatus & ATA_STSREG_CORR) != 0) {\r
265 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Corrected Data\n", StatusBlock.AtaStatus));\r
266 }\r
267\r
268 if ((StatusBlock.AtaStatus & ATA_STSREG_ERR) != 0) {\r
269 if ((StatusBlock.AtaError & ATA_ERRREG_BBK) != 0) {\r
270 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Bad Block Detected\n", StatusBlock.AtaError));\r
271 }\r
272\r
273 if ((StatusBlock.AtaError & ATA_ERRREG_UNC) != 0) {\r
274 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Uncorrectable Data\n", StatusBlock.AtaError));\r
275 }\r
276\r
277 if ((StatusBlock.AtaError & ATA_ERRREG_MC) != 0) {\r
278 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Media Change\n", StatusBlock.AtaError));\r
279 }\r
280\r
281 if ((StatusBlock.AtaError & ATA_ERRREG_ABRT) != 0) {\r
282 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Abort\n", StatusBlock.AtaError));\r
283 }\r
284\r
285 if ((StatusBlock.AtaError & ATA_ERRREG_TK0NF) != 0) {\r
286 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Track 0 Not Found\n", StatusBlock.AtaError));\r
287 }\r
288\r
289 if ((StatusBlock.AtaError & ATA_ERRREG_AMNF) != 0) {\r
290 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Address Mark Not Found\n", StatusBlock.AtaError));\r
291 }\r
292 }\r
293 DEBUG_CODE_END ();\r
294}\r
295\r
296/**\r
8536cc4b 297 This function is used to analyze the Status Register at the condition that BSY is zero.\r
298 if there is ERR bit set in the Status Register, then return error.\r
a41b5272 299\r
8536cc4b 300 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
a41b5272 301 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
302\r
303 @retval EFI_SUCCESS No err information in the Status Register.\r
304 @retval EFI_DEVICE_ERROR Any err information in the Status Register.\r
305\r
306**/\r
307EFI_STATUS\r
308EFIAPI\r
309CheckStatusRegister (\r
310 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
311 IN EFI_IDE_REGISTERS *IdeRegisters\r
312 )\r
313{\r
a41b5272 314 UINT8 StatusRegister;\r
315\r
316 ASSERT (PciIo != NULL);\r
317 ASSERT (IdeRegisters != NULL);\r
318\r
319 StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
320\r
8536cc4b 321 if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
322 if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {\r
323 return EFI_SUCCESS;\r
324 } else {\r
325 return EFI_DEVICE_ERROR;\r
326 }\r
a41b5272 327 }\r
8536cc4b 328 return EFI_SUCCESS;\r
a41b5272 329}\r
330\r
331/**\r
332 This function is used to poll for the DRQ bit clear in the Status\r
333 Register. DRQ is cleared when the device is finished transferring data.\r
334 So this function is called after data transfer is finished.\r
335\r
8536cc4b 336 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
a41b5272 337 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
8536cc4b 338 @param Timeout The time to complete the command, uses 100ns as a unit.\r
a41b5272 339\r
340 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
341\r
342 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
343\r
344 @note\r
345 Read Status Register will clear interrupt status.\r
346\r
347**/\r
348EFI_STATUS\r
349EFIAPI\r
350DRQClear (\r
351 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
352 IN EFI_IDE_REGISTERS *IdeRegisters,\r
353 IN UINT64 Timeout\r
354 )\r
355{\r
ab82122d 356 UINT64 Delay;\r
a41b5272 357 UINT8 StatusRegister;\r
ab82122d 358 BOOLEAN InfiniteWait;\r
a41b5272 359\r
360 ASSERT (PciIo != NULL);\r
361 ASSERT (IdeRegisters != NULL);\r
362\r
ab82122d
TF
363 if (Timeout == 0) {\r
364 InfiniteWait = TRUE;\r
365 } else {\r
366 InfiniteWait = FALSE;\r
367 }\r
368\r
369 Delay = DivU64x32(Timeout, 1000) + 1;\r
a41b5272 370 do {\r
371 StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
372\r
373 //\r
8536cc4b 374 // Wait for BSY == 0, then judge if DRQ is clear\r
a41b5272 375 //\r
8536cc4b 376 if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
377 if ((StatusRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
378 return EFI_DEVICE_ERROR;\r
379 } else {\r
380 return EFI_SUCCESS;\r
a41b5272 381 }\r
382 }\r
383\r
384 //\r
8536cc4b 385 // Stall for 100 microseconds.\r
a41b5272 386 //\r
387 MicroSecondDelay (100);\r
388\r
389 Delay--;\r
390\r
ab82122d 391 } while (InfiniteWait || (Delay > 0));\r
a41b5272 392\r
8536cc4b 393 return EFI_TIMEOUT;\r
a41b5272 394}\r
395/**\r
396 This function is used to poll for the DRQ bit clear in the Alternate\r
397 Status Register. DRQ is cleared when the device is finished\r
398 transferring data. So this function is called after data transfer\r
399 is finished.\r
400\r
8536cc4b 401 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
a41b5272 402 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
8536cc4b 403 @param Timeout The time to complete the command, uses 100ns as a unit.\r
a41b5272 404\r
405 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
406\r
407 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
408 @note Read Alternate Status Register will not clear interrupt status.\r
409\r
410**/\r
411EFI_STATUS\r
412EFIAPI\r
413DRQClear2 (\r
414 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
415 IN EFI_IDE_REGISTERS *IdeRegisters,\r
416 IN UINT64 Timeout\r
417 )\r
418{\r
ab82122d 419 UINT64 Delay;\r
a41b5272 420 UINT8 AltRegister;\r
ab82122d 421 BOOLEAN InfiniteWait;\r
a41b5272 422\r
423 ASSERT (PciIo != NULL);\r
424 ASSERT (IdeRegisters != NULL);\r
425\r
ab82122d
TF
426 if (Timeout == 0) {\r
427 InfiniteWait = TRUE;\r
428 } else {\r
429 InfiniteWait = FALSE;\r
430 }\r
431\r
432 Delay = DivU64x32(Timeout, 1000) + 1;\r
a41b5272 433 do {\r
434 AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
435\r
436 //\r
8536cc4b 437 // Wait for BSY == 0, then judge if DRQ is clear\r
a41b5272 438 //\r
8536cc4b 439 if ((AltRegister & ATA_STSREG_BSY) == 0) {\r
440 if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
441 return EFI_DEVICE_ERROR;\r
442 } else {\r
443 return EFI_SUCCESS;\r
a41b5272 444 }\r
445 }\r
446\r
447 //\r
448 // Stall for 100 microseconds.\r
449 //\r
450 MicroSecondDelay (100);\r
451\r
452 Delay--;\r
453\r
ab82122d 454 } while (InfiniteWait || (Delay > 0));\r
a41b5272 455\r
8536cc4b 456 return EFI_TIMEOUT;\r
a41b5272 457}\r
458\r
459/**\r
460 This function is used to poll for the DRQ bit set in the\r
461 Status Register.\r
462 DRQ is set when the device is ready to transfer data. So this function\r
463 is called after the command is sent to the device and before required\r
464 data is transferred.\r
465\r
8536cc4b 466 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
a41b5272 467 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
8536cc4b 468 @param Timeout The time to complete the command, uses 100ns as a unit.\r
a41b5272 469\r
dfc229f6
LE
470 @retval EFI_SUCCESS BSY bit cleared and DRQ bit set within the\r
471 timeout.\r
472\r
473 @retval EFI_TIMEOUT BSY bit not cleared within the timeout.\r
474\r
475 @retval EFI_ABORTED Polling abandoned due to command abort.\r
476\r
477 @retval EFI_DEVICE_ERROR Polling abandoned due to a non-abort error.\r
478\r
479 @retval EFI_NOT_READY BSY bit cleared within timeout, and device\r
480 reported "command complete" by clearing DRQ\r
481 bit.\r
a41b5272 482\r
483 @note Read Status Register will clear interrupt status.\r
484\r
485**/\r
486EFI_STATUS\r
487EFIAPI\r
488DRQReady (\r
489 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
490 IN EFI_IDE_REGISTERS *IdeRegisters,\r
491 IN UINT64 Timeout\r
492 )\r
493{\r
ab82122d 494 UINT64 Delay;\r
a41b5272 495 UINT8 StatusRegister;\r
496 UINT8 ErrorRegister;\r
ab82122d 497 BOOLEAN InfiniteWait;\r
a41b5272 498\r
499 ASSERT (PciIo != NULL);\r
500 ASSERT (IdeRegisters != NULL);\r
501\r
ab82122d
TF
502 if (Timeout == 0) {\r
503 InfiniteWait = TRUE;\r
504 } else {\r
505 InfiniteWait = FALSE;\r
506 }\r
507\r
508 Delay = DivU64x32(Timeout, 1000) + 1;\r
a41b5272 509 do {\r
510 //\r
8536cc4b 511 // Read Status Register will clear interrupt\r
a41b5272 512 //\r
513 StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
514\r
515 //\r
8536cc4b 516 // Wait for BSY == 0, then judge if DRQ is clear or ERR is set\r
a41b5272 517 //\r
8536cc4b 518 if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
519 if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
520 ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
a41b5272 521\r
8536cc4b 522 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
523 return EFI_ABORTED;\r
524 }\r
525 return EFI_DEVICE_ERROR;\r
526 }\r
a41b5272 527\r
8536cc4b 528 if ((StatusRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
529 return EFI_SUCCESS;\r
530 } else {\r
531 return EFI_NOT_READY;\r
a41b5272 532 }\r
533 }\r
534\r
535 //\r
536 // Stall for 100 microseconds.\r
537 //\r
538 MicroSecondDelay (100);\r
539\r
540 Delay--;\r
ab82122d 541 } while (InfiniteWait || (Delay > 0));\r
a41b5272 542\r
8536cc4b 543 return EFI_TIMEOUT;\r
a41b5272 544}\r
545/**\r
546 This function is used to poll for the DRQ bit set in the Alternate Status Register.\r
1aff716a 547 DRQ is set when the device is ready to transfer data. So this function is called after\r
a41b5272 548 the command is sent to the device and before required data is transferred.\r
549\r
8536cc4b 550 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
a41b5272 551 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
8536cc4b 552 @param Timeout The time to complete the command, uses 100ns as a unit.\r
a41b5272 553\r
dfc229f6
LE
554 @retval EFI_SUCCESS BSY bit cleared and DRQ bit set within the\r
555 timeout.\r
556\r
557 @retval EFI_TIMEOUT BSY bit not cleared within the timeout.\r
558\r
559 @retval EFI_ABORTED Polling abandoned due to command abort.\r
560\r
561 @retval EFI_DEVICE_ERROR Polling abandoned due to a non-abort error.\r
562\r
563 @retval EFI_NOT_READY BSY bit cleared within timeout, and device\r
564 reported "command complete" by clearing DRQ\r
565 bit.\r
566\r
a41b5272 567 @note Read Alternate Status Register will not clear interrupt status.\r
568\r
569**/\r
570EFI_STATUS\r
571EFIAPI\r
572DRQReady2 (\r
573 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
574 IN EFI_IDE_REGISTERS *IdeRegisters,\r
575 IN UINT64 Timeout\r
576 )\r
577{\r
ab82122d 578 UINT64 Delay;\r
a41b5272 579 UINT8 AltRegister;\r
580 UINT8 ErrorRegister;\r
ab82122d 581 BOOLEAN InfiniteWait;\r
a41b5272 582\r
583 ASSERT (PciIo != NULL);\r
584 ASSERT (IdeRegisters != NULL);\r
585\r
ab82122d
TF
586 if (Timeout == 0) {\r
587 InfiniteWait = TRUE;\r
588 } else {\r
589 InfiniteWait = FALSE;\r
590 }\r
591\r
592 Delay = DivU64x32(Timeout, 1000) + 1;\r
a41b5272 593\r
594 do {\r
595 //\r
8536cc4b 596 // Read Alternate Status Register will not clear interrupt status\r
a41b5272 597 //\r
598 AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
599 //\r
8536cc4b 600 // Wait for BSY == 0, then judge if DRQ is clear or ERR is set\r
a41b5272 601 //\r
8536cc4b 602 if ((AltRegister & ATA_STSREG_BSY) == 0) {\r
603 if ((AltRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
604 ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
a41b5272 605\r
8536cc4b 606 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
607 return EFI_ABORTED;\r
608 }\r
609 return EFI_DEVICE_ERROR;\r
610 }\r
a41b5272 611\r
8536cc4b 612 if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
613 return EFI_SUCCESS;\r
614 } else {\r
615 return EFI_NOT_READY;\r
a41b5272 616 }\r
617 }\r
618\r
619 //\r
620 // Stall for 100 microseconds.\r
621 //\r
622 MicroSecondDelay (100);\r
623\r
624 Delay--;\r
ab82122d 625 } while (InfiniteWait || (Delay > 0));\r
a41b5272 626\r
8536cc4b 627 return EFI_TIMEOUT;\r
a41b5272 628}\r
629\r
a41b5272 630\r
a41b5272 631\r
a41b5272 632\r
633/**\r
634 This function is used to poll for the BSY bit clear in the Status Register. BSY\r
635 is clear when the device is not busy. Every command must be sent after device is not busy.\r
636\r
637 @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
638 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
8536cc4b 639 @param Timeout The time to complete the command, uses 100ns as a unit.\r
a41b5272 640\r
641 @retval EFI_SUCCESS BSY bit clear within the time out.\r
642 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
643\r
644 @note Read Status Register will clear interrupt status.\r
645**/\r
646EFI_STATUS\r
647EFIAPI\r
648WaitForBSYClear (\r
649 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
650 IN EFI_IDE_REGISTERS *IdeRegisters,\r
651 IN UINT64 Timeout\r
652 )\r
653{\r
ab82122d 654 UINT64 Delay;\r
a41b5272 655 UINT8 StatusRegister;\r
ab82122d 656 BOOLEAN InfiniteWait;\r
a41b5272 657\r
658 ASSERT (PciIo != NULL);\r
659 ASSERT (IdeRegisters != NULL);\r
660\r
ab82122d
TF
661 if (Timeout == 0) {\r
662 InfiniteWait = TRUE;\r
663 } else {\r
664 InfiniteWait = FALSE;\r
665 }\r
666\r
667 Delay = DivU64x32(Timeout, 1000) + 1;\r
a41b5272 668 do {\r
669 StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
670\r
671 if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
8536cc4b 672 return EFI_SUCCESS;\r
a41b5272 673 }\r
674\r
675 //\r
676 // Stall for 100 microseconds.\r
677 //\r
678 MicroSecondDelay (100);\r
679\r
680 Delay--;\r
681\r
ab82122d 682 } while (InfiniteWait || (Delay > 0));\r
a41b5272 683\r
8536cc4b 684 return EFI_TIMEOUT;\r
a41b5272 685}\r
686\r
a41b5272 687\r
688/**\r
1aff716a 689 Get IDE i/o port registers' base addresses by mode.\r
a41b5272 690\r
691 In 'Compatibility' mode, use fixed addresses.\r
692 In Native-PCI mode, get base addresses from BARs in the PCI IDE controller's\r
693 Configuration Space.\r
694\r
695 The steps to get IDE i/o port registers' base addresses for each channel\r
696 as follows:\r
697\r
698 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
699 controller's Configuration Space to determine the operating mode.\r
700\r
701 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
702 ___________________________________________\r
703 | | Command Block | Control Block |\r
704 | Channel | Registers | Registers |\r
705 |___________|_______________|_______________|\r
706 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
707 |___________|_______________|_______________|\r
708 | Secondary | 170h - 177h | 376h - 377h |\r
709 |___________|_______________|_______________|\r
710\r
711 Table 1. Compatibility resource mappings\r
1aff716a 712\r
a41b5272 713 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
714 in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
715 ___________________________________________________\r
716 | | Command Block | Control Block |\r
717 | Channel | Registers | Registers |\r
718 |___________|___________________|___________________|\r
719 | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
720 |___________|___________________|___________________|\r
721 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
722 |___________|___________________|___________________|\r
723\r
724 Table 2. BARs for Register Mapping\r
725\r
726 @param[in] PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
727 @param[in, out] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to\r
728 store the IDE i/o port registers' base addresses\r
1aff716a 729\r
a41b5272 730 @retval EFI_UNSUPPORTED Return this value when the BARs is not IO type\r
731 @retval EFI_SUCCESS Get the Base address successfully\r
732 @retval Other Read the pci configureation data error\r
733\r
734**/\r
735EFI_STATUS\r
736EFIAPI\r
737GetIdeRegisterIoAddr (\r
738 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
739 IN OUT EFI_IDE_REGISTERS *IdeRegisters\r
740 )\r
741{\r
742 EFI_STATUS Status;\r
743 PCI_TYPE00 PciData;\r
744 UINT16 CommandBlockBaseAddr;\r
745 UINT16 ControlBlockBaseAddr;\r
746 UINT16 BusMasterBaseAddr;\r
747\r
748 if ((PciIo == NULL) || (IdeRegisters == NULL)) {\r
749 return EFI_INVALID_PARAMETER;\r
750 }\r
751\r
752 Status = PciIo->Pci.Read (\r
753 PciIo,\r
754 EfiPciIoWidthUint8,\r
755 0,\r
756 sizeof (PciData),\r
757 &PciData\r
758 );\r
759\r
760 if (EFI_ERROR (Status)) {\r
761 return Status;\r
762 }\r
763\r
764 BusMasterBaseAddr = (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
765\r
766 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
767 CommandBlockBaseAddr = 0x1f0;\r
768 ControlBlockBaseAddr = 0x3f6;\r
769 } else {\r
770 //\r
771 // The BARs should be of IO type\r
772 //\r
773 if ((PciData.Device.Bar[0] & BIT0) == 0 ||\r
774 (PciData.Device.Bar[1] & BIT0) == 0) {\r
775 return EFI_UNSUPPORTED;\r
776 }\r
777\r
778 CommandBlockBaseAddr = (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
779 ControlBlockBaseAddr = (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
780 }\r
781\r
782 //\r
783 // Calculate IDE primary channel I/O register base address.\r
784 //\r
785 IdeRegisters[EfiIdePrimary].Data = CommandBlockBaseAddr;\r
786 IdeRegisters[EfiIdePrimary].ErrOrFeature = (UINT16) (CommandBlockBaseAddr + 0x01);\r
787 IdeRegisters[EfiIdePrimary].SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
788 IdeRegisters[EfiIdePrimary].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
789 IdeRegisters[EfiIdePrimary].CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
790 IdeRegisters[EfiIdePrimary].CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
791 IdeRegisters[EfiIdePrimary].Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
792 IdeRegisters[EfiIdePrimary].CmdOrStatus = (UINT16) (CommandBlockBaseAddr + 0x07);\r
793 IdeRegisters[EfiIdePrimary].AltOrDev = ControlBlockBaseAddr;\r
794 IdeRegisters[EfiIdePrimary].BusMasterBaseAddr = BusMasterBaseAddr;\r
795\r
796 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
797 CommandBlockBaseAddr = 0x170;\r
798 ControlBlockBaseAddr = 0x376;\r
799 } else {\r
800 //\r
801 // The BARs should be of IO type\r
802 //\r
803 if ((PciData.Device.Bar[2] & BIT0) == 0 ||\r
804 (PciData.Device.Bar[3] & BIT0) == 0) {\r
805 return EFI_UNSUPPORTED;\r
806 }\r
807\r
808 CommandBlockBaseAddr = (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
809 ControlBlockBaseAddr = (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
810 }\r
811\r
812 //\r
813 // Calculate IDE secondary channel I/O register base address.\r
814 //\r
815 IdeRegisters[EfiIdeSecondary].Data = CommandBlockBaseAddr;\r
816 IdeRegisters[EfiIdeSecondary].ErrOrFeature = (UINT16) (CommandBlockBaseAddr + 0x01);\r
817 IdeRegisters[EfiIdeSecondary].SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
818 IdeRegisters[EfiIdeSecondary].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
819 IdeRegisters[EfiIdeSecondary].CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
820 IdeRegisters[EfiIdeSecondary].CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
821 IdeRegisters[EfiIdeSecondary].Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
822 IdeRegisters[EfiIdeSecondary].CmdOrStatus = (UINT16) (CommandBlockBaseAddr + 0x07);\r
823 IdeRegisters[EfiIdeSecondary].AltOrDev = ControlBlockBaseAddr;\r
aca84419 824 IdeRegisters[EfiIdeSecondary].BusMasterBaseAddr = (UINT16) (BusMasterBaseAddr + 0x8);\r
a41b5272 825\r
826 return EFI_SUCCESS;\r
827}\r
828\r
a41b5272 829\r
830/**\r
831 Send ATA Ext command into device with NON_DATA protocol.\r
832\r
833 @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
834 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
835 @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
8536cc4b 836 @param Timeout The time to complete the command, uses 100ns as a unit.\r
a41b5272 837\r
838 @retval EFI_SUCCESS Reading succeed\r
839 @retval EFI_DEVICE_ERROR Error executing commands on this device.\r
840\r
841**/\r
842EFI_STATUS\r
843EFIAPI\r
844AtaIssueCommand (\r
845 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
846 IN EFI_IDE_REGISTERS *IdeRegisters,\r
847 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
848 IN UINT64 Timeout\r
849 )\r
850{\r
851 EFI_STATUS Status;\r
852 UINT8 DeviceHead;\r
853 UINT8 AtaCommand;\r
854\r
855 ASSERT (PciIo != NULL);\r
856 ASSERT (IdeRegisters != NULL);\r
857 ASSERT (AtaCommandBlock != NULL);\r
858\r
859 DeviceHead = AtaCommandBlock->AtaDeviceHead;\r
860 AtaCommand = AtaCommandBlock->AtaCommand;\r
861\r
862 Status = WaitForBSYClear (PciIo, IdeRegisters, Timeout);\r
863 if (EFI_ERROR (Status)) {\r
864 return EFI_DEVICE_ERROR;\r
865 }\r
866\r
867 //\r
868 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
869 //\r
870 IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8) (0xe0 | DeviceHead));\r
871\r
872 //\r
873 // set all the command parameters\r
874 // Before write to all the following registers, BSY and DRQ must be 0.\r
875 //\r
876 Status = DRQClear2 (PciIo, IdeRegisters, Timeout);\r
877 if (EFI_ERROR (Status)) {\r
878 return EFI_DEVICE_ERROR;\r
879 }\r
880\r
881 //\r
882 // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
883 //\r
884 IdeWritePortB (PciIo, IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeaturesExp);\r
885 IdeWritePortB (PciIo, IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeatures);\r
886\r
887 //\r
888 // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
889 //\r
890 IdeWritePortB (PciIo, IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCountExp);\r
891 IdeWritePortB (PciIo, IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCount);\r
892\r
893 //\r
894 // Fill the start LBA registers, which are also two-byte FIFO\r
895 //\r
896 IdeWritePortB (PciIo, IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumberExp);\r
897 IdeWritePortB (PciIo, IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumber);\r
898\r
899 IdeWritePortB (PciIo, IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLowExp);\r
900 IdeWritePortB (PciIo, IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLow);\r
901\r
902 IdeWritePortB (PciIo, IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHighExp);\r
903 IdeWritePortB (PciIo, IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHigh);\r
904\r
905 //\r
906 // Send command via Command Register\r
907 //\r
908 IdeWritePortB (PciIo, IdeRegisters->CmdOrStatus, AtaCommand);\r
909\r
910 //\r
911 // Stall at least 400 microseconds.\r
912 //\r
913 MicroSecondDelay (400);\r
914\r
915 return EFI_SUCCESS;\r
916}\r
917\r
918/**\r
919 This function is used to send out ATA commands conforms to the PIO Data In Protocol.\r
920\r
490b5ea1 921 @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data\r
922 structure.\r
923 @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
924 @param[in, out] Buffer A pointer to the source buffer for the data.\r
925 @param[in] ByteCount The length of the data.\r
86d8e199 926 @param[in] Read Flag used to determine the data transfer direction.\r
490b5ea1 927 Read equals 1, means data transferred from device\r
928 to host;Read equals 0, means data transferred\r
929 from host to device.\r
930 @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
86d8e199 931 @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
8536cc4b 932 @param[in] Timeout The time to complete the command, uses 100ns as a unit.\r
490b5ea1 933 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
934 used by non-blocking mode.\r
1aff716a 935\r
a41b5272 936 @retval EFI_SUCCESS send out the ATA command and device send required data successfully.\r
937 @retval EFI_DEVICE_ERROR command sent failed.\r
938\r
939**/\r
940EFI_STATUS\r
941EFIAPI\r
1aff716a 942AtaPioDataInOut (\r
a41b5272 943 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
944 IN EFI_IDE_REGISTERS *IdeRegisters,\r
945 IN OUT VOID *Buffer,\r
946 IN UINT64 ByteCount,\r
947 IN BOOLEAN Read,\r
948 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
949 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
490b5ea1 950 IN UINT64 Timeout,\r
951 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 952 )\r
953{\r
954 UINTN WordCount;\r
955 UINTN Increment;\r
956 UINT16 *Buffer16;\r
957 EFI_STATUS Status;\r
958\r
959 if ((PciIo == NULL) || (IdeRegisters == NULL) || (Buffer == NULL) || (AtaCommandBlock == NULL)) {\r
960 return EFI_INVALID_PARAMETER;\r
961 }\r
962\r
963 //\r
964 // Issue ATA command\r
965 //\r
966 Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
967 if (EFI_ERROR (Status)) {\r
968 Status = EFI_DEVICE_ERROR;\r
969 goto Exit;\r
970 }\r
971\r
972 Buffer16 = (UINT16 *) Buffer;\r
973\r
974 //\r
975 // According to PIO data in protocol, host can perform a series of reads to\r
976 // the data register after each time device set DRQ ready;\r
977 // The data size of "a series of read" is command specific.\r
978 // For most ATA command, data size received from device will not exceed\r
979 // 1 sector, hence the data size for "a series of read" can be the whole data\r
980 // size of one command request.\r
981 // For ATA command such as Read Sector command, the data size of one ATA\r
982 // command request is often larger than 1 sector, according to the\r
983 // Read Sector command, the data size of "a series of read" is exactly 1\r
984 // sector.\r
985 // Here for simplification reason, we specify the data size for\r
986 // "a series of read" to 1 sector (256 words) if data size of one ATA command\r
987 // request is larger than 256 words.\r
988 //\r
989 Increment = 256;\r
990\r
991 //\r
992 // used to record bytes of currently transfered data\r
993 //\r
994 WordCount = 0;\r
995\r
996 while (WordCount < RShiftU64(ByteCount, 1)) {\r
997 //\r
998 // Poll DRQ bit set, data transfer can be performed only when DRQ is ready\r
999 //\r
1000 Status = DRQReady2 (PciIo, IdeRegisters, Timeout);\r
1aff716a 1001 if (EFI_ERROR (Status)) {\r
a41b5272 1002 Status = EFI_DEVICE_ERROR;\r
1003 goto Exit;\r
1004 }\r
1005\r
1006 //\r
1007 // Get the byte count for one series of read\r
1008 //\r
1009 if ((WordCount + Increment) > RShiftU64(ByteCount, 1)) {\r
1010 Increment = (UINTN)(RShiftU64(ByteCount, 1) - WordCount);\r
1011 }\r
1012\r
1013 if (Read) {\r
1014 IdeReadPortWMultiple (\r
1015 PciIo,\r
1016 IdeRegisters->Data,\r
1017 Increment,\r
1018 Buffer16\r
1019 );\r
1020 } else {\r
1021 IdeWritePortWMultiple (\r
1022 PciIo,\r
1023 IdeRegisters->Data,\r
1024 Increment,\r
1025 Buffer16\r
1026 );\r
1027 }\r
1028\r
1029 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1030 if (EFI_ERROR (Status)) {\r
1031 Status = EFI_DEVICE_ERROR;\r
1032 goto Exit;\r
1033 }\r
1034\r
1035 WordCount += Increment;\r
1036 Buffer16 += Increment;\r
1037 }\r
1038\r
1039 Status = DRQClear (PciIo, IdeRegisters, Timeout);\r
1040 if (EFI_ERROR (Status)) {\r
1041 Status = EFI_DEVICE_ERROR;\r
1042 goto Exit;\r
1043 }\r
1044\r
1045Exit:\r
1046 //\r
1047 // Dump All Ide registers to ATA_STATUS_BLOCK\r
1048 //\r
1049 DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
1050\r
490b5ea1 1051 //\r
1052 // Not support the Non-blocking now,just do the blocking process.\r
1053 //\r
a41b5272 1054 return Status;\r
1055}\r
1056\r
1057/**\r
1058 Send ATA command into device with NON_DATA protocol\r
1059\r
490b5ea1 1060 @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE\r
1061 data structure.\r
1062 @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
1063 @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data\r
1064 structure.\r
1065 @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
8536cc4b 1066 @param[in] Timeout The time to complete the command, uses 100ns as a unit.\r
490b5ea1 1067 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1068 used by non-blocking mode.\r
a41b5272 1069\r
1070 @retval EFI_SUCCESS Reading succeed\r
1071 @retval EFI_ABORTED Command failed\r
1072 @retval EFI_DEVICE_ERROR Device status error.\r
1073\r
1074**/\r
1075EFI_STATUS\r
1076EFIAPI\r
1aff716a 1077AtaNonDataCommandIn (\r
a41b5272 1078 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1079 IN EFI_IDE_REGISTERS *IdeRegisters,\r
1080 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
1081 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
490b5ea1 1082 IN UINT64 Timeout,\r
1083 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 1084 )\r
1085{\r
1086 EFI_STATUS Status;\r
1087\r
1088 if ((PciIo == NULL) || (IdeRegisters == NULL) || (AtaCommandBlock == NULL)) {\r
1089 return EFI_INVALID_PARAMETER;\r
1090 }\r
1091\r
1092 //\r
1093 // Issue ATA command\r
1094 //\r
1095 Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
1096 if (EFI_ERROR (Status)) {\r
1097 Status = EFI_DEVICE_ERROR;\r
1098 goto Exit;\r
1099 }\r
1100\r
1101 //\r
1102 // Wait for command completion\r
1103 //\r
1104 Status = WaitForBSYClear (PciIo, IdeRegisters, Timeout);\r
1105 if (EFI_ERROR (Status)) {\r
1106 Status = EFI_DEVICE_ERROR;\r
1107 goto Exit;\r
1108 }\r
1aff716a 1109\r
a41b5272 1110 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1111 if (EFI_ERROR (Status)) {\r
1112 Status = EFI_DEVICE_ERROR;\r
1113 goto Exit;\r
1114 }\r
1115\r
1116Exit:\r
1117 //\r
1118 // Dump All Ide registers to ATA_STATUS_BLOCK\r
1119 //\r
1120 DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
1aff716a 1121\r
490b5ea1 1122 //\r
1123 // Not support the Non-blocking now,just do the blocking process.\r
1124 //\r
1125 return Status;\r
1126}\r
1127\r
1128/**\r
1129 Wait for memory to be set.\r
1aff716a 1130\r
490b5ea1 1131 @param[in] PciIo The PCI IO protocol instance.\r
8536cc4b 1132 @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
ab82122d 1133 @param[in] Timeout The time to complete the command, uses 100ns as a unit.\r
490b5ea1 1134\r
1135 @retval EFI_DEVICE_ERROR The memory is not set.\r
1136 @retval EFI_TIMEOUT The memory setting is time out.\r
1137 @retval EFI_SUCCESS The memory is correct set.\r
1138\r
1139**/\r
1140EFI_STATUS\r
1141AtaUdmStatusWait (\r
ab82122d
TF
1142 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1143 IN EFI_IDE_REGISTERS *IdeRegisters,\r
1144 IN UINT64 Timeout\r
1aff716a 1145 )\r
490b5ea1 1146{\r
1147 UINT8 RegisterValue;\r
1148 EFI_STATUS Status;\r
8536cc4b 1149 UINT16 IoPortForBmis;\r
ab82122d
TF
1150 UINT64 Delay;\r
1151 BOOLEAN InfiniteWait;\r
1152\r
1153 if (Timeout == 0) {\r
1154 InfiniteWait = TRUE;\r
1155 } else {\r
1156 InfiniteWait = FALSE;\r
1157 }\r
490b5ea1 1158\r
ab82122d 1159 Delay = DivU64x32 (Timeout, 1000) + 1;\r
490b5ea1 1160\r
ab82122d 1161 do {\r
8536cc4b 1162 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1163 if (EFI_ERROR (Status)) {\r
1164 Status = EFI_DEVICE_ERROR;\r
1165 break;\r
1166 }\r
490b5ea1 1167\r
8536cc4b 1168 IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);\r
1169 RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);\r
490b5ea1 1170 if (((RegisterValue & BMIS_ERROR) != 0) || (Timeout == 0)) {\r
1171 DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));\r
1172 Status = EFI_DEVICE_ERROR;\r
1173 break;\r
1174 }\r
1175\r
1176 if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
1177 Status = EFI_SUCCESS;\r
490b5ea1 1178 break;\r
1179 }\r
1180 //\r
ab82122d 1181 // Stall for 100 microseconds.\r
490b5ea1 1182 //\r
ab82122d
TF
1183 MicroSecondDelay (100);\r
1184 Delay--;\r
1185 } while (InfiniteWait || (Delay > 0));\r
a41b5272 1186\r
1187 return Status;\r
1188}\r
1189\r
490b5ea1 1190/**\r
1191 Check if the memory to be set.\r
1aff716a 1192\r
490b5ea1 1193 @param[in] PciIo The PCI IO protocol instance.\r
1194 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1195 used by non-blocking mode.\r
8536cc4b 1196 @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
490b5ea1 1197\r
1198 @retval EFI_DEVICE_ERROR The memory setting met a issue.\r
1199 @retval EFI_NOT_READY The memory is not set.\r
1200 @retval EFI_TIMEOUT The memory setting is time out.\r
1201 @retval EFI_SUCCESS The memory is correct set.\r
1202\r
1203**/\r
1204EFI_STATUS\r
1205AtaUdmStatusCheck (\r
1206 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1207 IN ATA_NONBLOCK_TASK *Task,\r
8536cc4b 1208 IN EFI_IDE_REGISTERS *IdeRegisters\r
490b5ea1 1209 )\r
1210{\r
8536cc4b 1211 UINT8 RegisterValue;\r
1212 UINT16 IoPortForBmis;\r
1213 EFI_STATUS Status;\r
490b5ea1 1214\r
1215 Task->RetryTimes--;\r
8536cc4b 1216\r
1217 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1218 if (EFI_ERROR (Status)) {\r
1219 return EFI_DEVICE_ERROR;\r
1220 }\r
1221\r
1222 IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);\r
1223 RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);\r
490b5ea1 1224\r
1225 if ((RegisterValue & BMIS_ERROR) != 0) {\r
1226 DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));\r
1227 return EFI_DEVICE_ERROR;\r
1228 }\r
1229\r
1230 if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
490b5ea1 1231 return EFI_SUCCESS;\r
1232 }\r
1233\r
ab82122d 1234 if (!Task->InfiniteWait && (Task->RetryTimes == 0)) {\r
490b5ea1 1235 return EFI_TIMEOUT;\r
1236 } else {\r
1237 //\r
1238 // The memory is not set.\r
1239 //\r
1240 return EFI_NOT_READY;\r
1241 }\r
1242}\r
a41b5272 1243\r
1244/**\r
1245 Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
1246\r
490b5ea1 1247 @param[in] Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data\r
1248 structure.\r
1249 @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
1250 @param[in] Read Flag used to determine the data transfer\r
1251 direction. Read equals 1, means data transferred\r
1252 from device to host;Read equals 0, means data\r
1253 transferred from host to device.\r
1254 @param[in] DataBuffer A pointer to the source buffer for the data.\r
1255 @param[in] DataLength The length of the data.\r
1256 @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
1257 @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
8536cc4b 1258 @param[in] Timeout The time to complete the command, uses 100ns as a unit.\r
490b5ea1 1259 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1260 used by non-blocking mode.\r
a41b5272 1261\r
1262 @retval EFI_SUCCESS the operation is successful.\r
1263 @retval EFI_OUT_OF_RESOURCES Build PRD table failed\r
1264 @retval EFI_UNSUPPORTED Unknown channel or operations command\r
1265 @retval EFI_DEVICE_ERROR Ata command execute failed\r
1266\r
1267**/\r
1268EFI_STATUS\r
1269EFIAPI\r
1270AtaUdmaInOut (\r
490b5ea1 1271 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
1272 IN EFI_IDE_REGISTERS *IdeRegisters,\r
1273 IN BOOLEAN Read,\r
1274 IN VOID *DataBuffer,\r
1275 IN UINT64 DataLength,\r
1276 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
1277 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
1278 IN UINT64 Timeout,\r
1279 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 1280 )\r
1281{\r
1282 EFI_STATUS Status;\r
1283 UINT16 IoPortForBmic;\r
1284 UINT16 IoPortForBmis;\r
1285 UINT16 IoPortForBmid;\r
1286\r
a41b5272 1287 UINTN PrdTableSize;\r
1288 EFI_PHYSICAL_ADDRESS PrdTableMapAddr;\r
1289 VOID *PrdTableMap;\r
51492422 1290 EFI_PHYSICAL_ADDRESS PrdTableBaseAddr;\r
2525e221 1291 EFI_ATA_DMA_PRD *TempPrdBaseAddr;\r
490b5ea1 1292 UINTN PrdTableNum;\r
a41b5272 1293\r
490b5ea1 1294 UINT8 RegisterValue;\r
a41b5272 1295 UINTN PageCount;\r
1296 UINTN ByteCount;\r
1297 UINTN ByteRemaining;\r
a41b5272 1298 UINT8 DeviceControl;\r
1299\r
1300 VOID *BufferMap;\r
1301 EFI_PHYSICAL_ADDRESS BufferMapAddress;\r
1302 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation;\r
1303\r
1304 UINT8 DeviceHead;\r
490b5ea1 1305 EFI_PCI_IO_PROTOCOL *PciIo;\r
1306 EFI_TPL OldTpl;\r
a41b5272 1307\r
51492422
FT
1308 UINTN AlignmentMask;\r
1309 UINTN RealPageCount;\r
1310 EFI_PHYSICAL_ADDRESS BaseAddr;\r
1311 EFI_PHYSICAL_ADDRESS BaseMapAddr;\r
490b5ea1 1312\r
1313 Status = EFI_SUCCESS;\r
490b5ea1 1314 PrdTableMap = NULL;\r
1315 BufferMap = NULL;\r
1316 PageCount = 0;\r
51492422
FT
1317 RealPageCount = 0;\r
1318 BaseAddr = 0;\r
490b5ea1 1319 PciIo = Instance->PciIo;\r
a41b5272 1320\r
1321 if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {\r
1322 return EFI_INVALID_PARAMETER;\r
1323 }\r
1324\r
490b5ea1 1325 //\r
1326 // Before starting the Blocking BlockIO operation, push to finish all non-blocking\r
1327 // BlockIO tasks.\r
1328 // Delay 1ms to simulate the blocking time out checking.\r
1329 //\r
1aff716a 1330 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
490b5ea1 1331 while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {\r
490b5ea1 1332 AsyncNonBlockingTransferRoutine (NULL, Instance);\r
490b5ea1 1333 //\r
1334 // Stall for 1 milliseconds.\r
1335 //\r
1336 MicroSecondDelay (1000);\r
1aff716a 1337 }\r
1338 gBS->RestoreTPL (OldTpl);\r
490b5ea1 1339\r
a41b5272 1340 //\r
1341 // The data buffer should be even alignment\r
1342 //\r
1343 if (((UINTN)DataBuffer & 0x1) != 0) {\r
1344 return EFI_INVALID_PARAMETER;\r
1345 }\r
1346\r
1347 //\r
490b5ea1 1348 // Set relevant IO Port address.\r
a41b5272 1349 //\r
490b5ea1 1350 IoPortForBmic = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET);\r
1351 IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);\r
1352 IoPortForBmid = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMID_OFFSET);\r
a41b5272 1353\r
1354 //\r
1aff716a 1355 // For Blocking mode, start the command.\r
490b5ea1 1356 // For non-blocking mode, when the command is not started, start it, otherwise\r
1357 // go to check the status.\r
1aff716a 1358 //\r
490b5ea1 1359 if (((Task != NULL) && (!Task->IsStart)) || (Task == NULL)) {\r
1360 //\r
1361 // Calculate the number of PRD entry.\r
1362 // Every entry in PRD table can specify a 64K memory region.\r
1363 //\r
1364 PrdTableNum = (UINTN)(RShiftU64(DataLength, 16) + 1);\r
a41b5272 1365\r
490b5ea1 1366 //\r
1367 // Make sure that the memory region of PRD table is not cross 64K boundary\r
1368 //\r
1369 PrdTableSize = PrdTableNum * sizeof (EFI_ATA_DMA_PRD);\r
1370 if (PrdTableSize > 0x10000) {\r
1371 return EFI_INVALID_PARAMETER;\r
1372 }\r
a41b5272 1373\r
490b5ea1 1374 //\r
1375 // Allocate buffer for PRD table initialization.\r
51492422
FT
1376 // Note Ide Bus Master spec said the descriptor table must be aligned on a 4 byte\r
1377 // boundary and the table cannot cross a 64K boundary in memory.\r
490b5ea1 1378 //\r
51492422
FT
1379 PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);\r
1380 RealPageCount = PageCount + EFI_SIZE_TO_PAGES (SIZE_64KB);\r
1381\r
1382 //\r
1383 // Make sure that PageCount plus EFI_SIZE_TO_PAGES (SIZE_64KB) does not overflow.\r
1384 //\r
1385 ASSERT (RealPageCount > PageCount);\r
1386\r
490b5ea1 1387 Status = PciIo->AllocateBuffer (\r
1388 PciIo,\r
1389 AllocateAnyPages,\r
1390 EfiBootServicesData,\r
51492422
FT
1391 RealPageCount,\r
1392 (VOID **)&BaseAddr,\r
490b5ea1 1393 0\r
1394 );\r
1395 if (EFI_ERROR (Status)) {\r
1396 return EFI_OUT_OF_RESOURCES;\r
1397 }\r
a41b5272 1398\r
51492422 1399 ByteCount = EFI_PAGES_TO_SIZE (RealPageCount);\r
490b5ea1 1400 Status = PciIo->Map (\r
1401 PciIo,\r
1402 EfiPciIoOperationBusMasterCommonBuffer,\r
51492422 1403 (VOID*)(UINTN)BaseAddr,\r
490b5ea1 1404 &ByteCount,\r
51492422 1405 &BaseMapAddr,\r
490b5ea1 1406 &PrdTableMap\r
1407 );\r
51492422 1408 if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (RealPageCount))) {\r
490b5ea1 1409 //\r
1410 // If the data length actually mapped is not equal to the requested amount,\r
1411 // it means the DMA operation may be broken into several discontinuous smaller chunks.\r
1412 // Can't handle this case.\r
1413 //\r
51492422 1414 PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
490b5ea1 1415 return EFI_OUT_OF_RESOURCES;\r
1416 }\r
a41b5272 1417\r
51492422
FT
1418 ZeroMem ((VOID *) ((UINTN) BaseAddr), ByteCount);\r
1419\r
1420 //\r
1421 // Calculate the 64K align address as PRD Table base address.\r
1422 //\r
1423 AlignmentMask = SIZE_64KB - 1;\r
1424 PrdTableBaseAddr = ((UINTN) BaseAddr + AlignmentMask) & ~AlignmentMask;\r
1425 PrdTableMapAddr = ((UINTN) BaseMapAddr + AlignmentMask) & ~AlignmentMask;\r
a41b5272 1426\r
490b5ea1 1427 //\r
1428 // Map the host address of DataBuffer to DMA master address.\r
1429 //\r
1430 if (Read) {\r
1431 PciIoOperation = EfiPciIoOperationBusMasterWrite;\r
1432 } else {\r
1433 PciIoOperation = EfiPciIoOperationBusMasterRead;\r
1434 }\r
a41b5272 1435\r
490b5ea1 1436 ByteCount = (UINTN)DataLength;\r
1437 Status = PciIo->Map (\r
1438 PciIo,\r
1439 PciIoOperation,\r
1440 DataBuffer,\r
1441 &ByteCount,\r
1442 &BufferMapAddress,\r
1443 &BufferMap\r
1444 );\r
1445 if (EFI_ERROR (Status) || (ByteCount != DataLength)) {\r
1446 PciIo->Unmap (PciIo, PrdTableMap);\r
51492422 1447 PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
490b5ea1 1448 return EFI_OUT_OF_RESOURCES;\r
1449 }\r
1450\r
1451 //\r
1452 // According to Ata spec, it requires the buffer address and size to be even.\r
1453 //\r
1454 ASSERT ((BufferMapAddress & 0x1) == 0);\r
1455 ASSERT ((ByteCount & 0x1) == 0);\r
1456\r
1457 //\r
1458 // Fill the PRD table with appropriate bus master address of data buffer and data length.\r
1459 //\r
2525e221 1460 ByteRemaining = ByteCount;\r
51492422 1461 TempPrdBaseAddr = (EFI_ATA_DMA_PRD*)(UINTN)PrdTableBaseAddr;\r
490b5ea1 1462 while (ByteRemaining != 0) {\r
1463 if (ByteRemaining <= 0x10000) {\r
2525e221 1464 TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
1465 TempPrdBaseAddr->ByteCount = (UINT16) ByteRemaining;\r
1466 TempPrdBaseAddr->EndOfTable = 0x8000;\r
490b5ea1 1467 break;\r
1468 }\r
a41b5272 1469\r
2525e221 1470 TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
1471 TempPrdBaseAddr->ByteCount = (UINT16) 0x0;\r
a41b5272 1472\r
490b5ea1 1473 ByteRemaining -= 0x10000;\r
1474 BufferMapAddress += 0x10000;\r
2525e221 1475 TempPrdBaseAddr++;\r
490b5ea1 1476 }\r
a41b5272 1477\r
490b5ea1 1478 //\r
1479 // Start to enable the DMA operation\r
1480 //\r
1481 DeviceHead = AtaCommandBlock->AtaDeviceHead;\r
a41b5272 1482\r
490b5ea1 1483 IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead));\r
a41b5272 1484\r
490b5ea1 1485 //\r
1486 // Enable interrupt to support UDMA\r
1487 //\r
1488 DeviceControl = 0;\r
1489 IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
a41b5272 1490\r
490b5ea1 1491 //\r
1492 // Read BMIS register and clear ERROR and INTR bit\r
1493 //\r
1494 RegisterValue = IdeReadPortB(PciIo, IoPortForBmis);\r
1495 RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
8536cc4b 1496 IdeWritePortB (PciIo, IoPortForBmis, RegisterValue);\r
a41b5272 1497\r
490b5ea1 1498 //\r
1499 // Set the base address to BMID register\r
1500 //\r
1501 IdeWritePortDW (PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr);\r
a41b5272 1502\r
490b5ea1 1503 //\r
1504 // Set BMIC register to identify the operation direction\r
1505 //\r
1506 RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);\r
1507 if (Read) {\r
1508 RegisterValue |= BMIC_NREAD;\r
1509 } else {\r
1510 RegisterValue &= ~((UINT8) BMIC_NREAD);\r
1511 }\r
1512 IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);\r
a41b5272 1513\r
1aff716a 1514 if (Task != NULL) {\r
1aff716a 1515 Task->Map = BufferMap;\r
1516 Task->TableMap = PrdTableMap;\r
51492422
FT
1517 Task->MapBaseAddress = (EFI_ATA_DMA_PRD*)(UINTN)BaseAddr;\r
1518 Task->PageCount = RealPageCount;\r
1aff716a 1519 Task->IsStart = TRUE;\r
1520 }\r
1521\r
490b5ea1 1522 //\r
1523 // Issue ATA command\r
1524 //\r
1525 Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
a41b5272 1526\r
490b5ea1 1527 if (EFI_ERROR (Status)) {\r
1528 Status = EFI_DEVICE_ERROR;\r
1529 goto Exit;\r
1530 }\r
a41b5272 1531\r
8536cc4b 1532 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1533 if (EFI_ERROR (Status)) {\r
1534 Status = EFI_DEVICE_ERROR;\r
1535 goto Exit;\r
1536 }\r
490b5ea1 1537 //\r
1538 // Set START bit of BMIC register\r
1539 //\r
1540 RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);\r
1541 RegisterValue |= BMIC_START;\r
1542 IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
a41b5272 1543\r
a41b5272 1544 }\r
1545\r
a41b5272 1546 //\r
1547 // Check the INTERRUPT and ERROR bit of BMIS\r
a41b5272 1548 //\r
490b5ea1 1549 if (Task != NULL) {\r
8536cc4b 1550 Status = AtaUdmStatusCheck (PciIo, Task, IdeRegisters);\r
490b5ea1 1551 } else {\r
ab82122d 1552 Status = AtaUdmStatusWait (PciIo, IdeRegisters, Timeout);\r
a41b5272 1553 }\r
1554\r
1555 //\r
490b5ea1 1556 // For blocking mode, clear registers and free buffers.\r
1557 // For non blocking mode, when the related registers have been set or time\r
1558 // out, or a error has been happened, it needs to clear the register and free\r
1559 // buffer.\r
a41b5272 1560 //\r
490b5ea1 1561 if ((Task == NULL) || Status != EFI_NOT_READY) {\r
1562 //\r
1563 // Read BMIS register and clear ERROR and INTR bit\r
1564 //\r
1565 RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);\r
1566 RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
1567 IdeWritePortB (PciIo, IoPortForBmis, RegisterValue);\r
a41b5272 1568\r
490b5ea1 1569 //\r
1570 // Read Status Register of IDE device to clear interrupt\r
1571 //\r
1572 RegisterValue = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus);\r
a41b5272 1573\r
490b5ea1 1574 //\r
1575 // Clear START bit of BMIC register\r
1576 //\r
1577 RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);\r
1578 RegisterValue &= ~((UINT8) BMIC_START);\r
1579 IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);\r
a41b5272 1580\r
490b5ea1 1581 //\r
1582 // Disable interrupt of Select device\r
1583 //\r
1584 DeviceControl = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
1585 DeviceControl |= ATA_CTLREG_IEN_L;\r
1586 IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
1587 //\r
1588 // Stall for 10 milliseconds.\r
1589 //\r
1590 MicroSecondDelay (10000);\r
1591\r
1592 }\r
a41b5272 1593\r
1594Exit:\r
1595 //\r
1596 // Free all allocated resource\r
1597 //\r
490b5ea1 1598 if ((Task == NULL) || Status != EFI_NOT_READY) {\r
1599 if (Task != NULL) {\r
1600 PciIo->Unmap (PciIo, Task->TableMap);\r
1601 PciIo->FreeBuffer (PciIo, Task->PageCount, Task->MapBaseAddress);\r
1602 PciIo->Unmap (PciIo, Task->Map);\r
1603 } else {\r
1604 PciIo->Unmap (PciIo, PrdTableMap);\r
51492422 1605 PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
490b5ea1 1606 PciIo->Unmap (PciIo, BufferMap);\r
1607 }\r
a41b5272 1608\r
490b5ea1 1609 //\r
1610 // Dump All Ide registers to ATA_STATUS_BLOCK\r
1611 //\r
1612 DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
1613 }\r
1aff716a 1614\r
a41b5272 1615 return Status;\r
1616}\r
1617\r
1618/**\r
1619 This function reads the pending data in the device.\r
1620\r
1621 @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
1622 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
1623\r
1624 @retval EFI_SUCCESS Successfully read.\r
1625 @retval EFI_NOT_READY The BSY is set avoiding reading.\r
1626\r
1627**/\r
1628EFI_STATUS\r
1629EFIAPI\r
1630AtaPacketReadPendingData (\r
1631 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1632 IN EFI_IDE_REGISTERS *IdeRegisters\r
1633 )\r
1634{\r
1635 UINT8 AltRegister;\r
1636 UINT16 TempWordBuffer;\r
1637\r
1638 AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
1639 if ((AltRegister & ATA_STSREG_BSY) == ATA_STSREG_BSY) {\r
1640 return EFI_NOT_READY;\r
1641 }\r
1642\r
1643 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
1644 TempWordBuffer = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
1645 while ((TempWordBuffer & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
1646 IdeReadPortWMultiple (\r
1647 PciIo,\r
1aff716a 1648 IdeRegisters->Data,\r
1649 1,\r
a41b5272 1650 &TempWordBuffer\r
1651 );\r
1652 TempWordBuffer = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
1653 }\r
1654 }\r
1655 return EFI_SUCCESS;\r
1656}\r
1657\r
1658/**\r
1aff716a 1659 This function is called by AtaPacketCommandExecute().\r
a41b5272 1660 It is used to transfer data between host and device. The data direction is specified\r
1661 by the fourth parameter.\r
1662\r
1663 @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
1664 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
1665 @param Buffer Buffer contained data transferred between host and device.\r
1666 @param ByteCount Data size in byte unit of the buffer.\r
1667 @param Read Flag used to determine the data transfer direction.\r
1668 Read equals 1, means data transferred from device to host;\r
1669 Read equals 0, means data transferred from host to device.\r
8536cc4b 1670 @param Timeout Timeout value for wait DRQ ready before each data stream's transfer\r
1671 , uses 100ns as a unit.\r
a41b5272 1672\r
1673 @retval EFI_SUCCESS data is transferred successfully.\r
1674 @retval EFI_DEVICE_ERROR the device failed to transfer data.\r
1675**/\r
1676EFI_STATUS\r
1677EFIAPI\r
1678AtaPacketReadWrite (\r
1679 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1680 IN EFI_IDE_REGISTERS *IdeRegisters,\r
1681 IN OUT VOID *Buffer,\r
f6a683e0 1682 IN OUT UINT32 *ByteCount,\r
a41b5272 1683 IN BOOLEAN Read,\r
1684 IN UINT64 Timeout\r
1685 )\r
1686{\r
1687 UINT32 RequiredWordCount;\r
1688 UINT32 ActualWordCount;\r
1689 UINT32 WordCount;\r
1690 EFI_STATUS Status;\r
1691 UINT16 *PtrBuffer;\r
1692\r
f6a683e0
PB
1693 PtrBuffer = Buffer;\r
1694 RequiredWordCount = *ByteCount >> 1;\r
1695\r
a41b5272 1696 //\r
1697 // No data transfer is premitted.\r
1698 //\r
f6a683e0 1699 if (RequiredWordCount == 0) {\r
a41b5272 1700 return EFI_SUCCESS;\r
1701 }\r
1aff716a 1702\r
a41b5272 1703 //\r
f6a683e0 1704 // ActualWordCount means the word count of data really transferred.\r
a41b5272 1705 //\r
1706 ActualWordCount = 0;\r
1707\r
1708 while (ActualWordCount < RequiredWordCount) {\r
1709 //\r
1710 // before each data transfer stream, the host should poll DRQ bit ready,\r
1711 // to see whether indicates device is ready to transfer data.\r
1712 //\r
1713 Status = DRQReady2 (PciIo, IdeRegisters, Timeout);\r
1714 if (EFI_ERROR (Status)) {\r
f6a683e0
PB
1715 if (Status == EFI_NOT_READY) {\r
1716 //\r
1717 // Device provided less data than we intended to read, or wanted less\r
1718 // data than we intended to write, but it may still be successful.\r
1719 //\r
1720 break;\r
1721 } else {\r
1722 return Status;\r
1723 }\r
a41b5272 1724 }\r
1725\r
1726 //\r
1727 // get current data transfer size from Cylinder Registers.\r
1728 //\r
1729 WordCount = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb) << 8;\r
1730 WordCount = WordCount | IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
1731 WordCount = WordCount & 0xffff;\r
1732 WordCount /= 2;\r
1733\r
1734 WordCount = MIN (WordCount, (RequiredWordCount - ActualWordCount));\r
1735\r
1736 if (Read) {\r
1737 IdeReadPortWMultiple (\r
1738 PciIo,\r
1739 IdeRegisters->Data,\r
1740 WordCount,\r
1741 PtrBuffer\r
1742 );\r
1743 } else {\r
1744 IdeWritePortWMultiple (\r
1745 PciIo,\r
1746 IdeRegisters->Data,\r
1747 WordCount,\r
1748 PtrBuffer\r
1749 );\r
1750 }\r
1751\r
1752 //\r
1753 // read status register to check whether error happens.\r
1754 //\r
1755 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1756 if (EFI_ERROR (Status)) {\r
1757 return EFI_DEVICE_ERROR;\r
1758 }\r
1759\r
1760 PtrBuffer += WordCount;\r
1761 ActualWordCount += WordCount;\r
1762 }\r
1aff716a 1763\r
a41b5272 1764 if (Read) {\r
1765 //\r
1766 // In the case where the drive wants to send more data than we need to read,\r
1767 // the DRQ bit will be set and cause delays from DRQClear2().\r
1768 // We need to read data from the drive until it clears DRQ so we can move on.\r
1769 //\r
1770 AtaPacketReadPendingData (PciIo, IdeRegisters);\r
1771 }\r
1772\r
1773 //\r
1774 // read status register to check whether error happens.\r
1775 //\r
1776 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1777 if (EFI_ERROR (Status)) {\r
1778 return EFI_DEVICE_ERROR;\r
1779 }\r
1780\r
1781 //\r
1782 // After data transfer is completed, normally, DRQ bit should clear.\r
1783 //\r
8536cc4b 1784 Status = DRQClear (PciIo, IdeRegisters, Timeout);\r
a41b5272 1785 if (EFI_ERROR (Status)) {\r
1786 return EFI_DEVICE_ERROR;\r
1787 }\r
1aff716a 1788\r
f6a683e0 1789 *ByteCount = ActualWordCount << 1;\r
a41b5272 1790 return Status;\r
1791}\r
1792\r
a41b5272 1793/**\r
1aff716a 1794 This function is used to send out ATAPI commands conforms to the Packet Command\r
a41b5272 1795 with PIO Data In Protocol.\r
1796\r
1797 @param[in] PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
1798 @param[in] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to\r
1799 store the IDE i/o port registers' base addresses\r
1800 @param[in] Channel The channel number of device.\r
1801 @param[in] Device The device number of device.\r
1802 @param[in] Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.\r
1803\r
1804 @retval EFI_SUCCESS send out the ATAPI packet command successfully\r
1805 and device sends data successfully.\r
1806 @retval EFI_DEVICE_ERROR the device failed to send data.\r
1807\r
1808**/\r
1809EFI_STATUS\r
1810EFIAPI\r
1811AtaPacketCommandExecute (\r
1812 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1813 IN EFI_IDE_REGISTERS *IdeRegisters,\r
1814 IN UINT8 Channel,\r
1815 IN UINT8 Device,\r
1816 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
1817 )\r
1818{\r
a41b5272 1819 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1820 EFI_STATUS Status;\r
1821 UINT8 Count;\r
1822 UINT8 PacketCommand[12];\r
1823\r
1824 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1825\r
1826 //\r
1827 // Fill ATAPI Command Packet according to CDB.\r
1828 // For Atapi cmd, its length should be less than or equal to 12 bytes.\r
1829 //\r
1830 if (Packet->CdbLength > 12) {\r
1831 return EFI_INVALID_PARAMETER;\r
1832 }\r
1833\r
1834 ZeroMem (PacketCommand, 12);\r
1835 CopyMem (PacketCommand, Packet->Cdb, Packet->CdbLength);\r
1836\r
1837 //\r
1838 // No OVL; No DMA\r
1839 //\r
1840 AtaCommandBlock.AtaFeatures = 0x00;\r
1841 //\r
1842 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
1843 // determine how many data should be transferred.\r
1844 //\r
1845 AtaCommandBlock.AtaCylinderLow = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
1846 AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);\r
aca84419 1847 AtaCommandBlock.AtaDeviceHead = (UINT8) (Device << 0x4);\r
a41b5272 1848 AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;\r
1849\r
1850 IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | (Device << 0x4)));\r
1851 //\r
1852 // Disable interrupt\r
1853 //\r
1854 IdeWritePortB (PciIo, IdeRegisters->AltOrDev, ATA_DEFAULT_CTL);\r
1855\r
1856 //\r
1857 // Issue ATA PACKET command firstly\r
1858 //\r
1859 Status = AtaIssueCommand (PciIo, IdeRegisters, &AtaCommandBlock, Packet->Timeout);\r
1860 if (EFI_ERROR (Status)) {\r
1861 return Status;\r
1862 }\r
1863\r
1864 Status = DRQReady (PciIo, IdeRegisters, Packet->Timeout);\r
1865 if (EFI_ERROR (Status)) {\r
1866 return Status;\r
1867 }\r
1868\r
1869 //\r
1870 // Send out ATAPI command packet\r
1871 //\r
1872 for (Count = 0; Count < 6; Count++) {\r
1aff716a 1873 IdeWritePortW (PciIo, IdeRegisters->Data, *((UINT16*)PacketCommand + Count));\r
a41b5272 1874 //\r
1875 // Stall for 10 microseconds.\r
1876 //\r
1877 MicroSecondDelay (10);\r
1878 }\r
1879\r
1880 //\r
1881 // Read/Write the data of ATAPI Command\r
1882 //\r
1883 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
73a9e822
TF
1884 Status = AtaPacketReadWrite (\r
1885 PciIo,\r
1886 IdeRegisters,\r
1887 Packet->InDataBuffer,\r
f6a683e0 1888 &Packet->InTransferLength,\r
73a9e822
TF
1889 TRUE,\r
1890 Packet->Timeout\r
1891 );\r
a41b5272 1892 } else {\r
73a9e822
TF
1893 Status = AtaPacketReadWrite (\r
1894 PciIo,\r
1895 IdeRegisters,\r
1896 Packet->OutDataBuffer,\r
f6a683e0 1897 &Packet->OutTransferLength,\r
73a9e822
TF
1898 FALSE,\r
1899 Packet->Timeout\r
1900 );\r
a41b5272 1901 }\r
1902\r
73a9e822 1903 return Status;\r
a41b5272 1904}\r
1905\r
1906\r
1907/**\r
1908 Set the calculated Best transfer mode to a detected device.\r
1909\r
1910 @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
1911 @param Channel The channel number of device.\r
1912 @param Device The device number of device.\r
1913 @param TransferMode A pointer to EFI_ATA_TRANSFER_MODE data structure.\r
1914 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1915\r
1916 @retval EFI_SUCCESS Set transfer mode successfully.\r
1917 @retval EFI_DEVICE_ERROR Set transfer mode failed.\r
1918 @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
1919\r
1920**/\r
1921EFI_STATUS\r
1922EFIAPI\r
1923SetDeviceTransferMode (\r
1924 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
1925 IN UINT8 Channel,\r
1926 IN UINT8 Device,\r
1927 IN EFI_ATA_TRANSFER_MODE *TransferMode,\r
1928 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
1929 )\r
1930{\r
1931 EFI_STATUS Status;\r
1932 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1933\r
1934 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1935\r
1936 AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;\r
1937 AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
1938 AtaCommandBlock.AtaFeatures = 0x03;\r
1939 AtaCommandBlock.AtaSectorCount = *((UINT8 *)TransferMode);\r
1940\r
1941 //\r
1942 // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
1943 //\r
1944 Status = AtaNonDataCommandIn (\r
1945 Instance->PciIo,\r
1946 &Instance->IdeRegisters[Channel],\r
1947 &AtaCommandBlock,\r
1948 AtaStatusBlock,\r
490b5ea1 1949 ATA_ATAPI_TIMEOUT,\r
1950 NULL\r
a41b5272 1951 );\r
1952\r
1953 return Status;\r
1954}\r
1955\r
1956/**\r
1957 Set drive parameters for devices not support PACKETS command.\r
1958\r
1959 @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
1960 @param Channel The channel number of device.\r
1961 @param Device The device number of device.\r
1962 @param DriveParameters A pointer to EFI_ATA_DRIVE_PARMS data structure.\r
1963 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1964\r
1965 @retval EFI_SUCCESS Set drive parameter successfully.\r
1966 @retval EFI_DEVICE_ERROR Set drive parameter failed.\r
1967 @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
1968\r
1969**/\r
1970EFI_STATUS\r
1971EFIAPI\r
1972SetDriveParameters (\r
1973 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
1974 IN UINT8 Channel,\r
1975 IN UINT8 Device,\r
1976 IN EFI_ATA_DRIVE_PARMS *DriveParameters,\r
1977 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
a41b5272 1978 )\r
1979{\r
1980 EFI_STATUS Status;\r
1981 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1982\r
1983 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1aff716a 1984\r
a41b5272 1985 AtaCommandBlock.AtaCommand = ATA_CMD_INIT_DRIVE_PARAM;\r
1986 AtaCommandBlock.AtaSectorCount = DriveParameters->Sector;\r
1987 AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) + DriveParameters->Heads);\r
1988\r
1989 //\r
1990 // Send Init drive parameters\r
1991 //\r
1992 Status = AtaNonDataCommandIn (\r
1993 Instance->PciIo,\r
1994 &Instance->IdeRegisters[Channel],\r
1995 &AtaCommandBlock,\r
1996 AtaStatusBlock,\r
1aff716a 1997 ATA_ATAPI_TIMEOUT,\r
490b5ea1 1998 NULL\r
a41b5272 1999 );\r
2000\r
2001 //\r
2002 // Send Set Multiple parameters\r
2003 //\r
2004 AtaCommandBlock.AtaCommand = ATA_CMD_SET_MULTIPLE_MODE;\r
2005 AtaCommandBlock.AtaSectorCount = DriveParameters->MultipleSector;\r
2006 AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
2007\r
2008 Status = AtaNonDataCommandIn (\r
2009 Instance->PciIo,\r
2010 &Instance->IdeRegisters[Channel],\r
2011 &AtaCommandBlock,\r
2012 AtaStatusBlock,\r
1aff716a 2013 ATA_ATAPI_TIMEOUT,\r
490b5ea1 2014 NULL\r
a41b5272 2015 );\r
2016\r
2017 return Status;\r
2018}\r
2019\r
12873d57 2020/**\r
2021 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
2022\r
2023 @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
2024 @param Channel The channel number of device.\r
2025 @param Device The device number of device.\r
2026 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
2027\r
2028 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.\r
2029 @retval Others Fail to get return status data.\r
2030\r
2031**/\r
2032EFI_STATUS\r
2033EFIAPI\r
2034IdeAtaSmartReturnStatusCheck (\r
2035 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
2036 IN UINT8 Channel,\r
2037 IN UINT8 Device,\r
2038 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
2039 )\r
2040{\r
2041 EFI_STATUS Status;\r
2042 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2043 UINT8 LBAMid;\r
2044 UINT8 LBAHigh;\r
2045\r
2046 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2047\r
2048 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
2049 AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;\r
2050 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
2051 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
2052 AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);\r
2053\r
2054 //\r
2055 // Send S.M.A.R.T Read Return Status command to device\r
2056 //\r
2057 Status = AtaNonDataCommandIn (\r
2058 Instance->PciIo,\r
2059 &Instance->IdeRegisters[Channel],\r
2060 &AtaCommandBlock,\r
2061 AtaStatusBlock,\r
490b5ea1 2062 ATA_ATAPI_TIMEOUT,\r
2063 NULL\r
12873d57 2064 );\r
2065\r
2066 if (EFI_ERROR (Status)) {\r
cffd2171
EL
2067 REPORT_STATUS_CODE (\r
2068 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
2069 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
2070 );\r
12873d57 2071 return EFI_DEVICE_ERROR;\r
2072 }\r
2073\r
cffd2171
EL
2074 REPORT_STATUS_CODE (\r
2075 EFI_PROGRESS_CODE,\r
2076 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
2077 );\r
2078\r
12873d57 2079 LBAMid = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderLsb);\r
2080 LBAHigh = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderMsb);\r
2081\r
2082 if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
2083 //\r
2084 // The threshold exceeded condition is not detected by the device\r
2085 //\r
2086 DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
cffd2171
EL
2087 REPORT_STATUS_CODE (\r
2088 EFI_PROGRESS_CODE,\r
2089 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
2090 );\r
12873d57 2091 } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
2092 //\r
2093 // The threshold exceeded condition is detected by the device\r
2094 //\r
2095 DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
cffd2171
EL
2096 REPORT_STATUS_CODE (\r
2097 EFI_PROGRESS_CODE,\r
2098 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
2099 );\r
12873d57 2100 }\r
2101\r
2102 return EFI_SUCCESS;\r
2103}\r
2104\r
2105/**\r
2106 Enable SMART command of the disk if supported.\r
2107\r
2108 @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
2109 @param Channel The channel number of device.\r
2110 @param Device The device number of device.\r
2111 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
2112 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
2113\r
2114**/\r
2115VOID\r
2116EFIAPI\r
2117IdeAtaSmartSupport (\r
2118 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
2119 IN UINT8 Channel,\r
2120 IN UINT8 Device,\r
2121 IN EFI_IDENTIFY_DATA *IdentifyData,\r
2122 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
2123 )\r
2124{\r
2125 EFI_STATUS Status;\r
2126 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2127\r
2128 //\r
2129 // Detect if the device supports S.M.A.R.T.\r
2130 //\r
2131 if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
2132 //\r
2133 // S.M.A.R.T is not supported by the device\r
2134 //\r
1aff716a 2135 DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at [%a] channel [%a] device!\n",\r
12873d57 2136 (Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));\r
cffd2171
EL
2137 REPORT_STATUS_CODE (\r
2138 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
2139 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
2140 );\r
12873d57 2141 } else {\r
2142 //\r
2143 // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
2144 //\r
2145 if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
2146\r
cffd2171
EL
2147 REPORT_STATUS_CODE (\r
2148 EFI_PROGRESS_CODE,\r
2149 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)\r
2150 );\r
2151\r
12873d57 2152 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2153\r
2154 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
2155 AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;\r
2156 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
2157 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
2158 AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);\r
2159\r
2160 //\r
2161 // Send S.M.A.R.T Enable command to device\r
2162 //\r
2163 Status = AtaNonDataCommandIn (\r
2164 Instance->PciIo,\r
2165 &Instance->IdeRegisters[Channel],\r
2166 &AtaCommandBlock,\r
2167 AtaStatusBlock,\r
490b5ea1 2168 ATA_ATAPI_TIMEOUT,\r
2169 NULL\r
12873d57 2170 );\r
2171\r
2172 if (!EFI_ERROR (Status)) {\r
2173 //\r
2174 // Send S.M.A.R.T AutoSave command to device\r
2175 //\r
2176 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2177\r
2178 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
2179 AtaCommandBlock.AtaFeatures = 0xD2;\r
2180 AtaCommandBlock.AtaSectorCount = 0xF1;\r
2181 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
2182 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
2183 AtaCommandBlock.AtaDeviceHead = (UINT8) ((Device << 0x4) | 0xe0);\r
2184\r
2185 Status = AtaNonDataCommandIn (\r
2186 Instance->PciIo,\r
2187 &Instance->IdeRegisters[Channel],\r
2188 &AtaCommandBlock,\r
2189 AtaStatusBlock,\r
490b5ea1 2190 ATA_ATAPI_TIMEOUT,\r
2191 NULL\r
12873d57 2192 );\r
2193 if (!EFI_ERROR (Status)) {\r
2194 Status = IdeAtaSmartReturnStatusCheck (\r
2195 Instance,\r
2196 Channel,\r
2197 Device,\r
2198 AtaStatusBlock\r
2199 );\r
2200 }\r
2201 }\r
2202 }\r
2203\r
1aff716a 2204 DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at [%a] channel [%a] device!\n",\r
12873d57 2205 (Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));\r
2206\r
2207 }\r
2208\r
2209 return ;\r
2210}\r
2211\r
490b5ea1 2212\r
a41b5272 2213/**\r
2214 Sends out an ATA Identify Command to the specified device.\r
2215\r
2216 This function is called by DiscoverIdeDevice() during its device\r
2217 identification. It sends out the ATA Identify Command to the\r
2218 specified device. Only ATA device responses to this command. If\r
2219 the command succeeds, it returns the Identify data structure which\r
2220 contains information about the device. This function extracts the\r
2221 information it needs to fill the IDE_BLK_IO_DEV data structure,\r
2222 including device type, media block size, media capacity, and etc.\r
2223\r
2224 @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
2225 @param Channel The channel number of device.\r
2226 @param Device The device number of device.\r
2227 @param Buffer A pointer to data buffer which is used to contain IDENTIFY data.\r
2228 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
2229\r
2230 @retval EFI_SUCCESS Identify ATA device successfully.\r
2231 @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.\r
2232 @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
490b5ea1 2233\r
a41b5272 2234**/\r
2235EFI_STATUS\r
2236EFIAPI\r
2237AtaIdentify (\r
2238 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
2239 IN UINT8 Channel,\r
2240 IN UINT8 Device,\r
2241 IN OUT EFI_IDENTIFY_DATA *Buffer,\r
2242 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
2243 )\r
2244{\r
2245 EFI_STATUS Status;\r
490b5ea1 2246 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
a41b5272 2247\r
2248 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
490b5ea1 2249\r
a41b5272 2250 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
2251 AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
2252\r
2253 Status = AtaPioDataInOut (\r
2254 Instance->PciIo,\r
2255 &Instance->IdeRegisters[Channel],\r
2256 Buffer,\r
2257 sizeof (EFI_IDENTIFY_DATA),\r
2258 TRUE,\r
2259 &AtaCommandBlock,\r
2260 AtaStatusBlock,\r
490b5ea1 2261 ATA_ATAPI_TIMEOUT,\r
2262 NULL\r
a41b5272 2263 );\r
2264\r
2265 return Status;\r
2266}\r
2267\r
2268/**\r
2269 This function is called by DiscoverIdeDevice() during its device\r
2270 identification.\r
2271 Its main purpose is to get enough information for the device media\r
2272 to fill in the Media data structure of the Block I/O Protocol interface.\r
2273\r
2274 There are 5 steps to reach such objective:\r
1aff716a 2275 1. Sends out the ATAPI Identify Command to the specified device.\r
a41b5272 2276 Only ATAPI device responses to this command. If the command succeeds,\r
1aff716a 2277 it returns the Identify data structure which filled with information\r
2278 about the device. Since the ATAPI device contains removable media,\r
a41b5272 2279 the only meaningful information is the device module name.\r
2280 2. Sends out ATAPI Inquiry Packet Command to the specified device.\r
2281 This command will return inquiry data of the device, which contains\r
2282 the device type information.\r
2283 3. Allocate sense data space for future use. We don't detect the media\r
1aff716a 2284 presence here to improvement boot performance, especially when CD\r
a41b5272 2285 media is present. The media detection will be performed just before\r
2286 each BLK_IO read/write\r
1aff716a 2287\r
a41b5272 2288 @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
2289 @param Channel The channel number of device.\r
2290 @param Device The device number of device.\r
2291 @param Buffer A pointer to data buffer which is used to contain IDENTIFY data.\r
2292 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
2293\r
2294 @retval EFI_SUCCESS Identify ATAPI device successfully.\r
2295 @retval EFI_DEVICE_ERROR ATA Identify Packet Device Command failed or device type\r
2296 is not supported by this IDE driver.\r
2297 @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
2298\r
2299**/\r
2300EFI_STATUS\r
2301EFIAPI\r
2302AtaIdentifyPacket (\r
2303 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
2304 IN UINT8 Channel,\r
2305 IN UINT8 Device,\r
2306 IN OUT EFI_IDENTIFY_DATA *Buffer,\r
2307 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
2308 )\r
2309{\r
2310 EFI_STATUS Status;\r
2311 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2312\r
2313 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1aff716a 2314\r
a41b5272 2315 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DEVICE;\r
2316 AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
2317\r
2318 //\r
2319 // Send ATAPI Identify Command to get IDENTIFY data.\r
2320 //\r
2321 Status = AtaPioDataInOut (\r
2322 Instance->PciIo,\r
2323 &Instance->IdeRegisters[Channel],\r
2324 (VOID *) Buffer,\r
2325 sizeof (EFI_IDENTIFY_DATA),\r
2326 TRUE,\r
2327 &AtaCommandBlock,\r
2328 AtaStatusBlock,\r
490b5ea1 2329 ATA_ATAPI_TIMEOUT,\r
2330 NULL\r
a41b5272 2331 );\r
2332\r
2333 return Status;\r
2334}\r
2335\r
2336\r
2337/**\r
2338 This function is used for detect whether the IDE device exists in the\r
2339 specified Channel as the specified Device Number.\r
2340\r
2341 There is two IDE channels: one is Primary Channel, the other is\r
2342 Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
2343 Different channel has different register group.\r
2344\r
2345 On each IDE channel, at most two IDE devices attach,\r
2346 one is called Device 0 (Master device), the other is called Device 1\r
2347 (Slave device). The devices on the same channel co-use the same register\r
2348 group, so before sending out a command for a specified device via command\r
2349 register, it is a must to select the current device to accept the command\r
2350 by set the device number in the Head/Device Register.\r
2351\r
2352 @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
2353 @param IdeChannel The channel number of device.\r
2354\r
2355 @retval EFI_SUCCESS successfully detects device.\r
2356 @retval other any failure during detection process will return this value.\r
2357\r
2358**/\r
2359EFI_STATUS\r
2360EFIAPI\r
2361DetectAndConfigIdeDevice (\r
2362 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
2363 IN UINT8 IdeChannel\r
2364 )\r
2365{\r
2366 EFI_STATUS Status;\r
2367 UINT8 SectorCountReg;\r
2368 UINT8 LBALowReg;\r
2369 UINT8 LBAMidReg;\r
2370 UINT8 LBAHighReg;\r
2371 EFI_ATA_DEVICE_TYPE DeviceType;\r
aca84419 2372 UINT8 IdeDevice;\r
a41b5272 2373 EFI_IDE_REGISTERS *IdeRegisters;\r
2374 EFI_IDENTIFY_DATA Buffer;\r
2375\r
2376 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2377 EFI_PCI_IO_PROTOCOL *PciIo;\r
2378\r
2379 EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
2380 EFI_ATA_TRANSFER_MODE TransferMode;\r
2381 EFI_ATA_DRIVE_PARMS DriveParameters;\r
2382\r
2383 IdeRegisters = &Instance->IdeRegisters[IdeChannel];\r
2384 IdeInit = Instance->IdeControllerInit;\r
2385 PciIo = Instance->PciIo;\r
2386\r
490b5ea1 2387 for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {\r
2dc5090d
RJ
2388 //\r
2389 // Select Master or Slave device to get the return signature for ATA DEVICE DIAGNOSTIC cmd.\r
2390 //\r
2391 IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)((IdeDevice << 4) | 0xe0));\r
2392\r
a41b5272 2393 //\r
2394 // Send ATA Device Execut Diagnostic command.\r
2395 // This command should work no matter DRDY is ready or not\r
2396 //\r
2397 IdeWritePortB (PciIo, IdeRegisters->CmdOrStatus, ATA_CMD_EXEC_DRIVE_DIAG);\r
1aff716a 2398\r
a41b5272 2399 Status = WaitForBSYClear (PciIo, IdeRegisters, 350000000);\r
2400 if (EFI_ERROR (Status)) {\r
2401 DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
2402 continue;\r
2403 }\r
2404\r
2405 //\r
2406 // Select Master or Slave device to get the return signature for ATA DEVICE DIAGNOSTIC cmd.\r
2407 //\r
2408 IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)((IdeDevice << 4) | 0xe0));\r
2409 //\r
2410 // Stall for 1 milliseconds.\r
2411 //\r
2412 MicroSecondDelay (1000);\r
2413\r
2414 SectorCountReg = IdeReadPortB (PciIo, IdeRegisters->SectorCount);\r
2415 LBALowReg = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);\r
2416 LBAMidReg = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
2417 LBAHighReg = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);\r
2418\r
2419 //\r
2420 // Refer to ATA/ATAPI 4 Spec, section 9.1\r
2421 //\r
2422 if ((SectorCountReg == 0x1) && (LBALowReg == 0x1) && (LBAMidReg == 0x0) && (LBAHighReg == 0x0)) {\r
2423 DeviceType = EfiIdeHarddisk;\r
2424 } else if ((LBAMidReg == 0x14) && (LBAHighReg == 0xeb)) {\r
2425 DeviceType = EfiIdeCdrom;\r
2426 } else {\r
2427 continue;\r
2428 }\r
2429\r
2430 //\r
2431 // Send IDENTIFY cmd to the device to test if it is really attached.\r
2432 //\r
2433 if (DeviceType == EfiIdeHarddisk) {\r
2434 Status = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
2435 //\r
2436 // if identifying ata device is failure, then try to send identify packet cmd.\r
2437 //\r
2438 if (EFI_ERROR (Status)) {\r
3d0a2385 2439 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
2440\r
a41b5272 2441 DeviceType = EfiIdeCdrom;\r
2442 Status = AtaIdentifyPacket (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
2443 }\r
2444 } else {\r
2445 Status = AtaIdentifyPacket (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
2446 //\r
2447 // if identifying atapi device is failure, then try to send identify cmd.\r
2448 //\r
2449 if (EFI_ERROR (Status)) {\r
2450 DeviceType = EfiIdeHarddisk;\r
2451 Status = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
490b5ea1 2452 }\r
a41b5272 2453 }\r
2454\r
2455 if (EFI_ERROR (Status)) {\r
2456 //\r
2457 // No device is found at this port\r
2458 //\r
2459 continue;\r
490b5ea1 2460 }\r
2461\r
1aff716a 2462 DEBUG ((EFI_D_INFO, "[%a] channel [%a] [%a] device\n",\r
a41b5272 2463 (IdeChannel == 1) ? "secondary" : "primary ", (IdeDevice == 1) ? "slave " : "master",\r
2464 DeviceType == EfiIdeCdrom ? "cdrom " : "harddisk"));\r
12873d57 2465 //\r
2466 // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
2467 //\r
fc80ee69 2468 if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {\r
12873d57 2469 IdeAtaSmartSupport (\r
2470 Instance,\r
2471 IdeChannel,\r
2472 IdeDevice,\r
2473 &Buffer,\r
2474 NULL\r
2475 );\r
2476 }\r
2477\r
a41b5272 2478 //\r
2479 // Submit identify data to IDE controller init driver\r
2480 //\r
2481 IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &Buffer);\r
2482\r
2483 //\r
2484 // Now start to config ide device parameter and transfer mode.\r
2485 //\r
2486 Status = IdeInit->CalculateMode (\r
2487 IdeInit,\r
2488 IdeChannel,\r
2489 IdeDevice,\r
2490 &SupportedModes\r
2491 );\r
2492 if (EFI_ERROR (Status)) {\r
2493 DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
2494 continue;\r
2495 }\r
2496\r
2497 //\r
2498 // Set best supported PIO mode on this IDE device\r
2499 //\r
2500 if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
2501 TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
2502 } else {\r
2503 TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
2504 }\r
2505\r
2506 TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
2507\r
2508 if (SupportedModes->ExtModeCount == 0){\r
2509 Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
2510\r
2511 if (EFI_ERROR (Status)) {\r
2512 DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
2513 continue;\r
2514 }\r
2515 }\r
490b5ea1 2516\r
a41b5272 2517 //\r
2518 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
2519 // be set together. Only one DMA mode can be set to a device. If setting\r
2520 // DMA mode operation fails, we can continue moving on because we only use\r
2521 // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
2522 //\r
2523 if (SupportedModes->UdmaMode.Valid) {\r
2524 TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
2525 TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
2526 Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
490b5ea1 2527\r
a41b5272 2528 if (EFI_ERROR (Status)) {\r
2529 DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
2530 continue;\r
2531 }\r
2532 } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
2533 TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
2534 TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;\r
2535 Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
490b5ea1 2536\r
a41b5272 2537 if (EFI_ERROR (Status)) {\r
2538 DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
2539 continue;\r
2540 }\r
2541 }\r
490b5ea1 2542\r
a41b5272 2543 //\r
2544 // Set Parameters for the device:\r
2545 // 1) Init\r
2546 // 2) Establish the block count for READ/WRITE MULTIPLE (EXT) command\r
2547 //\r
2548 if (DeviceType == EfiIdeHarddisk) {\r
2549 //\r
2550 // Init driver parameters\r
2551 //\r
2552 DriveParameters.Sector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->sectors_per_track;\r
aca84419 2553 DriveParameters.Heads = (UINT8) (((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->heads - 1);\r
a41b5272 2554 DriveParameters.MultipleSector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->multi_sector_cmd_max_sct_cnt;\r
490b5ea1 2555\r
a41b5272 2556 Status = SetDriveParameters (Instance, IdeChannel, IdeDevice, &DriveParameters, NULL);\r
2557 }\r
490b5ea1 2558\r
a41b5272 2559 //\r
2560 // Set IDE controller Timing Blocks in the PCI Configuration Space\r
2561 //\r
2562 IdeInit->SetTiming (IdeInit, IdeChannel, IdeDevice, SupportedModes);\r
2563\r
2564 //\r
2565 // IDE controller and IDE device timing is configured successfully.\r
2566 // Now insert the device into device list.\r
2567 //\r
2568 Status = CreateNewDeviceInfo (Instance, IdeChannel, IdeDevice, DeviceType, &Buffer);\r
2569 if (EFI_ERROR (Status)) {\r
2570 continue;\r
2571 }\r
3d0a2385 2572\r
2573 if (DeviceType == EfiIdeHarddisk) {\r
2574 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
2575 }\r
a41b5272 2576 }\r
2577 return EFI_SUCCESS;\r
2578}\r
2579\r
2580\r
2581/**\r
2582 Initialize ATA host controller at IDE mode.\r
1aff716a 2583\r
2584 The function is designed to initialize ATA host controller.\r
2585\r
a41b5272 2586 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
2587\r
2588**/\r
2589EFI_STATUS\r
2590EFIAPI\r
2591IdeModeInitialization (\r
2592 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance\r
2593 )\r
2594{\r
a41b5272 2595 EFI_STATUS Status;\r
2596 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2597 EFI_PCI_IO_PROTOCOL *PciIo;\r
2598 UINT8 Channel;\r
2599 UINT8 IdeChannel;\r
2600 BOOLEAN ChannelEnabled;\r
2601 UINT8 MaxDevices;\r
2602\r
2603 IdeInit = Instance->IdeControllerInit;\r
2604 PciIo = Instance->PciIo;\r
a41b5272 2605 Channel = IdeInit->ChannelCount;\r
2606\r
2607 //\r
2608 // Obtain IDE IO port registers' base addresses\r
2609 //\r
2610 Status = GetIdeRegisterIoAddr (PciIo, Instance->IdeRegisters);\r
2611 if (EFI_ERROR (Status)) {\r
2612 goto ErrorExit;\r
2613 }\r
2614\r
2615 for (IdeChannel = 0; IdeChannel < Channel; IdeChannel++) {\r
2616 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, IdeChannel);\r
2617\r
2618 //\r
2619 // now obtain channel information fron IdeControllerInit protocol.\r
2620 //\r
2621 Status = IdeInit->GetChannelInfo (\r
2622 IdeInit,\r
2623 IdeChannel,\r
2624 &ChannelEnabled,\r
2625 &MaxDevices\r
2626 );\r
2627 if (EFI_ERROR (Status)) {\r
2628 DEBUG ((EFI_D_ERROR, "[GetChannel, Status=%x]", Status));\r
2629 continue;\r
2630 }\r
2631\r
2632 if (!ChannelEnabled) {\r
2633 continue;\r
2634 }\r
2635\r
2636 ASSERT (MaxDevices <= 2);\r
2637 //\r
2638 // Now inform the IDE Controller Init Module.\r
2639 //\r
2640 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelReset, IdeChannel);\r
2641\r
2642 //\r
2643 // No reset channel function implemented.\r
2644 //\r
2645 IdeInit->NotifyPhase (IdeInit, EfiIdeAfterChannelReset, IdeChannel);\r
2646\r
2647 //\r
2648 // Now inform the IDE Controller Init Module.\r
2649 //\r
2650 IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, IdeChannel);\r
2651\r
2652 //\r
2653 // Detect all attached ATA devices and set the transfer mode for each device.\r
2654 //\r
2655 DetectAndConfigIdeDevice (Instance, IdeChannel);\r
2656 }\r
2657\r
2658 //\r
2659 // All configurations done! Notify IdeController to do post initialization\r
2660 // work such as saving IDE controller PCI settings for S3 resume\r
2661 //\r
2662 IdeInit->NotifyPhase (IdeInit, EfiIdeBusPhaseMaximum, 0);\r
2663\r
2664ErrorExit:\r
2665 return Status;\r
2666}\r
2667\r