]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AtaBusDxe/AtaPassThruExecute.c
1. Enabled SSP(StorageSecurityCommandProtocol) for ATA devices.
[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
8 NOTE: This file aslo implements the StorageSecurityCommandProtocol(SSP). For input\r
9 parameter SecurityProtocolSpecificData, ATA spec has no explicitly definition \r
10 for Security Protocol Specific layout. This implementation uses big edian for \r
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
109 @param[in] Event If Event is NULL, then blocking I/O is performed.\r
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
135 Packet->Asb = AllocateAlignedBuffer (AtaDevice, sizeof (*AtaDevice->Asb));\r
136 CopyMem (Packet->Asb, AtaDevice->Asb, sizeof (*AtaDevice->Asb));\r
137 Packet->Acb = AllocateCopyPool(sizeof (EFI_ATA_COMMAND_BLOCK), &AtaDevice->Acb);\r
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
490b5ea1 304 DEBUG ((EFI_D_INFO, "AtaBus - Identify Device (%x %x)\n", (UINTN)AtaDevice->Port, (UINTN)AtaDevice->PortMultiplierPort));\r
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
401 Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb));\r
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
408 Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet));\r
409 Packet->InDataBuffer = AtaDevice->IdentifyData;\r
410 Packet->InTransferLength = sizeof (*AtaDevice->IdentifyData);\r
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
481 Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb));\r
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
501 Packet = ZeroMem (TaskPacket, sizeof (*Packet));\r
502 } else {\r
503 Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet));\r
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
530 IN ATA_BUS_ASYN_TASK *Task\r
531 )\r
532{\r
533 if (Task->Packet.Asb != NULL) {\r
534 FreeAlignedBuffer (Task->Packet.Asb, sizeof (Task->Packet.Asb));\r
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
547 @param[in] Context Pointer to the context data registerd to the\r
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
569 if ((!(*Task->IsError)) && (Task->Packet.Asb->AtaStatus & 0x01) == 0x01) {\r
570 Task->Token->TransactionStatus = EFI_DEVICE_ERROR;\r
571 }\r
572 DEBUG ((\r
573 DEBUG_INFO, \r
574 "NON-BLOCKING EVENT FINISHED!- STATUS = %r\n", \r
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
582 DEBUG ((DEBUG_INFO, "UnsignalledEventCount = %x\n", *Task->UnsignalledEventCount));\r
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
590 // All Sub tasks are done, then signal the upper layyer event.\r
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
595 DEBUG ((DEBUG_INFO, "Signal Up Level Event UnsignalledEventCount = %x!\n", *Task->UnsignalledEventCount));\r
596 }\r
597 \r
598 FreePool (Task->UnsignalledEventCount);\r
599 FreePool (Task->IsError);\r
600 }\r
ad86a50a 601\r
490b5ea1 602 DEBUG ((\r
603 DEBUG_INFO, \r
604 "PACKET INFO: Write=%s, Lenght=%x, LowCylinder=%x, HighCylinder=%x,SectionNumber=%x",\r
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
658 SubEvent = NULL;\r
659 TempCount = 0;\r
660 Status = EFI_SUCCESS;\r
661\r
662 EventCount = AllocateZeroPool (sizeof (UINTN));\r
663 if (EventCount == NULL) {\r
664 return EFI_OUT_OF_RESOURCES;\r
665 }\r
666 \r
667 IsError = AllocateZeroPool (sizeof (BOOLEAN));\r
668 if (IsError == NULL) {\r
669 goto EXIT;\r
670 }\r
671 *IsError = FALSE;\r
672\r
673 //\r
674 // Initial the return status for Non Blocking.\r
675 //\r
676 if (Token != NULL && Token->Event != NULL) {\r
677 Token->TransactionStatus = EFI_SUCCESS;\r
678 }\r
423401f9 679 //\r
680 // Ensure AtaDevice->Lba48Bit is a valid boolean value \r
681 //\r
682 ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);\r
ad86a50a 683 MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit];\r
490b5ea1 684 BlockSize = AtaDevice->BlockMedia.BlockSize;\r
685\r
686 TempCount = (NumberOfBlocks + MaxTransferBlockNumber - 1) / MaxTransferBlockNumber;\r
687 *EventCount = TempCount;\r
688 Index = 0;\r
689\r
ad86a50a 690 do {\r
691 if (NumberOfBlocks > MaxTransferBlockNumber) {\r
692 TransferBlockNumber = MaxTransferBlockNumber;\r
490b5ea1 693 NumberOfBlocks -= MaxTransferBlockNumber;\r
ad86a50a 694 } else {\r
695 TransferBlockNumber = NumberOfBlocks;\r
696 NumberOfBlocks = 0;\r
697 }\r
698\r
490b5ea1 699 //\r
700 // Create sub event for the sub Ata task. Non-Blocking Mode.\r
701 //\r
702 if (Token != NULL && Token->Event != NULL) {\r
703 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
704 Task = AllocateZeroPool (sizeof (ATA_BUS_ASYN_TASK));\r
705 if (Task == NULL) {\r
706 //\r
707 // If resource allocation fail, reduce the total sub event counts.\r
708 //\r
709 *EventCount = (*EventCount) - (TempCount - Index);\r
710 *IsError = TRUE;\r
711 Token->TransactionStatus = EFI_OUT_OF_RESOURCES;\r
712 Status = EFI_OUT_OF_RESOURCES;\r
713\r
714 gBS->RestoreTPL (OldTpl);\r
715 goto EXIT;\r
716 }\r
717\r
718 Task->UnsignalledEventCount = EventCount;\r
719 Task->Token = Token;\r
720 Task->IsError = IsError;\r
721\r
722 InsertTailList (&AtaDevice->AtaTaskList, &Task->TaskEntry);\r
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
736 *EventCount = (*EventCount) - (TempCount - Index);\r
737 *IsError = TRUE;\r
738 gBS->RestoreTPL (OldTpl);\r
739 goto EXIT;\r
740 }\r
741 Index++;\r
742 gBS->RestoreTPL (OldTpl); \r
743\r
744 DEBUG ((EFI_D_INFO, "NON-BLOCKING SET EVENT START: WRITE = %d\n", IsWrite));\r
745 Status = TransferAtaDevice (AtaDevice, &Task->Packet, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, SubEvent);\r
746 DEBUG ((\r
747 EFI_D_INFO,\r
748 "NON-BLOCKING SET EVENT END:StartLba=%x, TransferBlockNumbers=%x, Status=%r\n",\r
749 StartLba,\r
750 TransferBlockNumber,\r
751 Status\r
752 ));\r
753 }else {\r
754 //\r
755 // Blocking Mode.\r
756 //\r
757 DEBUG ((EFI_D_INFO, "BLOCKING BLOCK I/O START: WRITE = %d\n", IsWrite));\r
758 Status = TransferAtaDevice (AtaDevice, NULL, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite, NULL);\r
759 DEBUG ((\r
760 EFI_D_INFO,\r
761 "BLOCKING BLOCK I/O FINISHE - StartLba = %x; TransferBlockNumbers = %x, status = %r\n", \r
762 StartLba,\r
763 TransferBlockNumber,\r
764 Status\r
765 ));\r
766 }\r
767\r
ad86a50a 768 if (EFI_ERROR (Status)) {\r
490b5ea1 769 goto EXIT;\r
ad86a50a 770 }\r
490b5ea1 771\r
ad86a50a 772 StartLba += TransferBlockNumber;\r
773 Buffer += TransferBlockNumber * BlockSize;\r
774 } while (NumberOfBlocks > 0);\r
775\r
490b5ea1 776EXIT:\r
777\r
778 if (*EventCount == 0) {\r
779 FreePool (EventCount);\r
780 FreePool (IsError);\r
781 }\r
782\r
ad86a50a 783 return Status;\r
784}\r
c24097a5 785\r
786/**\r
787 Trust transfer data from/to ATA device.\r
788\r
789 This function performs one ATA pass through transaction to do a trust transfer from/to\r
790 ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru\r
791 interface of ATA pass through.\r
792\r
793 @param AtaDevice The ATA child device involved for the operation.\r
794 @param Buffer The pointer to the current transaction buffer.\r
795 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
796 the security protocol command to be sent.\r
797 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
798 of the security protocol command to be sent.\r
799 @param TransferLength The block number or sector count of the transfer.\r
800 @param IsTrustSend Indicates whether it is a trust send operation or not.\r
801 @param Timeout The timeout, in 100ns units, to use for the execution\r
802 of the security protocol command. A Timeout value of 0\r
803 means that this function will wait indefinitely for the\r
804 security protocol command to execute. If Timeout is greater\r
805 than zero, then this function will return EFI_TIMEOUT\r
806 if the time required to execute the receive data command\r
807 is greater than Timeout.\r
808\r
809 @retval EFI_SUCCESS The data transfer is complete successfully.\r
810 @return others Some error occurs when transferring data. \r
811\r
812**/\r
813EFI_STATUS\r
814EFIAPI\r
815TrustTransferAtaDevice (\r
816 IN OUT ATA_DEVICE *AtaDevice,\r
817 IN OUT VOID *Buffer,\r
818 IN UINT8 SecurityProtocolId,\r
819 IN UINT16 SecurityProtocolSpecificData,\r
820 IN UINTN TransferLength,\r
821 IN BOOLEAN IsTrustSend,\r
822 IN UINT64 Timeout,\r
823 OUT UINTN *TransferLengthOut\r
824 )\r
825{\r
826 EFI_ATA_COMMAND_BLOCK *Acb;\r
827 EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet;\r
828 EFI_STATUS Status;\r
829 VOID *NewBuffer;\r
830 EFI_ATA_PASS_THRU_PROTOCOL *AtaPassThru;\r
831\r
832 //\r
833 // Ensure AtaDevice->UdmaValid and IsTrustSend are valid boolean values \r
834 //\r
835 ASSERT ((UINTN) AtaDevice->UdmaValid < 2);\r
836 ASSERT ((UINTN) IsTrustSend < 2);\r
837 //\r
838 // Prepare for ATA command block.\r
839 //\r
840 Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb));\r
841 if (TransferLength == 0) {\r
842 Acb->AtaCommand = ATA_CMD_TRUST_NON_DATA;\r
843 } else {\r
844 Acb->AtaCommand = mAtaTrustCommands[AtaDevice->UdmaValid][IsTrustSend];\r
845 }\r
846 Acb->AtaFeatures = SecurityProtocolId;\r
847 Acb->AtaSectorCount = (UINT8) (TransferLength / 512);\r
848 Acb->AtaSectorNumber = (UINT8) ((TransferLength / 512) >> 8);\r
849 //\r
850 // NOTE: ATA Spec has no explicitly definition for Security Protocol Specific layout. \r
851 // Here use big edian for Cylinder register. \r
852 //\r
853 Acb->AtaCylinderHigh = (UINT8) SecurityProtocolSpecificData;\r
854 Acb->AtaCylinderLow = (UINT8) (SecurityProtocolSpecificData >> 8);\r
855 Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4)); \r
856\r
857 //\r
858 // Prepare for ATA pass through packet.\r
859 //\r
860 Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet));\r
861 if (TransferLength == 0) {\r
862 Packet->InTransferLength = 0;\r
863 Packet->OutTransferLength = 0;\r
864 Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA;\r
865 } else if (IsTrustSend) {\r
866 //\r
867 // Check the alignment of the incoming buffer prior to invoking underlying ATA PassThru\r
868 //\r
869 AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
870 if ((AtaPassThru->Mode->IoAlign > 1) && !IS_ALIGNED (Buffer, AtaPassThru->Mode->IoAlign)) {\r
871 NewBuffer = AllocateAlignedBuffer (AtaDevice, TransferLength);\r
872 CopyMem (NewBuffer, Buffer, TransferLength);\r
873 FreePool (Buffer);\r
874 Buffer = NewBuffer;\r
875 } \r
876 Packet->OutDataBuffer = Buffer;\r
877 Packet->OutTransferLength = (UINT32) TransferLength;\r
878 Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];\r
879 } else {\r
880 Packet->InDataBuffer = Buffer;\r
881 Packet->InTransferLength = (UINT32) TransferLength;\r
882 Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsTrustSend];\r
883 }\r
884 Packet->Length = EFI_ATA_PASS_THRU_LENGTH_BYTES;\r
885 Packet->Timeout = Timeout;\r
886\r
887 Status = AtaDevicePassThru (AtaDevice, NULL, NULL);\r
888 if (TransferLengthOut != NULL) {\r
889 if (! IsTrustSend) {\r
890 *TransferLengthOut = Packet->InTransferLength;\r
891 }\r
892 }\r
893 return Status;\r
894}\r