]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
Remove, correct and refine some debug messages.
[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
c24097a5 9 parameter SecurityProtocolSpecificData, ATA spec has no explicitly definition \r
3c063fed 10 for Security Protocol Specific layout. This implementation uses big endian for \r
c24097a5 11 Cylinder register.\r
ad86a50a 12 \r
490b5ea1 13 Copyright (c) 2009 - 2011, 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
76UINT8 mAtaTrustCommands[2][2] = { \r
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
105 @param[in, out] TaskPacket Pointer to a Pass Thru Command Packet. Optional, \r
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
490b5ea1 130 // Assemble packet. If it is non blocking mode, the Ata driver should keep each \r
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
155 // interpretation of ATA pass through protocol. \r
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
168 for an ATA device. \r
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
181 \r
182 AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
183 \r
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
195 This function converts ATA device model name from ATA identify data \r
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
274 This function identifies the ATA device and initializes the Media information in \r
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
366 // Get ATA model name from identify data structure. \r
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
385 @return others Some error occurs when discovering the ATA device. \r
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
440 @param[in, out] TaskPacket Pointer to a Pass Thru Command Packet. Optional, \r
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
455 @return others Some error occurs when transferring data. \r
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
465 IN BOOLEAN IsWrite, \r
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
61d4f8f9 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
522 Free SubTask. \r
523\r
524 @param[in, out] Task Pointer to task to be freed.\r
525\r
526**/\r
527VOID\r
528EFIAPI \r
529FreeAtaSubTask (\r
86d8e199 530 IN OUT ATA_BUS_ASYN_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
552EFIAPI \r
553AtaNonBlockingCallBack (\r
554 IN EFI_EVENT Event,\r
555 IN VOID *Context\r
556 )\r
557{\r
558 ATA_BUS_ASYN_TASK *Task;\r
559\r
560 Task = (ATA_BUS_ASYN_TASK *) Context;\r
561 gBS->CloseEvent (Event);\r
562\r
563 //\r
564 // Check the command status.\r
565 // If there is error during the sub task source allocation, the error status\r
566 // should be returned to the caller directly, so here the Task->Token may already\r
567 // be deleted by the caller and no need to update the status.\r
568 //\r
3c063fed 569 if ((!(*Task->IsError)) && ((Task->Packet.Asb->AtaStatus & 0x01) == 0x01)) {\r
490b5ea1 570 Task->Token->TransactionStatus = EFI_DEVICE_ERROR;\r
571 }\r
572 DEBUG ((\r
25dd150b
SZ
573 EFI_D_BLKIO,\r
574 "NON-BLOCKING EVENT FINISHED!- STATUS = %r\n",\r
490b5ea1 575 Task->Token->TransactionStatus\r
576 ));\r
577\r
578 //\r
579 // Reduce the SubEventCount, till it comes to zero.\r
580 //\r
581 (*Task->UnsignalledEventCount) --;\r
25dd150b 582 DEBUG ((EFI_D_BLKIO, "UnsignalledEventCount = %d\n", *Task->UnsignalledEventCount));\r
490b5ea1 583\r
584 //\r
585 // Remove the SubTask from the Task list.\r
586 //\r
587 RemoveEntryList (&Task->TaskEntry);\r
588 if ((*Task->UnsignalledEventCount) == 0) {\r
589 //\r
3c063fed 590 // All Sub tasks are done, then signal the upper layer event.\r
490b5ea1 591 // Except there is error during the sub task source allocation.\r
592 //\r
593 if (!(*Task->IsError)) {\r
594 gBS->SignalEvent (Task->Token->Event);\r
25dd150b 595 DEBUG ((EFI_D_BLKIO, "Signal the upper layer event!\n"));\r
490b5ea1 596 }\r
597 \r
598 FreePool (Task->UnsignalledEventCount);\r
599 FreePool (Task->IsError);\r
600 }\r
ad86a50a 601\r
490b5ea1 602 DEBUG ((\r
25dd150b
SZ
603 EFI_D_BLKIO,\r
604 "PACKET INFO: Write=%s, Length=%x, LowCylinder=%x, HighCylinder=%x, SectionNumber=%x\n",\r
490b5ea1 605 Task->Packet.OutDataBuffer != NULL ? L"YES" : L"NO",\r
606 Task->Packet.OutDataBuffer != NULL ? Task->Packet.OutTransferLength : Task->Packet.InTransferLength,\r
607 Task->Packet.Acb->AtaCylinderLow,\r
608 Task->Packet.Acb->AtaCylinderHigh,\r
609 Task->Packet.Acb->AtaSectorCount\r
610 ));\r
611\r
612 //\r
613 // Free the buffer of SubTask.\r
614 //\r
615 FreeAtaSubTask (Task);\r
ad86a50a 616}\r
617\r
618/**\r
619 Read or write a number of blocks from ATA device.\r
620\r
621 This function performs ATA pass through transactions to read/write data from/to\r
622 ATA device. It may separate the read/write request into several ATA pass through\r
623 transactions.\r
624\r
490b5ea1 625 @param[in, out] AtaDevice The ATA child device involved for the operation.\r
626 @param[in, out] Buffer The pointer to the current transaction buffer.\r
627 @param[in] StartLba The starting logical block address to be accessed.\r
628 @param[in] NumberOfBlocks The block number or sector count of the transfer.\r
629 @param[in] IsWrite Indicates whether it is a write operation.\r
630 @param[in, out] Token A pointer to the token associated with the transaction.\r
ad86a50a 631\r
632 @retval EFI_SUCCESS The data transfer is complete successfully.\r
633 @return others Some error occurs when transferring data. \r
634\r
635**/\r
636EFI_STATUS \r
637AccessAtaDevice(\r
638 IN OUT ATA_DEVICE *AtaDevice,\r
639 IN OUT UINT8 *Buffer,\r
640 IN EFI_LBA StartLba,\r
641 IN UINTN NumberOfBlocks,\r
490b5ea1 642 IN BOOLEAN IsWrite,\r
643 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
ad86a50a 644 )\r
645{\r
646 EFI_STATUS Status;\r
647 UINTN MaxTransferBlockNumber;\r
648 UINTN TransferBlockNumber;\r
649 UINTN BlockSize;\r
490b5ea1 650 UINTN *EventCount;\r
651 UINTN TempCount;\r
652 ATA_BUS_ASYN_TASK *Task;\r
653 EFI_EVENT SubEvent;\r
654 UINTN Index;\r
655 BOOLEAN *IsError;\r
656 EFI_TPL OldTpl;\r
657\r
3c063fed 658 TempCount = 0;\r
659 Status = EFI_SUCCESS;\r
660 EventCount = NULL;\r
661 IsError = NULL;\r
662 Index = 0;\r
663 Task = NULL;\r
664 SubEvent = NULL;\r
490b5ea1 665\r
423401f9 666 //\r
667 // Ensure AtaDevice->Lba48Bit is a valid boolean value \r
668 //\r
669 ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);\r
ad86a50a 670 MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit];\r
490b5ea1 671 BlockSize = AtaDevice->BlockMedia.BlockSize;\r
672\r
3c063fed 673 //\r
674 // Initial the return status and shared account for Non Blocking.\r
675 //\r
676 if ((Token != NULL) && (Token->Event != NULL)) {\r
677 Token->TransactionStatus = EFI_SUCCESS;\r
678\r
679 EventCount = AllocateZeroPool (sizeof (UINTN));\r
680 if (EventCount == NULL) {\r
681 return EFI_OUT_OF_RESOURCES;\r
682 }\r
683 \r
684 IsError = AllocateZeroPool (sizeof (BOOLEAN));\r
685 if (IsError == NULL) {\r
686 FreePool (EventCount);\r
687 return EFI_OUT_OF_RESOURCES;\r
688 }\r
689 *IsError = FALSE;\r
690 \r
691 TempCount = (NumberOfBlocks + MaxTransferBlockNumber - 1) / MaxTransferBlockNumber;\r
692 *EventCount = TempCount;\r
693 }\r
490b5ea1 694\r
ad86a50a 695 do {\r
696 if (NumberOfBlocks > MaxTransferBlockNumber) {\r
697 TransferBlockNumber = MaxTransferBlockNumber;\r
490b5ea1 698 NumberOfBlocks -= MaxTransferBlockNumber;\r
ad86a50a 699 } else {\r
700 TransferBlockNumber = NumberOfBlocks;\r
3c063fed 701 NumberOfBlocks = 0;\r
ad86a50a 702 }\r
703\r
490b5ea1 704 //\r
3c063fed 705 // Create sub event for the sub ata task. Non-blocking mode.\r
490b5ea1 706 //\r
3c063fed 707 if ((Token != NULL) && (Token->Event != NULL)) {\r
708 Task = NULL;\r
709 SubEvent = NULL;\r
710\r
711 Task = AllocateZeroPool (sizeof (ATA_BUS_ASYN_TASK));\r
490b5ea1 712 if (Task == NULL) {\r
3c063fed 713 Status = EFI_OUT_OF_RESOURCES;\r
490b5ea1 714 goto EXIT;\r
715 }\r
716\r
3c063fed 717 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
490b5ea1 718 Task->UnsignalledEventCount = EventCount;\r
719 Task->Token = Token;\r
720 Task->IsError = IsError;\r
490b5ea1 721 InsertTailList (&AtaDevice->AtaTaskList, &Task->TaskEntry);\r
3c063fed 722 gBS->RestoreTPL (OldTpl); \r
490b5ea1 723\r
724 Status = gBS->CreateEvent (\r
725 EVT_NOTIFY_SIGNAL,\r
726 TPL_NOTIFY,\r
727 AtaNonBlockingCallBack,\r
728 Task,\r
729 &SubEvent\r
730 );\r
731 //\r
732 // If resource allocation fail, the un-signalled event count should equal to\r
733 // the original one minus the unassigned subtasks number.\r
734 //\r
735 if (EFI_ERROR (Status)) {\r
3c063fed 736 Status = EFI_OUT_OF_RESOURCES;\r
490b5ea1 737 goto EXIT;\r
738 }\r
490b5ea1 739\r
490b5ea1 740 Status = TransferAtaDevice (AtaDevice, &Task->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent);\r
3c063fed 741 } else {\r
490b5ea1 742 //\r
743 // Blocking Mode.\r
744 //\r
490b5ea1 745 Status = TransferAtaDevice (AtaDevice, NULL, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, NULL);\r
490b5ea1 746 }\r
747\r
ad86a50a 748 if (EFI_ERROR (Status)) {\r
490b5ea1 749 goto EXIT;\r
ad86a50a 750 }\r
490b5ea1 751\r
3c063fed 752 Index++;\r
ad86a50a 753 StartLba += TransferBlockNumber;\r
754 Buffer += TransferBlockNumber * BlockSize;\r
755 } while (NumberOfBlocks > 0);\r
756\r
490b5ea1 757EXIT:\r
3c063fed 758 if ((Token != NULL) && (Token->Event != NULL)) {\r
759 //\r
760 // Release resource at non-blocking mode.\r
761 //\r
762 if (EFI_ERROR (Status)) {\r
763 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
764 Token->TransactionStatus = Status;\r
765 *EventCount = (*EventCount) - (TempCount - Index);\r
766 *IsError = TRUE;\r
767 \r
768 if (*EventCount == 0) {\r
769 FreePool (EventCount);\r
770 FreePool (IsError);\r
771 }\r
772 \r
773 if (Task != NULL) {\r
774 RemoveEntryList (&Task->TaskEntry);\r
775 FreeAtaSubTask (Task); \r
776 }\r
490b5ea1 777\r
3c063fed 778 if (SubEvent != NULL) {\r
779 gBS->CloseEvent (SubEvent); \r
780 }\r
781 \r
782 gBS->RestoreTPL (OldTpl);\r
783 }\r
784 } \r
490b5ea1 785\r
ad86a50a 786 return Status;\r
787}\r
c24097a5 788\r
789/**\r
790 Trust transfer data from/to ATA device.\r
791\r
792 This function performs one ATA pass through transaction to do a trust transfer from/to\r
793 ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru\r
794 interface of ATA pass through.\r
795\r
796 @param AtaDevice The ATA child device involved for the operation.\r
797 @param Buffer The pointer to the current transaction buffer.\r
798 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
799 the security protocol command to be sent.\r
800 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
801 of the security protocol command to be sent.\r
802 @param TransferLength The block number or sector count of the transfer.\r
803 @param IsTrustSend Indicates whether it is a trust send operation or not.\r
804 @param Timeout The timeout, in 100ns units, to use for the execution\r
805 of the security protocol command. A Timeout value of 0\r
806 means that this function will wait indefinitely for the\r
807 security protocol command to execute. If Timeout is greater\r
808 than zero, then this function will return EFI_TIMEOUT\r
809 if the time required to execute the receive data command\r
810 is greater than Timeout.\r
86d8e199 811 @param TransferLengthOut A pointer to a buffer to store the size in bytes of the data\r
812 written to the buffer. Ignore it when IsTrustSend is TRUE.\r
c24097a5 813\r
814 @retval EFI_SUCCESS The data transfer is complete successfully.\r
815 @return others Some error occurs when transferring data. \r
816\r
817**/\r
818EFI_STATUS\r
819EFIAPI\r
820TrustTransferAtaDevice (\r
821 IN OUT ATA_DEVICE *AtaDevice,\r
822 IN OUT VOID *Buffer,\r
823 IN UINT8 SecurityProtocolId,\r
824 IN UINT16 SecurityProtocolSpecificData,\r
825 IN UINTN TransferLength,\r
826 IN BOOLEAN IsTrustSend,\r
827 IN UINT64 Timeout,\r
828 OUT UINTN *TransferLengthOut\r
829 )\r
830{\r
831 EFI_ATA_COMMAND_BLOCK *Acb;\r
832 EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;\r
833 EFI_STATUS Status;\r
834 VOID *NewBuffer;\r
835 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
836\r
837 //\r
838 // Ensure AtaDevice->UdmaValid and IsTrustSend are valid boolean values \r
839 //\r
840 ASSERT ((UINTN) AtaDevice->UdmaValid < 2);\r
841 ASSERT ((UINTN) IsTrustSend < 2);\r
842 //\r
843 // Prepare for ATA command block.\r
844 //\r
3c063fed 845 Acb = ZeroMem (&AtaDevice->Acb, sizeof (EFI_ATA_COMMAND_BLOCK));\r
c24097a5 846 if (TransferLength == 0) {\r
847 Acb->AtaCommand = ATA_CMD_TRUST_NON_DATA;\r
848 } else {\r
849 Acb->AtaCommand = mAtaTrustCommands[AtaDevice->UdmaValid][IsTrustSend];\r
850 }\r
851 Acb->AtaFeatures = SecurityProtocolId;\r
852 Acb->AtaSectorCount = (UINT8) (TransferLength / 512);\r
853 Acb->AtaSectorNumber = (UINT8) ((TransferLength / 512) >> 8);\r
854 //\r
855 // NOTE: ATA Spec has no explicitly definition for Security Protocol Specific layout. \r
3c063fed 856 // Here use big endian for Cylinder register. \r
c24097a5 857 //\r
858 Acb->AtaCylinderHigh = (UINT8) SecurityProtocolSpecificData;\r
859 Acb->AtaCylinderLow = (UINT8) (SecurityProtocolSpecificData >> 8);\r
860 Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4)); \r
861\r
862 //\r
863 // Prepare for ATA pass through packet.\r
864 //\r
3c063fed 865 Packet = ZeroMem (&AtaDevice->Packet, sizeof (EFI_ATA_PASS_THRU_COMMAND_PACKET));\r
c24097a5 866 if (TransferLength == 0) {\r
867 Packet->InTransferLength = 0;\r
868 Packet->OutTransferLength = 0;\r
869 Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;\r
870 } else if (IsTrustSend) {\r
871 //\r
872 // Check the alignment of the incoming buffer prior to invoking underlying ATA PassThru\r
873 //\r
874 AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
875 if ((AtaPassThru->Mode->IoAlign > 1) && !IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {\r
876 NewBuffer = AllocateAlignedBuffer (AtaDevice, TransferLength);\r
877 CopyMem (NewBuffer, Buffer, TransferLength);\r
878 FreePool (Buffer);\r
879 Buffer = NewBuffer;\r
880 } \r
881 Packet->OutDataBuffer = Buffer;\r
882 Packet->OutTransferLength = (UINT32) TransferLength;\r
883 Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];\r
884 } else {\r
885 Packet->InDataBuffer = Buffer;\r
886 Packet->InTransferLength = (UINT32) TransferLength;\r
887 Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];\r
888 }\r
889 Packet->Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
890 Packet->Timeout = Timeout;\r
891\r
892 Status = AtaDevicePassThru (AtaDevice, NULL, NULL);\r
893 if (TransferLengthOut != NULL) {\r
894 if (! IsTrustSend) {\r
895 *TransferLengthOut = Packet->InTransferLength;\r
896 }\r
897 }\r
898 return Status;\r
899}\r