]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c
Fix capitalization.
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / IdeBus / Dxe / ata.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 ata.c\r
15 \r
16Abstract: \r
17 \r
18Revision History\r
19\r
20 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including\r
21 update - ATAIdentity() func\r
22 update - AtaBlockIoReadBlocks() func\r
23 update - AtaBlockIoWriteBlocks() func\r
24 add - AtaAtapi6Identify() func\r
25 add - AtaReadSectorsExt() func\r
26 add - AtaWriteSectorsExt() func\r
27 add - AtaPioDataInExt() func\r
28 add - AtaPioDataOutExt() func\r
29 \r
30--*/\r
31\r
32#include "idebus.h"\r
33\r
34\r
35EFI_STATUS\r
36AtaReadSectorsExt (\r
37 IN IDE_BLK_IO_DEV *IdeDev,\r
38 IN OUT VOID *DataBuffer,\r
39 IN EFI_LBA StartLba,\r
40 IN UINTN NumberOfBlocks\r
41 );\r
42\r
43EFI_STATUS\r
44AtaWriteSectorsExt (\r
45 IN IDE_BLK_IO_DEV *IdeDev,\r
46 IN VOID *DataBuffer,\r
47 IN EFI_LBA StartLba,\r
48 IN UINTN NumberOfBlocks\r
49 );\r
50\r
51EFI_STATUS\r
52AtaPioDataInExt (\r
53 IN IDE_BLK_IO_DEV *IdeDev,\r
54 IN OUT VOID *Buffer,\r
55 IN UINT32 ByteCount,\r
56 IN UINT8 AtaCommand,\r
57 IN EFI_LBA StartLba,\r
58 IN UINT16 SectorCount\r
59 );\r
60\r
61EFI_STATUS\r
62AtaPioDataOutExt (\r
63 IN IDE_BLK_IO_DEV *IdeDev,\r
64 IN VOID *Buffer,\r
65 IN UINT32 ByteCount,\r
66 IN UINT8 AtaCommand,\r
67 IN EFI_LBA StartLba,\r
68 IN UINT16 SectorCount\r
69 );\r
70\r
71EFI_STATUS\r
72ATAIdentify (\r
73 IN IDE_BLK_IO_DEV *IdeDev\r
74 )\r
75/*++\r
76 Name:\r
77 ATAIdentify\r
78\r
79\r
80 Purpose: \r
81 This function is called by DiscoverIdeDevice() during its device\r
82 identification. It sends out the ATA Identify Command to the \r
83 specified device. Only ATA device responses to this command. If \r
84 the command succeeds, it returns the Identify data structure which \r
85 contains information about the device. This function extracts the \r
86 information it needs to fill the IDE_BLK_IO_DEV data structure, \r
87 including device type, media block size, media capacity, and etc.\r
88\r
89\r
90 Parameters:\r
91 IDE_BLK_IO_DEV IN *IdeDev\r
92 pointer pointing to IDE_BLK_IO_DEV data structure,used\r
93 to record all the information of the IDE device.\r
94\r
95\r
96 Returns: \r
97 EFI_SUCCESS\r
98 Identify ATA device successfully.\r
99\r
100 EFI_DEVICE_ERROR\r
101 ATA Identify Device Command failed or device is not \r
102 ATA device.\r
103\r
104\r
105 Notes:\r
106 parameter IdeDev will be updated in this function.\r
107--*/\r
108// TODO: function comment is missing 'Routine Description:'\r
109// TODO: function comment is missing 'Arguments:'\r
110// TODO: IdeDev - add argument and description to function comment\r
111{\r
112 EFI_STATUS Status;\r
113 EFI_IDENTIFY_DATA *AtaIdentifyPointer;\r
114 UINT32 Capacity;\r
115 UINT8 DeviceSelect;\r
116\r
117 //\r
118 // AtaIdentifyPointer is used for accommodating returned IDENTIFY data of\r
119 // the ATA Identify command\r
120 //\r
121 AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
122\r
123 //\r
124 // use ATA PIO Data In protocol to send ATA Identify command\r
125 // and receive data from device\r
126 //\r
127 DeviceSelect = 0;\r
128 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
129 Status = AtaPioDataIn (\r
130 IdeDev,\r
131 (VOID *) AtaIdentifyPointer,\r
132 sizeof (EFI_IDENTIFY_DATA),\r
133 IDENTIFY_DRIVE_CMD,\r
134 DeviceSelect,\r
135 0,\r
136 0,\r
137 0,\r
138 0\r
139 );\r
140 //\r
141 // If ATA Identify command succeeds, then according to the received\r
142 // IDENTIFY data,\r
143 // identify the device type ( ATA or not ).\r
144 // If ATA device, fill the information in IdeDev.\r
145 // If not ATA device, return IDE_DEVICE_ERROR\r
146 //\r
147 if (!EFI_ERROR (Status)) {\r
148\r
149 IdeDev->pIdData = AtaIdentifyPointer;\r
150\r
151 //\r
152 // Print ATA Module Name\r
153 //\r
154 PrintAtaModuleName (IdeDev);\r
155\r
156 //\r
157 // bit 15 of pAtaIdentify->config is used to identify whether device is\r
158 // ATA device or ATAPI device.\r
159 // if 0, means ATA device; if 1, means ATAPI device.\r
160 //\r
161 if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) {\r
162 //\r
163 // Detect if support S.M.A.R.T. If yes, enable it as default\r
164 //\r
165 AtaSMARTSupport (IdeDev);\r
166\r
167 //\r
168 // Check whether this device needs 48-bit addressing (ATAPI-6 ata device)\r
169 //\r
170 Status = AtaAtapi6Identify (IdeDev);\r
171 if (!EFI_ERROR (Status)) {\r
172 //\r
173 // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify()\r
174 //\r
175 return EFI_SUCCESS;\r
176 }\r
177 //\r
178 // This is a hard disk <= 120GB capacity, treat it as normal hard disk\r
179 //\r
180 IdeDev->Type = IdeHardDisk;\r
181\r
182 //\r
183 // Block Media Information:\r
184 // Media->LogicalPartition , Media->WriteCaching will be filled\r
185 // in the DiscoverIdeDevcie() function.\r
186 //\r
187 IdeDev->BlkIo.Media->IoAlign = 4;\r
188 IdeDev->BlkIo.Media->MediaId = 1;\r
189 IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
190 IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
191 IdeDev->BlkIo.Media->ReadOnly = FALSE;\r
192 IdeDev->BlkIo.Media->BlockSize = 0x200;\r
193\r
194 //\r
195 // Calculate device capacity\r
196 //\r
197 Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) |\r
198 AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ;\r
199 IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r
200\r
201 return EFI_SUCCESS;\r
202\r
203 }\r
204 }\r
205\r
206 gBS->FreePool (AtaIdentifyPointer);\r
207 //\r
208 // Make sure the pIdData will not be freed again.\r
209 //\r
210 IdeDev->pIdData = NULL;\r
211\r
212 return EFI_DEVICE_ERROR;\r
213}\r
214\r
215\r
216EFI_STATUS\r
217AtaAtapi6Identify (\r
218 IN IDE_BLK_IO_DEV *IdeDev\r
219 )\r
220/*++\r
221 Name:\r
222 \r
223 AtaAtapi6Identify\r
224\r
225 Purpose: \r
226 \r
227 This function is called by ATAIdentify() to identity whether this disk\r
228 supports ATA/ATAPI6 48bit addressing, ie support >120G capacity\r
229\r
230 Parameters:\r
231 IDE_BLK_IO_DEV IN *IdeDev\r
232 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
233 to record all the information of the IDE device.\r
234\r
235 Returns: \r
236 \r
237 EFI_SUCCESS - The disk specified by IdeDev is a Atapi6 supported one\r
238 and 48-bit addressing must be used\r
239\r
240 EFI_UNSUPPORTED - The disk dosn't not support Atapi6 or it supports but\r
241 the capacity is below 120G, 48bit addressing is not \r
242 needed\r
243 \r
244 Notes:\r
245\r
246 This function must be called after DEVICE_IDENTITY command has been \r
247 successfully returned\r
248--*/\r
249// TODO: function comment is missing 'Routine Description:'\r
250// TODO: function comment is missing 'Arguments:'\r
251// TODO: IdeDev - add argument and description to function comment\r
252{\r
253 UINT8 Index;\r
254 EFI_LBA TmpLba;\r
255 EFI_LBA Capacity;\r
256 EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;\r
257\r
258 if (IdeDev->pIdData == NULL) {\r
259 return EFI_UNSUPPORTED;\r
260 }\r
261\r
262 Atapi6IdentifyStruct = IdeDev->pIdData;\r
263\r
264 if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & bit10) == 0) {\r
265 //\r
266 // The device dosn't support 48 bit addressing\r
267 //\r
268 return EFI_UNSUPPORTED;\r
269 }\r
270\r
271 //\r
272 // 48 bit address feature set is supported, get maximum capacity\r
273 //\r
274 Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0];\r
275 for (Index = 1; Index < 4; Index++) {\r
276 //\r
277 // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r
278 //\r
279 TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index];\r
280 Capacity |= LShiftU64 (TmpLba, 16 * Index);\r
281 }\r
282\r
283 if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {\r
284 //\r
285 // Capacity exceeds 120GB. 48-bit addressing is really needed\r
286 //\r
287 IdeDev->Type = Ide48bitAddressingHardDisk;\r
288\r
289 //\r
290 // Fill block media information:Media->LogicalPartition ,\r
291 // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.\r
292 //\r
293 IdeDev->BlkIo.Media->IoAlign = 4;\r
294 IdeDev->BlkIo.Media->MediaId = 1;\r
295 IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
296 IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
297 IdeDev->BlkIo.Media->ReadOnly = FALSE;\r
298 IdeDev->BlkIo.Media->BlockSize = 0x200;\r
299 IdeDev->BlkIo.Media->LastBlock = Capacity - 1;\r
300\r
301 return EFI_SUCCESS;\r
302 }\r
303\r
304 return EFI_UNSUPPORTED;\r
305}\r
306\r
307VOID\r
308PrintAtaModuleName (\r
309 IN IDE_BLK_IO_DEV *IdeDev\r
310 )\r
311/*++\r
312 Name:\r
313 PrintAtaModuleName\r
314\r
315\r
316 Purpose: \r
317 This function is called by ATAIdentify() or ATAPIIdentify()\r
318 to print device's module name. \r
319\r
320\r
321 Parameters:\r
322 IDE_BLK_IO_DEV IN *IdeDev\r
323 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
324 to record all the information of the IDE device.\r
325\r
326 Returns: \r
327 no returns.\r
328\r
329 Notes:\r
330--*/\r
331// TODO: function comment is missing 'Routine Description:'\r
332// TODO: function comment is missing 'Arguments:'\r
333// TODO: IdeDev - add argument and description to function comment\r
334{\r
335 if (IdeDev->pIdData == NULL) {\r
336 return ;\r
337 }\r
338\r
339 SwapStringChars (IdeDev->ModelName, IdeDev->pIdData->AtaData.ModelName, 40);\r
340 IdeDev->ModelName[40] = 0x00;\r
341}\r
342\r
343EFI_STATUS\r
344AtaPioDataIn (\r
345 IN IDE_BLK_IO_DEV *IdeDev,\r
346 IN VOID *Buffer,\r
347 IN UINT32 ByteCount,\r
348 IN UINT8 AtaCommand,\r
349 IN UINT8 Head,\r
350 IN UINT8 SectorCount,\r
351 IN UINT8 SectorNumber,\r
352 IN UINT8 CylinderLsb,\r
353 IN UINT8 CylinderMsb\r
354 )\r
355/*++\r
356 Name:\r
357 AtaPioDataIn\r
358\r
359\r
360 Purpose: \r
361 This function is used to send out ATA commands conforms to the \r
362 PIO Data In Protocol.\r
363\r
364\r
365 Parameters:\r
366 IDE_BLK_IO_DEV IN *IdeDev\r
367 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
368 to record all the information of the IDE device.\r
369\r
370 VOID IN *Buffer\r
371 buffer contained data transferred from device to host.\r
372\r
373 UINT32 IN ByteCount\r
374 data size in byte unit of the buffer.\r
375\r
376 UINT8 IN AtaCommand\r
377 value of the Command Register\r
378\r
379 UINT8 IN Head\r
380 value of the Head/Device Register\r
381\r
382 UINT8 IN SectorCount\r
383 value of the Sector Count Register\r
384\r
385 UINT8 IN SectorNumber\r
386 value of the Sector Number Register\r
387\r
388 UINT8 IN CylinderLsb\r
389 value of the low byte of the Cylinder Register\r
390\r
391 UINT8 IN CylinderMsb\r
392 value of the high byte of the Cylinder Register\r
393\r
394\r
395 Returns: \r
396 EFI_SUCCESS\r
397 send out the ATA command and device send required\r
398 data successfully.\r
399\r
400 EFI_DEVICE_ERROR\r
401 command sent failed.\r
402 Notes:\r
403--*/\r
404// TODO: function comment is missing 'Routine Description:'\r
405// TODO: function comment is missing 'Arguments:'\r
406// TODO: IdeDev - add argument and description to function comment\r
407// TODO: Buffer - add argument and description to function comment\r
408// TODO: ByteCount - add argument and description to function comment\r
409// TODO: AtaCommand - add argument and description to function comment\r
410// TODO: Head - add argument and description to function comment\r
411// TODO: SectorCount - add argument and description to function comment\r
412// TODO: SectorNumber - add argument and description to function comment\r
413// TODO: CylinderLsb - add argument and description to function comment\r
414// TODO: CylinderMsb - add argument and description to function comment\r
415{\r
416 UINTN WordCount;\r
417 UINTN Increment;\r
418 UINT16 *Buffer16;\r
419 EFI_STATUS Status;\r
420\r
421 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
422 if (EFI_ERROR (Status)) {\r
423 return EFI_DEVICE_ERROR;\r
424 }\r
425\r
426 //\r
427 // e0:1110,0000-- bit7 and bit5 are reserved bits.\r
428 // bit6 set means LBA mode\r
429 //\r
430 IDEWritePortB (\r
431 IdeDev->PciIo,\r
432 IdeDev->IoPort->Head,\r
433 (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)\r
434 );\r
435\r
436 //\r
437 // All ATAPI device's ATA commands can be issued regardless of the\r
438 // state of the DRDY\r
439 //\r
440 if (IdeDev->Type == IdeHardDisk) {\r
441\r
442 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
443 if (EFI_ERROR (Status)) {\r
444 return EFI_DEVICE_ERROR;\r
445 }\r
446 }\r
447 //\r
448 // set all the command parameters\r
449 // Before write to all the following registers, BSY and DRQ must be 0.\r
450 //\r
451 Status = DRQClear2 (IdeDev, ATATIMEOUT);\r
452 if (EFI_ERROR (Status)) {\r
453 return EFI_DEVICE_ERROR;\r
454 }\r
455\r
456 if (AtaCommand == SET_FEATURES_CMD) {\r
457 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
458 }\r
459\r
460 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
461 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);\r
462 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);\r
463 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);\r
464\r
465 //\r
466 // send command via Command Register\r
467 //\r
468 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
469\r
470 Buffer16 = (UINT16 *) Buffer;\r
471\r
472 //\r
473 // According to PIO data in protocol, host can perform a series of reads to\r
474 // the data register after each time device set DRQ ready;\r
475 // The data size of "a series of read" is command specific.\r
476 // For most ATA command, data size received from device will not exceed\r
477 // 1 sector, hence the data size for "a series of read" can be the whole data\r
478 // size of one command request.\r
479 // For ATA command such as Read Sector command, the data size of one ATA\r
480 // command request is often larger than 1 sector, according to the\r
481 // Read Sector command, the data size of "a series of read" is exactly 1\r
482 // sector.\r
483 // Here for simplification reason, we specify the data size for\r
484 // "a series of read" to 1 sector (256 words) if data size of one ATA command\r
485 // request is larger than 256 words.\r
486 //\r
487 Increment = 256;\r
488\r
489 //\r
490 // used to record bytes of currently transfered data\r
491 //\r
492 WordCount = 0;\r
493\r
494 while (WordCount < ByteCount / 2) {\r
495 //\r
496 // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
497 //\r
498 Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
499 if (EFI_ERROR (Status)) {\r
500 return EFI_DEVICE_ERROR;\r
501 }\r
502\r
503 Status = CheckErrorStatus (IdeDev);\r
504 if (EFI_ERROR (Status)) {\r
505 return EFI_DEVICE_ERROR;\r
506 }\r
507\r
508 //\r
509 // Get the byte count for one series of read\r
510 //\r
511 if ((WordCount + Increment) > ByteCount / 2) {\r
512 Increment = ByteCount / 2 - WordCount;\r
513 }\r
514\r
515 IDEReadPortWMultiple (\r
516 IdeDev->PciIo,\r
517 IdeDev->IoPort->Data,\r
518 Increment,\r
519 Buffer16\r
520 );\r
521\r
522 WordCount += Increment;\r
523 Buffer16 += Increment;\r
524\r
525 }\r
526\r
527 DRQClear (IdeDev, ATATIMEOUT);\r
528\r
529 return CheckErrorStatus (IdeDev);\r
530}\r
531\r
532EFI_STATUS\r
533AtaPioDataOut (\r
534 IN IDE_BLK_IO_DEV *IdeDev,\r
535 IN VOID *Buffer,\r
536 IN UINT32 ByteCount,\r
537 IN UINT8 AtaCommand,\r
538 IN UINT8 Head,\r
539 IN UINT8 SectorCount,\r
540 IN UINT8 SectorNumber,\r
541 IN UINT8 CylinderLsb,\r
542 IN UINT8 CylinderMsb\r
543 )\r
544/*++\r
545 Name:\r
546 AtaPioDataOut\r
547\r
548\r
549 Purpose: \r
550 This function is used to send out ATA commands conforms to the \r
551 PIO Data Out Protocol.\r
552\r
553\r
554 Parameters:\r
555 IDE_BLK_IO_DEV IN *IdeDev\r
556 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
557 to record all the information of the IDE device.\r
558\r
559 VOID IN *Buffer\r
560 buffer contained data transferred from host to device.\r
561\r
562 UINT32 IN ByteCount\r
563 data size in byte unit of the buffer.\r
564\r
565 UINT8 IN AtaCommand\r
566 value of the Command Register\r
567\r
568 UINT8 IN Head\r
569 value of the Head/Device Register\r
570\r
571 UINT8 IN SectorCount\r
572 value of the Sector Count Register\r
573\r
574 UINT8 IN SectorNumber\r
575 value of the Sector Number Register\r
576\r
577 UINT8 IN CylinderLsb\r
578 value of the low byte of the Cylinder Register\r
579\r
580 UINT8 IN CylinderMsb\r
581 value of the high byte of the Cylinder Register\r
582\r
583\r
584 Returns: \r
585 EFI_SUCCESS\r
586 send out the ATA command and device received required\r
587 data successfully.\r
588\r
589 EFI_DEVICE_ERROR\r
590 command sent failed. \r
591\r
592 Notes:\r
593--*/\r
594// TODO: function comment is missing 'Routine Description:'\r
595// TODO: function comment is missing 'Arguments:'\r
596// TODO: IdeDev - add argument and description to function comment\r
597// TODO: Buffer - add argument and description to function comment\r
598// TODO: ByteCount - add argument and description to function comment\r
599// TODO: AtaCommand - add argument and description to function comment\r
600// TODO: Head - add argument and description to function comment\r
601// TODO: SectorCount - add argument and description to function comment\r
602// TODO: SectorNumber - add argument and description to function comment\r
603// TODO: CylinderLsb - add argument and description to function comment\r
604// TODO: CylinderMsb - add argument and description to function comment\r
605{\r
606 UINTN WordCount;\r
607 UINTN Increment;\r
608 UINT16 *Buffer16;\r
609 EFI_STATUS Status;\r
610\r
611 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
612 if (EFI_ERROR (Status)) {\r
613 return EFI_DEVICE_ERROR;\r
614 }\r
615\r
616 //\r
617 // select device via Head/Device register.\r
618 // Before write Head/Device register, BSY and DRQ must be 0.\r
619 //\r
620 Status = DRQClear2 (IdeDev, ATATIMEOUT);\r
621 if (EFI_ERROR (Status)) {\r
622 return EFI_DEVICE_ERROR;\r
623 }\r
624\r
625 //\r
626 // e0:1110,0000-- bit7 and bit5 are reserved bits.\r
627 // bit6 set means LBA mode\r
628 //\r
629 IDEWritePortB (\r
630 IdeDev->PciIo,\r
631 IdeDev->IoPort->Head,\r
632 (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)\r
633 );\r
634\r
635 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
636 if (EFI_ERROR (Status)) {\r
637 return EFI_DEVICE_ERROR;\r
638 }\r
639\r
640 //\r
641 // set all the command parameters\r
642 // Before write to all the following registers, BSY and DRQ must be 0.\r
643 //\r
644 Status = DRQClear2 (IdeDev, ATATIMEOUT);\r
645 if (EFI_ERROR (Status)) {\r
646 return EFI_DEVICE_ERROR;\r
647 }\r
648\r
649 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
650 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);\r
651 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);\r
652 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);\r
653\r
654 //\r
655 // send command via Command Register\r
656 //\r
657 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
658\r
659 Buffer16 = (UINT16 *) Buffer;\r
660\r
661 //\r
662 // According to PIO data out protocol, host can perform a series of\r
663 // writes to the data register after each time device set DRQ ready;\r
664 // The data size of "a series of read" is command specific.\r
665 // For most ATA command, data size written to device will not exceed 1 sector,\r
666 // hence the data size for "a series of write" can be the data size of one\r
667 // command request.\r
668 // For ATA command such as Write Sector command, the data size of one\r
669 // ATA command request is often larger than 1 sector, according to the\r
670 // Write Sector command, the data size of "a series of read" is exactly\r
671 // 1 sector.\r
672 // Here for simplification reason, we specify the data size for\r
673 // "a series of write" to 1 sector (256 words) if data size of one ATA command\r
674 // request is larger than 256 words.\r
675 //\r
676 Increment = 256;\r
677 WordCount = 0;\r
678\r
679 while (WordCount < ByteCount / 2) {\r
680 \r
681 //\r
682 // DRQReady2-- read Alternate Status Register to determine the DRQ bit\r
683 // data transfer can be performed only when DRQ is ready.\r
684 //\r
685 Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
686 if (EFI_ERROR (Status)) {\r
687 return EFI_DEVICE_ERROR;\r
688 }\r
689\r
690 Status = CheckErrorStatus (IdeDev);\r
691 if (EFI_ERROR (Status)) {\r
692 return EFI_DEVICE_ERROR;\r
693 }\r
694\r
695 //\r
696 // Check the remaining byte count is less than 512 bytes\r
697 //\r
698 if ((WordCount + Increment) > ByteCount / 2) {\r
699 Increment = ByteCount / 2 - WordCount;\r
700 }\r
701 //\r
702 // perform a series of write without check DRQ ready\r
703 //\r
704 \r
705 IDEWritePortWMultiple (\r
706 IdeDev->PciIo,\r
707 IdeDev->IoPort->Data,\r
708 Increment,\r
709 Buffer16\r
710 );\r
711 WordCount += Increment;\r
712 Buffer16 += Increment;\r
713\r
714 }\r
715\r
716 DRQClear (IdeDev, ATATIMEOUT);\r
717\r
718 return CheckErrorStatus (IdeDev);\r
719}\r
720\r
721EFI_STATUS\r
722CheckErrorStatus (\r
723 IN IDE_BLK_IO_DEV *IdeDev\r
724 )\r
725/*++\r
726 Name:\r
727 CheckErrorStatus\r
728\r
729\r
730 Purpose: \r
731 This function is used to analyze the Status Register and print out \r
732 some debug information and if there is ERR bit set in the Status\r
733 Register, the Error Register's value is also be parsed and print out.\r
734\r
735\r
736 Parameters:\r
737 IDE_BLK_IO_DEV IN *IdeDev\r
738 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
739 to record all the information of the IDE device.\r
740\r
741 Returns: \r
742 EFI_SUCCESS\r
743 No err information in the Status Register.\r
744\r
745 EFI_DEVICE_ERROR\r
746 Any err information in the Status Register.\r
747\r
748 Notes:\r
749--*/\r
750// TODO: function comment is missing 'Routine Description:'\r
751// TODO: function comment is missing 'Arguments:'\r
752// TODO: IdeDev - add argument and description to function comment\r
753{\r
754 UINT8 StatusRegister;\r
755\r
756//#ifdef EFI_DEBUG\r
757\r
758 UINT8 ErrorRegister;\r
759\r
760//#endif\r
761\r
762 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
763\r
764 DEBUG_CODE (\r
765\r
766 if (StatusRegister & DWF) {\r
767 DEBUG (\r
768 (EFI_D_BLKIO,\r
769 "CheckErrorStatus()-- %02x : Error : Write Fault\n",\r
770 StatusRegister)\r
771 );\r
772 }\r
773\r
774 if (StatusRegister & CORR) {\r
775 DEBUG (\r
776 (EFI_D_BLKIO,\r
777 "CheckErrorStatus()-- %02x : Error : Corrected Data\n",\r
778 StatusRegister)\r
779 );\r
780 }\r
781\r
782 if (StatusRegister & ERR) {\r
783 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
784\r
785 if (ErrorRegister & BBK_ERR) {\r
786 DEBUG (\r
787 (EFI_D_BLKIO,\r
788 "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",\r
789 ErrorRegister)\r
790 );\r
791 }\r
792\r
793 if (ErrorRegister & UNC_ERR) {\r
794 DEBUG (\r
795 (EFI_D_BLKIO,\r
796 "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",\r
797 ErrorRegister)\r
798 );\r
799 }\r
800\r
801 if (ErrorRegister & MC_ERR) {\r
802 DEBUG (\r
803 (EFI_D_BLKIO,\r
804 "CheckErrorStatus()-- %02x : Error : Media Change\n",\r
805 ErrorRegister)\r
806 );\r
807 }\r
808\r
809 if (ErrorRegister & ABRT_ERR) {\r
810 DEBUG (\r
811 (EFI_D_BLKIO,\r
812 "CheckErrorStatus()-- %02x : Error : Abort\n",\r
813 ErrorRegister)\r
814 );\r
815 }\r
816\r
817 if (ErrorRegister & TK0NF_ERR) {\r
818 DEBUG (\r
819 (EFI_D_BLKIO,\r
820 "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",\r
821 ErrorRegister)\r
822 );\r
823 }\r
824\r
825 if (ErrorRegister & AMNF_ERR) {\r
826 DEBUG (\r
827 (EFI_D_BLKIO,\r
828 "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",\r
829 ErrorRegister)\r
830 );\r
831 }\r
832\r
833 }\r
834 );\r
835\r
836 if ((StatusRegister & (ERR | DWF | CORR)) == 0) {\r
837 return EFI_SUCCESS;\r
838 }\r
839\r
840 return EFI_DEVICE_ERROR;\r
841\r
842}\r
843\r
844EFI_STATUS\r
845AtaReadSectors (\r
846 IN IDE_BLK_IO_DEV *IdeDev,\r
847 IN VOID *DataBuffer,\r
848 IN EFI_LBA Lba,\r
849 IN UINTN NumberOfBlocks\r
850 )\r
851/*++\r
852 Name:\r
853 AtaReadSectors\r
854\r
855\r
856 Purpose: \r
857 This function is called by the AtaBlkIoReadBlocks() to perform\r
858 reading from media in block unit.\r
859\r
860\r
861 Parameters:\r
862 IDE_BLK_IO_DEV IN *IdeDev\r
863 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
864 to record all the information of the IDE device.\r
865\r
866 VOID IN *DataBuffer\r
867 A pointer to the destination buffer for the data. \r
868\r
869 EFI_LBA IN Lba\r
870 The starting logical block address to read from \r
871 on the device media.\r
872\r
873 UINTN IN NumberOfBlocks\r
874 The number of transfer data blocks.\r
875\r
876 Returns: \r
877 return status is fully dependent on the return status\r
878 of AtaPioDataIn() function.\r
879\r
880 Notes:\r
881--*/\r
882// TODO: function comment is missing 'Routine Description:'\r
883// TODO: function comment is missing 'Arguments:'\r
884// TODO: IdeDev - add argument and description to function comment\r
885// TODO: DataBuffer - add argument and description to function comment\r
886// TODO: Lba - add argument and description to function comment\r
887// TODO: NumberOfBlocks - add argument and description to function comment\r
888{\r
889 EFI_STATUS Status;\r
890 UINTN BlocksRemaining;\r
891 UINT32 Lba32;\r
892 UINT8 Lba0;\r
893 UINT8 Lba1;\r
894 UINT8 Lba2;\r
895 UINT8 Lba3;\r
896 UINT8 AtaCommand;\r
897 UINT8 SectorCount8;\r
898 UINT16 SectorCount;\r
899 UINTN ByteCount;\r
900 VOID *Buffer;\r
901\r
902 Buffer = DataBuffer;\r
903\r
904 //\r
905 // Using ATA Read Sector(s) command (opcode=0x20) with PIO DATA IN protocol\r
906 //\r
907 AtaCommand = READ_SECTORS_CMD;\r
908\r
909 \r
910 BlocksRemaining = NumberOfBlocks;\r
911\r
912 Lba32 = (UINT32) Lba;\r
913\r
914 Status = EFI_SUCCESS;\r
915\r
916 while (BlocksRemaining > 0) {\r
917 \r
918 //\r
919 // in ATA-3 spec, LBA is in 28 bit width\r
920 //\r
921 Lba0 = (UINT8) Lba32;\r
922 Lba1 = (UINT8) (Lba32 >> 8);\r
923 Lba2 = (UINT8) (Lba32 >> 16);\r
924 //\r
925 // low 4 bit of Lba3 stands for LBA bit24~bit27.\r
926 //\r
927 Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);\r
928\r
929 if (BlocksRemaining >= 0x100) {\r
930 \r
931 //\r
932 // SectorCount8 is sent to Sector Count register, 0x00 means 256\r
933 // sectors to be read\r
934 //\r
935 SectorCount8 = 0x00;\r
936 //\r
937 // SectorCount is used to record the number of sectors to be read\r
938 //\r
939 SectorCount = 256;\r
940 } else {\r
941\r
942 SectorCount8 = (UINT8) BlocksRemaining;\r
943 SectorCount = (UINT16) BlocksRemaining;\r
944 }\r
945\r
946 //\r
947 // ByteCount is the number of bytes that will be read\r
948 //\r
949 ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
950\r
951 //\r
952 // call AtaPioDataIn() to send Read Sector Command and receive data read\r
953 //\r
954 Status = AtaPioDataIn (\r
955 IdeDev,\r
956 Buffer,\r
957 (UINT32) ByteCount,\r
958 AtaCommand,\r
959 Lba3,\r
960 SectorCount8,\r
961 Lba0,\r
962 Lba1,\r
963 Lba2\r
964 );\r
965 if (EFI_ERROR (Status)) {\r
966 return Status;\r
967 }\r
968\r
969 Lba32 += SectorCount;\r
970 Buffer = ((UINT8 *) Buffer + ByteCount);\r
971 BlocksRemaining -= SectorCount;\r
972 }\r
973\r
974 return Status;\r
975}\r
976\r
977EFI_STATUS\r
978AtaWriteSectors (\r
979 IN IDE_BLK_IO_DEV *IdeDev,\r
980 IN VOID *BufferData,\r
981 IN EFI_LBA Lba,\r
982 IN UINTN NumberOfBlocks\r
983 )\r
984/*++\r
985 Name:\r
986 AtaWriteSectors\r
987\r
988\r
989 Purpose: \r
990 This function is called by the AtaBlkIoWriteBlocks() to perform\r
991 writing onto media in block unit.\r
992\r
993\r
994 Parameters:\r
995 IDE_BLK_IO_DEV IN *IdeDev\r
996 pointer pointing to IDE_BLK_IO_DEV data structure,used\r
997 to record all the information of the IDE device.\r
998\r
999 VOID IN *BufferData\r
1000 A pointer to the source buffer for the data. \r
1001\r
1002 EFI_LBA IN Lba\r
1003 The starting logical block address to write onto \r
1004 the device media.\r
1005\r
1006 UINTN IN NumberOfBlocks\r
1007 The number of transfer data blocks.\r
1008\r
1009\r
1010 Returns: \r
1011 return status is fully dependent on the return status\r
1012 of AtaPioDataOut() function.\r
1013\r
1014 Notes:\r
1015--*/\r
1016// TODO: function comment is missing 'Routine Description:'\r
1017// TODO: function comment is missing 'Arguments:'\r
1018// TODO: IdeDev - add argument and description to function comment\r
1019// TODO: BufferData - add argument and description to function comment\r
1020// TODO: Lba - add argument and description to function comment\r
1021// TODO: NumberOfBlocks - add argument and description to function comment\r
1022{\r
1023 EFI_STATUS Status;\r
1024 UINTN BlocksRemaining;\r
1025 UINT32 Lba32;\r
1026 UINT8 Lba0;\r
1027 UINT8 Lba1;\r
1028 UINT8 Lba2;\r
1029 UINT8 Lba3;\r
1030 UINT8 AtaCommand;\r
1031 UINT8 SectorCount8;\r
1032 UINT16 SectorCount;\r
1033 UINTN ByteCount;\r
1034 VOID *Buffer;\r
1035\r
1036 Buffer = BufferData;\r
1037\r
1038 //\r
1039 // Using Write Sector(s) command (opcode=0x30) with PIO DATA OUT protocol\r
1040 //\r
1041 AtaCommand = WRITE_SECTORS_CMD;\r
1042\r
1043 BlocksRemaining = NumberOfBlocks;\r
1044\r
1045 Lba32 = (UINT32) Lba;\r
1046\r
1047 Status = EFI_SUCCESS;\r
1048\r
1049 while (BlocksRemaining > 0) {\r
1050\r
1051 Lba0 = (UINT8) Lba32;\r
1052 Lba1 = (UINT8) (Lba32 >> 8);\r
1053 Lba2 = (UINT8) (Lba32 >> 16);\r
1054 Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);\r
1055\r
1056 if (BlocksRemaining >= 0x100) {\r
1057 \r
1058 //\r
1059 // SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors\r
1060 // to be written\r
1061 //\r
1062 SectorCount8 = 0x00;\r
1063 //\r
1064 // SectorCount is used to record the number of sectors to be written\r
1065 //\r
1066 SectorCount = 256;\r
1067 } else {\r
1068\r
1069 SectorCount8 = (UINT8) BlocksRemaining;\r
1070 SectorCount = (UINT16) BlocksRemaining;\r
1071 }\r
1072\r
1073 ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
1074\r
1075 Status = AtaPioDataOut (\r
1076 IdeDev,\r
1077 Buffer,\r
1078 (UINT32) ByteCount,\r
1079 AtaCommand,\r
1080 Lba3,\r
1081 SectorCount8,\r
1082 Lba0,\r
1083 Lba1,\r
1084 Lba2\r
1085 );\r
1086 if (EFI_ERROR (Status)) {\r
1087 return Status;\r
1088 }\r
1089\r
1090 Lba32 += SectorCount;\r
1091 Buffer = ((UINT8 *) Buffer + ByteCount);\r
1092 BlocksRemaining -= SectorCount;\r
1093 }\r
1094\r
1095 return Status;\r
1096}\r
1097\r
1098EFI_STATUS\r
1099AtaSoftReset (\r
1100 IN IDE_BLK_IO_DEV *IdeDev\r
1101 )\r
1102/*++\r
1103 Name:\r
1104 AtaSoftReset\r
1105\r
1106 Purpose: \r
1107 This function is used to implement the Soft Reset on the specified\r
1108 device. But, the ATA Soft Reset mechanism is so strong a reset method \r
1109 that it will force resetting on both devices connected to the \r
1110 same cable.\r
1111 It is called by IdeBlkIoReset(), a interface function of Block\r
1112 I/O protocol.\r
1113 This function can also be used by the ATAPI device to perform reset when\r
1114 ATAPI Reset command is failed.\r
1115 \r
1116 Parameters:\r
1117 IDE_BLK_IO_DEV IN *IdeDev\r
1118 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1119 to record all the information of the IDE device.\r
1120 Returns: \r
1121 EFI_SUCCESS\r
1122 Soft reset completes successfully.\r
1123\r
1124 EFI_DEVICE_ERROR\r
1125 Any step during the reset process is failed.\r
1126 Notes:\r
1127 The registers initial values after ATA soft reset are different\r
1128 to the ATA device and ATAPI device.\r
1129--*/\r
1130// TODO: function comment is missing 'Routine Description:'\r
1131// TODO: function comment is missing 'Arguments:'\r
1132// TODO: IdeDev - add argument and description to function comment\r
1133{\r
1134\r
1135 UINT8 DeviceControl;\r
1136\r
1137 DeviceControl = 0;\r
1138 //\r
1139 // set SRST bit to initiate soft reset\r
1140 //\r
1141 DeviceControl |= SRST;\r
1142\r
1143 //\r
1144 // disable Interrupt\r
1145 //\r
1146 DeviceControl |= bit1;\r
1147\r
1148 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
1149\r
1150 gBS->Stall (10);\r
1151\r
1152 //\r
1153 // Enable interrupt to support UDMA, and clear SRST bit\r
1154 //\r
1155 DeviceControl = 0;\r
1156 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
1157\r
1158 //\r
1159 // slave device needs at most 31s to clear BSY\r
1160 //\r
1161 if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) {\r
1162 return EFI_DEVICE_ERROR;\r
1163 }\r
1164\r
1165 return EFI_SUCCESS;\r
1166}\r
1167\r
1168EFI_STATUS\r
1169AtaBlkIoReadBlocks (\r
1170 IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
1171 IN UINT32 MediaId,\r
1172 IN EFI_LBA LBA,\r
1173 IN UINTN BufferSize,\r
1174 OUT VOID *Buffer\r
1175 )\r
1176/*++\r
1177 Name:\r
1178 AtaBlkIoReadBlocks\r
1179\r
1180\r
1181 Purpose: \r
1182 This function is the ATA implementation for ReadBlocks in the\r
1183 Block I/O Protocol interface.\r
1184\r
1185\r
1186 Parameters:\r
1187 IDE_BLK_IO_DEV IN *IdeBlkIoDevice\r
1188 Indicates the calling context.\r
1189\r
1190 UINT32 IN MediaId\r
1191 The media id that the read request is for.\r
1192\r
1193 EFI_LBA IN LBA\r
1194 The starting logical block address to read from \r
1195 on the device.\r
1196\r
1197 UINTN IN BufferSize\r
1198 The size of the Buffer in bytes. This must be a\r
1199 multiple of the intrinsic block size of the device.\r
1200\r
1201 VOID OUT *Buffer\r
1202 A pointer to the destination buffer for the data. \r
1203 The caller is responsible for either having implicit\r
1204 or explicit ownership of the memory that data is read into.\r
1205\r
1206 Returns: \r
1207 EFI_SUCCESS \r
1208 Read Blocks successfully.\r
1209\r
1210 EFI_DEVICE_ERROR\r
1211 Read Blocks failed.\r
1212\r
1213 EFI_NO_MEDIA\r
1214 There is no media in the device.\r
1215\r
1216 EFI_MEDIA_CHANGE\r
1217 The MediaId is not for the current media.\r
1218\r
1219 EFI_BAD_BUFFER_SIZE\r
1220 The BufferSize parameter is not a multiple of the \r
1221 intrinsic block size of the device.\r
1222\r
1223 EFI_INVALID_PARAMETER\r
1224 The read request contains LBAs that are not valid,\r
1225 or the data buffer is not valid.\r
1226\r
1227 Notes:\r
1228 If Read Block error because of device error, this function will call\r
1229 AtaSoftReset() function to reset device.\r
1230--*/\r
1231// TODO: function comment is missing 'Routine Description:'\r
1232// TODO: function comment is missing 'Arguments:'\r
1233// TODO: IdeBlkIoDevice - add argument and description to function comment\r
1234// TODO: MediaId - add argument and description to function comment\r
1235// TODO: LBA - add argument and description to function comment\r
1236// TODO: BufferSize - add argument and description to function comment\r
1237// TODO: Buffer - add argument and description to function comment\r
1238// TODO: EFI_MEDIA_CHANGED - add return value to function comment\r
1239{\r
1240 EFI_BLOCK_IO_MEDIA *Media;\r
1241 UINTN BlockSize;\r
1242 UINTN NumberOfBlocks;\r
1243 EFI_STATUS Status;\r
1244\r
1245 if (Buffer == NULL) {\r
1246 return EFI_INVALID_PARAMETER;\r
1247 }\r
1248\r
1249 if (BufferSize == 0) {\r
1250 return EFI_SUCCESS;\r
1251 }\r
1252\r
1253 Status = EFI_SUCCESS;\r
1254\r
1255 //\r
1256 // Get the intrinsic block size\r
1257 //\r
1258 Media = IdeBlkIoDevice->BlkIo.Media;\r
1259 BlockSize = Media->BlockSize;\r
1260\r
1261 NumberOfBlocks = BufferSize / BlockSize;\r
1262\r
1263 if (MediaId != Media->MediaId) {\r
1264 return EFI_MEDIA_CHANGED;\r
1265 }\r
1266\r
1267 if (BufferSize % BlockSize != 0) {\r
1268 return EFI_BAD_BUFFER_SIZE;\r
1269 }\r
1270\r
1271 if (!(Media->MediaPresent)) {\r
1272 return EFI_NO_MEDIA;\r
1273 }\r
1274\r
1275 if (LBA > Media->LastBlock) {\r
1276 return EFI_INVALID_PARAMETER;\r
1277 }\r
1278\r
1279 if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
1280 return EFI_INVALID_PARAMETER;\r
1281 }\r
1282\r
1283 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
1284 return EFI_INVALID_PARAMETER;\r
1285 }\r
1286\r
1287 if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
1288 //\r
1289 // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism\r
1290 //\r
1291 Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
1292 if (EFI_ERROR (Status)) {\r
1293 Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
1294 }\r
1295 } else {\r
1296 //\r
1297 // For ATA-3 compatible device, use ATA-3 read block mechanism\r
1298 // Notice DMA operation can only handle 32bit address\r
1299 //\r
1300 if ((UINTN) Buffer <= 0xFFFFFFFF) {\r
1301 Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
1302 }\r
1303\r
1304 if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) {\r
1305 Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
1306 }\r
1307 }\r
1308\r
1309 if (EFI_ERROR (Status)) {\r
1310 AtaSoftReset (IdeBlkIoDevice);\r
1311 return EFI_DEVICE_ERROR;\r
1312 }\r
1313\r
1314 return EFI_SUCCESS;\r
1315\r
1316}\r
1317\r
1318EFI_STATUS\r
1319AtaBlkIoWriteBlocks (\r
1320 IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
1321 IN UINT32 MediaId,\r
1322 IN EFI_LBA LBA,\r
1323 IN UINTN BufferSize,\r
1324 OUT VOID *Buffer\r
1325 )\r
1326/*++\r
1327 Name:\r
1328 AtaBlkIoWriteBlocks\r
1329\r
1330\r
1331 Purpose: \r
1332 This function is the ATA implementation for WriteBlocks in the\r
1333 Block I/O Protocol interface.\r
1334\r
1335 Parameters:\r
1336 IDE_BLK_IO_DEV IN *IdeBlkIoDevice\r
1337 Indicates the calling context.\r
1338\r
1339 UINT32 IN MediaId\r
1340 The media id that the write request is for.\r
1341\r
1342 EFI_LBA IN LBA\r
1343 The starting logical block address to write onto \r
1344 the device.\r
1345\r
1346 UINTN IN BufferSize\r
1347 The size of the Buffer in bytes. This must be a\r
1348 multiple of the intrinsic block size of the device.\r
1349\r
1350 VOID OUT *Buffer\r
1351 A pointer to the source buffer for the data. \r
1352 The caller is responsible for either having implicit\r
1353 or explicit ownership of the memory that data is \r
1354 written from.\r
1355\r
1356\r
1357 Returns: \r
1358 EFI_SUCCESS \r
1359 Write Blocks successfully.\r
1360\r
1361 EFI_DEVICE_ERROR\r
1362 Write Blocks failed.\r
1363\r
1364 EFI_NO_MEDIA\r
1365 There is no media in the device.\r
1366\r
1367 EFI_MEDIA_CHANGE\r
1368 The MediaId is not for the current media.\r
1369\r
1370 EFI_BAD_BUFFER_SIZE\r
1371 The BufferSize parameter is not a multiple of the \r
1372 intrinsic block size of the device.\r
1373\r
1374 EFI_INVALID_PARAMETER\r
1375 The write request contains LBAs that are not valid,\r
1376 or the data buffer is not valid.\r
1377\r
1378 Notes:\r
1379 If Write Block error because of device error, this function will call\r
1380 AtaSoftReset() function to reset device.\r
1381--*/\r
1382// TODO: function comment is missing 'Routine Description:'\r
1383// TODO: function comment is missing 'Arguments:'\r
1384// TODO: IdeBlkIoDevice - add argument and description to function comment\r
1385// TODO: MediaId - add argument and description to function comment\r
1386// TODO: LBA - add argument and description to function comment\r
1387// TODO: BufferSize - add argument and description to function comment\r
1388// TODO: Buffer - add argument and description to function comment\r
1389// TODO: EFI_MEDIA_CHANGED - add return value to function comment\r
1390{\r
1391\r
1392 EFI_BLOCK_IO_MEDIA *Media;\r
1393 UINTN BlockSize;\r
1394 UINTN NumberOfBlocks;\r
1395 EFI_STATUS Status;\r
1396\r
1397 if (Buffer == NULL) {\r
1398 return EFI_INVALID_PARAMETER;\r
1399 }\r
1400\r
1401 if (BufferSize == 0) {\r
1402 return EFI_SUCCESS;\r
1403 }\r
1404\r
1405 Status = EFI_SUCCESS;\r
1406\r
1407 //\r
1408 // Get the intrinsic block size\r
1409 //\r
1410 Media = IdeBlkIoDevice->BlkIo.Media;\r
1411 BlockSize = Media->BlockSize;\r
1412 NumberOfBlocks = BufferSize / BlockSize;\r
1413\r
1414 if (MediaId != Media->MediaId) {\r
1415 return EFI_MEDIA_CHANGED;\r
1416 }\r
1417\r
1418 if (BufferSize % BlockSize != 0) {\r
1419 return EFI_BAD_BUFFER_SIZE;\r
1420 }\r
1421\r
1422 if (LBA > Media->LastBlock) {\r
1423 return EFI_INVALID_PARAMETER;\r
1424 }\r
1425\r
1426 if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
1427 return EFI_INVALID_PARAMETER;\r
1428 }\r
1429\r
1430 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
1431 return EFI_INVALID_PARAMETER;\r
1432 }\r
1433\r
1434 if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
1435 //\r
1436 // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism\r
1437 //\r
1438 Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
1439 if (EFI_ERROR (Status)) {\r
1440 Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
1441 }\r
1442 } else {\r
1443 //\r
1444 // For ATA-3 compatible device, use ATA-3 write block mechanism\r
1445 //\r
1446 Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
1447 if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) {\r
1448 Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
1449 }\r
1450 }\r
1451\r
1452 if (EFI_ERROR (Status)) {\r
1453 AtaSoftReset (IdeBlkIoDevice);\r
1454 return EFI_DEVICE_ERROR;\r
1455 }\r
1456\r
1457 return EFI_SUCCESS;\r
1458}\r
1459\r
1460EFI_STATUS\r
1461AtaReadSectorsExt (\r
1462 IN IDE_BLK_IO_DEV *IdeDev,\r
1463 IN VOID *DataBuffer,\r
1464 IN EFI_LBA StartLba,\r
1465 IN UINTN NumberOfBlocks\r
1466 )\r
1467/*++\r
1468 Name:\r
1469 \r
1470 AtaReadSectorsExt\r
1471\r
1472 Purpose: \r
1473 \r
1474 This function is called by the AtaBlkIoReadBlocks() to perform\r
1475 reading from media in block unit. The function has been enhanced to \r
1476 support >120GB access and transfer at most 65536 blocks per command\r
1477\r
1478 Parameters:\r
1479 \r
1480 IDE_BLK_IO_DEV IN *IdeDev\r
1481 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1482 to record all the information of the IDE device.\r
1483\r
1484 VOID IN *DataBuffer\r
1485 A pointer to the destination buffer for the data. \r
1486\r
1487 EFI_LBA IN StartLba\r
1488 The starting logical block address to read from \r
1489 on the device media.\r
1490\r
1491 UINTN IN NumberOfBlocks\r
1492 The number of transfer data blocks.\r
1493\r
1494 Returns: \r
1495 \r
1496 return status is fully dependent on the return status\r
1497 of AtaPioDataInExt() function.\r
1498\r
1499 Notes:\r
1500--*/\r
1501// TODO: function comment is missing 'Routine Description:'\r
1502// TODO: function comment is missing 'Arguments:'\r
1503// TODO: IdeDev - add argument and description to function comment\r
1504// TODO: DataBuffer - add argument and description to function comment\r
1505// TODO: StartLba - add argument and description to function comment\r
1506// TODO: NumberOfBlocks - add argument and description to function comment\r
1507{\r
1508 EFI_STATUS Status;\r
1509 UINTN BlocksRemaining;\r
1510 EFI_LBA Lba64;\r
1511 UINT8 AtaCommand;\r
1512 UINT16 SectorCount;\r
1513 UINT32 ByteCount;\r
1514 VOID *Buffer;\r
1515\r
1516 //\r
1517 // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol\r
1518 //\r
1519 AtaCommand = READ_SECTORS_EXT_CMD;\r
1520 Buffer = DataBuffer;\r
1521 BlocksRemaining = NumberOfBlocks;\r
1522 Lba64 = StartLba;\r
1523 Status = EFI_SUCCESS;\r
1524\r
1525 while (BlocksRemaining > 0) {\r
1526\r
1527 if (BlocksRemaining >= 0x10000) {\r
1528 //\r
1529 // SectorCount is used to record the number of sectors to be read\r
1530 // Max 65536 sectors can be transfered at a time.\r
1531 //\r
1532 SectorCount = 0xffff;\r
1533 } else {\r
1534 SectorCount = (UINT16) BlocksRemaining;\r
1535 }\r
1536\r
1537 //\r
1538 // ByteCount is the number of bytes that will be read\r
1539 //\r
1540 ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
1541\r
1542 //\r
1543 // call AtaPioDataInExt() to send Read Sector Command and receive data read\r
1544 //\r
1545 Status = AtaPioDataInExt (\r
1546 IdeDev,\r
1547 Buffer,\r
1548 ByteCount,\r
1549 AtaCommand,\r
1550 Lba64,\r
1551 SectorCount\r
1552 );\r
1553 if (EFI_ERROR (Status)) {\r
1554 return Status;\r
1555 }\r
1556\r
1557 Lba64 += SectorCount;\r
1558 Buffer = ((UINT8 *) Buffer + ByteCount);\r
1559 BlocksRemaining -= SectorCount;\r
1560 }\r
1561\r
1562 return Status;\r
1563}\r
1564\r
1565EFI_STATUS\r
1566AtaWriteSectorsExt (\r
1567 IN IDE_BLK_IO_DEV *IdeDev,\r
1568 IN VOID *DataBuffer,\r
1569 IN EFI_LBA StartLba,\r
1570 IN UINTN NumberOfBlocks\r
1571 )\r
1572/*++\r
1573 Name:\r
1574 \r
1575 AtaWriteSectorsExt\r
1576\r
1577 Purpose: \r
1578 \r
1579 This function is called by the AtaBlkIoWriteBlocks() to perform\r
1580 writing onto media in block unit. The function has been enhanced to \r
1581 support >120GB access and transfer at most 65536 blocks per command\r
1582\r
1583 Parameters:\r
1584 \r
1585 IDE_BLK_IO_DEV IN *IdeDev\r
1586 pointer pointing to IDE_BLK_IO_DEV data structure,used\r
1587 to record all the information of the IDE device.\r
1588\r
1589 VOID IN *DataBuffer\r
1590 A pointer to the source buffer for the data. \r
1591\r
1592 EFI_LBA IN Lba\r
1593 The starting logical block address to write onto \r
1594 the device media.\r
1595\r
1596 UINTN IN NumberOfBlocks\r
1597 The number of transfer data blocks.\r
1598\r
1599 Returns: \r
1600 \r
1601 return status is fully dependent on the return status\r
1602 of AtaPioDataOutExt() function.\r
1603\r
1604 Notes:\r
1605--*/\r
1606// TODO: function comment is missing 'Routine Description:'\r
1607// TODO: function comment is missing 'Arguments:'\r
1608// TODO: IdeDev - add argument and description to function comment\r
1609// TODO: DataBuffer - add argument and description to function comment\r
1610// TODO: StartLba - add argument and description to function comment\r
1611// TODO: NumberOfBlocks - add argument and description to function comment\r
1612{\r
1613 EFI_STATUS Status;\r
1614 EFI_LBA Lba64;\r
1615 UINTN BlocksRemaining;\r
1616 UINT8 AtaCommand;\r
1617 UINT16 SectorCount;\r
1618 UINT32 ByteCount;\r
1619 VOID *Buffer;\r
1620\r
1621 //\r
1622 // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol\r
1623 //\r
1624 AtaCommand = WRITE_SECTORS_EXT_CMD;\r
1625 Lba64 = StartLba;\r
1626 Buffer = DataBuffer;\r
1627 BlocksRemaining = NumberOfBlocks;\r
1628\r
1629 Status = EFI_SUCCESS;\r
1630\r
1631 while (BlocksRemaining > 0) {\r
1632\r
1633 if (BlocksRemaining >= 0x10000) {\r
1634 //\r
1635 // SectorCount is used to record the number of sectors to be written.\r
1636 // Max 65536 sectors can be transfered at a time.\r
1637 //\r
1638 SectorCount = 0xffff;\r
1639 } else {\r
1640 SectorCount = (UINT16) BlocksRemaining;\r
1641 }\r
1642\r
1643 //\r
1644 // ByteCount is the number of bytes that will be written\r
1645 //\r
1646 ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
1647\r
1648 //\r
1649 // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command\r
1650 //\r
1651 Status = AtaPioDataOutExt (\r
1652 IdeDev,\r
1653 Buffer,\r
1654 ByteCount,\r
1655 AtaCommand,\r
1656 Lba64,\r
1657 SectorCount\r
1658 );\r
1659 if (EFI_ERROR (Status)) {\r
1660 return Status;\r
1661 }\r
1662\r
1663 Lba64 += SectorCount;\r
1664 Buffer = ((UINT8 *) Buffer + ByteCount);\r
1665 BlocksRemaining -= SectorCount;\r
1666 }\r
1667\r
1668 return Status;\r
1669}\r
1670\r
1671EFI_STATUS\r
1672AtaPioDataInExt (\r
1673 IN IDE_BLK_IO_DEV *IdeDev,\r
1674 IN OUT VOID *Buffer,\r
1675 IN UINT32 ByteCount,\r
1676 IN UINT8 AtaCommand,\r
1677 IN EFI_LBA StartLba,\r
1678 IN UINT16 SectorCount\r
1679 )\r
1680/*++\r
1681 Name:\r
1682 \r
1683 AtaPioDataInExt\r
1684\r
1685 Purpose: \r
1686 \r
1687 This function is used to send out ATA commands conforms to the \r
1688 PIO Data In Protocol, supporting ATA/ATAPI-6 standard\r
1689\r
1690 Comparing with ATA-3 data in protocol, we have two differents here:\r
1691 1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
1692 wait will frequently fail... cause writing function return error)\r
1693 \r
1694 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly \r
1695 slow down writing performance by 100 times!)\r
1696\r
1697\r
1698 Parameters:\r
1699 \r
1700 IDE_BLK_IO_DEV IN *IdeDev\r
1701 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1702 to record all the information of the IDE device.\r
1703\r
1704 VOID IN OUT *Buffer\r
1705 buffer contained data transferred from device to host.\r
1706\r
1707 UINT32 IN ByteCount\r
1708 data size in byte unit of the buffer.\r
1709\r
1710 UINT8 IN AtaCommand\r
1711 value of the Command Register\r
1712\r
1713 EFI_LBA IN StartLba\r
1714 the start LBA of this transaction\r
1715 \r
1716 UINT16 IN SectorCount\r
1717 the count of sectors to be transfered\r
1718\r
1719 Returns: \r
1720 \r
1721 EFI_SUCCESS\r
1722 send out the ATA command and device send required\r
1723 data successfully.\r
1724\r
1725 EFI_DEVICE_ERROR\r
1726 command sent failed.\r
1727 Notes:\r
1728--*/\r
1729// TODO: function comment is missing 'Routine Description:'\r
1730// TODO: function comment is missing 'Arguments:'\r
1731// TODO: IdeDev - add argument and description to function comment\r
1732// TODO: Buffer - add argument and description to function comment\r
1733// TODO: ByteCount - add argument and description to function comment\r
1734// TODO: AtaCommand - add argument and description to function comment\r
1735// TODO: StartLba - add argument and description to function comment\r
1736// TODO: SectorCount - add argument and description to function comment\r
1737{\r
1738 UINT8 DevSel;\r
1739 UINT8 SectorCount8;\r
1740 UINT8 LbaLow;\r
1741 UINT8 LbaMid;\r
1742 UINT8 LbaHigh;\r
1743 UINTN WordCount;\r
1744 UINTN Increment;\r
1745 UINT16 *Buffer16;\r
1746 EFI_STATUS Status;\r
1747\r
1748 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1749 if (EFI_ERROR (Status)) {\r
1750 return EFI_DEVICE_ERROR;\r
1751 }\r
1752\r
1753 //\r
1754 // Select device, set bit6 as 1 to indicate LBA mode is used\r
1755 //\r
1756 DevSel = (UINT8) (IdeDev->Device << 4);\r
1757 DevSel |= 0x40;\r
1758 IDEWritePortB (\r
1759 IdeDev->PciIo,\r
1760 IdeDev->IoPort->Head,\r
1761 DevSel\r
1762 );\r
1763\r
1764 //\r
1765 // Wait for DRDY singnal asserting. ATAPI device needn't wait\r
1766 //\r
1767 if ( (IdeDev->Type == IdeHardDisk) ||\r
1768 (IdeDev->Type == Ide48bitAddressingHardDisk)) {\r
1769\r
1770 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
1771 if (EFI_ERROR (Status)) {\r
1772 return EFI_DEVICE_ERROR;\r
1773 }\r
1774 }\r
1775\r
1776 //\r
1777 // Fill feature register if needed\r
1778 //\r
1779 if (AtaCommand == SET_FEATURES_CMD) {\r
1780 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
1781 }\r
1782\r
1783 //\r
1784 // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
1785 //\r
1786 SectorCount8 = (UINT8) (SectorCount >> 8);\r
1787 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
1788\r
1789 SectorCount8 = (UINT8) SectorCount;\r
1790 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
1791\r
1792 //\r
1793 // Fill the start LBA registers, which are also two-byte FIFO\r
1794 //\r
1795 LbaLow = (UINT8) RShiftU64 (StartLba, 24);\r
1796 LbaMid = (UINT8) RShiftU64 (StartLba, 32);\r
1797 LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
1798 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1799 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
1800 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1801\r
1802 LbaLow = (UINT8) StartLba;\r
1803 LbaMid = (UINT8) RShiftU64 (StartLba, 8);\r
1804 LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
1805 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1806 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
1807 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1808\r
1809 //\r
1810 // Send command via Command Register, invoking the processing of this command\r
1811 //\r
1812 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
1813\r
1814 Buffer16 = (UINT16 *) Buffer;\r
1815\r
1816 //\r
1817 // According to PIO data in protocol, host can perform a series of reads to\r
1818 // the data register after each time device set DRQ ready;\r
1819 //\r
1820 \r
1821 //\r
1822 // 256 words\r
1823 //\r
1824 Increment = 256;\r
1825\r
1826 //\r
1827 // used to record bytes of currently transfered data\r
1828 //\r
1829 WordCount = 0;\r
1830\r
1831 while (WordCount < ByteCount / 2) {\r
1832 //\r
1833 // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
1834 //\r
1835 Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
1836 if (EFI_ERROR (Status)) {\r
1837 return EFI_DEVICE_ERROR;\r
1838 }\r
1839\r
1840 Status = CheckErrorStatus (IdeDev);\r
1841 if (EFI_ERROR (Status)) {\r
1842 return EFI_DEVICE_ERROR;\r
1843 }\r
1844\r
1845 //\r
1846 // Get the byte count for one series of read\r
1847 //\r
1848 if ((WordCount + Increment) > ByteCount / 2) {\r
1849 Increment = ByteCount / 2 - WordCount;\r
1850 }\r
1851\r
1852 IDEReadPortWMultiple (\r
1853 IdeDev->PciIo,\r
1854 IdeDev->IoPort->Data,\r
1855 Increment,\r
1856 Buffer16\r
1857 );\r
1858\r
1859 WordCount += Increment;\r
1860 Buffer16 += Increment;\r
1861\r
1862 }\r
1863\r
1864 return CheckErrorStatus (IdeDev);\r
1865}\r
1866\r
1867EFI_STATUS\r
1868AtaPioDataOutExt (\r
1869 IN IDE_BLK_IO_DEV *IdeDev,\r
1870 IN VOID *Buffer,\r
1871 IN UINT32 ByteCount,\r
1872 IN UINT8 AtaCommand,\r
1873 IN EFI_LBA StartLba,\r
1874 IN UINT16 SectorCount\r
1875 )\r
1876/*++\r
1877 Name:\r
1878 \r
1879 AtaPioDataOutExt\r
1880\r
1881 Purpose: \r
1882 \r
1883 This function is used to send out ATA commands conforms to the \r
1884 PIO Data Out Protocol, supporting ATA/ATAPI-6 standard\r
1885\r
1886 Comparing with ATA-3 data out protocol, we have two differents here:\r
1887 1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
1888 wait will frequently fail... cause writing function return error)\r
1889 \r
1890 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly \r
1891 slow down writing performance by 100 times!)\r
1892\r
1893 Parameters:\r
1894 \r
1895 IDE_BLK_IO_DEV IN *IdeDev\r
1896 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1897 to record all the information of the IDE device.\r
1898\r
1899 VOID IN *Buffer\r
1900 buffer contained data transferred from host to device.\r
1901\r
1902 UINT32 IN ByteCount\r
1903 data size in byte unit of the buffer.\r
1904\r
1905 UINT8 IN AtaCommand\r
1906 value of the Command Register\r
1907\r
1908 EFI_LBA IN StartLba\r
1909 the start LBA of this transaction\r
1910 \r
1911 UINT16 IN SectorCount\r
1912 the count of sectors to be transfered\r
1913\r
1914 Returns: \r
1915 \r
1916 EFI_SUCCESS\r
1917 send out the ATA command and device receive required\r
1918 data successfully.\r
1919\r
1920 EFI_DEVICE_ERROR\r
1921 command sent failed.\r
1922 Notes:\r
1923--*/\r
1924// TODO: function comment is missing 'Routine Description:'\r
1925// TODO: function comment is missing 'Arguments:'\r
1926// TODO: IdeDev - add argument and description to function comment\r
1927// TODO: Buffer - add argument and description to function comment\r
1928// TODO: ByteCount - add argument and description to function comment\r
1929// TODO: AtaCommand - add argument and description to function comment\r
1930// TODO: StartLba - add argument and description to function comment\r
1931// TODO: SectorCount - add argument and description to function comment\r
1932{\r
1933 UINT8 DevSel;\r
1934 UINT8 SectorCount8;\r
1935 UINT8 LbaLow;\r
1936 UINT8 LbaMid;\r
1937 UINT8 LbaHigh;\r
1938 UINTN WordCount;\r
1939 UINTN Increment;\r
1940 UINT16 *Buffer16;\r
1941 EFI_STATUS Status;\r
1942\r
1943 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1944 if (EFI_ERROR (Status)) {\r
1945 return EFI_DEVICE_ERROR;\r
1946 }\r
1947\r
1948 //\r
1949 // Select device. Set bit6 as 1 to indicate LBA mode is used\r
1950 //\r
1951 DevSel = (UINT8) (IdeDev->Device << 4);\r
1952 DevSel |= 0x40;\r
1953 IDEWritePortB (\r
1954 IdeDev->PciIo,\r
1955 IdeDev->IoPort->Head,\r
1956 DevSel\r
1957 );\r
1958\r
1959 //\r
1960 // Wait for DRDY singnal asserting.\r
1961 //\r
1962 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
1963 if (EFI_ERROR (Status)) {\r
1964 return EFI_DEVICE_ERROR;\r
1965 }\r
1966 \r
1967 //\r
1968 // Fill feature register if needed\r
1969 //\r
1970 if (AtaCommand == SET_FEATURES_CMD) {\r
1971 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
1972 }\r
1973\r
1974 //\r
1975 // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
1976 //\r
1977 SectorCount8 = (UINT8) (SectorCount >> 8);\r
1978 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
1979\r
1980 SectorCount8 = (UINT8) SectorCount;\r
1981 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
1982\r
1983 //\r
1984 // Fill the start LBA registers, which are also two-byte FIFO\r
1985 //\r
1986 LbaLow = (UINT8) RShiftU64 (StartLba, 24);\r
1987 LbaMid = (UINT8) RShiftU64 (StartLba, 32);\r
1988 LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
1989 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1990 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
1991 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1992\r
1993 LbaLow = (UINT8) StartLba;\r
1994 LbaMid = (UINT8) RShiftU64 (StartLba, 8);\r
1995 LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
1996 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1997 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
1998 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1999\r
2000 //\r
2001 // Send command via Command Register, invoking the processing of this command\r
2002 //\r
2003 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
2004\r
2005 Buffer16 = (UINT16 *) Buffer;\r
2006\r
2007 //\r
2008 // According to PIO Data Out protocol, host can perform a series of writes to\r
2009 // the data register after each time device set DRQ ready;\r
2010 //\r
2011 Increment = 256;\r
2012\r
2013 //\r
2014 // used to record bytes of currently transfered data\r
2015 //\r
2016 WordCount = 0;\r
2017\r
2018 while (WordCount < ByteCount / 2) {\r
2019 //\r
2020 // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
2021 //\r
2022 Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
2023 if (EFI_ERROR (Status)) {\r
2024 return EFI_DEVICE_ERROR;\r
2025 }\r
2026\r
2027 Status = CheckErrorStatus (IdeDev);\r
2028 if (EFI_ERROR (Status)) {\r
2029 return EFI_DEVICE_ERROR;\r
2030 }\r
2031\r
2032 //\r
2033 // Write data into device by one series of writing to data register\r
2034 //\r
2035 if ((WordCount + Increment) > ByteCount / 2) {\r
2036 Increment = ByteCount / 2 - WordCount;\r
2037 }\r
2038\r
2039 IDEWritePortWMultiple (\r
2040 IdeDev->PciIo,\r
2041 IdeDev->IoPort->Data,\r
2042 Increment,\r
2043 Buffer16\r
2044 );\r
2045\r
2046 WordCount += Increment;\r
2047 Buffer16 += Increment;\r
2048\r
2049 }\r
2050 //\r
2051 // while\r
2052 //\r
2053\r
2054 return CheckErrorStatus (IdeDev);\r
2055}\r
2056\r
2057\r
2058VOID\r
2059AtaSMARTSupport (\r
2060 IN IDE_BLK_IO_DEV *IdeDev\r
2061 )\r
2062/*++\r
2063 Name: \r
2064 AtaSMARTSupport\r
2065\r
2066 Purpose: \r
2067\r
2068 Enable SMART of the disk if supported\r
2069\r
2070 Parameters:\r
2071 \r
2072 IDE_BLK_IO_DEV IN *IdeDev\r
2073 pointer pointing to IDE_BLK_IO_DEV data structure,used\r
2074 to record all the information of the IDE device.\r
2075\r
2076 Returns: \r
2077 \r
2078 NONE\r
2079--*/\r
2080// TODO: function comment is missing 'Routine Description:'\r
2081// TODO: function comment is missing 'Arguments:'\r
2082// TODO: IdeDev - add argument and description to function comment\r
2083{\r
2084 EFI_STATUS Status;\r
2085 BOOLEAN SMARTSupported;\r
2086 UINT8 Device;\r
2087 EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;\r
2088 UINT8 DeviceSelect;\r
2089 UINT8 LBAMid;\r
2090 UINT8 LBAHigh;\r
2091\r
2092 //\r
2093 // Detect if the device supports S.M.A.R.T.\r
2094 //\r
2095 if ((IdeDev->pIdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {\r
2096 //\r
2097 // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)\r
2098 //\r
2099 return ;\r
2100 } else {\r
2101 if ((IdeDev->pIdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
2102 //\r
2103 // S.M.A.R.T is not supported by the device\r
2104 //\r
2105 SMARTSupported = FALSE;\r
2106 } else {\r
2107 SMARTSupported = TRUE;\r
2108 }\r
2109 }\r
2110\r
2111 if (!SMARTSupported) {\r
2112 //\r
2113 // Report nonsupport status code\r
2114 //\r
2115 REPORT_STATUS_CODE (\r
2116 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
2117 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
2118 );\r
2119 } else {\r
2120 //\r
2121 // Enable this feature\r
2122 //\r
2123 REPORT_STATUS_CODE (\r
2124 EFI_PROGRESS_CODE,\r
2125 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
2126 );\r
2127\r
2128 Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
2129 Status = AtaNonDataCommandIn (\r
2130 IdeDev,\r
2131 ATA_SMART_CMD,\r
2132 Device,\r
2133 ATA_SMART_ENABLE_OPERATION,\r
2134 0,\r
2135 0,\r
2136 ATA_CONSTANT_4F,\r
2137 ATA_CONSTANT_C2\r
2138 );\r
2139 //\r
2140 // Detect if this feature is enabled\r
2141 //\r
2142 TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
2143\r
2144 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
2145 Status = AtaPioDataIn (\r
2146 IdeDev,\r
2147 (VOID *) TmpAtaIdentifyPointer,\r
2148 sizeof (EFI_IDENTIFY_DATA),\r
2149 IDENTIFY_DRIVE_CMD,\r
2150 DeviceSelect,\r
2151 0,\r
2152 0,\r
2153 0,\r
2154 0\r
2155 );\r
2156 if (EFI_ERROR (Status)) {\r
2157 gBS->FreePool (TmpAtaIdentifyPointer);\r
2158 return ;\r
2159 }\r
2160\r
2161 //\r
2162 // Check if the feature is enabled\r
2163 //\r
2164 if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {\r
2165 //\r
2166 // Read status data\r
2167 //\r
2168 AtaNonDataCommandIn (\r
2169 IdeDev,\r
2170 ATA_SMART_CMD,\r
2171 Device,\r
2172 ATA_SMART_RETURN_STATUS,\r
2173 0,\r
2174 0,\r
2175 ATA_CONSTANT_4F,\r
2176 ATA_CONSTANT_C2\r
2177 );\r
2178 LBAMid = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r
2179 LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);\r
2180\r
2181 if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
2182 //\r
2183 // The threshold exceeded condition is not detected by the device\r
2184 //\r
2185 REPORT_STATUS_CODE (\r
2186 EFI_PROGRESS_CODE,\r
2187 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
2188 );\r
2189\r
2190 } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
2191 //\r
2192 // The threshold exceeded condition is detected by the device\r
2193 //\r
2194 REPORT_STATUS_CODE (\r
2195 EFI_PROGRESS_CODE,\r
2196 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
2197 );\r
2198 }\r
2199\r
2200 } else {\r
2201 //\r
2202 // Report disabled status code\r
2203 //\r
2204 REPORT_STATUS_CODE (\r
2205 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
2206 (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
2207 );\r
2208 }\r
2209\r
2210 gBS->FreePool (TmpAtaIdentifyPointer);\r
2211 }\r
2212\r
2213 return ;\r
2214}\r
2215\r
2216EFI_STATUS\r
2217AtaCommandIssueExt (\r
2218 IN IDE_BLK_IO_DEV *IdeDev,\r
2219 IN UINT8 AtaCommand,\r
2220 IN UINT8 Device,\r
2221 IN UINT16 Feature,\r
2222 IN UINT16 SectorCount,\r
2223 IN EFI_LBA LbaAddress\r
2224 )\r
2225/*++\r
2226\r
2227Routine Description:\r
2228\r
2229 Send ATA Ext command into device with NON_DATA protocol\r
2230\r
2231Arguments:\r
2232\r
2233 IdeDev - Standard IDE device private data structure\r
2234 AtaCommand - The ATA command to be sent\r
2235 Device - The value in Device register\r
2236 Feature - The value in Feature register\r
2237 SectorCount - The value in SectorCount register \r
2238 LbaAddress - The LBA address in 48-bit mode\r
2239\r
2240Returns:\r
2241\r
2242 EFI_SUCCESS - Reading succeed\r
2243 EFI_DEVICE_ERROR - Error executing commands on this device \r
2244\r
2245--*/\r
2246{\r
2247 EFI_STATUS Status;\r
2248 UINT8 SectorCount8;\r
2249 UINT8 Feature8;\r
2250 UINT8 LbaLow;\r
2251 UINT8 LbaMid;\r
2252 UINT8 LbaHigh;\r
2253\r
2254 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
2255 if (EFI_ERROR (Status)) {\r
2256 return EFI_DEVICE_ERROR;\r
2257 }\r
2258\r
2259 //\r
2260 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
2261 //\r
2262 IDEWritePortB (\r
2263 IdeDev->PciIo,\r
2264 IdeDev->IoPort->Head,\r
2265 (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
2266 );\r
2267\r
2268 //\r
2269 // ATA commands for ATA device must be issued when DRDY is set\r
2270 //\r
2271 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
2272 if (EFI_ERROR (Status)) {\r
2273 return EFI_DEVICE_ERROR;\r
2274 }\r
2275\r
2276 //\r
2277 // Pass parameter into device register block\r
2278 //\r
2279 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
2280\r
2281 //\r
2282 // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
2283 //\r
2284 Feature8 = (UINT8) (Feature >> 8);\r
2285 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
2286\r
2287 Feature8 = (UINT8) Feature;\r
2288 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
2289\r
2290 //\r
2291 // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
2292 //\r
2293 SectorCount8 = (UINT8) (SectorCount >> 8);\r
2294 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
2295\r
2296 SectorCount8 = (UINT8) SectorCount;\r
2297 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
2298\r
2299 //\r
2300 // Fill the start LBA registers, which are also two-byte FIFO\r
2301 //\r
2302 LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
2303 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
2304 LbaLow = (UINT8) LbaAddress;\r
2305 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
2306\r
2307 LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
2308 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
2309 LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
2310 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
2311\r
2312 LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
2313 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
2314 LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
2315 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
2316\r
2317 //\r
2318 // Work around for Segate 160G disk writing\r
2319 //\r
2320 gBS->Stall (1800);\r
2321\r
2322 //\r
2323 // Send command via Command Register\r
2324 //\r
2325 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
2326\r
2327 //\r
2328 // Stall at least 400ns\r
2329 //\r
2330 gBS->Stall (100);\r
2331\r
2332 return EFI_SUCCESS;\r
2333}\r
2334\r
2335EFI_STATUS\r
2336AtaCommandIssue (\r
2337 IN IDE_BLK_IO_DEV *IdeDev,\r
2338 IN UINT8 AtaCommand,\r
2339 IN UINT8 Device,\r
2340 IN UINT16 Feature,\r
2341 IN UINT16 SectorCount,\r
2342 IN EFI_LBA LbaAddress\r
2343 )\r
2344/*++\r
2345\r
2346Routine Description:\r
2347\r
2348 Send ATA Ext command into device with NON_DATA protocol\r
2349\r
2350Arguments:\r
2351\r
2352 IdeDev - Standard IDE device private data structure\r
2353 AtaCommand - The ATA command to be sent\r
2354 Device - The value in Device register\r
2355 Feature - The value in Feature register\r
2356 SectorCount - The value in SectorCount register \r
2357 LbaAddress - The LBA address in 48-bit mode\r
2358\r
2359Returns:\r
2360\r
2361 EFI_SUCCESS - Reading succeed\r
2362 EFI_DEVICE_ERROR - Error executing commands on this device \r
2363\r
2364--*/\r
2365{\r
2366 EFI_STATUS Status;\r
2367 UINT8 SectorCount8;\r
2368 UINT8 Feature8;\r
2369 UINT8 Lba0;\r
2370 UINT8 Lba1;\r
2371 UINT8 Lba2;\r
2372 UINT8 Lba3;\r
2373\r
2374 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
2375 if (EFI_ERROR (Status)) {\r
2376 return EFI_DEVICE_ERROR;\r
2377 }\r
2378\r
2379 //\r
2380 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
2381 //\r
2382 IDEWritePortB (\r
2383 IdeDev->PciIo,\r
2384 IdeDev->IoPort->Head,\r
2385 (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
2386 );\r
2387\r
2388 //\r
2389 // ATA commands for ATA device must be issued when DRDY is set\r
2390 //\r
2391 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
2392 if (EFI_ERROR (Status)) {\r
2393 return EFI_DEVICE_ERROR;\r
2394 }\r
2395\r
2396 Lba0 = (UINT8) LbaAddress;\r
2397 Lba1 = (UINT8) RShiftU64 (LbaAddress, 8);\r
2398 Lba2 = (UINT8) RShiftU64 (LbaAddress, 16);\r
2399 Lba3 = (UINT8) RShiftU64 (LbaAddress, 24);\r
2400 Device |= Lba3;\r
2401\r
2402 //\r
2403 // Pass parameter into device register block\r
2404 //\r
2405 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
2406\r
2407 //\r
2408 // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
2409 //\r
2410 Feature8 = (UINT8) Feature;\r
2411 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
2412\r
2413 //\r
2414 // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
2415 //\r
2416 SectorCount8 = (UINT8) SectorCount;\r
2417 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
2418\r
2419 //\r
2420 // Fill the start LBA registers, which are also two-byte FIFO\r
2421 //\r
2422 \r
2423 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);\r
2424 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);\r
2425 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);\r
2426\r
2427 //\r
2428 // Send command via Command Register\r
2429 //\r
2430 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
2431\r
2432 //\r
2433 // Stall at least 400ns\r
2434 //\r
2435 gBS->Stall (100);\r
2436\r
2437 return EFI_SUCCESS;\r
2438}\r
2439\r
2440EFI_STATUS\r
2441AtaUdmaReadExt (\r
2442 IN IDE_BLK_IO_DEV *IdeDev,\r
2443 IN VOID *DataBuffer,\r
2444 IN EFI_LBA StartLba,\r
2445 IN UINTN NumberOfBlocks\r
2446 )\r
2447/*++\r
2448 Name:\r
2449 \r
2450 AtaUdmaReadExt\r
2451\r
2452 Purpose: \r
2453 \r
2454 This function is called by the AtaBlkIoReadBlocks() to perform\r
2455 reading from media in block unit. The function has been enhanced to \r
2456 support >120GB access and transfer at most 65536 blocks per command\r
2457\r
2458 Parameters:\r
2459 \r
2460 IDE_BLK_IO_DEV IN *IdeDev\r
2461 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
2462 to record all the information of the IDE device.\r
2463\r
2464 VOID IN *DataBuffer\r
2465 A pointer to the destination buffer for the data. \r
2466\r
2467 EFI_LBA IN StartLba\r
2468 The starting logical block address to read from \r
2469 on the device media.\r
2470\r
2471 UINTN IN NumberOfBlocks\r
2472 The number of transfer data blocks.\r
2473\r
2474 Returns: \r
2475\r
2476 The device status of UDMA operation. If the operation is \r
2477 successful, return EFI_SUCCESS.\r
2478\r
2479--*/\r
2480// TODO: function comment is missing 'Routine Description:'\r
2481// TODO: function comment is missing 'Arguments:'\r
2482// TODO: IdeDev - add argument and description to function comment\r
2483// TODO: DataBuffer - add argument and description to function comment\r
2484// TODO: StartLba - add argument and description to function comment\r
2485// TODO: NumberOfBlocks - add argument and description to function comment\r
2486// TODO: EFI_UNSUPPORTED - add return value to function comment\r
2487// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
2488// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
2489// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
2490{\r
2491 IDE_DMA_PRD *PrdAddr;\r
2492 IDE_DMA_PRD *UsedPrdAddr;\r
2493 IDE_DMA_PRD *TempPrdAddr;\r
2494 UINT8 RegisterValue;\r
2495 UINT8 Device;\r
2496 UINT64 IoPortForBmic;\r
2497 UINT64 IoPortForBmis;\r
2498 UINT64 IoPortForBmid;\r
2499 EFI_STATUS Status;\r
2500 UINTN PrdTableNum;\r
2501 UINTN ByteCount;\r
2502 UINTN ByteAvailable;\r
2503 UINT8 *PrdBuffer;\r
2504 UINTN RemainBlockNum;\r
2505 UINT8 DeviceControl;\r
2506\r
2507 //\r
2508 // Channel and device differential. Select device.\r
2509 //\r
2510 Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
2511\r
2512 //\r
2513 // Enable interrupt to support UDMA and Select device\r
2514 //\r
2515 DeviceControl = 0;\r
2516 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
2517\r
2518 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
2519\r
2520 if (IdePrimary == IdeDev->Channel) {\r
2521 IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
2522 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
2523 IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
2524 } else {\r
2525 if (IdeSecondary == IdeDev->Channel) {\r
2526 IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
2527 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
2528 IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
2529 } else {\r
2530 return EFI_UNSUPPORTED;\r
2531 }\r
2532 }\r
2533\r
2534 RemainBlockNum = NumberOfBlocks;\r
2535 while (RemainBlockNum > 0) {\r
2536\r
2537 if (RemainBlockNum >= MAX_DMA_EXT_COMMAND_SECTORS) {\r
2538 //\r
2539 // SectorCount is used to record the number of sectors to be read\r
2540 // Max 65536 sectors can be transfered at a time.\r
2541 //\r
2542 NumberOfBlocks = MAX_DMA_EXT_COMMAND_SECTORS;\r
2543 RemainBlockNum -= MAX_DMA_EXT_COMMAND_SECTORS;\r
2544 } else {\r
2545 NumberOfBlocks = (UINT16) RemainBlockNum;\r
2546 RemainBlockNum = 0;\r
2547 }\r
2548\r
2549 //\r
2550 // Calculate the number of PRD table to make sure the memory region\r
2551 // not cross 64K boundary\r
2552 //\r
2553 ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
2554 PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
2555\r
2556 //\r
2557 // Build PRD table\r
2558 //\r
2559 PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));\r
2560\r
2561 //\r
2562 // To make sure PRD is allocated in one 64K page\r
2563 //\r
2564 if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
2565 UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
2566 } else {\r
2567 if ((UINTN) PrdAddr & 0x03) {\r
2568 UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
2569 } else {\r
2570 UsedPrdAddr = PrdAddr;\r
2571 }\r
2572 }\r
2573\r
2574 //\r
2575 // Build the PRD table\r
2576 //\r
2577 PrdBuffer = DataBuffer;\r
2578 TempPrdAddr = UsedPrdAddr;\r
2579 while (TRUE) {\r
2580\r
2581 ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
2582\r
2583 if (ByteCount <= ByteAvailable) {\r
2584 TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
2585 TempPrdAddr->ByteCount = (UINT16) ByteCount;\r
2586 TempPrdAddr->EndOfTable = 0x8000;\r
2587 break;\r
2588 }\r
2589\r
2590 TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
2591 TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r
2592\r
2593 ByteCount -= ByteAvailable;\r
2594 PrdBuffer += ByteAvailable;\r
2595 TempPrdAddr++;\r
2596 }\r
2597 \r
2598 //\r
2599 // Set the base address to BMID register\r
2600 //\r
2601 IdeDev->PciIo->Io.Write (\r
2602 IdeDev->PciIo,\r
2603 EfiPciIoWidthUint32,\r
2604 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2605 IoPortForBmid,\r
2606 1,\r
2607 &UsedPrdAddr\r
2608 );\r
2609\r
2610 //\r
2611 // Set BMIC register to identify the operation direction\r
2612 //\r
2613 IdeDev->PciIo->Io.Read (\r
2614 IdeDev->PciIo,\r
2615 EfiPciIoWidthUint8,\r
2616 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2617 IoPortForBmic,\r
2618 1,\r
2619 &RegisterValue\r
2620 );\r
2621\r
2622 RegisterValue |= BMIC_nREAD;\r
2623\r
2624 IdeDev->PciIo->Io.Write (\r
2625 IdeDev->PciIo,\r
2626 EfiPciIoWidthUint8,\r
2627 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2628 IoPortForBmic,\r
2629 1,\r
2630 &RegisterValue\r
2631 );\r
2632\r
2633 //\r
2634 // Read BMIS register and clear ERROR and INTR bit\r
2635 //\r
2636 IdeDev->PciIo->Io.Read (\r
2637 IdeDev->PciIo,\r
2638 EfiPciIoWidthUint8,\r
2639 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2640 IoPortForBmis,\r
2641 1,\r
2642 &RegisterValue\r
2643 );\r
2644\r
2645 RegisterValue |= BMIS_INTERRUPT | BMIS_ERROR;\r
2646\r
2647 IdeDev->PciIo->Io.Write (\r
2648 IdeDev->PciIo,\r
2649 EfiPciIoWidthUint8,\r
2650 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2651 IoPortForBmis,\r
2652 1,\r
2653 &RegisterValue\r
2654 );\r
2655\r
2656 //\r
2657 // Issue READ DMA EXT command\r
2658 //\r
2659 Status = AtaCommandIssueExt (\r
2660 IdeDev,\r
2661 READ_DMA_EXT_CMD,\r
2662 Device,\r
2663 0,\r
2664 (UINT16) NumberOfBlocks,\r
2665 StartLba\r
2666 );\r
2667 if (EFI_ERROR (Status)) {\r
2668 gBS->FreePool (PrdAddr);\r
2669 return EFI_DEVICE_ERROR;\r
2670 }\r
2671\r
2672 //\r
2673 // Set START bit of BMIC register\r
2674 //\r
2675 IdeDev->PciIo->Io.Read (\r
2676 IdeDev->PciIo,\r
2677 EfiPciIoWidthUint8,\r
2678 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2679 IoPortForBmic,\r
2680 1,\r
2681 &RegisterValue\r
2682 );\r
2683\r
2684 RegisterValue |= BMIC_START;\r
2685\r
2686 IdeDev->PciIo->Io.Write (\r
2687 IdeDev->PciIo,\r
2688 EfiPciIoWidthUint8,\r
2689 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2690 IoPortForBmic,\r
2691 1,\r
2692 &RegisterValue\r
2693 );\r
2694\r
2695 //\r
2696 // Check the INTERRUPT and ERROR bit of BMIS\r
2697 //\r
2698 while (TRUE) {\r
2699\r
2700 IdeDev->PciIo->Io.Read (\r
2701 IdeDev->PciIo,\r
2702 EfiPciIoWidthUint8,\r
2703 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2704 IoPortForBmis,\r
2705 1,\r
2706 &RegisterValue\r
2707 );\r
2708 if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {\r
2709 if (RegisterValue & BMIS_ERROR) {\r
2710 gBS->FreePool (PrdAddr);\r
2711 return EFI_DEVICE_ERROR;\r
2712 }\r
2713 break;\r
2714 }\r
2715\r
2716 gBS->Stall (1000);\r
2717 }\r
2718\r
2719 gBS->FreePool (PrdAddr);\r
2720\r
2721 //\r
2722 // Set START bit of BMIC register\r
2723 //\r
2724 IdeDev->PciIo->Io.Read (\r
2725 IdeDev->PciIo,\r
2726 EfiPciIoWidthUint8,\r
2727 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2728 IoPortForBmic,\r
2729 1,\r
2730 &RegisterValue\r
2731 );\r
2732\r
2733 RegisterValue &= ~((UINT8) BMIC_START);\r
2734\r
2735 IdeDev->PciIo->Io.Write (\r
2736 IdeDev->PciIo,\r
2737 EfiPciIoWidthUint8,\r
2738 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2739 IoPortForBmic,\r
2740 1,\r
2741 &RegisterValue\r
2742 );\r
2743\r
2744 if (RegisterValue & BMIS_ERROR) {\r
2745 return EFI_DEVICE_ERROR;\r
2746 }\r
2747\r
2748 DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
2749 StartLba += NumberOfBlocks;\r
2750 }\r
2751\r
2752 return EFI_SUCCESS;\r
2753}\r
2754\r
2755EFI_STATUS\r
2756AtaUdmaRead (\r
2757 IN IDE_BLK_IO_DEV *IdeDev,\r
2758 IN VOID *DataBuffer,\r
2759 IN EFI_LBA StartLba,\r
2760 IN UINTN NumberOfBlocks\r
2761 )\r
2762/*++\r
2763 Name:\r
2764 \r
2765 AtaUdmaRead\r
2766\r
2767 Purpose: \r
2768 \r
2769 This function is called by the AtaBlkIoReadBlocks() to perform\r
2770 reading from media in block unit. The function has been enhanced to \r
2771 support >120GB access and transfer at most 65536 blocks per command\r
2772\r
2773 Parameters:\r
2774 \r
2775 IDE_BLK_IO_DEV IN *IdeDev\r
2776 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
2777 to record all the information of the IDE device.\r
2778\r
2779 VOID IN *DataBuffer\r
2780 A pointer to the destination buffer for the data. \r
2781\r
2782 EFI_LBA IN StartLba\r
2783 The starting logical block address to read from \r
2784 on the device media.\r
2785\r
2786 UINTN IN NumberOfBlocks\r
2787 The number of transfer data blocks.\r
2788\r
2789 Returns: \r
2790\r
2791 The device status of UDMA operation. If the operation is \r
2792 successful, return EFI_SUCCESS.\r
2793\r
2794--*/\r
2795// TODO: function comment is missing 'Routine Description:'\r
2796// TODO: function comment is missing 'Arguments:'\r
2797// TODO: IdeDev - add argument and description to function comment\r
2798// TODO: DataBuffer - add argument and description to function comment\r
2799// TODO: StartLba - add argument and description to function comment\r
2800// TODO: NumberOfBlocks - add argument and description to function comment\r
2801// TODO: EFI_UNSUPPORTED - add return value to function comment\r
2802// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
2803// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
2804// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
2805{\r
2806 IDE_DMA_PRD *PrdAddr;\r
2807 IDE_DMA_PRD *UsedPrdAddr;\r
2808 IDE_DMA_PRD *TempPrdAddr;\r
2809 UINT8 RegisterValue;\r
2810 UINT8 Device;\r
2811 UINT64 IoPortForBmic;\r
2812 UINT64 IoPortForBmis;\r
2813 UINT64 IoPortForBmid;\r
2814 EFI_STATUS Status;\r
2815 UINTN PrdTableNum;\r
2816 UINTN ByteCount;\r
2817 UINTN ByteAvailable;\r
2818 UINT8 *PrdBuffer;\r
2819 UINTN RemainBlockNum;\r
2820 UINT8 DeviceControl;\r
2821\r
2822 //\r
2823 // Channel and device differential\r
2824 //\r
2825 Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
2826\r
2827 //\r
2828 // Enable interrupt to support UDMA and Select device\r
2829 //\r
2830 DeviceControl = 0;\r
2831 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
2832\r
2833 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
2834\r
2835 if (IdePrimary == IdeDev->Channel) {\r
2836 IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
2837 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
2838 IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
2839 } else {\r
2840 if (IdeSecondary == IdeDev->Channel) {\r
2841 IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
2842 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
2843 IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
2844 } else {\r
2845 return EFI_UNSUPPORTED;\r
2846 }\r
2847 }\r
2848\r
2849 RemainBlockNum = NumberOfBlocks;\r
2850 while (RemainBlockNum > 0) {\r
2851\r
2852 if (RemainBlockNum >= MAX_DMA_COMMAND_SECTORS) {\r
2853 //\r
2854 // SectorCount is used to record the number of sectors to be read\r
2855 // Max 256 sectors can be transfered at a time.\r
2856 //\r
2857 NumberOfBlocks = MAX_DMA_COMMAND_SECTORS;\r
2858 RemainBlockNum -= MAX_DMA_COMMAND_SECTORS;\r
2859 } else {\r
2860 NumberOfBlocks = (UINT16) RemainBlockNum;\r
2861 RemainBlockNum = 0;\r
2862 }\r
2863\r
2864 //\r
2865 // Calculate the number of PRD table to make sure the memory region\r
2866 // not cross 64K boundary\r
2867 //\r
2868 ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
2869 PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
2870\r
2871 //\r
2872 // Build PRD table\r
2873 //\r
2874 PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));\r
2875 //\r
2876 // To make sure PRD is allocated in one 64K page\r
2877 //\r
2878 if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
2879 UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
2880 } else {\r
2881 if ((UINTN) PrdAddr & 0x03) {\r
2882 UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
2883 } else {\r
2884 UsedPrdAddr = PrdAddr;\r
2885 }\r
2886 }\r
2887\r
2888 //\r
2889 // Build the PRD table\r
2890 //\r
2891 PrdBuffer = DataBuffer;\r
2892 TempPrdAddr = UsedPrdAddr;\r
2893 while (TRUE) {\r
2894\r
2895 ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
2896\r
2897 if (ByteCount <= ByteAvailable) {\r
2898 TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
2899 TempPrdAddr->ByteCount = (UINT16) ByteCount;\r
2900 TempPrdAddr->EndOfTable = 0x8000;\r
2901 break;\r
2902 }\r
2903\r
2904 TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
2905 TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r
2906\r
2907 ByteCount -= ByteAvailable;\r
2908 PrdBuffer += ByteAvailable;\r
2909 TempPrdAddr++;\r
2910 }\r
2911\r
2912 //\r
2913 // Set the base address to BMID register\r
2914 //\r
2915 IdeDev->PciIo->Io.Write (\r
2916 IdeDev->PciIo,\r
2917 EfiPciIoWidthUint32,\r
2918 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2919 IoPortForBmid,\r
2920 1,\r
2921 &UsedPrdAddr\r
2922 );\r
2923\r
2924 //\r
2925 // Set BMIC register to identify the operation direction\r
2926 //\r
2927 IdeDev->PciIo->Io.Read (\r
2928 IdeDev->PciIo,\r
2929 EfiPciIoWidthUint8,\r
2930 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2931 IoPortForBmic,\r
2932 1,\r
2933 &RegisterValue\r
2934 );\r
2935\r
2936 RegisterValue |= BMIC_nREAD;\r
2937\r
2938 IdeDev->PciIo->Io.Write (\r
2939 IdeDev->PciIo,\r
2940 EfiPciIoWidthUint8,\r
2941 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2942 IoPortForBmic,\r
2943 1,\r
2944 &RegisterValue\r
2945 );\r
2946\r
2947 //\r
2948 // Read BMIS register and clear ERROR and INTR bit\r
2949 //\r
2950 IdeDev->PciIo->Io.Read (\r
2951 IdeDev->PciIo,\r
2952 EfiPciIoWidthUint8,\r
2953 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2954 IoPortForBmis,\r
2955 1,\r
2956 &RegisterValue\r
2957 );\r
2958\r
2959 RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
2960\r
2961 IdeDev->PciIo->Io.Write (\r
2962 IdeDev->PciIo,\r
2963 EfiPciIoWidthUint8,\r
2964 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2965 IoPortForBmis,\r
2966 1,\r
2967 &RegisterValue\r
2968 );\r
2969\r
2970 //\r
2971 // Issue READ DMA command\r
2972 //\r
2973 Status = AtaCommandIssue (\r
2974 IdeDev,\r
2975 READ_DMA_CMD,\r
2976 Device,\r
2977 0,\r
2978 (UINT16) NumberOfBlocks,\r
2979 StartLba\r
2980 );\r
2981 if (EFI_ERROR (Status)) {\r
2982 gBS->FreePool (PrdAddr);\r
2983 return EFI_DEVICE_ERROR;\r
2984 }\r
2985\r
2986 //\r
2987 // Set START bit of BMIC register\r
2988 //\r
2989 IdeDev->PciIo->Io.Read (\r
2990 IdeDev->PciIo,\r
2991 EfiPciIoWidthUint8,\r
2992 EFI_PCI_IO_PASS_THROUGH_BAR,\r
2993 IoPortForBmic,\r
2994 1,\r
2995 &RegisterValue\r
2996 );\r
2997\r
2998 RegisterValue |= BMIC_START;\r
2999\r
3000 IdeDev->PciIo->Io.Write (\r
3001 IdeDev->PciIo,\r
3002 EfiPciIoWidthUint8,\r
3003 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3004 IoPortForBmic,\r
3005 1,\r
3006 &RegisterValue\r
3007 );\r
3008\r
3009 //\r
3010 // Check the INTERRUPT and ERROR bit of BMIS\r
3011 //\r
3012 while (TRUE) {\r
3013\r
3014 IdeDev->PciIo->Io.Read (\r
3015 IdeDev->PciIo,\r
3016 EfiPciIoWidthUint8,\r
3017 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3018 IoPortForBmis,\r
3019 1,\r
3020 &RegisterValue\r
3021 );\r
3022 if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {\r
3023 if (RegisterValue & BMIS_ERROR) {\r
3024 gBS->FreePool (PrdAddr);\r
3025 return EFI_DEVICE_ERROR;\r
3026 }\r
3027 break;\r
3028 }\r
3029\r
3030 gBS->Stall (1000);\r
3031 }\r
3032\r
3033 gBS->FreePool (PrdAddr);\r
3034\r
3035 //\r
3036 // Set START bit of BMIC register\r
3037 //\r
3038 IdeDev->PciIo->Io.Read (\r
3039 IdeDev->PciIo,\r
3040 EfiPciIoWidthUint8,\r
3041 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3042 IoPortForBmic,\r
3043 1,\r
3044 &RegisterValue\r
3045 );\r
3046\r
3047 RegisterValue &= ~((UINT8) BMIC_START);\r
3048\r
3049 IdeDev->PciIo->Io.Write (\r
3050 IdeDev->PciIo,\r
3051 EfiPciIoWidthUint8,\r
3052 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3053 IoPortForBmic,\r
3054 1,\r
3055 &RegisterValue\r
3056 );\r
3057\r
3058 if (RegisterValue & BMIS_ERROR) {\r
3059 return EFI_DEVICE_ERROR;\r
3060 }\r
3061\r
3062 DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
3063 StartLba += NumberOfBlocks;\r
3064 }\r
3065\r
3066 return EFI_SUCCESS;\r
3067}\r
3068\r
3069EFI_STATUS\r
3070AtaUdmaWriteExt (\r
3071 IN IDE_BLK_IO_DEV *IdeDev,\r
3072 IN VOID *DataBuffer,\r
3073 IN EFI_LBA StartLba,\r
3074 IN UINTN NumberOfBlocks\r
3075 )\r
3076/*++\r
3077 Name:\r
3078 \r
3079 AtaUdmaWriteExt\r
3080\r
3081 Purpose: \r
3082 \r
3083 This function is called by the AtaBlkIoWriteBlocks() to perform\r
3084 writing to media in block unit. The function has been enhanced to \r
3085 support >120GB access and transfer at most 65536 blocks per command\r
3086\r
3087 Parameters:\r
3088 \r
3089 IDE_BLK_IO_DEV IN *IdeDev\r
3090 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
3091 to record all the information of the IDE device.\r
3092\r
3093 VOID IN *DataBuffer\r
3094 A pointer to the source buffer for the data. \r
3095\r
3096 EFI_LBA IN StartLba\r
3097 The starting logical block address to write to \r
3098 on the device media.\r
3099\r
3100 UINTN IN NumberOfBlocks\r
3101 The number of transfer data blocks.\r
3102\r
3103 Returns: \r
3104\r
3105 The device status of UDMA operation. If the operation is \r
3106 successful, return EFI_SUCCESS.\r
3107\r
3108--*/\r
3109// TODO: function comment is missing 'Routine Description:'\r
3110// TODO: function comment is missing 'Arguments:'\r
3111// TODO: IdeDev - add argument and description to function comment\r
3112// TODO: DataBuffer - add argument and description to function comment\r
3113// TODO: StartLba - add argument and description to function comment\r
3114// TODO: NumberOfBlocks - add argument and description to function comment\r
3115// TODO: EFI_UNSUPPORTED - add return value to function comment\r
3116// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
3117// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
3118{\r
3119 IDE_DMA_PRD *PrdAddr;\r
3120 IDE_DMA_PRD *UsedPrdAddr;\r
3121 IDE_DMA_PRD *TempPrdAddr;\r
3122 UINT8 RegisterValue;\r
3123 UINT8 Device;\r
3124 UINT64 IoPortForBmic;\r
3125 UINT64 IoPortForBmis;\r
3126 UINT64 IoPortForBmid;\r
3127 EFI_STATUS Status;\r
3128 UINTN PrdTableNum;\r
3129 UINTN ByteCount;\r
3130 UINTN ByteAvailable;\r
3131 UINT8 *PrdBuffer;\r
3132 UINTN RemainBlockNum;\r
3133 UINT8 DeviceControl;\r
3134\r
3135 //\r
3136 // Channel and device differential\r
3137 //\r
3138 Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
3139\r
3140 //\r
3141 // Enable interrupt to support UDMA and Select device\r
3142 //\r
3143 DeviceControl = 0;\r
3144 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
3145\r
3146 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
3147\r
3148 if (IdePrimary == IdeDev->Channel) {\r
3149 IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
3150 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
3151 IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
3152 } else {\r
3153 if (IdeSecondary == IdeDev->Channel) {\r
3154 IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
3155 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
3156 IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
3157 } else {\r
3158 return EFI_UNSUPPORTED;\r
3159 }\r
3160 }\r
3161\r
3162 RemainBlockNum = NumberOfBlocks;\r
3163 while (RemainBlockNum > 0) {\r
3164\r
3165 if (RemainBlockNum >= MAX_DMA_EXT_COMMAND_SECTORS) {\r
3166 //\r
3167 // SectorCount is used to record the number of sectors to be read\r
3168 // Max 65536 sectors can be transfered at a time.\r
3169 //\r
3170 NumberOfBlocks = MAX_DMA_EXT_COMMAND_SECTORS;\r
3171 RemainBlockNum -= MAX_DMA_EXT_COMMAND_SECTORS;\r
3172 } else {\r
3173 NumberOfBlocks = (UINT16) RemainBlockNum;\r
3174 RemainBlockNum = 0;\r
3175 }\r
3176\r
3177 //\r
3178 // Calculate the number of PRD table to make sure the memory region\r
3179 // not cross 64K boundary\r
3180 //\r
3181 ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
3182 PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
3183\r
3184 //\r
3185 // Build PRD table\r
3186 //\r
3187 PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));\r
3188 //\r
3189 // To make sure PRD is allocated in one 64K page\r
3190 //\r
3191 if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
3192 UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
3193 } else {\r
3194 if ((UINTN) PrdAddr & 0x03) {\r
3195 UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
3196 } else {\r
3197 UsedPrdAddr = PrdAddr;\r
3198 }\r
3199 }\r
3200\r
3201 //\r
3202 // Build the PRD table\r
3203 //\r
3204 PrdBuffer = DataBuffer;\r
3205 TempPrdAddr = UsedPrdAddr;\r
3206 while (TRUE) {\r
3207\r
3208 ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
3209\r
3210 if (ByteCount <= ByteAvailable) {\r
3211 TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
3212 TempPrdAddr->ByteCount = (UINT16) ByteCount;\r
3213 TempPrdAddr->EndOfTable = 0x8000;\r
3214 break;\r
3215 }\r
3216\r
3217 TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
3218 TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r
3219\r
3220 ByteCount -= ByteAvailable;\r
3221 PrdBuffer += ByteAvailable;\r
3222 TempPrdAddr++;\r
3223 }\r
3224 \r
3225 //\r
3226 // Set the base address to BMID register\r
3227 //\r
3228 IdeDev->PciIo->Io.Write (\r
3229 IdeDev->PciIo,\r
3230 EfiPciIoWidthUint32,\r
3231 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3232 IoPortForBmid,\r
3233 1,\r
3234 &UsedPrdAddr\r
3235 );\r
3236\r
3237 //\r
3238 // Set BMIC register to identify the operation direction\r
3239 //\r
3240 IdeDev->PciIo->Io.Read (\r
3241 IdeDev->PciIo,\r
3242 EfiPciIoWidthUint8,\r
3243 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3244 IoPortForBmic,\r
3245 1,\r
3246 &RegisterValue\r
3247 );\r
3248 //\r
3249 // 0000 1000\r
3250 //\r
3251 RegisterValue &= ~((UINT8) BMIC_nREAD);\r
3252\r
3253 IdeDev->PciIo->Io.Write (\r
3254 IdeDev->PciIo,\r
3255 EfiPciIoWidthUint8,\r
3256 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3257 IoPortForBmic,\r
3258 1,\r
3259 &RegisterValue\r
3260 );\r
3261\r
3262 //\r
3263 // Read BMIS register and clear ERROR and INTR bit\r
3264 //\r
3265 IdeDev->PciIo->Io.Read (\r
3266 IdeDev->PciIo,\r
3267 EfiPciIoWidthUint8,\r
3268 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3269 IoPortForBmis,\r
3270 1,\r
3271 &RegisterValue\r
3272 );\r
3273\r
3274 RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
3275\r
3276 IdeDev->PciIo->Io.Write (\r
3277 IdeDev->PciIo,\r
3278 EfiPciIoWidthUint8,\r
3279 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3280 IoPortForBmis,\r
3281 1,\r
3282 &RegisterValue\r
3283 );\r
3284\r
3285 //\r
3286 // Issue WRITE DMA EXT command\r
3287 //\r
3288 Status = AtaCommandIssueExt (\r
3289 IdeDev,\r
3290 WRITE_DMA_EXT_CMD,\r
3291 Device,\r
3292 0,\r
3293 (UINT16) NumberOfBlocks,\r
3294 StartLba\r
3295 );\r
3296 if (EFI_ERROR (Status)) {\r
3297 gBS->FreePool (PrdAddr);\r
3298 return EFI_DEVICE_ERROR;\r
3299 }\r
3300\r
3301 //\r
3302 // Set START bit of BMIC register\r
3303 //\r
3304 IdeDev->PciIo->Io.Read (\r
3305 IdeDev->PciIo,\r
3306 EfiPciIoWidthUint8,\r
3307 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3308 IoPortForBmic,\r
3309 1,\r
3310 &RegisterValue\r
3311 );\r
3312\r
3313 RegisterValue |= BMIC_START;\r
3314\r
3315 IdeDev->PciIo->Io.Write (\r
3316 IdeDev->PciIo,\r
3317 EfiPciIoWidthUint8,\r
3318 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3319 IoPortForBmic,\r
3320 1,\r
3321 &RegisterValue\r
3322 );\r
3323\r
3324 //\r
3325 // Check the INTERRUPT and ERROR bit of BMIS\r
3326 //\r
3327 while (TRUE) {\r
3328\r
3329 IdeDev->PciIo->Io.Read (\r
3330 IdeDev->PciIo,\r
3331 EfiPciIoWidthUint8,\r
3332 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3333 IoPortForBmis,\r
3334 1,\r
3335 &RegisterValue\r
3336 );\r
3337 if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {\r
3338 if (RegisterValue & BMIS_ERROR) {\r
3339 gBS->FreePool (PrdAddr);\r
3340 return EFI_DEVICE_ERROR;\r
3341 }\r
3342 break;\r
3343 }\r
3344\r
3345 gBS->Stall (1000);\r
3346 }\r
3347\r
3348 gBS->FreePool (PrdAddr);\r
3349\r
3350 //\r
3351 // Set START bit of BMIC register\r
3352 //\r
3353 IdeDev->PciIo->Io.Read (\r
3354 IdeDev->PciIo,\r
3355 EfiPciIoWidthUint8,\r
3356 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3357 IoPortForBmic,\r
3358 1,\r
3359 &RegisterValue\r
3360 );\r
3361\r
3362 RegisterValue &= ~((UINT8) BMIC_START);\r
3363\r
3364 IdeDev->PciIo->Io.Write (\r
3365 IdeDev->PciIo,\r
3366 EfiPciIoWidthUint8,\r
3367 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3368 IoPortForBmic,\r
3369 1,\r
3370 &RegisterValue\r
3371 );\r
3372\r
3373 DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
3374 StartLba += NumberOfBlocks;\r
3375 }\r
3376\r
3377 return EFI_SUCCESS;\r
3378}\r
3379\r
3380EFI_STATUS\r
3381AtaUdmaWrite (\r
3382 IN IDE_BLK_IO_DEV *IdeDev,\r
3383 IN VOID *DataBuffer,\r
3384 IN EFI_LBA StartLba,\r
3385 IN UINTN NumberOfBlocks\r
3386 )\r
3387/*++\r
3388 Name:\r
3389 \r
3390 AtaUdmaWrite\r
3391\r
3392 Purpose: \r
3393 \r
3394 This function is called by the AtaBlkIoWriteBlocks() to perform\r
3395 writing to media in block unit. The function has been enhanced to \r
3396 support >120GB access and transfer at most 65536 blocks per command\r
3397\r
3398 Parameters:\r
3399 \r
3400 IDE_BLK_IO_DEV IN *IdeDev\r
3401 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
3402 to record all the information of the IDE device.\r
3403\r
3404 VOID IN *DataBuffer\r
3405 A pointer to the source buffer for the data. \r
3406\r
3407 EFI_LBA IN StartLba\r
3408 The starting logical block address to write to \r
3409 on the device media.\r
3410\r
3411 UINTN IN NumberOfBlocks\r
3412 The number of transfer data blocks.\r
3413\r
3414 Returns: \r
3415\r
3416 The device status of UDMA operation. If the operation is \r
3417 successful, return EFI_SUCCESS.\r
3418\r
3419--*/\r
3420// TODO: function comment is missing 'Routine Description:'\r
3421// TODO: function comment is missing 'Arguments:'\r
3422// TODO: IdeDev - add argument and description to function comment\r
3423// TODO: DataBuffer - add argument and description to function comment\r
3424// TODO: StartLba - add argument and description to function comment\r
3425// TODO: NumberOfBlocks - add argument and description to function comment\r
3426// TODO: EFI_UNSUPPORTED - add return value to function comment\r
3427// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
3428// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
3429{\r
3430 IDE_DMA_PRD *PrdAddr;\r
3431 IDE_DMA_PRD *UsedPrdAddr;\r
3432 IDE_DMA_PRD *TempPrdAddr;\r
3433 UINT8 RegisterValue;\r
3434 UINT8 Device;\r
3435 UINT64 IoPortForBmic;\r
3436 UINT64 IoPortForBmis;\r
3437 UINT64 IoPortForBmid;\r
3438 EFI_STATUS Status;\r
3439 UINTN PrdTableNum;\r
3440 UINTN ByteCount;\r
3441 UINTN ByteAvailable;\r
3442 UINT8 *PrdBuffer;\r
3443 UINTN RemainBlockNum;\r
3444 UINT8 DeviceControl;\r
3445\r
3446 //\r
3447 // Channel and device differential\r
3448 //\r
3449 Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
3450\r
3451 //\r
3452 // Enable interrupt to support UDMA\r
3453 //\r
3454 DeviceControl = 0;\r
3455 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
3456\r
3457 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
3458\r
3459 if (IdePrimary == IdeDev->Channel) {\r
3460 IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
3461 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
3462 IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
3463 } else {\r
3464 if (IdeSecondary == IdeDev->Channel) {\r
3465 IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
3466 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
3467 IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
3468 } else {\r
3469 return EFI_UNSUPPORTED;\r
3470 }\r
3471 }\r
3472\r
3473 RemainBlockNum = NumberOfBlocks;\r
3474 while (RemainBlockNum > 0) {\r
3475\r
3476 if (RemainBlockNum >= MAX_DMA_COMMAND_SECTORS) {\r
3477 //\r
3478 // SectorCount is used to record the number of sectors to be read\r
3479 // Max 256 sectors can be transfered at a time.\r
3480 //\r
3481 NumberOfBlocks = MAX_DMA_COMMAND_SECTORS;\r
3482 RemainBlockNum -= MAX_DMA_COMMAND_SECTORS;\r
3483 } else {\r
3484 NumberOfBlocks = (UINT16) RemainBlockNum;\r
3485 RemainBlockNum = 0;\r
3486 }\r
3487\r
3488 //\r
3489 // Calculate the number of PRD table to make sure the memory region\r
3490 // not cross 64K boundary\r
3491 //\r
3492 ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
3493 PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
3494\r
3495 //\r
3496 // Build PRD table\r
3497 //\r
3498 PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));\r
3499\r
3500 //\r
3501 // To make sure PRD is allocated in one 64K page\r
3502 //\r
3503 if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
3504 UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
3505 } else {\r
3506 if ((UINTN) PrdAddr & 0x03) {\r
3507 UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
3508 } else {\r
3509 UsedPrdAddr = PrdAddr;\r
3510 }\r
3511 }\r
3512\r
3513 //\r
3514 // Build the PRD table\r
3515 //\r
3516 PrdBuffer = DataBuffer;\r
3517 TempPrdAddr = UsedPrdAddr;\r
3518 while (TRUE) {\r
3519\r
3520 ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
3521\r
3522 if (ByteCount <= ByteAvailable) {\r
3523 TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
3524 TempPrdAddr->ByteCount = (UINT16) ByteCount;\r
3525 TempPrdAddr->EndOfTable = 0x8000;\r
3526 break;\r
3527 }\r
3528\r
3529 TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
3530 TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r
3531\r
3532 ByteCount -= ByteAvailable;\r
3533 PrdBuffer += ByteAvailable;\r
3534 TempPrdAddr++;\r
3535 }\r
3536 \r
3537 //\r
3538 // Set the base address to BMID register\r
3539 //\r
3540 IdeDev->PciIo->Io.Write (\r
3541 IdeDev->PciIo,\r
3542 EfiPciIoWidthUint32,\r
3543 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3544 IoPortForBmid,\r
3545 1,\r
3546 &UsedPrdAddr\r
3547 );\r
3548\r
3549 //\r
3550 // Set BMIC register to identify the operation direction\r
3551 //\r
3552 IdeDev->PciIo->Io.Read (\r
3553 IdeDev->PciIo,\r
3554 EfiPciIoWidthUint8,\r
3555 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3556 IoPortForBmic,\r
3557 1,\r
3558 &RegisterValue\r
3559 );\r
3560 //\r
3561 // 0000 1000\r
3562 //\r
3563 RegisterValue &= ~((UINT8) BMIC_nREAD);\r
3564\r
3565 IdeDev->PciIo->Io.Write (\r
3566 IdeDev->PciIo,\r
3567 EfiPciIoWidthUint8,\r
3568 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3569 IoPortForBmic,\r
3570 1,\r
3571 &RegisterValue\r
3572 );\r
3573\r
3574 //\r
3575 // Read BMIS register and clear ERROR and INTR bit\r
3576 //\r
3577 IdeDev->PciIo->Io.Read (\r
3578 IdeDev->PciIo,\r
3579 EfiPciIoWidthUint8,\r
3580 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3581 IoPortForBmis,\r
3582 1,\r
3583 &RegisterValue\r
3584 );\r
3585\r
3586 RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
3587\r
3588 IdeDev->PciIo->Io.Write (\r
3589 IdeDev->PciIo,\r
3590 EfiPciIoWidthUint8,\r
3591 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3592 IoPortForBmis,\r
3593 1,\r
3594 &RegisterValue\r
3595 );\r
3596\r
3597 //\r
3598 // Issue WRITE DMA command\r
3599 //\r
3600 Status = AtaCommandIssue (\r
3601 IdeDev,\r
3602 WRITE_DMA_CMD,\r
3603 Device,\r
3604 0,\r
3605 (UINT16) NumberOfBlocks,\r
3606 StartLba\r
3607 );\r
3608 if (EFI_ERROR (Status)) {\r
3609 gBS->FreePool (PrdAddr);\r
3610 return EFI_DEVICE_ERROR;\r
3611 }\r
3612\r
3613 //\r
3614 // Set START bit of BMIC register\r
3615 //\r
3616 IdeDev->PciIo->Io.Read (\r
3617 IdeDev->PciIo,\r
3618 EfiPciIoWidthUint8,\r
3619 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3620 IoPortForBmic,\r
3621 1,\r
3622 &RegisterValue\r
3623 );\r
3624\r
3625 RegisterValue |= BMIC_START;\r
3626\r
3627 IdeDev->PciIo->Io.Write (\r
3628 IdeDev->PciIo,\r
3629 EfiPciIoWidthUint8,\r
3630 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3631 IoPortForBmic,\r
3632 1,\r
3633 &RegisterValue\r
3634 );\r
3635\r
3636 //\r
3637 // Check the INTERRUPT and ERROR bit of BMIS\r
3638 //\r
3639 while (TRUE) {\r
3640\r
3641 IdeDev->PciIo->Io.Read (\r
3642 IdeDev->PciIo,\r
3643 EfiPciIoWidthUint8,\r
3644 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3645 IoPortForBmis,\r
3646 1,\r
3647 &RegisterValue\r
3648 );\r
3649 if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {\r
3650 if (RegisterValue & BMIS_ERROR) {\r
3651 gBS->FreePool (PrdAddr);\r
3652 return EFI_DEVICE_ERROR;\r
3653 }\r
3654 break;\r
3655 }\r
3656\r
3657 gBS->Stall (1000);\r
3658 }\r
3659\r
3660 gBS->FreePool (PrdAddr);\r
3661\r
3662 //\r
3663 // Set START bit of BMIC register\r
3664 //\r
3665 IdeDev->PciIo->Io.Read (\r
3666 IdeDev->PciIo,\r
3667 EfiPciIoWidthUint8,\r
3668 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3669 IoPortForBmic,\r
3670 1,\r
3671 &RegisterValue\r
3672 );\r
3673\r
3674 RegisterValue &= ~((UINT8) BMIC_START);\r
3675\r
3676 IdeDev->PciIo->Io.Write (\r
3677 IdeDev->PciIo,\r
3678 EfiPciIoWidthUint8,\r
3679 EFI_PCI_IO_PASS_THROUGH_BAR,\r
3680 IoPortForBmic,\r
3681 1,\r
3682 &RegisterValue\r
3683 );\r
3684\r
3685 DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
3686 StartLba += NumberOfBlocks;\r
3687 }\r
3688\r
3689 return EFI_SUCCESS;\r
3690}\r