]>
Commit | Line | Data |
---|---|---|
ead42efc | 1 | /** @file\r |
630d580d | 2 | This file contains all helper functions on the ATA command \r |
3 | \r | |
180a5a35 HT |
4 | Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r |
5 | This program and the accompanying materials\r | |
ead42efc | 6 | are licensed and made available under the terms and conditions of the BSD License\r |
7 | which accompanies this distribution. The full text of the license may be found at\r | |
8 | http://opensource.org/licenses/bsd-license.php\r | |
9 | \r | |
10 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
11 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
12 | \r | |
13 | @par Revision Reference:\r | |
14 | 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including\r | |
15 | update - ATAIdentity() func\r | |
16 | update - AtaBlockIoReadBlocks() func\r | |
17 | update - AtaBlockIoWriteBlocks() func\r | |
18 | add - AtaAtapi6Identify() func\r | |
19 | add - AtaReadSectorsExt() func\r | |
20 | add - AtaWriteSectorsExt() func\r | |
21 | add - AtaPioDataInExt() func\r | |
22 | add - AtaPioDataOutExt() func\r | |
23 | \r | |
24 | **/\r | |
25 | \r | |
03417d8d | 26 | #include "IdeBus.h"\r |
630d580d | 27 | /**\r |
28 | This function is called by ATAIdentify() to identity whether this disk\r | |
29 | supports ATA/ATAPI6 48bit addressing, ie support >120G capacity\r | |
30 | \r | |
31 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r | |
32 | all the information of the IDE device.\r | |
33 | \r | |
34 | @retval EFI_SUCCESS The disk specified by IdeDev is a Atapi6 supported one and \r | |
35 | 48-bit addressing must be used\r | |
36 | @retval EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but the \r | |
37 | capacity is below 120G, 48bit addressing is not needed\r | |
38 | @retval EFI_DEVICE_ERROR The identify data in IdeDev is incorrect\r | |
39 | @retval EFI_INVALID_PARAMETER The identify data in IdeDev is NULL.\r | |
40 | \r | |
41 | @note This function must be called after DEVICE_IDENTITY command has been\r | |
42 | successfully returned\r | |
43 | \r | |
44 | **/\r | |
45 | EFI_STATUS\r | |
46 | AtaAtapi6Identify (\r | |
47 | IN IDE_BLK_IO_DEV *IdeDev\r | |
48 | )\r | |
49 | {\r | |
50 | UINT8 Index;\r | |
51 | EFI_LBA TmpLba;\r | |
52 | EFI_LBA Capacity;\r | |
53 | EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;\r | |
54 | \r | |
55 | if (IdeDev->IdData == NULL) {\r | |
56 | return EFI_INVALID_PARAMETER;\r | |
57 | }\r | |
58 | \r | |
59 | Atapi6IdentifyStruct = IdeDev->IdData;\r | |
60 | \r | |
61 | if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & (BIT15 | BIT14)) != 0x4000) {\r | |
62 | //\r | |
63 | // Per ATA-6 spec, word83: bit15 is zero and bit14 is one\r | |
64 | //\r | |
65 | return EFI_DEVICE_ERROR;\r | |
66 | }\r | |
67 | \r | |
68 | if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & BIT10) == 0) {\r | |
69 | //\r | |
70 | // The device dosn't support 48 bit addressing\r | |
71 | //\r | |
72 | return EFI_UNSUPPORTED;\r | |
73 | }\r | |
74 | \r | |
75 | //\r | |
76 | // 48 bit address feature set is supported, get maximum capacity\r | |
77 | //\r | |
a7ddec11 | 78 | Capacity = Atapi6IdentifyStruct->AtaData.maximum_lba_for_48bit_addressing[0];\r |
630d580d | 79 | for (Index = 1; Index < 4; Index++) {\r |
80 | //\r | |
81 | // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r | |
82 | //\r | |
a7ddec11 | 83 | TmpLba = Atapi6IdentifyStruct->AtaData.maximum_lba_for_48bit_addressing[Index];\r |
630d580d | 84 | Capacity |= LShiftU64 (TmpLba, 16 * Index);\r |
85 | }\r | |
86 | \r | |
87 | if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {\r | |
88 | //\r | |
89 | // Capacity exceeds 120GB. 48-bit addressing is really needed\r | |
90 | //\r | |
91 | IdeDev->Type = Ide48bitAddressingHardDisk;\r | |
92 | \r | |
93 | //\r | |
94 | // Fill block media information:Media->LogicalPartition ,\r | |
95 | // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.\r | |
96 | //\r | |
97 | IdeDev->BlkIo.Media->IoAlign = 4;\r | |
98 | IdeDev->BlkIo.Media->MediaId = 1;\r | |
99 | IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r | |
100 | IdeDev->BlkIo.Media->MediaPresent = TRUE;\r | |
101 | IdeDev->BlkIo.Media->ReadOnly = FALSE;\r | |
102 | IdeDev->BlkIo.Media->BlockSize = 0x200;\r | |
103 | IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r | |
104 | \r | |
105 | return EFI_SUCCESS;\r | |
106 | }\r | |
107 | \r | |
108 | return EFI_UNSUPPORTED;\r | |
109 | }\r | |
110 | /**\r | |
111 | Enable SMART of the disk if supported\r | |
112 | \r | |
113 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record \r | |
114 | all the information of the IDE device.\r | |
115 | **/\r | |
116 | VOID\r | |
117 | AtaSMARTSupport (\r | |
118 | IN IDE_BLK_IO_DEV *IdeDev\r | |
119 | )\r | |
120 | {\r | |
121 | EFI_STATUS Status;\r | |
122 | BOOLEAN SMARTSupported;\r | |
123 | UINT8 Device;\r | |
124 | EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;\r | |
125 | UINT8 DeviceSelect;\r | |
126 | UINT8 LBAMid;\r | |
127 | UINT8 LBAHigh;\r | |
128 | \r | |
129 | //\r | |
130 | // Detect if the device supports S.M.A.R.T.\r | |
131 | //\r | |
132 | if ((IdeDev->IdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {\r | |
133 | //\r | |
134 | // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)\r | |
135 | //\r | |
136 | return ;\r | |
137 | } else {\r | |
138 | if ((IdeDev->IdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r | |
139 | //\r | |
140 | // S.M.A.R.T is not supported by the device\r | |
141 | //\r | |
142 | SMARTSupported = FALSE;\r | |
143 | } else {\r | |
144 | SMARTSupported = TRUE;\r | |
145 | }\r | |
146 | }\r | |
147 | \r | |
148 | if (!SMARTSupported) {\r | |
149 | //\r | |
150 | // Report nonsupport status code\r | |
151 | //\r | |
152 | REPORT_STATUS_CODE (\r | |
153 | EFI_ERROR_CODE | EFI_ERROR_MINOR,\r | |
154 | (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r | |
155 | );\r | |
156 | } else {\r | |
157 | //\r | |
158 | // Enable this feature\r | |
159 | //\r | |
160 | REPORT_STATUS_CODE (\r | |
161 | EFI_PROGRESS_CODE,\r | |
162 | (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r | |
163 | );\r | |
164 | \r | |
165 | Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r | |
166 | Status = AtaNonDataCommandIn (\r | |
167 | IdeDev,\r | |
168 | ATA_CMD_SMART,\r | |
169 | Device,\r | |
170 | ATA_SMART_ENABLE_OPERATION,\r | |
171 | 0,\r | |
172 | 0,\r | |
173 | ATA_CONSTANT_4F,\r | |
174 | ATA_CONSTANT_C2\r | |
175 | );\r | |
176 | //\r | |
177 | // Detect if this feature is enabled\r | |
178 | //\r | |
179 | TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r | |
180 | if (TmpAtaIdentifyPointer == NULL) {\r | |
181 | return;\r | |
182 | }\r | |
183 | \r | |
184 | DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r | |
185 | Status = AtaPioDataIn (\r | |
186 | IdeDev,\r | |
187 | (VOID *) TmpAtaIdentifyPointer,\r | |
188 | sizeof (EFI_IDENTIFY_DATA),\r | |
189 | ATA_CMD_IDENTIFY_DRIVE,\r | |
190 | DeviceSelect,\r | |
191 | 0,\r | |
192 | 0,\r | |
193 | 0,\r | |
194 | 0\r | |
195 | );\r | |
196 | if (EFI_ERROR (Status)) {\r | |
197 | gBS->FreePool (TmpAtaIdentifyPointer);\r | |
198 | return ;\r | |
199 | }\r | |
200 | \r | |
201 | //\r | |
202 | // Check if the feature is enabled\r | |
203 | //\r | |
204 | if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {\r | |
205 | //\r | |
206 | // Read status data\r | |
207 | //\r | |
208 | AtaNonDataCommandIn (\r | |
209 | IdeDev,\r | |
210 | ATA_CMD_SMART,\r | |
211 | Device,\r | |
212 | ATA_SMART_RETURN_STATUS,\r | |
213 | 0,\r | |
214 | 0,\r | |
215 | ATA_CONSTANT_4F,\r | |
216 | ATA_CONSTANT_C2\r | |
217 | );\r | |
218 | LBAMid = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r | |
219 | LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);\r | |
220 | \r | |
221 | if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r | |
222 | //\r | |
223 | // The threshold exceeded condition is not detected by the device\r | |
224 | //\r | |
225 | REPORT_STATUS_CODE (\r | |
226 | EFI_PROGRESS_CODE,\r | |
227 | (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r | |
228 | );\r | |
ead42efc | 229 | \r |
630d580d | 230 | } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r |
231 | //\r | |
232 | // The threshold exceeded condition is detected by the device\r | |
233 | //\r | |
234 | REPORT_STATUS_CODE (\r | |
235 | EFI_PROGRESS_CODE,\r | |
236 | (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r | |
237 | );\r | |
238 | }\r | |
239 | \r | |
240 | } else {\r | |
241 | //\r | |
242 | // Report disabled status code\r | |
243 | //\r | |
244 | REPORT_STATUS_CODE (\r | |
245 | EFI_ERROR_CODE | EFI_ERROR_MINOR,\r | |
246 | (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r | |
247 | );\r | |
248 | }\r | |
249 | \r | |
250 | gBS->FreePool (TmpAtaIdentifyPointer);\r | |
251 | }\r | |
252 | \r | |
253 | return ;\r | |
254 | }\r | |
ead42efc | 255 | /**\r |
256 | Sends out an ATA Identify Command to the specified device.\r | |
257 | \r | |
258 | This function is called by DiscoverIdeDevice() during its device\r | |
259 | identification. It sends out the ATA Identify Command to the\r | |
260 | specified device. Only ATA device responses to this command. If\r | |
261 | the command succeeds, it returns the Identify data structure which\r | |
262 | contains information about the device. This function extracts the\r | |
263 | information it needs to fill the IDE_BLK_IO_DEV data structure,\r | |
264 | including device type, media block size, media capacity, and etc.\r | |
265 | \r | |
630d580d | 266 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record \r |
267 | all the information of the IDE device.\r | |
ead42efc | 268 | \r |
630d580d | 269 | @retval EFI_SUCCESS Identify ATA device successfully.\r |
270 | @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.\r | |
271 | @note parameter IdeDev will be updated in this function.\r | |
ead42efc | 272 | \r |
273 | **/\r | |
274 | EFI_STATUS\r | |
275 | ATAIdentify (\r | |
276 | IN IDE_BLK_IO_DEV *IdeDev\r | |
277 | )\r | |
278 | {\r | |
279 | EFI_STATUS Status;\r | |
280 | EFI_IDENTIFY_DATA *AtaIdentifyPointer;\r | |
281 | UINT32 Capacity;\r | |
282 | UINT8 DeviceSelect;\r | |
6979fd93 | 283 | UINTN Retry;\r |
ead42efc | 284 | \r |
285 | //\r | |
286 | // AtaIdentifyPointer is used for accommodating returned IDENTIFY data of\r | |
287 | // the ATA Identify command\r | |
288 | //\r | |
289 | AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r | |
261136bc | 290 | if (AtaIdentifyPointer == NULL) {\r |
291 | return EFI_OUT_OF_RESOURCES;\r | |
292 | }\r | |
ead42efc | 293 | \r |
294 | //\r | |
295 | // use ATA PIO Data In protocol to send ATA Identify command\r | |
296 | // and receive data from device\r | |
297 | //\r | |
298 | DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r | |
ead42efc | 299 | \r |
6979fd93 | 300 | \r |
301 | Retry = 3;\r | |
302 | while (Retry > 0) { \r | |
303 | Status = AtaPioDataIn (\r | |
304 | IdeDev,\r | |
305 | (VOID *) AtaIdentifyPointer,\r | |
306 | sizeof (EFI_IDENTIFY_DATA),\r | |
307 | ATA_CMD_IDENTIFY_DRIVE,\r | |
308 | DeviceSelect,\r | |
309 | 0,\r | |
310 | 0,\r | |
311 | 0,\r | |
312 | 0\r | |
313 | );\r | |
ead42efc | 314 | //\r |
6979fd93 | 315 | // If ATA Identify command succeeds, then according to the received\r |
316 | // IDENTIFY data,\r | |
317 | // identify the device type ( ATA or not ).\r | |
318 | // If ATA device, fill the information in IdeDev.\r | |
319 | // If not ATA device, return IDE_DEVICE_ERROR\r | |
ead42efc | 320 | //\r |
6979fd93 | 321 | if (!EFI_ERROR (Status)) {\r |
322 | \r | |
e72ca438 | 323 | IdeDev->IdData = AtaIdentifyPointer;\r |
ead42efc | 324 | \r |
ead42efc | 325 | //\r |
6979fd93 | 326 | // Print ATA Module Name\r |
ead42efc | 327 | //\r |
6979fd93 | 328 | PrintAtaModuleName (IdeDev);\r |
ead42efc | 329 | \r |
330 | //\r | |
6979fd93 | 331 | // bit 15 of pAtaIdentify->config is used to identify whether device is\r |
332 | // ATA device or ATAPI device.\r | |
333 | // if 0, means ATA device; if 1, means ATAPI device.\r | |
ead42efc | 334 | //\r |
6979fd93 | 335 | if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) {\r |
ead42efc | 336 | //\r |
6979fd93 | 337 | // Detect if support S.M.A.R.T. If yes, enable it as default\r |
ead42efc | 338 | //\r |
6979fd93 | 339 | AtaSMARTSupport (IdeDev);\r |
ead42efc | 340 | \r |
6979fd93 | 341 | //\r |
342 | // Check whether this device needs 48-bit addressing (ATAPI-6 ata device)\r | |
343 | //\r | |
344 | Status = AtaAtapi6Identify (IdeDev);\r | |
345 | if (!EFI_ERROR (Status)) {\r | |
346 | //\r | |
347 | // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify()\r | |
348 | //\r | |
349 | return EFI_SUCCESS;\r | |
350 | } else if (Status == EFI_DEVICE_ERROR) {\r | |
351 | //\r | |
352 | // Some disk with big capacity (>200GB) is slow when being identified\r | |
353 | // and will return all zero for word83.\r | |
354 | // We try twice at first. If it fails, we do a SoftRest and try again.\r | |
355 | //\r | |
356 | Retry--;\r | |
357 | if (Retry == 1) {\r | |
358 | //\r | |
359 | // Do a SoftRest before the third attempt.\r | |
360 | //\r | |
361 | AtaSoftReset (IdeDev);\r | |
362 | }\r | |
363 | continue;\r | |
364 | }\r | |
365 | //\r | |
366 | // This is a hard disk <= 120GB capacity, treat it as normal hard disk\r | |
367 | //\r | |
368 | IdeDev->Type = IdeHardDisk;\r | |
ead42efc | 369 | \r |
6979fd93 | 370 | //\r |
371 | // Block Media Information:\r | |
372 | // Media->LogicalPartition , Media->WriteCaching will be filled\r | |
373 | // in the DiscoverIdeDevcie() function.\r | |
374 | //\r | |
375 | IdeDev->BlkIo.Media->IoAlign = 4;\r | |
376 | IdeDev->BlkIo.Media->MediaId = 1;\r | |
377 | IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r | |
378 | IdeDev->BlkIo.Media->MediaPresent = TRUE;\r | |
379 | IdeDev->BlkIo.Media->ReadOnly = FALSE;\r | |
380 | IdeDev->BlkIo.Media->BlockSize = 0x200;\r | |
381 | \r | |
382 | //\r | |
383 | // Calculate device capacity\r | |
384 | //\r | |
385 | Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) |\r | |
ead42efc | 386 | AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ;\r |
6979fd93 | 387 | IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r |
ead42efc | 388 | \r |
6979fd93 | 389 | return EFI_SUCCESS;\r |
390 | }\r | |
ead42efc | 391 | \r |
392 | }\r | |
6979fd93 | 393 | break;\r |
ead42efc | 394 | }\r |
395 | \r | |
396 | gBS->FreePool (AtaIdentifyPointer);\r | |
397 | //\r | |
398 | // Make sure the pIdData will not be freed again.\r | |
399 | //\r | |
e72ca438 | 400 | IdeDev->IdData = NULL;\r |
ead42efc | 401 | \r |
402 | return EFI_DEVICE_ERROR;\r | |
403 | }\r | |
404 | \r | |
ead42efc | 405 | /**\r |
630d580d | 406 | This function is a helper function used to change the char order in a string. It\r |
407 | is designed specially for the PrintAtaModuleName() function. After the IDE device \r | |
408 | is detected, the IDE driver gets the device module name by sending ATA command \r | |
409 | called ATA Identify Command or ATAPI Identify Command to the specified IDE device.\r | |
410 | The module name returned is a string of ASCII characters: the first character is bit8--bit15\r | |
411 | of the first word, the second character is BIT0--bit7 of the first word and so on. Thus\r | |
412 | the string can not be print directly before it is preprocessed by this func to change \r | |
413 | the order of characters in each word in the string.\r | |
414 | \r | |
415 | @param Destination Indicates the destination string.\r | |
416 | @param Source Indicates the source string.\r | |
417 | @param Size the length of the string\r | |
418 | **/\r | |
419 | VOID\r | |
420 | SwapStringChars (\r | |
421 | IN CHAR8 *Destination,\r | |
422 | IN CHAR8 *Source,\r | |
423 | IN UINT32 Size\r | |
424 | )\r | |
425 | {\r | |
426 | UINT32 Index;\r | |
427 | CHAR8 Temp;\r | |
6979fd93 | 428 | \r |
630d580d | 429 | for (Index = 0; Index < Size; Index += 2) {\r |
ead42efc | 430 | \r |
630d580d | 431 | Temp = Source[Index + 1];\r |
432 | Destination[Index + 1] = Source[Index];\r | |
433 | Destination[Index] = Temp;\r | |
434 | }\r | |
435 | }\r | |
436 | /**\r | |
437 | This function is called by ATAIdentify() or ATAPIIdentify() to print device's module name.\r | |
ead42efc | 438 | \r |
630d580d | 439 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r |
440 | all the information of the IDE device.\r | |
ead42efc | 441 | **/\r |
630d580d | 442 | VOID\r |
443 | PrintAtaModuleName (\r | |
ead42efc | 444 | IN IDE_BLK_IO_DEV *IdeDev\r |
445 | )\r | |
446 | {\r | |
e72ca438 | 447 | if (IdeDev->IdData == NULL) {\r |
630d580d | 448 | return ;\r |
ead42efc | 449 | }\r |
450 | \r | |
630d580d | 451 | SwapStringChars (IdeDev->ModelName, IdeDev->IdData->AtaData.ModelName, 40);\r |
452 | IdeDev->ModelName[40] = 0x00;\r | |
453 | }\r | |
ead42efc | 454 | \r |
630d580d | 455 | /**\r |
456 | This function is used to send out ATA commands conforms to the PIO Data In Protocol.\r | |
ead42efc | 457 | \r |
630d580d | 458 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r |
459 | all the information of the IDE device.\r | |
460 | @param Buffer buffer contained data transferred from device to host.\r | |
461 | @param ByteCount data size in byte unit of the buffer.\r | |
462 | @param AtaCommand value of the Command Register\r | |
463 | @param Head value of the Head/Device Register\r | |
464 | @param SectorCount value of the Sector Count Register\r | |
465 | @param SectorNumber value of the Sector Number Register\r | |
466 | @param CylinderLsb value of the low byte of the Cylinder Register\r | |
467 | @param CylinderMsb value of the high byte of the Cylinder Register\r | |
468 | \r | |
469 | @retval EFI_SUCCESS send out the ATA command and device send required data successfully.\r | |
ead42efc | 470 | @retval EFI_DEVICE_ERROR command sent failed.\r |
471 | \r | |
472 | **/\r | |
473 | EFI_STATUS\r | |
474 | AtaPioDataIn (\r | |
475 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
476 | IN VOID *Buffer,\r | |
477 | IN UINT32 ByteCount,\r | |
478 | IN UINT8 AtaCommand,\r | |
479 | IN UINT8 Head,\r | |
480 | IN UINT8 SectorCount,\r | |
481 | IN UINT8 SectorNumber,\r | |
482 | IN UINT8 CylinderLsb,\r | |
483 | IN UINT8 CylinderMsb\r | |
484 | )\r | |
485 | {\r | |
486 | UINTN WordCount;\r | |
487 | UINTN Increment;\r | |
488 | UINT16 *Buffer16;\r | |
489 | EFI_STATUS Status;\r | |
490 | \r | |
491 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r | |
492 | if (EFI_ERROR (Status)) {\r | |
493 | return EFI_DEVICE_ERROR;\r | |
494 | }\r | |
495 | \r | |
496 | //\r | |
497 | // e0:1110,0000-- bit7 and bit5 are reserved bits.\r | |
498 | // bit6 set means LBA mode\r | |
499 | //\r | |
500 | IDEWritePortB (\r | |
501 | IdeDev->PciIo,\r | |
502 | IdeDev->IoPort->Head,\r | |
503 | (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)\r | |
504 | );\r | |
505 | \r | |
506 | //\r | |
507 | // All ATAPI device's ATA commands can be issued regardless of the\r | |
508 | // state of the DRDY\r | |
509 | //\r | |
510 | if (IdeDev->Type == IdeHardDisk) {\r | |
511 | \r | |
512 | Status = DRDYReady (IdeDev, ATATIMEOUT);\r | |
513 | if (EFI_ERROR (Status)) {\r | |
514 | return EFI_DEVICE_ERROR;\r | |
515 | }\r | |
516 | }\r | |
517 | //\r | |
518 | // set all the command parameters\r | |
519 | // Before write to all the following registers, BSY and DRQ must be 0.\r | |
520 | //\r | |
521 | Status = DRQClear2 (IdeDev, ATATIMEOUT);\r | |
522 | if (EFI_ERROR (Status)) {\r | |
523 | return EFI_DEVICE_ERROR;\r | |
524 | }\r | |
525 | \r | |
1e23bd8d | 526 | if (AtaCommand == ATA_CMD_SET_FEATURES) {\r |
ead42efc | 527 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r |
528 | }\r | |
529 | \r | |
530 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r | |
531 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);\r | |
532 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);\r | |
533 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);\r | |
534 | \r | |
535 | //\r | |
536 | // send command via Command Register\r | |
537 | //\r | |
538 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r | |
539 | \r | |
540 | Buffer16 = (UINT16 *) Buffer;\r | |
541 | \r | |
542 | //\r | |
543 | // According to PIO data in protocol, host can perform a series of reads to\r | |
544 | // the data register after each time device set DRQ ready;\r | |
545 | // The data size of "a series of read" is command specific.\r | |
546 | // For most ATA command, data size received from device will not exceed\r | |
547 | // 1 sector, hence the data size for "a series of read" can be the whole data\r | |
548 | // size of one command request.\r | |
549 | // For ATA command such as Read Sector command, the data size of one ATA\r | |
550 | // command request is often larger than 1 sector, according to the\r | |
551 | // Read Sector command, the data size of "a series of read" is exactly 1\r | |
552 | // sector.\r | |
553 | // Here for simplification reason, we specify the data size for\r | |
554 | // "a series of read" to 1 sector (256 words) if data size of one ATA command\r | |
555 | // request is larger than 256 words.\r | |
556 | //\r | |
557 | Increment = 256;\r | |
558 | \r | |
559 | //\r | |
560 | // used to record bytes of currently transfered data\r | |
561 | //\r | |
562 | WordCount = 0;\r | |
563 | \r | |
564 | while (WordCount < ByteCount / 2) {\r | |
565 | //\r | |
566 | // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r | |
567 | //\r | |
568 | Status = DRQReady2 (IdeDev, ATATIMEOUT);\r | |
569 | if (EFI_ERROR (Status)) {\r | |
570 | return EFI_DEVICE_ERROR;\r | |
571 | }\r | |
572 | \r | |
573 | Status = CheckErrorStatus (IdeDev);\r | |
574 | if (EFI_ERROR (Status)) {\r | |
575 | return EFI_DEVICE_ERROR;\r | |
576 | }\r | |
577 | \r | |
578 | //\r | |
579 | // Get the byte count for one series of read\r | |
580 | //\r | |
581 | if ((WordCount + Increment) > ByteCount / 2) {\r | |
582 | Increment = ByteCount / 2 - WordCount;\r | |
583 | }\r | |
584 | \r | |
585 | IDEReadPortWMultiple (\r | |
586 | IdeDev->PciIo,\r | |
587 | IdeDev->IoPort->Data,\r | |
588 | Increment,\r | |
589 | Buffer16\r | |
590 | );\r | |
591 | \r | |
592 | WordCount += Increment;\r | |
593 | Buffer16 += Increment;\r | |
594 | \r | |
595 | }\r | |
596 | \r | |
597 | DRQClear (IdeDev, ATATIMEOUT);\r | |
598 | \r | |
599 | return CheckErrorStatus (IdeDev);\r | |
600 | }\r | |
601 | \r | |
602 | /**\r | |
603 | This function is used to send out ATA commands conforms to the\r | |
604 | PIO Data Out Protocol.\r | |
605 | \r | |
630d580d | 606 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
607 | to record all the information of the IDE device.\r | |
ead42efc | 608 | @param *Buffer buffer contained data transferred from host to device.\r |
609 | @param ByteCount data size in byte unit of the buffer.\r | |
610 | @param AtaCommand value of the Command Register\r | |
611 | @param Head value of the Head/Device Register\r | |
612 | @param SectorCount value of the Sector Count Register\r | |
613 | @param SectorNumber value of the Sector Number Register\r | |
614 | @param CylinderLsb value of the low byte of the Cylinder Register\r | |
615 | @param CylinderMsb value of the high byte of the Cylinder Register\r | |
616 | \r | |
630d580d | 617 | @retval EFI_SUCCESS send out the ATA command and device received required\r |
618 | data successfully.\r | |
ead42efc | 619 | @retval EFI_DEVICE_ERROR command sent failed.\r |
620 | \r | |
621 | **/\r | |
622 | EFI_STATUS\r | |
623 | AtaPioDataOut (\r | |
624 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
625 | IN VOID *Buffer,\r | |
626 | IN UINT32 ByteCount,\r | |
627 | IN UINT8 AtaCommand,\r | |
628 | IN UINT8 Head,\r | |
629 | IN UINT8 SectorCount,\r | |
630 | IN UINT8 SectorNumber,\r | |
631 | IN UINT8 CylinderLsb,\r | |
632 | IN UINT8 CylinderMsb\r | |
633 | )\r | |
634 | {\r | |
635 | UINTN WordCount;\r | |
636 | UINTN Increment;\r | |
637 | UINT16 *Buffer16;\r | |
638 | EFI_STATUS Status;\r | |
639 | \r | |
640 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r | |
641 | if (EFI_ERROR (Status)) {\r | |
642 | return EFI_DEVICE_ERROR;\r | |
643 | }\r | |
644 | \r | |
645 | //\r | |
646 | // select device via Head/Device register.\r | |
647 | // Before write Head/Device register, BSY and DRQ must be 0.\r | |
648 | //\r | |
649 | Status = DRQClear2 (IdeDev, ATATIMEOUT);\r | |
650 | if (EFI_ERROR (Status)) {\r | |
651 | return EFI_DEVICE_ERROR;\r | |
652 | }\r | |
653 | \r | |
654 | //\r | |
655 | // e0:1110,0000-- bit7 and bit5 are reserved bits.\r | |
656 | // bit6 set means LBA mode\r | |
657 | //\r | |
658 | IDEWritePortB (\r | |
659 | IdeDev->PciIo,\r | |
660 | IdeDev->IoPort->Head,\r | |
661 | (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)\r | |
662 | );\r | |
663 | \r | |
664 | Status = DRDYReady (IdeDev, ATATIMEOUT);\r | |
665 | if (EFI_ERROR (Status)) {\r | |
666 | return EFI_DEVICE_ERROR;\r | |
667 | }\r | |
668 | \r | |
669 | //\r | |
670 | // set all the command parameters\r | |
671 | // Before write to all the following registers, BSY and DRQ must be 0.\r | |
672 | //\r | |
673 | Status = DRQClear2 (IdeDev, ATATIMEOUT);\r | |
674 | if (EFI_ERROR (Status)) {\r | |
675 | return EFI_DEVICE_ERROR;\r | |
676 | }\r | |
677 | \r | |
678 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r | |
679 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);\r | |
680 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);\r | |
681 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);\r | |
682 | \r | |
683 | //\r | |
684 | // send command via Command Register\r | |
685 | //\r | |
686 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r | |
687 | \r | |
688 | Buffer16 = (UINT16 *) Buffer;\r | |
689 | \r | |
690 | //\r | |
691 | // According to PIO data out protocol, host can perform a series of\r | |
692 | // writes to the data register after each time device set DRQ ready;\r | |
693 | // The data size of "a series of read" is command specific.\r | |
694 | // For most ATA command, data size written to device will not exceed 1 sector,\r | |
695 | // hence the data size for "a series of write" can be the data size of one\r | |
696 | // command request.\r | |
697 | // For ATA command such as Write Sector command, the data size of one\r | |
698 | // ATA command request is often larger than 1 sector, according to the\r | |
699 | // Write Sector command, the data size of "a series of read" is exactly\r | |
700 | // 1 sector.\r | |
701 | // Here for simplification reason, we specify the data size for\r | |
702 | // "a series of write" to 1 sector (256 words) if data size of one ATA command\r | |
703 | // request is larger than 256 words.\r | |
704 | //\r | |
705 | Increment = 256;\r | |
706 | WordCount = 0;\r | |
707 | \r | |
708 | while (WordCount < ByteCount / 2) {\r | |
709 | \r | |
710 | //\r | |
711 | // DRQReady2-- read Alternate Status Register to determine the DRQ bit\r | |
712 | // data transfer can be performed only when DRQ is ready.\r | |
713 | //\r | |
714 | Status = DRQReady2 (IdeDev, ATATIMEOUT);\r | |
715 | if (EFI_ERROR (Status)) {\r | |
716 | return EFI_DEVICE_ERROR;\r | |
717 | }\r | |
718 | \r | |
719 | Status = CheckErrorStatus (IdeDev);\r | |
720 | if (EFI_ERROR (Status)) {\r | |
721 | return EFI_DEVICE_ERROR;\r | |
722 | }\r | |
723 | \r | |
724 | //\r | |
725 | // Check the remaining byte count is less than 512 bytes\r | |
726 | //\r | |
727 | if ((WordCount + Increment) > ByteCount / 2) {\r | |
728 | Increment = ByteCount / 2 - WordCount;\r | |
729 | }\r | |
730 | //\r | |
731 | // perform a series of write without check DRQ ready\r | |
732 | //\r | |
733 | \r | |
734 | IDEWritePortWMultiple (\r | |
735 | IdeDev->PciIo,\r | |
736 | IdeDev->IoPort->Data,\r | |
737 | Increment,\r | |
738 | Buffer16\r | |
739 | );\r | |
740 | WordCount += Increment;\r | |
741 | Buffer16 += Increment;\r | |
742 | \r | |
743 | }\r | |
744 | \r | |
745 | DRQClear (IdeDev, ATATIMEOUT);\r | |
746 | \r | |
747 | return CheckErrorStatus (IdeDev);\r | |
748 | }\r | |
749 | \r | |
750 | /**\r | |
751 | This function is used to analyze the Status Register and print out\r | |
752 | some debug information and if there is ERR bit set in the Status\r | |
753 | Register, the Error Register's value is also be parsed and print out.\r | |
754 | \r | |
630d580d | 755 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to \r |
756 | record all the information of the IDE device.\r | |
ead42efc | 757 | \r |
758 | @retval EFI_SUCCESS No err information in the Status Register.\r | |
759 | @retval EFI_DEVICE_ERROR Any err information in the Status Register.\r | |
760 | \r | |
761 | **/\r | |
762 | EFI_STATUS\r | |
763 | CheckErrorStatus (\r | |
764 | IN IDE_BLK_IO_DEV *IdeDev\r | |
765 | )\r | |
766 | {\r | |
767 | UINT8 StatusRegister;\r | |
768 | UINT8 ErrorRegister;\r | |
769 | \r | |
770 | StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r | |
771 | \r | |
772 | DEBUG_CODE_BEGIN ();\r | |
773 | \r | |
630d580d | 774 | if ((StatusRegister & ATA_STSREG_DWF) != 0) {\r |
775 | DEBUG (\r | |
776 | (EFI_D_BLKIO,\r | |
777 | "CheckErrorStatus()-- %02x : Error : Write Fault\n",\r | |
778 | StatusRegister)\r | |
779 | );\r | |
780 | }\r | |
ead42efc | 781 | \r |
630d580d | 782 | if ((StatusRegister & ATA_STSREG_CORR) != 0) {\r |
783 | DEBUG (\r | |
784 | (EFI_D_BLKIO,\r | |
785 | "CheckErrorStatus()-- %02x : Error : Corrected Data\n",\r | |
786 | StatusRegister)\r | |
787 | );\r | |
788 | }\r | |
ead42efc | 789 | \r |
630d580d | 790 | if ((StatusRegister & ATA_STSREG_ERR) != 0) {\r |
791 | ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r | |
ead42efc | 792 | \r |
630d580d | 793 | if ((ErrorRegister & ATA_ERRREG_BBK) != 0) {\r |
ead42efc | 794 | DEBUG (\r |
795 | (EFI_D_BLKIO,\r | |
796 | "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",\r | |
797 | ErrorRegister)\r | |
798 | );\r | |
799 | }\r | |
800 | \r | |
97404058 | 801 | if ((ErrorRegister & ATA_ERRREG_UNC) != 0) {\r |
ead42efc | 802 | DEBUG (\r |
803 | (EFI_D_BLKIO,\r | |
804 | "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",\r | |
805 | ErrorRegister)\r | |
806 | );\r | |
807 | }\r | |
808 | \r | |
97404058 | 809 | if ((ErrorRegister & ATA_ERRREG_MC) != 0) {\r |
ead42efc | 810 | DEBUG (\r |
811 | (EFI_D_BLKIO,\r | |
812 | "CheckErrorStatus()-- %02x : Error : Media Change\n",\r | |
813 | ErrorRegister)\r | |
814 | );\r | |
815 | }\r | |
816 | \r | |
97404058 | 817 | if ((ErrorRegister & ATA_ERRREG_ABRT) != 0) {\r |
ead42efc | 818 | DEBUG (\r |
819 | (EFI_D_BLKIO,\r | |
820 | "CheckErrorStatus()-- %02x : Error : Abort\n",\r | |
821 | ErrorRegister)\r | |
822 | );\r | |
823 | }\r | |
824 | \r | |
97404058 | 825 | if ((ErrorRegister & ATA_ERRREG_TK0NF) != 0) {\r |
ead42efc | 826 | DEBUG (\r |
827 | (EFI_D_BLKIO,\r | |
828 | "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",\r | |
829 | ErrorRegister)\r | |
830 | );\r | |
831 | }\r | |
832 | \r | |
97404058 | 833 | if ((ErrorRegister & ATA_ERRREG_AMNF) != 0) {\r |
ead42efc | 834 | DEBUG (\r |
835 | (EFI_D_BLKIO,\r | |
836 | "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",\r | |
837 | ErrorRegister)\r | |
838 | );\r | |
839 | }\r | |
840 | }\r | |
841 | \r | |
842 | DEBUG_CODE_END ();\r | |
843 | \r | |
1e23bd8d | 844 | if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {\r |
ead42efc | 845 | return EFI_SUCCESS;\r |
846 | }\r | |
847 | \r | |
848 | return EFI_DEVICE_ERROR;\r | |
849 | \r | |
850 | }\r | |
851 | \r | |
852 | /**\r | |
630d580d | 853 | This function is called by the AtaBlkIoReadBlocks() to perform reading from \r |
854 | media in block unit.\r | |
855 | \r | |
856 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r | |
857 | all the information of the IDE device.\r | |
858 | @param DataBuffer A pointer to the destination buffer for the data.\r | |
859 | @param Lba The starting logical block address to read from on the device media.\r | |
860 | @param NumberOfBlocks The number of transfer data blocks.\r | |
861 | \r | |
862 | @return status is fully dependent on the return status of AtaPioDataIn() function.\r | |
ead42efc | 863 | \r |
864 | **/\r | |
865 | EFI_STATUS\r | |
866 | AtaReadSectors (\r | |
867 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
868 | IN VOID *DataBuffer,\r | |
869 | IN EFI_LBA Lba,\r | |
870 | IN UINTN NumberOfBlocks\r | |
871 | )\r | |
872 | {\r | |
873 | EFI_STATUS Status;\r | |
874 | UINTN BlocksRemaining;\r | |
875 | UINT32 Lba32;\r | |
876 | UINT8 Lba0;\r | |
877 | UINT8 Lba1;\r | |
878 | UINT8 Lba2;\r | |
879 | UINT8 Lba3;\r | |
880 | UINT8 AtaCommand;\r | |
881 | UINT8 SectorCount8;\r | |
882 | UINT16 SectorCount;\r | |
883 | UINTN ByteCount;\r | |
884 | VOID *Buffer;\r | |
885 | \r | |
886 | Buffer = DataBuffer;\r | |
887 | \r | |
888 | //\r | |
889 | // Using ATA Read Sector(s) command (opcode=0x20) with PIO DATA IN protocol\r | |
890 | //\r | |
1e23bd8d | 891 | AtaCommand = ATA_CMD_READ_SECTORS;\r |
ead42efc | 892 | \r |
893 | \r | |
894 | BlocksRemaining = NumberOfBlocks;\r | |
895 | \r | |
896 | Lba32 = (UINT32) Lba;\r | |
897 | \r | |
898 | Status = EFI_SUCCESS;\r | |
899 | \r | |
900 | while (BlocksRemaining > 0) {\r | |
901 | \r | |
902 | //\r | |
903 | // in ATA-3 spec, LBA is in 28 bit width\r | |
904 | //\r | |
905 | Lba0 = (UINT8) Lba32;\r | |
906 | Lba1 = (UINT8) (Lba32 >> 8);\r | |
907 | Lba2 = (UINT8) (Lba32 >> 16);\r | |
908 | //\r | |
909 | // low 4 bit of Lba3 stands for LBA bit24~bit27.\r | |
910 | //\r | |
911 | Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);\r | |
912 | \r | |
913 | if (BlocksRemaining >= 0x100) {\r | |
914 | \r | |
915 | //\r | |
916 | // SectorCount8 is sent to Sector Count register, 0x00 means 256\r | |
917 | // sectors to be read\r | |
918 | //\r | |
919 | SectorCount8 = 0x00;\r | |
920 | //\r | |
921 | // SectorCount is used to record the number of sectors to be read\r | |
922 | //\r | |
923 | SectorCount = 256;\r | |
924 | } else {\r | |
925 | \r | |
926 | SectorCount8 = (UINT8) BlocksRemaining;\r | |
927 | SectorCount = (UINT16) BlocksRemaining;\r | |
928 | }\r | |
929 | \r | |
930 | //\r | |
931 | // ByteCount is the number of bytes that will be read\r | |
932 | //\r | |
933 | ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r | |
934 | \r | |
935 | //\r | |
936 | // call AtaPioDataIn() to send Read Sector Command and receive data read\r | |
937 | //\r | |
938 | Status = AtaPioDataIn (\r | |
939 | IdeDev,\r | |
940 | Buffer,\r | |
941 | (UINT32) ByteCount,\r | |
942 | AtaCommand,\r | |
943 | Lba3,\r | |
944 | SectorCount8,\r | |
945 | Lba0,\r | |
946 | Lba1,\r | |
947 | Lba2\r | |
948 | );\r | |
949 | if (EFI_ERROR (Status)) {\r | |
950 | return Status;\r | |
951 | }\r | |
952 | \r | |
953 | Lba32 += SectorCount;\r | |
954 | Buffer = ((UINT8 *) Buffer + ByteCount);\r | |
955 | BlocksRemaining -= SectorCount;\r | |
956 | }\r | |
957 | \r | |
958 | return Status;\r | |
959 | }\r | |
960 | \r | |
961 | /**\r | |
630d580d | 962 | This function is called by the AtaBlkIoWriteBlocks() to perform writing onto \r |
963 | media in block unit.\r | |
964 | \r | |
965 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record\r | |
966 | all the information of the IDE device.\r | |
967 | @param BufferData A pointer to the source buffer for the data.\r | |
968 | @param Lba The starting logical block address to write onto the device media.\r | |
969 | @param NumberOfBlocks The number of transfer data blocks.\r | |
970 | \r | |
971 | @return status is fully dependent on the return status of AtaPioDataIn() function.\r | |
ead42efc | 972 | \r |
973 | **/\r | |
974 | EFI_STATUS\r | |
975 | AtaWriteSectors (\r | |
976 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
977 | IN VOID *BufferData,\r | |
978 | IN EFI_LBA Lba,\r | |
979 | IN UINTN NumberOfBlocks\r | |
980 | )\r | |
981 | {\r | |
982 | EFI_STATUS Status;\r | |
983 | UINTN BlocksRemaining;\r | |
984 | UINT32 Lba32;\r | |
985 | UINT8 Lba0;\r | |
986 | UINT8 Lba1;\r | |
987 | UINT8 Lba2;\r | |
988 | UINT8 Lba3;\r | |
989 | UINT8 AtaCommand;\r | |
990 | UINT8 SectorCount8;\r | |
991 | UINT16 SectorCount;\r | |
992 | UINTN ByteCount;\r | |
993 | VOID *Buffer;\r | |
994 | \r | |
995 | Buffer = BufferData;\r | |
996 | \r | |
997 | //\r | |
998 | // Using Write Sector(s) command (opcode=0x30) with PIO DATA OUT protocol\r | |
999 | //\r | |
1e23bd8d | 1000 | AtaCommand = ATA_CMD_WRITE_SECTORS;\r |
ead42efc | 1001 | \r |
1002 | BlocksRemaining = NumberOfBlocks;\r | |
1003 | \r | |
1004 | Lba32 = (UINT32) Lba;\r | |
1005 | \r | |
1006 | Status = EFI_SUCCESS;\r | |
1007 | \r | |
1008 | while (BlocksRemaining > 0) {\r | |
1009 | \r | |
1010 | Lba0 = (UINT8) Lba32;\r | |
1011 | Lba1 = (UINT8) (Lba32 >> 8);\r | |
1012 | Lba2 = (UINT8) (Lba32 >> 16);\r | |
1013 | Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);\r | |
1014 | \r | |
1015 | if (BlocksRemaining >= 0x100) {\r | |
1016 | \r | |
1017 | //\r | |
1018 | // SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors\r | |
1019 | // to be written\r | |
1020 | //\r | |
1021 | SectorCount8 = 0x00;\r | |
1022 | //\r | |
1023 | // SectorCount is used to record the number of sectors to be written\r | |
1024 | //\r | |
1025 | SectorCount = 256;\r | |
1026 | } else {\r | |
1027 | \r | |
1028 | SectorCount8 = (UINT8) BlocksRemaining;\r | |
1029 | SectorCount = (UINT16) BlocksRemaining;\r | |
1030 | }\r | |
1031 | \r | |
1032 | ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r | |
1033 | \r | |
1034 | Status = AtaPioDataOut (\r | |
1035 | IdeDev,\r | |
1036 | Buffer,\r | |
1037 | (UINT32) ByteCount,\r | |
1038 | AtaCommand,\r | |
1039 | Lba3,\r | |
1040 | SectorCount8,\r | |
1041 | Lba0,\r | |
1042 | Lba1,\r | |
1043 | Lba2\r | |
1044 | );\r | |
1045 | if (EFI_ERROR (Status)) {\r | |
1046 | return Status;\r | |
1047 | }\r | |
1048 | \r | |
1049 | Lba32 += SectorCount;\r | |
1050 | Buffer = ((UINT8 *) Buffer + ByteCount);\r | |
1051 | BlocksRemaining -= SectorCount;\r | |
1052 | }\r | |
1053 | \r | |
1054 | return Status;\r | |
1055 | }\r | |
ead42efc | 1056 | /**\r |
630d580d | 1057 | This function is used to implement the Soft Reset on the specified device. But,\r |
1058 | the ATA Soft Reset mechanism is so strong a reset method that it will force \r | |
1059 | resetting on both devices connected to the same cable.\r | |
ead42efc | 1060 | \r |
1061 | It is called by IdeBlkIoReset(), a interface function of Block\r | |
1062 | I/O protocol.\r | |
1063 | \r | |
1064 | This function can also be used by the ATAPI device to perform reset when\r | |
1065 | ATAPI Reset command is failed.\r | |
1066 | \r | |
630d580d | 1067 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r |
1068 | all the information of the IDE device.\r | |
ead42efc | 1069 | @retval EFI_SUCCESS Soft reset completes successfully.\r |
1070 | @retval EFI_DEVICE_ERROR Any step during the reset process is failed.\r | |
1071 | \r | |
630d580d | 1072 | @note The registers initial values after ATA soft reset are different\r |
1073 | to the ATA device and ATAPI device.\r | |
ead42efc | 1074 | **/\r |
1075 | EFI_STATUS\r | |
1076 | AtaSoftReset (\r | |
1077 | IN IDE_BLK_IO_DEV *IdeDev\r | |
1078 | )\r | |
1079 | {\r | |
1080 | \r | |
1081 | UINT8 DeviceControl;\r | |
1082 | \r | |
1083 | DeviceControl = 0;\r | |
1084 | //\r | |
1085 | // set SRST bit to initiate soft reset\r | |
1086 | //\r | |
1e23bd8d | 1087 | DeviceControl |= ATA_CTLREG_SRST;\r |
ead42efc | 1088 | \r |
1089 | //\r | |
1090 | // disable Interrupt\r | |
1091 | //\r | |
1e23bd8d | 1092 | DeviceControl |= BIT1;\r |
ead42efc | 1093 | \r |
1094 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r | |
1095 | \r | |
1096 | //\r | |
1097 | // SRST should assert for at least 5 us, we use 10 us for\r | |
1098 | // better compatibility\r | |
1099 | //\r | |
1100 | gBS->Stall (10);\r | |
1101 | \r | |
1102 | //\r | |
1103 | // Enable interrupt to support UDMA, and clear SRST bit\r | |
1104 | //\r | |
1105 | DeviceControl = 0;\r | |
1106 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r | |
1107 | \r | |
1108 | //\r | |
1109 | // Wait for at least 2 ms to check BSY status, we use 10 ms\r | |
1110 | // for better compatibility\r | |
1111 | //\r | |
1112 | gBS->Stall(10000);\r | |
1113 | //\r | |
1114 | // slave device needs at most 31s to clear BSY\r | |
1115 | //\r | |
1116 | if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) {\r | |
1117 | return EFI_DEVICE_ERROR;\r | |
1118 | }\r | |
1119 | \r | |
1120 | return EFI_SUCCESS;\r | |
1121 | }\r | |
ead42efc | 1122 | /**\r |
630d580d | 1123 | This function is used to send out ATA commands conforms to the PIO Data In \r |
1124 | Protocol, supporting ATA/ATAPI-6 standard\r | |
ead42efc | 1125 | \r |
630d580d | 1126 | Comparing with ATA-3 data in protocol, we have two differents here:\r |
1127 | 1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r | |
1128 | wait will frequently fail... cause writing function return error)\r | |
ead42efc | 1129 | \r |
630d580d | 1130 | 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r |
1131 | slow down writing performance by 100 times!)\r | |
ead42efc | 1132 | \r |
630d580d | 1133 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
1134 | to record all the information of the IDE device.\r | |
1135 | @param Buffer buffer contained data transferred from device to host.\r | |
1136 | @param ByteCount data size in byte unit of the buffer.\r | |
1137 | @param AtaCommand value of the Command Register\r | |
1138 | @param StartLba the start LBA of this transaction\r | |
1139 | @param SectorCount the count of sectors to be transfered\r | |
ead42efc | 1140 | \r |
630d580d | 1141 | @retval EFI_SUCCESS send out the ATA command and device send required data successfully.\r |
1142 | @retval EFI_DEVICE_ERROR command sent failed.\r | |
ead42efc | 1143 | \r |
1144 | **/\r | |
1145 | EFI_STATUS\r | |
630d580d | 1146 | AtaPioDataInExt (\r |
1147 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
1148 | IN OUT VOID *Buffer,\r | |
1149 | IN UINT32 ByteCount,\r | |
1150 | IN UINT8 AtaCommand,\r | |
1151 | IN EFI_LBA StartLba,\r | |
1152 | IN UINT16 SectorCount\r | |
ead42efc | 1153 | )\r |
1154 | {\r | |
630d580d | 1155 | UINT8 DevSel;\r |
1156 | UINT8 SectorCount8;\r | |
1157 | UINT8 LbaLow;\r | |
1158 | UINT8 LbaMid;\r | |
1159 | UINT8 LbaHigh;\r | |
1160 | UINTN WordCount;\r | |
1161 | UINTN Increment;\r | |
1162 | UINT16 *Buffer16;\r | |
1163 | EFI_STATUS Status;\r | |
ead42efc | 1164 | \r |
630d580d | 1165 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r |
1166 | if (EFI_ERROR (Status)) {\r | |
1167 | return EFI_DEVICE_ERROR;\r | |
ead42efc | 1168 | }\r |
1169 | \r | |
630d580d | 1170 | //\r |
1171 | // Select device, set bit6 as 1 to indicate LBA mode is used\r | |
1172 | //\r | |
1173 | DevSel = (UINT8) (IdeDev->Device << 4);\r | |
1174 | DevSel |= 0x40;\r | |
1175 | IDEWritePortB (\r | |
1176 | IdeDev->PciIo,\r | |
1177 | IdeDev->IoPort->Head,\r | |
1178 | DevSel\r | |
1179 | );\r | |
1180 | \r | |
1181 | //\r | |
1182 | // Wait for DRDY singnal asserting. ATAPI device needn't wait\r | |
1183 | //\r | |
1184 | if ( (IdeDev->Type == IdeHardDisk) ||\r | |
1185 | (IdeDev->Type == Ide48bitAddressingHardDisk)) {\r | |
1186 | \r | |
1187 | Status = DRDYReady (IdeDev, ATATIMEOUT);\r | |
1188 | if (EFI_ERROR (Status)) {\r | |
1189 | return EFI_DEVICE_ERROR;\r | |
1190 | }\r | |
ead42efc | 1191 | }\r |
1192 | \r | |
630d580d | 1193 | //\r |
1194 | // Fill feature register if needed\r | |
1195 | //\r | |
1196 | if (AtaCommand == ATA_CMD_SET_FEATURES) {\r | |
1197 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r | |
1198 | }\r | |
ead42efc | 1199 | \r |
1200 | //\r | |
630d580d | 1201 | // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r |
ead42efc | 1202 | //\r |
630d580d | 1203 | SectorCount8 = (UINT8) (SectorCount >> 8);\r |
1204 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r | |
ead42efc | 1205 | \r |
630d580d | 1206 | SectorCount8 = (UINT8) SectorCount;\r |
1207 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r | |
ead42efc | 1208 | \r |
630d580d | 1209 | //\r |
1210 | // Fill the start LBA registers, which are also two-byte FIFO\r | |
1211 | //\r | |
1212 | LbaLow = (UINT8) RShiftU64 (StartLba, 24);\r | |
1213 | LbaMid = (UINT8) RShiftU64 (StartLba, 32);\r | |
1214 | LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r | |
1215 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r | |
1216 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r | |
1217 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r | |
ead42efc | 1218 | \r |
630d580d | 1219 | LbaLow = (UINT8) StartLba;\r |
1220 | LbaMid = (UINT8) RShiftU64 (StartLba, 8);\r | |
1221 | LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r | |
1222 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r | |
1223 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r | |
1224 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r | |
ead42efc | 1225 | \r |
630d580d | 1226 | //\r |
1227 | // Send command via Command Register, invoking the processing of this command\r | |
1228 | //\r | |
1229 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r | |
ead42efc | 1230 | \r |
630d580d | 1231 | Buffer16 = (UINT16 *) Buffer;\r |
ead42efc | 1232 | \r |
630d580d | 1233 | //\r |
1234 | // According to PIO data in protocol, host can perform a series of reads to\r | |
1235 | // the data register after each time device set DRQ ready;\r | |
1236 | //\r | |
ead42efc | 1237 | \r |
630d580d | 1238 | //\r |
1239 | // 256 words\r | |
1240 | //\r | |
1241 | Increment = 256;\r | |
ead42efc | 1242 | \r |
630d580d | 1243 | //\r |
1244 | // used to record bytes of currently transfered data\r | |
1245 | //\r | |
1246 | WordCount = 0;\r | |
1247 | \r | |
1248 | while (WordCount < ByteCount / 2) {\r | |
ead42efc | 1249 | //\r |
630d580d | 1250 | // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r |
ead42efc | 1251 | //\r |
630d580d | 1252 | Status = DRQReady2 (IdeDev, ATATIMEOUT);\r |
1253 | if (EFI_ERROR (Status)) {\r | |
1254 | return EFI_DEVICE_ERROR;\r | |
ead42efc | 1255 | }\r |
630d580d | 1256 | \r |
1257 | Status = CheckErrorStatus (IdeDev);\r | |
1258 | if (EFI_ERROR (Status)) {\r | |
1259 | return EFI_DEVICE_ERROR;\r | |
1260 | }\r | |
1261 | \r | |
ead42efc | 1262 | //\r |
630d580d | 1263 | // Get the byte count for one series of read\r |
ead42efc | 1264 | //\r |
630d580d | 1265 | if ((WordCount + Increment) > ByteCount / 2) {\r |
1266 | Increment = ByteCount / 2 - WordCount;\r | |
ead42efc | 1267 | }\r |
ead42efc | 1268 | \r |
630d580d | 1269 | IDEReadPortWMultiple (\r |
1270 | IdeDev->PciIo,\r | |
1271 | IdeDev->IoPort->Data,\r | |
1272 | Increment,\r | |
1273 | Buffer16\r | |
1274 | );\r | |
ead42efc | 1275 | \r |
630d580d | 1276 | WordCount += Increment;\r |
1277 | Buffer16 += Increment;\r | |
ead42efc | 1278 | \r |
630d580d | 1279 | }\r |
ead42efc | 1280 | \r |
630d580d | 1281 | return CheckErrorStatus (IdeDev);\r |
1282 | }\r | |
ead42efc | 1283 | /**\r |
cd57e888 | 1284 | Send ATA Ext command into device with NON_DATA protocol.\r |
ead42efc | 1285 | \r |
630d580d | 1286 | @param IdeDev Standard IDE device private data structure\r |
1287 | @param AtaCommand The ATA command to be sent\r | |
1288 | @param Device The value in Device register\r | |
1289 | @param Feature The value in Feature register\r | |
1290 | @param SectorCount The value in SectorCount register\r | |
1291 | @param LbaAddress The LBA address in 48-bit mode\r | |
ead42efc | 1292 | \r |
630d580d | 1293 | @retval EFI_SUCCESS Reading succeed\r |
1294 | @retval EFI_DEVICE_ERROR Error executing commands on this device.\r | |
ead42efc | 1295 | \r |
1296 | **/\r | |
1297 | EFI_STATUS\r | |
630d580d | 1298 | AtaCommandIssueExt (\r |
1299 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
1300 | IN UINT8 AtaCommand,\r | |
1301 | IN UINT8 Device,\r | |
1302 | IN UINT16 Feature,\r | |
1303 | IN UINT16 SectorCount,\r | |
1304 | IN EFI_LBA LbaAddress\r | |
ead42efc | 1305 | )\r |
1306 | {\r | |
630d580d | 1307 | EFI_STATUS Status;\r |
1308 | UINT8 SectorCount8;\r | |
1309 | UINT8 Feature8;\r | |
1310 | UINT8 LbaLow;\r | |
1311 | UINT8 LbaMid;\r | |
1312 | UINT8 LbaHigh;\r | |
ead42efc | 1313 | \r |
630d580d | 1314 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r |
1315 | if (EFI_ERROR (Status)) {\r | |
1316 | return EFI_DEVICE_ERROR;\r | |
ead42efc | 1317 | }\r |
1318 | \r | |
630d580d | 1319 | //\r |
1320 | // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r | |
1321 | //\r | |
1322 | IDEWritePortB (\r | |
1323 | IdeDev->PciIo,\r | |
1324 | IdeDev->IoPort->Head,\r | |
1325 | (UINT8) ((IdeDev->Device << 4) | 0xe0)\r | |
1326 | );\r | |
1327 | \r | |
1328 | //\r | |
1329 | // ATA commands for ATA device must be issued when DRDY is set\r | |
1330 | //\r | |
1331 | Status = DRDYReady (IdeDev, ATATIMEOUT);\r | |
1332 | if (EFI_ERROR (Status)) {\r | |
1333 | return EFI_DEVICE_ERROR;\r | |
ead42efc | 1334 | }\r |
1335 | \r | |
630d580d | 1336 | //\r |
1337 | // Pass parameter into device register block\r | |
1338 | //\r | |
1339 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r | |
ead42efc | 1340 | \r |
1341 | //\r | |
630d580d | 1342 | // Fill the feature register, which is a two-byte FIFO. Need write twice.\r |
ead42efc | 1343 | //\r |
630d580d | 1344 | Feature8 = (UINT8) (Feature >> 8);\r |
1345 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r | |
ead42efc | 1346 | \r |
630d580d | 1347 | Feature8 = (UINT8) Feature;\r |
1348 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r | |
ead42efc | 1349 | \r |
630d580d | 1350 | //\r |
1351 | // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r | |
1352 | //\r | |
1353 | SectorCount8 = (UINT8) (SectorCount >> 8);\r | |
1354 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r | |
ead42efc | 1355 | \r |
630d580d | 1356 | SectorCount8 = (UINT8) SectorCount;\r |
1357 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r | |
ead42efc | 1358 | \r |
630d580d | 1359 | //\r |
1360 | // Fill the start LBA registers, which are also two-byte FIFO\r | |
1361 | //\r | |
1362 | LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r | |
1363 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r | |
1364 | LbaLow = (UINT8) LbaAddress;\r | |
1365 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r | |
ead42efc | 1366 | \r |
630d580d | 1367 | LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r |
1368 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r | |
1369 | LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r | |
1370 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r | |
ead42efc | 1371 | \r |
630d580d | 1372 | LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r |
1373 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r | |
1374 | LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r | |
1375 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r | |
ead42efc | 1376 | \r |
630d580d | 1377 | //\r |
1378 | // Work around for Segate 160G disk writing\r | |
1379 | //\r | |
1380 | gBS->Stall (1800);\r | |
1381 | \r | |
1382 | //\r | |
1383 | // Send command via Command Register\r | |
1384 | //\r | |
1385 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r | |
1386 | \r | |
1387 | //\r | |
1388 | // Stall at least 400ns\r | |
1389 | //\r | |
1390 | gBS->Stall (100);\r | |
ead42efc | 1391 | \r |
1392 | return EFI_SUCCESS;\r | |
1393 | }\r | |
ead42efc | 1394 | /**\r |
630d580d | 1395 | Send ATA Ext command into device with NON_DATA protocol\r |
ead42efc | 1396 | \r |
630d580d | 1397 | @param IdeDev Standard IDE device private data structure\r |
1398 | @param AtaCommand The ATA command to be sent\r | |
1399 | @param Device The value in Device register\r | |
1400 | @param Feature The value in Feature register\r | |
1401 | @param SectorCount The value in SectorCount register\r | |
1402 | @param LbaAddress The LBA address in 48-bit mode\r | |
ead42efc | 1403 | \r |
630d580d | 1404 | @retval EFI_SUCCESS Reading succeed\r |
1405 | @retval EFI_DEVICE_ERROR Error executing commands on this device.\r | |
ead42efc | 1406 | \r |
1407 | **/\r | |
1408 | EFI_STATUS\r | |
630d580d | 1409 | AtaCommandIssue (\r |
ead42efc | 1410 | IN IDE_BLK_IO_DEV *IdeDev,\r |
630d580d | 1411 | IN UINT8 AtaCommand,\r |
1412 | IN UINT8 Device,\r | |
1413 | IN UINT16 Feature,\r | |
1414 | IN UINT16 SectorCount,\r | |
1415 | IN EFI_LBA LbaAddress\r | |
ead42efc | 1416 | )\r |
1417 | {\r | |
1418 | EFI_STATUS Status;\r | |
630d580d | 1419 | UINT8 SectorCount8;\r |
1420 | UINT8 Feature8;\r | |
1421 | UINT8 Lba0;\r | |
1422 | UINT8 Lba1;\r | |
1423 | UINT8 Lba2;\r | |
1424 | UINT8 Lba3;\r | |
1425 | \r | |
1426 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r | |
1427 | if (EFI_ERROR (Status)) {\r | |
1428 | return EFI_DEVICE_ERROR;\r | |
1429 | }\r | |
ead42efc | 1430 | \r |
1431 | //\r | |
630d580d | 1432 | // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r |
ead42efc | 1433 | //\r |
630d580d | 1434 | IDEWritePortB (\r |
1435 | IdeDev->PciIo,\r | |
1436 | IdeDev->IoPort->Head,\r | |
1437 | (UINT8) ((IdeDev->Device << 4) | 0xe0)\r | |
1438 | );\r | |
ead42efc | 1439 | \r |
630d580d | 1440 | //\r |
1441 | // ATA commands for ATA device must be issued when DRDY is set\r | |
1442 | //\r | |
1443 | Status = DRDYReady (IdeDev, ATATIMEOUT);\r | |
1444 | if (EFI_ERROR (Status)) {\r | |
1445 | return EFI_DEVICE_ERROR;\r | |
1446 | }\r | |
ead42efc | 1447 | \r |
630d580d | 1448 | Lba0 = (UINT8) LbaAddress;\r |
1449 | Lba1 = (UINT8) RShiftU64 (LbaAddress, 8);\r | |
1450 | Lba2 = (UINT8) RShiftU64 (LbaAddress, 16);\r | |
1451 | Lba3 = (UINT8) RShiftU64 (LbaAddress, 24);\r | |
1452 | Device = (UINT8) (Device | Lba3);\r | |
ead42efc | 1453 | \r |
630d580d | 1454 | //\r |
1455 | // Pass parameter into device register block\r | |
1456 | //\r | |
1457 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r | |
ead42efc | 1458 | \r |
630d580d | 1459 | //\r |
1460 | // Fill the feature register, which is a two-byte FIFO. Need write twice.\r | |
1461 | //\r | |
1462 | Feature8 = (UINT8) Feature;\r | |
1463 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r | |
ead42efc | 1464 | \r |
630d580d | 1465 | //\r |
1466 | // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r | |
1467 | //\r | |
1468 | SectorCount8 = (UINT8) SectorCount;\r | |
1469 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r | |
ead42efc | 1470 | \r |
630d580d | 1471 | //\r |
1472 | // Fill the start LBA registers, which are also two-byte FIFO\r | |
1473 | //\r | |
ead42efc | 1474 | \r |
630d580d | 1475 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);\r |
1476 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);\r | |
1477 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);\r | |
ead42efc | 1478 | \r |
630d580d | 1479 | //\r |
1480 | // Send command via Command Register\r | |
1481 | //\r | |
1482 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r | |
ead42efc | 1483 | \r |
630d580d | 1484 | //\r |
1485 | // Stall at least 400ns\r | |
1486 | //\r | |
1487 | gBS->Stall (100);\r | |
ead42efc | 1488 | \r |
630d580d | 1489 | return EFI_SUCCESS;\r |
1490 | }\r | |
1491 | /**\r | |
1492 | Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r | |
ead42efc | 1493 | \r |
630d580d | 1494 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
1495 | to record all the information of the IDE device.\r | |
1496 | @param DataBuffer A pointer to the source buffer for the data.\r | |
1497 | @param StartLba The starting logical block address to write to\r | |
1498 | on the device media.\r | |
1499 | @param NumberOfBlocks The number of transfer data blocks.\r | |
1500 | @param UdmaOp The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r | |
1501 | AtaUdmaWriteOp, AtaUdmaWriteExOp\r | |
ead42efc | 1502 | \r |
630d580d | 1503 | @retval EFI_SUCCESS the operation is successful.\r |
1504 | @retval EFI_OUT_OF_RESOURCES Build PRD table failed\r | |
1505 | @retval EFI_UNSUPPORTED Unknown channel or operations command\r | |
1506 | @retval EFI_DEVICE_ERROR Ata command execute failed\r | |
ead42efc | 1507 | \r |
1508 | **/\r | |
1509 | EFI_STATUS\r | |
630d580d | 1510 | DoAtaUdma (\r |
1511 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
1512 | IN VOID *DataBuffer,\r | |
1513 | IN EFI_LBA StartLba,\r | |
1514 | IN UINTN NumberOfBlocks,\r | |
1515 | IN ATA_UDMA_OPERATION UdmaOp\r | |
ead42efc | 1516 | )\r |
1517 | {\r | |
630d580d | 1518 | IDE_DMA_PRD *PrdAddr;\r |
1519 | IDE_DMA_PRD *UsedPrdAddr;\r | |
1520 | IDE_DMA_PRD *TempPrdAddr;\r | |
1521 | UINT8 RegisterValue;\r | |
1522 | UINT8 Device;\r | |
1523 | UINT64 IoPortForBmic;\r | |
1524 | UINT64 IoPortForBmis;\r | |
1525 | UINT64 IoPortForBmid;\r | |
1526 | EFI_STATUS Status;\r | |
1527 | UINTN PrdTableNum;\r | |
1528 | UINTN ByteCount;\r | |
1529 | UINTN ByteAvailable;\r | |
1530 | UINT8 *PrdBuffer;\r | |
1531 | UINTN RemainBlockNum;\r | |
1532 | UINT8 DeviceControl;\r | |
1533 | UINT32 Count;\r | |
1534 | UINTN PageCount;\r | |
1535 | VOID *Map;\r | |
1536 | VOID *MemPage;\r | |
1537 | EFI_PHYSICAL_ADDRESS DeviceAddress;\r | |
1538 | UINTN MaxDmaCommandSectors;\r | |
1539 | EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;\r | |
1540 | UINT8 AtaCommand;\r | |
1541 | \r | |
1542 | switch (UdmaOp) {\r | |
1543 | case AtaUdmaReadOp:\r | |
1544 | MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;\r | |
1545 | PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;\r | |
1546 | AtaCommand = ATA_CMD_READ_DMA;\r | |
1547 | break;\r | |
1548 | case AtaUdmaReadExtOp:\r | |
1549 | MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;\r | |
1550 | PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;\r | |
1551 | AtaCommand = ATA_CMD_READ_DMA_EXT;\r | |
1552 | break;\r | |
1553 | case AtaUdmaWriteOp:\r | |
1554 | MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;\r | |
1555 | PciIoProtocolOp = EfiPciIoOperationBusMasterRead;\r | |
1556 | AtaCommand = ATA_CMD_WRITE_DMA;\r | |
1557 | break;\r | |
1558 | case AtaUdmaWriteExtOp:\r | |
1559 | MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;\r | |
1560 | PciIoProtocolOp = EfiPciIoOperationBusMasterRead;\r | |
1561 | AtaCommand = ATA_CMD_WRITE_DMA_EXT;\r | |
1562 | break;\r | |
1563 | default:\r | |
1564 | return EFI_UNSUPPORTED;\r | |
1565 | break;\r | |
1566 | }\r | |
ead42efc | 1567 | \r |
1568 | //\r | |
630d580d | 1569 | // Select device\r |
ead42efc | 1570 | //\r |
630d580d | 1571 | Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r |
1572 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r | |
ead42efc | 1573 | \r |
630d580d | 1574 | //\r |
1575 | // Enable interrupt to support UDMA\r | |
1576 | //\r | |
1577 | DeviceControl = 0;\r | |
1578 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r | |
ead42efc | 1579 | \r |
630d580d | 1580 | if (IdePrimary == IdeDev->Channel) {\r |
1581 | IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r | |
1582 | IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r | |
1583 | IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r | |
1584 | } else {\r | |
1585 | if (IdeSecondary == IdeDev->Channel) {\r | |
1586 | IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r | |
1587 | IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r | |
1588 | IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r | |
1589 | } else {\r | |
1590 | return EFI_UNSUPPORTED;\r | |
1591 | }\r | |
1592 | }\r | |
ead42efc | 1593 | \r |
630d580d | 1594 | //\r |
1595 | // Read BMIS register and clear ERROR and INTR bit\r | |
1596 | //\r | |
1597 | IdeDev->PciIo->Io.Read (\r | |
1598 | IdeDev->PciIo,\r | |
1599 | EfiPciIoWidthUint8,\r | |
1600 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1601 | IoPortForBmis,\r | |
1602 | 1,\r | |
1603 | &RegisterValue\r | |
1604 | );\r | |
1605 | \r | |
1606 | RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r | |
1607 | \r | |
1608 | IdeDev->PciIo->Io.Write (\r | |
1609 | IdeDev->PciIo,\r | |
1610 | EfiPciIoWidthUint8,\r | |
1611 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1612 | IoPortForBmis,\r | |
1613 | 1,\r | |
1614 | &RegisterValue\r | |
1615 | );\r | |
1616 | \r | |
1617 | Status = EFI_SUCCESS;\r | |
1618 | \r | |
1619 | RemainBlockNum = NumberOfBlocks;\r | |
1620 | while (RemainBlockNum > 0) {\r | |
1621 | \r | |
1622 | if (RemainBlockNum >= MaxDmaCommandSectors) {\r | |
ead42efc | 1623 | //\r |
630d580d | 1624 | // SectorCount is used to record the number of sectors to be read\r |
ead42efc | 1625 | // Max 65536 sectors can be transfered at a time.\r |
1626 | //\r | |
630d580d | 1627 | NumberOfBlocks = MaxDmaCommandSectors;\r |
1628 | RemainBlockNum -= MaxDmaCommandSectors;\r | |
ead42efc | 1629 | } else {\r |
630d580d | 1630 | NumberOfBlocks = (UINT16) RemainBlockNum;\r |
1631 | RemainBlockNum = 0;\r | |
ead42efc | 1632 | }\r |
1633 | \r | |
1634 | //\r | |
630d580d | 1635 | // Calculate the number of PRD table to make sure the memory region\r |
1636 | // not cross 64K boundary\r | |
ead42efc | 1637 | //\r |
630d580d | 1638 | ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r |
1639 | PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r | |
ead42efc | 1640 | \r |
1641 | //\r | |
630d580d | 1642 | // Build PRD table\r |
ead42efc | 1643 | //\r |
630d580d | 1644 | PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r |
1645 | Status = IdeDev->PciIo->AllocateBuffer (\r | |
1646 | IdeDev->PciIo,\r | |
1647 | AllocateAnyPages,\r | |
1648 | EfiBootServicesData,\r | |
1649 | PageCount,\r | |
1650 | &MemPage,\r | |
1651 | 0\r | |
1652 | );\r | |
ead42efc | 1653 | if (EFI_ERROR (Status)) {\r |
630d580d | 1654 | return EFI_OUT_OF_RESOURCES;\r |
ead42efc | 1655 | }\r |
630d580d | 1656 | ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r |
ead42efc | 1657 | \r |
630d580d | 1658 | PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r |
1659 | //\r | |
1660 | // To make sure PRD is allocated in one 64K page\r | |
1661 | //\r | |
1662 | if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r | |
1663 | UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r | |
1664 | } else {\r | |
1665 | if ((UINTN) PrdAddr & 0x03) {\r | |
1666 | UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r | |
1667 | } else {\r | |
1668 | UsedPrdAddr = PrdAddr;\r | |
1669 | }\r | |
1670 | }\r | |
ead42efc | 1671 | \r |
630d580d | 1672 | //\r |
1673 | // Build the PRD table\r | |
1674 | //\r | |
1675 | Status = IdeDev->PciIo->Map (\r | |
1676 | IdeDev->PciIo,\r | |
1677 | PciIoProtocolOp,\r | |
1678 | DataBuffer,\r | |
1679 | &ByteCount,\r | |
1680 | &DeviceAddress,\r | |
1681 | &Map\r | |
1682 | );\r | |
1683 | if (EFI_ERROR (Status)) {\r | |
1684 | IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r | |
1685 | return EFI_OUT_OF_RESOURCES;\r | |
1686 | }\r | |
1687 | PrdBuffer = (VOID *) ((UINTN) DeviceAddress);\r | |
1688 | TempPrdAddr = UsedPrdAddr;\r | |
1689 | while (TRUE) {\r | |
ead42efc | 1690 | \r |
630d580d | 1691 | ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r |
ead42efc | 1692 | \r |
630d580d | 1693 | if (ByteCount <= ByteAvailable) {\r |
1694 | TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r | |
1695 | TempPrdAddr->ByteCount = (UINT16) ByteCount;\r | |
1696 | TempPrdAddr->EndOfTable = 0x8000;\r | |
1697 | break;\r | |
1698 | }\r | |
ead42efc | 1699 | \r |
630d580d | 1700 | TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r |
1701 | TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r | |
ead42efc | 1702 | \r |
630d580d | 1703 | ByteCount -= ByteAvailable;\r |
1704 | PrdBuffer += ByteAvailable;\r | |
1705 | TempPrdAddr++;\r | |
1706 | }\r | |
ead42efc | 1707 | \r |
630d580d | 1708 | //\r |
1709 | // Set the base address to BMID register\r | |
1710 | //\r | |
1711 | IdeDev->PciIo->Io.Write (\r | |
1712 | IdeDev->PciIo,\r | |
1713 | EfiPciIoWidthUint32,\r | |
1714 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1715 | IoPortForBmid,\r | |
1716 | 1,\r | |
1717 | &UsedPrdAddr\r | |
1718 | );\r | |
ead42efc | 1719 | \r |
630d580d | 1720 | //\r |
1721 | // Set BMIC register to identify the operation direction\r | |
1722 | //\r | |
1723 | IdeDev->PciIo->Io.Read (\r | |
1724 | IdeDev->PciIo,\r | |
1725 | EfiPciIoWidthUint8,\r | |
1726 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1727 | IoPortForBmic,\r | |
1728 | 1,\r | |
1729 | &RegisterValue\r | |
1730 | );\r | |
ead42efc | 1731 | \r |
630d580d | 1732 | if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {\r |
1733 | RegisterValue |= BMIC_NREAD;\r | |
1734 | } else {\r | |
1735 | RegisterValue &= ~((UINT8) BMIC_NREAD);\r | |
1736 | }\r | |
ead42efc | 1737 | \r |
630d580d | 1738 | IdeDev->PciIo->Io.Write (\r |
1739 | IdeDev->PciIo,\r | |
1740 | EfiPciIoWidthUint8,\r | |
1741 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1742 | IoPortForBmic,\r | |
1743 | 1,\r | |
1744 | &RegisterValue\r | |
1745 | );\r | |
ead42efc | 1746 | \r |
630d580d | 1747 | if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {\r |
1748 | Status = AtaCommandIssueExt (\r | |
1749 | IdeDev,\r | |
1750 | AtaCommand,\r | |
1751 | Device,\r | |
1752 | 0,\r | |
1753 | (UINT16) NumberOfBlocks,\r | |
1754 | StartLba\r | |
1755 | );\r | |
1756 | } else {\r | |
1757 | Status = AtaCommandIssue (\r | |
1758 | IdeDev,\r | |
1759 | AtaCommand,\r | |
1760 | Device,\r | |
1761 | 0,\r | |
1762 | (UINT16) NumberOfBlocks,\r | |
1763 | StartLba\r | |
1764 | );\r | |
1765 | }\r | |
ead42efc | 1766 | \r |
ead42efc | 1767 | if (EFI_ERROR (Status)) {\r |
630d580d | 1768 | IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r |
1769 | IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r | |
ead42efc | 1770 | return EFI_DEVICE_ERROR;\r |
1771 | }\r | |
ead42efc | 1772 | \r |
630d580d | 1773 | //\r |
1774 | // Set START bit of BMIC register\r | |
1775 | //\r | |
1776 | IdeDev->PciIo->Io.Read (\r | |
1777 | IdeDev->PciIo,\r | |
1778 | EfiPciIoWidthUint8,\r | |
1779 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1780 | IoPortForBmic,\r | |
1781 | 1,\r | |
1782 | &RegisterValue\r | |
1783 | );\r | |
ead42efc | 1784 | \r |
630d580d | 1785 | RegisterValue |= BMIC_START;\r |
ead42efc | 1786 | \r |
630d580d | 1787 | IdeDev->PciIo->Io.Write (\r |
1788 | IdeDev->PciIo,\r | |
1789 | EfiPciIoWidthUint8,\r | |
1790 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1791 | IoPortForBmic,\r | |
1792 | 1,\r | |
1793 | &RegisterValue\r | |
1794 | );\r | |
ead42efc | 1795 | \r |
ead42efc | 1796 | //\r |
630d580d | 1797 | // Check the INTERRUPT and ERROR bit of BMIS\r |
1798 | // Max transfer number of sectors for one command is 65536(32Mbyte),\r | |
1799 | // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r | |
1800 | // So set the variable Count to 2000, for about 2 second timeout time.\r | |
ead42efc | 1801 | //\r |
630d580d | 1802 | Status = EFI_SUCCESS;\r |
1803 | Count = 2000;\r | |
1804 | while (TRUE) {\r | |
ead42efc | 1805 | \r |
630d580d | 1806 | IdeDev->PciIo->Io.Read (\r |
1807 | IdeDev->PciIo,\r | |
1808 | EfiPciIoWidthUint8,\r | |
1809 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1810 | IoPortForBmis,\r | |
1811 | 1,\r | |
1812 | &RegisterValue\r | |
1813 | );\r | |
1814 | if (((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) != 0) || (Count == 0)) {\r | |
1815 | if (((RegisterValue & BMIS_ERROR) != 0) || (Count == 0)) {\r | |
1816 | Status = EFI_DEVICE_ERROR;\r | |
1817 | break;\r | |
1818 | }\r | |
1819 | break;\r | |
1820 | }\r | |
1821 | \r | |
1822 | gBS->Stall (1000);\r | |
1823 | Count --;\r | |
ead42efc | 1824 | }\r |
1825 | \r | |
630d580d | 1826 | IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r |
1827 | IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r | |
ead42efc | 1828 | //\r |
630d580d | 1829 | // Read BMIS register and clear ERROR and INTR bit\r |
ead42efc | 1830 | //\r |
630d580d | 1831 | IdeDev->PciIo->Io.Read (\r |
1832 | IdeDev->PciIo,\r | |
1833 | EfiPciIoWidthUint8,\r | |
1834 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1835 | IoPortForBmis,\r | |
1836 | 1,\r | |
1837 | &RegisterValue\r | |
1838 | );\r | |
ead42efc | 1839 | \r |
630d580d | 1840 | RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r |
ead42efc | 1841 | \r |
630d580d | 1842 | IdeDev->PciIo->Io.Write (\r |
1843 | IdeDev->PciIo,\r | |
1844 | EfiPciIoWidthUint8,\r | |
1845 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1846 | IoPortForBmis,\r | |
1847 | 1,\r | |
1848 | &RegisterValue\r | |
1849 | );\r | |
1850 | //\r | |
1851 | // Read Status Register of IDE device to clear interrupt\r | |
1852 | //\r | |
1853 | RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r | |
1854 | //\r | |
1855 | // Clear START bit of BMIC register\r | |
1856 | //\r | |
1857 | IdeDev->PciIo->Io.Read (\r | |
1858 | IdeDev->PciIo,\r | |
1859 | EfiPciIoWidthUint8,\r | |
1860 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1861 | IoPortForBmic,\r | |
1862 | 1,\r | |
1863 | &RegisterValue\r | |
1864 | );\r | |
ead42efc | 1865 | \r |
630d580d | 1866 | RegisterValue &= ~((UINT8) BMIC_START);\r |
ead42efc | 1867 | \r |
630d580d | 1868 | IdeDev->PciIo->Io.Write (\r |
1869 | IdeDev->PciIo,\r | |
1870 | EfiPciIoWidthUint8,\r | |
1871 | EFI_PCI_IO_PASS_THROUGH_BAR,\r | |
1872 | IoPortForBmic,\r | |
1873 | 1,\r | |
1874 | &RegisterValue\r | |
1875 | );\r | |
ead42efc | 1876 | \r |
630d580d | 1877 | if ((RegisterValue & BMIS_ERROR) != 0) {\r |
1878 | return EFI_DEVICE_ERROR;\r | |
1879 | }\r | |
ead42efc | 1880 | \r |
630d580d | 1881 | if (EFI_ERROR (Status)) {\r |
1882 | break;\r | |
1883 | }\r | |
1884 | DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r | |
1885 | StartLba += NumberOfBlocks;\r | |
1886 | }\r | |
ead42efc | 1887 | \r |
630d580d | 1888 | //\r |
1889 | // Disable interrupt of Select device\r | |
1890 | //\r | |
1891 | IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);\r | |
1892 | DeviceControl |= ATA_CTLREG_IEN_L;\r | |
1893 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r | |
ead42efc | 1894 | \r |
630d580d | 1895 | return Status;\r |
1896 | }\r | |
ead42efc | 1897 | \r |
ead42efc | 1898 | \r |
630d580d | 1899 | /**\r |
1900 | This function is called by the AtaBlkIoReadBlocks() to perform reading from\r | |
1901 | media in block unit. The function has been enhanced to support >120GB access \r | |
1902 | and transfer at most 65536 blocks per command\r | |
ead42efc | 1903 | \r |
630d580d | 1904 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r |
1905 | all the information of the IDE device.\r | |
1906 | @param DataBuffer A pointer to the destination buffer for the data.\r | |
1907 | @param StartLba The starting logical block address to read from on the device media.\r | |
1908 | @param NumberOfBlocks The number of transfer data blocks.\r | |
ead42efc | 1909 | \r |
630d580d | 1910 | @return status depends on the function DoAtaUdma() returns.\r |
ead42efc | 1911 | **/\r |
1912 | EFI_STATUS\r | |
630d580d | 1913 | AtaUdmaReadExt (\r |
ead42efc | 1914 | IN IDE_BLK_IO_DEV *IdeDev,\r |
630d580d | 1915 | IN VOID *DataBuffer,\r |
ead42efc | 1916 | IN EFI_LBA StartLba,\r |
630d580d | 1917 | IN UINTN NumberOfBlocks\r |
ead42efc | 1918 | )\r |
1919 | {\r | |
630d580d | 1920 | return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);\r |
1921 | }\r | |
1922 | /**\r | |
1923 | This function is called by the AtaBlkIoReadBlocks() to perform\r | |
1924 | reading from media in block unit. The function has been enhanced to\r | |
1925 | support >120GB access and transfer at most 65536 blocks per command\r | |
ead42efc | 1926 | \r |
630d580d | 1927 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r |
1928 | all the information of the IDE device.\r | |
1929 | @param DataBuffer A pointer to the destination buffer for the data.\r | |
1930 | @param StartLba The starting logical block address to read from\r | |
1931 | on the device media.\r | |
1932 | @param NumberOfBlocks The number of transfer data blocks.\r | |
1933 | \r | |
1934 | @return status depends on the function DoAtaUdma() returns.\r | |
1935 | **/\r | |
1936 | EFI_STATUS\r | |
1937 | AtaUdmaRead (\r | |
1938 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
1939 | IN VOID *DataBuffer,\r | |
1940 | IN EFI_LBA StartLba,\r | |
1941 | IN UINTN NumberOfBlocks\r | |
1942 | )\r | |
1943 | {\r | |
1944 | return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);\r | |
1945 | }\r | |
ead42efc | 1946 | \r |
630d580d | 1947 | /**\r |
1948 | This function is called by the AtaBlkIoReadBlocks() to perform\r | |
1949 | reading from media in block unit. The function has been enhanced to\r | |
1950 | support >120GB access and transfer at most 65536 blocks per command\r | |
ead42efc | 1951 | \r |
630d580d | 1952 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r |
1953 | all the information of the IDE device.\r | |
1954 | @param DataBuffer A pointer to the destination buffer for the data.\r | |
1955 | @param StartLba The starting logical block address to read from on the device media.\r | |
1956 | @param NumberOfBlocks The number of transfer data blocks.\r | |
ead42efc | 1957 | \r |
630d580d | 1958 | @return status is fully dependent on the return status of AtaPioDataInExt() function.\r |
1959 | **/\r | |
1960 | EFI_STATUS\r | |
1961 | AtaReadSectorsExt (\r | |
1962 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
1963 | IN VOID *DataBuffer,\r | |
1964 | IN EFI_LBA StartLba,\r | |
1965 | IN UINTN NumberOfBlocks\r | |
1966 | )\r | |
1967 | {\r | |
1968 | EFI_STATUS Status;\r | |
1969 | UINTN BlocksRemaining;\r | |
1970 | EFI_LBA Lba64;\r | |
1971 | UINT8 AtaCommand;\r | |
1972 | UINT16 SectorCount;\r | |
1973 | UINT32 ByteCount;\r | |
1974 | VOID *Buffer;\r | |
ead42efc | 1975 | \r |
1976 | //\r | |
630d580d | 1977 | // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol\r |
ead42efc | 1978 | //\r |
630d580d | 1979 | AtaCommand = ATA_CMD_READ_SECTORS_EXT;\r |
1980 | Buffer = DataBuffer;\r | |
1981 | BlocksRemaining = NumberOfBlocks;\r | |
1982 | Lba64 = StartLba;\r | |
1983 | Status = EFI_SUCCESS;\r | |
ead42efc | 1984 | \r |
630d580d | 1985 | while (BlocksRemaining > 0) {\r |
ead42efc | 1986 | \r |
630d580d | 1987 | if (BlocksRemaining >= 0x10000) {\r |
1988 | //\r | |
1989 | // SectorCount is used to record the number of sectors to be read\r | |
1990 | // Max 65536 sectors can be transfered at a time.\r | |
1991 | //\r | |
1992 | SectorCount = 0xffff;\r | |
1993 | } else {\r | |
1994 | SectorCount = (UINT16) BlocksRemaining;\r | |
1995 | }\r | |
ead42efc | 1996 | \r |
ead42efc | 1997 | //\r |
630d580d | 1998 | // ByteCount is the number of bytes that will be read\r |
ead42efc | 1999 | //\r |
630d580d | 2000 | ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r |
ead42efc | 2001 | \r |
2002 | //\r | |
630d580d | 2003 | // call AtaPioDataInExt() to send Read Sector Command and receive data read\r |
ead42efc | 2004 | //\r |
630d580d | 2005 | Status = AtaPioDataInExt (\r |
2006 | IdeDev,\r | |
2007 | Buffer,\r | |
2008 | ByteCount,\r | |
2009 | AtaCommand,\r | |
2010 | Lba64,\r | |
2011 | SectorCount\r | |
2012 | );\r | |
2013 | if (EFI_ERROR (Status)) {\r | |
2014 | return Status;\r | |
ead42efc | 2015 | }\r |
2016 | \r | |
630d580d | 2017 | Lba64 += SectorCount;\r |
2018 | Buffer = ((UINT8 *) Buffer + ByteCount);\r | |
2019 | BlocksRemaining -= SectorCount;\r | |
ead42efc | 2020 | }\r |
ead42efc | 2021 | \r |
630d580d | 2022 | return Status;\r |
ead42efc | 2023 | }\r |
630d580d | 2024 | /**\r |
2025 | This function is the ATA implementation for ReadBlocks in the\r | |
2026 | Block I/O Protocol interface.\r | |
ead42efc | 2027 | \r |
630d580d | 2028 | @param IdeBlkIoDevice Indicates the calling context.\r |
2029 | @param MediaId The media id that the read request is for.\r | |
cd57e888 | 2030 | @param Lba The starting logical block address to read from on the device.\r |
630d580d | 2031 | @param BufferSize The size of the Buffer in bytes. This must be a multiple\r |
2032 | of the intrinsic block size of the device.\r | |
ead42efc | 2033 | \r |
630d580d | 2034 | @param Buffer A pointer to the destination buffer for the data. The caller\r |
2035 | is responsible for either having implicit or explicit ownership\r | |
2036 | of the memory that data is read into.\r | |
2037 | \r | |
2038 | @retval EFI_SUCCESS Read Blocks successfully.\r | |
2039 | @retval EFI_DEVICE_ERROR Read Blocks failed.\r | |
2040 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
2041 | @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.\r | |
2042 | @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r | |
2043 | intrinsic block size of the device.\r | |
2044 | @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r | |
2045 | or the data buffer is not valid.\r | |
ead42efc | 2046 | \r |
630d580d | 2047 | @note If Read Block error because of device error, this function will call\r |
2048 | AtaSoftReset() function to reset device.\r | |
ead42efc | 2049 | \r |
2050 | **/\r | |
630d580d | 2051 | EFI_STATUS\r |
2052 | AtaBlkIoReadBlocks (\r | |
2053 | IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r | |
2054 | IN UINT32 MediaId,\r | |
cd57e888 | 2055 | IN EFI_LBA Lba,\r |
630d580d | 2056 | IN UINTN BufferSize,\r |
2057 | OUT VOID *Buffer\r | |
ead42efc | 2058 | )\r |
2059 | {\r | |
630d580d | 2060 | EFI_BLOCK_IO_MEDIA *Media;\r |
2061 | UINTN BlockSize;\r | |
2062 | UINTN NumberOfBlocks;\r | |
2063 | EFI_STATUS Status;\r | |
2064 | \r | |
2065 | if (Buffer == NULL) {\r | |
2066 | return EFI_INVALID_PARAMETER;\r | |
2067 | }\r | |
2068 | \r | |
2069 | if (BufferSize == 0) {\r | |
2070 | return EFI_SUCCESS;\r | |
2071 | }\r | |
2072 | \r | |
2073 | Status = EFI_SUCCESS;\r | |
ead42efc | 2074 | \r |
2075 | //\r | |
630d580d | 2076 | // Get the intrinsic block size\r |
ead42efc | 2077 | //\r |
630d580d | 2078 | Media = IdeBlkIoDevice->BlkIo.Media;\r |
2079 | BlockSize = Media->BlockSize;\r | |
2080 | \r | |
2081 | NumberOfBlocks = BufferSize / BlockSize;\r | |
2082 | \r | |
2083 | if (MediaId != Media->MediaId) {\r | |
2084 | return EFI_MEDIA_CHANGED;\r | |
ead42efc | 2085 | }\r |
2086 | \r | |
630d580d | 2087 | if (BufferSize % BlockSize != 0) {\r |
2088 | return EFI_BAD_BUFFER_SIZE;\r | |
2089 | }\r | |
ead42efc | 2090 | \r |
630d580d | 2091 | if (!(Media->MediaPresent)) {\r |
2092 | return EFI_NO_MEDIA;\r | |
2093 | }\r | |
2094 | \r | |
cd57e888 | 2095 | if (Lba > Media->LastBlock) {\r |
630d580d | 2096 | return EFI_INVALID_PARAMETER;\r |
2097 | }\r | |
2098 | \r | |
cd57e888 | 2099 | if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r |
630d580d | 2100 | return EFI_INVALID_PARAMETER;\r |
2101 | }\r | |
2102 | \r | |
2103 | if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r | |
2104 | return EFI_INVALID_PARAMETER;\r | |
2105 | }\r | |
2106 | \r | |
2107 | Status = EFI_SUCCESS;\r | |
2108 | if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r | |
ead42efc | 2109 | //\r |
630d580d | 2110 | // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism\r |
ead42efc | 2111 | //\r |
630d580d | 2112 | if (IdeBlkIoDevice->UdmaMode.Valid) {\r |
cd57e888 | 2113 | Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r |
630d580d | 2114 | } else {\r |
cd57e888 | 2115 | Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r |
ead42efc | 2116 | }\r |
630d580d | 2117 | } else {\r |
ead42efc | 2118 | //\r |
630d580d | 2119 | // For ATA-3 compatible device, use ATA-3 read block mechanism\r |
ead42efc | 2120 | //\r |
630d580d | 2121 | if (IdeBlkIoDevice->UdmaMode.Valid) {\r |
cd57e888 | 2122 | Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r |
ead42efc | 2123 | } else {\r |
cd57e888 | 2124 | Status = AtaReadSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r |
ead42efc | 2125 | }\r |
630d580d | 2126 | }\r |
ead42efc | 2127 | \r |
630d580d | 2128 | if (EFI_ERROR (Status)) {\r |
2129 | AtaSoftReset (IdeBlkIoDevice);\r | |
2130 | return EFI_DEVICE_ERROR;\r | |
ead42efc | 2131 | }\r |
2132 | \r | |
630d580d | 2133 | return EFI_SUCCESS;\r |
ead42efc | 2134 | \r |
630d580d | 2135 | }\r |
75eccf9d | 2136 | /**\r |
630d580d | 2137 | This function is used to send out ATA commands conforms to the\r |
2138 | PIO Data Out Protocol, supporting ATA/ATAPI-6 standard\r | |
75eccf9d | 2139 | \r |
630d580d | 2140 | Comparing with ATA-3 data out protocol, we have two differents here:<BR>\r |
2141 | 1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r | |
2142 | wait will frequently fail... cause writing function return error)\r | |
2143 | \r | |
2144 | 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r | |
2145 | slow down writing performance by 100 times!)\r | |
2146 | \r | |
2147 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r | |
2148 | to record all the information of the IDE device.\r | |
2149 | @param Buffer buffer contained data transferred from host to device.\r | |
2150 | @param ByteCount data size in byte unit of the buffer.\r | |
2151 | @param AtaCommand value of the Command Register\r | |
2152 | @param StartLba the start LBA of this transaction\r | |
2153 | @param SectorCount the count of sectors to be transfered\r | |
2154 | \r | |
2155 | @retval EFI_SUCCESS send out the ATA command and device receive required\r | |
2156 | data successfully.\r | |
2157 | @retval EFI_DEVICE_ERROR command sent failed.\r | |
75eccf9d | 2158 | \r |
75eccf9d | 2159 | **/\r |
2160 | EFI_STATUS\r | |
630d580d | 2161 | AtaPioDataOutExt (\r |
2162 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
2163 | IN VOID *Buffer,\r | |
2164 | IN UINT32 ByteCount,\r | |
2165 | IN UINT8 AtaCommand,\r | |
2166 | IN EFI_LBA StartLba,\r | |
2167 | IN UINT16 SectorCount\r | |
75eccf9d | 2168 | )\r |
2169 | {\r | |
630d580d | 2170 | UINT8 DevSel;\r |
2171 | UINT8 SectorCount8;\r | |
2172 | UINT8 LbaLow;\r | |
2173 | UINT8 LbaMid;\r | |
2174 | UINT8 LbaHigh;\r | |
2175 | UINTN WordCount;\r | |
2176 | UINTN Increment;\r | |
2177 | UINT16 *Buffer16;\r | |
2178 | EFI_STATUS Status;\r | |
2179 | \r | |
2180 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r | |
2181 | if (EFI_ERROR (Status)) {\r | |
2182 | return EFI_DEVICE_ERROR;\r | |
2183 | }\r | |
75eccf9d | 2184 | \r |
75eccf9d | 2185 | //\r |
630d580d | 2186 | // Select device. Set bit6 as 1 to indicate LBA mode is used\r |
75eccf9d | 2187 | //\r |
630d580d | 2188 | DevSel = (UINT8) (IdeDev->Device << 4);\r |
2189 | DevSel |= 0x40;\r | |
2190 | IDEWritePortB (\r | |
2191 | IdeDev->PciIo,\r | |
2192 | IdeDev->IoPort->Head,\r | |
2193 | DevSel\r | |
2194 | );\r | |
2195 | \r | |
75eccf9d | 2196 | //\r |
630d580d | 2197 | // Wait for DRDY singnal asserting.\r |
ead42efc | 2198 | //\r |
2199 | Status = DRDYReady (IdeDev, ATATIMEOUT);\r | |
2200 | if (EFI_ERROR (Status)) {\r | |
2201 | return EFI_DEVICE_ERROR;\r | |
2202 | }\r | |
2203 | \r | |
2204 | //\r | |
630d580d | 2205 | // Fill feature register if needed\r |
ead42efc | 2206 | //\r |
630d580d | 2207 | if (AtaCommand == ATA_CMD_SET_FEATURES) {\r |
2208 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r | |
2209 | }\r | |
ead42efc | 2210 | \r |
2211 | //\r | |
2212 | // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r | |
2213 | //\r | |
2214 | SectorCount8 = (UINT8) (SectorCount >> 8);\r | |
2215 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r | |
2216 | \r | |
2217 | SectorCount8 = (UINT8) SectorCount;\r | |
2218 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r | |
2219 | \r | |
2220 | //\r | |
2221 | // Fill the start LBA registers, which are also two-byte FIFO\r | |
2222 | //\r | |
630d580d | 2223 | LbaLow = (UINT8) RShiftU64 (StartLba, 24);\r |
2224 | LbaMid = (UINT8) RShiftU64 (StartLba, 32);\r | |
2225 | LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r | |
ead42efc | 2226 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r |
ead42efc | 2227 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r |
ead42efc | 2228 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r |
2229 | \r | |
630d580d | 2230 | LbaLow = (UINT8) StartLba;\r |
2231 | LbaMid = (UINT8) RShiftU64 (StartLba, 8);\r | |
2232 | LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r | |
2233 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r | |
2234 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r | |
2235 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r | |
ead42efc | 2236 | \r |
2237 | //\r | |
630d580d | 2238 | // Send command via Command Register, invoking the processing of this command\r |
ead42efc | 2239 | //\r |
2240 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r | |
2241 | \r | |
630d580d | 2242 | Buffer16 = (UINT16 *) Buffer;\r |
ead42efc | 2243 | \r |
2244 | //\r | |
630d580d | 2245 | // According to PIO Data Out protocol, host can perform a series of writes to\r |
2246 | // the data register after each time device set DRQ ready;\r | |
ead42efc | 2247 | //\r |
630d580d | 2248 | Increment = 256;\r |
ead42efc | 2249 | \r |
2250 | //\r | |
630d580d | 2251 | // used to record bytes of currently transfered data\r |
ead42efc | 2252 | //\r |
630d580d | 2253 | WordCount = 0;\r |
ead42efc | 2254 | \r |
630d580d | 2255 | while (WordCount < ByteCount / 2) {\r |
2256 | //\r | |
2257 | // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r | |
2258 | //\r | |
2259 | Status = DRQReady2 (IdeDev, ATATIMEOUT);\r | |
2260 | if (EFI_ERROR (Status)) {\r | |
2261 | return EFI_DEVICE_ERROR;\r | |
2262 | }\r | |
ead42efc | 2263 | \r |
630d580d | 2264 | Status = CheckErrorStatus (IdeDev);\r |
2265 | if (EFI_ERROR (Status)) {\r | |
2266 | return EFI_DEVICE_ERROR;\r | |
2267 | }\r | |
ead42efc | 2268 | \r |
630d580d | 2269 | //\r |
2270 | // Write data into device by one series of writing to data register\r | |
2271 | //\r | |
2272 | if ((WordCount + Increment) > ByteCount / 2) {\r | |
2273 | Increment = ByteCount / 2 - WordCount;\r | |
2274 | }\r | |
ead42efc | 2275 | \r |
630d580d | 2276 | IDEWritePortWMultiple (\r |
2277 | IdeDev->PciIo,\r | |
2278 | IdeDev->IoPort->Data,\r | |
2279 | Increment,\r | |
2280 | Buffer16\r | |
2281 | );\r | |
ead42efc | 2282 | \r |
630d580d | 2283 | WordCount += Increment;\r |
2284 | Buffer16 += Increment;\r | |
ead42efc | 2285 | \r |
630d580d | 2286 | }\r |
2287 | return CheckErrorStatus (IdeDev);\r | |
ead42efc | 2288 | }\r |
ead42efc | 2289 | /**\r |
630d580d | 2290 | This function is called by the AtaBlkIoWriteBlocks() to perform\r |
2291 | writing to media in block unit. The function has been enhanced to\r | |
ead42efc | 2292 | support >120GB access and transfer at most 65536 blocks per command\r |
2293 | \r | |
630d580d | 2294 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r |
2295 | to record all the information of the IDE device.\r | |
2296 | @param DataBuffer A pointer to the source buffer for the data.\r | |
2297 | @param StartLba The starting logical block address to write to\r | |
2298 | on the device media.\r | |
2299 | @param NumberOfBlocks The number of transfer data blocks.\r | |
ead42efc | 2300 | \r |
630d580d | 2301 | @return status depends on the function DoAtaUdma() returns.\r |
ead42efc | 2302 | **/\r |
2303 | EFI_STATUS\r | |
630d580d | 2304 | AtaUdmaWriteExt (\r |
ead42efc | 2305 | IN IDE_BLK_IO_DEV *IdeDev,\r |
2306 | IN VOID *DataBuffer,\r | |
2307 | IN EFI_LBA StartLba,\r | |
2308 | IN UINTN NumberOfBlocks\r | |
2309 | )\r | |
2310 | {\r | |
630d580d | 2311 | return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);\r |
ead42efc | 2312 | }\r |
2313 | \r | |
2314 | /**\r | |
630d580d | 2315 | This function is called by the AtaBlkIoWriteBlocks() to perform\r |
2316 | writing to media in block unit. \r | |
2317 | \r | |
2318 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r | |
2319 | to record all the information of the IDE device.\r | |
2320 | @param DataBuffer A pointer to the source buffer for the data.\r | |
2321 | @param StartLba The starting logical block address to write to\r | |
2322 | on the device media.\r | |
2323 | @param NumberOfBlocks The number of transfer data blocks.\r | |
2324 | \r | |
2325 | @return status depends on the function DoAtaUdma() returns.\r | |
ead42efc | 2326 | **/\r |
2327 | EFI_STATUS\r | |
630d580d | 2328 | AtaUdmaWrite (\r |
ead42efc | 2329 | IN IDE_BLK_IO_DEV *IdeDev,\r |
2330 | IN VOID *DataBuffer,\r | |
2331 | IN EFI_LBA StartLba,\r | |
2332 | IN UINTN NumberOfBlocks\r | |
2333 | )\r | |
2334 | {\r | |
630d580d | 2335 | return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);\r |
ead42efc | 2336 | }\r |
ead42efc | 2337 | /**\r |
2338 | This function is called by the AtaBlkIoWriteBlocks() to perform\r | |
630d580d | 2339 | writing onto media in block unit. The function has been enhanced to\r |
ead42efc | 2340 | support >120GB access and transfer at most 65536 blocks per command\r |
2341 | \r | |
630d580d | 2342 | @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used\r |
2343 | to record all the information of the IDE device.\r | |
2344 | @param DataBuffer A pointer to the source buffer for the data.\r | |
2345 | @param StartLba The starting logical block address to write onto the device \r | |
2346 | media.\r | |
2347 | @param NumberOfBlocks The number of transfer data blocks.\r | |
ead42efc | 2348 | \r |
630d580d | 2349 | @return status is fully dependent on the return status of AtaPioDataOutExt() function.\r |
ead42efc | 2350 | **/\r |
2351 | EFI_STATUS\r | |
630d580d | 2352 | AtaWriteSectorsExt (\r |
ead42efc | 2353 | IN IDE_BLK_IO_DEV *IdeDev,\r |
2354 | IN VOID *DataBuffer,\r | |
2355 | IN EFI_LBA StartLba,\r | |
2356 | IN UINTN NumberOfBlocks\r | |
2357 | )\r | |
2358 | {\r | |
630d580d | 2359 | EFI_STATUS Status;\r |
2360 | EFI_LBA Lba64;\r | |
2361 | UINTN BlocksRemaining;\r | |
2362 | UINT8 AtaCommand;\r | |
2363 | UINT16 SectorCount;\r | |
2364 | UINT32 ByteCount;\r | |
2365 | VOID *Buffer;\r | |
ead42efc | 2366 | \r |
630d580d | 2367 | //\r |
2368 | // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol\r | |
2369 | //\r | |
2370 | AtaCommand = ATA_CMD_WRITE_SECTORS_EXT;\r | |
2371 | Lba64 = StartLba;\r | |
2372 | Buffer = DataBuffer;\r | |
2373 | BlocksRemaining = NumberOfBlocks;\r | |
2374 | \r | |
2375 | Status = EFI_SUCCESS;\r | |
ead42efc | 2376 | \r |
630d580d | 2377 | while (BlocksRemaining > 0) {\r |
ead42efc | 2378 | \r |
630d580d | 2379 | if (BlocksRemaining >= 0x10000) {\r |
2380 | //\r | |
2381 | // SectorCount is used to record the number of sectors to be written.\r | |
2382 | // Max 65536 sectors can be transfered at a time.\r | |
2383 | //\r | |
2384 | SectorCount = 0xffff;\r | |
2385 | } else {\r | |
2386 | SectorCount = (UINT16) BlocksRemaining;\r | |
2387 | }\r | |
ead42efc | 2388 | \r |
630d580d | 2389 | //\r |
2390 | // ByteCount is the number of bytes that will be written\r | |
2391 | //\r | |
2392 | ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r | |
ead42efc | 2393 | \r |
630d580d | 2394 | //\r |
2395 | // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command\r | |
2396 | //\r | |
2397 | Status = AtaPioDataOutExt (\r | |
2398 | IdeDev,\r | |
2399 | Buffer,\r | |
2400 | ByteCount,\r | |
2401 | AtaCommand,\r | |
2402 | Lba64,\r | |
2403 | SectorCount\r | |
2404 | );\r | |
2405 | if (EFI_ERROR (Status)) {\r | |
2406 | return Status;\r | |
2407 | }\r | |
ead42efc | 2408 | \r |
630d580d | 2409 | Lba64 += SectorCount;\r |
2410 | Buffer = ((UINT8 *) Buffer + ByteCount);\r | |
2411 | BlocksRemaining -= SectorCount;\r | |
2412 | }\r | |
ead42efc | 2413 | \r |
630d580d | 2414 | return Status;\r |
ead42efc | 2415 | }\r |
ead42efc | 2416 | /**\r |
630d580d | 2417 | This function is the ATA implementation for WriteBlocks in the\r |
2418 | Block I/O Protocol interface.\r | |
ead42efc | 2419 | \r |
630d580d | 2420 | @param IdeBlkIoDevice Indicates the calling context.\r |
2421 | @param MediaId The media id that the write request is for.\r | |
cd57e888 | 2422 | @param Lba The starting logical block address to write onto the device.\r |
630d580d | 2423 | @param BufferSize The size of the Buffer in bytes. This must be a multiple\r |
2424 | of the intrinsic block size of the device.\r | |
2425 | @param Buffer A pointer to the source buffer for the data.The caller\r | |
2426 | is responsible for either having implicit or explicit \r | |
2427 | ownership of the memory that data is written from.\r | |
ead42efc | 2428 | \r |
630d580d | 2429 | @retval EFI_SUCCESS Write Blocks successfully.\r |
2430 | @retval EFI_DEVICE_ERROR Write Blocks failed.\r | |
2431 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
2432 | @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.\r | |
ead42efc | 2433 | \r |
630d580d | 2434 | @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r |
2435 | intrinsic block size of the device.\r | |
2436 | @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r | |
2437 | or the data buffer is not valid.\r | |
ead42efc | 2438 | \r |
630d580d | 2439 | @note If Write Block error because of device error, this function will call\r |
2440 | AtaSoftReset() function to reset device.\r | |
ead42efc | 2441 | **/\r |
2442 | EFI_STATUS\r | |
630d580d | 2443 | AtaBlkIoWriteBlocks (\r |
2444 | IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r | |
2445 | IN UINT32 MediaId,\r | |
cd57e888 | 2446 | IN EFI_LBA Lba,\r |
630d580d | 2447 | IN UINTN BufferSize,\r |
2448 | OUT VOID *Buffer\r | |
ead42efc | 2449 | )\r |
2450 | {\r | |
ead42efc | 2451 | \r |
630d580d | 2452 | EFI_BLOCK_IO_MEDIA *Media;\r |
2453 | UINTN BlockSize;\r | |
2454 | UINTN NumberOfBlocks;\r | |
2455 | EFI_STATUS Status;\r | |
2456 | \r | |
2457 | if (Buffer == NULL) {\r | |
2458 | return EFI_INVALID_PARAMETER;\r | |
ead42efc | 2459 | }\r |
2460 | \r | |
630d580d | 2461 | if (BufferSize == 0) {\r |
2462 | return EFI_SUCCESS;\r | |
2463 | }\r | |
2464 | \r | |
2465 | Status = EFI_SUCCESS;\r | |
ead42efc | 2466 | \r |
2467 | //\r | |
630d580d | 2468 | // Get the intrinsic block size\r |
ead42efc | 2469 | //\r |
630d580d | 2470 | Media = IdeBlkIoDevice->BlkIo.Media;\r |
2471 | BlockSize = Media->BlockSize;\r | |
2472 | NumberOfBlocks = BufferSize / BlockSize;\r | |
ead42efc | 2473 | \r |
630d580d | 2474 | if (MediaId != Media->MediaId) {\r |
2475 | return EFI_MEDIA_CHANGED;\r | |
ead42efc | 2476 | }\r |
2477 | \r | |
630d580d | 2478 | if (BufferSize % BlockSize != 0) {\r |
2479 | return EFI_BAD_BUFFER_SIZE;\r | |
2480 | }\r | |
6979fd93 | 2481 | \r |
cd57e888 | 2482 | if (Lba > Media->LastBlock) {\r |
630d580d | 2483 | return EFI_INVALID_PARAMETER;\r |
2484 | }\r | |
ead42efc | 2485 | \r |
cd57e888 | 2486 | if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r |
630d580d | 2487 | return EFI_INVALID_PARAMETER;\r |
2488 | }\r | |
ead42efc | 2489 | \r |
630d580d | 2490 | if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r |
2491 | return EFI_INVALID_PARAMETER;\r | |
2492 | }\r | |
ead42efc | 2493 | \r |
630d580d | 2494 | Status = EFI_SUCCESS;\r |
2495 | if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r | |
ead42efc | 2496 | //\r |
630d580d | 2497 | // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism\r |
ead42efc | 2498 | //\r |
630d580d | 2499 | if (IdeBlkIoDevice->UdmaMode.Valid) {\r |
cd57e888 | 2500 | Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r |
ead42efc | 2501 | } else {\r |
cd57e888 | 2502 | Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r |
ead42efc | 2503 | }\r |
630d580d | 2504 | } else {\r |
ead42efc | 2505 | //\r |
630d580d | 2506 | // For ATA-3 compatible device, use ATA-3 write block mechanism\r |
ead42efc | 2507 | //\r |
630d580d | 2508 | if (IdeBlkIoDevice->UdmaMode.Valid) {\r |
cd57e888 | 2509 | Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r |
630d580d | 2510 | } else {\r |
cd57e888 | 2511 | Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r |
ead42efc | 2512 | }\r |
630d580d | 2513 | }\r |
ead42efc | 2514 | \r |
630d580d | 2515 | if (EFI_ERROR (Status)) {\r |
2516 | AtaSoftReset (IdeBlkIoDevice);\r | |
2517 | return EFI_DEVICE_ERROR;\r | |
2518 | }\r | |
ead42efc | 2519 | \r |
630d580d | 2520 | return EFI_SUCCESS;\r |
2521 | }\r | |
2522 | /**\r | |
2523 | Enable Long Physical Sector Feature for ATA device.\r | |
ead42efc | 2524 | \r |
630d580d | 2525 | @param IdeDev The IDE device data\r |
ead42efc | 2526 | \r |
630d580d | 2527 | @retval EFI_SUCCESS The ATA device supports Long Physical Sector feature\r |
2528 | and corresponding fields in BlockIo structure is updated.\r | |
2529 | @retval EFI_UNSUPPORTED The device is not ATA device or Long Physical Sector\r | |
2530 | feature is not supported.\r | |
2531 | **/\r | |
2532 | EFI_STATUS\r | |
2533 | AtaEnableLongPhysicalSector (\r | |
2534 | IN IDE_BLK_IO_DEV *IdeDev\r | |
2535 | )\r | |
2536 | {\r | |
2537 | EFI_ATA_IDENTIFY_DATA *AtaIdentifyData;\r | |
2538 | UINT16 PhyLogicSectorSupport;\r | |
ead42efc | 2539 | \r |
630d580d | 2540 | ASSERT (IdeDev->IdData != NULL);\r |
2541 | //\r | |
2542 | // Only valid for ATA device\r | |
2543 | //\r | |
2544 | AtaIdentifyData = (EFI_ATA_IDENTIFY_DATA *) &IdeDev->IdData->AtaData;\r | |
2545 | if ((AtaIdentifyData->config & 0x8000) != 0) {\r | |
2546 | return EFI_UNSUPPORTED;\r | |
2547 | }\r | |
2548 | PhyLogicSectorSupport = AtaIdentifyData->phy_logic_sector_support;\r | |
2549 | //\r | |
2550 | // Check whether Long Physical Sector Feature is supported\r | |
2551 | //\r | |
2552 | if ((PhyLogicSectorSupport & 0xc000) == 0x4000) {\r | |
2553 | IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;\r | |
2554 | IdeDev->BlkIo.Media->LowestAlignedLba = 0;\r | |
ead42efc | 2555 | //\r |
630d580d | 2556 | // Check whether one physical block contains multiple physical blocks\r |
ead42efc | 2557 | //\r |
630d580d | 2558 | if ((PhyLogicSectorSupport & 0x2000) != 0) {\r |
2559 | IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock =\r | |
2560 | (UINT32) (1 << (PhyLogicSectorSupport & 0x000f));\r | |
2561 | //\r | |
2562 | // Check lowest alignment of logical blocks within physical block\r | |
2563 | //\r | |
2564 | if ((AtaIdentifyData->alignment_logic_in_phy_blocks & 0xc000) == 0x4000) {\r | |
2565 | IdeDev->BlkIo.Media->LowestAlignedLba =\r | |
d96d37d8 | 2566 | (EFI_LBA) ((IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock - ((UINT32)AtaIdentifyData->alignment_logic_in_phy_blocks & 0x3fff)) %\r |
2567 | IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock);\r | |
630d580d | 2568 | }\r |
2569 | }\r | |
ead42efc | 2570 | //\r |
630d580d | 2571 | // Check logical block size\r |
ead42efc | 2572 | //\r |
630d580d | 2573 | IdeDev->BlkIo.Media->BlockSize = 0x200;\r |
2574 | if ((PhyLogicSectorSupport & 0x1000) != 0) {\r | |
2575 | IdeDev->BlkIo.Media->BlockSize = (UINT32) (\r | |
2576 | ((AtaIdentifyData->logic_sector_size_hi << 16) |\r | |
2577 | AtaIdentifyData->logic_sector_size_lo) * sizeof (UINT16)\r | |
2578 | );\r | |
ead42efc | 2579 | }\r |
630d580d | 2580 | return EFI_SUCCESS;\r |
2581 | } else {\r | |
2582 | return EFI_UNSUPPORTED;\r | |
2583 | }\r | |
2584 | }\r | |
2585 | /**\r | |
2586 | Send ATA command into device with NON_DATA protocol\r | |
ead42efc | 2587 | \r |
630d580d | 2588 | @param IdeDev Standard IDE device private data structure\r |
2589 | @param AtaCommand The ATA command to be sent\r | |
2590 | @param Device The value in Device register\r | |
2591 | @param Feature The value in Feature register\r | |
2592 | @param SectorCount The value in SectorCount register\r | |
2593 | @param LbaLow The value in LBA_LOW register\r | |
2594 | @param LbaMiddle The value in LBA_MIDDLE register\r | |
2595 | @param LbaHigh The value in LBA_HIGH register\r | |
ead42efc | 2596 | \r |
630d580d | 2597 | @retval EFI_SUCCESS Reading succeed\r |
2598 | @retval EFI_ABORTED Command failed\r | |
2599 | @retval EFI_DEVICE_ERROR Device status error.\r | |
ead42efc | 2600 | \r |
630d580d | 2601 | **/\r |
2602 | EFI_STATUS\r | |
2603 | AtaNonDataCommandIn (\r | |
2604 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
2605 | IN UINT8 AtaCommand,\r | |
2606 | IN UINT8 Device,\r | |
2607 | IN UINT8 Feature,\r | |
2608 | IN UINT8 SectorCount,\r | |
2609 | IN UINT8 LbaLow,\r | |
2610 | IN UINT8 LbaMiddle,\r | |
2611 | IN UINT8 LbaHigh\r | |
2612 | )\r | |
2613 | {\r | |
2614 | EFI_STATUS Status;\r | |
2615 | UINT8 StatusRegister;\r | |
ead42efc | 2616 | \r |
630d580d | 2617 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r |
2618 | if (EFI_ERROR (Status)) {\r | |
2619 | return EFI_DEVICE_ERROR;\r | |
2620 | }\r | |
ead42efc | 2621 | \r |
630d580d | 2622 | //\r |
cd57e888 | 2623 | // Select device (bit4), set Lba mode(bit6) (use 0xe0 for compatibility)\r |
630d580d | 2624 | //\r |
2625 | IDEWritePortB (\r | |
2626 | IdeDev->PciIo,\r | |
2627 | IdeDev->IoPort->Head,\r | |
2628 | (UINT8) ((IdeDev->Device << 4) | 0xe0)\r | |
2629 | );\r | |
ead42efc | 2630 | \r |
630d580d | 2631 | //\r |
2632 | // ATA commands for ATA device must be issued when DRDY is set\r | |
2633 | //\r | |
2634 | Status = DRDYReady (IdeDev, ATATIMEOUT);\r | |
2635 | if (EFI_ERROR (Status)) {\r | |
2636 | return EFI_DEVICE_ERROR;\r | |
2637 | }\r | |
ead42efc | 2638 | \r |
630d580d | 2639 | //\r |
2640 | // Pass parameter into device register block\r | |
2641 | //\r | |
2642 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r | |
2643 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);\r | |
2644 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r | |
2645 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r | |
2646 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);\r | |
2647 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r | |
ead42efc | 2648 | \r |
630d580d | 2649 | //\r |
2650 | // Send command via Command Register\r | |
2651 | //\r | |
2652 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r | |
ead42efc | 2653 | \r |
630d580d | 2654 | //\r |
2655 | // Wait for command completion\r | |
2656 | // For ATAPI_SMART_CMD, we may need more timeout to let device\r | |
2657 | // adjust internal states.\r | |
2658 | //\r | |
2659 | if (AtaCommand == ATA_CMD_SMART) {\r | |
2660 | Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r | |
2661 | } else {\r | |
2662 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r | |
2663 | }\r | |
2664 | if (EFI_ERROR (Status)) {\r | |
2665 | return EFI_DEVICE_ERROR;\r | |
2666 | }\r | |
ead42efc | 2667 | \r |
630d580d | 2668 | StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r |
2669 | if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r | |
ead42efc | 2670 | //\r |
630d580d | 2671 | // Failed to execute command, abort operation\r |
6979fd93 | 2672 | //\r |
630d580d | 2673 | return EFI_ABORTED;\r |
2674 | }\r | |
6979fd93 | 2675 | \r |
630d580d | 2676 | return EFI_SUCCESS;\r |
2677 | }\r | |
6979fd93 | 2678 | \r |
630d580d | 2679 | /**\r |
2680 | Send ATA Ext command into device with NON_DATA protocol\r | |
ead42efc | 2681 | \r |
630d580d | 2682 | @param IdeDev Standard IDE device private data structure\r |
2683 | @param AtaCommand The ATA command to be sent\r | |
2684 | @param Device The value in Device register\r | |
2685 | @param Feature The value in Feature register\r | |
2686 | @param SectorCount The value in SectorCount register\r | |
2687 | @param LbaAddress The LBA address in 48-bit mode\r | |
ead42efc | 2688 | \r |
630d580d | 2689 | @retval EFI_SUCCESS Reading succeed\r |
2690 | @retval EFI_ABORTED Command failed\r | |
2691 | @retval EFI_DEVICE_ERROR Device status error.\r | |
ead42efc | 2692 | \r |
630d580d | 2693 | **/\r |
2694 | EFI_STATUS\r | |
2695 | AtaNonDataCommandInExt (\r | |
2696 | IN IDE_BLK_IO_DEV *IdeDev,\r | |
2697 | IN UINT8 AtaCommand,\r | |
2698 | IN UINT8 Device,\r | |
2699 | IN UINT16 Feature,\r | |
2700 | IN UINT16 SectorCount,\r | |
2701 | IN EFI_LBA LbaAddress\r | |
2702 | )\r | |
2703 | {\r | |
2704 | EFI_STATUS Status;\r | |
2705 | UINT8 StatusRegister;\r | |
2706 | UINT8 SectorCount8;\r | |
2707 | UINT8 Feature8;\r | |
2708 | UINT8 LbaLow;\r | |
2709 | UINT8 LbaMid;\r | |
2710 | UINT8 LbaHigh;\r | |
ead42efc | 2711 | \r |
630d580d | 2712 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r |
2713 | if (EFI_ERROR (Status)) {\r | |
2714 | return EFI_DEVICE_ERROR;\r | |
ead42efc | 2715 | }\r |
2716 | \r | |
2717 | //\r | |
630d580d | 2718 | // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r |
ead42efc | 2719 | //\r |
630d580d | 2720 | IDEWritePortB (\r |
2721 | IdeDev->PciIo,\r | |
2722 | IdeDev->IoPort->Head,\r | |
2723 | (UINT8) ((IdeDev->Device << 4) | 0xe0)\r | |
2724 | );\r | |
ead42efc | 2725 | \r |
630d580d | 2726 | //\r |
2727 | // ATA commands for ATA device must be issued when DRDY is set\r | |
2728 | //\r | |
2729 | Status = DRDYReady (IdeDev, ATATIMEOUT);\r | |
2730 | if (EFI_ERROR (Status)) {\r | |
2731 | return EFI_DEVICE_ERROR;\r | |
2732 | }\r | |
2733 | \r | |
2734 | //\r | |
2735 | // Pass parameter into device register block\r | |
2736 | //\r | |
2737 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r | |
2738 | \r | |
2739 | //\r | |
2740 | // Fill the feature register, which is a two-byte FIFO. Need write twice.\r | |
2741 | //\r | |
2742 | Feature8 = (UINT8) (Feature >> 8);\r | |
2743 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r | |
2744 | \r | |
2745 | Feature8 = (UINT8) Feature;\r | |
2746 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r | |
2747 | \r | |
2748 | //\r | |
2749 | // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r | |
2750 | //\r | |
2751 | SectorCount8 = (UINT8) (SectorCount >> 8);\r | |
2752 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r | |
2753 | \r | |
2754 | SectorCount8 = (UINT8) SectorCount;\r | |
2755 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r | |
2756 | \r | |
2757 | //\r | |
2758 | // Fill the start LBA registers, which are also two-byte FIFO\r | |
2759 | //\r | |
2760 | LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r | |
2761 | LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r | |
2762 | LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r | |
2763 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r | |
2764 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r | |
2765 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r | |
2766 | \r | |
2767 | LbaLow = (UINT8) LbaAddress;\r | |
2768 | LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r | |
2769 | LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r | |
2770 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r | |
2771 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r | |
2772 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r | |
2773 | \r | |
2774 | //\r | |
2775 | // Send command via Command Register\r | |
2776 | //\r | |
2777 | IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r | |
2778 | \r | |
2779 | //\r | |
2780 | // Wait for command completion\r | |
2781 | //\r | |
2782 | Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r | |
2783 | if (EFI_ERROR (Status)) {\r | |
2784 | return EFI_DEVICE_ERROR;\r | |
2785 | }\r | |
2786 | \r | |
2787 | StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r | |
2788 | if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r | |
2789 | //\r | |
2790 | // Failed to execute command, abort operation\r | |
2791 | //\r | |
2792 | return EFI_ABORTED;\r | |
2793 | }\r | |
2794 | \r | |
2795 | return EFI_SUCCESS;\r | |
ead42efc | 2796 | }\r |
6979fd93 | 2797 | \r |
630d580d | 2798 | \r |
2799 | \r |