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