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