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