]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.c
SecurityPkg OpalPassword: Add solution without SMM device code
[mirror_edk2.git] / SecurityPkg / Tcg / Opal / OpalPasswordSmm / OpalIdeMode.c
CommitLineData
cb274a27
ED
1/** @file\r
2 This driver is used for Opal Password Feature support at IDE mode.\r
3\r
4Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "OpalPasswordSmm.h"\r
16\r
17/**\r
18 Write multiple words of Data to the IDE Data port.\r
19 Call the IO abstraction once to do the complete read,\r
20 not one word at a time\r
21\r
22 @param Port IO port to read\r
23 @param Count No. of UINT16's to read\r
24 @param Buffer Pointer to the Data Buffer for read\r
25\r
26**/\r
27VOID\r
28EFIAPI\r
29IdeWritePortWMultiple (\r
30 IN UINT16 Port,\r
31 IN UINTN Count,\r
32 IN UINT16 *Buffer\r
33 )\r
34{\r
35 UINTN Index;\r
36\r
37 for (Index = 0; Index < Count; Index++) {\r
38 IoWrite16 (Port, Buffer[Index]);\r
39 }\r
40}\r
41\r
42/**\r
43 Reads multiple words of Data from the IDE Data port.\r
44 Call the IO abstraction once to do the complete read,\r
45 not one word at a time\r
46\r
47 @param Port IO port to read\r
48 @param Count Number of UINT16's to read\r
49 @param Buffer Pointer to the Data Buffer for read\r
50\r
51**/\r
52VOID\r
53EFIAPI\r
54IdeReadPortWMultiple (\r
55 IN UINT16 Port,\r
56 IN UINTN Count,\r
57 IN UINT16 *Buffer\r
58 )\r
59{\r
60 UINTN Index;\r
61\r
62 for (Index = 0; Index < Count; Index++) {\r
63 Buffer[Count] = IoRead16 (Port);\r
64 }\r
65}\r
66\r
67/**\r
68 This function is used to analyze the Status Register and print out\r
69 some debug information and if there is ERR bit set in the Status\r
70 Register, the Error Register's Value is also be parsed and print out.\r
71\r
72 @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.\r
73\r
74**/\r
75VOID\r
76EFIAPI\r
77DumpAllIdeRegisters (\r
78 IN EFI_IDE_REGISTERS *IdeRegisters\r
79 )\r
80{\r
81 ASSERT (IdeRegisters != NULL);\r
82\r
83 DEBUG_CODE_BEGIN ();\r
84 if ((IoRead8 (IdeRegisters->CmdOrStatus) & ATA_STSREG_DWF) != 0) {\r
85 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Write Fault\n", IoRead8 (IdeRegisters->CmdOrStatus)));\r
86 }\r
87\r
88 if ((IoRead8 (IdeRegisters->CmdOrStatus) & ATA_STSREG_CORR) != 0) {\r
89 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Corrected Data\n", IoRead8 (IdeRegisters->CmdOrStatus)));\r
90 }\r
91\r
92 if ((IoRead8 (IdeRegisters->CmdOrStatus) & ATA_STSREG_ERR) != 0) {\r
93 if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_BBK) != 0) {\r
94 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Bad Block Detected\n", IoRead8 (IdeRegisters->ErrOrFeature)));\r
95 }\r
96\r
97 if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_UNC) != 0) {\r
98 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Uncorrectable Data\n", IoRead8 (IdeRegisters->ErrOrFeature)));\r
99 }\r
100\r
101 if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_MC) != 0) {\r
102 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Media Change\n", IoRead8 (IdeRegisters->ErrOrFeature)));\r
103 }\r
104\r
105 if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_ABRT) != 0) {\r
106 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Abort\n", IoRead8 (IdeRegisters->ErrOrFeature)));\r
107 }\r
108\r
109 if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_TK0NF) != 0) {\r
110 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Track 0 Not Found\n", IoRead8 (IdeRegisters->ErrOrFeature)));\r
111 }\r
112\r
113 if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_AMNF) != 0) {\r
114 DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Address Mark Not Found\n", IoRead8 (IdeRegisters->ErrOrFeature)));\r
115 }\r
116 }\r
117 DEBUG_CODE_END ();\r
118}\r
119\r
120/**\r
121 This function is used to analyze the Status Register and print out\r
122 some debug information and if there is ERR bit set in the Status\r
123 Register, the Error Register's Value is also be parsed and print out.\r
124\r
125 @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.\r
126\r
127 @retval EFI_SUCCESS No err information in the Status Register.\r
128 @retval EFI_DEVICE_ERROR Any err information in the Status Register.\r
129\r
130**/\r
131EFI_STATUS\r
132EFIAPI\r
133CheckStatusRegister (\r
134 IN EFI_IDE_REGISTERS *IdeRegisters\r
135 )\r
136{\r
137 EFI_STATUS Status;\r
138 UINT8 StatusRegister;\r
139\r
140 ASSERT (IdeRegisters != NULL);\r
141\r
142 StatusRegister = IoRead8 (IdeRegisters->CmdOrStatus);\r
143\r
144 if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {\r
145 Status = EFI_SUCCESS;\r
146 } else {\r
147 Status = EFI_DEVICE_ERROR;\r
148 }\r
149\r
150 return Status;\r
151}\r
152\r
153/**\r
154 This function is used to poll for the DRQ bit clear in the Status\r
155 Register. DRQ is cleared when the device is finished transferring Data.\r
156 So this function is called after Data transfer is finished.\r
157\r
158 @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.\r
159 @param Timeout The time to complete the command.\r
160\r
161 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
162 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
163\r
164 @note\r
165 Read Status Register will clear interrupt status.\r
166\r
167**/\r
168EFI_STATUS\r
169EFIAPI\r
170DRQClear (\r
171 IN EFI_IDE_REGISTERS *IdeRegisters,\r
172 IN UINT64 Timeout\r
173 )\r
174{\r
175 UINT32 Delay;\r
176 UINT8 StatusRegister;\r
177\r
178 ASSERT (IdeRegisters != NULL);\r
179\r
180 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
181 do {\r
182 StatusRegister = IoRead8 (IdeRegisters->CmdOrStatus);\r
183\r
184 //\r
185 // wait for BSY == 0 and DRQ == 0\r
186 //\r
187 if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
188\r
189 if ((StatusRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
190 return EFI_DEVICE_ERROR;\r
191 } else {\r
192 return EFI_SUCCESS;\r
193 }\r
194 }\r
195\r
196 //\r
197 // Stall for 100 microseconds.\r
198 //\r
199 MicroSecondDelay (100);\r
200\r
201 Delay--;\r
202\r
203 } while (Delay > 0);\r
204\r
205 return EFI_TIMEOUT;\r
206}\r
207/**\r
208 This function is used to poll for the DRQ bit clear in the Alternate\r
209 Status Register. DRQ is cleared when the device is finished\r
210 transferring Data. So this function is called after Data transfer\r
211 is finished.\r
212\r
213 @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.\r
214 @param Timeout The time to complete the command.\r
215\r
216 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
217\r
218 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
219 @note Read Alternate Status Register will not clear interrupt status.\r
220\r
221**/\r
222EFI_STATUS\r
223EFIAPI\r
224DRQClear2 (\r
225 IN EFI_IDE_REGISTERS *IdeRegisters,\r
226 IN UINT64 Timeout\r
227 )\r
228{\r
229 UINT32 Delay;\r
230 UINT8 AltRegister;\r
231\r
232 ASSERT (IdeRegisters != NULL);\r
233\r
234 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
235 do {\r
236 AltRegister = IoRead8 (IdeRegisters->AltOrDev);\r
237\r
238 //\r
239 // wait for BSY == 0 and DRQ == 0\r
240 //\r
241 if ((AltRegister & ATA_STSREG_BSY) == 0) {\r
242 if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
243 return EFI_DEVICE_ERROR;\r
244 } else {\r
245 return EFI_SUCCESS;\r
246 }\r
247 }\r
248\r
249 //\r
250 // Stall for 100 microseconds.\r
251 //\r
252 MicroSecondDelay (100);\r
253\r
254 Delay--;\r
255\r
256 } while (Delay > 0);\r
257\r
258 return EFI_TIMEOUT;\r
259}\r
260\r
261\r
262/**\r
263 This function is used to poll for the DRQ bit set in the Alternate Status Register.\r
264 DRQ is set when the device is ready to transfer Data. So this function is called after\r
265 the command is sent to the device and before required Data is transferred.\r
266\r
267 @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.\r
268 @param Timeout The time to complete the command.\r
269\r
270 @retval EFI_SUCCESS DRQ bit set within the time out.\r
271 @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
272 @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
273 @note Read Alternate Status Register will not clear interrupt status.\r
274\r
275**/\r
276EFI_STATUS\r
277EFIAPI\r
278DRQReady2 (\r
279 IN EFI_IDE_REGISTERS *IdeRegisters,\r
280 IN UINT64 Timeout\r
281 )\r
282{\r
283 UINT32 Delay;\r
284 UINT8 AltRegister;\r
285 UINT8 ErrorRegister;\r
286\r
287 ASSERT (IdeRegisters != NULL);\r
288\r
289 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
290\r
291 do {\r
292 //\r
293 // Read Alternate Status Register will not clear interrupt status\r
294 //\r
295 AltRegister = IoRead8 (IdeRegisters->AltOrDev);\r
296 //\r
297 // BSY == 0 , DRQ == 1\r
298 //\r
299 if ((AltRegister & ATA_STSREG_BSY) == 0) {\r
300 if ((AltRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
301 ErrorRegister = IoRead8 (IdeRegisters->ErrOrFeature);\r
302\r
303 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
304 return EFI_ABORTED;\r
305 }\r
306 return EFI_DEVICE_ERROR;\r
307 }\r
308\r
309 if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
310 return EFI_SUCCESS;\r
311 } else {\r
312 return EFI_NOT_READY;\r
313 }\r
314 }\r
315\r
316 //\r
317 // Stall for 100 microseconds.\r
318 //\r
319 MicroSecondDelay (100);\r
320\r
321 Delay--;\r
322 } while (Delay > 0);\r
323\r
324 return EFI_TIMEOUT;\r
325}\r
326\r
327/**\r
328 This function is used to poll for the BSY bit clear in the Status Register. BSY\r
329 is clear when the device is not busy. Every command must be sent after device is not busy.\r
330\r
331 @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.\r
332 @param Timeout The time to complete the command.\r
333\r
334 @retval EFI_SUCCESS BSY bit clear within the time out.\r
335 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
336\r
337 @note Read Status Register will clear interrupt status.\r
338**/\r
339EFI_STATUS\r
340EFIAPI\r
341WaitForBSYClear (\r
342 IN EFI_IDE_REGISTERS *IdeRegisters,\r
343 IN UINT64 Timeout\r
344 )\r
345{\r
346 UINT32 Delay;\r
347 UINT8 StatusRegister;\r
348\r
349 ASSERT (IdeRegisters != NULL);\r
350\r
351 Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
352 do {\r
353 StatusRegister = IoRead8 (IdeRegisters->CmdOrStatus);\r
354\r
355 if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
356 return EFI_SUCCESS;\r
357 }\r
358\r
359 //\r
360 // Stall for 100 microseconds.\r
361 //\r
362 MicroSecondDelay (100);\r
363\r
364 Delay--;\r
365\r
366 } while (Delay > 0);\r
367\r
368 return EFI_TIMEOUT;\r
369}\r
370\r
371/**\r
372 Get IDE i/o port registers' base addresses by mode.\r
373\r
374 In 'Compatibility' mode, use fixed addresses.\r
375 In Native-PCI mode, get base addresses from BARs in the PCI IDE controller's\r
376 Configuration Space.\r
377\r
378 The steps to get IDE i/o port registers' base addresses for each channel\r
379 as follows:\r
380\r
381 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
382 controller's Configuration Space to determine the operating mode.\r
383\r
384 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
385 ___________________________________________\r
386 | | Command Block | Control Block |\r
387 | Channel | Registers | Registers |\r
388 |___________|_______________|_______________|\r
389 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
390 |___________|_______________|_______________|\r
391 | Secondary | 170h - 177h | 376h - 377h |\r
392 |___________|_______________|_______________|\r
393\r
394 Table 1. Compatibility resource mappings\r
395\r
396 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
397 in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
398 ___________________________________________________\r
399 | | Command Block | Control Block |\r
400 | Channel | Registers | Registers |\r
401 |___________|___________________|___________________|\r
402 | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
403 |___________|___________________|___________________|\r
404 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
405 |___________|___________________|___________________|\r
406\r
407 Table 2. BARs for Register Mapping\r
408\r
409 @param[in] Bus The bus number of ata host controller.\r
410 @param[in] Device The device number of ata host controller.\r
411 @param[in] Function The function number of ata host controller.\r
412 @param[in, out] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to\r
413 store the IDE i/o port registers' base addresses\r
414\r
415 @retval EFI_UNSUPPORTED Return this Value when the BARs is not IO type\r
416 @retval EFI_SUCCESS Get the Base address successfully\r
417 @retval Other Read the pci configureation Data error\r
418\r
419**/\r
420EFI_STATUS\r
421EFIAPI\r
422GetIdeRegisterIoAddr (\r
423 IN UINTN Bus,\r
424 IN UINTN Device,\r
425 IN UINTN Function,\r
426 IN OUT EFI_IDE_REGISTERS *IdeRegisters\r
427 )\r
428{\r
429 UINT16 CommandBlockBaseAddr;\r
430 UINT16 ControlBlockBaseAddr;\r
431 UINT8 ClassCode;\r
432 UINT32 BaseAddress[4];\r
433\r
434 if (IdeRegisters == NULL) {\r
435 return EFI_INVALID_PARAMETER;\r
436 }\r
437\r
438 ClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x9));\r
439 BaseAddress[0] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x10));\r
440 BaseAddress[1] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x14));\r
441 BaseAddress[2] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x18));\r
442 BaseAddress[3] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x1C));\r
443\r
444 if ((ClassCode & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
445 CommandBlockBaseAddr = 0x1f0;\r
446 ControlBlockBaseAddr = 0x3f6;\r
447 } else {\r
448 //\r
449 // The BARs should be of IO type\r
450 //\r
451 if ((BaseAddress[0] & BIT0) == 0 ||\r
452 (BaseAddress[1] & BIT0) == 0) {\r
453 return EFI_UNSUPPORTED;\r
454 }\r
455\r
456 CommandBlockBaseAddr = (UINT16) (BaseAddress[0] & 0x0000fff8);\r
457 ControlBlockBaseAddr = (UINT16) ((BaseAddress[1] & 0x0000fffc) + 2);\r
458 }\r
459\r
460 //\r
461 // Calculate IDE primary channel I/O register base address.\r
462 //\r
463 IdeRegisters[EfiIdePrimary].Data = CommandBlockBaseAddr;\r
464 IdeRegisters[EfiIdePrimary].ErrOrFeature = (UINT16) (CommandBlockBaseAddr + 0x01);\r
465 IdeRegisters[EfiIdePrimary].SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
466 IdeRegisters[EfiIdePrimary].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
467 IdeRegisters[EfiIdePrimary].CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
468 IdeRegisters[EfiIdePrimary].CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
469 IdeRegisters[EfiIdePrimary].Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
470 IdeRegisters[EfiIdePrimary].CmdOrStatus = (UINT16) (CommandBlockBaseAddr + 0x07);\r
471 IdeRegisters[EfiIdePrimary].AltOrDev = ControlBlockBaseAddr;\r
472\r
473 if ((ClassCode & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
474 CommandBlockBaseAddr = 0x170;\r
475 ControlBlockBaseAddr = 0x376;\r
476 } else {\r
477 //\r
478 // The BARs should be of IO type\r
479 //\r
480 if ((BaseAddress[2] & BIT0) == 0 ||\r
481 (BaseAddress[3] & BIT0) == 0) {\r
482 return EFI_UNSUPPORTED;\r
483 }\r
484\r
485 CommandBlockBaseAddr = (UINT16) (BaseAddress[2] & 0x0000fff8);\r
486 ControlBlockBaseAddr = (UINT16) ((BaseAddress[3] & 0x0000fffc) + 2);\r
487 }\r
488\r
489 //\r
490 // Calculate IDE secondary channel I/O register base address.\r
491 //\r
492 IdeRegisters[EfiIdeSecondary].Data = CommandBlockBaseAddr;\r
493 IdeRegisters[EfiIdeSecondary].ErrOrFeature = (UINT16) (CommandBlockBaseAddr + 0x01);\r
494 IdeRegisters[EfiIdeSecondary].SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
495 IdeRegisters[EfiIdeSecondary].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
496 IdeRegisters[EfiIdeSecondary].CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
497 IdeRegisters[EfiIdeSecondary].CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
498 IdeRegisters[EfiIdeSecondary].Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
499 IdeRegisters[EfiIdeSecondary].CmdOrStatus = (UINT16) (CommandBlockBaseAddr + 0x07);\r
500 IdeRegisters[EfiIdeSecondary].AltOrDev = ControlBlockBaseAddr;\r
501\r
502 return EFI_SUCCESS;\r
503}\r
504\r
505/**\r
506 Send ATA Ext command into device with NON_DATA protocol.\r
507\r
508 @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.\r
509 @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK Data structure.\r
510 @param Timeout The time to complete the command.\r
511\r
512 @retval EFI_SUCCESS Reading succeed\r
513 @retval EFI_DEVICE_ERROR Error executing commands on this device.\r
514\r
515**/\r
516EFI_STATUS\r
517EFIAPI\r
518AtaIssueCommand (\r
519 IN EFI_IDE_REGISTERS *IdeRegisters,\r
520 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
521 IN UINT64 Timeout\r
522 )\r
523{\r
524 EFI_STATUS Status;\r
525 UINT8 DeviceHead;\r
526 UINT8 AtaCommand;\r
527\r
528 ASSERT (IdeRegisters != NULL);\r
529 ASSERT (AtaCommandBlock != NULL);\r
530\r
531 DeviceHead = AtaCommandBlock->AtaDeviceHead;\r
532 AtaCommand = AtaCommandBlock->AtaCommand;\r
533\r
534 Status = WaitForBSYClear (IdeRegisters, Timeout);\r
535 if (EFI_ERROR (Status)) {\r
536 return EFI_DEVICE_ERROR;\r
537 }\r
538\r
539 //\r
540 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
541 //\r
542 IoWrite8 (IdeRegisters->Head, (UINT8) (0xe0 | DeviceHead));\r
543\r
544 //\r
545 // set all the command parameters\r
546 // Before write to all the following registers, BSY and DRQ must be 0.\r
547 //\r
548 Status = DRQClear2 (IdeRegisters, Timeout);\r
549 if (EFI_ERROR (Status)) {\r
550 return EFI_DEVICE_ERROR;\r
551 }\r
552\r
553 //\r
554 // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
555 //\r
556 IoWrite8 (IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeaturesExp);\r
557 IoWrite8 (IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeatures);\r
558\r
559 //\r
560 // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
561 //\r
562 IoWrite8 (IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCountExp);\r
563 IoWrite8 (IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCount);\r
564\r
565 //\r
566 // Fill the start LBA registers, which are also two-byte FIFO\r
567 //\r
568 IoWrite8 (IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumberExp);\r
569 IoWrite8 (IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumber);\r
570\r
571 IoWrite8 (IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLowExp);\r
572 IoWrite8 (IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLow);\r
573\r
574 IoWrite8 (IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHighExp);\r
575 IoWrite8 (IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHigh);\r
576\r
577 //\r
578 // Send command via Command Register\r
579 //\r
580 IoWrite8 (IdeRegisters->CmdOrStatus, AtaCommand);\r
581\r
582 //\r
583 // Stall at least 400 microseconds.\r
584 //\r
585 MicroSecondDelay (400);\r
586\r
587 return EFI_SUCCESS;\r
588}\r
589\r
590/**\r
591 This function is used to send out ATA commands conforms to the PIO Data In Protocol.\r
592\r
593 @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.\r
594 @param Buffer A pointer to the source Buffer for the Data.\r
595 @param ByteCount The Length of the Data.\r
596 @param Read Flag used to determine the Data transfer direction.\r
597 Read equals 1, means Data transferred from device to host;\r
598 Read equals 0, means Data transferred from host to device.\r
599 @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK Data structure.\r
600 @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK Data structure.\r
601 @param Timeout The time to complete the command.\r
602\r
603 @retval EFI_SUCCESS send out the ATA command and device send required Data successfully.\r
604 @retval EFI_DEVICE_ERROR command sent failed.\r
605\r
606**/\r
607EFI_STATUS\r
608EFIAPI\r
609AtaPioDataInOut (\r
610 IN EFI_IDE_REGISTERS *IdeRegisters,\r
611 IN OUT VOID *Buffer,\r
612 IN UINT64 ByteCount,\r
613 IN BOOLEAN Read,\r
614 IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,\r
615 IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,\r
616 IN UINT64 Timeout\r
617 )\r
618{\r
619 UINTN WordCount;\r
620 UINTN Increment;\r
621 UINT16 *Buffer16;\r
622 EFI_STATUS Status;\r
623\r
624 if ((IdeRegisters == NULL) || (Buffer == NULL) || (AtaCommandBlock == NULL)) {\r
625 return EFI_INVALID_PARAMETER;\r
626 }\r
627\r
628 //\r
629 // Issue ATA command\r
630 //\r
631 Status = AtaIssueCommand (IdeRegisters, AtaCommandBlock, Timeout);\r
632 if (EFI_ERROR (Status)) {\r
633 Status = EFI_DEVICE_ERROR;\r
634 goto Exit;\r
635 }\r
636\r
637 Buffer16 = (UINT16 *) Buffer;\r
638\r
639 //\r
640 // According to PIO Data in protocol, host can perform a series of reads to\r
641 // the Data register after each time device set DRQ ready;\r
642 // The Data Size of "a series of read" is command specific.\r
643 // For most ATA command, Data Size received from device will not exceed\r
644 // 1 sector, hence the Data Size for "a series of read" can be the whole Data\r
645 // Size of one command request.\r
646 // For ATA command such as Read Sector command, the Data Size of one ATA\r
647 // command request is often larger than 1 sector, according to the\r
648 // Read Sector command, the Data Size of "a series of read" is exactly 1\r
649 // sector.\r
650 // Here for simplification reason, we specify the Data Size for\r
651 // "a series of read" to 1 sector (256 words) if Data Size of one ATA command\r
652 // request is larger than 256 words.\r
653 //\r
654 Increment = 256;\r
655\r
656 //\r
657 // used to record bytes of currently transfered Data\r
658 //\r
659 WordCount = 0;\r
660\r
661 while (WordCount < RShiftU64(ByteCount, 1)) {\r
662 //\r
663 // Poll DRQ bit set, Data transfer can be performed only when DRQ is ready\r
664 //\r
665 Status = DRQReady2 (IdeRegisters, Timeout);\r
666 if (EFI_ERROR (Status)) {\r
667 Status = EFI_DEVICE_ERROR;\r
668 goto Exit;\r
669 }\r
670\r
671 //\r
672 // Get the byte count for one series of read\r
673 //\r
674 if ((WordCount + Increment) > RShiftU64(ByteCount, 1)) {\r
675 Increment = (UINTN)(RShiftU64(ByteCount, 1) - WordCount);\r
676 }\r
677\r
678 if (Read) {\r
679 IdeReadPortWMultiple (\r
680 IdeRegisters->Data,\r
681 Increment,\r
682 Buffer16\r
683 );\r
684 } else {\r
685 IdeWritePortWMultiple (\r
686 IdeRegisters->Data,\r
687 Increment,\r
688 Buffer16\r
689 );\r
690 }\r
691\r
692 Status = CheckStatusRegister (IdeRegisters);\r
693 if (EFI_ERROR (Status)) {\r
694 Status = EFI_DEVICE_ERROR;\r
695 goto Exit;\r
696 }\r
697\r
698 WordCount += Increment;\r
699 Buffer16 += Increment;\r
700 }\r
701\r
702 Status = DRQClear (IdeRegisters, Timeout);\r
703 if (EFI_ERROR (Status)) {\r
704 Status = EFI_DEVICE_ERROR;\r
705 goto Exit;\r
706 }\r
707\r
708Exit:\r
709 //\r
710 // Dump All Ide registers to ATA_STATUS_BLOCK\r
711 //\r
712 DumpAllIdeRegisters (IdeRegisters);\r
713\r
714 return Status;\r
715}\r
716\r
717/**\r
718 Sends out an ATA Identify Command to the specified device.\r
719\r
720 This function sends out the ATA Identify Command to the\r
721 specified device. Only ATA device responses to this command. If\r
722 the command succeeds, it returns the Identify Data structure which\r
723 contains information about the device. This function extracts the\r
724 information it needs to fill the IDE_BLK_IO_DEV Data structure,\r
725 including device type, media block Size, media capacity, and etc.\r
726\r
727 @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.\r
728 @param Channel The channel number of device.\r
729 @param Device The device number of device.\r
730 @param Buffer A pointer to Data Buffer which is used to contain IDENTIFY Data.\r
731\r
732 @retval EFI_SUCCESS Identify ATA device successfully.\r
733 @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.\r
734 @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
735**/\r
736EFI_STATUS\r
737EFIAPI\r
738AtaIdentify (\r
739 IN EFI_IDE_REGISTERS *IdeRegisters,\r
740 IN UINT8 Channel,\r
741 IN UINT8 Device,\r
742 IN OUT ATA_IDENTIFY_DATA *Buffer\r
743 )\r
744{\r
745 EFI_STATUS Status;\r
746 EFI_ATA_COMMAND_BLOCK AtaCommandBlock;\r
747\r
748 ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
749\r
750 AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
751 AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
752\r
753 Status = AtaPioDataInOut (\r
754 IdeRegisters,\r
755 Buffer,\r
756 sizeof (ATA_IDENTIFY_DATA),\r
757 TRUE,\r
758 &AtaCommandBlock,\r
759 NULL,\r
760 ATA_TIMEOUT\r
761 );\r
762\r
763 return Status;\r
764}\r
765\r
766\r
767\r