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