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