]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
MdeModulePkg: Apply uncrustify changes
[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
1436aea4
MK
22 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
23 IN UINT16 Port\r
a41b5272 24 )\r
25{\r
1436aea4 26 UINT8 Data;\r
a41b5272 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
1436aea4 38 (UINT64)Port,\r
a41b5272 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
8c39253d 49 @param Port The IDE port to be written\r
a41b5272 50 @param Data The data to write to the port\r
51**/\r
52VOID\r
53EFIAPI\r
54IdeWritePortB (\r
1436aea4
MK
55 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
56 IN UINT16 Port,\r
57 IN UINT8 Data\r
a41b5272 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
1436aea4 69 (UINT64)Port,\r
a41b5272 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
8c39253d 79 @param Port The IDE port to be written\r
a41b5272 80 @param Data The data to write to the port\r
81**/\r
82VOID\r
83EFIAPI\r
84IdeWritePortW (\r
1436aea4
MK
85 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
86 IN UINT16 Port,\r
87 IN UINT16 Data\r
a41b5272 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
1436aea4 99 (UINT64)Port,\r
a41b5272 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
8c39253d 109 @param Port The IDE port to be written\r
a41b5272 110 @param Data The data to write to the port\r
111**/\r
112VOID\r
113EFIAPI\r
114IdeWritePortDW (\r
1436aea4
MK
115 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
116 IN UINT16 Port,\r
117 IN UINT32 Data\r
a41b5272 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
1436aea4 129 (UINT64)Port,\r
a41b5272 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
1436aea4
MK
149 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
150 IN UINT16 Port,\r
151 IN UINTN Count,\r
152 IN VOID *Buffer\r
a41b5272 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
1436aea4 165 (UINT64)Port,\r
a41b5272 166 Count,\r
1436aea4 167 (UINT16 *)Buffer\r
a41b5272 168 );\r
a41b5272 169}\r
170\r
171/**\r
172 Reads multiple words of data from the IDE data port.\r
173 Call the IO abstraction once to do the complete read,\r
174 not one word at a time\r
175\r
8536cc4b 176 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure\r
a41b5272 177 @param Port IO port to read\r
178 @param Count Number of UINT16's to read\r
179 @param Buffer Pointer to the data buffer for read\r
180\r
181**/\r
182VOID\r
183EFIAPI\r
184IdeReadPortWMultiple (\r
1436aea4
MK
185 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
186 IN UINT16 Port,\r
187 IN UINTN Count,\r
188 IN VOID *Buffer\r
a41b5272 189 )\r
190{\r
191 ASSERT (PciIo != NULL);\r
192 ASSERT (Buffer != NULL);\r
193\r
194 //\r
195 // Perform UINT16 data read from FIFO\r
196 //\r
197 PciIo->Io.Read (\r
198 PciIo,\r
199 EfiPciIoWidthFifoUint16,\r
200 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1436aea4 201 (UINT64)Port,\r
a41b5272 202 Count,\r
1436aea4 203 (UINT16 *)Buffer\r
a41b5272 204 );\r
a41b5272 205}\r
206\r
207/**\r
208 This function is used to analyze the Status Register and print out\r
209 some debug information and if there is ERR bit set in the Status\r
210 Register, the Error Register's value is also be parsed and print out.\r
211\r
8536cc4b 212 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
a41b5272 213 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
214 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
215\r
216**/\r
217VOID\r
218EFIAPI\r
219DumpAllIdeRegisters (\r
1436aea4
MK
220 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
221 IN EFI_IDE_REGISTERS *IdeRegisters,\r
222 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
a41b5272 223 )\r
224{\r
1436aea4 225 EFI_ATA_STATUS_BLOCK StatusBlock;\r
a41b5272 226\r
227 ASSERT (PciIo != NULL);\r
228 ASSERT (IdeRegisters != NULL);\r
229\r
230 ZeroMem (&StatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
231\r
232 StatusBlock.AtaStatus = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
233 StatusBlock.AtaError = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
234 StatusBlock.AtaSectorCount = IdeReadPortB (PciIo, IdeRegisters->SectorCount);\r
235 StatusBlock.AtaSectorCountExp = IdeReadPortB (PciIo, IdeRegisters->SectorCount);\r
236 StatusBlock.AtaSectorNumber = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);\r
237 StatusBlock.AtaSectorNumberExp = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);\r
238 StatusBlock.AtaCylinderLow = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
239 StatusBlock.AtaCylinderLowExp = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
240 StatusBlock.AtaCylinderHigh = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);\r
241 StatusBlock.AtaCylinderHighExp = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);\r
242 StatusBlock.AtaDeviceHead = IdeReadPortB (PciIo, IdeRegisters->Head);\r
243\r
244 if (AtaStatusBlock != NULL) {\r
245 //\r
246 // Dump the content of all ATA registers.\r
247 //\r
248 CopyMem (AtaStatusBlock, &StatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
249 }\r
250\r
251 DEBUG_CODE_BEGIN ();\r
252 if ((StatusBlock.AtaStatus & ATA_STSREG_DWF) != 0) {\r
87000d77 253 DEBUG ((DEBUG_ERROR, "CheckRegisterStatus()-- %02x : Error : Write Fault\n", StatusBlock.AtaStatus));\r
a41b5272 254 }\r
255\r
256 if ((StatusBlock.AtaStatus & ATA_STSREG_CORR) != 0) {\r
87000d77 257 DEBUG ((DEBUG_ERROR, "CheckRegisterStatus()-- %02x : Error : Corrected Data\n", StatusBlock.AtaStatus));\r
a41b5272 258 }\r
259\r
260 if ((StatusBlock.AtaStatus & ATA_STSREG_ERR) != 0) {\r
261 if ((StatusBlock.AtaError & ATA_ERRREG_BBK) != 0) {\r
87000d77 262 DEBUG ((DEBUG_ERROR, "CheckRegisterStatus()-- %02x : Error : Bad Block Detected\n", StatusBlock.AtaError));\r
a41b5272 263 }\r
264\r
265 if ((StatusBlock.AtaError & ATA_ERRREG_UNC) != 0) {\r
87000d77 266 DEBUG ((DEBUG_ERROR, "CheckRegisterStatus()-- %02x : Error : Uncorrectable Data\n", StatusBlock.AtaError));\r
a41b5272 267 }\r
268\r
269 if ((StatusBlock.AtaError & ATA_ERRREG_MC) != 0) {\r
87000d77 270 DEBUG ((DEBUG_ERROR, "CheckRegisterStatus()-- %02x : Error : Media Change\n", StatusBlock.AtaError));\r
a41b5272 271 }\r
272\r
273 if ((StatusBlock.AtaError & ATA_ERRREG_ABRT) != 0) {\r
87000d77 274 DEBUG ((DEBUG_ERROR, "CheckRegisterStatus()-- %02x : Error : Abort\n", StatusBlock.AtaError));\r
a41b5272 275 }\r
276\r
277 if ((StatusBlock.AtaError & ATA_ERRREG_TK0NF) != 0) {\r
87000d77 278 DEBUG ((DEBUG_ERROR, "CheckRegisterStatus()-- %02x : Error : Track 0 Not Found\n", StatusBlock.AtaError));\r
a41b5272 279 }\r
280\r
281 if ((StatusBlock.AtaError & ATA_ERRREG_AMNF) != 0) {\r
87000d77 282 DEBUG ((DEBUG_ERROR, "CheckRegisterStatus()-- %02x : Error : Address Mark Not Found\n", StatusBlock.AtaError));\r
a41b5272 283 }\r
284 }\r
1436aea4 285\r
a41b5272 286 DEBUG_CODE_END ();\r
287}\r
288\r
289/**\r
8536cc4b 290 This function is used to analyze the Status Register at the condition that BSY is zero.\r
291 if there is ERR bit set in the Status Register, then return error.\r
a41b5272 292\r
8536cc4b 293 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
a41b5272 294 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
295\r
296 @retval EFI_SUCCESS No err information in the Status Register.\r
297 @retval EFI_DEVICE_ERROR Any err information in the Status Register.\r
298\r
299**/\r
300EFI_STATUS\r
301EFIAPI\r
302CheckStatusRegister (\r
1436aea4
MK
303 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
304 IN EFI_IDE_REGISTERS *IdeRegisters\r
a41b5272 305 )\r
306{\r
1436aea4 307 UINT8 StatusRegister;\r
a41b5272 308\r
309 ASSERT (PciIo != NULL);\r
310 ASSERT (IdeRegisters != NULL);\r
311\r
312 StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
313\r
8536cc4b 314 if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
315 if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {\r
316 return EFI_SUCCESS;\r
317 } else {\r
318 return EFI_DEVICE_ERROR;\r
319 }\r
a41b5272 320 }\r
1436aea4 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
1436aea4
MK
345 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
346 IN EFI_IDE_REGISTERS *IdeRegisters,\r
347 IN UINT64 Timeout\r
a41b5272 348 )\r
349{\r
1436aea4
MK
350 UINT64 Delay;\r
351 UINT8 StatusRegister;\r
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
1436aea4 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
ab82122d 384 } while (InfiniteWait || (Delay > 0));\r
a41b5272 385\r
8536cc4b 386 return EFI_TIMEOUT;\r
a41b5272 387}\r
1436aea4 388\r
a41b5272 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
1436aea4
MK
413 UINT64 Delay;\r
414 UINT8 AltRegister;\r
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
1436aea4 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
ab82122d 447 } while (InfiniteWait || (Delay > 0));\r
a41b5272 448\r
8536cc4b 449 return EFI_TIMEOUT;\r
a41b5272 450}\r
451\r
452/**\r
453 This function is used to poll for the DRQ bit set in the\r
454 Status Register.\r
455 DRQ is set when the device is ready to transfer data. So this function\r
456 is called after the command is sent to the device and before required\r
457 data is transferred.\r
458\r
8536cc4b 459 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
a41b5272 460 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
8536cc4b 461 @param Timeout The time to complete the command, uses 100ns as a unit.\r
a41b5272 462\r
dfc229f6
LE
463 @retval EFI_SUCCESS BSY bit cleared and DRQ bit set within the\r
464 timeout.\r
465\r
466 @retval EFI_TIMEOUT BSY bit not cleared within the timeout.\r
467\r
468 @retval EFI_ABORTED Polling abandoned due to command abort.\r
469\r
470 @retval EFI_DEVICE_ERROR Polling abandoned due to a non-abort error.\r
471\r
472 @retval EFI_NOT_READY BSY bit cleared within timeout, and device\r
473 reported "command complete" by clearing DRQ\r
474 bit.\r
a41b5272 475\r
476 @note Read Status Register will clear interrupt status.\r
477\r
478**/\r
479EFI_STATUS\r
480EFIAPI\r
481DRQReady (\r
482 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
483 IN EFI_IDE_REGISTERS *IdeRegisters,\r
484 IN UINT64 Timeout\r
485 )\r
486{\r
1436aea4
MK
487 UINT64 Delay;\r
488 UINT8 StatusRegister;\r
489 UINT8 ErrorRegister;\r
490 BOOLEAN InfiniteWait;\r
a41b5272 491\r
492 ASSERT (PciIo != NULL);\r
493 ASSERT (IdeRegisters != NULL);\r
494\r
ab82122d
TF
495 if (Timeout == 0) {\r
496 InfiniteWait = TRUE;\r
497 } else {\r
498 InfiniteWait = FALSE;\r
499 }\r
500\r
1436aea4 501 Delay = DivU64x32 (Timeout, 1000) + 1;\r
a41b5272 502 do {\r
503 //\r
8536cc4b 504 // Read Status Register will clear interrupt\r
a41b5272 505 //\r
506 StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
507\r
508 //\r
8536cc4b 509 // Wait for BSY == 0, then judge if DRQ is clear or ERR is set\r
a41b5272 510 //\r
8536cc4b 511 if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
512 if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
513 ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
a41b5272 514\r
8536cc4b 515 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
516 return EFI_ABORTED;\r
517 }\r
1436aea4 518\r
8536cc4b 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
1436aea4 539\r
a41b5272 540/**\r
541 This function is used to poll for the DRQ bit set in the Alternate Status Register.\r
1aff716a 542 DRQ is set when the device is ready to transfer data. So this function is called after\r
a41b5272 543 the command is sent to the device and before required data is transferred.\r
544\r
8536cc4b 545 @param PciIo A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
a41b5272 546 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
8536cc4b 547 @param Timeout The time to complete the command, uses 100ns as a unit.\r
a41b5272 548\r
dfc229f6
LE
549 @retval EFI_SUCCESS BSY bit cleared and DRQ bit set within the\r
550 timeout.\r
551\r
552 @retval EFI_TIMEOUT BSY bit not cleared within the timeout.\r
553\r
554 @retval EFI_ABORTED Polling abandoned due to command abort.\r
555\r
556 @retval EFI_DEVICE_ERROR Polling abandoned due to a non-abort error.\r
557\r
558 @retval EFI_NOT_READY BSY bit cleared within timeout, and device\r
559 reported "command complete" by clearing DRQ\r
560 bit.\r
561\r
a41b5272 562 @note Read Alternate Status Register will not clear interrupt status.\r
563\r
564**/\r
565EFI_STATUS\r
566EFIAPI\r
567DRQReady2 (\r
568 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
569 IN EFI_IDE_REGISTERS *IdeRegisters,\r
570 IN UINT64 Timeout\r
571 )\r
572{\r
1436aea4
MK
573 UINT64 Delay;\r
574 UINT8 AltRegister;\r
575 UINT8 ErrorRegister;\r
576 BOOLEAN InfiniteWait;\r
a41b5272 577\r
578 ASSERT (PciIo != NULL);\r
579 ASSERT (IdeRegisters != NULL);\r
580\r
ab82122d
TF
581 if (Timeout == 0) {\r
582 InfiniteWait = TRUE;\r
583 } else {\r
584 InfiniteWait = FALSE;\r
585 }\r
586\r
1436aea4 587 Delay = DivU64x32 (Timeout, 1000) + 1;\r
a41b5272 588\r
589 do {\r
590 //\r
8536cc4b 591 // Read Alternate Status Register will not clear interrupt status\r
a41b5272 592 //\r
593 AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
594 //\r
8536cc4b 595 // Wait for BSY == 0, then judge if DRQ is clear or ERR is set\r
a41b5272 596 //\r
8536cc4b 597 if ((AltRegister & ATA_STSREG_BSY) == 0) {\r
598 if ((AltRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
599 ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
a41b5272 600\r
8536cc4b 601 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
602 return EFI_ABORTED;\r
603 }\r
1436aea4 604\r
8536cc4b 605 return EFI_DEVICE_ERROR;\r
606 }\r
a41b5272 607\r
8536cc4b 608 if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
609 return EFI_SUCCESS;\r
610 } else {\r
611 return EFI_NOT_READY;\r
a41b5272 612 }\r
613 }\r
614\r
615 //\r
616 // Stall for 100 microseconds.\r
617 //\r
618 MicroSecondDelay (100);\r
619\r
620 Delay--;\r
ab82122d 621 } while (InfiniteWait || (Delay > 0));\r
a41b5272 622\r
8536cc4b 623 return EFI_TIMEOUT;\r
a41b5272 624}\r
625\r
a41b5272 626/**\r
627 This function is used to poll for the BSY bit clear in the Status Register. BSY\r
628 is clear when the device is not busy. Every command must be sent after device is not busy.\r
629\r
630 @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
631 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
8536cc4b 632 @param Timeout The time to complete the command, uses 100ns as a unit.\r
a41b5272 633\r
634 @retval EFI_SUCCESS BSY bit clear within the time out.\r
635 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
636\r
637 @note Read Status Register will clear interrupt status.\r
638**/\r
639EFI_STATUS\r
640EFIAPI\r
641WaitForBSYClear (\r
642 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
643 IN EFI_IDE_REGISTERS *IdeRegisters,\r
644 IN UINT64 Timeout\r
645 )\r
646{\r
1436aea4
MK
647 UINT64 Delay;\r
648 UINT8 StatusRegister;\r
649 BOOLEAN InfiniteWait;\r
a41b5272 650\r
651 ASSERT (PciIo != NULL);\r
652 ASSERT (IdeRegisters != NULL);\r
653\r
ab82122d
TF
654 if (Timeout == 0) {\r
655 InfiniteWait = TRUE;\r
656 } else {\r
657 InfiniteWait = FALSE;\r
658 }\r
659\r
1436aea4 660 Delay = DivU64x32 (Timeout, 1000) + 1;\r
a41b5272 661 do {\r
662 StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
663\r
664 if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
8536cc4b 665 return EFI_SUCCESS;\r
a41b5272 666 }\r
667\r
668 //\r
669 // Stall for 100 microseconds.\r
670 //\r
671 MicroSecondDelay (100);\r
672\r
673 Delay--;\r
ab82122d 674 } while (InfiniteWait || (Delay > 0));\r
a41b5272 675\r
8536cc4b 676 return EFI_TIMEOUT;\r
a41b5272 677}\r
678\r
a41b5272 679/**\r
1aff716a 680 Get IDE i/o port registers' base addresses by mode.\r
a41b5272 681\r
682 In 'Compatibility' mode, use fixed addresses.\r
683 In Native-PCI mode, get base addresses from BARs in the PCI IDE controller's\r
684 Configuration Space.\r
685\r
686 The steps to get IDE i/o port registers' base addresses for each channel\r
687 as follows:\r
688\r
689 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
690 controller's Configuration Space to determine the operating mode.\r
691\r
692 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
693 ___________________________________________\r
694 | | Command Block | Control Block |\r
695 | Channel | Registers | Registers |\r
696 |___________|_______________|_______________|\r
697 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
698 |___________|_______________|_______________|\r
699 | Secondary | 170h - 177h | 376h - 377h |\r
700 |___________|_______________|_______________|\r
701\r
702 Table 1. Compatibility resource mappings\r
1aff716a 703\r
a41b5272 704 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
705 in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
706 ___________________________________________________\r
707 | | Command Block | Control Block |\r
708 | Channel | Registers | Registers |\r
709 |___________|___________________|___________________|\r
710 | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
711 |___________|___________________|___________________|\r
712 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
713 |___________|___________________|___________________|\r
714\r
715 Table 2. BARs for Register Mapping\r
716\r
717 @param[in] PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
8c39253d 718 @param[in, out] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to\r
a41b5272 719 store the IDE i/o port registers' base addresses\r
1aff716a 720\r
a41b5272 721 @retval EFI_UNSUPPORTED Return this value when the BARs is not IO type\r
722 @retval EFI_SUCCESS Get the Base address successfully\r
8c39253d 723 @retval Other Read the pci configuration data error\r
a41b5272 724\r
725**/\r
726EFI_STATUS\r
727EFIAPI\r
728GetIdeRegisterIoAddr (\r
1436aea4
MK
729 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
730 IN OUT EFI_IDE_REGISTERS *IdeRegisters\r
a41b5272 731 )\r
732{\r
1436aea4
MK
733 EFI_STATUS Status;\r
734 PCI_TYPE00 PciData;\r
735 UINT16 CommandBlockBaseAddr;\r
736 UINT16 ControlBlockBaseAddr;\r
737 UINT16 BusMasterBaseAddr;\r
a41b5272 738\r
739 if ((PciIo == NULL) || (IdeRegisters == NULL)) {\r
740 return EFI_INVALID_PARAMETER;\r
741 }\r
742\r
743 Status = PciIo->Pci.Read (\r
744 PciIo,\r
745 EfiPciIoWidthUint8,\r
746 0,\r
747 sizeof (PciData),\r
748 &PciData\r
749 );\r
750\r
751 if (EFI_ERROR (Status)) {\r
752 return Status;\r
753 }\r
754\r
1436aea4 755 BusMasterBaseAddr = (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
a41b5272 756\r
757 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
758 CommandBlockBaseAddr = 0x1f0;\r
759 ControlBlockBaseAddr = 0x3f6;\r
760 } else {\r
761 //\r
762 // The BARs should be of IO type\r
763 //\r
1436aea4
MK
764 if (((PciData.Device.Bar[0] & BIT0) == 0) ||\r
765 ((PciData.Device.Bar[1] & BIT0) == 0))\r
766 {\r
a41b5272 767 return EFI_UNSUPPORTED;\r
768 }\r
769\r
1436aea4
MK
770 CommandBlockBaseAddr = (UINT16)(PciData.Device.Bar[0] & 0x0000fff8);\r
771 ControlBlockBaseAddr = (UINT16)((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
a41b5272 772 }\r
773\r
774 //\r
775 // Calculate IDE primary channel I/O register base address.\r
776 //\r
777 IdeRegisters[EfiIdePrimary].Data = CommandBlockBaseAddr;\r
1436aea4
MK
778 IdeRegisters[EfiIdePrimary].ErrOrFeature = (UINT16)(CommandBlockBaseAddr + 0x01);\r
779 IdeRegisters[EfiIdePrimary].SectorCount = (UINT16)(CommandBlockBaseAddr + 0x02);\r
780 IdeRegisters[EfiIdePrimary].SectorNumber = (UINT16)(CommandBlockBaseAddr + 0x03);\r
781 IdeRegisters[EfiIdePrimary].CylinderLsb = (UINT16)(CommandBlockBaseAddr + 0x04);\r
782 IdeRegisters[EfiIdePrimary].CylinderMsb = (UINT16)(CommandBlockBaseAddr + 0x05);\r
783 IdeRegisters[EfiIdePrimary].Head = (UINT16)(CommandBlockBaseAddr + 0x06);\r
784 IdeRegisters[EfiIdePrimary].CmdOrStatus = (UINT16)(CommandBlockBaseAddr + 0x07);\r
a41b5272 785 IdeRegisters[EfiIdePrimary].AltOrDev = ControlBlockBaseAddr;\r
786 IdeRegisters[EfiIdePrimary].BusMasterBaseAddr = BusMasterBaseAddr;\r
787\r
788 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
789 CommandBlockBaseAddr = 0x170;\r
790 ControlBlockBaseAddr = 0x376;\r
791 } else {\r
792 //\r
793 // The BARs should be of IO type\r
794 //\r
1436aea4
MK
795 if (((PciData.Device.Bar[2] & BIT0) == 0) ||\r
796 ((PciData.Device.Bar[3] & BIT0) == 0))\r
797 {\r
a41b5272 798 return EFI_UNSUPPORTED;\r
799 }\r
800\r
1436aea4
MK
801 CommandBlockBaseAddr = (UINT16)(PciData.Device.Bar[2] & 0x0000fff8);\r
802 ControlBlockBaseAddr = (UINT16)((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
a41b5272 803 }\r
804\r
805 //\r
806 // Calculate IDE secondary channel I/O register base address.\r
807 //\r
808 IdeRegisters[EfiIdeSecondary].Data = CommandBlockBaseAddr;\r
1436aea4
MK
809 IdeRegisters[EfiIdeSecondary].ErrOrFeature = (UINT16)(CommandBlockBaseAddr + 0x01);\r
810 IdeRegisters[EfiIdeSecondary].SectorCount = (UINT16)(CommandBlockBaseAddr + 0x02);\r
811 IdeRegisters[EfiIdeSecondary].SectorNumber = (UINT16)(CommandBlockBaseAddr + 0x03);\r
812 IdeRegisters[EfiIdeSecondary].CylinderLsb = (UINT16)(CommandBlockBaseAddr + 0x04);\r
813 IdeRegisters[EfiIdeSecondary].CylinderMsb = (UINT16)(CommandBlockBaseAddr + 0x05);\r
814 IdeRegisters[EfiIdeSecondary].Head = (UINT16)(CommandBlockBaseAddr + 0x06);\r
815 IdeRegisters[EfiIdeSecondary].CmdOrStatus = (UINT16)(CommandBlockBaseAddr + 0x07);\r
a41b5272 816 IdeRegisters[EfiIdeSecondary].AltOrDev = ControlBlockBaseAddr;\r
1436aea4 817 IdeRegisters[EfiIdeSecondary].BusMasterBaseAddr = (UINT16)(BusMasterBaseAddr + 0x8);\r
a41b5272 818\r
819 return EFI_SUCCESS;\r
820}\r
821\r
a41b5272 822/**\r
823 Send ATA Ext command into device with NON_DATA protocol.\r
824\r
825 @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
826 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
827 @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
8536cc4b 828 @param Timeout The time to complete the command, uses 100ns as a unit.\r
a41b5272 829\r
830 @retval EFI_SUCCESS Reading succeed\r
831 @retval EFI_DEVICE_ERROR Error executing commands on this device.\r
832\r
833**/\r
834EFI_STATUS\r
835EFIAPI\r
836AtaIssueCommand (\r
1436aea4
MK
837 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
838 IN EFI_IDE_REGISTERS *IdeRegisters,\r
839 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
840 IN UINT64 Timeout\r
a41b5272 841 )\r
842{\r
843 EFI_STATUS Status;\r
844 UINT8 DeviceHead;\r
845 UINT8 AtaCommand;\r
846\r
847 ASSERT (PciIo != NULL);\r
848 ASSERT (IdeRegisters != NULL);\r
849 ASSERT (AtaCommandBlock != NULL);\r
850\r
851 DeviceHead = AtaCommandBlock->AtaDeviceHead;\r
852 AtaCommand = AtaCommandBlock->AtaCommand;\r
853\r
854 Status = WaitForBSYClear (PciIo, IdeRegisters, Timeout);\r
855 if (EFI_ERROR (Status)) {\r
856 return EFI_DEVICE_ERROR;\r
857 }\r
858\r
859 //\r
860 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
861 //\r
1436aea4 862 IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead));\r
a41b5272 863\r
864 //\r
865 // set all the command parameters\r
866 // Before write to all the following registers, BSY and DRQ must be 0.\r
867 //\r
868 Status = DRQClear2 (PciIo, IdeRegisters, Timeout);\r
869 if (EFI_ERROR (Status)) {\r
870 return EFI_DEVICE_ERROR;\r
871 }\r
872\r
873 //\r
874 // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
875 //\r
876 IdeWritePortB (PciIo, IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeaturesExp);\r
877 IdeWritePortB (PciIo, IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeatures);\r
878\r
879 //\r
880 // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
881 //\r
882 IdeWritePortB (PciIo, IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCountExp);\r
883 IdeWritePortB (PciIo, IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCount);\r
884\r
885 //\r
886 // Fill the start LBA registers, which are also two-byte FIFO\r
887 //\r
888 IdeWritePortB (PciIo, IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumberExp);\r
889 IdeWritePortB (PciIo, IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumber);\r
890\r
891 IdeWritePortB (PciIo, IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLowExp);\r
892 IdeWritePortB (PciIo, IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLow);\r
893\r
894 IdeWritePortB (PciIo, IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHighExp);\r
895 IdeWritePortB (PciIo, IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHigh);\r
896\r
897 //\r
898 // Send command via Command Register\r
899 //\r
900 IdeWritePortB (PciIo, IdeRegisters->CmdOrStatus, AtaCommand);\r
901\r
902 //\r
903 // Stall at least 400 microseconds.\r
904 //\r
905 MicroSecondDelay (400);\r
906\r
907 return EFI_SUCCESS;\r
908}\r
909\r
910/**\r
911 This function is used to send out ATA commands conforms to the PIO Data In Protocol.\r
912\r
490b5ea1 913 @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data\r
914 structure.\r
915 @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
916 @param[in, out] Buffer A pointer to the source buffer for the data.\r
917 @param[in] ByteCount The length of the data.\r
86d8e199 918 @param[in] Read Flag used to determine the data transfer direction.\r
490b5ea1 919 Read equals 1, means data transferred from device\r
920 to host;Read equals 0, means data transferred\r
921 from host to device.\r
922 @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
86d8e199 923 @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
8536cc4b 924 @param[in] Timeout The time to complete the command, uses 100ns as a unit.\r
490b5ea1 925 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
926 used by non-blocking mode.\r
1aff716a 927\r
a41b5272 928 @retval EFI_SUCCESS send out the ATA command and device send required data successfully.\r
929 @retval EFI_DEVICE_ERROR command sent failed.\r
930\r
931**/\r
932EFI_STATUS\r
933EFIAPI\r
1aff716a 934AtaPioDataInOut (\r
1436aea4
MK
935 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
936 IN EFI_IDE_REGISTERS *IdeRegisters,\r
937 IN OUT VOID *Buffer,\r
938 IN UINT64 ByteCount,\r
939 IN BOOLEAN Read,\r
940 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
941 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
942 IN UINT64 Timeout,\r
943 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 944 )\r
945{\r
946 UINTN WordCount;\r
947 UINTN Increment;\r
948 UINT16 *Buffer16;\r
949 EFI_STATUS Status;\r
950\r
951 if ((PciIo == NULL) || (IdeRegisters == NULL) || (Buffer == NULL) || (AtaCommandBlock == NULL)) {\r
952 return EFI_INVALID_PARAMETER;\r
953 }\r
954\r
955 //\r
956 // Issue ATA command\r
957 //\r
958 Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
959 if (EFI_ERROR (Status)) {\r
960 Status = EFI_DEVICE_ERROR;\r
961 goto Exit;\r
962 }\r
963\r
1436aea4 964 Buffer16 = (UINT16 *)Buffer;\r
a41b5272 965\r
966 //\r
967 // According to PIO data in protocol, host can perform a series of reads to\r
968 // the data register after each time device set DRQ ready;\r
969 // The data size of "a series of read" is command specific.\r
970 // For most ATA command, data size received from device will not exceed\r
971 // 1 sector, hence the data size for "a series of read" can be the whole data\r
972 // size of one command request.\r
973 // For ATA command such as Read Sector command, the data size of one ATA\r
974 // command request is often larger than 1 sector, according to the\r
975 // Read Sector command, the data size of "a series of read" is exactly 1\r
976 // sector.\r
977 // Here for simplification reason, we specify the data size for\r
978 // "a series of read" to 1 sector (256 words) if data size of one ATA command\r
979 // request is larger than 256 words.\r
980 //\r
981 Increment = 256;\r
982\r
983 //\r
8c39253d 984 // used to record bytes of currently transferred data\r
a41b5272 985 //\r
986 WordCount = 0;\r
987\r
1436aea4 988 while (WordCount < RShiftU64 (ByteCount, 1)) {\r
a41b5272 989 //\r
990 // Poll DRQ bit set, data transfer can be performed only when DRQ is ready\r
991 //\r
992 Status = DRQReady2 (PciIo, IdeRegisters, Timeout);\r
1aff716a 993 if (EFI_ERROR (Status)) {\r
a41b5272 994 Status = EFI_DEVICE_ERROR;\r
995 goto Exit;\r
996 }\r
997\r
998 //\r
999 // Get the byte count for one series of read\r
1000 //\r
1436aea4
MK
1001 if ((WordCount + Increment) > RShiftU64 (ByteCount, 1)) {\r
1002 Increment = (UINTN)(RShiftU64 (ByteCount, 1) - WordCount);\r
a41b5272 1003 }\r
1004\r
1005 if (Read) {\r
1006 IdeReadPortWMultiple (\r
1007 PciIo,\r
1008 IdeRegisters->Data,\r
1009 Increment,\r
1010 Buffer16\r
1011 );\r
1012 } else {\r
1013 IdeWritePortWMultiple (\r
1014 PciIo,\r
1015 IdeRegisters->Data,\r
1016 Increment,\r
1017 Buffer16\r
1018 );\r
1019 }\r
1020\r
1021 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1022 if (EFI_ERROR (Status)) {\r
1023 Status = EFI_DEVICE_ERROR;\r
1024 goto Exit;\r
1025 }\r
1026\r
1027 WordCount += Increment;\r
1028 Buffer16 += Increment;\r
1029 }\r
1030\r
1031 Status = DRQClear (PciIo, IdeRegisters, Timeout);\r
1032 if (EFI_ERROR (Status)) {\r
1033 Status = EFI_DEVICE_ERROR;\r
1034 goto Exit;\r
1035 }\r
1036\r
1037Exit:\r
1038 //\r
1039 // Dump All Ide registers to ATA_STATUS_BLOCK\r
1040 //\r
1041 DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
1042\r
490b5ea1 1043 //\r
1044 // Not support the Non-blocking now,just do the blocking process.\r
1045 //\r
a41b5272 1046 return Status;\r
1047}\r
1048\r
1049/**\r
1050 Send ATA command into device with NON_DATA protocol\r
1051\r
490b5ea1 1052 @param[in] PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE\r
1053 data structure.\r
1054 @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
1055 @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data\r
1056 structure.\r
1057 @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
8536cc4b 1058 @param[in] Timeout The time to complete the command, uses 100ns as a unit.\r
490b5ea1 1059 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1060 used by non-blocking mode.\r
a41b5272 1061\r
1062 @retval EFI_SUCCESS Reading succeed\r
1063 @retval EFI_ABORTED Command failed\r
1064 @retval EFI_DEVICE_ERROR Device status error.\r
1065\r
1066**/\r
1067EFI_STATUS\r
1068EFIAPI\r
1aff716a 1069AtaNonDataCommandIn (\r
1436aea4
MK
1070 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1071 IN EFI_IDE_REGISTERS *IdeRegisters,\r
1072 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
1073 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
1074 IN UINT64 Timeout,\r
1075 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 1076 )\r
1077{\r
1078 EFI_STATUS Status;\r
1079\r
1080 if ((PciIo == NULL) || (IdeRegisters == NULL) || (AtaCommandBlock == NULL)) {\r
1081 return EFI_INVALID_PARAMETER;\r
1082 }\r
1083\r
1084 //\r
1085 // Issue ATA command\r
1086 //\r
1087 Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
1088 if (EFI_ERROR (Status)) {\r
1089 Status = EFI_DEVICE_ERROR;\r
1090 goto Exit;\r
1091 }\r
1092\r
1093 //\r
1094 // Wait for command completion\r
1095 //\r
1096 Status = WaitForBSYClear (PciIo, IdeRegisters, Timeout);\r
1097 if (EFI_ERROR (Status)) {\r
1098 Status = EFI_DEVICE_ERROR;\r
1099 goto Exit;\r
1100 }\r
1aff716a 1101\r
a41b5272 1102 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1103 if (EFI_ERROR (Status)) {\r
1104 Status = EFI_DEVICE_ERROR;\r
1105 goto Exit;\r
1106 }\r
1107\r
1108Exit:\r
1109 //\r
1110 // Dump All Ide registers to ATA_STATUS_BLOCK\r
1111 //\r
1112 DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
1aff716a 1113\r
490b5ea1 1114 //\r
1115 // Not support the Non-blocking now,just do the blocking process.\r
1116 //\r
1117 return Status;\r
1118}\r
1119\r
1120/**\r
1121 Wait for memory to be set.\r
1aff716a 1122\r
490b5ea1 1123 @param[in] PciIo The PCI IO protocol instance.\r
8536cc4b 1124 @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
ab82122d 1125 @param[in] Timeout The time to complete the command, uses 100ns as a unit.\r
490b5ea1 1126\r
1127 @retval EFI_DEVICE_ERROR The memory is not set.\r
1128 @retval EFI_TIMEOUT The memory setting is time out.\r
1129 @retval EFI_SUCCESS The memory is correct set.\r
1130\r
1131**/\r
1132EFI_STATUS\r
1133AtaUdmStatusWait (\r
1436aea4
MK
1134 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1135 IN EFI_IDE_REGISTERS *IdeRegisters,\r
1136 IN UINT64 Timeout\r
1137 )\r
490b5ea1 1138{\r
1436aea4
MK
1139 UINT8 RegisterValue;\r
1140 EFI_STATUS Status;\r
1141 UINT16 IoPortForBmis;\r
1142 UINT64 Delay;\r
1143 BOOLEAN InfiniteWait;\r
ab82122d
TF
1144\r
1145 if (Timeout == 0) {\r
1146 InfiniteWait = TRUE;\r
1147 } else {\r
1148 InfiniteWait = FALSE;\r
1149 }\r
490b5ea1 1150\r
ab82122d 1151 Delay = DivU64x32 (Timeout, 1000) + 1;\r
490b5ea1 1152\r
ab82122d 1153 do {\r
8536cc4b 1154 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1155 if (EFI_ERROR (Status)) {\r
1156 Status = EFI_DEVICE_ERROR;\r
1157 break;\r
1158 }\r
490b5ea1 1159\r
1436aea4 1160 IoPortForBmis = (UINT16)(IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);\r
8536cc4b 1161 RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);\r
490b5ea1 1162 if (((RegisterValue & BMIS_ERROR) != 0) || (Timeout == 0)) {\r
87000d77 1163 DEBUG ((DEBUG_ERROR, "ATA UDMA operation fails\n"));\r
490b5ea1 1164 Status = EFI_DEVICE_ERROR;\r
1165 break;\r
1166 }\r
1167\r
1168 if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
1169 Status = EFI_SUCCESS;\r
490b5ea1 1170 break;\r
1171 }\r
1436aea4 1172\r
490b5ea1 1173 //\r
ab82122d 1174 // Stall for 100 microseconds.\r
490b5ea1 1175 //\r
ab82122d
TF
1176 MicroSecondDelay (100);\r
1177 Delay--;\r
1178 } while (InfiniteWait || (Delay > 0));\r
a41b5272 1179\r
1180 return Status;\r
1181}\r
1182\r
490b5ea1 1183/**\r
1184 Check if the memory to be set.\r
1aff716a 1185\r
490b5ea1 1186 @param[in] PciIo The PCI IO protocol instance.\r
1187 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1188 used by non-blocking mode.\r
8536cc4b 1189 @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
490b5ea1 1190\r
1191 @retval EFI_DEVICE_ERROR The memory setting met a issue.\r
1192 @retval EFI_NOT_READY The memory is not set.\r
1193 @retval EFI_TIMEOUT The memory setting is time out.\r
1194 @retval EFI_SUCCESS The memory is correct set.\r
1195\r
1196**/\r
1197EFI_STATUS\r
1198AtaUdmStatusCheck (\r
1436aea4
MK
1199 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1200 IN ATA_NONBLOCK_TASK *Task,\r
1201 IN EFI_IDE_REGISTERS *IdeRegisters\r
1202 )\r
490b5ea1 1203{\r
1436aea4
MK
1204 UINT8 RegisterValue;\r
1205 UINT16 IoPortForBmis;\r
1206 EFI_STATUS Status;\r
490b5ea1 1207\r
1208 Task->RetryTimes--;\r
8536cc4b 1209\r
1210 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1211 if (EFI_ERROR (Status)) {\r
1212 return EFI_DEVICE_ERROR;\r
1213 }\r
1214\r
1436aea4 1215 IoPortForBmis = (UINT16)(IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);\r
8536cc4b 1216 RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);\r
490b5ea1 1217\r
1218 if ((RegisterValue & BMIS_ERROR) != 0) {\r
87000d77 1219 DEBUG ((DEBUG_ERROR, "ATA UDMA operation fails\n"));\r
490b5ea1 1220 return EFI_DEVICE_ERROR;\r
1221 }\r
1222\r
1223 if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
490b5ea1 1224 return EFI_SUCCESS;\r
1225 }\r
1226\r
ab82122d 1227 if (!Task->InfiniteWait && (Task->RetryTimes == 0)) {\r
490b5ea1 1228 return EFI_TIMEOUT;\r
1229 } else {\r
1230 //\r
1231 // The memory is not set.\r
1232 //\r
1233 return EFI_NOT_READY;\r
1234 }\r
1235}\r
a41b5272 1236\r
1237/**\r
1238 Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
1239\r
490b5ea1 1240 @param[in] Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data\r
1241 structure.\r
1242 @param[in] IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
1243 @param[in] Read Flag used to determine the data transfer\r
1244 direction. Read equals 1, means data transferred\r
1245 from device to host;Read equals 0, means data\r
1246 transferred from host to device.\r
1247 @param[in] DataBuffer A pointer to the source buffer for the data.\r
1248 @param[in] DataLength The length of the data.\r
1249 @param[in] AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
1250 @param[in, out] AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
8536cc4b 1251 @param[in] Timeout The time to complete the command, uses 100ns as a unit.\r
490b5ea1 1252 @param[in] Task Optional. Pointer to the ATA_NONBLOCK_TASK\r
1253 used by non-blocking mode.\r
a41b5272 1254\r
1255 @retval EFI_SUCCESS the operation is successful.\r
1256 @retval EFI_OUT_OF_RESOURCES Build PRD table failed\r
1257 @retval EFI_UNSUPPORTED Unknown channel or operations command\r
1258 @retval EFI_DEVICE_ERROR Ata command execute failed\r
1259\r
1260**/\r
1261EFI_STATUS\r
1262EFIAPI\r
1263AtaUdmaInOut (\r
490b5ea1 1264 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
1265 IN EFI_IDE_REGISTERS *IdeRegisters,\r
1266 IN BOOLEAN Read,\r
1267 IN VOID *DataBuffer,\r
1268 IN UINT64 DataLength,\r
1269 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
1270 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
1271 IN UINT64 Timeout,\r
1272 IN ATA_NONBLOCK_TASK *Task\r
a41b5272 1273 )\r
1274{\r
1436aea4
MK
1275 EFI_STATUS Status;\r
1276 UINT16 IoPortForBmic;\r
1277 UINT16 IoPortForBmis;\r
1278 UINT16 IoPortForBmid;\r
1279\r
1280 UINTN PrdTableSize;\r
1281 EFI_PHYSICAL_ADDRESS PrdTableMapAddr;\r
1282 VOID *PrdTableMap;\r
1283 EFI_PHYSICAL_ADDRESS PrdTableBaseAddr;\r
1284 EFI_ATA_DMA_PRD *TempPrdBaseAddr;\r
1285 UINTN PrdTableNum;\r
1286\r
1287 UINT8 RegisterValue;\r
1288 UINTN PageCount;\r
1289 UINTN ByteCount;\r
1290 UINTN ByteRemaining;\r
1291 UINT8 DeviceControl;\r
1292\r
1293 VOID *BufferMap;\r
1294 EFI_PHYSICAL_ADDRESS BufferMapAddress;\r
1295 EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation;\r
1296\r
1297 UINT8 DeviceHead;\r
1298 EFI_PCI_IO_PROTOCOL *PciIo;\r
1299 EFI_TPL OldTpl;\r
1300\r
1301 UINTN AlignmentMask;\r
1302 UINTN RealPageCount;\r
1303 EFI_PHYSICAL_ADDRESS BaseAddr;\r
1304 EFI_PHYSICAL_ADDRESS BaseMapAddr;\r
490b5ea1 1305\r
1306 Status = EFI_SUCCESS;\r
490b5ea1 1307 PrdTableMap = NULL;\r
1308 BufferMap = NULL;\r
1309 PageCount = 0;\r
51492422
FT
1310 RealPageCount = 0;\r
1311 BaseAddr = 0;\r
490b5ea1 1312 PciIo = Instance->PciIo;\r
a41b5272 1313\r
1314 if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {\r
1315 return EFI_INVALID_PARAMETER;\r
1316 }\r
1317\r
490b5ea1 1318 //\r
1319 // Before starting the Blocking BlockIO operation, push to finish all non-blocking\r
1320 // BlockIO tasks.\r
1321 // Delay 1ms to simulate the blocking time out checking.\r
1322 //\r
1aff716a 1323 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
490b5ea1 1324 while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {\r
490b5ea1 1325 AsyncNonBlockingTransferRoutine (NULL, Instance);\r
490b5ea1 1326 //\r
1327 // Stall for 1 milliseconds.\r
1328 //\r
1329 MicroSecondDelay (1000);\r
1aff716a 1330 }\r
1436aea4 1331\r
1aff716a 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
1436aea4
MK
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
1436aea4 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
1436aea4
MK
1381 Status = PciIo->AllocateBuffer (\r
1382 PciIo,\r
1383 AllocateAnyPages,\r
1384 EfiBootServicesData,\r
1385 RealPageCount,\r
1386 (VOID **)&BaseAddr,\r
1387 0\r
1388 );\r
490b5ea1 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
1436aea4 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
1436aea4 1408 PciIo->FreeBuffer (PciIo, RealPageCount, (VOID *)(UINTN)BaseAddr);\r
490b5ea1 1409 return EFI_OUT_OF_RESOURCES;\r
1410 }\r
a41b5272 1411\r
1436aea4 1412 ZeroMem ((VOID *)((UINTN)BaseAddr), ByteCount);\r
51492422
FT
1413\r
1414 //\r
1415 // Calculate the 64K align address as PRD Table base address.\r
1416 //\r
1417 AlignmentMask = SIZE_64KB - 1;\r
1436aea4
MK
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
1436aea4 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
1436aea4 1455 TempPrdBaseAddr = (EFI_ATA_DMA_PRD *)(UINTN)PrdTableBaseAddr;\r
490b5ea1 1456 while (ByteRemaining != 0) {\r
1457 if (ByteRemaining <= 0x10000) {\r
1436aea4
MK
1458 TempPrdBaseAddr->RegionBaseAddr = (UINT32)((UINTN)BufferMapAddress);\r
1459 TempPrdBaseAddr->ByteCount = (UINT16)ByteRemaining;\r
2525e221 1460 TempPrdBaseAddr->EndOfTable = 0x8000;\r
490b5ea1 1461 break;\r
1462 }\r
a41b5272 1463\r
1436aea4
MK
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
1436aea4 1488 RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);\r
490b5ea1 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
1436aea4 1500 RegisterValue = IdeReadPortB (PciIo, IoPortForBmic);\r
490b5ea1 1501 if (Read) {\r
1502 RegisterValue |= BMIC_NREAD;\r
1503 } else {\r
1436aea4 1504 RegisterValue &= ~((UINT8)BMIC_NREAD);\r
490b5ea1 1505 }\r
1436aea4 1506\r
490b5ea1 1507 IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);\r
a41b5272 1508\r
1aff716a 1509 if (Task != NULL) {\r
1aff716a 1510 Task->Map = BufferMap;\r
1511 Task->TableMap = PrdTableMap;\r
1436aea4 1512 Task->MapBaseAddress = (EFI_ATA_DMA_PRD *)(UINTN)BaseAddr;\r
51492422 1513 Task->PageCount = RealPageCount;\r
1aff716a 1514 Task->IsStart = TRUE;\r
1515 }\r
1516\r
490b5ea1 1517 //\r
1518 // Issue ATA command\r
1519 //\r
1520 Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
a41b5272 1521\r
490b5ea1 1522 if (EFI_ERROR (Status)) {\r
1523 Status = EFI_DEVICE_ERROR;\r
1524 goto Exit;\r
1525 }\r
a41b5272 1526\r
8536cc4b 1527 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1528 if (EFI_ERROR (Status)) {\r
1529 Status = EFI_DEVICE_ERROR;\r
1530 goto Exit;\r
1531 }\r
1436aea4 1532\r
490b5ea1 1533 //\r
1534 // Set START bit of BMIC register\r
1535 //\r
1436aea4 1536 RegisterValue = IdeReadPortB (PciIo, IoPortForBmic);\r
490b5ea1 1537 RegisterValue |= BMIC_START;\r
1436aea4 1538 IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);\r
a41b5272 1539 }\r
1540\r
a41b5272 1541 //\r
1542 // Check the INTERRUPT and ERROR bit of BMIS\r
a41b5272 1543 //\r
490b5ea1 1544 if (Task != NULL) {\r
8536cc4b 1545 Status = AtaUdmStatusCheck (PciIo, Task, IdeRegisters);\r
490b5ea1 1546 } else {\r
ab82122d 1547 Status = AtaUdmStatusWait (PciIo, IdeRegisters, Timeout);\r
a41b5272 1548 }\r
1549\r
1550 //\r
490b5ea1 1551 // For blocking mode, clear registers and free buffers.\r
1552 // For non blocking mode, when the related registers have been set or time\r
1553 // out, or a error has been happened, it needs to clear the register and free\r
1554 // buffer.\r
a41b5272 1555 //\r
1436aea4 1556 if ((Task == NULL) || (Status != EFI_NOT_READY)) {\r
490b5ea1 1557 //\r
1558 // Read BMIS register and clear ERROR and INTR bit\r
1559 //\r
1560 RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);\r
1561 RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
1562 IdeWritePortB (PciIo, IoPortForBmis, RegisterValue);\r
a41b5272 1563\r
490b5ea1 1564 //\r
1565 // Read Status Register of IDE device to clear interrupt\r
1566 //\r
1436aea4 1567 RegisterValue = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
a41b5272 1568\r
490b5ea1 1569 //\r
1570 // Clear START bit of BMIC register\r
1571 //\r
1436aea4
MK
1572 RegisterValue = IdeReadPortB (PciIo, IoPortForBmic);\r
1573 RegisterValue &= ~((UINT8)BMIC_START);\r
490b5ea1 1574 IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);\r
a41b5272 1575\r
490b5ea1 1576 //\r
1577 // Disable interrupt of Select device\r
1578 //\r
1579 DeviceControl = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
1580 DeviceControl |= ATA_CTLREG_IEN_L;\r
1581 IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
1582 //\r
1583 // Stall for 10 milliseconds.\r
1584 //\r
1585 MicroSecondDelay (10000);\r
490b5ea1 1586 }\r
a41b5272 1587\r
1588Exit:\r
1589 //\r
1590 // Free all allocated resource\r
1591 //\r
1436aea4 1592 if ((Task == NULL) || (Status != EFI_NOT_READY)) {\r
490b5ea1 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
1436aea4 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
1436aea4
MK
1625 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1626 IN EFI_IDE_REGISTERS *IdeRegisters\r
a41b5272 1627 )\r
1628{\r
1436aea4
MK
1629 UINT8 AltRegister;\r
1630 UINT16 TempWordBuffer;\r
a41b5272 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
1436aea4 1649\r
a41b5272 1650 return EFI_SUCCESS;\r
1651}\r
1652\r
1653/**\r
1aff716a 1654 This function is called by AtaPacketCommandExecute().\r
a41b5272 1655 It is used to transfer data between host and device. The data direction is specified\r
1656 by the fourth parameter.\r
1657\r
1658 @param PciIo A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
1659 @param IdeRegisters A pointer to EFI_IDE_REGISTERS data structure.\r
1660 @param Buffer Buffer contained data transferred between host and device.\r
1661 @param ByteCount Data size in byte unit of the buffer.\r
1662 @param Read Flag used to determine the data transfer direction.\r
1663 Read equals 1, means data transferred from device to host;\r
1664 Read equals 0, means data transferred from host to device.\r
8536cc4b 1665 @param Timeout Timeout value for wait DRQ ready before each data stream's transfer\r
1666 , uses 100ns as a unit.\r
a41b5272 1667\r
1668 @retval EFI_SUCCESS data is transferred successfully.\r
1669 @retval EFI_DEVICE_ERROR the device failed to transfer data.\r
1670**/\r
1671EFI_STATUS\r
1672EFIAPI\r
1673AtaPacketReadWrite (\r
1436aea4
MK
1674 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1675 IN EFI_IDE_REGISTERS *IdeRegisters,\r
1676 IN OUT VOID *Buffer,\r
1677 IN OUT UINT32 *ByteCount,\r
1678 IN BOOLEAN Read,\r
1679 IN UINT64 Timeout\r
a41b5272 1680 )\r
1681{\r
1682 UINT32 RequiredWordCount;\r
1683 UINT32 ActualWordCount;\r
1684 UINT32 WordCount;\r
1685 EFI_STATUS Status;\r
1686 UINT16 *PtrBuffer;\r
1687\r
f6a683e0
PB
1688 PtrBuffer = Buffer;\r
1689 RequiredWordCount = *ByteCount >> 1;\r
1690\r
a41b5272 1691 //\r
8c39253d 1692 // No data transfer is permitted.\r
a41b5272 1693 //\r
f6a683e0 1694 if (RequiredWordCount == 0) {\r
a41b5272 1695 return EFI_SUCCESS;\r
1696 }\r
1aff716a 1697\r
a41b5272 1698 //\r
f6a683e0 1699 // ActualWordCount means the word count of data really transferred.\r
a41b5272 1700 //\r
1701 ActualWordCount = 0;\r
1702\r
1703 while (ActualWordCount < RequiredWordCount) {\r
1704 //\r
1705 // before each data transfer stream, the host should poll DRQ bit ready,\r
1706 // to see whether indicates device is ready to transfer data.\r
1707 //\r
1708 Status = DRQReady2 (PciIo, IdeRegisters, Timeout);\r
1709 if (EFI_ERROR (Status)) {\r
f6a683e0
PB
1710 if (Status == EFI_NOT_READY) {\r
1711 //\r
1712 // Device provided less data than we intended to read, or wanted less\r
1713 // data than we intended to write, but it may still be successful.\r
1714 //\r
1715 break;\r
1716 } else {\r
1717 return Status;\r
1718 }\r
a41b5272 1719 }\r
1720\r
1721 //\r
1722 // get current data transfer size from Cylinder Registers.\r
1723 //\r
1724 WordCount = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb) << 8;\r
1725 WordCount = WordCount | IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
1726 WordCount = WordCount & 0xffff;\r
1727 WordCount /= 2;\r
1728\r
1729 WordCount = MIN (WordCount, (RequiredWordCount - ActualWordCount));\r
1730\r
1731 if (Read) {\r
1732 IdeReadPortWMultiple (\r
1733 PciIo,\r
1734 IdeRegisters->Data,\r
1735 WordCount,\r
1736 PtrBuffer\r
1737 );\r
1738 } else {\r
1739 IdeWritePortWMultiple (\r
1740 PciIo,\r
1741 IdeRegisters->Data,\r
1742 WordCount,\r
1743 PtrBuffer\r
1744 );\r
1745 }\r
1746\r
1747 //\r
1748 // read status register to check whether error happens.\r
1749 //\r
1750 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1751 if (EFI_ERROR (Status)) {\r
1752 return EFI_DEVICE_ERROR;\r
1753 }\r
1754\r
1755 PtrBuffer += WordCount;\r
1756 ActualWordCount += WordCount;\r
1757 }\r
1aff716a 1758\r
a41b5272 1759 if (Read) {\r
1760 //\r
1761 // In the case where the drive wants to send more data than we need to read,\r
1762 // the DRQ bit will be set and cause delays from DRQClear2().\r
1763 // We need to read data from the drive until it clears DRQ so we can move on.\r
1764 //\r
1765 AtaPacketReadPendingData (PciIo, IdeRegisters);\r
1766 }\r
1767\r
1768 //\r
1769 // read status register to check whether error happens.\r
1770 //\r
1771 Status = CheckStatusRegister (PciIo, IdeRegisters);\r
1772 if (EFI_ERROR (Status)) {\r
1773 return EFI_DEVICE_ERROR;\r
1774 }\r
1775\r
1776 //\r
1777 // After data transfer is completed, normally, DRQ bit should clear.\r
1778 //\r
8536cc4b 1779 Status = DRQClear (PciIo, IdeRegisters, Timeout);\r
a41b5272 1780 if (EFI_ERROR (Status)) {\r
1781 return EFI_DEVICE_ERROR;\r
1782 }\r
1aff716a 1783\r
f6a683e0 1784 *ByteCount = ActualWordCount << 1;\r
a41b5272 1785 return Status;\r
1786}\r
1787\r
a41b5272 1788/**\r
1aff716a 1789 This function is used to send out ATAPI commands conforms to the Packet Command\r
a41b5272 1790 with PIO Data In Protocol.\r
1791\r
1792 @param[in] PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
1793 @param[in] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to\r
1794 store the IDE i/o port registers' base addresses\r
1795 @param[in] Channel The channel number of device.\r
1796 @param[in] Device The device number of device.\r
1797 @param[in] Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.\r
1798\r
1799 @retval EFI_SUCCESS send out the ATAPI packet command successfully\r
1800 and device sends data successfully.\r
1801 @retval EFI_DEVICE_ERROR the device failed to send data.\r
1802\r
1803**/\r
1804EFI_STATUS\r
1805EFIAPI\r
1806AtaPacketCommandExecute (\r
1436aea4
MK
1807 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1808 IN EFI_IDE_REGISTERS *IdeRegisters,\r
1809 IN UINT8 Channel,\r
1810 IN UINT8 Device,\r
1811 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
a41b5272 1812 )\r
1813{\r
1436aea4
MK
1814 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1815 EFI_STATUS Status;\r
1816 UINT8 Count;\r
1817 UINT8 PacketCommand[12];\r
a41b5272 1818\r
1819 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1820\r
1821 //\r
1822 // Fill ATAPI Command Packet according to CDB.\r
1823 // For Atapi cmd, its length should be less than or equal to 12 bytes.\r
1824 //\r
1825 if (Packet->CdbLength > 12) {\r
1826 return EFI_INVALID_PARAMETER;\r
1827 }\r
1828\r
1829 ZeroMem (PacketCommand, 12);\r
1830 CopyMem (PacketCommand, Packet->Cdb, Packet->CdbLength);\r
1831\r
1832 //\r
1833 // No OVL; No DMA\r
1834 //\r
1835 AtaCommandBlock.AtaFeatures = 0x00;\r
1836 //\r
1837 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
1838 // determine how many data should be transferred.\r
1839 //\r
1436aea4
MK
1840 AtaCommandBlock.AtaCylinderLow = (UINT8)(ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
1841 AtaCommandBlock.AtaCylinderHigh = (UINT8)(ATAPI_MAX_BYTE_COUNT >> 8);\r
1842 AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
a41b5272 1843 AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;\r
1844\r
1845 IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | (Device << 0x4)));\r
1846 //\r
1847 // Disable interrupt\r
1848 //\r
1849 IdeWritePortB (PciIo, IdeRegisters->AltOrDev, ATA_DEFAULT_CTL);\r
1850\r
1851 //\r
1852 // Issue ATA PACKET command firstly\r
1853 //\r
1854 Status = AtaIssueCommand (PciIo, IdeRegisters, &AtaCommandBlock, Packet->Timeout);\r
1855 if (EFI_ERROR (Status)) {\r
1856 return Status;\r
1857 }\r
1858\r
1859 Status = DRQReady (PciIo, IdeRegisters, Packet->Timeout);\r
1860 if (EFI_ERROR (Status)) {\r
1861 return Status;\r
1862 }\r
1863\r
1864 //\r
1865 // Send out ATAPI command packet\r
1866 //\r
1867 for (Count = 0; Count < 6; Count++) {\r
1436aea4 1868 IdeWritePortW (PciIo, IdeRegisters->Data, *((UINT16 *)PacketCommand + Count));\r
a41b5272 1869 //\r
1870 // Stall for 10 microseconds.\r
1871 //\r
1872 MicroSecondDelay (10);\r
1873 }\r
1874\r
1875 //\r
1876 // Read/Write the data of ATAPI Command\r
1877 //\r
1878 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
73a9e822
TF
1879 Status = AtaPacketReadWrite (\r
1880 PciIo,\r
1881 IdeRegisters,\r
1882 Packet->InDataBuffer,\r
f6a683e0 1883 &Packet->InTransferLength,\r
73a9e822
TF
1884 TRUE,\r
1885 Packet->Timeout\r
1886 );\r
a41b5272 1887 } else {\r
73a9e822
TF
1888 Status = AtaPacketReadWrite (\r
1889 PciIo,\r
1890 IdeRegisters,\r
1891 Packet->OutDataBuffer,\r
f6a683e0 1892 &Packet->OutTransferLength,\r
73a9e822
TF
1893 FALSE,\r
1894 Packet->Timeout\r
1895 );\r
a41b5272 1896 }\r
1897\r
73a9e822 1898 return Status;\r
a41b5272 1899}\r
1900\r
a41b5272 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
1436aea4
MK
1925 EFI_STATUS Status;\r
1926 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
a41b5272 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
1436aea4
MK
1974 EFI_STATUS Status;\r
1975 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
a41b5272 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
1436aea4 1981 AtaCommandBlock.AtaDeviceHead = (UINT8)((Device << 0x4) + DriveParameters->Heads);\r
a41b5272 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
1436aea4
MK
2035 EFI_STATUS Status;\r
2036 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2037 UINT8 LBAMid;\r
2038 UINT8 LBAHigh;\r
12873d57 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
1436aea4 2046 AtaCommandBlock.AtaDeviceHead = (UINT8)((Device << 0x4) | 0xe0);\r
12873d57 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
87000d77 2080 DEBUG ((DEBUG_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
cffd2171 2081 REPORT_STATUS_CODE (\r
1436aea4
MK
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
87000d77 2089 DEBUG ((DEBUG_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
cffd2171 2090 REPORT_STATUS_CODE (\r
1436aea4
MK
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
1436aea4
MK
2119 EFI_STATUS Status;\r
2120 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
12873d57 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
1436aea4
MK
2129 DEBUG ((\r
2130 DEBUG_INFO,\r
2131 "S.M.A.R.T feature is not supported at [%a] channel [%a] device!\n",\r
2132 (Channel == 1) ? "secondary" : "primary",\r
2133 (Device == 1) ? "slave" : "master"\r
2134 ));\r
cffd2171
EL
2135 REPORT_STATUS_CODE (\r
2136 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
2137 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
2138 );\r
12873d57 2139 } else {\r
2140 //\r
2141 // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
2142 //\r
2143 if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
cffd2171
EL
2144 REPORT_STATUS_CODE (\r
2145 EFI_PROGRESS_CODE,\r
2146 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)\r
2147 );\r
2148\r
12873d57 2149 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2150\r
2151 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
2152 AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;\r
2153 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
2154 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1436aea4 2155 AtaCommandBlock.AtaDeviceHead = (UINT8)((Device << 0x4) | 0xe0);\r
12873d57 2156\r
2157 //\r
2158 // Send S.M.A.R.T Enable command to device\r
2159 //\r
2160 Status = AtaNonDataCommandIn (\r
2161 Instance->PciIo,\r
2162 &Instance->IdeRegisters[Channel],\r
2163 &AtaCommandBlock,\r
2164 AtaStatusBlock,\r
490b5ea1 2165 ATA_ATAPI_TIMEOUT,\r
2166 NULL\r
12873d57 2167 );\r
2168\r
2169 if (!EFI_ERROR (Status)) {\r
2170 //\r
2171 // Send S.M.A.R.T AutoSave command to device\r
2172 //\r
2173 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
2174\r
2175 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
2176 AtaCommandBlock.AtaFeatures = 0xD2;\r
2177 AtaCommandBlock.AtaSectorCount = 0xF1;\r
2178 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
2179 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1436aea4 2180 AtaCommandBlock.AtaDeviceHead = (UINT8)((Device << 0x4) | 0xe0);\r
12873d57 2181\r
2182 Status = AtaNonDataCommandIn (\r
2183 Instance->PciIo,\r
2184 &Instance->IdeRegisters[Channel],\r
2185 &AtaCommandBlock,\r
2186 AtaStatusBlock,\r
490b5ea1 2187 ATA_ATAPI_TIMEOUT,\r
2188 NULL\r
12873d57 2189 );\r
2190 if (!EFI_ERROR (Status)) {\r
2191 Status = IdeAtaSmartReturnStatusCheck (\r
2192 Instance,\r
2193 Channel,\r
2194 Device,\r
2195 AtaStatusBlock\r
2196 );\r
2197 }\r
2198 }\r
2199 }\r
2200\r
1436aea4
MK
2201 DEBUG ((\r
2202 DEBUG_INFO,\r
2203 "Enabled S.M.A.R.T feature at [%a] channel [%a] device!\n",\r
2204 (Channel == 1) ? "secondary" : "primary",\r
2205 (Device == 1) ? "slave" : "master"\r
2206 ));\r
12873d57 2207 }\r
2208\r
1436aea4 2209 return;\r
12873d57 2210}\r
2211\r
a41b5272 2212/**\r
2213 Sends out an ATA Identify Command to the specified device.\r
2214\r
2215 This function is called by DiscoverIdeDevice() during its device\r
2216 identification. It sends out the ATA Identify Command to the\r
2217 specified device. Only ATA device responses to this command. If\r
2218 the command succeeds, it returns the Identify data structure which\r
2219 contains information about the device. This function extracts the\r
2220 information it needs to fill the IDE_BLK_IO_DEV data structure,\r
2221 including device type, media block size, media capacity, and etc.\r
2222\r
2223 @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
2224 @param Channel The channel number of device.\r
2225 @param Device The device number of device.\r
2226 @param Buffer A pointer to data buffer which is used to contain IDENTIFY data.\r
2227 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
2228\r
2229 @retval EFI_SUCCESS Identify ATA device successfully.\r
2230 @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.\r
2231 @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
490b5ea1 2232\r
a41b5272 2233**/\r
2234EFI_STATUS\r
2235EFIAPI\r
2236AtaIdentify (\r
2237 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
2238 IN UINT8 Channel,\r
2239 IN UINT8 Device,\r
2240 IN OUT EFI_IDENTIFY_DATA *Buffer,\r
2241 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
2242 )\r
2243{\r
2244 EFI_STATUS Status;\r
490b5ea1 2245 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
a41b5272 2246\r
2247 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
490b5ea1 2248\r
a41b5272 2249 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
2250 AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
2251\r
2252 Status = AtaPioDataInOut (\r
2253 Instance->PciIo,\r
2254 &Instance->IdeRegisters[Channel],\r
2255 Buffer,\r
2256 sizeof (EFI_IDENTIFY_DATA),\r
2257 TRUE,\r
2258 &AtaCommandBlock,\r
2259 AtaStatusBlock,\r
490b5ea1 2260 ATA_ATAPI_TIMEOUT,\r
2261 NULL\r
a41b5272 2262 );\r
2263\r
2264 return Status;\r
2265}\r
2266\r
2267/**\r
2268 This function is called by DiscoverIdeDevice() during its device\r
2269 identification.\r
2270 Its main purpose is to get enough information for the device media\r
2271 to fill in the Media data structure of the Block I/O Protocol interface.\r
2272\r
2273 There are 5 steps to reach such objective:\r
1aff716a 2274 1. Sends out the ATAPI Identify Command to the specified device.\r
a41b5272 2275 Only ATAPI device responses to this command. If the command succeeds,\r
1aff716a 2276 it returns the Identify data structure which filled with information\r
2277 about the device. Since the ATAPI device contains removable media,\r
a41b5272 2278 the only meaningful information is the device module name.\r
2279 2. Sends out ATAPI Inquiry Packet Command to the specified device.\r
2280 This command will return inquiry data of the device, which contains\r
2281 the device type information.\r
2282 3. Allocate sense data space for future use. We don't detect the media\r
1aff716a 2283 presence here to improvement boot performance, especially when CD\r
a41b5272 2284 media is present. The media detection will be performed just before\r
2285 each BLK_IO read/write\r
1aff716a 2286\r
a41b5272 2287 @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
2288 @param Channel The channel number of device.\r
2289 @param Device The device number of device.\r
2290 @param Buffer A pointer to data buffer which is used to contain IDENTIFY data.\r
2291 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
2292\r
2293 @retval EFI_SUCCESS Identify ATAPI device successfully.\r
2294 @retval EFI_DEVICE_ERROR ATA Identify Packet Device Command failed or device type\r
2295 is not supported by this IDE driver.\r
2296 @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
2297\r
2298**/\r
2299EFI_STATUS\r
2300EFIAPI\r
2301AtaIdentifyPacket (\r
2302 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
2303 IN UINT8 Channel,\r
2304 IN UINT8 Device,\r
2305 IN OUT EFI_IDENTIFY_DATA *Buffer,\r
2306 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
2307 )\r
2308{\r
2309 EFI_STATUS Status;\r
2310 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
2311\r
2312 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1aff716a 2313\r
a41b5272 2314 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DEVICE;\r
2315 AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
2316\r
2317 //\r
2318 // Send ATAPI Identify Command to get IDENTIFY data.\r
2319 //\r
2320 Status = AtaPioDataInOut (\r
2321 Instance->PciIo,\r
2322 &Instance->IdeRegisters[Channel],\r
1436aea4 2323 (VOID *)Buffer,\r
a41b5272 2324 sizeof (EFI_IDENTIFY_DATA),\r
2325 TRUE,\r
2326 &AtaCommandBlock,\r
2327 AtaStatusBlock,\r
490b5ea1 2328 ATA_ATAPI_TIMEOUT,\r
2329 NULL\r
a41b5272 2330 );\r
2331\r
2332 return Status;\r
2333}\r
2334\r
a41b5272 2335/**\r
2336 This function is used for detect whether the IDE device exists in the\r
2337 specified Channel as the specified Device Number.\r
2338\r
2339 There is two IDE channels: one is Primary Channel, the other is\r
2340 Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
2341 Different channel has different register group.\r
2342\r
2343 On each IDE channel, at most two IDE devices attach,\r
2344 one is called Device 0 (Master device), the other is called Device 1\r
2345 (Slave device). The devices on the same channel co-use the same register\r
2346 group, so before sending out a command for a specified device via command\r
2347 register, it is a must to select the current device to accept the command\r
2348 by set the device number in the Head/Device Register.\r
2349\r
2350 @param Instance A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
2351 @param IdeChannel The channel number of device.\r
2352\r
2353 @retval EFI_SUCCESS successfully detects device.\r
2354 @retval other any failure during detection process will return this value.\r
2355\r
2356**/\r
2357EFI_STATUS\r
2358EFIAPI\r
2359DetectAndConfigIdeDevice (\r
2360 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
2361 IN UINT8 IdeChannel\r
2362 )\r
2363{\r
1436aea4
MK
2364 EFI_STATUS Status;\r
2365 UINT8 SectorCountReg;\r
2366 UINT8 LBALowReg;\r
2367 UINT8 LBAMidReg;\r
2368 UINT8 LBAHighReg;\r
2369 EFI_ATA_DEVICE_TYPE DeviceType;\r
2370 UINT8 IdeDevice;\r
2371 EFI_IDE_REGISTERS *IdeRegisters;\r
2372 EFI_IDENTIFY_DATA Buffer;\r
a41b5272 2373\r
2374 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2375 EFI_PCI_IO_PROTOCOL *PciIo;\r
2376\r
1436aea4
MK
2377 EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
2378 EFI_ATA_TRANSFER_MODE TransferMode;\r
2379 EFI_ATA_DRIVE_PARMS DriveParameters;\r
a41b5272 2380\r
2381 IdeRegisters = &Instance->IdeRegisters[IdeChannel];\r
2382 IdeInit = Instance->IdeControllerInit;\r
2383 PciIo = Instance->PciIo;\r
2384\r
490b5ea1 2385 for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {\r
2dc5090d
RJ
2386 //\r
2387 // Select Master or Slave device to get the return signature for ATA DEVICE DIAGNOSTIC cmd.\r
2388 //\r
2389 IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)((IdeDevice << 4) | 0xe0));\r
2390\r
a41b5272 2391 //\r
2392 // Send ATA Device Execut Diagnostic command.\r
2393 // This command should work no matter DRDY is ready or not\r
2394 //\r
2395 IdeWritePortB (PciIo, IdeRegisters->CmdOrStatus, ATA_CMD_EXEC_DRIVE_DIAG);\r
1aff716a 2396\r
a41b5272 2397 Status = WaitForBSYClear (PciIo, IdeRegisters, 350000000);\r
2398 if (EFI_ERROR (Status)) {\r
1436aea4 2399 DEBUG ((DEBUG_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
a41b5272 2400 continue;\r
2401 }\r
2402\r
2403 //\r
2404 // Select Master or Slave device to get the return signature for ATA DEVICE DIAGNOSTIC cmd.\r
2405 //\r
2406 IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)((IdeDevice << 4) | 0xe0));\r
2407 //\r
2408 // Stall for 1 milliseconds.\r
2409 //\r
2410 MicroSecondDelay (1000);\r
2411\r
2412 SectorCountReg = IdeReadPortB (PciIo, IdeRegisters->SectorCount);\r
2413 LBALowReg = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);\r
2414 LBAMidReg = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
2415 LBAHighReg = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);\r
2416\r
2417 //\r
2418 // Refer to ATA/ATAPI 4 Spec, section 9.1\r
2419 //\r
2420 if ((SectorCountReg == 0x1) && (LBALowReg == 0x1) && (LBAMidReg == 0x0) && (LBAHighReg == 0x0)) {\r
2421 DeviceType = EfiIdeHarddisk;\r
2422 } else if ((LBAMidReg == 0x14) && (LBAHighReg == 0xeb)) {\r
2423 DeviceType = EfiIdeCdrom;\r
2424 } else {\r
2425 continue;\r
2426 }\r
2427\r
2428 //\r
2429 // Send IDENTIFY cmd to the device to test if it is really attached.\r
2430 //\r
2431 if (DeviceType == EfiIdeHarddisk) {\r
2432 Status = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
2433 //\r
2434 // if identifying ata device is failure, then try to send identify packet cmd.\r
2435 //\r
2436 if (EFI_ERROR (Status)) {\r
3d0a2385 2437 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
2438\r
a41b5272 2439 DeviceType = EfiIdeCdrom;\r
2440 Status = AtaIdentifyPacket (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
2441 }\r
2442 } else {\r
2443 Status = AtaIdentifyPacket (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
2444 //\r
2445 // if identifying atapi device is failure, then try to send identify cmd.\r
2446 //\r
2447 if (EFI_ERROR (Status)) {\r
2448 DeviceType = EfiIdeHarddisk;\r
2449 Status = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
490b5ea1 2450 }\r
a41b5272 2451 }\r
2452\r
2453 if (EFI_ERROR (Status)) {\r
2454 //\r
2455 // No device is found at this port\r
2456 //\r
2457 continue;\r
490b5ea1 2458 }\r
2459\r
1436aea4
MK
2460 DEBUG ((\r
2461 DEBUG_INFO,\r
2462 "[%a] channel [%a] [%a] device\n",\r
2463 (IdeChannel == 1) ? "secondary" : "primary ",\r
2464 (IdeDevice == 1) ? "slave " : "master",\r
2465 DeviceType == EfiIdeCdrom ? "cdrom " : "harddisk"\r
2466 ));\r
12873d57 2467 //\r
2468 // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
2469 //\r
fc80ee69 2470 if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {\r
12873d57 2471 IdeAtaSmartSupport (\r
2472 Instance,\r
2473 IdeChannel,\r
2474 IdeDevice,\r
2475 &Buffer,\r
2476 NULL\r
2477 );\r
2478 }\r
2479\r
a41b5272 2480 //\r
2481 // Submit identify data to IDE controller init driver\r
2482 //\r
2483 IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &Buffer);\r
2484\r
2485 //\r
2486 // Now start to config ide device parameter and transfer mode.\r
2487 //\r
2488 Status = IdeInit->CalculateMode (\r
2489 IdeInit,\r
2490 IdeChannel,\r
2491 IdeDevice,\r
2492 &SupportedModes\r
2493 );\r
2494 if (EFI_ERROR (Status)) {\r
87000d77 2495 DEBUG ((DEBUG_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
a41b5272 2496 continue;\r
2497 }\r
2498\r
2499 //\r
2500 // Set best supported PIO mode on this IDE device\r
2501 //\r
2502 if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
2503 TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
2504 } else {\r
2505 TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
2506 }\r
2507\r
1436aea4 2508 TransferMode.ModeNumber = (UINT8)(SupportedModes->PioMode.Mode);\r
a41b5272 2509\r
1436aea4 2510 if (SupportedModes->ExtModeCount == 0) {\r
a41b5272 2511 Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
2512\r
2513 if (EFI_ERROR (Status)) {\r
87000d77 2514 DEBUG ((DEBUG_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
a41b5272 2515 continue;\r
2516 }\r
2517 }\r
490b5ea1 2518\r
a41b5272 2519 //\r
8c39253d 2520 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA can't\r
a41b5272 2521 // be set together. Only one DMA mode can be set to a device. If setting\r
2522 // DMA mode operation fails, we can continue moving on because we only use\r
2523 // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
2524 //\r
2525 if (SupportedModes->UdmaMode.Valid) {\r
2526 TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
1436aea4
MK
2527 TransferMode.ModeNumber = (UINT8)(SupportedModes->UdmaMode.Mode);\r
2528 Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
490b5ea1 2529\r
a41b5272 2530 if (EFI_ERROR (Status)) {\r
87000d77 2531 DEBUG ((DEBUG_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
a41b5272 2532 continue;\r
2533 }\r
2534 } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
2535 TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
1436aea4
MK
2536 TransferMode.ModeNumber = (UINT8)SupportedModes->MultiWordDmaMode.Mode;\r
2537 Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
490b5ea1 2538\r
a41b5272 2539 if (EFI_ERROR (Status)) {\r
87000d77 2540 DEBUG ((DEBUG_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
a41b5272 2541 continue;\r
2542 }\r
2543 }\r
490b5ea1 2544\r
a41b5272 2545 //\r
2546 // Set Parameters for the device:\r
2547 // 1) Init\r
2548 // 2) Establish the block count for READ/WRITE MULTIPLE (EXT) command\r
2549 //\r
2550 if (DeviceType == EfiIdeHarddisk) {\r
2551 //\r
2552 // Init driver parameters\r
2553 //\r
1436aea4
MK
2554 DriveParameters.Sector = (UINT8)((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->sectors_per_track;\r
2555 DriveParameters.Heads = (UINT8)(((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->heads - 1);\r
2556 DriveParameters.MultipleSector = (UINT8)((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->multi_sector_cmd_max_sct_cnt;\r
490b5ea1 2557\r
a41b5272 2558 Status = SetDriveParameters (Instance, IdeChannel, IdeDevice, &DriveParameters, NULL);\r
2559 }\r
490b5ea1 2560\r
a41b5272 2561 //\r
2562 // Set IDE controller Timing Blocks in the PCI Configuration Space\r
2563 //\r
2564 IdeInit->SetTiming (IdeInit, IdeChannel, IdeDevice, SupportedModes);\r
2565\r
2566 //\r
2567 // IDE controller and IDE device timing is configured successfully.\r
2568 // Now insert the device into device list.\r
2569 //\r
2570 Status = CreateNewDeviceInfo (Instance, IdeChannel, IdeDevice, DeviceType, &Buffer);\r
2571 if (EFI_ERROR (Status)) {\r
2572 continue;\r
2573 }\r
3d0a2385 2574\r
2575 if (DeviceType == EfiIdeHarddisk) {\r
2576 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
2577 }\r
a41b5272 2578 }\r
1436aea4 2579\r
a41b5272 2580 return EFI_SUCCESS;\r
2581}\r
2582\r
a41b5272 2583/**\r
2584 Initialize ATA host controller at IDE mode.\r
1aff716a 2585\r
2586 The function is designed to initialize ATA host controller.\r
2587\r
a41b5272 2588 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
2589\r
2590**/\r
2591EFI_STATUS\r
2592EFIAPI\r
2593IdeModeInitialization (\r
1436aea4 2594 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance\r
a41b5272 2595 )\r
2596{\r
a41b5272 2597 EFI_STATUS Status;\r
2598 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2599 EFI_PCI_IO_PROTOCOL *PciIo;\r
2600 UINT8 Channel;\r
2601 UINT8 IdeChannel;\r
2602 BOOLEAN ChannelEnabled;\r
2603 UINT8 MaxDevices;\r
2604\r
2605 IdeInit = Instance->IdeControllerInit;\r
2606 PciIo = Instance->PciIo;\r
a41b5272 2607 Channel = IdeInit->ChannelCount;\r
2608\r
2609 //\r
2610 // Obtain IDE IO port registers' base addresses\r
2611 //\r
2612 Status = GetIdeRegisterIoAddr (PciIo, Instance->IdeRegisters);\r
2613 if (EFI_ERROR (Status)) {\r
2614 goto ErrorExit;\r
2615 }\r
2616\r
2617 for (IdeChannel = 0; IdeChannel < Channel; IdeChannel++) {\r
2618 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, IdeChannel);\r
2619\r
2620 //\r
2621 // now obtain channel information fron IdeControllerInit protocol.\r
2622 //\r
2623 Status = IdeInit->GetChannelInfo (\r
2624 IdeInit,\r
2625 IdeChannel,\r
2626 &ChannelEnabled,\r
2627 &MaxDevices\r
2628 );\r
2629 if (EFI_ERROR (Status)) {\r
87000d77 2630 DEBUG ((DEBUG_ERROR, "[GetChannel, Status=%x]", Status));\r
a41b5272 2631 continue;\r
2632 }\r
2633\r
2634 if (!ChannelEnabled) {\r
2635 continue;\r
2636 }\r
2637\r
2638 ASSERT (MaxDevices <= 2);\r
2639 //\r
2640 // Now inform the IDE Controller Init Module.\r
2641 //\r
2642 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelReset, IdeChannel);\r
2643\r
2644 //\r
2645 // No reset channel function implemented.\r
2646 //\r
2647 IdeInit->NotifyPhase (IdeInit, EfiIdeAfterChannelReset, IdeChannel);\r
2648\r
2649 //\r
2650 // Now inform the IDE Controller Init Module.\r
2651 //\r
2652 IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, IdeChannel);\r
2653\r
2654 //\r
2655 // Detect all attached ATA devices and set the transfer mode for each device.\r
2656 //\r
2657 DetectAndConfigIdeDevice (Instance, IdeChannel);\r
2658 }\r
2659\r
2660 //\r
2661 // All configurations done! Notify IdeController to do post initialization\r
2662 // work such as saving IDE controller PCI settings for S3 resume\r
2663 //\r
2664 IdeInit->NotifyPhase (IdeInit, EfiIdeBusPhaseMaximum, 0);\r
2665\r
2666ErrorExit:\r
2667 return Status;\r
2668}\r