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