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