]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaBusDxe / AtaPassThruExecute.c
CommitLineData
ad86a50a 1/** @file\r
2 This file implements ATA pass through transaction for ATA bus driver.\r
3\r
4 This file implements the low level execution of ATA pass through transaction.\r
5 It transforms the high level identity, read/write, reset command to ATA pass\r
c24097a5 6 through command and protocol.\r
7\r
3c063fed 8 NOTE: This file also implements the StorageSecurityCommandProtocol(SSP). For input\r
58727f29 9 parameter SecurityProtocolSpecificData, ATA spec has no explicitly definition\r
10 for Security Protocol Specific layout. This implementation uses big endian for\r
c24097a5 11 Cylinder register.\r
58727f29 12\r
d1102dba 13 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
2d273c8d 14 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
cd5ebaa0 15 This program and the accompanying materials\r
ad86a50a 16 are licensed and made available under the terms and conditions of the BSD License\r
17 which accompanies this distribution. The full text of the license may be found at\r
18 http://opensource.org/licenses/bsd-license.php\r
19\r
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
22\r
23\r
24**/\r
25\r
26#include "AtaBus.h"\r
27\r
c24097a5 28#define ATA_CMD_TRUST_NON_DATA 0x5B\r
29#define ATA_CMD_TRUST_RECEIVE 0x5C\r
30#define ATA_CMD_TRUST_RECEIVE_DMA 0x5D\r
31#define ATA_CMD_TRUST_SEND 0x5E\r
32#define ATA_CMD_TRUST_SEND_DMA 0x5F\r
33\r
ad86a50a 34//\r
35// Look up table (UdmaValid, IsWrite) for EFI_ATA_PASS_THRU_CMD_PROTOCOL\r
36//\r
37EFI_ATA_PASS_THRU_CMD_PROTOCOL mAtaPassThruCmdProtocols[][2] = {\r
38 {\r
39 EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN,\r
40 EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT\r
41 },\r
42 {\r
43 EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN,\r
44 EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT,\r
45 }\r
46};\r
47\r
48//\r
49// Look up table (UdmaValid, Lba48Bit, IsIsWrite) for ATA_CMD\r
50//\r
51UINT8 mAtaCommands[][2][2] = {\r
52 {\r
53 {\r
54 ATA_CMD_READ_SECTORS, // 28-bit LBA; PIO read\r
55 ATA_CMD_WRITE_SECTORS // 28-bit LBA; PIO write\r
56 },\r
57 {\r
58 ATA_CMD_READ_SECTORS_EXT, // 48-bit LBA; PIO read\r
59 ATA_CMD_WRITE_SECTORS_EXT // 48-bit LBA; PIO write\r
60 }\r
61 },\r
62 {\r
63 {\r
64 ATA_CMD_READ_DMA, // 28-bit LBA; DMA read\r
65 ATA_CMD_WRITE_DMA // 28-bit LBA; DMA write\r
66 },\r
67 {\r
68 ATA_CMD_READ_DMA_EXT, // 48-bit LBA; DMA read\r
69 ATA_CMD_WRITE_DMA_EXT // 48-bit LBA; DMA write\r
70 }\r
71 }\r
72};\r
73\r
c24097a5 74//\r
75// Look up table (UdmaValid, IsTrustSend) for ATA_CMD\r
76//\r
58727f29 77UINT8 mAtaTrustCommands[2][2] = {\r
c24097a5 78 {\r
79 ATA_CMD_TRUST_RECEIVE, // PIO read\r
80 ATA_CMD_TRUST_SEND // PIO write\r
81 },\r
82 {\r
83 ATA_CMD_TRUST_RECEIVE_DMA, // DMA read\r
84 ATA_CMD_TRUST_SEND_DMA // DMA write\r
85 }\r
86};\r
87\r
88\r
ad86a50a 89//\r
90// Look up table (Lba48Bit) for maximum transfer block number\r
91//\r
92UINTN mMaxTransferBlockNumber[] = {\r
93 MAX_28BIT_TRANSFER_BLOCK_NUM,\r
94 MAX_48BIT_TRANSFER_BLOCK_NUM\r
95};\r
96\r
97\r
98/**\r
99 Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.PassThru().\r
100\r
101 This function wraps the PassThru() invocation for ATA pass through function\r
102 for an ATA device. It assembles the ATA pass through command packet for ATA\r
103 transaction.\r
104\r
490b5ea1 105 @param[in, out] AtaDevice The ATA child device involved for the operation.\r
58727f29 106 @param[in, out] TaskPacket Pointer to a Pass Thru Command Packet. Optional,\r
490b5ea1 107 if it is NULL, blocking mode, and use the packet\r
108 in AtaDevice. If it is not NULL, non blocking mode,\r
109 and pass down this Packet.\r
86d8e199 110 @param[in, out] Event If Event is NULL, then blocking I/O is performed.\r
490b5ea1 111 If Event is not NULL and non-blocking I/O is\r
112 supported,then non-blocking I/O is performed,\r
113 and Event will be signaled when the write\r
114 request is completed.\r
ad86a50a 115\r
116 @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().\r
117\r
118**/\r
119EFI_STATUS\r
120AtaDevicePassThru (\r
490b5ea1 121 IN OUT ATA_DEVICE *AtaDevice,\r
122 IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL\r
123 IN OUT EFI_EVENT Event OPTIONAL\r
ad86a50a 124 )\r
125{\r
126 EFI_STATUS Status;\r
127 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
128 EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;\r
129\r
130 //\r
58727f29 131 // Assemble packet. If it is non blocking mode, the Ata driver should keep each\r
490b5ea1 132 // subtask and clean them when the event is signaled.\r
ad86a50a 133 //\r
490b5ea1 134 if (TaskPacket != NULL) {\r
135 Packet = TaskPacket;\r
3c063fed 136 Packet->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (EFI_ATA_STATUS_BLOCK));\r
3d267c70
ED
137 if (Packet->Asb == NULL) {\r
138 return EFI_OUT_OF_RESOURCES;\r
139 }\r
140\r
3c063fed 141 CopyMem (Packet->Asb, AtaDevice->Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
142 Packet->Acb = AllocateCopyPool (sizeof (EFI_ATA_COMMAND_BLOCK), &AtaDevice->Acb);\r
490b5ea1 143 } else {\r
144 Packet = &AtaDevice->Packet;\r
145 Packet->Asb = AtaDevice->Asb;\r
146 Packet->Acb = &AtaDevice->Acb;\r
147 }\r
ad86a50a 148\r
149 AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
150\r
151 Status = AtaPassThru->PassThru (\r
152 AtaPassThru,\r
153 AtaDevice->Port,\r
154 AtaDevice->PortMultiplierPort,\r
155 Packet,\r
490b5ea1 156 Event\r
ad86a50a 157 );\r
158 //\r
159 // Ensure ATA pass through caller and callee have the same\r
58727f29 160 // interpretation of ATA pass through protocol.\r
ad86a50a 161 //\r
162 ASSERT (Status != EFI_INVALID_PARAMETER);\r
163 ASSERT (Status != EFI_BAD_BUFFER_SIZE);\r
164\r
165 return Status;\r
166}\r
167\r
168\r
169/**\r
170 Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.ResetDevice().\r
171\r
172 This function wraps the ResetDevice() invocation for ATA pass through function\r
58727f29 173 for an ATA device.\r
ad86a50a 174\r
175 @param AtaDevice The ATA child device involved for the operation.\r
176\r
177 @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().\r
178\r
179**/\r
180EFI_STATUS\r
181ResetAtaDevice (\r
182 IN ATA_DEVICE *AtaDevice\r
183 )\r
184{\r
185 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
58727f29 186\r
ad86a50a 187 AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
58727f29 188\r
37623a5c 189 //\r
190 // Report Status Code to indicate reset happens\r
191 //\r
192 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
193 EFI_PROGRESS_CODE,\r
194 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),\r
195 AtaDevice->AtaBusDriverData->ParentDevicePath\r
196 );\r
197\r
ad86a50a 198 return AtaPassThru->ResetDevice (\r
199 AtaPassThru,\r
200 AtaDevice->Port,\r
201 AtaDevice->PortMultiplierPort\r
202 );\r
203}\r
204\r
205\r
206/**\r
207 Prints ATA model name to ATA device structure.\r
208\r
58727f29 209 This function converts ATA device model name from ATA identify data\r
ad86a50a 210 to a string in ATA device structure. It needs to change the character\r
211 order in the original model name string.\r
212\r
213 @param AtaDevice The ATA child device involved for the operation.\r
214\r
215**/\r
216VOID\r
217PrintAtaModelName (\r
218 IN OUT ATA_DEVICE *AtaDevice\r
219 )\r
220{\r
221 UINTN Index;\r
222 CHAR8 *Source;\r
223 CHAR16 *Destination;\r
224\r
6ea8e37b 225 Source = AtaDevice->IdentifyData->ModelName;\r
ad86a50a 226 Destination = AtaDevice->ModelName;\r
227\r
228 //\r
229 // Swap the byte order in the original module name.\r
230 //\r
231 for (Index = 0; Index < MAX_MODEL_NAME_LEN; Index += 2) {\r
232 Destination[Index] = Source[Index + 1];\r
233 Destination[Index + 1] = Source[Index];\r
234 }\r
235 AtaDevice->ModelName[MAX_MODEL_NAME_LEN] = L'\0';\r
236}\r
237\r
238\r
239/**\r
240 Gets ATA device Capacity according to ATA 6.\r
241\r
242 This function returns the capacity of the ATA device if it follows\r
243 ATA 6 to support 48 bit addressing.\r
244\r
245 @param AtaDevice The ATA child device involved for the operation.\r
246\r
247 @return The capacity of the ATA device or 0 if the device does not support\r
248 48-bit addressing defined in ATA 6.\r
249\r
250**/\r
251EFI_LBA\r
252GetAtapi6Capacity (\r
253 IN ATA_DEVICE *AtaDevice\r
254 )\r
255{\r
256 EFI_LBA Capacity;\r
257 EFI_LBA TmpLba;\r
258 UINTN Index;\r
6ea8e37b 259 ATA_IDENTIFY_DATA *IdentifyData;\r
ad86a50a 260\r
6ea8e37b 261 IdentifyData = AtaDevice->IdentifyData;\r
262 if ((IdentifyData->command_set_supported_83 & BIT10) == 0) {\r
ad86a50a 263 //\r
264 // The device doesn't support 48 bit addressing\r
265 //\r
266 return 0;\r
267 }\r
268\r
269 //\r
270 // 48 bit address feature set is supported, get maximum capacity\r
271 //\r
272 Capacity = 0;\r
273 for (Index = 0; Index < 4; Index++) {\r
274 //\r
275 // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r
276 //\r
6ea8e37b 277 TmpLba = IdentifyData->maximum_lba_for_48bit_addressing[Index];\r
ad86a50a 278 Capacity |= LShiftU64 (TmpLba, 16 * Index);\r
279 }\r
280\r
281 return Capacity;\r
282}\r
283\r
284\r
285/**\r
286 Identifies ATA device via the Identify data.\r
287\r
58727f29 288 This function identifies the ATA device and initializes the Media information in\r
ad86a50a 289 Block IO protocol interface.\r
290\r
291 @param AtaDevice The ATA child device involved for the operation.\r
292\r
293 @retval EFI_UNSUPPORTED The device is not a valid ATA device (hard disk).\r
294 @retval EFI_SUCCESS The device is successfully identified and Media information\r
295 is correctly initialized.\r
296\r
297**/\r
298EFI_STATUS\r
299IdentifyAtaDevice (\r
300 IN OUT ATA_DEVICE *AtaDevice\r
301 )\r
302{\r
6ea8e37b 303 ATA_IDENTIFY_DATA *IdentifyData;\r
ad86a50a 304 EFI_BLOCK_IO_MEDIA *BlockMedia;\r
305 EFI_LBA Capacity;\r
306 UINT16 PhyLogicSectorSupport;\r
307 UINT16 UdmaMode;\r
308\r
6ea8e37b 309 IdentifyData = AtaDevice->IdentifyData;\r
ad86a50a 310\r
311 if ((IdentifyData->config & BIT15) != 0) {\r
312 //\r
313 // This is not an hard disk\r
314 //\r
315 return EFI_UNSUPPORTED;\r
316 }\r
317\r
25dd150b 318 DEBUG ((EFI_D_INFO, "AtaBus - Identify Device: Port %x PortMultiplierPort %x\n", AtaDevice->Port, AtaDevice->PortMultiplierPort));\r
490b5ea1 319\r
ad86a50a 320 //\r
321 // Check whether the WORD 88 (supported UltraDMA by drive) is valid\r
322 //\r
323 if ((IdentifyData->field_validity & BIT2) != 0) {\r
324 UdmaMode = IdentifyData->ultra_dma_mode;\r
325 if ((UdmaMode & (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0) {\r
326 //\r
327 // If BIT0~BIT6 is selected, then UDMA is supported\r
328 //\r
329 AtaDevice->UdmaValid = TRUE;\r
330 }\r
331 }\r
332\r
333 Capacity = GetAtapi6Capacity (AtaDevice);\r
334 if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {\r
335 //\r
336 // Capacity exceeds 120GB. 48-bit addressing is really needed\r
337 //\r
338 AtaDevice->Lba48Bit = TRUE;\r
339 } else {\r
340 //\r
341 // This is a hard disk <= 120GB capacity, treat it as normal hard disk\r
342 //\r
343 Capacity = ((UINT32)IdentifyData->user_addressable_sectors_hi << 16) | IdentifyData->user_addressable_sectors_lo;\r
344 AtaDevice->Lba48Bit = FALSE;\r
345 }\r
346\r
347 //\r
348 // Block Media Information:\r
349 //\r
350 BlockMedia = &AtaDevice->BlockMedia;\r
351 BlockMedia->LastBlock = Capacity - 1;\r
907c1a00 352 BlockMedia->IoAlign = AtaDevice->AtaBusDriverData->AtaPassThru->Mode->IoAlign;\r
ad86a50a 353 //\r
354 // Check whether Long Physical Sector Feature is supported\r
355 //\r
356 PhyLogicSectorSupport = IdentifyData->phy_logic_sector_support;\r
357 if ((PhyLogicSectorSupport & (BIT14 | BIT15)) == BIT14) {\r
358 //\r
359 // Check whether one physical block contains multiple physical blocks\r
360 //\r
361 if ((PhyLogicSectorSupport & BIT13) != 0) {\r
362 BlockMedia->LogicalBlocksPerPhysicalBlock = (UINT32) (1 << (PhyLogicSectorSupport & 0x000f));\r
363 //\r
364 // Check lowest alignment of logical blocks within physical block\r
365 //\r
366 if ((IdentifyData->alignment_logic_in_phy_blocks & (BIT14 | BIT15)) == BIT14) {\r
c61f9362 367 BlockMedia->LowestAlignedLba = (EFI_LBA) ((BlockMedia->LogicalBlocksPerPhysicalBlock - ((UINT32)IdentifyData->alignment_logic_in_phy_blocks & 0x3fff)) %\r
368 BlockMedia->LogicalBlocksPerPhysicalBlock);\r
ad86a50a 369 }\r
370 }\r
371 //\r
372 // Check logical block size\r
373 //\r
374 if ((PhyLogicSectorSupport & BIT12) != 0) {\r
375 BlockMedia->BlockSize = (UINT32) (((IdentifyData->logic_sector_size_hi << 16) | IdentifyData->logic_sector_size_lo) * sizeof (UINT16));\r
376 }\r
377 AtaDevice->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
378 }\r
379 //\r
58727f29 380 // Get ATA model name from identify data structure.\r
ad86a50a 381 //\r
490b5ea1 382 PrintAtaModelName (AtaDevice);\r
ad86a50a 383\r
384 return EFI_SUCCESS;\r
385}\r
386\r
387\r
388/**\r
389 Discovers whether it is a valid ATA device.\r
390\r
391 This function issues ATA_CMD_IDENTIFY_DRIVE command to the ATA device to identify it.\r
392 If the command is executed successfully, it then identifies it and initializes\r
393 the Media information in Block IO protocol interface.\r
394\r
395 @param AtaDevice The ATA child device involved for the operation.\r
396\r
397 @retval EFI_SUCCESS The device is successfully identified and Media information\r
398 is correctly initialized.\r
58727f29 399 @return others Some error occurs when discovering the ATA device.\r
ad86a50a 400\r
401**/\r
402EFI_STATUS\r
403DiscoverAtaDevice (\r
404 IN OUT ATA_DEVICE *AtaDevice\r
405 )\r
406{\r
407 EFI_STATUS Status;\r
408 EFI_ATA_COMMAND_BLOCK *Acb;\r
409 EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;\r
410 UINTN Retry;\r
411\r
412 //\r
413 // Prepare for ATA command block.\r
414 //\r
3c063fed 415 Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));\r
ad86a50a 416 Acb->AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
2d273c8d 417 Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));\r
ad86a50a 418\r
419 //\r
420 // Prepare for ATA pass through packet.\r
421 //\r
3c063fed 422 Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
ad86a50a 423 Packet->InDataBuffer = AtaDevice->IdentifyData;\r
3c063fed 424 Packet->InTransferLength = sizeof (ATA_IDENTIFY_DATA);\r
ad86a50a 425 Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;\r
490b5ea1 426 Packet->Length = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
427 Packet->Timeout = ATA_TIMEOUT;\r
ad86a50a 428\r
429 Retry = MAX_RETRY_TIMES;\r
430 do {\r
490b5ea1 431 Status = AtaDevicePassThru (AtaDevice, NULL, NULL);\r
ad86a50a 432 if (!EFI_ERROR (Status)) {\r
433 //\r
434 // The command is issued successfully\r
435 //\r
436 Status = IdentifyAtaDevice (AtaDevice);\r
0d5df2ab 437 return Status;\r
ad86a50a 438 }\r
439 } while (Retry-- > 0);\r
440\r
441 return Status;\r
442}\r
443\r
444/**\r
445 Transfer data from ATA device.\r
446\r
447 This function performs one ATA pass through transaction to transfer data from/to\r
448 ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru\r
449 interface of ATA pass through.\r
450\r
490b5ea1 451 @param[in, out] AtaDevice The ATA child device involved for the operation.\r
58727f29 452 @param[in, out] TaskPacket Pointer to a Pass Thru Command Packet. Optional,\r
490b5ea1 453 if it is NULL, blocking mode, and use the packet\r
454 in AtaDevice. If it is not NULL, non blocking mode,\r
455 and pass down this Packet.\r
456 @param[in, out] Buffer The pointer to the current transaction buffer.\r
457 @param[in] StartLba The starting logical block address to be accessed.\r
458 @param[in] TransferLength The block number or sector count of the transfer.\r
459 @param[in] IsWrite Indicates whether it is a write operation.\r
460 @param[in] Event If Event is NULL, then blocking I/O is performed.\r
461 If Event is not NULL and non-blocking I/O is\r
462 supported,then non-blocking I/O is performed,\r
463 and Event will be signaled when the write\r
464 request is completed.\r
ad86a50a 465\r
466 @retval EFI_SUCCESS The data transfer is complete successfully.\r
58727f29 467 @return others Some error occurs when transferring data.\r
ad86a50a 468\r
469**/\r
470EFI_STATUS\r
471TransferAtaDevice (\r
490b5ea1 472 IN OUT ATA_DEVICE *AtaDevice,\r
473 IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *TaskPacket, OPTIONAL\r
474 IN OUT VOID *Buffer,\r
475 IN EFI_LBA StartLba,\r
476 IN UINT32 TransferLength,\r
58727f29 477 IN BOOLEAN IsWrite,\r
490b5ea1 478 IN EFI_EVENT Event OPTIONAL\r
ad86a50a 479 )\r
480{\r
481 EFI_ATA_COMMAND_BLOCK *Acb;\r
482 EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;\r
483\r
423401f9 484 //\r
58727f29 485 // Ensure AtaDevice->UdmaValid, AtaDevice->Lba48Bit and IsWrite are valid boolean values\r
423401f9 486 //\r
61d4f8f9 487 ASSERT ((UINTN) AtaDevice->UdmaValid < 2);\r
423401f9 488 ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);\r
489 ASSERT ((UINTN) IsWrite < 2);\r
ad86a50a 490 //\r
491 // Prepare for ATA command block.\r
492 //\r
3c063fed 493 Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));\r
ad86a50a 494 Acb->AtaCommand = mAtaCommands[AtaDevice->UdmaValid][AtaDevice->Lba48Bit][IsWrite];\r
495 Acb->AtaSectorNumber = (UINT8) StartLba;\r
496 Acb->AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);\r
497 Acb->AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16);\r
4c33f8b1 498 Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));\r
423401f9 499 Acb->AtaSectorCount = (UINT8) TransferLength;\r
ad86a50a 500 if (AtaDevice->Lba48Bit) {\r
501 Acb->AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);\r
423401f9 502 Acb->AtaCylinderLowExp = (UINT8) RShiftU64 (StartLba, 32);\r
503 Acb->AtaCylinderHighExp = (UINT8) RShiftU64 (StartLba, 40);\r
504 Acb->AtaSectorCountExp = (UINT8) (TransferLength >> 8);\r
ad86a50a 505 } else {\r
506 Acb->AtaDeviceHead = (UINT8) (Acb->AtaDeviceHead | RShiftU64 (StartLba, 24));\r
507 }\r
ad86a50a 508\r
509 //\r
510 // Prepare for ATA pass through packet.\r
511 //\r
490b5ea1 512 if (TaskPacket != NULL) {\r
3c063fed 513 Packet = ZeroMem (TaskPacket, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
490b5ea1 514 } else {\r
3c063fed 515 Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
490b5ea1 516 }\r
517\r
ad86a50a 518 if (IsWrite) {\r
519 Packet->OutDataBuffer = Buffer;\r
520 Packet->OutTransferLength = TransferLength;\r
521 } else {\r
522 Packet->InDataBuffer = Buffer;\r
523 Packet->InTransferLength = TransferLength;\r
524 }\r
490b5ea1 525\r
ad86a50a 526 Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsWrite];\r
527 Packet->Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
9690325d 528 //\r
529 // |------------------------|-----------------|------------------------|-----------------|\r
530 // | ATA PIO Transfer Mode | Transfer Rate | ATA DMA Transfer Mode | Transfer Rate |\r
531 // |------------------------|-----------------|------------------------|-----------------|\r
532 // | PIO Mode 0 | 3.3Mbytes/sec | Single-word DMA Mode 0 | 2.1Mbytes/sec |\r
533 // |------------------------|-----------------|------------------------|-----------------|\r
534 // | PIO Mode 1 | 5.2Mbytes/sec | Single-word DMA Mode 1 | 4.2Mbytes/sec |\r
535 // |------------------------|-----------------|------------------------|-----------------|\r
536 // | PIO Mode 2 | 8.3Mbytes/sec | Single-word DMA Mode 2 | 8.4Mbytes/sec |\r
537 // |------------------------|-----------------|------------------------|-----------------|\r
538 // | PIO Mode 3 | 11.1Mbytes/sec | Multi-word DMA Mode 0 | 4.2Mbytes/sec |\r
539 // |------------------------|-----------------|------------------------|-----------------|\r
540 // | PIO Mode 4 | 16.6Mbytes/sec | Multi-word DMA Mode 1 | 13.3Mbytes/sec |\r
541 // |------------------------|-----------------|------------------------|-----------------|\r
542 //\r
543 // As AtaBus is used to manage ATA devices, we have to use the lowest transfer rate to\r
544 // calculate the possible maximum timeout value for each read/write operation.\r
8e1f0612
FT
545 // The timout value is rounded up to nearest integar and here an additional 30s is added\r
546 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond\r
547 // commands in the Standby/Idle mode.\r
9690325d 548 //\r
549 if (AtaDevice->UdmaValid) {\r
550 //\r
551 // Calculate the maximum timeout value for DMA read/write operation.\r
552 //\r
8e1f0612 553 Packet->Timeout = EFI_TIMER_PERIOD_SECONDS (DivU64x32 (MultU64x32 (TransferLength, AtaDevice->BlockMedia.BlockSize), 2100000) + 31);\r
9690325d 554 } else {\r
555 //\r
556 // Calculate the maximum timeout value for PIO read/write operation\r
557 //\r
8e1f0612 558 Packet->Timeout = EFI_TIMER_PERIOD_SECONDS (DivU64x32 (MultU64x32 (TransferLength, AtaDevice->BlockMedia.BlockSize), 3300000) + 31);\r
9690325d 559 }\r
490b5ea1 560\r
561 return AtaDevicePassThru (AtaDevice, TaskPacket, Event);\r
562}\r
563\r
564/**\r
58727f29 565 Free SubTask.\r
490b5ea1 566\r
567 @param[in, out] Task Pointer to task to be freed.\r
568\r
569**/\r
570VOID\r
58727f29 571EFIAPI\r
490b5ea1 572FreeAtaSubTask (\r
58727f29 573 IN OUT ATA_BUS_ASYN_SUB_TASK *Task\r
490b5ea1 574 )\r
575{\r
576 if (Task->Packet.Asb != NULL) {\r
3c063fed 577 FreeAlignedBuffer (Task->Packet.Asb, sizeof (EFI_ATA_STATUS_BLOCK));\r
490b5ea1 578 }\r
579 if (Task->Packet.Acb != NULL) {\r
580 FreePool (Task->Packet.Acb);\r
581 }\r
582\r
583 FreePool (Task);\r
584}\r
585\r
71fd9fae
TF
586/**\r
587 Terminate any in-flight non-blocking I/O requests by signaling an EFI_ABORTED\r
588 in the TransactionStatus member of the EFI_BLOCK_IO2_TOKEN for the non-blocking\r
589 I/O. After that it is safe to free any Token or Buffer data structures that\r
590 were allocated to initiate the non-blockingI/O requests that were in-flight for\r
591 this device.\r
592\r
593 @param[in] AtaDevice The ATA child device involved for the operation.\r
594\r
595**/\r
596VOID\r
597EFIAPI\r
598AtaTerminateNonBlockingTask (\r
599 IN ATA_DEVICE *AtaDevice\r
600 )\r
601{\r
602 BOOLEAN SubTaskEmpty;\r
603 EFI_TPL OldTpl;\r
604 ATA_BUS_ASYN_TASK *AtaTask;\r
605 LIST_ENTRY *Entry;\r
606 LIST_ENTRY *List;\r
607\r
608 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
609 //\r
610 // Abort all executing tasks from now.\r
611 //\r
612 AtaDevice->Abort = TRUE;\r
613\r
614 List = &AtaDevice->AtaTaskList;\r
615 for (Entry = GetFirstNode (List); !IsNull (List, Entry);) {\r
616 AtaTask = ATA_ASYN_TASK_FROM_ENTRY (Entry);\r
617 AtaTask->Token->TransactionStatus = EFI_ABORTED;\r
618 gBS->SignalEvent (AtaTask->Token->Event);\r
619\r
620 Entry = RemoveEntryList (Entry);\r
621 FreePool (AtaTask);\r
622 }\r
623 gBS->RestoreTPL (OldTpl);\r
624\r
625 do {\r
626 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
627 //\r
628 // Wait for executing subtasks done.\r
629 //\r
630 SubTaskEmpty = IsListEmpty (&AtaDevice->AtaSubTaskList);\r
631 gBS->RestoreTPL (OldTpl);\r
632 } while (!SubTaskEmpty);\r
633\r
634 //\r
635 // Aborting operation has been done. From now on, don't need to abort normal operation.\r
d1102dba 636 //\r
71fd9fae
TF
637 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
638 AtaDevice->Abort = FALSE;\r
639 gBS->RestoreTPL (OldTpl);\r
640}\r
641\r
490b5ea1 642/**\r
643 Call back funtion when the event is signaled.\r
644\r
645 @param[in] Event The Event this notify function registered to.\r
3c063fed 646 @param[in] Context Pointer to the context data registered to the\r
490b5ea1 647 Event.\r
648\r
649**/\r
650VOID\r
58727f29 651EFIAPI\r
490b5ea1 652AtaNonBlockingCallBack (\r
653 IN EFI_EVENT Event,\r
654 IN VOID *Context\r
655 )\r
656{\r
58727f29 657 ATA_BUS_ASYN_SUB_TASK *Task;\r
658 ATA_BUS_ASYN_TASK *AtaTask;\r
659 ATA_DEVICE *AtaDevice;\r
660 LIST_ENTRY *Entry;\r
661 EFI_STATUS Status;\r
490b5ea1 662\r
58727f29 663 Task = (ATA_BUS_ASYN_SUB_TASK *) Context;\r
490b5ea1 664 gBS->CloseEvent (Event);\r
665\r
58727f29 666 AtaDevice = Task->AtaDevice;\r
667\r
490b5ea1 668 //\r
669 // Check the command status.\r
670 // If there is error during the sub task source allocation, the error status\r
671 // should be returned to the caller directly, so here the Task->Token may already\r
672 // be deleted by the caller and no need to update the status.\r
673 //\r
3c063fed 674 if ((!(*Task->IsError)) && ((Task->Packet.Asb->AtaStatus & 0x01) == 0x01)) {\r
490b5ea1 675 Task->Token->TransactionStatus = EFI_DEVICE_ERROR;\r
676 }\r
71fd9fae
TF
677\r
678 if (AtaDevice->Abort) {\r
679 Task->Token->TransactionStatus = EFI_ABORTED;\r
680 }\r
681\r
490b5ea1 682 DEBUG ((\r
25dd150b
SZ
683 EFI_D_BLKIO,\r
684 "NON-BLOCKING EVENT FINISHED!- STATUS = %r\n",\r
490b5ea1 685 Task->Token->TransactionStatus\r
686 ));\r
687\r
688 //\r
689 // Reduce the SubEventCount, till it comes to zero.\r
690 //\r
691 (*Task->UnsignalledEventCount) --;\r
25dd150b 692 DEBUG ((EFI_D_BLKIO, "UnsignalledEventCount = %d\n", *Task->UnsignalledEventCount));\r
490b5ea1 693\r
694 //\r
695 // Remove the SubTask from the Task list.\r
696 //\r
697 RemoveEntryList (&Task->TaskEntry);\r
698 if ((*Task->UnsignalledEventCount) == 0) {\r
699 //\r
3c063fed 700 // All Sub tasks are done, then signal the upper layer event.\r
490b5ea1 701 // Except there is error during the sub task source allocation.\r
702 //\r
703 if (!(*Task->IsError)) {\r
704 gBS->SignalEvent (Task->Token->Event);\r
25dd150b 705 DEBUG ((EFI_D_BLKIO, "Signal the upper layer event!\n"));\r
490b5ea1 706 }\r
58727f29 707\r
490b5ea1 708 FreePool (Task->UnsignalledEventCount);\r
709 FreePool (Task->IsError);\r
58727f29 710\r
711\r
712 //\r
713 // Finish all subtasks and move to the next task in AtaTaskList.\r
714 //\r
715 if (!IsListEmpty (&AtaDevice->AtaTaskList)) {\r
716 Entry = GetFirstNode (&AtaDevice->AtaTaskList);\r
71fd9fae 717 AtaTask = ATA_ASYN_TASK_FROM_ENTRY (Entry);\r
58727f29 718 DEBUG ((EFI_D_BLKIO, "Start to embark a new Ata Task\n"));\r
719 DEBUG ((EFI_D_BLKIO, "AtaTask->NumberOfBlocks = %x; AtaTask->Token=%x\n", AtaTask->NumberOfBlocks, AtaTask->Token));\r
720 Status = AccessAtaDevice (\r
721 AtaTask->AtaDevice,\r
722 AtaTask->Buffer,\r
723 AtaTask->StartLba,\r
724 AtaTask->NumberOfBlocks,\r
725 AtaTask->IsWrite,\r
726 AtaTask->Token\r
727 );\r
728 if (EFI_ERROR (Status)) {\r
729 AtaTask->Token->TransactionStatus = Status;\r
730 gBS->SignalEvent (AtaTask->Token->Event);\r
731 }\r
732 RemoveEntryList (Entry);\r
733 FreePool (AtaTask);\r
734 }\r
490b5ea1 735 }\r
ad86a50a 736\r
490b5ea1 737 DEBUG ((\r
25dd150b
SZ
738 EFI_D_BLKIO,\r
739 "PACKET INFO: Write=%s, Length=%x, LowCylinder=%x, HighCylinder=%x, SectionNumber=%x\n",\r
490b5ea1 740 Task->Packet.OutDataBuffer != NULL ? L"YES" : L"NO",\r
741 Task->Packet.OutDataBuffer != NULL ? Task->Packet.OutTransferLength : Task->Packet.InTransferLength,\r
742 Task->Packet.Acb->AtaCylinderLow,\r
743 Task->Packet.Acb->AtaCylinderHigh,\r
744 Task->Packet.Acb->AtaSectorCount\r
745 ));\r
746\r
747 //\r
748 // Free the buffer of SubTask.\r
749 //\r
750 FreeAtaSubTask (Task);\r
ad86a50a 751}\r
752\r
753/**\r
754 Read or write a number of blocks from ATA device.\r
755\r
756 This function performs ATA pass through transactions to read/write data from/to\r
757 ATA device. It may separate the read/write request into several ATA pass through\r
758 transactions.\r
759\r
490b5ea1 760 @param[in, out] AtaDevice The ATA child device involved for the operation.\r
761 @param[in, out] Buffer The pointer to the current transaction buffer.\r
762 @param[in] StartLba The starting logical block address to be accessed.\r
763 @param[in] NumberOfBlocks The block number or sector count of the transfer.\r
764 @param[in] IsWrite Indicates whether it is a write operation.\r
765 @param[in, out] Token A pointer to the token associated with the transaction.\r
ad86a50a 766\r
767 @retval EFI_SUCCESS The data transfer is complete successfully.\r
58727f29 768 @return others Some error occurs when transferring data.\r
ad86a50a 769\r
770**/\r
58727f29 771EFI_STATUS\r
ad86a50a 772AccessAtaDevice(\r
773 IN OUT ATA_DEVICE *AtaDevice,\r
774 IN OUT UINT8 *Buffer,\r
775 IN EFI_LBA StartLba,\r
776 IN UINTN NumberOfBlocks,\r
490b5ea1 777 IN BOOLEAN IsWrite,\r
778 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
ad86a50a 779 )\r
780{\r
781 EFI_STATUS Status;\r
782 UINTN MaxTransferBlockNumber;\r
783 UINTN TransferBlockNumber;\r
784 UINTN BlockSize;\r
58727f29 785 ATA_BUS_ASYN_SUB_TASK *SubTask;\r
490b5ea1 786 UINTN *EventCount;\r
787 UINTN TempCount;\r
58727f29 788 ATA_BUS_ASYN_TASK *AtaTask;\r
490b5ea1 789 EFI_EVENT SubEvent;\r
790 UINTN Index;\r
791 BOOLEAN *IsError;\r
792 EFI_TPL OldTpl;\r
793\r
3c063fed 794 TempCount = 0;\r
795 Status = EFI_SUCCESS;\r
796 EventCount = NULL;\r
797 IsError = NULL;\r
798 Index = 0;\r
58727f29 799 SubTask = NULL;\r
3c063fed 800 SubEvent = NULL;\r
58727f29 801 AtaTask = NULL;\r
71fd9fae 802\r
423401f9 803 //\r
58727f29 804 // Ensure AtaDevice->Lba48Bit is a valid boolean value\r
423401f9 805 //\r
806 ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);\r
ad86a50a 807 MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit];\r
490b5ea1 808 BlockSize = AtaDevice->BlockMedia.BlockSize;\r
809\r
3c063fed 810 //\r
811 // Initial the return status and shared account for Non Blocking.\r
812 //\r
813 if ((Token != NULL) && (Token->Event != NULL)) {\r
58727f29 814 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
71fd9fae 815\r
58727f29 816 if (!IsListEmpty (&AtaDevice->AtaSubTaskList)) {\r
817 AtaTask = AllocateZeroPool (sizeof (ATA_BUS_ASYN_TASK));\r
818 if (AtaTask == NULL) {\r
819 gBS->RestoreTPL (OldTpl);\r
820 return EFI_OUT_OF_RESOURCES;\r
821 }\r
822 AtaTask->AtaDevice = AtaDevice;\r
823 AtaTask->Buffer = Buffer;\r
824 AtaTask->IsWrite = IsWrite;\r
825 AtaTask->NumberOfBlocks = NumberOfBlocks;\r
826 AtaTask->Signature = ATA_TASK_SIGNATURE;\r
827 AtaTask->StartLba = StartLba;\r
828 AtaTask->Token = Token;\r
829\r
830 InsertTailList (&AtaDevice->AtaTaskList, &AtaTask->TaskEntry);\r
831 gBS->RestoreTPL (OldTpl);\r
832 return EFI_SUCCESS;\r
833 }\r
834 gBS->RestoreTPL (OldTpl);\r
3c063fed 835\r
58727f29 836 Token->TransactionStatus = EFI_SUCCESS;\r
3c063fed 837 EventCount = AllocateZeroPool (sizeof (UINTN));\r
838 if (EventCount == NULL) {\r
839 return EFI_OUT_OF_RESOURCES;\r
840 }\r
58727f29 841\r
3c063fed 842 IsError = AllocateZeroPool (sizeof (BOOLEAN));\r
843 if (IsError == NULL) {\r
844 FreePool (EventCount);\r
845 return EFI_OUT_OF_RESOURCES;\r
846 }\r
58727f29 847 DEBUG ((EFI_D_BLKIO, "Allocation IsError Addr=%x\n", IsError));\r
3c063fed 848 *IsError = FALSE;\r
3c063fed 849 TempCount = (NumberOfBlocks + MaxTransferBlockNumber - 1) / MaxTransferBlockNumber;\r
850 *EventCount = TempCount;\r
58727f29 851 DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, NumberOfBlocks=%x\n", NumberOfBlocks));\r
852 DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, MaxTransferBlockNumber=%x\n", MaxTransferBlockNumber));\r
853 DEBUG ((EFI_D_BLKIO, "AccessAtaDevice, EventCount=%x\n", TempCount));\r
71fd9fae 854 } else {\r
58727f29 855 while (!IsListEmpty (&AtaDevice->AtaTaskList) || !IsListEmpty (&AtaDevice->AtaSubTaskList)) {\r
856 //\r
857 // Stall for 100us.\r
858 //\r
859 MicroSecondDelay (100);\r
860 }\r
3c063fed 861 }\r
490b5ea1 862\r
ad86a50a 863 do {\r
864 if (NumberOfBlocks > MaxTransferBlockNumber) {\r
865 TransferBlockNumber = MaxTransferBlockNumber;\r
490b5ea1 866 NumberOfBlocks -= MaxTransferBlockNumber;\r
ad86a50a 867 } else {\r
868 TransferBlockNumber = NumberOfBlocks;\r
3c063fed 869 NumberOfBlocks = 0;\r
ad86a50a 870 }\r
871\r
490b5ea1 872 //\r
3c063fed 873 // Create sub event for the sub ata task. Non-blocking mode.\r
490b5ea1 874 //\r
3c063fed 875 if ((Token != NULL) && (Token->Event != NULL)) {\r
58727f29 876 SubTask = NULL;\r
3c063fed 877 SubEvent = NULL;\r
878\r
58727f29 879 SubTask = AllocateZeroPool (sizeof (ATA_BUS_ASYN_SUB_TASK));\r
880 if (SubTask == NULL) {\r
3c063fed 881 Status = EFI_OUT_OF_RESOURCES;\r
490b5ea1 882 goto EXIT;\r
883 }\r
884\r
3c063fed 885 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
58727f29 886 SubTask->UnsignalledEventCount = EventCount;\r
887 SubTask->Signature = ATA_SUB_TASK_SIGNATURE;\r
888 SubTask->AtaDevice = AtaDevice;\r
889 SubTask->Token = Token;\r
890 SubTask->IsError = IsError;\r
891 InsertTailList (&AtaDevice->AtaSubTaskList, &SubTask->TaskEntry);\r
892 gBS->RestoreTPL (OldTpl);\r
490b5ea1 893\r
894 Status = gBS->CreateEvent (\r
895 EVT_NOTIFY_SIGNAL,\r
896 TPL_NOTIFY,\r
897 AtaNonBlockingCallBack,\r
58727f29 898 SubTask,\r
490b5ea1 899 &SubEvent\r
900 );\r
901 //\r
902 // If resource allocation fail, the un-signalled event count should equal to\r
903 // the original one minus the unassigned subtasks number.\r
904 //\r
905 if (EFI_ERROR (Status)) {\r
3c063fed 906 Status = EFI_OUT_OF_RESOURCES;\r
490b5ea1 907 goto EXIT;\r
908 }\r
490b5ea1 909\r
58727f29 910 Status = TransferAtaDevice (AtaDevice, &SubTask->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent);\r
3c063fed 911 } else {\r
490b5ea1 912 //\r
913 // Blocking Mode.\r
914 //\r
58727f29 915 DEBUG ((EFI_D_BLKIO, "Blocking AccessAtaDevice, TransferBlockNumber=%x; StartLba = %x\n", TransferBlockNumber, StartLba));\r
490b5ea1 916 Status = TransferAtaDevice (AtaDevice, NULL, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, NULL);\r
490b5ea1 917 }\r
918\r
ad86a50a 919 if (EFI_ERROR (Status)) {\r
490b5ea1 920 goto EXIT;\r
ad86a50a 921 }\r
490b5ea1 922\r
3c063fed 923 Index++;\r
ad86a50a 924 StartLba += TransferBlockNumber;\r
925 Buffer += TransferBlockNumber * BlockSize;\r
926 } while (NumberOfBlocks > 0);\r
927\r
490b5ea1 928EXIT:\r
3c063fed 929 if ((Token != NULL) && (Token->Event != NULL)) {\r
930 //\r
931 // Release resource at non-blocking mode.\r
932 //\r
933 if (EFI_ERROR (Status)) {\r
934 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
935 Token->TransactionStatus = Status;\r
936 *EventCount = (*EventCount) - (TempCount - Index);\r
937 *IsError = TRUE;\r
58727f29 938\r
3c063fed 939 if (*EventCount == 0) {\r
940 FreePool (EventCount);\r
941 FreePool (IsError);\r
942 }\r
58727f29 943\r
944 if (SubTask != NULL) {\r
945 RemoveEntryList (&SubTask->TaskEntry);\r
946 FreeAtaSubTask (SubTask);\r
3c063fed 947 }\r
490b5ea1 948\r
3c063fed 949 if (SubEvent != NULL) {\r
58727f29 950 gBS->CloseEvent (SubEvent);\r
3c063fed 951 }\r
3c063fed 952 gBS->RestoreTPL (OldTpl);\r
953 }\r
58727f29 954 }\r
490b5ea1 955\r
ad86a50a 956 return Status;\r
957}\r
c24097a5 958\r
959/**\r
960 Trust transfer data from/to ATA device.\r
961\r
962 This function performs one ATA pass through transaction to do a trust transfer from/to\r
963 ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru\r
964 interface of ATA pass through.\r
965\r
966 @param AtaDevice The ATA child device involved for the operation.\r
967 @param Buffer The pointer to the current transaction buffer.\r
968 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
969 the security protocol command to be sent.\r
970 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
971 of the security protocol command to be sent.\r
972 @param TransferLength The block number or sector count of the transfer.\r
973 @param IsTrustSend Indicates whether it is a trust send operation or not.\r
974 @param Timeout The timeout, in 100ns units, to use for the execution\r
975 of the security protocol command. A Timeout value of 0\r
976 means that this function will wait indefinitely for the\r
977 security protocol command to execute. If Timeout is greater\r
978 than zero, then this function will return EFI_TIMEOUT\r
979 if the time required to execute the receive data command\r
980 is greater than Timeout.\r
86d8e199 981 @param TransferLengthOut A pointer to a buffer to store the size in bytes of the data\r
982 written to the buffer. Ignore it when IsTrustSend is TRUE.\r
c24097a5 983\r
984 @retval EFI_SUCCESS The data transfer is complete successfully.\r
58727f29 985 @return others Some error occurs when transferring data.\r
c24097a5 986\r
987**/\r
988EFI_STATUS\r
989EFIAPI\r
990TrustTransferAtaDevice (\r
991 IN OUT ATA_DEVICE *AtaDevice,\r
992 IN OUT VOID *Buffer,\r
993 IN UINT8 SecurityProtocolId,\r
994 IN UINT16 SecurityProtocolSpecificData,\r
995 IN UINTN TransferLength,\r
996 IN BOOLEAN IsTrustSend,\r
997 IN UINT64 Timeout,\r
998 OUT UINTN *TransferLengthOut\r
999 )\r
1000{\r
1001 EFI_ATA_COMMAND_BLOCK *Acb;\r
1002 EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;\r
1003 EFI_STATUS Status;\r
1004 VOID *NewBuffer;\r
1005 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
1006\r
1007 //\r
58727f29 1008 // Ensure AtaDevice->UdmaValid and IsTrustSend are valid boolean values\r
c24097a5 1009 //\r
1010 ASSERT ((UINTN) AtaDevice->UdmaValid < 2);\r
1011 ASSERT ((UINTN) IsTrustSend < 2);\r
1012 //\r
1013 // Prepare for ATA command block.\r
1014 //\r
3c063fed 1015 Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));\r
c24097a5 1016 if (TransferLength == 0) {\r
1017 Acb->AtaCommand = ATA_CMD_TRUST_NON_DATA;\r
1018 } else {\r
1019 Acb->AtaCommand = mAtaTrustCommands[AtaDevice->UdmaValid][IsTrustSend];\r
1020 }\r
1021 Acb->AtaFeatures = SecurityProtocolId;\r
1022 Acb->AtaSectorCount = (UINT8) (TransferLength / 512);\r
1023 Acb->AtaSectorNumber = (UINT8) ((TransferLength / 512) >> 8);\r
1024 //\r
58727f29 1025 // NOTE: ATA Spec has no explicitly definition for Security Protocol Specific layout.\r
1026 // Here use big endian for Cylinder register.\r
c24097a5 1027 //\r
1028 Acb->AtaCylinderHigh = (UINT8) SecurityProtocolSpecificData;\r
1029 Acb->AtaCylinderLow = (UINT8) (SecurityProtocolSpecificData >> 8);\r
4c33f8b1 1030 Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort == 0xFFFF ? 0 : (AtaDevice->PortMultiplierPort << 4)));\r
c24097a5 1031\r
1032 //\r
1033 // Prepare for ATA pass through packet.\r
1034 //\r
3c063fed 1035 Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
c24097a5 1036 if (TransferLength == 0) {\r
1037 Packet->InTransferLength = 0;\r
1038 Packet->OutTransferLength = 0;\r
1039 Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;\r
1040 } else if (IsTrustSend) {\r
1041 //\r
1042 // Check the alignment of the incoming buffer prior to invoking underlying ATA PassThru\r
1043 //\r
1044 AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
1045 if ((AtaPassThru->Mode->IoAlign > 1) && !IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {\r
1046 NewBuffer = AllocateAlignedBuffer (AtaDevice, TransferLength);\r
3d267c70
ED
1047 if (NewBuffer == NULL) {\r
1048 return EFI_OUT_OF_RESOURCES;\r
1049 }\r
1050\r
c24097a5 1051 CopyMem (NewBuffer, Buffer, TransferLength);\r
1052 FreePool (Buffer);\r
1053 Buffer = NewBuffer;\r
58727f29 1054 }\r
c24097a5 1055 Packet->OutDataBuffer = Buffer;\r
1056 Packet->OutTransferLength = (UINT32) TransferLength;\r
1057 Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];\r
1058 } else {\r
1059 Packet->InDataBuffer = Buffer;\r
1060 Packet->InTransferLength = (UINT32) TransferLength;\r
1061 Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];\r
1062 }\r
1063 Packet->Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
1064 Packet->Timeout = Timeout;\r
1065\r
1066 Status = AtaDevicePassThru (AtaDevice, NULL, NULL);\r
1067 if (TransferLengthOut != NULL) {\r
1068 if (! IsTrustSend) {\r
1069 *TransferLengthOut = Packet->InTransferLength;\r
1070 }\r
1071 }\r
1072 return Status;\r
1073}\r