]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
fix a invalid pointer conversion when builing 32bit image.
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
CommitLineData
a41b5272 1/** @file\r
2 The file for AHCI mode of ATA host controller.\r
3 \r
e519983a 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 AHCI Operation register.\r
19\r
20 @param PciIo The PCI IO protocol instance.\r
21 @param Offset The operation register offset.\r
22\r
23 @return The register content read.\r
24\r
25**/\r
26UINT32\r
27EFIAPI\r
28AhciReadReg (\r
29 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
30 IN UINT32 Offset\r
31 )\r
32{\r
33 UINT32 Data;\r
34\r
35 ASSERT (PciIo != NULL);\r
36 \r
37 Data = 0;\r
38\r
39 PciIo->Mem.Read (\r
40 PciIo,\r
41 EfiPciIoWidthUint32,\r
42 EFI_AHCI_BAR_INDEX,\r
43 (UINT64) Offset,\r
44 1,\r
45 &Data\r
46 );\r
47\r
48 return Data;\r
49}\r
50\r
51/**\r
52 Write AHCI Operation register.\r
53\r
54 @param PciIo The PCI IO protocol instance.\r
55 @param Offset The operation register offset.\r
56 @param Data The data used to write down.\r
57\r
58**/\r
59VOID\r
60EFIAPI\r
61AhciWriteReg (\r
62 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
63 IN UINT32 Offset,\r
64 IN UINT32 Data\r
65 )\r
66{\r
67 ASSERT (PciIo != NULL);\r
68\r
69 PciIo->Mem.Write (\r
70 PciIo,\r
71 EfiPciIoWidthUint32,\r
72 EFI_AHCI_BAR_INDEX,\r
73 (UINT64) Offset,\r
74 1,\r
75 &Data\r
76 );\r
77\r
78 return ;\r
79}\r
80\r
81/**\r
82 Do AND operation with the value of AHCI Operation register.\r
83\r
84 @param PciIo The PCI IO protocol instance.\r
85 @param Offset The operation register offset.\r
86 @param AndData The data used to do AND operation.\r
87\r
88**/\r
89VOID\r
90EFIAPI\r
91AhciAndReg (\r
92 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
93 IN UINT32 Offset,\r
94 IN UINT32 AndData\r
95 )\r
96{\r
97 UINT32 Data;\r
98 \r
99 ASSERT (PciIo != NULL);\r
100\r
101 Data = AhciReadReg (PciIo, Offset);\r
102\r
103 Data &= AndData;\r
104\r
105 AhciWriteReg (PciIo, Offset, Data);\r
106}\r
107\r
108/**\r
109 Do OR operation with the value of AHCI Operation register.\r
110\r
111 @param PciIo The PCI IO protocol instance.\r
112 @param Offset The operation register offset.\r
113 @param OrData The data used to do OR operation.\r
114\r
115**/\r
116VOID\r
117EFIAPI\r
118AhciOrReg (\r
119 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
120 IN UINT32 Offset,\r
121 IN UINT32 OrData\r
122 )\r
123{\r
124 UINT32 Data;\r
125\r
126 ASSERT (PciIo != NULL);\r
127\r
128 Data = AhciReadReg (PciIo, Offset);\r
129\r
130 Data |= OrData;\r
131\r
132 AhciWriteReg (PciIo, Offset, Data);\r
133}\r
134\r
135/**\r
136 Wait for memory set to the test value.\r
137 \r
aca84419 138 @param PciIo The PCI IO protocol instance.\r
139 @param Offset The memory address to test.\r
140 @param MaskValue The mask value of memory.\r
141 @param TestValue The test value of memory.\r
142 @param Timeout The time out value for wait memory set.\r
a41b5272 143\r
144 @retval EFI_DEVICE_ERROR The memory is not set.\r
145 @retval EFI_TIMEOUT The memory setting is time out.\r
146 @retval EFI_SUCCESS The memory is correct set.\r
147\r
148**/\r
149EFI_STATUS\r
150EFIAPI\r
151AhciWaitMemSet (\r
152 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
153 IN UINT32 Offset,\r
154 IN UINT32 MaskValue,\r
155 IN UINT32 TestValue,\r
156 IN UINT64 Timeout\r
157 )\r
158{\r
159 UINT32 Value; \r
160 UINT32 Delay;\r
161\r
162 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
163\r
164 do {\r
165 Value = AhciReadReg (PciIo, Offset) & MaskValue;\r
166\r
167 if (Value == TestValue) {\r
168 return EFI_SUCCESS;\r
169 }\r
170\r
171 //\r
172 // Stall for 100 microseconds.\r
173 //\r
174 MicroSecondDelay (100);\r
175\r
176 Delay--;\r
177\r
178 } while (Delay > 0);\r
179\r
180 if (Delay == 0) {\r
181 return EFI_TIMEOUT;\r
182 }\r
183\r
184 return EFI_DEVICE_ERROR;\r
185}\r
186\r
187/**\r
188 Check if the device is still on port. It also checks if the AHCI controller \r
189 supports the address and data count will be transfered.\r
190\r
aca84419 191 @param PciIo The PCI IO protocol instance.\r
192 @param Port The number of port.\r
a41b5272 193\r
194 @retval EFI_SUCCESS The device is attached to port and the transfer data is \r
195 supported by AHCI controller.\r
196 @retval EFI_UNSUPPORTED The transfer address and count is not supported by AHCI\r
197 controller.\r
198 @retval EFI_NOT_READY The physical communication between AHCI controller and device\r
199 is not ready.\r
200\r
201**/\r
202EFI_STATUS\r
203EFIAPI\r
204AhciCheckDeviceStatus (\r
205 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
206 IN UINT8 Port\r
207 )\r
208{\r
209 UINT32 Data; \r
210 UINT32 Offset;\r
211\r
212 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
213\r
214 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
215\r
216 if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
217 return EFI_SUCCESS; \r
218 }\r
219\r
220 return EFI_NOT_READY;\r
221}\r
222\r
223/**\r
224\r
225 Clear the port interrupt and error status. It will also clear\r
226 HBA interrupt status.\r
227 \r
228 @param PciIo The PCI IO protocol instance.\r
229 @param Port The number of port.\r
230 \r
231**/ \r
232VOID\r
233EFIAPI\r
234AhciClearPortStatus (\r
235 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
236 IN UINT8 Port\r
237 ) \r
238{\r
239 UINT32 Offset;\r
240\r
241 //\r
242 // Clear any error status\r
243 // \r
244 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
245 AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
246\r
247 //\r
248 // Clear any port interrupt status\r
249 //\r
250 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
251 AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
252\r
253 //\r
254 // Clear any HBA interrupt status\r
255 //\r
256 AhciWriteReg (PciIo, EFI_AHCI_IS_OFFSET, AhciReadReg (PciIo, EFI_AHCI_IS_OFFSET));\r
257}\r
258\r
e519983a 259/**\r
260 This function is used to dump the Status Registers and if there is ERR bit set\r
261 in the Status Register, the Error Register's value is also be dumped.\r
262\r
263 @param PciIo The PCI IO protocol instance.\r
264 @param Port The number of port.\r
265 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
266\r
267**/\r
268VOID\r
269EFIAPI\r
270AhciDumpPortStatus (\r
271 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
272 IN UINT8 Port,\r
273 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
274 )\r
275{\r
276 UINT32 Offset;\r
277 UINT32 Data;\r
278\r
279 ASSERT (PciIo != NULL);\r
280\r
281 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
282 Data = AhciReadReg (PciIo, Offset);\r
283\r
284 if (AtaStatusBlock != NULL) {\r
285 ZeroMem (AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
286\r
287 AtaStatusBlock->AtaStatus = (UINT8)Data;\r
288 if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {\r
289 AtaStatusBlock->AtaError = (UINT8)(Data >> 8);\r
290 }\r
291 }\r
292}\r
293\r
294\r
a41b5272 295/**\r
296 Enable the FIS running for giving port.\r
297 \r
298 @param PciIo The PCI IO protocol instance.\r
299 @param Port The number of port.\r
300 @param Timeout The timeout value of enabling FIS.\r
301\r
302 @retval EFI_DEVICE_ERROR The FIS enable setting fails.\r
303 @retval EFI_TIMEOUT The FIS enable setting is time out.\r
304 @retval EFI_SUCCESS The FIS enable successfully.\r
305\r
306**/\r
307EFI_STATUS\r
308EFIAPI\r
309AhciEnableFisReceive (\r
310 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
311 IN UINT8 Port,\r
312 IN UINT64 Timeout\r
313 ) \r
314{ \r
315 UINT32 Offset;\r
316\r
317 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
318 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
319\r
320 return AhciWaitMemSet (\r
321 PciIo, \r
322 Offset,\r
323 EFI_AHCI_PORT_CMD_FR,\r
324 EFI_AHCI_PORT_CMD_FR,\r
325 Timeout\r
326 );\r
327}\r
328\r
329/**\r
330 Disable the FIS running for giving port.\r
331\r
332 @param PciIo The PCI IO protocol instance.\r
333 @param Port The number of port.\r
334 @param Timeout The timeout value of disabling FIS.\r
335\r
336 @retval EFI_DEVICE_ERROR The FIS disable setting fails.\r
337 @retval EFI_TIMEOUT The FIS disable setting is time out.\r
338 @retval EFI_UNSUPPORTED The port is in running state.\r
339 @retval EFI_SUCCESS The FIS disable successfully.\r
340\r
341**/\r
342EFI_STATUS\r
343EFIAPI\r
344AhciDisableFisReceive (\r
345 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
346 IN UINT8 Port,\r
347 IN UINT64 Timeout\r
348 ) \r
349{\r
350 UINT32 Offset;\r
351 UINT32 Data;\r
352\r
353 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
354 Data = AhciReadReg (PciIo, Offset);\r
355\r
356 //\r
357 // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.\r
358 //\r
359 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {\r
360 return EFI_UNSUPPORTED;\r
361 }\r
362 \r
363 //\r
364 // Check if the Fis receive DMA engine for the port is running.\r
365 //\r
366 if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {\r
367 return EFI_SUCCESS;\r
368 }\r
369\r
370 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));\r
371\r
372 return AhciWaitMemSet (\r
373 PciIo, \r
374 Offset,\r
375 EFI_AHCI_PORT_CMD_FR,\r
376 0,\r
377 Timeout\r
378 ); \r
379}\r
380\r
381\r
382\r
383/**\r
384 Build the command list, command table and prepare the fis receiver.\r
385 \r
aca84419 386 @param PciIo The PCI IO protocol instance.\r
a41b5272 387 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
aca84419 388 @param Port The number of port.\r
389 @param PortMultiplier The timeout value of stop.\r
390 @param CommandFis The control fis will be used for the transfer.\r
391 @param CommandList The command list will be used for the transfer.\r
392 @param AtapiCommand The atapi command will be used for the transfer.\r
393 @param AtapiCommandLength The length of the atapi command.\r
394 @param CommandSlotNumber The command slot will be used for the transfer.\r
a41b5272 395 @param DataPhysicalAddr The pointer to the data buffer pci bus master address.\r
396 @param DataLength The data count to be transferred.\r
397\r
398**/ \r
399VOID\r
400EFIAPI\r
401AhciBuildCommand (\r
402 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
403 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
404 IN UINT8 Port,\r
405 IN UINT8 PortMultiplier,\r
406 IN EFI_AHCI_COMMAND_FIS *CommandFis,\r
407 IN EFI_AHCI_COMMAND_LIST *CommandList,\r
408 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
409 IN UINT8 AtapiCommandLength,\r
410 IN UINT8 CommandSlotNumber,\r
411 IN OUT VOID *DataPhysicalAddr,\r
412 IN UINT64 DataLength\r
413 ) \r
414{\r
415 UINT64 BaseAddr; \r
416 UINT64 PrdtNumber;\r
417 UINT64 PrdtIndex;\r
418 UINTN RemainedData;\r
419 UINTN MemAddr;\r
420 DATA_64 Data64;\r
421 UINT32 Offset;\r
422\r
423 //\r
424 // Filling the PRDT\r
425 // \r
426 PrdtNumber = (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1) / EFI_AHCI_MAX_DATA_PER_PRDT;\r
427\r
428 //\r
429 // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.\r
430 // It also limits that the maximum amount of the PRDT entry in the command table\r
431 // is 65535.\r
432 //\r
433 ASSERT (PrdtNumber <= 65535);\r
434\r
435 Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
436\r
437 BaseAddr = Data64.Uint64;\r
438 \r
439 ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS)); \r
440 \r
441 ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
442\r
443 CommandFis->AhciCFisPmNum = PortMultiplier;\r
444 \r
445 CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
446\r
447 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
448 if (AtapiCommand != NULL) {\r
449 CopyMem (\r
450 &AhciRegisters->AhciCommandTable->AtapiCmd,\r
451 AtapiCommand,\r
452 AtapiCommandLength\r
453 );\r
454\r
455 CommandList->AhciCmdA = 1;\r
456 CommandList->AhciCmdP = 1;\r
457 CommandList->AhciCmdC = (DataLength == 0) ? 1 : 0;\r
458\r
459 AhciOrReg (PciIo, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
460 } else {\r
461 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
462 }\r
463 \r
5dec0c68 464 RemainedData = (UINTN) DataLength;\r
a41b5272 465 MemAddr = (UINTN) DataPhysicalAddr;\r
466 CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;\r
467 \r
468 for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
469 if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) { \r
470 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;\r
471 } else {\r
472 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;\r
473 }\r
474\r
475 Data64.Uint64 = (UINT64)MemAddr;\r
476 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba = Data64.Uint32.Lower32;\r
477 AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;\r
478 RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT; \r
479 MemAddr += EFI_AHCI_MAX_DATA_PER_PRDT;\r
480 }\r
481\r
482 //\r
483 // Set the last PRDT to Interrupt On Complete\r
484 //\r
485 if (PrdtNumber > 0) {\r
486 AhciRegisters->AhciCommandTable->PrdtTable[PrdtNumber - 1].AhciPrdtIoc = 1;\r
487 }\r
488\r
489 CopyMem (\r
490 (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),\r
491 CommandList,\r
492 sizeof (EFI_AHCI_COMMAND_LIST)\r
493 ); \r
494\r
495 Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTablePciAddr;\r
496 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;\r
497 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;\r
498 AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;\r
499\r
500}\r
501\r
502/**\r
503 Buid a command FIS.\r
504 \r
aca84419 505 @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS data structure.\r
a41b5272 506 @param AtaCommandBlock A pointer to the AhciBuildCommandFis data structure.\r
507\r
508**/\r
509VOID\r
510EFIAPI\r
511AhciBuildCommandFis (\r
512 IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,\r
513 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock\r
514 )\r
515{\r
516 ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
517\r
518 CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;\r
519 //\r
520 // Indicator it's a command\r
521 //\r
522 CmdFis->AhciCFisCmdInd = 0x1; \r
523 CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;\r
524\r
525 CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;\r
526 CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;\r
527\r
528 CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;\r
529 CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;\r
530\r
531 CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;\r
532 CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;\r
533\r
534 CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;\r
535 CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;\r
536\r
537 CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;\r
538 CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;\r
539\r
aca84419 540 CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);\r
a41b5272 541}\r
542\r
543/**\r
544 Start a PIO data transfer on specific port.\r
545 \r
aca84419 546 @param PciIo The PCI IO protocol instance.\r
a41b5272 547 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
aca84419 548 @param Port The number of port.\r
549 @param PortMultiplier The timeout value of stop.\r
550 @param AtapiCommand The atapi command will be used for the transfer.\r
a41b5272 551 @param AtapiCommandLength The length of the atapi command.\r
552 @param Read The transfer direction.\r
553 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
554 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
555 @param MemoryAddr The pointer to the data buffer.\r
556 @param DataCount The data count to be transferred.\r
557 @param Timeout The timeout value of non data transfer.\r
558\r
559 @retval EFI_DEVICE_ERROR The PIO data transfer abort with error occurs.\r
560 @retval EFI_TIMEOUT The operation is time out.\r
561 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
562 @retval EFI_SUCCESS The PIO data transfer executes successfully.\r
563\r
564**/\r
565EFI_STATUS\r
aca84419 566EFIAPI\r
a41b5272 567AhciPioTransfer (\r
568 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
569 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
570 IN UINT8 Port,\r
571 IN UINT8 PortMultiplier,\r
572 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
573 IN UINT8 AtapiCommandLength, \r
574 IN BOOLEAN Read, \r
575 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
576 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
577 IN OUT VOID *MemoryAddr,\r
578 IN UINT32 DataCount,\r
579 IN UINT64 Timeout \r
580 )\r
581{\r
582 EFI_STATUS Status;\r
583 UINTN FisBaseAddr;\r
584 UINT32 Offset;\r
585 UINT32 Value;\r
586 EFI_PHYSICAL_ADDRESS PhyAddr;\r
587 VOID *Map;\r
588 UINTN MapLength;\r
589 EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
590 UINT32 Delay;\r
591 EFI_AHCI_COMMAND_FIS CFis;\r
592 EFI_AHCI_COMMAND_LIST CmdList;\r
593\r
594 if (Read) {\r
595 Flag = EfiPciIoOperationBusMasterWrite;\r
596 } else {\r
597 Flag = EfiPciIoOperationBusMasterRead;\r
598 }\r
599\r
600 //\r
601 // construct command list and command table with pci bus address\r
602 //\r
603 MapLength = DataCount;\r
604 Status = PciIo->Map (\r
605 PciIo,\r
606 Flag,\r
607 MemoryAddr,\r
608 &MapLength,\r
609 &PhyAddr,\r
610 &Map\r
611 );\r
612\r
613 if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
614 return EFI_OUT_OF_RESOURCES;\r
615 }\r
616 \r
617 //\r
618 // Package read needed\r
619 //\r
620 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
621\r
622 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
623\r
624 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
625 CmdList.AhciCmdW = Read ? 0 : 1;\r
626\r
627 AhciBuildCommand (\r
628 PciIo,\r
629 AhciRegisters,\r
630 Port,\r
631 PortMultiplier,\r
632 &CFis,\r
633 &CmdList,\r
634 AtapiCommand,\r
635 AtapiCommandLength,\r
636 0,\r
637 (VOID *)(UINTN)PhyAddr,\r
638 DataCount\r
639 ); \r
640 \r
641 Status = AhciStartCommand (\r
642 PciIo, \r
643 Port, \r
644 0,\r
645 Timeout\r
646 );\r
647 if (EFI_ERROR (Status)) {\r
648 goto Exit;\r
649 }\r
650 \r
651 //\r
652 // Checking the status and wait the driver sending data\r
653 //\r
654 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
655 //\r
656 // Wait device sends the PIO setup fis before data transfer\r
657 //\r
658 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
659 do {\r
e519983a 660 Value = *(volatile UINT32 *) (FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET);\r
a41b5272 661\r
662 if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_PIO_SETUP) {\r
663 break;\r
664 }\r
665\r
666 //\r
667 // Stall for 100 microseconds.\r
668 //\r
669 MicroSecondDelay(100);\r
670\r
671 Delay--; \r
672 } while (Delay > 0);\r
673\r
674 if (Delay == 0) {\r
675 Status = EFI_TIMEOUT;\r
676 goto Exit;\r
677 }\r
678\r
679 //\r
680 // Wait for command compelte\r
681 //\r
682 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
683 Status = AhciWaitMemSet (\r
684 PciIo,\r
685 Offset,\r
686 0xFFFFFFFF,\r
687 0,\r
688 Timeout\r
689 );\r
690\r
691 if (EFI_ERROR (Status)) {\r
692 goto Exit; \r
693 }\r
694\r
695 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
696 Status = AhciWaitMemSet (\r
697 PciIo,\r
698 Offset, \r
699 EFI_AHCI_PORT_IS_PSS,\r
700 EFI_AHCI_PORT_IS_PSS,\r
701 Timeout\r
702 ); \r
703 if (EFI_ERROR (Status)) {\r
704 goto Exit; \r
705 }\r
706\r
707Exit: \r
708 AhciStopCommand (\r
709 PciIo, \r
710 Port,\r
711 Timeout\r
712 );\r
713 \r
714 AhciDisableFisReceive (\r
715 PciIo, \r
716 Port,\r
717 Timeout\r
718 );\r
719\r
720 PciIo->Unmap (\r
721 PciIo,\r
722 Map\r
723 );\r
724\r
e519983a 725 AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
726\r
a41b5272 727 return Status;\r
728}\r
729\r
730/**\r
731 Start a DMA data transfer on specific port\r
732\r
aca84419 733 @param PciIo The PCI IO protocol instance.\r
734 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
735 @param Port The number of port.\r
a41b5272 736 @param PortMultiplier The timeout value of stop.\r
737 @param AtapiCommand The atapi command will be used for the transfer.\r
aca84419 738 @param AtapiCommandLength The length of the atapi command.\r
739 @param Read The transfer direction.\r
740 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
741 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
742 @param MemoryAddr The pointer to the data buffer.\r
743 @param DataCount The data count to be transferred.\r
744 @param Timeout The timeout value of non data transfer.\r
745\r
746 @retval EFI_DEVICE_ERROR The DMA data transfer abort with error occurs.\r
747 @retval EFI_TIMEOUT The operation is time out.\r
748 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
749 @retval EFI_SUCCESS The DMA data transfer executes successfully.\r
a41b5272 750 \r
751**/\r
752EFI_STATUS\r
753EFIAPI\r
754AhciDmaTransfer (\r
755 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
756 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
757 IN UINT8 Port,\r
758 IN UINT8 PortMultiplier,\r
759 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
760 IN UINT8 AtapiCommandLength,\r
761 IN BOOLEAN Read, \r
762 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
763 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
764 IN OUT VOID *MemoryAddr,\r
765 IN UINTN DataCount,\r
766 IN UINT64 Timeout\r
767 )\r
768{\r
769 EFI_STATUS Status;\r
770 UINT32 Offset;\r
771 EFI_PHYSICAL_ADDRESS PhyAddr;\r
772 VOID *Map;\r
773 UINTN MapLength;\r
774 EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
775 EFI_AHCI_COMMAND_FIS CFis;\r
776 EFI_AHCI_COMMAND_LIST CmdList;\r
777\r
778 if (Read) {\r
779 Flag = EfiPciIoOperationBusMasterWrite;\r
780 } else {\r
781 Flag = EfiPciIoOperationBusMasterRead;\r
782 }\r
783\r
784 //\r
785 // construct command list and command table with pci bus address\r
786 //\r
787 MapLength = DataCount;\r
788 Status = PciIo->Map (\r
789 PciIo,\r
790 Flag,\r
791 MemoryAddr,\r
792 &MapLength,\r
793 &PhyAddr,\r
794 &Map\r
795 );\r
796\r
797 if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
798 return EFI_OUT_OF_RESOURCES;\r
799 }\r
800\r
801 //\r
802 // Package read needed\r
803 //\r
804 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
805\r
806 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
807\r
808 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
809 CmdList.AhciCmdW = Read ? 0 : 1;\r
810\r
811 AhciBuildCommand (\r
812 PciIo,\r
813 AhciRegisters,\r
814 Port,\r
815 PortMultiplier,\r
816 &CFis,\r
817 &CmdList,\r
818 AtapiCommand,\r
819 AtapiCommandLength,\r
820 0,\r
821 (VOID *)(UINTN)PhyAddr,\r
822 DataCount\r
823 ); \r
824 \r
825 Status = AhciStartCommand (\r
826 PciIo, \r
827 Port, \r
828 0,\r
829 Timeout\r
830 );\r
831 if (EFI_ERROR (Status)) {\r
832 goto Exit;\r
833 }\r
834 \r
835 //\r
836 // Wait device PRD processed\r
837 //\r
838 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
839 Status = AhciWaitMemSet (\r
840 PciIo,\r
841 Offset,\r
842 EFI_AHCI_PORT_IS_DPS,\r
843 EFI_AHCI_PORT_IS_DPS,\r
844 Timeout\r
845 ); \r
846 \r
847 if (EFI_ERROR (Status)) {\r
848 goto Exit;\r
849 }\r
850\r
851 //\r
852 // Wait for command compelte\r
853 //\r
854 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
855 Status = AhciWaitMemSet (\r
856 PciIo,\r
857 Offset,\r
858 0xFFFFFFFF,\r
859 0,\r
860 Timeout\r
861 );\r
862 if (EFI_ERROR (Status)) {\r
863 goto Exit;\r
864 }\r
865\r
866 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
867 Status = AhciWaitMemSet (\r
868 PciIo,\r
869 Offset,\r
870 EFI_AHCI_PORT_IS_DHRS,\r
871 EFI_AHCI_PORT_IS_DHRS,\r
872 Timeout\r
873 ); \r
874 if (EFI_ERROR (Status)) {\r
875 goto Exit;\r
876 }\r
877\r
878Exit: \r
879 AhciStopCommand (\r
880 PciIo, \r
881 Port,\r
882 Timeout\r
883 );\r
884\r
885 AhciDisableFisReceive (\r
886 PciIo, \r
887 Port,\r
888 Timeout\r
889 );\r
890\r
891 PciIo->Unmap (\r
892 PciIo,\r
893 Map\r
894 ); \r
895 \r
e519983a 896 AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
897\r
a41b5272 898 return Status;\r
899}\r
900\r
901/**\r
902 Start a non data transfer on specific port.\r
903 \r
aca84419 904 @param PciIo The PCI IO protocol instance.\r
905 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
906 @param Port The number of port.\r
a41b5272 907 @param PortMultiplier The timeout value of stop.\r
aca84419 908 @param AtapiCommand The atapi command will be used for the transfer.\r
909 @param AtapiCommandLength The length of the atapi command.\r
910 @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK data.\r
911 @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK data.\r
912 @param Timeout The timeout value of non data transfer.\r
a41b5272 913\r
914 @retval EFI_DEVICE_ERROR The non data transfer abort with error occurs.\r
915 @retval EFI_TIMEOUT The operation is time out.\r
916 @retval EFI_UNSUPPORTED The device is not ready for transfer.\r
917 @retval EFI_SUCCESS The non data transfer executes successfully.\r
918\r
919**/ \r
920EFI_STATUS\r
921EFIAPI\r
922AhciNonDataTransfer (\r
923 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
924 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
925 IN UINT8 Port,\r
926 IN UINT8 PortMultiplier,\r
927 IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,\r
928 IN UINT8 AtapiCommandLength,\r
929 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
930 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
931 IN UINT64 Timeout\r
932 ) \r
933{\r
934 EFI_STATUS Status; \r
935 UINTN FisBaseAddr;\r
936 UINT32 Offset;\r
937 UINT32 Value;\r
938 UINT32 Delay;\r
939 \r
940 EFI_AHCI_COMMAND_FIS CFis;\r
941 EFI_AHCI_COMMAND_LIST CmdList;\r
942\r
943 //\r
944 // Package read needed\r
945 //\r
946 AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
947\r
948 ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
949\r
950 CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
951\r
952 AhciBuildCommand (\r
953 PciIo,\r
954 AhciRegisters,\r
955 Port,\r
956 PortMultiplier,\r
957 &CFis,\r
958 &CmdList,\r
959 AtapiCommand,\r
960 AtapiCommandLength,\r
961 0,\r
962 NULL,\r
963 0\r
964 ); \r
965 \r
966 Status = AhciStartCommand (\r
967 PciIo, \r
968 Port, \r
969 0,\r
970 Timeout\r
971 );\r
972 if (EFI_ERROR (Status)) {\r
973 goto Exit;\r
974 }\r
975 \r
976 //\r
977 // Wait device sends the Response Fis\r
978 //\r
979 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
980 //\r
981 // Wait device sends the PIO setup fis before data transfer\r
982 //\r
983 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
984 do {\r
e519983a 985 Value = *(volatile UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
a41b5272 986\r
987 if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
988 break;\r
989 }\r
990\r
991 //\r
992 // Stall for 100 microseconds.\r
993 //\r
994 MicroSecondDelay(100);\r
995\r
996 Delay --; \r
997 } while (Delay > 0);\r
998\r
999 if (Delay == 0) {\r
1000 Status = EFI_TIMEOUT;\r
1001 goto Exit;\r
1002 }\r
1003\r
1004 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
1005\r
1006 Status = AhciWaitMemSet (\r
1007 PciIo,\r
1008 Offset,\r
1009 0xFFFFFFFF,\r
1010 0,\r
1011 Timeout\r
1012 ); \r
1013 \r
1014Exit: \r
1015 AhciStopCommand (\r
1016 PciIo, \r
1017 Port,\r
1018 Timeout\r
1019 );\r
1020\r
1021 AhciDisableFisReceive (\r
1022 PciIo, \r
1023 Port,\r
1024 Timeout\r
1025 );\r
1026\r
e519983a 1027 AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
1028\r
a41b5272 1029 return Status;\r
1030}\r
1031\r
1032/**\r
1033 Stop command running for giving port\r
1034 \r
1035 @param PciIo The PCI IO protocol instance.\r
1036 @param Port The number of port.\r
1037 @param Timeout The timeout value of stop.\r
1038 \r
1039 @retval EFI_DEVICE_ERROR The command stop unsuccessfully.\r
1040 @retval EFI_TIMEOUT The operation is time out.\r
1041 @retval EFI_SUCCESS The command stop successfully.\r
1042\r
1043**/\r
1044EFI_STATUS\r
1045EFIAPI\r
1046AhciStopCommand (\r
1047 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1048 IN UINT8 Port,\r
1049 IN UINT64 Timeout\r
1050 )\r
1051{\r
1052 UINT32 Offset;\r
1053 UINT32 Data;\r
1054\r
1055 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1056 Data = AhciReadReg (PciIo, Offset);\r
1057\r
1058 if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {\r
1059 return EFI_SUCCESS; \r
1060 }\r
1061\r
1062 if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
1063 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));\r
1064 }\r
1065\r
1066 return AhciWaitMemSet (\r
1067 PciIo, \r
1068 Offset,\r
1069 EFI_AHCI_PORT_CMD_CR,\r
1070 0,\r
1071 Timeout\r
1072 ); \r
1073}\r
1074\r
1075/**\r
1076 Start command for give slot on specific port.\r
1077 \r
1078 @param PciIo The PCI IO protocol instance.\r
1079 @param Port The number of port.\r
1080 @param CommandSlot The number of CommandSlot.\r
1081 @param Timeout The timeout value of start.\r
1082 \r
1083 @retval EFI_DEVICE_ERROR The command start unsuccessfully.\r
1084 @retval EFI_TIMEOUT The operation is time out.\r
1085 @retval EFI_SUCCESS The command start successfully.\r
1086\r
1087**/\r
1088EFI_STATUS\r
1089EFIAPI\r
1090AhciStartCommand (\r
1091 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1092 IN UINT8 Port,\r
1093 IN UINT8 CommandSlot,\r
1094 IN UINT64 Timeout\r
1095 )\r
1096{\r
1097 UINT32 CmdSlotBit;\r
1098 EFI_STATUS Status;\r
1099 UINT32 PortStatus;\r
1100 UINT32 StartCmd;\r
1101 UINT32 PortTfd;\r
1102 UINT32 Offset;\r
1103 UINT32 Capability;\r
1104\r
1105 //\r
1106 // Collect AHCI controller information\r
1107 //\r
1108 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
1109\r
1110 CmdSlotBit = (UINT32) (1 << CommandSlot);\r
1111\r
1112 AhciClearPortStatus (\r
1113 PciIo,\r
1114 Port\r
1115 );\r
1116\r
1117 Status = AhciEnableFisReceive (\r
1118 PciIo, \r
1119 Port,\r
1120 Timeout\r
1121 );\r
1122 \r
1123 if (EFI_ERROR (Status)) {\r
1124 return Status;\r
1125 }\r
1126\r
a41b5272 1127 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1128 PortStatus = AhciReadReg (PciIo, Offset);\r
1129 \r
1130 StartCmd = 0;\r
1131 if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
1132 StartCmd = AhciReadReg (PciIo, Offset);\r
1133 StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;\r
1134 StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;\r
1135 }\r
1136\r
1137 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
1138 PortTfd = AhciReadReg (PciIo, Offset);\r
1139\r
1140 if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
1141 if ((Capability & BIT24) != 0) {\r
1142 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1143 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL);\r
1144\r
1145 AhciWaitMemSet (\r
1146 PciIo, \r
1147 Offset,\r
1148 EFI_AHCI_PORT_CMD_COL,\r
1149 0,\r
1150 Timeout\r
1151 ); \r
1152 }\r
1153 }\r
1154\r
1155 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
1156 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);\r
1157\r
e519983a 1158 //\r
1159 // Setting the command\r
1160 //\r
1161 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
1162 AhciAndReg (PciIo, Offset, 0);\r
1163 AhciOrReg (PciIo, Offset, CmdSlotBit);\r
1164\r
1165 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
1166 AhciAndReg (PciIo, Offset, 0);\r
1167 AhciOrReg (PciIo, Offset, CmdSlotBit);\r
1168\r
a41b5272 1169 return EFI_SUCCESS;\r
1170}\r
1171\r
1172/**\r
1173 Do AHCI port reset.\r
1174\r
1175 @param PciIo The PCI IO protocol instance.\r
1176 @param Port The number of port.\r
1177 @param Timeout The timeout value of reset.\r
1178 \r
1179 @retval EFI_DEVICE_ERROR The port reset unsuccessfully\r
1180 @retval EFI_TIMEOUT The reset operation is time out.\r
1181 @retval EFI_SUCCESS The port reset successfully.\r
1182\r
1183**/\r
1184EFI_STATUS\r
1185EFIAPI\r
1186AhciPortReset (\r
1187 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1188 IN UINT8 Port,\r
1189 IN UINT64 Timeout\r
1190 )\r
1191{\r
1192 EFI_STATUS Status;\r
1193 UINT32 Offset; \r
1194 \r
1195 AhciClearPortStatus (PciIo, Port);\r
1196\r
1197 AhciStopCommand (PciIo, Port, Timeout);\r
1198\r
1199 AhciDisableFisReceive (PciIo, Port, Timeout);\r
1200\r
1201 AhciEnableFisReceive (PciIo, Port, Timeout);\r
1202\r
1203 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
1204\r
1205 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);\r
1206\r
1207 //\r
1208 // wait 5 milliseceond before de-assert DET \r
1209 //\r
1210 MicroSecondDelay (5000);\r
1211\r
1212 AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK);\r
1213\r
1214 //\r
1215 // wait 5 milliseceond before de-assert DET \r
1216 //\r
1217 MicroSecondDelay (5000);\r
1218\r
1219 //\r
1220 // Wait for communication to be re-established\r
1221 //\r
1222 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
1223 Status = AhciWaitMemSet (\r
1224 PciIo,\r
1225 Offset,\r
1226 EFI_AHCI_PORT_SSTS_DET_MASK,\r
1227 EFI_AHCI_PORT_SSTS_DET_PCE,\r
1228 Timeout\r
1229 ); \r
1230\r
1231 if (EFI_ERROR (Status)) {\r
1232 return Status;\r
1233 }\r
1234\r
1235 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
1236 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_ERR_CLEAR);\r
1237\r
1238 return EFI_SUCCESS;\r
1239}\r
1240\r
1241/**\r
1242 Do AHCI HBA reset.\r
1243 \r
1244 @param PciIo The PCI IO protocol instance.\r
1245 @param Timeout The timeout value of reset.\r
1246 \r
1247 \r
1248 @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.\r
1249 @retval EFI_TIMEOUT The reset operation is time out.\r
1250 @retval EFI_SUCCESS AHCI controller is reset successfully.\r
1251\r
1252**/\r
1253EFI_STATUS\r
1254EFIAPI\r
1255AhciReset (\r
1256 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1257 IN UINT64 Timeout\r
1258 ) \r
1259{\r
1260 EFI_STATUS Status;\r
1261 UINT32 Delay;\r
1262 UINT32 Value;\r
1263\r
1264 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
1265\r
1266 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
1267\r
1268 Status = EFI_TIMEOUT;\r
1269\r
1270 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
1271\r
1272 do {\r
1273 Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
1274\r
1275 if ((Value & EFI_AHCI_GHC_RESET) == 0) {\r
1276 break;\r
1277 }\r
1278\r
1279 //\r
1280 // Stall for 100 microseconds.\r
1281 //\r
1282 MicroSecondDelay(100);\r
1283\r
1284 Delay--;\r
1285 } while (Delay > 0);\r
1286\r
1287 if (Delay == 0) {\r
1288 return EFI_TIMEOUT;\r
1289 }\r
1290\r
1291 return EFI_SUCCESS;\r
1292}\r
1293\r
12873d57 1294/**\r
1295 Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
1296\r
1297 @param PciIo The PCI IO protocol instance.\r
1298 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1299 @param Port The number of port.\r
1300 @param PortMultiplier The timeout value of stop.\r
1301 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1302\r
1303 @retval EFI_SUCCESS Successfully get the return status of S.M.A.R.T command execution.\r
1304 @retval Others Fail to get return status data.\r
1305\r
1306**/\r
1307EFI_STATUS\r
1308EFIAPI\r
1309AhciAtaSmartReturnStatusCheck (\r
1310 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1311 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1312 IN UINT8 Port,\r
1313 IN UINT8 PortMultiplier,\r
1314 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
1315 )\r
1316{\r
1317 EFI_STATUS Status;\r
1318 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1319 UINT8 LBAMid;\r
1320 UINT8 LBAHigh;\r
1321 UINTN FisBaseAddr;\r
1322 UINT32 Value;\r
1323\r
1324 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1325\r
1326 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1327 AtaCommandBlock.AtaFeatures = ATA_SMART_RETURN_STATUS;\r
1328 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1329 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1330\r
1331 //\r
1332 // Send S.M.A.R.T Read Return Status command to device\r
1333 //\r
1334 Status = AhciNonDataTransfer (\r
1335 PciIo,\r
1336 AhciRegisters,\r
1337 (UINT8)Port,\r
1338 (UINT8)PortMultiplier,\r
1339 NULL,\r
1340 0,\r
1341 &AtaCommandBlock,\r
1342 AtaStatusBlock,\r
1343 ATA_ATAPI_TIMEOUT\r
1344 );\r
1345\r
1346 if (EFI_ERROR (Status)) {\r
1347 return EFI_DEVICE_ERROR;\r
1348 }\r
1349\r
1350 FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1351\r
1352 Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
1353\r
1354 if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
1355 LBAMid = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];\r
1356 LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];\r
1357\r
1358 if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
1359 //\r
1360 // The threshold exceeded condition is not detected by the device\r
1361 //\r
1362 DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
1363\r
1364 } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
1365 //\r
1366 // The threshold exceeded condition is detected by the device\r
1367 //\r
1368 DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
1369 }\r
1370 }\r
1371\r
1372 return EFI_SUCCESS;\r
1373}\r
1374\r
1375/**\r
1376 Enable SMART command of the disk if supported.\r
1377\r
1378 @param PciIo The PCI IO protocol instance.\r
1379 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1380 @param Port The number of port.\r
1381 @param PortMultiplier The timeout value of stop.\r
1382 @param IdentifyData A pointer to data buffer which is used to contain IDENTIFY data.\r
1383 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
1384\r
1385**/\r
1386VOID\r
1387EFIAPI\r
1388AhciAtaSmartSupport (\r
1389 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1390 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1391 IN UINT8 Port,\r
1392 IN UINT8 PortMultiplier,\r
1393 IN EFI_IDENTIFY_DATA *IdentifyData, \r
1394 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock\r
1395 )\r
1396{\r
1397 EFI_STATUS Status;\r
1398 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1399\r
1400 //\r
1401 // Detect if the device supports S.M.A.R.T.\r
1402 //\r
1403 if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
1404 //\r
1405 // S.M.A.R.T is not supported by the device\r
1406 //\r
1407 DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n", \r
1408 Port, PortMultiplier));\r
1409 } else {\r
1410 //\r
1411 // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
1412 //\r
1413 if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
1414 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1415\r
1416 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1417 AtaCommandBlock.AtaFeatures = ATA_SMART_ENABLE_OPERATION;\r
1418 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1419 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1420\r
1421 //\r
1422 // Send S.M.A.R.T Enable command to device\r
1423 //\r
1424 Status = AhciNonDataTransfer (\r
1425 PciIo,\r
1426 AhciRegisters,\r
1427 (UINT8)Port,\r
1428 (UINT8)PortMultiplier,\r
1429 NULL,\r
1430 0,\r
1431 &AtaCommandBlock,\r
1432 AtaStatusBlock,\r
1433 ATA_ATAPI_TIMEOUT\r
1434 );\r
1435\r
1436\r
1437 if (!EFI_ERROR (Status)) {\r
1438 //\r
1439 // Send S.M.A.R.T AutoSave command to device\r
1440 //\r
1441 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1442\r
1443 AtaCommandBlock.AtaCommand = ATA_CMD_SMART;\r
1444 AtaCommandBlock.AtaFeatures = 0xD2;\r
1445 AtaCommandBlock.AtaSectorCount = 0xF1;\r
1446 AtaCommandBlock.AtaCylinderLow = ATA_CONSTANT_4F;\r
1447 AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
1448\r
1449 Status = AhciNonDataTransfer (\r
1450 PciIo,\r
1451 AhciRegisters,\r
1452 (UINT8)Port,\r
1453 (UINT8)PortMultiplier,\r
1454 NULL,\r
1455 0,\r
1456 &AtaCommandBlock,\r
1457 AtaStatusBlock,\r
1458 ATA_ATAPI_TIMEOUT\r
1459 );\r
1460\r
1461 if (!EFI_ERROR (Status)) {\r
1462 Status = AhciAtaSmartReturnStatusCheck (\r
1463 PciIo,\r
1464 AhciRegisters,\r
1465 (UINT8)Port,\r
1466 (UINT8)PortMultiplier,\r
1467 AtaStatusBlock\r
1468 );\r
1469 }\r
1470 }\r
1471 }\r
1472 DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n", \r
1473 Port, PortMultiplier));\r
1474 }\r
1475\r
1476 return ;\r
1477}\r
1478\r
a41b5272 1479/**\r
1480 Send Buffer cmd to specific device.\r
1481 \r
aca84419 1482 @param PciIo The PCI IO protocol instance.\r
1483 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1484 @param Port The number of port.\r
a41b5272 1485 @param PortMultiplier The timeout value of stop.\r
aca84419 1486 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1487\r
1488 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1489 @retval EFI_TIMEOUT The operation is time out.\r
1490 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1491 @retval EFI_SUCCESS The cmd executes successfully.\r
1492\r
1493**/\r
1494EFI_STATUS\r
1495EFIAPI\r
1496AhciIdentify (\r
1497 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1498 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1499 IN UINT8 Port,\r
1500 IN UINT8 PortMultiplier,\r
1501 IN OUT EFI_IDENTIFY_DATA *Buffer \r
1502 )\r
1503{\r
1504 EFI_STATUS Status;\r
1505 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1506 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1507\r
1508 if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {\r
1509 return EFI_INVALID_PARAMETER;\r
1510 }\r
1511\r
1512 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1513 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1514 \r
1515 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
1516 AtaCommandBlock.AtaSectorCount = 1;\r
1517\r
1518 Status = AhciPioTransfer (\r
1519 PciIo,\r
1520 AhciRegisters,\r
1521 Port,\r
1522 PortMultiplier,\r
1523 NULL,\r
1524 0,\r
1525 TRUE,\r
1526 &AtaCommandBlock,\r
1527 &AtaStatusBlock,\r
1528 Buffer,\r
1529 sizeof (EFI_IDENTIFY_DATA),\r
1530 ATA_ATAPI_TIMEOUT\r
1531 );\r
1532\r
1533 return Status;\r
1534}\r
1535\r
1536/**\r
1537 Send Buffer cmd to specific device.\r
1538 \r
aca84419 1539 @param PciIo The PCI IO protocol instance.\r
1540 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1541 @param Port The number of port.\r
a41b5272 1542 @param PortMultiplier The timeout value of stop.\r
aca84419 1543 @param Buffer The data buffer to store IDENTIFY PACKET data.\r
a41b5272 1544\r
1545 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1546 @retval EFI_TIMEOUT The operation is time out.\r
1547 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1548 @retval EFI_SUCCESS The cmd executes successfully.\r
1549\r
1550**/\r
1551EFI_STATUS\r
1552EFIAPI\r
1553AhciIdentifyPacket (\r
1554 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1555 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1556 IN UINT8 Port,\r
1557 IN UINT8 PortMultiplier,\r
1558 IN OUT EFI_IDENTIFY_DATA *Buffer \r
1559 )\r
1560{\r
1561 EFI_STATUS Status;\r
1562 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1563 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1564\r
1565 if (PciIo == NULL || AhciRegisters == NULL) {\r
1566 return EFI_INVALID_PARAMETER;\r
1567 }\r
1568 \r
1569 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1570 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1571\r
1572 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DEVICE;\r
1573 AtaCommandBlock.AtaSectorCount = 1;\r
1574\r
1575 Status = AhciPioTransfer (\r
1576 PciIo,\r
1577 AhciRegisters,\r
1578 Port,\r
1579 PortMultiplier,\r
1580 NULL,\r
1581 0,\r
1582 TRUE,\r
1583 &AtaCommandBlock,\r
1584 &AtaStatusBlock,\r
1585 Buffer,\r
1586 sizeof (EFI_IDENTIFY_DATA),\r
1587 ATA_ATAPI_TIMEOUT\r
1588 );\r
1589\r
1590 return Status;\r
1591}\r
1592\r
1593/**\r
1594 Send SET FEATURE cmd on specific device.\r
1595 \r
aca84419 1596 @param PciIo The PCI IO protocol instance.\r
1597 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1598 @param Port The number of port.\r
a41b5272 1599 @param PortMultiplier The timeout value of stop.\r
aca84419 1600 @param Feature The data to send Feature register.\r
1601 @param FeatureSpecificData The specific data for SET FEATURE cmd.\r
a41b5272 1602\r
1603 @retval EFI_DEVICE_ERROR The cmd abort with error occurs.\r
1604 @retval EFI_TIMEOUT The operation is time out.\r
1605 @retval EFI_UNSUPPORTED The device is not ready for executing.\r
1606 @retval EFI_SUCCESS The cmd executes successfully.\r
1607\r
1608**/\r
1609EFI_STATUS\r
1610EFIAPI\r
1611AhciDeviceSetFeature (\r
1612 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1613 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1614 IN UINT8 Port,\r
1615 IN UINT8 PortMultiplier,\r
1616 IN UINT16 Feature,\r
1617 IN UINT32 FeatureSpecificData\r
1618 )\r
1619{\r
1620 EFI_STATUS Status;\r
1621 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1622 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1623\r
1624 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1625 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1626 \r
1627 AtaCommandBlock.AtaCommand = ATA_CMD_SET_FEATURES;\r
1628 AtaCommandBlock.AtaFeatures = (UINT8) Feature;\r
1629 AtaCommandBlock.AtaFeaturesExp = (UINT8) (Feature >> 8);\r
1630 AtaCommandBlock.AtaSectorCount = (UINT8) FeatureSpecificData;\r
1631 AtaCommandBlock.AtaSectorNumber = (UINT8) (FeatureSpecificData >> 8);\r
1632 AtaCommandBlock.AtaCylinderLow = (UINT8) (FeatureSpecificData >> 16);\r
1633 AtaCommandBlock.AtaCylinderHigh = (UINT8) (FeatureSpecificData >> 24);\r
1634\r
1635 Status = AhciNonDataTransfer (\r
1636 PciIo,\r
1637 AhciRegisters,\r
1638 (UINT8)Port,\r
1639 (UINT8)PortMultiplier,\r
1640 NULL,\r
1641 0,\r
1642 &AtaCommandBlock,\r
1643 &AtaStatusBlock,\r
1644 ATA_ATAPI_TIMEOUT\r
1645 );\r
1646\r
1647 return Status;\r
1648}\r
1649\r
1650/**\r
1651 This function is used to send out ATAPI commands conforms to the Packet Command \r
1652 with PIO Protocol.\r
1653\r
1654 @param PciIo The PCI IO protocol instance.\r
1655 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1656 @param Port The number of port. \r
1657 @param PortMultiplier The number of port multiplier.\r
1658 @param Packet A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.\r
1659\r
1660 @retval EFI_SUCCESS send out the ATAPI packet command successfully\r
1661 and device sends data successfully.\r
1662 @retval EFI_DEVICE_ERROR the device failed to send data.\r
1663\r
1664**/\r
1665EFI_STATUS\r
1666EFIAPI\r
1667AhciPacketCommandExecute (\r
1668 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1669 IN EFI_AHCI_REGISTERS *AhciRegisters,\r
1670 IN UINT8 Port,\r
1671 IN UINT8 PortMultiplier,\r
1672 IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
1673 )\r
1674{\r
1675 EFI_STATUS Status;\r
1676 VOID *Buffer;\r
1677 UINT32 Length;\r
1678 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
1679 EFI_ATA_STATUS_BLOCK AtaStatusBlock;\r
1680 BOOLEAN Read;\r
1681 UINT8 Retry;\r
1682\r
1683 if (Packet == NULL || Packet->Cdb == NULL) {\r
1684 return EFI_INVALID_PARAMETER;\r
1685 }\r
1686\r
1687 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
1688 ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
1689 AtaCommandBlock.AtaCommand = ATA_CMD_PACKET;\r
1690 //\r
1691 // No OVL; No DMA\r
1692 //\r
1693 AtaCommandBlock.AtaFeatures = 0x00;\r
1694 //\r
1695 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
1696 // determine how many data should be transferred.\r
1697 //\r
1698 AtaCommandBlock.AtaCylinderLow = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
1699 AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);\r
1700\r
1701 if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
1702 Buffer = Packet->InDataBuffer;\r
1703 Length = Packet->InTransferLength;\r
1704 Read = TRUE;\r
1705 } else {\r
1706 Buffer = Packet->OutDataBuffer;\r
1707 Length = Packet->OutTransferLength;\r
1708 Read = FALSE;\r
1709 }\r
1710\r
1711 if (Length == 0) { \r
1712 Status = AhciNonDataTransfer (\r
1713 PciIo,\r
1714 AhciRegisters,\r
1715 Port,\r
1716 PortMultiplier,\r
1717 Packet->Cdb,\r
1718 Packet->CdbLength,\r
1719 &AtaCommandBlock,\r
1720 &AtaStatusBlock,\r
1721 Packet->Timeout\r
1722 );\r
1723 } else {\r
1724 //\r
1725 // READ_CAPACITY cmd may execute failure. Retry 5 times\r
1726 //\r
1727 if (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_READ_CAPACITY) {\r
1728 Retry = 5;\r
1729 } else {\r
1730 Retry = 1;\r
1731 }\r
1732 do {\r
1733 Status = AhciPioTransfer (\r
1734 PciIo,\r
1735 AhciRegisters,\r
1736 Port,\r
1737 PortMultiplier,\r
1738 Packet->Cdb,\r
1739 Packet->CdbLength,\r
1740 Read,\r
1741 &AtaCommandBlock,\r
1742 &AtaStatusBlock,\r
1743 Buffer,\r
1744 Length,\r
1745 Packet->Timeout\r
1746 );\r
1747 if (!EFI_ERROR (Status)) {\r
1748 break;\r
1749 }\r
1750 Retry--;\r
1751 } while (Retry != 0);\r
1752 }\r
1753 return Status;\r
1754}\r
1755\r
1756/**\r
1757 Allocate transfer-related data struct which is used at AHCI mode.\r
1758 \r
1759 @param PciIo The PCI IO protocol instance.\r
1760 @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.\r
1761\r
1762**/\r
1763EFI_STATUS\r
1764EFIAPI\r
1765AhciCreateTransferDescriptor (\r
1766 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1767 IN OUT EFI_AHCI_REGISTERS *AhciRegisters\r
1768 )\r
1769{\r
1770 EFI_STATUS Status;\r
1771 UINTN Bytes;\r
1772 VOID *Buffer;\r
1773\r
1774 UINT32 Capability;\r
1775 UINT8 MaxPortNumber;\r
1776 UINT8 MaxCommandSlotNumber;\r
1777 BOOLEAN Support64Bit;\r
1778 UINT64 MaxReceiveFisSize;\r
1779 UINT64 MaxCommandListSize;\r
1780 UINT64 MaxCommandTableSize;\r
ed365e93 1781 EFI_PHYSICAL_ADDRESS AhciRFisPciAddr;\r
1782 EFI_PHYSICAL_ADDRESS AhciCmdListPciAddr;\r
1783 EFI_PHYSICAL_ADDRESS AhciCommandTablePciAddr;\r
a41b5272 1784\r
1785 Buffer = NULL;\r
1786 //\r
1787 // Collect AHCI controller information\r
1788 //\r
1789 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
1790 MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
1791 //\r
1792 // Get the number of command slots per port supported by this HBA.\r
1793 //\r
1794 MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
aca84419 1795 Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
a41b5272 1796\r
1797 MaxReceiveFisSize = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
1798 Status = PciIo->AllocateBuffer (\r
1799 PciIo,\r
1800 AllocateAnyPages,\r
1801 EfiBootServicesData,\r
ed365e93 1802 EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
a41b5272 1803 &Buffer,\r
1804 0\r
1805 );\r
1806\r
1807 if (EFI_ERROR (Status)) {\r
1808 return EFI_OUT_OF_RESOURCES;\r
1809 }\r
1810\r
5dec0c68 1811 ZeroMem (Buffer, (UINTN)MaxReceiveFisSize);\r
a41b5272 1812\r
1813 AhciRegisters->AhciRFis = Buffer;\r
1814 AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;\r
5dec0c68 1815 Bytes = (UINTN)MaxReceiveFisSize;\r
a41b5272 1816\r
1817 Status = PciIo->Map (\r
1818 PciIo,\r
1819 EfiPciIoOperationBusMasterCommonBuffer,\r
1820 Buffer,\r
1821 &Bytes,\r
ed365e93 1822 &AhciRFisPciAddr,\r
a41b5272 1823 &AhciRegisters->MapRFis\r
1824 );\r
1825\r
1826 if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {\r
1827 //\r
1828 // Map error or unable to map the whole RFis buffer into a contiguous region. \r
1829 //\r
1830 Status = EFI_OUT_OF_RESOURCES;\r
1831 goto Error6;\r
1832 }\r
1833\r
ed365e93 1834 if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {\r
a41b5272 1835 //\r
1836 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
1837 //\r
1838 Status = EFI_DEVICE_ERROR;\r
1839 goto Error5;\r
1840 }\r
ed365e93 1841 AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;\r
a41b5272 1842\r
1843 //\r
1844 // Allocate memory for command list\r
1845 // Note that the implemenation is a single task model which only use a command list for all ports.\r
1846 //\r
1847 Buffer = NULL;\r
1848 MaxCommandListSize = MaxCommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST);\r
1849 Status = PciIo->AllocateBuffer (\r
1850 PciIo,\r
1851 AllocateAnyPages,\r
1852 EfiBootServicesData,\r
ed365e93 1853 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
a41b5272 1854 &Buffer,\r
1855 0\r
1856 );\r
1857\r
1858 if (EFI_ERROR (Status)) {\r
1859 //\r
1860 // Free mapped resource. \r
1861 //\r
1862 Status = EFI_OUT_OF_RESOURCES;\r
1863 goto Error5;\r
1864 }\r
1865\r
5dec0c68 1866 ZeroMem (Buffer, (UINTN)MaxCommandListSize);\r
a41b5272 1867\r
1868 AhciRegisters->AhciCmdList = Buffer;\r
1869 AhciRegisters->MaxCommandListSize = MaxCommandListSize;\r
5dec0c68 1870 Bytes = (UINTN)MaxCommandListSize;\r
a41b5272 1871\r
1872 Status = PciIo->Map (\r
1873 PciIo,\r
1874 EfiPciIoOperationBusMasterCommonBuffer,\r
1875 Buffer,\r
1876 &Bytes,\r
ed365e93 1877 &AhciCmdListPciAddr,\r
a41b5272 1878 &AhciRegisters->MapCmdList\r
1879 );\r
1880\r
1881 if (EFI_ERROR (Status) || (Bytes != MaxCommandListSize)) {\r
1882 //\r
1883 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
1884 //\r
1885 Status = EFI_OUT_OF_RESOURCES;\r
1886 goto Error4;\r
1887 }\r
1888\r
ed365e93 1889 if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {\r
a41b5272 1890 //\r
1891 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
1892 //\r
1893 Status = EFI_DEVICE_ERROR;\r
1894 goto Error3;\r
1895 }\r
ed365e93 1896 AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;\r
a41b5272 1897\r
1898 //\r
1899 // Allocate memory for command table\r
1900 // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.\r
1901 //\r
1902 Buffer = NULL;\r
1903 MaxCommandTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);\r
1904\r
1905 Status = PciIo->AllocateBuffer (\r
1906 PciIo,\r
1907 AllocateAnyPages,\r
1908 EfiBootServicesData,\r
ed365e93 1909 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
a41b5272 1910 &Buffer,\r
1911 0\r
1912 );\r
1913\r
1914 if (EFI_ERROR (Status)) {\r
1915 //\r
1916 // Free mapped resource. \r
1917 //\r
1918 Status = EFI_OUT_OF_RESOURCES;\r
1919 goto Error3;\r
1920 }\r
1921\r
5dec0c68 1922 ZeroMem (Buffer, (UINTN)MaxCommandTableSize);\r
a41b5272 1923\r
1924 AhciRegisters->AhciCommandTable = Buffer;\r
1925 AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;\r
5dec0c68 1926 Bytes = (UINTN)MaxCommandTableSize;\r
a41b5272 1927\r
1928 Status = PciIo->Map (\r
1929 PciIo,\r
1930 EfiPciIoOperationBusMasterCommonBuffer,\r
1931 Buffer,\r
1932 &Bytes,\r
ed365e93 1933 &AhciCommandTablePciAddr,\r
a41b5272 1934 &AhciRegisters->MapCommandTable\r
1935 );\r
1936\r
1937 if (EFI_ERROR (Status) || (Bytes != MaxCommandTableSize)) {\r
1938 //\r
1939 // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
1940 //\r
1941 Status = EFI_OUT_OF_RESOURCES;\r
1942 goto Error2;\r
1943 }\r
1944\r
ed365e93 1945 if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {\r
a41b5272 1946 //\r
1947 // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
1948 //\r
1949 Status = EFI_DEVICE_ERROR;\r
1950 goto Error1;\r
1951 }\r
ed365e93 1952 AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;\r
a41b5272 1953\r
1954 return EFI_SUCCESS;\r
1955 //\r
1956 // Map error or unable to map the whole CmdList buffer into a contiguous region. \r
1957 //\r
1958Error1:\r
1959 PciIo->Unmap (\r
1960 PciIo,\r
1961 AhciRegisters->MapCommandTable\r
1962 );\r
1963Error2:\r
1964 PciIo->FreeBuffer (\r
1965 PciIo,\r
ed365e93 1966 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
a41b5272 1967 AhciRegisters->AhciCommandTable\r
1968 );\r
1969Error3:\r
1970 PciIo->Unmap (\r
1971 PciIo,\r
1972 AhciRegisters->MapCmdList\r
1973 );\r
1974Error4:\r
1975 PciIo->FreeBuffer (\r
1976 PciIo,\r
ed365e93 1977 EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
a41b5272 1978 AhciRegisters->AhciCmdList\r
1979 );\r
1980Error5:\r
1981 PciIo->Unmap (\r
1982 PciIo,\r
1983 AhciRegisters->MapRFis\r
1984 );\r
1985Error6:\r
1986 PciIo->FreeBuffer (\r
1987 PciIo,\r
ed365e93 1988 EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
a41b5272 1989 AhciRegisters->AhciRFis\r
1990 );\r
1991\r
1992 return Status;\r
1993}\r
1994\r
1995/**\r
1996 Initialize ATA host controller at AHCI mode.\r
1997\r
1998 The function is designed to initialize ATA host controller. \r
1999 \r
2000 @param[in] Instance A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
2001\r
2002**/\r
2003EFI_STATUS\r
2004EFIAPI\r
2005AhciModeInitialization (\r
2006 IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance\r
2007 )\r
2008{\r
2009 EFI_STATUS Status;\r
2010 EFI_PCI_IO_PROTOCOL *PciIo;\r
2011 EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
2012 UINT32 Capability;\r
2013 UINT8 MaxPortNumber;\r
2014 UINT32 PortImplementBitMap;\r
2015 UINT8 MaxCommandSlotNumber;\r
2016 BOOLEAN Support64Bit;\r
2017\r
2018 EFI_AHCI_REGISTERS *AhciRegisters;\r
2019\r
2020 UINT8 Port;\r
2021 DATA_64 Data64;\r
2022 UINT32 Offset;\r
2023 UINT32 Data;\r
2024 EFI_IDENTIFY_DATA Buffer;\r
2025 EFI_ATA_DEVICE_TYPE DeviceType;\r
2026 EFI_ATA_COLLECTIVE_MODE *SupportedModes;\r
2027 EFI_ATA_TRANSFER_MODE TransferMode;\r
2028 \r
2029 if (Instance == NULL) {\r
2030 return EFI_INVALID_PARAMETER;\r
2031 }\r
2032\r
2033 PciIo = Instance->PciIo;\r
2034 IdeInit = Instance->IdeControllerInit;\r
2035\r
2036 Status = AhciReset (PciIo, ATA_ATAPI_TIMEOUT); \r
2037\r
2038 if (EFI_ERROR (Status)) {\r
2039 return EFI_DEVICE_ERROR;\r
2040 }\r
2041\r
2042 //\r
2043 // Enable AE before accessing any AHCI registers\r
2044 //\r
2045 AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
2046\r
2047 //\r
2048 // Collect AHCI controller information\r
2049 //\r
2050 Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
2051\r
2052 //\r
2053 // Get the number of command slots per port supported by this HBA.\r
2054 //\r
2055 MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
aca84419 2056 Support64Bit = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
a41b5272 2057\r
2058 //\r
2059 // Get the bit map of those ports exposed by this HBA.\r
2060 // It indicates which ports that the HBA supports are available for software to use. \r
2061 //\r
2062 PortImplementBitMap = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
2063 MaxPortNumber = (UINT8) ((Capability & 0x1F) + 1);\r
2064 \r
2065 AhciRegisters = &Instance->AhciRegisters;\r
2066 Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
2067\r
2068 if (EFI_ERROR (Status)) {\r
2069 return EFI_OUT_OF_RESOURCES;\r
2070 }\r
2071\r
2072 for (Port = 0; Port < MaxPortNumber; Port ++) { \r
2073 Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
2074 \r
2075 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
2076 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2077 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
2078 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2079 \r
2080 //\r
2081 // Single task envrionment, we only use one command table for all port\r
2082 //\r
2083 Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
2084 \r
2085 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
2086 AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
2087 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
2088 AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
2089 \r
2090 if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
2091 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
2092 \r
2093 if ((Capability & EFI_AHCI_PORT_CMD_ASP) != 0) {\r
2094 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
2095 }\r
2096 Data = AhciReadReg (PciIo, Offset);\r
2097 if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
2098 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
2099 }\r
2100 \r
2101 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE|EFI_AHCI_PORT_CMD_COL|EFI_AHCI_PORT_CMD_ST));\r
2102 }\r
2103 \r
2104 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
2105 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_MASK));\r
2106 \r
2107 AhciAndReg (PciIo, Offset,(UINT32) ~(EFI_AHCI_PORT_SCTL_IPM_PSD));\r
2108 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_PSD);\r
2109 \r
2110 AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_SSD));\r
2111 AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_SSD);\r
2112 \r
2113 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
2114 AhciAndReg (PciIo, Offset, 0);\r
2115 \r
2116 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
2117 AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
2118 }\r
2119\r
2120 //\r
2121 // Stall for 100 milliseconds.\r
2122 //\r
2123 MicroSecondDelay(100000);\r
2124 \r
2125 IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
2126 \r
2127 for (Port = 0; Port < MaxPortNumber; Port ++) { \r
2128 if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
2129 \r
2130 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
2131 Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
2132\r
2133 if (Data == 0) {\r
2134 continue;\r
2135 }\r
2136 //\r
2137 // Found device in the port\r
2138 //\r
2139 if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
2140 Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
2141\r
2142 Status = AhciWaitMemSet (\r
2143 PciIo, \r
2144 Offset,\r
2145 0x0000FFFF,\r
2146 0x00000101,\r
2147 ATA_ATAPI_TIMEOUT\r
2148 );\r
2149 if (EFI_ERROR (Status)) {\r
2150 continue;\r
2151 }\r
2152\r
2153 //\r
2154 // Now inform the IDE Controller Init Module.\r
2155 //\r
2156 IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
2157\r
2158 Data = AhciReadReg (PciIo, Offset);\r
2159\r
2160 if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
2161 Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
2162\r
2163 if (EFI_ERROR (Status)) {\r
2164 continue;\r
2165 }\r
2166\r
2167 DeviceType = EfiIdeCdrom;\r
2168 } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
2169 Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
2170\r
2171 if (EFI_ERROR (Status)) {\r
2172 continue;\r
2173 }\r
2174\r
2175 DeviceType = EfiIdeHarddisk;\r
2176 } else {\r
2177 continue;\r
2178 }\r
aca84419 2179\r
a41b5272 2180 DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
2181 Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
2182\r
12873d57 2183 //\r
2184 // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
2185 //\r
2186 if (DeviceType == EfiIdeHarddisk) {\r
2187 AhciAtaSmartSupport (\r
2188 PciIo,\r
2189 AhciRegisters,\r
2190 Port,\r
2191 0,\r
2192 &Buffer,\r
2193 NULL\r
2194 );\r
2195 }\r
2196\r
a41b5272 2197 //\r
2198 // Submit identify data to IDE controller init driver\r
2199 //\r
2200 IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
2201\r
2202 //\r
2203 // Now start to config ide device parameter and transfer mode.\r
2204 //\r
2205 Status = IdeInit->CalculateMode (\r
2206 IdeInit,\r
2207 Port,\r
2208 0,\r
2209 &SupportedModes\r
2210 );\r
2211 if (EFI_ERROR (Status)) {\r
2212 DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
2213 continue;\r
2214 }\r
2215\r
2216 //\r
2217 // Set best supported PIO mode on this IDE device\r
2218 //\r
2219 if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
2220 TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
2221 } else {\r
2222 TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
2223 }\r
2224\r
2225 TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
2226 \r
2227 //\r
2228 // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
2229 // be set together. Only one DMA mode can be set to a device. If setting\r
2230 // DMA mode operation fails, we can continue moving on because we only use\r
2231 // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
2232 //\r
2233 if (SupportedModes->UdmaMode.Valid) {\r
2234 TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
2235 TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
2236 } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
2237 TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
2238 TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode; \r
2239 }\r
2240\r
2241 Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
aca84419 2242\r
a41b5272 2243 if (EFI_ERROR (Status)) {\r
2244 DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
2245 continue;\r
2246 }\r
2247 //\r
2248 // Found a ATA or ATAPI device, add it into the device list.\r
2249 //\r
2250 CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
2251 }\r
2252 }\r
2253 }\r
2254 return EFI_SUCCESS;\r
2255}\r
2256\r