The ATA alignment_logic_in_phy_blocks field doesn’t directly report the lowest aligne...
[efi/edk2/.git] / edk2 / MdeModulePkg / Bus / Ata / AtaBusDxe / AtaPassThruExecute.c
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
6   through command and protocol. \r
7     \r
8   Copyright (c) 2009 - 2010 Intel Corporation. <BR>\r
9   All rights reserved. This program and the accompanying materials\r
10   are licensed and made available under the terms and conditions of the BSD License\r
11   which accompanies this distribution.  The full text of the license may be found at\r
12   http://opensource.org/licenses/bsd-license.php\r
13 \r
14   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
16 \r
17 \r
18 **/\r
19 \r
20 #include "AtaBus.h"\r
21 \r
22 //\r
23 // Look up table (UdmaValid, IsWrite) for EFI_ATA_PASS_THRU_CMD_PROTOCOL\r
24 //\r
25 EFI_ATA_PASS_THRU_CMD_PROTOCOL mAtaPassThruCmdProtocols[][2] = {\r
26   {\r
27     EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN,\r
28     EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT\r
29   },\r
30   {\r
31     EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN,\r
32     EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT,\r
33   }\r
34 };\r
35 \r
36 //\r
37 // Look up table (UdmaValid, Lba48Bit, IsIsWrite) for ATA_CMD\r
38 //\r
39 UINT8 mAtaCommands[][2][2] = {\r
40   {\r
41     {\r
42       ATA_CMD_READ_SECTORS,            // 28-bit LBA; PIO read\r
43       ATA_CMD_WRITE_SECTORS            // 28-bit LBA; PIO write\r
44     },\r
45     {\r
46       ATA_CMD_READ_SECTORS_EXT,        // 48-bit LBA; PIO read\r
47       ATA_CMD_WRITE_SECTORS_EXT        // 48-bit LBA; PIO write\r
48     }\r
49   },\r
50   {\r
51     {\r
52       ATA_CMD_READ_DMA,                // 28-bit LBA; DMA read\r
53       ATA_CMD_WRITE_DMA                // 28-bit LBA; DMA write\r
54     },\r
55     {\r
56       ATA_CMD_READ_DMA_EXT,            // 48-bit LBA; DMA read\r
57       ATA_CMD_WRITE_DMA_EXT            // 48-bit LBA; DMA write\r
58     }\r
59   }\r
60 };\r
61 \r
62 //\r
63 // Look up table (Lba48Bit) for maximum transfer block number\r
64 //\r
65 UINTN mMaxTransferBlockNumber[] = {\r
66   MAX_28BIT_TRANSFER_BLOCK_NUM,\r
67   MAX_48BIT_TRANSFER_BLOCK_NUM\r
68 };\r
69 \r
70 \r
71 /**\r
72   Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.PassThru().\r
73 \r
74   This function wraps the PassThru() invocation for ATA pass through function\r
75   for an ATA device. It assembles the ATA pass through command packet for ATA\r
76   transaction.\r
77 \r
78   @param  AtaDevice         The ATA child device involved for the operation.\r
79 \r
80   @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().\r
81 \r
82 **/\r
83 EFI_STATUS\r
84 AtaDevicePassThru (\r
85   IN OUT ATA_DEVICE                       *AtaDevice\r
86   )\r
87 {\r
88   EFI_STATUS                              Status;\r
89   EFI_ATA_PASS_THRU_PROTOCOL              *AtaPassThru;\r
90   EFI_ATA_PASS_THRU_COMMAND_PACKET        *Packet;\r
91 \r
92   //\r
93   // Assemble packet\r
94   //\r
95   Packet = &AtaDevice->Packet;\r
96   Packet->Asb = AtaDevice->Asb;\r
97   Packet->Acb = &AtaDevice->Acb;\r
98   Packet->Timeout = ATA_TIMEOUT;\r
99 \r
100   AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
101 \r
102   Status = AtaPassThru->PassThru (\r
103                           AtaPassThru,\r
104                           AtaDevice->Port,\r
105                           AtaDevice->PortMultiplierPort,\r
106                           Packet,\r
107                           NULL\r
108                           );\r
109   //\r
110   // Ensure ATA pass through caller and callee have the same\r
111   // interpretation of ATA pass through protocol. \r
112   //\r
113   ASSERT (Status != EFI_INVALID_PARAMETER);\r
114   ASSERT (Status != EFI_BAD_BUFFER_SIZE);\r
115 \r
116   return Status;\r
117 }\r
118 \r
119 \r
120 /**\r
121   Wrapper for EFI_ATA_PASS_THRU_PROTOCOL.ResetDevice().\r
122 \r
123   This function wraps the ResetDevice() invocation for ATA pass through function\r
124   for an ATA device. \r
125 \r
126   @param  AtaDevice         The ATA child device involved for the operation.\r
127 \r
128   @return The return status from EFI_ATA_PASS_THRU_PROTOCOL.PassThru().\r
129 \r
130 **/\r
131 EFI_STATUS\r
132 ResetAtaDevice (\r
133   IN ATA_DEVICE                           *AtaDevice\r
134   )\r
135 {\r
136   EFI_ATA_PASS_THRU_PROTOCOL              *AtaPassThru;\r
137   \r
138   AtaPassThru = AtaDevice->AtaBusDriverData->AtaPassThru;\r
139   \r
140   return AtaPassThru->ResetDevice (\r
141                         AtaPassThru,\r
142                         AtaDevice->Port,\r
143                         AtaDevice->PortMultiplierPort\r
144                         );\r
145 }\r
146 \r
147 \r
148 /**\r
149   Prints ATA model name to ATA device structure.\r
150 \r
151   This function converts ATA device model name from ATA identify data \r
152   to a string in ATA device structure. It needs to change the character\r
153   order in the original model name string.\r
154 \r
155   @param  AtaDevice         The ATA child device involved for the operation.\r
156 \r
157 **/\r
158 VOID\r
159 PrintAtaModelName (\r
160   IN OUT ATA_DEVICE  *AtaDevice\r
161   )\r
162 {\r
163   UINTN   Index;\r
164   CHAR8   *Source;\r
165   CHAR16  *Destination;\r
166 \r
167   Source = AtaDevice->IdentifyData->ModelName;\r
168   Destination = AtaDevice->ModelName;\r
169 \r
170   //\r
171   // Swap the byte order in the original module name.\r
172   //\r
173   for (Index = 0; Index < MAX_MODEL_NAME_LEN; Index += 2) {\r
174     Destination[Index]      = Source[Index + 1];\r
175     Destination[Index + 1]  = Source[Index];\r
176   }\r
177   AtaDevice->ModelName[MAX_MODEL_NAME_LEN] = L'\0';\r
178 }\r
179 \r
180 \r
181 /**\r
182   Gets ATA device Capacity according to ATA 6.\r
183 \r
184   This function returns the capacity of the ATA device if it follows\r
185   ATA 6 to support 48 bit addressing.\r
186 \r
187   @param  AtaDevice         The ATA child device involved for the operation.\r
188 \r
189   @return The capacity of the ATA device or 0 if the device does not support\r
190           48-bit addressing defined in ATA 6.\r
191 \r
192 **/\r
193 EFI_LBA\r
194 GetAtapi6Capacity (\r
195   IN ATA_DEVICE                 *AtaDevice\r
196   )\r
197 {\r
198   EFI_LBA                       Capacity;\r
199   EFI_LBA                       TmpLba;\r
200   UINTN                         Index;\r
201   ATA_IDENTIFY_DATA             *IdentifyData;\r
202 \r
203   IdentifyData = AtaDevice->IdentifyData;\r
204   if ((IdentifyData->command_set_supported_83 & BIT10) == 0) {\r
205     //\r
206     // The device doesn't support 48 bit addressing\r
207     //\r
208     return 0;\r
209   }\r
210 \r
211   //\r
212   // 48 bit address feature set is supported, get maximum capacity\r
213   //\r
214   Capacity = 0;\r
215   for (Index = 0; Index < 4; Index++) {\r
216     //\r
217     // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r
218     //\r
219     TmpLba = IdentifyData->maximum_lba_for_48bit_addressing[Index];\r
220     Capacity |= LShiftU64 (TmpLba, 16 * Index);\r
221   }\r
222 \r
223   return Capacity;\r
224 }\r
225 \r
226 \r
227 /**\r
228   Identifies ATA device via the Identify data.\r
229 \r
230   This function identifies the ATA device and initializes the Media information in \r
231   Block IO protocol interface.\r
232 \r
233   @param  AtaDevice         The ATA child device involved for the operation.\r
234 \r
235   @retval EFI_UNSUPPORTED   The device is not a valid ATA device (hard disk).\r
236   @retval EFI_SUCCESS       The device is successfully identified and Media information\r
237                             is correctly initialized.\r
238 \r
239 **/\r
240 EFI_STATUS\r
241 IdentifyAtaDevice (\r
242   IN OUT ATA_DEVICE                 *AtaDevice\r
243   )\r
244 {\r
245   ATA_IDENTIFY_DATA                 *IdentifyData;\r
246   EFI_BLOCK_IO_MEDIA                *BlockMedia;\r
247   EFI_LBA                           Capacity;\r
248   UINT16                            PhyLogicSectorSupport;\r
249   UINT16                            UdmaMode;\r
250 \r
251   IdentifyData = AtaDevice->IdentifyData;\r
252 \r
253   if ((IdentifyData->config & BIT15) != 0) {\r
254     //\r
255     // This is not an hard disk\r
256     //\r
257     return EFI_UNSUPPORTED;\r
258   }\r
259 \r
260   //\r
261   // Check whether the WORD 88 (supported UltraDMA by drive) is valid\r
262   //\r
263   if ((IdentifyData->field_validity & BIT2) != 0) {\r
264     UdmaMode = IdentifyData->ultra_dma_mode;\r
265     if ((UdmaMode & (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0) {\r
266       //\r
267       // If BIT0~BIT6 is selected, then UDMA is supported\r
268       //\r
269       AtaDevice->UdmaValid = TRUE;\r
270     }\r
271   }\r
272 \r
273   Capacity = GetAtapi6Capacity (AtaDevice);\r
274   if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {\r
275     //\r
276     // Capacity exceeds 120GB. 48-bit addressing is really needed\r
277     //\r
278     AtaDevice->Lba48Bit = TRUE;\r
279   } else {\r
280     //\r
281     // This is a hard disk <= 120GB capacity, treat it as normal hard disk\r
282     //\r
283     Capacity = ((UINT32)IdentifyData->user_addressable_sectors_hi << 16) | IdentifyData->user_addressable_sectors_lo;\r
284     AtaDevice->Lba48Bit = FALSE;\r
285   }\r
286 \r
287   //\r
288   // Block Media Information:\r
289   //\r
290   BlockMedia = &AtaDevice->BlockMedia;\r
291   BlockMedia->LastBlock = Capacity - 1;\r
292   BlockMedia->IoAlign = AtaDevice->AtaBusDriverData->AtaPassThru->Mode->IoAlign;\r
293   //\r
294   // Check whether Long Physical Sector Feature is supported\r
295   //\r
296   PhyLogicSectorSupport = IdentifyData->phy_logic_sector_support;\r
297   if ((PhyLogicSectorSupport & (BIT14 | BIT15)) == BIT14) {\r
298     //\r
299     // Check whether one physical block contains multiple physical blocks\r
300     //\r
301     if ((PhyLogicSectorSupport & BIT13) != 0) {\r
302       BlockMedia->LogicalBlocksPerPhysicalBlock = (UINT32) (1 << (PhyLogicSectorSupport & 0x000f));\r
303       //\r
304       // Check lowest alignment of logical blocks within physical block\r
305       //\r
306       if ((IdentifyData->alignment_logic_in_phy_blocks & (BIT14 | BIT15)) == BIT14) {\r
307         BlockMedia->LowestAlignedLba = (EFI_LBA) (BlockMedia->LogicalBlocksPerPhysicalBlock - (IdentifyData->alignment_logic_in_phy_blocks & 0x3fff)) %\r
308           BlockMedia->LogicalBlocksPerPhysicalBlock;\r
309       }\r
310     }\r
311     //\r
312     // Check logical block size\r
313     //\r
314     if ((PhyLogicSectorSupport & BIT12) != 0) {\r
315       BlockMedia->BlockSize = (UINT32) (((IdentifyData->logic_sector_size_hi << 16) | IdentifyData->logic_sector_size_lo) * sizeof (UINT16));\r
316     }\r
317     AtaDevice->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
318   }\r
319   //\r
320   // Get ATA model name from identify data structure. \r
321   //\r
322   PrintAtaModelName (AtaDevice); \r
323 \r
324   return EFI_SUCCESS;\r
325 }\r
326 \r
327 \r
328 /**\r
329   Discovers whether it is a valid ATA device.\r
330 \r
331   This function issues ATA_CMD_IDENTIFY_DRIVE command to the ATA device to identify it.\r
332   If the command is executed successfully, it then identifies it and initializes\r
333   the Media information in Block IO protocol interface.\r
334 \r
335   @param  AtaDevice         The ATA child device involved for the operation.\r
336 \r
337   @retval EFI_SUCCESS       The device is successfully identified and Media information\r
338                             is correctly initialized.\r
339   @return others            Some error occurs when discovering the ATA device. \r
340 \r
341 **/\r
342 EFI_STATUS\r
343 DiscoverAtaDevice (\r
344   IN OUT ATA_DEVICE                 *AtaDevice\r
345   )\r
346 {\r
347   EFI_STATUS                        Status;\r
348   EFI_ATA_COMMAND_BLOCK             *Acb;\r
349   EFI_ATA_PASS_THRU_COMMAND_PACKET  *Packet;\r
350   UINTN                             Retry;\r
351 \r
352   //\r
353   // Prepare for ATA command block.\r
354   //\r
355   Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb));\r
356   Acb->AtaCommand = ATA_CMD_IDENTIFY_DRIVE;\r
357 \r
358   //\r
359   // Prepare for ATA pass through packet.\r
360   //\r
361   Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet));\r
362   Packet->InDataBuffer = AtaDevice->IdentifyData;\r
363   Packet->InTransferLength = sizeof (*AtaDevice->IdentifyData);\r
364   Packet->Protocol = EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN;\r
365   Packet->Length = EFI_ATA_PASS_THRU_LENGTH_BYTES | EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
366 \r
367   Retry = MAX_RETRY_TIMES;\r
368   do {\r
369     Status = AtaDevicePassThru (AtaDevice);\r
370     if (!EFI_ERROR (Status)) {\r
371       //\r
372       // The command is issued successfully\r
373       //\r
374       Status = IdentifyAtaDevice (AtaDevice);\r
375       if (!EFI_ERROR (Status)) {\r
376         return Status;\r
377       }\r
378     }\r
379   } while (Retry-- > 0);\r
380 \r
381   return Status;\r
382 }\r
383 \r
384 /**\r
385   Transfer data from ATA device.\r
386 \r
387   This function performs one ATA pass through transaction to transfer data from/to\r
388   ATA device. It chooses the appropriate ATA command and protocol to invoke PassThru\r
389   interface of ATA pass through.\r
390 \r
391   @param  AtaDevice         The ATA child device involved for the operation.\r
392   @param  Buffer            The pointer to the current transaction buffer.\r
393   @param  StartLba          The starting logical block address to be accessed.\r
394   @param  TransferLength    The block number or sector count of the transfer.\r
395   @param  IsWrite           Indicates whether it is a write operation.\r
396 \r
397   @retval EFI_SUCCESS       The data transfer is complete successfully.\r
398   @return others            Some error occurs when transferring data. \r
399 \r
400 **/\r
401 EFI_STATUS\r
402 TransferAtaDevice (\r
403   IN OUT ATA_DEVICE                 *AtaDevice,\r
404   IN OUT VOID                       *Buffer,\r
405   IN EFI_LBA                        StartLba,\r
406   IN UINT32                         TransferLength,\r
407   IN BOOLEAN                        IsWrite\r
408   )\r
409 {\r
410   EFI_ATA_COMMAND_BLOCK             *Acb;\r
411   EFI_ATA_PASS_THRU_COMMAND_PACKET  *Packet;\r
412 \r
413   //\r
414   // Ensure AtaDevice->UdmaValid, AtaDevice->Lba48Bit and IsWrite are valid boolean values \r
415   //\r
416   ASSERT ((UINTN) AtaDevice->UdmaValid < 2);\r
417   ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);\r
418   ASSERT ((UINTN) IsWrite < 2);\r
419   //\r
420   // Prepare for ATA command block.\r
421   //\r
422   Acb = ZeroMem (&AtaDevice->Acb, sizeof (*Acb));\r
423   Acb->AtaCommand = mAtaCommands[AtaDevice->UdmaValid][AtaDevice->Lba48Bit][IsWrite];\r
424   Acb->AtaSectorNumber = (UINT8) StartLba;\r
425   Acb->AtaCylinderLow = (UINT8) RShiftU64 (StartLba, 8);\r
426   Acb->AtaCylinderHigh = (UINT8) RShiftU64 (StartLba, 16);\r
427   Acb->AtaDeviceHead = (UINT8) (BIT7 | BIT6 | BIT5 | (AtaDevice->PortMultiplierPort << 4)); \r
428   Acb->AtaSectorCount = (UINT8) TransferLength;\r
429   if (AtaDevice->Lba48Bit) {\r
430     Acb->AtaSectorNumberExp = (UINT8) RShiftU64 (StartLba, 24);\r
431     Acb->AtaCylinderLowExp = (UINT8) RShiftU64 (StartLba, 32);\r
432     Acb->AtaCylinderHighExp = (UINT8) RShiftU64 (StartLba, 40);\r
433     Acb->AtaSectorCountExp = (UINT8) (TransferLength >> 8);\r
434   } else {\r
435     Acb->AtaDeviceHead = (UINT8) (Acb->AtaDeviceHead | RShiftU64 (StartLba, 24));\r
436   }\r
437 \r
438   //\r
439   // Prepare for ATA pass through packet.\r
440   //\r
441   Packet = ZeroMem (&AtaDevice->Packet, sizeof (*Packet));\r
442   if (IsWrite) {\r
443     Packet->OutDataBuffer = Buffer;\r
444     Packet->OutTransferLength = TransferLength;\r
445   } else {\r
446     Packet->InDataBuffer = Buffer;\r
447     Packet->InTransferLength = TransferLength;\r
448   }\r
449   Packet->Protocol = mAtaPassThruCmdProtocols[AtaDevice->UdmaValid][IsWrite];\r
450   Packet->Length = EFI_ATA_PASS_THRU_LENGTH_SECTOR_COUNT;\r
451 \r
452   return AtaDevicePassThru (AtaDevice); \r
453 }\r
454 \r
455 /**\r
456   Read or write a number of blocks from ATA device.\r
457 \r
458   This function performs ATA pass through transactions to read/write data from/to\r
459   ATA device. It may separate the read/write request into several ATA pass through\r
460   transactions.\r
461 \r
462   @param  AtaDevice         The ATA child device involved for the operation.\r
463   @param  Buffer            The pointer to the current transaction buffer.\r
464   @param  StartLba          The starting logical block address to be accessed.\r
465   @param  NumberOfBlocks    The block number or sector count of the transfer.\r
466   @param  IsWrite           Indicates whether it is a write operation.\r
467 \r
468   @retval EFI_SUCCESS       The data transfer is complete successfully.\r
469   @return others            Some error occurs when transferring data. \r
470 \r
471 **/\r
472 EFI_STATUS \r
473 AccessAtaDevice(\r
474   IN OUT ATA_DEVICE                 *AtaDevice,\r
475   IN OUT UINT8                      *Buffer,\r
476   IN EFI_LBA                        StartLba,\r
477   IN UINTN                          NumberOfBlocks,\r
478   IN BOOLEAN                        IsWrite\r
479   )\r
480 {\r
481   EFI_STATUS                        Status;\r
482   UINTN                             MaxTransferBlockNumber;\r
483   UINTN                             TransferBlockNumber;\r
484   UINTN                             BlockSize;\r
485  \r
486   //\r
487   // Ensure AtaDevice->Lba48Bit is a valid boolean value \r
488   //\r
489   ASSERT ((UINTN) AtaDevice->Lba48Bit < 2);\r
490   MaxTransferBlockNumber = mMaxTransferBlockNumber[AtaDevice->Lba48Bit];\r
491   BlockSize = AtaDevice->BlockMedia.BlockSize;\r
492   do {\r
493     if (NumberOfBlocks > MaxTransferBlockNumber) {\r
494       TransferBlockNumber = MaxTransferBlockNumber;\r
495       NumberOfBlocks -= MaxTransferBlockNumber;\r
496     } else  {\r
497       TransferBlockNumber = NumberOfBlocks;\r
498       NumberOfBlocks  = 0;\r
499     }\r
500 \r
501     Status = TransferAtaDevice (AtaDevice, Buffer, StartLba, (UINT32) TransferBlockNumber, IsWrite);\r
502     if (EFI_ERROR (Status)) {\r
503       return Status;\r
504     }\r
505     StartLba += TransferBlockNumber;\r
506     Buffer   += TransferBlockNumber * BlockSize;\r
507   } while (NumberOfBlocks > 0);\r
508 \r
509   return Status;\r
510 }\r