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