]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c
Updated MSA by putting Specification element at the end of the header section
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / IdeBus / Dxe / atapi.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 atapi.c\r
15 \r
16Abstract: \r
17 \r
18\r
19Revision History\r
20--*/\r
21\r
22#include "idebus.h"\r
23\r
24STATIC\r
25EFI_STATUS\r
26LS120GetMediaStatus (\r
27 IN IDE_BLK_IO_DEV *IdeDev\r
28 )\r
29/*++\r
30 Name:\r
31 LS120GetMediaStatus\r
32\r
33 Purpose: \r
34 This function is used to get the current status of the media residing\r
35 in the LS-120 drive or ZIP drive. The media status is returned in the \r
36 Error Status.\r
37\r
38 Parameters:\r
39 IDE_BLK_IO_DEV IN *IdeDev\r
40 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
41 to record all the information of the IDE device.\r
42\r
43 Returns: \r
44 EFI_SUCCESS\r
45 The media status is achieved successfully and the media\r
46 can be read/written. \r
47 \r
48 EFI_DEVICE_ERROR\r
49 Get Media Status Command is failed.\r
50\r
51 EFI_NO_MEDIA\r
52 There is no media in the drive.\r
53\r
54 EFI_WRITE_PROTECTED\r
55 The media is writing protected. \r
56\r
57 Notes: \r
58 This function must be called after the LS120EnableMediaStatus() \r
59 with second parameter set to TRUE \r
60 (means enable media status notification) is called.\r
61--*/\r
62// TODO: function comment is missing 'Routine Description:'\r
63// TODO: function comment is missing 'Arguments:'\r
64// TODO: IdeDev - add argument and description to function comment\r
65{\r
66 UINT8 DeviceSelect;\r
67 UINT8 StatusValue;\r
68 EFI_STATUS EfiStatus;\r
69 //\r
70 // Poll Alternate Register for BSY clear within timeout.\r
71 //\r
72 EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r
73 if (EFI_ERROR (EfiStatus)) {\r
74 return EFI_DEVICE_ERROR;\r
75 }\r
76\r
77 //\r
78 // Select device via Device/Head Register.\r
79 //\r
80 DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);\r
81 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
82\r
83 //\r
84 // Poll Alternate Register for DRDY set within timeout.\r
85 // After device is selected, DRDY set indicates the device is ready to\r
86 // accept command.\r
87 //\r
88 EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT);\r
89 if (EFI_ERROR (EfiStatus)) {\r
90 return EFI_DEVICE_ERROR;\r
91 }\r
92\r
93 //\r
94 // Get Media Status Command is sent\r
95 //\r
96 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA);\r
97\r
98 //\r
99 // BSY bit will clear after command is complete.\r
100 //\r
101 EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r
102 if (EFI_ERROR (EfiStatus)) {\r
103 return EFI_DEVICE_ERROR;\r
104 }\r
105\r
106 //\r
107 // the media status is returned by the command in the ERROR register\r
108 //\r
109 StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
110\r
111 if (StatusValue & bit1) {\r
112 return EFI_NO_MEDIA;\r
113 }\r
114\r
115 if (StatusValue & bit6) {\r
116 return EFI_WRITE_PROTECTED;\r
117 } else {\r
118 return EFI_SUCCESS;\r
119 }\r
120}\r
121\r
122STATIC\r
123EFI_STATUS\r
124LS120EnableMediaStatus (\r
125 IN IDE_BLK_IO_DEV *IdeDev,\r
126 IN BOOLEAN Enable\r
127 )\r
128/*++\r
129 Name:\r
130 LS120EnableMediaStatus\r
131\r
132 Purpose: \r
133 This function is used to send Enable Media Status Notification Command\r
134 or Disable Media Status Notification Command.\r
135\r
136 Parameters:\r
137 IDE_BLK_IO_DEV IN *IdeDev\r
138 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
139 to record all the information of the IDE device.\r
140\r
141 BOOLEAN IN Enable\r
142 a flag that indicates whether enable or disable media\r
143 status notification.\r
144\r
145 Returns: \r
146 EFI_SUCCESS\r
147 If command completes successfully.\r
148\r
149 EFI_DEVICE_ERROR\r
150 If command failed.\r
151\r
152\r
153 Notes: \r
154--*/\r
155// TODO: function comment is missing 'Routine Description:'\r
156// TODO: function comment is missing 'Arguments:'\r
157// TODO: IdeDev - add argument and description to function comment\r
158// TODO: Enable - add argument and description to function comment\r
159{\r
160 UINT8 DeviceSelect;\r
161 EFI_STATUS Status;\r
162\r
163 //\r
164 // Poll Alternate Register for BSY clear within timeout.\r
165 //\r
166 Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT);\r
167 if (EFI_ERROR (Status)) {\r
168 return EFI_DEVICE_ERROR;\r
169 }\r
170\r
171 //\r
172 // Select device via Device/Head Register.\r
173 //\r
174 DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);\r
175 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
176\r
177 //\r
178 // Poll Alternate Register for DRDY set within timeout.\r
179 // After device is selected, DRDY set indicates the device is ready to\r
180 // accept command.\r
181 //\r
182 Status = DRDYReady2 (IdeDev, ATATIMEOUT);\r
183 if (EFI_ERROR (Status)) {\r
184 return EFI_DEVICE_ERROR;\r
185 }\r
186\r
187 if (Enable) {\r
188 //\r
189 // 0x95: Enable media status notification\r
190 //\r
191 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95);\r
192 } else {\r
193 //\r
194 // 0x31: Disable media status notification\r
195 //\r
196 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31);\r
197 }\r
198 //\r
199 // Set Feature Command is sent\r
200 //\r
201 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF);\r
202\r
203 //\r
204 // BSY bit will clear after command is complete.\r
205 //\r
206 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
207 if (EFI_ERROR (Status)) {\r
208 return EFI_DEVICE_ERROR;\r
209 }\r
210\r
211 return EFI_SUCCESS;\r
212}\r
213\r
214EFI_STATUS\r
215ATAPIIdentify (\r
216 IN IDE_BLK_IO_DEV *IdeDev\r
217 )\r
218/*++\r
219 Name:\r
220 ATAPIIdentify\r
221\r
222\r
223 Purpose: \r
224 This function is called by DiscoverIdeDevice() during its device\r
225 identification.\r
226\r
227 Its main purpose is to get enough information for the device media\r
228 to fill in the Media data structure of the Block I/O Protocol interface.\r
229\r
230 There are 5 steps to reach such objective:\r
231\r
232 1. Sends out the ATAPI Identify Command to the specified device. \r
233 Only ATAPI device responses to this command. If the command succeeds,\r
234 it returns the Identify data structure which filled with information \r
235 about the device. Since the ATAPI device contains removable media, \r
236 the only meaningful information is the device module name.\r
237\r
238 2. Sends out ATAPI Inquiry Packet Command to the specified device.\r
239 This command will return inquiry data of the device, which contains\r
240 the device type information.\r
241\r
242 3. Allocate sense data space for future use. We don't detect the media\r
243 presence here to improvement boot performance, especially when CD \r
244 media is present. The media detection will be performed just before\r
245 each BLK_IO read/write\r
246\r
247 Parameters:\r
248 IDE_BLK_IO_DEV IN *IdeDev\r
249 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
250 to record all the information of the IDE device.\r
251\r
252 Returns: \r
253 EFI_SUCCESS\r
254 Identify ATAPI device successfully.\r
255\r
256 EFI_DEVICE_ERROR\r
257 ATAPI Identify Device Command failed or device type \r
258 is not supported by this IDE driver.\r
259\r
260 Notes:\r
261 Parameter "IdeDev" will be updated in this function.\r
262--*/\r
263// TODO: function comment is missing 'Routine Description:'\r
264// TODO: function comment is missing 'Arguments:'\r
265// TODO: IdeDev - add argument and description to function comment\r
266// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
267// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
268{\r
269 EFI_IDENTIFY_DATA *AtapiIdentifyPointer;\r
270 UINT8 DeviceSelect;\r
271 EFI_STATUS Status;\r
272\r
273 //\r
274 // device select bit\r
275 //\r
276 DeviceSelect = 0;\r
277 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
278\r
279 AtapiIdentifyPointer = AllocatePool (sizeof (EFI_IDENTIFY_DATA));\r
280 if (AtapiIdentifyPointer == NULL) {\r
281 return EFI_OUT_OF_RESOURCES;\r
282 }\r
283 //\r
284 // Send ATAPI Identify Command to get IDENTIFY data.\r
285 //\r
286 Status = AtaPioDataIn (\r
287 IdeDev,\r
288 (VOID *) AtapiIdentifyPointer,\r
289 sizeof (EFI_IDENTIFY_DATA),\r
290 ATAPI_IDENTIFY_DEVICE_CMD,\r
291 DeviceSelect,\r
292 0,\r
293 0,\r
294 0,\r
295 0\r
296 );\r
297\r
298 if (EFI_ERROR (Status)) {\r
299 gBS->FreePool (AtapiIdentifyPointer);\r
300 return EFI_DEVICE_ERROR;\r
301 }\r
302\r
303 IdeDev->pIdData = AtapiIdentifyPointer;\r
304 PrintAtaModuleName (IdeDev);\r
305\r
306 //\r
307 // Send ATAPI Inquiry Packet Command to get INQUIRY data.\r
308 //\r
309 Status = AtapiInquiry (IdeDev);\r
310 if (EFI_ERROR (Status)) {\r
311 gBS->FreePool (IdeDev->pIdData);\r
312 //\r
313 // Make sure the pIdData will not be freed again.\r
314 //\r
315 IdeDev->pIdData = NULL;\r
316 return EFI_DEVICE_ERROR;\r
317 }\r
318 //\r
319 // Get media removable info from INQUIRY data.\r
320 //\r
321 IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80);\r
322\r
323 //\r
324 // Identify device type via INQUIRY data.\r
325 //\r
326 switch (IdeDev->pInquiryData->peripheral_type & 0x1f) {\r
327\r
328 //\r
329 // Magnetic Disk\r
330 //\r
331 case 0x00:\r
332\r
333 //\r
334 // device is LS120 or ZIP drive.\r
335 //\r
336 IdeDev->Type = IdeMagnetic;\r
337\r
338 IdeDev->BlkIo.Media->MediaId = 0;\r
339 //\r
340 // Give initial value\r
341 //\r
342 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
343\r
344 IdeDev->BlkIo.Media->LastBlock = 0;\r
345 IdeDev->BlkIo.Media->BlockSize = 0x200;\r
346 break;\r
347\r
348 //\r
349 // CD-ROM\r
350 //\r
351 case 0x05:\r
352\r
353 IdeDev->Type = IdeCdRom;\r
354 IdeDev->BlkIo.Media->MediaId = 0;\r
355 //\r
356 // Give initial value\r
357 //\r
358 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
359\r
360 IdeDev->BlkIo.Media->LastBlock = 0;\r
361 IdeDev->BlkIo.Media->BlockSize = 0x800;\r
362 IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
363 break;\r
364\r
365 //\r
366 // Tape\r
367 //\r
368 case 0x01:\r
369\r
370 //\r
371 // WORM\r
372 //\r
373 case 0x04:\r
374 \r
375 //\r
376 // Optical\r
377 //\r
378 case 0x07:\r
379\r
380 default:\r
381 IdeDev->Type = IdeUnknown;\r
382 gBS->FreePool (IdeDev->pIdData);\r
383 gBS->FreePool (IdeDev->pInquiryData);\r
384 //\r
385 // Make sure the pIdData and pInquiryData will not be freed again.\r
386 //\r
387 IdeDev->pIdData = NULL;\r
388 IdeDev->pInquiryData = NULL;\r
389 return EFI_DEVICE_ERROR;\r
390 }\r
391\r
392 //\r
393 // original sense data numbers\r
394 //\r
395 IdeDev->SenseDataNumber = 20;\r
396\r
397 IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (REQUEST_SENSE_DATA));\r
398 if (IdeDev->SenseData == NULL) {\r
399 gBS->FreePool (IdeDev->pIdData);\r
400 gBS->FreePool (IdeDev->pInquiryData);\r
401 //\r
402 // Make sure the pIdData and pInquiryData will not be freed again.\r
403 //\r
404 IdeDev->pIdData = NULL;\r
405 IdeDev->pInquiryData = NULL;\r
406 return EFI_OUT_OF_RESOURCES;\r
407 }\r
408\r
409 return EFI_SUCCESS;\r
410}\r
411\r
412EFI_STATUS\r
413AtapiInquiry (\r
414 IN IDE_BLK_IO_DEV *IdeDev\r
415 )\r
416/*++\r
417 Name:\r
418 AtapiInquiry\r
419\r
420 Purpose: \r
421 Sends out ATAPI Inquiry Packet Command to the specified device.\r
422 This command will return INQUIRY data of the device.\r
423\r
424 Parameters:\r
425 IDE_BLK_IO_DEV IN *IdeDev\r
426 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
427 to record all the information of the IDE device.\r
428\r
429 Returns: \r
430 EFI_SUCCESS\r
431 Inquiry command completes successfully.\r
432\r
433 EFI_DEVICE_ERROR\r
434 Inquiry command failed.\r
435 Notes:\r
436 Parameter "IdeDev" will be updated in this function.\r
437--*/\r
438// TODO: function comment is missing 'Routine Description:'\r
439// TODO: function comment is missing 'Arguments:'\r
440// TODO: IdeDev - add argument and description to function comment\r
441{\r
442 ATAPI_PACKET_COMMAND Packet;\r
443 EFI_STATUS Status;\r
444 INQUIRY_DATA *InquiryData;\r
445\r
446 //\r
447 // prepare command packet for the ATAPI Inquiry Packet Command.\r
448 //\r
449 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
450 Packet.Inquiry.opcode = INQUIRY;\r
451 Packet.Inquiry.page_code = 0;\r
452 Packet.Inquiry.allocation_length = sizeof (INQUIRY_DATA);\r
453\r
454 InquiryData = AllocatePool (sizeof (INQUIRY_DATA));\r
455 if (InquiryData == NULL) {\r
456 return EFI_DEVICE_ERROR;\r
457 }\r
458\r
459 //\r
460 // Send command packet and get requested Inquiry data.\r
461 //\r
462 Status = AtapiPacketCommandIn (\r
463 IdeDev,\r
464 &Packet,\r
465 (UINT16 *) InquiryData,\r
466 sizeof (INQUIRY_DATA),\r
467 ATAPITIMEOUT\r
468 );\r
469 if (EFI_ERROR (Status)) {\r
470 gBS->FreePool (InquiryData);\r
471 return EFI_DEVICE_ERROR;\r
472 }\r
473\r
474 IdeDev->pInquiryData = InquiryData;\r
475\r
476 return EFI_SUCCESS;\r
477}\r
478\r
479EFI_STATUS\r
480AtapiPacketCommandIn (\r
481 IN IDE_BLK_IO_DEV *IdeDev,\r
482 IN ATAPI_PACKET_COMMAND *Packet,\r
483 IN UINT16 *Buffer,\r
484 IN UINT32 ByteCount,\r
485 IN UINTN TimeOut\r
486 )\r
487/*++\r
488 Name:\r
489 AtapiPacketCommandIn\r
490\r
491 Purpose: \r
492 This function is used to send out ATAPI commands conforms to the \r
493 Packet Command with PIO Data In Protocol.\r
494\r
495 Parameters:\r
496 IDE_BLK_IO_DEV IN *IdeDev\r
497 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
498 to record all the information of the IDE device.\r
499\r
500 ATAPI_PACKET_COMMAND IN *Packet\r
501 pointer pointing to ATAPI_PACKET_COMMAND data structure\r
502 which contains the contents of the command. \r
503 \r
504 UINT16 IN *Buffer\r
505 buffer contained data transferred from device to host.\r
506\r
507 UINT32 IN ByteCount\r
508 data size in byte unit of the buffer.\r
509\r
510 UINTN IN TimeOut\r
511 this parameter is used to specify the timeout \r
512 value for the PioReadWriteData() function. \r
513\r
514 Returns: \r
515 EFI_SUCCESS\r
516 send out the ATAPI packet command successfully \r
517 and device sends data successfully.\r
518\r
519 EFI_DEVICE_ERROR\r
520 the device failed to send data. \r
521\r
522 Notes:\r
523--*/\r
524// TODO: function comment is missing 'Routine Description:'\r
525// TODO: function comment is missing 'Arguments:'\r
526// TODO: IdeDev - add argument and description to function comment\r
527// TODO: Packet - add argument and description to function comment\r
528// TODO: Buffer - add argument and description to function comment\r
529// TODO: ByteCount - add argument and description to function comment\r
530// TODO: TimeOut - add argument and description to function comment\r
531{\r
532 UINT16 *CommandIndex;\r
533 EFI_STATUS Status;\r
534 UINT32 Count;\r
535\r
536 //\r
537 // Set all the command parameters by fill related registers.\r
538 // Before write to all the following registers, BSY and DRQ must be 0.\r
539 //\r
540 Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
541 if (EFI_ERROR (Status)) {\r
542 return Status;\r
543 }\r
544\r
545 //\r
546 // Select device via Device/Head Register.\r
547 //\r
548 IDEWritePortB (\r
549 IdeDev->PciIo,\r
550 IdeDev->IoPort->Head,\r
551 (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)\r
552 );\r
553\r
554 //\r
555 // No OVL; No DMA\r
556 //\r
557 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);\r
558\r
559 //\r
560 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device\r
561 // determine how many data should be transferred.\r
562 //\r
563 IDEWritePortB (\r
564 IdeDev->PciIo,\r
565 IdeDev->IoPort->CylinderLsb,\r
566 (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
567 );\r
568 IDEWritePortB (\r
569 IdeDev->PciIo,\r
570 IdeDev->IoPort->CylinderMsb,\r
571 (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
572 );\r
573\r
574 //\r
575 // DEFAULT_CTL:0x0a (0000,1010)\r
576 // Disable interrupt\r
577 //\r
578 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL);\r
579\r
580 //\r
581 // Send Packet command to inform device\r
582 // that the following data bytes are command packet.\r
583 //\r
584 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD);\r
585\r
586 Status = DRQReady (IdeDev, ATAPITIMEOUT);\r
587 if (EFI_ERROR (Status)) {\r
588 return Status;\r
589 }\r
590\r
591 //\r
592 // Send out command packet\r
593 //\r
594 CommandIndex = Packet->Data16;\r
595 for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
596\r
597 IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);\r
598 gBS->Stall (10);\r
599 }\r
600\r
601 //\r
602 // call PioReadWriteData() function to get\r
603 // requested transfer data form device.\r
604 //\r
605 return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut);\r
606}\r
607\r
608EFI_STATUS\r
609AtapiPacketCommandOut (\r
610 IN IDE_BLK_IO_DEV *IdeDev,\r
611 IN ATAPI_PACKET_COMMAND *Packet,\r
612 IN UINT16 *Buffer,\r
613 IN UINT32 ByteCount,\r
614 IN UINTN TimeOut\r
615 )\r
616/*++\r
617 Name:\r
618 AtapiPacketCommandOut\r
619\r
620 Purpose: \r
621 This function is used to send out ATAPI commands conforms to the \r
622 Packet Command with PIO Data Out Protocol.\r
623\r
624 Parameters:\r
625 IDE_BLK_IO_DEV IN *IdeDev\r
626 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
627 to record all the information of the IDE device.\r
628\r
629 ATAPI_PACKET_COMMAND IN *Packet\r
630 pointer pointing to ATAPI_PACKET_COMMAND data structure\r
631 which contains the contents of the command.\r
632\r
633 VOID IN *Buffer\r
634 buffer contained data transferred from host to device.\r
635\r
636 UINT32 IN ByteCount\r
637 data size in byte unit of the buffer.\r
638\r
639 UINTN IN TimeOut\r
640 this parameter is used to specify the timeout \r
641 value for the PioReadWriteData() function. \r
642\r
643 Returns: \r
644 EFI_SUCCESS\r
645 send out the ATAPI packet command successfully \r
646 and device received data successfully.\r
647\r
648 EFI_DEVICE_ERROR\r
649 the device failed to send data. \r
650\r
651 Notes:\r
652 \r
653--*/\r
654// TODO: function comment is missing 'Routine Description:'\r
655// TODO: function comment is missing 'Arguments:'\r
656// TODO: IdeDev - add argument and description to function comment\r
657// TODO: Packet - add argument and description to function comment\r
658// TODO: Buffer - add argument and description to function comment\r
659// TODO: ByteCount - add argument and description to function comment\r
660// TODO: TimeOut - add argument and description to function comment\r
661{\r
662 UINT16 *CommandIndex;\r
663 EFI_STATUS Status;\r
664 UINT32 Count;\r
665\r
666 //\r
667 // set all the command parameters\r
668 // Before write to all the following registers, BSY and DRQ must be 0.\r
669 //\r
670 Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
671 if (EFI_ERROR (Status)) {\r
672 return Status;\r
673 }\r
674 \r
675 //\r
676 // Select device via Device/Head Register.\r
677 //\r
678 IDEWritePortB (\r
679 IdeDev->PciIo,\r
680 IdeDev->IoPort->Head,\r
681 (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)\r
682 );\r
683\r
684 //\r
685 // No OVL; No DMA\r
686 //\r
687 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);\r
688\r
689 //\r
690 // set the transfersize to MAX_ATAPI_BYTE_COUNT to\r
691 // let the device determine how many data should be transferred.\r
692 //\r
693 IDEWritePortB (\r
694 IdeDev->PciIo,\r
695 IdeDev->IoPort->CylinderLsb,\r
696 (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
697 );\r
698 IDEWritePortB (\r
699 IdeDev->PciIo,\r
700 IdeDev->IoPort->CylinderMsb,\r
701 (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
702 );\r
703\r
704 //\r
705 // DEFAULT_CTL:0x0a (0000,1010)\r
706 // Disable interrupt\r
707 //\r
708 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL);\r
709\r
710 //\r
711 // Send Packet command to inform device\r
712 // that the following data bytes are command packet.\r
713 //\r
714 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD);\r
715\r
716 Status = DRQReady2 (IdeDev, ATAPITIMEOUT);\r
717 if (EFI_ERROR (Status)) {\r
718 return Status;\r
719 }\r
720\r
721 //\r
722 // Send out command packet\r
723 //\r
724 CommandIndex = Packet->Data16;\r
725 for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
726 IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);\r
727 gBS->Stall (10);\r
728 }\r
729\r
730 //\r
731 // call PioReadWriteData() function to send requested transfer data to device.\r
732 //\r
733 return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut);\r
734}\r
735\r
736EFI_STATUS\r
737PioReadWriteData (\r
738 IN IDE_BLK_IO_DEV *IdeDev,\r
739 IN UINT16 *Buffer,\r
740 IN UINT32 ByteCount,\r
741 IN BOOLEAN Read,\r
742 IN UINTN TimeOut\r
743 )\r
744/*++\r
745 Name:\r
746 PioReadWriteData\r
747\r
748 Purpose: \r
749 This function is called by either AtapiPacketCommandIn() or \r
750 AtapiPacketCommandOut(). It is used to transfer data between\r
751 host and device. The data direction is specified by the fourth\r
752 parameter.\r
753\r
754\r
755 Parameters:\r
756 IDE_BLK_IO_DEV IN *IdeDev\r
757 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
758 to record all the information of the IDE device.\r
759\r
760 VOID IN *Buffer\r
761 buffer contained data transferred between host and device.\r
762\r
763 UINT32 IN ByteCount\r
764 data size in byte unit of the buffer.\r
765\r
766 BOOLEAN IN Read\r
767 flag used to determine the data transfer direction.\r
768 Read equals 1, means data transferred from device to host;\r
769 Read equals 0, means data transferred from host to device.\r
770\r
771 UINTN IN TimeOut\r
772 timeout value for wait DRQ ready before each data \r
773 stream's transfer.\r
774\r
775 Returns: \r
776 EFI_SUCCESS\r
777 data is transferred successfully. \r
778\r
779 EFI_DEVICE_ERROR\r
780 the device failed to transfer data. \r
781\r
782 Notes:\r
783\r
784--*/\r
785// TODO: function comment is missing 'Routine Description:'\r
786// TODO: function comment is missing 'Arguments:'\r
787// TODO: IdeDev - add argument and description to function comment\r
788// TODO: Buffer - add argument and description to function comment\r
789// TODO: ByteCount - add argument and description to function comment\r
790// TODO: Read - add argument and description to function comment\r
791// TODO: TimeOut - add argument and description to function comment\r
792{\r
793 //\r
794 // required transfer data in word unit.\r
795 //\r
796 UINT32 RequiredWordCount;\r
797\r
798 //\r
799 // actual transfer data in word unit.\r
800 //\r
801 UINT32 ActualWordCount;\r
802 UINT32 WordCount;\r
803 EFI_STATUS Status;\r
804 UINT16 *PtrBuffer;\r
805\r
806 //\r
807 // containing status byte read from Status Register.\r
808 //\r
809 UINT8 StatusRegister;\r
810\r
811 //\r
812 // No data transfer is premitted.\r
813 //\r
814 if (ByteCount == 0) {\r
815 return EFI_SUCCESS;\r
816 }\r
817 //\r
818 // for performance, we assert the ByteCount is an even number\r
819 // which is actually a resonable assumption \r
820 ASSERT((ByteCount%2) == 0);\r
821 \r
822 PtrBuffer = Buffer;\r
823 RequiredWordCount = ByteCount / 2;\r
824 //\r
825 // ActuralWordCount means the word count of data really transferred.\r
826 //\r
827 ActualWordCount = 0;\r
828\r
829 while (ActualWordCount < RequiredWordCount) {\r
830 \r
831 //\r
832 // before each data transfer stream, the host should poll DRQ bit ready,\r
833 // to see whether indicates device is ready to transfer data.\r
834 //\r
835 Status = DRQReady2 (IdeDev, TimeOut);\r
836 if (EFI_ERROR (Status)) {\r
837 return CheckErrorStatus (IdeDev);\r
838 }\r
839 \r
840 //\r
841 // read Status Register will clear interrupt\r
842 //\r
843 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
844\r
845 //\r
846 // get current data transfer size from Cylinder Registers.\r
847 //\r
848 WordCount =\r
849 (\r
850 (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8) |\r
851 IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb)\r
852 ) & 0xffff;\r
853 WordCount /= 2;\r
854\r
855 WordCount = EFI_MIN (WordCount, (RequiredWordCount - ActualWordCount));\r
856\r
857 if (Read) {\r
858 IDEReadPortWMultiple (\r
859 IdeDev->PciIo,\r
860 IdeDev->IoPort->Data,\r
861 WordCount,\r
862 PtrBuffer\r
863 );\r
864 } else {\r
865 IDEWritePortWMultiple (\r
866 IdeDev->PciIo,\r
867 IdeDev->IoPort->Data,\r
868 WordCount,\r
869 PtrBuffer\r
870 );\r
871 }\r
872\r
873 PtrBuffer += WordCount;\r
874 ActualWordCount += WordCount;\r
875 }\r
876\r
877 //\r
878 // After data transfer is completed, normally, DRQ bit should clear.\r
879 //\r
880 Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
881 if (EFI_ERROR (Status)) {\r
882 return EFI_DEVICE_ERROR;\r
883 }\r
884\r
885 //\r
886 // read status register to check whether error happens.\r
887 //\r
888 return CheckErrorStatus (IdeDev);\r
889}\r
890\r
891EFI_STATUS\r
892AtapiTestUnitReady (\r
893 IN IDE_BLK_IO_DEV *IdeDev\r
894 )\r
895/*++\r
896 Name:\r
897 AtapiTestUnitReady\r
898\r
899 Purpose: \r
900 Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
901 to find out whether device is accessible.\r
902\r
903 Parameters:\r
904 IDE_BLK_IO_DEV IN *IdeDev\r
905 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
906 to record all the information of the IDE device.\r
907\r
908 Returns: \r
909 EFI_SUCCESS\r
910 device is accessible.\r
911\r
912 EFI_DEVICE_ERROR\r
913 device is not accessible.\r
914\r
915 Notes:\r
916\r
917--*/\r
918// TODO: function comment is missing 'Routine Description:'\r
919// TODO: function comment is missing 'Arguments:'\r
920// TODO: IdeDev - add argument and description to function comment\r
921{\r
922 ATAPI_PACKET_COMMAND Packet;\r
923 EFI_STATUS Status;\r
924\r
925 //\r
926 // fill command packet\r
927 //\r
928 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
929 Packet.TestUnitReady.opcode = TEST_UNIT_READY;\r
930\r
931 //\r
932 // send command packet\r
933 //\r
934 Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);\r
935 return Status;\r
936}\r
937\r
938EFI_STATUS\r
939AtapiRequestSense (\r
940 IN IDE_BLK_IO_DEV *IdeDev,\r
941 OUT UINTN *SenseCounts\r
942 )\r
943/*++\r
944 Name:\r
945 AtapiRequestSense\r
946\r
947 Purpose: \r
948 Sends out ATAPI Request Sense Packet Command to the specified device.\r
949 This command will return all the current Sense data in the device. \r
950 This function will pack all the Sense data in one single buffer.\r
951\r
952 Parameters:\r
953 IDE_BLK_IO_DEV IN *IdeDev\r
954 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
955 to record all the information of the IDE device.\r
956\r
957 UINT16 OUT **SenseBuffers\r
958 allocated in this function, and freed by the calling function.\r
959 This buffer is used to accommodate all the sense data returned \r
960 by the device.\r
961\r
962 UINTN OUT *BufUnit\r
963 record the unit size of the sense data block in the SenseBuffers,\r
964\r
965 UINTN OUT *BufNumbers\r
966 record the number of units in the SenseBuffers.\r
967\r
968 Returns: \r
969 EFI_SUCCESS\r
970 Request Sense command completes successfully.\r
971\r
972 EFI_DEVICE_ERROR\r
973 Request Sense command failed.\r
974\r
975 Notes:\r
976\r
977--*/\r
978// TODO: function comment is missing 'Routine Description:'\r
979// TODO: function comment is missing 'Arguments:'\r
980// TODO: IdeDev - add argument and description to function comment\r
981// TODO: SenseCounts - add argument and description to function comment\r
982{\r
983 EFI_STATUS Status;\r
984 REQUEST_SENSE_DATA *Sense;\r
985 UINT16 *Ptr;\r
986 BOOLEAN FetchSenseData;\r
987 ATAPI_PACKET_COMMAND Packet;\r
988\r
989 *SenseCounts = 0;\r
990\r
991 ZeroMem (IdeDev->SenseData, sizeof (REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));\r
992 //\r
993 // fill command packet for Request Sense Packet Command\r
994 //\r
995 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
996 Packet.RequestSence.opcode = REQUEST_SENSE;\r
997 Packet.RequestSence.allocation_length = sizeof (REQUEST_SENSE_DATA);\r
998\r
999 //\r
1000 // initialize pointer\r
1001 //\r
1002 Ptr = (UINT16 *) IdeDev->SenseData;\r
1003 //\r
1004 // request sense data from device continuously until no sense data\r
1005 // exists in the device.\r
1006 //\r
1007 for (FetchSenseData = TRUE; FetchSenseData;) {\r
1008\r
1009 Sense = (REQUEST_SENSE_DATA *) Ptr;\r
1010\r
1011 //\r
1012 // send out Request Sense Packet Command and get one Sense data form device\r
1013 //\r
1014 Status = AtapiPacketCommandIn (\r
1015 IdeDev,\r
1016 &Packet,\r
1017 Ptr,\r
1018 sizeof (REQUEST_SENSE_DATA),\r
1019 ATAPITIMEOUT\r
1020 );\r
1021 //\r
1022 // failed to get Sense data\r
1023 //\r
1024 if (EFI_ERROR (Status)) {\r
1025 if (*SenseCounts == 0) {\r
1026 return EFI_DEVICE_ERROR;\r
1027 } else {\r
1028 return EFI_SUCCESS;\r
1029 }\r
1030 }\r
1031\r
1032 (*SenseCounts)++;\r
1033 //\r
1034 // We limit MAX sense data count to 20 in order to avoid dead loop. Some\r
1035 // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.\r
1036 // In this case, dead loop occurs if we don't have a gatekeeper. 20 is\r
1037 // supposed to be large enough for any ATAPI device.\r
1038 //\r
1039 if ((Sense->sense_key != SK_NO_SENSE) && ((*SenseCounts) < 20)) {\r
1040 //\r
1041 // Ptr is word-based pointer\r
1042 //\r
1043 Ptr += sizeof (REQUEST_SENSE_DATA) / 2;\r
1044\r
1045 } else {\r
1046 //\r
1047 // when no sense key, skip out the loop\r
1048 //\r
1049 FetchSenseData = FALSE;\r
1050 }\r
1051 }\r
1052\r
1053 return EFI_SUCCESS;\r
1054}\r
1055\r
1056EFI_STATUS\r
1057AtapiReadCapacity (\r
1058 IN IDE_BLK_IO_DEV *IdeDev\r
1059 )\r
1060/*++\r
1061 Name:\r
1062 AtapiReadCapacity\r
1063\r
1064 Purpose: \r
1065 Sends out ATAPI Read Capacity Packet Command to the specified device.\r
1066 This command will return the information regarding the capacity of the\r
1067 media in the device.\r
1068\r
1069 Current device status will impact device's response to the Read Capacity\r
1070 Command. For example, if the device once reset, the Read Capacity\r
1071 Command will fail. The Sense data record the current device status, so \r
1072 if the Read Capacity Command failed, the Sense data must be requested\r
1073 and be analyzed to determine if the Read Capacity Command should retry.\r
1074\r
1075\r
1076 Parameters:\r
1077 IDE_BLK_IO_DEV IN *IdeDev\r
1078 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1079 to record all the information of the IDE device.\r
1080\r
1081 Returns: \r
1082 EFI_SUCCESS\r
1083 Read Capacity Command finally completes successfully.\r
1084\r
1085 EFI_DEVICE_ERROR\r
1086 Read Capacity Command failed because of device error.\r
1087\r
1088 Notes:\r
1089 parameter "IdeDev" will be updated in this function.\r
1090--*/\r
1091// TODO: function comment is missing 'Routine Description:'\r
1092// TODO: function comment is missing 'Arguments:'\r
1093// TODO: IdeDev - add argument and description to function comment\r
1094// TODO: EFI_NOT_READY - add return value to function comment\r
1095{\r
1096 //\r
1097 // status returned by Read Capacity Packet Command\r
1098 //\r
1099 EFI_STATUS Status;\r
1100 ATAPI_PACKET_COMMAND Packet;\r
1101\r
1102 //\r
1103 // used for capacity data returned from ATAPI device\r
1104 //\r
1105 READ_CAPACITY_DATA Data;\r
1106 READ_FORMAT_CAPACITY_DATA FormatData;\r
1107\r
1108 ZeroMem (&Data, sizeof (Data));\r
1109 ZeroMem (&FormatData, sizeof (FormatData));\r
1110\r
1111 if (IdeDev->Type == IdeCdRom) {\r
1112\r
1113 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1114 Packet.Inquiry.opcode = READ_CAPACITY;\r
1115 Status = AtapiPacketCommandIn (\r
1116 IdeDev,\r
1117 &Packet,\r
1118 (UINT16 *) &Data,\r
1119 sizeof (READ_CAPACITY_DATA),\r
1120 ATAPITIMEOUT\r
1121 );\r
1122\r
1123 } else {\r
1124 //\r
1125 // Type == IdeMagnetic\r
1126 //\r
1127 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1128 Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY;\r
1129 Packet.ReadFormatCapacity.allocation_length_lo = 12;\r
1130 Status = AtapiPacketCommandIn (\r
1131 IdeDev,\r
1132 &Packet,\r
1133 (UINT16 *) &FormatData,\r
1134 sizeof (READ_FORMAT_CAPACITY_DATA),\r
1135 ATAPITIMEOUT\r
1136 );\r
1137 }\r
1138\r
1139 if (!EFI_ERROR (Status)) {\r
1140\r
1141 if (IdeDev->Type == IdeCdRom) {\r
1142\r
1143 IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |\r
1144 (Data.LastLba2 << 16) |\r
1145 (Data.LastLba1 << 8) |\r
1146 Data.LastLba0;\r
1147\r
1148 if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
1149\r
1150 IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) |\r
1151 (Data.BlockSize2 << 16) |\r
1152 (Data.BlockSize1 << 8) |\r
1153 Data.BlockSize0;\r
1154\r
1155 IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
1156 } else {\r
1157 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
1158 return EFI_DEVICE_ERROR;\r
1159 }\r
1160\r
1161 IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
1162\r
1163 //\r
1164 // Because the user data portion in the sector of the Data CD supported\r
1165 // is always 0x800\r
1166 //\r
1167 IdeDev->BlkIo.Media->BlockSize = 0x800;\r
1168 }\r
1169\r
1170 if (IdeDev->Type == IdeMagnetic) {\r
1171\r
1172 if (FormatData.DesCode == 3) {\r
1173 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
1174 IdeDev->BlkIo.Media->LastBlock = 0;\r
1175 } else {\r
1176\r
1177 IdeDev->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) |\r
1178 (FormatData.LastLba2 << 16) | \r
1179 (FormatData.LastLba1 << 8) |\r
1180 FormatData.LastLba0;\r
1181 if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
1182 IdeDev->BlkIo.Media->LastBlock--;\r
1183\r
1184 IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |\r
1185 (FormatData.BlockSize1 << 8) |\r
1186 FormatData.BlockSize0;\r
1187\r
1188 IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
1189 } else {\r
1190 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
1191 //\r
1192 // Return EFI_NOT_READY operation succeeds but returned capacity is 0\r
1193 //\r
1194 return EFI_NOT_READY;\r
1195 }\r
1196\r
1197 IdeDev->BlkIo.Media->BlockSize = 0x200;\r
1198\r
1199 }\r
1200 }\r
1201\r
1202 return EFI_SUCCESS;\r
1203\r
1204 } else {\r
1205\r
1206 return EFI_DEVICE_ERROR;\r
1207 }\r
1208}\r
1209\r
1210EFI_STATUS\r
1211AtapiDetectMedia (\r
1212 IN IDE_BLK_IO_DEV *IdeDev,\r
1213 OUT BOOLEAN *MediaChange\r
1214 )\r
1215/*++\r
1216 Name:\r
1217 AtapiDetectMedia\r
1218\r
1219 Purpose: \r
1220 Used before read/write blocks from/to ATAPI device media. \r
1221 Since ATAPI device media is removable, it is necessary to detect\r
1222 whether media is present and get current present media's\r
1223 information, and if media has been changed, Block I/O Protocol\r
1224 need to be reinstalled.\r
1225\r
1226 Parameters:\r
1227 IDE_BLK_IO_DEV IN *IdeDev\r
1228 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1229 to record all the information of the IDE device.\r
1230\r
1231 BOOLEAN OUT *MediaChange\r
1232 return value that indicates if the media of the device has been\r
1233 changed.\r
1234\r
1235 Returns: \r
1236 EFI_SUCCESS\r
1237 media found successfully.\r
1238\r
1239 EFI_DEVICE_ERROR\r
1240 any error encounters during media detection.\r
1241 \r
1242 EFI_NO_MEDIA\r
1243 media not found.\r
1244\r
1245 Notes:\r
1246 parameter IdeDev may be updated in this function.\r
1247--*/\r
1248// TODO: function comment is missing 'Routine Description:'\r
1249// TODO: function comment is missing 'Arguments:'\r
1250// TODO: IdeDev - add argument and description to function comment\r
1251// TODO: MediaChange - add argument and description to function comment\r
1252{\r
1253 EFI_STATUS Status;\r
1254 EFI_STATUS ReadCapacityStatus;\r
1255 EFI_BLOCK_IO_MEDIA OldMediaInfo;\r
1256 UINTN SenseCounts;\r
1257 UINTN RetryIndex;\r
1258 UINTN RetryTimes;\r
1259 UINTN MaximumRetryTimes;\r
1260 UINTN ReadyWaitFactor;\r
1261 BOOLEAN NeedRetry;\r
1262 //\r
1263 // a flag used to determine whether need to perform Read Capacity command.\r
1264 //\r
1265 BOOLEAN NeedReadCapacity;\r
1266 BOOLEAN WriteProtected;\r
1267\r
1268 //\r
1269 // init\r
1270 //\r
1271 CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (OldMediaInfo));\r
1272 // OldMediaInfo = *(IdeDev->BlkIo.Media);\r
1273 *MediaChange = FALSE;\r
1274 ReadCapacityStatus = EFI_DEVICE_ERROR;\r
1275\r
1276 //\r
1277 // if there is no media, or media is not changed,\r
1278 // the request sense command will detect faster than read capacity command.\r
1279 // read capacity command can be bypassed, thus improve performance.\r
1280 //\r
1281\r
1282 //\r
1283 // Test Unit Ready command is used to detect whether device is accessible,\r
1284 // the device will produce corresponding Sense data.\r
1285 //\r
1286 for (RetryIndex = 0; RetryIndex < 2; RetryIndex++) {\r
1287\r
1288 Status = AtapiTestUnitReady (IdeDev);\r
1289 if (!EFI_ERROR (Status)) {\r
1290 //\r
1291 // skip the loop if test unit command succeeds.\r
1292 //\r
1293 break;\r
1294 }\r
1295\r
1296 Status = AtapiSoftReset (IdeDev);\r
1297\r
1298 if (EFI_ERROR (Status)) {\r
1299 AtaSoftReset (IdeDev);\r
1300 }\r
1301 }\r
1302\r
1303 SenseCounts = 0;\r
1304 NeedReadCapacity = TRUE;\r
1305\r
1306 //\r
1307 // at most retry 5 times\r
1308 //\r
1309 MaximumRetryTimes = 5;\r
1310 RetryTimes = 1;\r
1311\r
1312 for (RetryIndex = 0; \r
1313 (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes);\r
1314 RetryIndex++) {\r
1315\r
1316 Status = AtapiRequestSense (IdeDev, &SenseCounts);\r
1317\r
1318 if (!EFI_ERROR (Status)) {\r
1319 //\r
1320 // if first time there is no Sense Key, no need to read capacity any more\r
1321 //\r
1322 if (!HaveSenseKey (IdeDev->SenseData, SenseCounts) &&\r
1323 (IdeDev->BlkIo.Media->MediaPresent)) {\r
1324\r
1325 if (RetryIndex == 0) {\r
1326 NeedReadCapacity = FALSE;\r
1327 }\r
1328\r
1329 } else {\r
1330 //\r
1331 // No Media\r
1332 //\r
1333 if (IsNoMedia (IdeDev->SenseData, SenseCounts)) {\r
1334 NeedReadCapacity = FALSE;\r
1335 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
1336 IdeDev->BlkIo.Media->LastBlock = 0;\r
1337 } else {\r
1338 //\r
1339 // Media Changed\r
1340 //\r
1341 if (IsMediaChange (IdeDev->SenseData, SenseCounts)) {\r
1342 NeedReadCapacity = TRUE;\r
1343 IdeDev->BlkIo.Media->MediaId++;\r
1344 }\r
1345 //\r
1346 // Media Error\r
1347 //\r
1348 if (IsMediaError (IdeDev->SenseData, SenseCounts)) {\r
1349 return EFI_DEVICE_ERROR;\r
1350 }\r
1351 }\r
1352 }\r
1353 } else {\r
1354 //\r
1355 // retry once more, if request sense command met errors.\r
1356 //\r
1357 RetryTimes++;\r
1358 }\r
1359 }\r
1360\r
1361 if (NeedReadCapacity) {\r
1362 //\r
1363 // at most retry 5 times\r
1364 //\r
1365 MaximumRetryTimes = 5;\r
1366 //\r
1367 // initial retry twice\r
1368 //\r
1369 RetryTimes = 2;\r
1370 ReadyWaitFactor = 2;\r
1371\r
1372 for (RetryIndex = 0;\r
1373 (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes);\r
1374 RetryIndex++) {\r
1375\r
1376 ReadCapacityStatus = AtapiReadCapacity (IdeDev);\r
1377\r
1378 SenseCounts = 0;\r
1379\r
1380 if (!EFI_ERROR (ReadCapacityStatus)) {\r
1381 //\r
1382 // Read Capacity succeeded\r
1383 //\r
1384 break;\r
1385\r
1386 } else {\r
1387\r
1388 if (ReadCapacityStatus == EFI_NOT_READY) {\r
1389 //\r
1390 // If device not ready, wait here... waiting time increases by retry\r
1391 // times.\r
1392 //\r
1393 gBS->Stall (ReadyWaitFactor * 2000 * STALL_1_MILLI_SECOND);\r
1394 ReadyWaitFactor++;\r
1395 //\r
1396 // retry once more\r
1397 //\r
1398 RetryTimes++;\r
1399 continue;\r
1400 }\r
1401 \r
1402 //\r
1403 // Other errors returned, requery sense data\r
1404 //\r
1405 Status = AtapiRequestSense (IdeDev, &SenseCounts);\r
1406\r
1407 //\r
1408 // If Request Sense data failed, reset the device and retry.\r
1409 //\r
1410 if (EFI_ERROR (Status)) {\r
1411\r
1412 Status = AtapiSoftReset (IdeDev);\r
1413\r
1414 //\r
1415 // if ATAPI soft reset fail,\r
1416 // use stronger reset mechanism -- ATA soft reset.\r
1417 //\r
1418 if (EFI_ERROR (Status)) {\r
1419 AtaSoftReset (IdeDev);\r
1420 }\r
1421 //\r
1422 // retry once more\r
1423 //\r
1424 RetryTimes++;\r
1425 continue;\r
1426 }\r
1427 \r
1428 //\r
1429 // No Media\r
1430 //\r
1431 if (IsNoMedia (IdeDev->SenseData, SenseCounts)) {\r
1432\r
1433 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
1434 IdeDev->BlkIo.Media->LastBlock = 0;\r
1435 return EFI_NO_MEDIA;\r
1436 }\r
1437\r
1438 if (IsMediaError (IdeDev->SenseData, SenseCounts)) {\r
1439 return EFI_DEVICE_ERROR;\r
1440 }\r
1441 \r
1442 //\r
1443 // Media Changed\r
1444 //\r
1445 if (IsMediaChange (IdeDev->SenseData, SenseCounts)) {\r
1446 IdeDev->BlkIo.Media->MediaId++;\r
1447 }\r
1448\r
1449 if (!IsDriveReady (IdeDev->SenseData, SenseCounts, &NeedRetry)) {\r
1450 \r
1451 //\r
1452 // Drive not ready: if NeedRetry, then retry once more;\r
1453 // else return error\r
1454 //\r
1455 if (NeedRetry) {\r
1456 //\r
1457 // Stall 1 second to wait for drive becoming ready\r
1458 //\r
1459 gBS->Stall (1000 * STALL_1_MILLI_SECOND);\r
1460 //\r
1461 // reset retry variable to zero,\r
1462 // to make it retry for "drive in progress of becoming ready".\r
1463 //\r
1464 RetryIndex = 0;\r
1465 continue;\r
1466 } else {\r
1467 AtapiSoftReset (IdeDev);\r
1468 return EFI_DEVICE_ERROR;\r
1469 }\r
1470 }\r
1471 //\r
1472 // if read capacity fail not for above reasons, retry once more\r
1473 //\r
1474 RetryTimes++;\r
1475 }\r
1476\r
1477 }\r
1478 \r
1479 //\r
1480 // tell whether the readcapacity process is successful or not in the end\r
1481 //\r
1482 if (EFI_ERROR (ReadCapacityStatus)) {\r
1483 return EFI_DEVICE_ERROR;\r
1484 }\r
1485 }\r
1486\r
1487 //\r
1488 // the following code is to check the write-protected for LS120 media\r
1489 //\r
1490 if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) {\r
1491\r
1492 Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected);\r
1493 if (!EFI_ERROR (Status)) {\r
1494\r
1495 if (WriteProtected) {\r
1496\r
1497 IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
1498 } else {\r
1499\r
1500 IdeDev->BlkIo.Media->ReadOnly = FALSE;\r
1501 }\r
1502\r
1503 }\r
1504 }\r
1505\r
1506 if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) {\r
1507 //\r
1508 // Media change information got from the device\r
1509 //\r
1510 *MediaChange = TRUE;\r
1511 }\r
1512\r
1513 if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) {\r
1514 *MediaChange = TRUE;\r
1515 IdeDev->BlkIo.Media->MediaId += 1;\r
1516 }\r
1517\r
1518 if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) {\r
1519 *MediaChange = TRUE;\r
1520 IdeDev->BlkIo.Media->MediaId += 1;\r
1521 }\r
1522\r
1523 if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) {\r
1524 *MediaChange = TRUE;\r
1525 IdeDev->BlkIo.Media->MediaId += 1;\r
1526 }\r
1527\r
1528 if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) {\r
1529 if (IdeDev->BlkIo.Media->MediaPresent) {\r
1530 //\r
1531 // when change from no media to media present, reset the MediaId to 1.\r
1532 //\r
1533 IdeDev->BlkIo.Media->MediaId = 1;\r
1534 } else {\r
1535 //\r
1536 // when no media, reset the MediaId to zero.\r
1537 //\r
1538 IdeDev->BlkIo.Media->MediaId = 0;\r
1539 }\r
1540\r
1541 *MediaChange = TRUE;\r
1542 }\r
1543\r
1544 //\r
1545 // if any change on current existing media,\r
1546 // the Block I/O protocol need to be reinstalled.\r
1547 //\r
1548 if (*MediaChange) {\r
1549 gBS->ReinstallProtocolInterface (\r
1550 IdeDev->Handle,\r
1551 &gEfiBlockIoProtocolGuid,\r
1552 &IdeDev->BlkIo,\r
1553 &IdeDev->BlkIo\r
1554 );\r
1555 }\r
1556\r
1557 return EFI_SUCCESS;\r
1558\r
1559}\r
1560\r
1561EFI_STATUS\r
1562AtapiReadSectors (\r
1563 IN IDE_BLK_IO_DEV *IdeDev,\r
1564 IN VOID *Buffer,\r
1565 IN EFI_LBA Lba,\r
1566 IN UINTN NumberOfBlocks\r
1567 )\r
1568/*++\r
1569 Name:\r
1570 AtapiReadSectors\r
1571\r
1572 Purpose: \r
1573 This function is called by the AtapiBlkIoReadBlocks() to perform\r
1574 read from media in block unit.\r
1575\r
1576 The main command used to access media here is READ(10) Command. \r
1577 READ(10) Command requests that the ATAPI device media transfer \r
1578 specified data to the host. Data is transferred in block(sector) \r
1579 unit. The maximum number of blocks that can be transferred once is\r
1580 65536. This is the main difference between READ(10) and READ(12) \r
1581 Command. The maximum number of blocks in READ(12) is 2 power 32.\r
1582\r
1583 Parameters:\r
1584 IDE_BLK_IO_DEV IN *IdeDev\r
1585 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1586 to record all the information of the IDE device.\r
1587\r
1588 VOID IN *Buffer\r
1589 A pointer to the destination buffer for the data. \r
1590\r
1591 EFI_LBA IN Lba\r
1592 The starting logical block address to read from \r
1593 on the device media.\r
1594\r
1595 UINTN IN NumberOfBlocks\r
1596 The number of transfer data blocks.\r
1597\r
1598 Returns: \r
1599 return status is fully dependent on the return status\r
1600 of AtapiPacketCommandIn() function.\r
1601\r
1602 Notes:\r
1603\r
1604--*/\r
1605// TODO: function comment is missing 'Routine Description:'\r
1606// TODO: function comment is missing 'Arguments:'\r
1607// TODO: IdeDev - add argument and description to function comment\r
1608// TODO: Buffer - add argument and description to function comment\r
1609// TODO: Lba - add argument and description to function comment\r
1610// TODO: NumberOfBlocks - add argument and description to function comment\r
1611{\r
1612\r
1613 ATAPI_PACKET_COMMAND Packet;\r
1614 READ10_CMD *Read10Packet;\r
1615 EFI_STATUS Status;\r
1616 UINTN BlocksRemaining;\r
1617 UINT32 Lba32;\r
1618 UINT32 BlockSize;\r
1619 UINT32 ByteCount;\r
1620 UINT16 SectorCount;\r
1621 VOID *PtrBuffer;\r
1622 UINT16 MaxBlock;\r
1623 UINTN TimeOut;\r
1624\r
1625 //\r
1626 // fill command packet for Read(10) command\r
1627 //\r
1628 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1629 Read10Packet = &Packet.Read10;\r
1630 Lba32 = (UINT32) Lba;\r
1631 PtrBuffer = Buffer;\r
1632\r
1633 BlockSize = IdeDev->BlkIo.Media->BlockSize;\r
1634\r
1635 //\r
1636 // limit the data bytes that can be transferred by one Read(10) Command\r
1637 //\r
1638 MaxBlock = (UINT16) (65536 / BlockSize);\r
1639\r
1640 BlocksRemaining = NumberOfBlocks;\r
1641\r
1642 Status = EFI_SUCCESS;\r
1643 while (BlocksRemaining > 0) {\r
1644\r
1645 if (BlocksRemaining <= MaxBlock) {\r
1646\r
1647 SectorCount = (UINT16) BlocksRemaining;\r
1648 } else {\r
1649\r
1650 SectorCount = MaxBlock;\r
1651 }\r
1652\r
1653 //\r
1654 // fill the Packet data structure\r
1655 //\r
1656\r
1657 Read10Packet->opcode = READ_10;\r
1658\r
1659 //\r
1660 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
1661 // Lba0 is MSB, Lba3 is LSB\r
1662 //\r
1663 Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r
1664 Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r
1665 Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r
1666 Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r
1667\r
1668 //\r
1669 // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
1670 // TranLen0 is MSB, TranLen is LSB\r
1671 //\r
1672 Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r
1673 Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r
1674\r
1675 ByteCount = SectorCount * BlockSize;\r
1676\r
1677 if (IdeDev->Type == IdeCdRom) {\r
1678 TimeOut = CDROMLONGTIMEOUT;\r
1679 } else {\r
1680 TimeOut = ATAPILONGTIMEOUT;\r
1681 }\r
1682\r
1683 Status = AtapiPacketCommandIn (\r
1684 IdeDev,\r
1685 &Packet,\r
1686 (UINT16 *) PtrBuffer,\r
1687 ByteCount,\r
1688 TimeOut\r
1689 );\r
1690 if (EFI_ERROR (Status)) {\r
1691 return Status;\r
1692 }\r
1693\r
1694 Lba32 += SectorCount;\r
1695 PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;\r
1696 BlocksRemaining -= SectorCount;\r
1697 }\r
1698\r
1699 return Status;\r
1700}\r
1701\r
1702EFI_STATUS\r
1703AtapiWriteSectors (\r
1704 IN IDE_BLK_IO_DEV *IdeDev,\r
1705 IN VOID *Buffer,\r
1706 IN EFI_LBA Lba,\r
1707 IN UINTN NumberOfBlocks\r
1708 )\r
1709/*++\r
1710 Name:\r
1711 AtapiWriteSectors\r
1712\r
1713 Purpose: \r
1714 This function is called by the AtapiBlkIoWriteBlocks() to perform\r
1715 write onto media in block unit.\r
1716 The main command used to access media here is Write(10) Command. \r
1717 Write(10) Command requests that the ATAPI device media transfer \r
1718 specified data to the host. Data is transferred in block (sector) \r
1719 unit. The maximum number of blocks that can be transferred once is\r
1720 65536. \r
1721\r
1722 Parameters:\r
1723 IDE_BLK_IO_DEV IN *IdeDev\r
1724 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1725 to record all the information of the IDE device.\r
1726\r
1727 VOID IN *Buffer\r
1728 A pointer to the source buffer for the data. \r
1729\r
1730 EFI_LBA IN Lba\r
1731 The starting logical block address to write onto \r
1732 the device media.\r
1733\r
1734 UINTN IN NumberOfBlocks\r
1735 The number of transfer data blocks.\r
1736\r
1737 Returns: \r
1738 return status is fully dependent on the return status\r
1739 of AtapiPacketCommandOut() function.\r
1740\r
1741 Notes:\r
1742\r
1743--*/\r
1744// TODO: function comment is missing 'Routine Description:'\r
1745// TODO: function comment is missing 'Arguments:'\r
1746// TODO: IdeDev - add argument and description to function comment\r
1747// TODO: Buffer - add argument and description to function comment\r
1748// TODO: Lba - add argument and description to function comment\r
1749// TODO: NumberOfBlocks - add argument and description to function comment\r
1750{\r
1751\r
1752 ATAPI_PACKET_COMMAND Packet;\r
1753 READ10_CMD *Read10Packet;\r
1754\r
1755 EFI_STATUS Status;\r
1756 UINTN BlocksRemaining;\r
1757 UINT32 Lba32;\r
1758 UINT32 BlockSize;\r
1759 UINT32 ByteCount;\r
1760 UINT16 SectorCount;\r
1761 VOID *PtrBuffer;\r
1762 UINT16 MaxBlock;\r
1763\r
1764 //\r
1765 // fill command packet for Write(10) command\r
1766 // Write(10) command packet has the same data structure as\r
1767 // Read(10) command packet,\r
1768 // so here use the Read10Packet data structure\r
1769 // for the Write(10) command packet.\r
1770 //\r
1771 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1772 Read10Packet = &Packet.Read10;\r
1773\r
1774 Lba32 = (UINT32) Lba;\r
1775 PtrBuffer = Buffer;\r
1776\r
1777 BlockSize = IdeDev->BlkIo.Media->BlockSize;\r
1778\r
1779 //\r
1780 // limit the data bytes that can be transferred by one Read(10) Command\r
1781 //\r
1782 MaxBlock = (UINT16) (65536 / BlockSize);\r
1783\r
1784 BlocksRemaining = NumberOfBlocks;\r
1785\r
1786 Status = EFI_SUCCESS;\r
1787 while (BlocksRemaining > 0) {\r
1788\r
1789 if (BlocksRemaining >= MaxBlock) {\r
1790 SectorCount = MaxBlock;\r
1791 } else {\r
1792 SectorCount = (UINT16) BlocksRemaining;\r
1793 }\r
1794 \r
1795 //\r
1796 // Command code is WRITE_10.\r
1797 //\r
1798 Read10Packet->opcode = WRITE_10;\r
1799\r
1800 //\r
1801 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
1802 // Lba0 is MSB, Lba3 is LSB\r
1803 //\r
1804 Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r
1805 Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r
1806 Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r
1807 Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r
1808\r
1809 //\r
1810 // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
1811 // TranLen0 is MSB, TranLen is LSB\r
1812 //\r
1813 Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r
1814 Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r
1815\r
1816 ByteCount = SectorCount * BlockSize;\r
1817\r
1818 Status = AtapiPacketCommandOut (\r
1819 IdeDev,\r
1820 &Packet,\r
1821 (UINT16 *) PtrBuffer,\r
1822 ByteCount,\r
1823 ATAPILONGTIMEOUT\r
1824 );\r
1825 if (EFI_ERROR (Status)) {\r
1826 return Status;\r
1827 }\r
1828\r
1829 Lba32 += SectorCount;\r
1830 PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize);\r
1831 BlocksRemaining -= SectorCount;\r
1832 }\r
1833\r
1834 return Status;\r
1835}\r
1836\r
1837EFI_STATUS\r
1838AtapiSoftReset (\r
1839 IN IDE_BLK_IO_DEV *IdeDev\r
1840 )\r
1841/*++\r
1842 Name:\r
1843 AtapiSoftReset\r
1844\r
1845 Purpose: \r
1846 This function is used to implement the Soft Reset on the specified\r
1847 ATAPI device. Different from the AtaSoftReset(), here reset is a ATA\r
1848 Soft Reset Command special for ATAPI device, and it only take effects\r
1849 on the specified ATAPI device, not on the whole IDE bus.\r
1850 Since the ATAPI soft reset is needed when device is in exceptional\r
1851 condition (such as BSY bit is always set ), I think the Soft Reset\r
1852 command should be sent without waiting for the BSY clear and DRDY\r
1853 set.\r
1854 This function is called by IdeBlkIoReset(), \r
1855 a interface function of Block I/O protocol.\r
1856\r
1857 \r
1858 Parameters:\r
1859 IDE_BLK_IO_DEV IN *IdeDev\r
1860 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1861 to record all the information of the IDE device.\r
1862\r
1863 Returns: \r
1864 EFI_SUCCESS\r
1865 Soft reset completes successfully.\r
1866\r
1867 EFI_DEVICE_ERROR\r
1868 Any step during the reset process is failed.\r
1869\r
1870 Notes:\r
1871\r
1872--*/\r
1873// TODO: function comment is missing 'Routine Description:'\r
1874// TODO: function comment is missing 'Arguments:'\r
1875// TODO: IdeDev - add argument and description to function comment\r
1876{\r
1877 UINT8 Command;\r
1878 UINT8 DeviceSelect;\r
1879 EFI_STATUS Status;\r
1880\r
1881 //\r
1882 // for ATAPI device, no need to wait DRDY ready after device selecting.\r
1883 // (bit7 and bit5 are both set to 1 for backward compatibility)\r
1884 //\r
1885 DeviceSelect = (UINT8) (((bit7 | bit5) | (IdeDev->Device << 4)));\r
1886 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
1887\r
1888 Command = ATAPI_SOFT_RESET_CMD;\r
1889 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command);\r
1890\r
1891 //\r
1892 // BSY cleared is the only status return to the host by the device\r
1893 // when reset is completed.\r
1894 // slave device needs at most 31s to clear BSY\r
1895 //\r
1896 Status = WaitForBSYClear (IdeDev, 31000);\r
1897 if (EFI_ERROR (Status)) {\r
1898 return EFI_DEVICE_ERROR;\r
1899 }\r
1900 \r
1901 //\r
1902 // stall 5 seconds to make the device status stable\r
1903 //\r
1904 gBS->Stall (5000000);\r
1905\r
1906 return EFI_SUCCESS;\r
1907}\r
1908\r
1909EFI_STATUS\r
1910AtapiBlkIoReadBlocks (\r
1911 IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
1912 IN UINT32 MediaId,\r
1913 IN EFI_LBA LBA,\r
1914 IN UINTN BufferSize,\r
1915 OUT VOID *Buffer\r
1916 )\r
1917/*++\r
1918 Name:\r
1919 AtapiBlkIoReadBlocks\r
1920\r
1921 Purpose: \r
1922 This function is the ATAPI implementation for ReadBlocks in the\r
1923 Block I/O Protocol interface.\r
1924\r
1925 Parameters:\r
1926 IDE_BLK_IO_DEV IN *IdeBlkIoDev\r
1927 Indicates the calling context.\r
1928\r
1929 UINT32 IN MediaId\r
1930 The media id that the read request is for.\r
1931\r
1932 EFI_LBA IN LBA\r
1933 The starting logical block address to read from \r
1934 on the device.\r
1935\r
1936 UINTN IN BufferSize\r
1937 The size of the Buffer in bytes. This must be a\r
1938 multiple of the intrinsic block size of the device.\r
1939\r
1940 VOID OUT *Buffer\r
1941 A pointer to the destination buffer for the data. \r
1942 The caller is responsible for either having implicit\r
1943 or explicit ownership of the memory that data is read into.\r
1944\r
1945 Returns: \r
1946 EFI_SUCCESS \r
1947 Read Blocks successfully.\r
1948\r
1949 EFI_DEVICE_ERROR\r
1950 Read Blocks failed.\r
1951\r
1952 EFI_NO_MEDIA\r
1953 There is no media in the device.\r
1954\r
1955 EFI_MEDIA_CHANGED\r
1956 The MediaId is not for the current media.\r
1957\r
1958 EFI_BAD_BUFFER_SIZE\r
1959 The BufferSize parameter is not a multiple of the \r
1960 intrinsic block size of the device.\r
1961\r
1962 EFI_INVALID_PARAMETER\r
1963 The read request contains LBAs that are not valid,\r
1964 or the data buffer is not valid.\r
1965\r
1966 Notes:\r
1967\r
1968--*/\r
1969// TODO: function comment is missing 'Routine Description:'\r
1970// TODO: function comment is missing 'Arguments:'\r
1971// TODO: IdeBlkIoDevice - add argument and description to function comment\r
1972// TODO: MediaId - add argument and description to function comment\r
1973// TODO: LBA - add argument and description to function comment\r
1974// TODO: BufferSize - add argument and description to function comment\r
1975// TODO: Buffer - add argument and description to function comment\r
1976{\r
1977 EFI_BLOCK_IO_MEDIA *Media;\r
1978 UINTN BlockSize;\r
1979 UINTN NumberOfBlocks;\r
1980 EFI_STATUS Status;\r
1981\r
1982 BOOLEAN MediaChange;\r
1983\r
1984 if (Buffer == NULL) {\r
1985 return EFI_INVALID_PARAMETER;\r
1986 }\r
1987\r
1988 if (BufferSize == 0) {\r
1989 return EFI_SUCCESS;\r
1990 }\r
1991\r
1992 //\r
1993 // ATAPI device media is removable, so it is a must\r
1994 // to detect media first before read operation\r
1995 //\r
1996 MediaChange = FALSE;\r
1997 Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);\r
1998 if (EFI_ERROR (Status)) {\r
1999\r
2000 if (IdeBlkIoDevice->Cache != NULL) {\r
2001 gBS->FreePool (IdeBlkIoDevice->Cache);\r
2002 IdeBlkIoDevice->Cache = NULL;\r
2003 }\r
2004\r
2005 return Status;\r
2006 }\r
2007 //\r
2008 // Get the intrinsic block size\r
2009 //\r
2010 Media = IdeBlkIoDevice->BlkIo.Media;\r
2011 BlockSize = Media->BlockSize;\r
2012\r
2013 NumberOfBlocks = BufferSize / BlockSize;\r
2014\r
2015 if (!(Media->MediaPresent)) {\r
2016\r
2017 if (IdeBlkIoDevice->Cache != NULL) {\r
2018 gBS->FreePool (IdeBlkIoDevice->Cache);\r
2019 IdeBlkIoDevice->Cache = NULL;\r
2020 }\r
2021 return EFI_NO_MEDIA;\r
2022\r
2023 }\r
2024\r
2025 if ((MediaId != Media->MediaId) || MediaChange) {\r
2026\r
2027 if (IdeBlkIoDevice->Cache != NULL) {\r
2028 gBS->FreePool (IdeBlkIoDevice->Cache);\r
2029 IdeBlkIoDevice->Cache = NULL;\r
2030 }\r
2031 return EFI_MEDIA_CHANGED;\r
2032 }\r
2033\r
2034 if (BufferSize % BlockSize != 0) {\r
2035 return EFI_BAD_BUFFER_SIZE;\r
2036 }\r
2037\r
2038 if (LBA > Media->LastBlock) {\r
2039 return EFI_INVALID_PARAMETER;\r
2040 }\r
2041\r
2042 if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
2043 return EFI_INVALID_PARAMETER;\r
2044 }\r
2045\r
2046 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
2047 return EFI_INVALID_PARAMETER;\r
2048 }\r
2049\r
2050 //\r
2051 // if all the parameters are valid, then perform read sectors command\r
2052 // to transfer data from device to host.\r
2053 //\r
2054 Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
2055 if (EFI_ERROR (Status)) {\r
2056 return EFI_DEVICE_ERROR;\r
2057 }\r
2058 \r
2059 //\r
2060 // Read blocks succeeded\r
2061 //\r
2062 \r
2063 //\r
2064 // save the first block to the cache for performance\r
2065 //\r
2066 if (LBA == 0 && !IdeBlkIoDevice->Cache) {\r
2067 IdeBlkIoDevice->Cache = AllocatePool (BlockSize);\r
2068 if (IdeBlkIoDevice != NULL) {\r
2069 CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);\r
2070 }\r
2071 }\r
2072\r
2073 return EFI_SUCCESS;\r
2074\r
2075}\r
2076\r
2077EFI_STATUS\r
2078AtapiBlkIoWriteBlocks (\r
2079 IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
2080 IN UINT32 MediaId,\r
2081 IN EFI_LBA LBA,\r
2082 IN UINTN BufferSize,\r
2083 OUT VOID *Buffer\r
2084 )\r
2085/*++\r
2086 Name:\r
2087 AtapiBlkIoWriteBlocks\r
2088\r
2089 Purpose: \r
2090 This function is the ATAPI implementation for WriteBlocks in the\r
2091 Block I/O Protocol interface.\r
2092\r
2093 Parameters:\r
2094 EFI_BLOCK_IO IN *This\r
2095 Indicates the calling context.\r
2096\r
2097 UINT32 IN MediaId\r
2098 The media id that the write request is for.\r
2099\r
2100 EFI_LBA IN LBA\r
2101 The starting logical block address to write onto \r
2102 the device.\r
2103\r
2104 UINTN IN BufferSize\r
2105 The size of the Buffer in bytes. This must be a\r
2106 multiple of the intrinsic block size of the device.\r
2107\r
2108 VOID OUT *Buffer\r
2109 A pointer to the source buffer for the data. \r
2110 The caller is responsible for either having implicit\r
2111 or explicit ownership of the memory that data is \r
2112 written from.\r
2113\r
2114 Returns: \r
2115 EFI_SUCCESS \r
2116 Write Blocks successfully.\r
2117\r
2118 EFI_DEVICE_ERROR\r
2119 Write Blocks failed.\r
2120\r
2121 EFI_NO_MEDIA\r
2122 There is no media in the device.\r
2123\r
2124 EFI_MEDIA_CHANGE\r
2125 The MediaId is not for the current media.\r
2126\r
2127 EFI_BAD_BUFFER_SIZE\r
2128 The BufferSize parameter is not a multiple of the \r
2129 intrinsic block size of the device.\r
2130\r
2131 EFI_INVALID_PARAMETER\r
2132 The write request contains LBAs that are not valid,\r
2133 or the data buffer is not valid. \r
2134\r
2135 Notes:\r
2136\r
2137--*/\r
2138// TODO: function comment is missing 'Routine Description:'\r
2139// TODO: function comment is missing 'Arguments:'\r
2140// TODO: IdeBlkIoDevice - add argument and description to function comment\r
2141// TODO: MediaId - add argument and description to function comment\r
2142// TODO: LBA - add argument and description to function comment\r
2143// TODO: BufferSize - add argument and description to function comment\r
2144// TODO: Buffer - add argument and description to function comment\r
2145// TODO: EFI_MEDIA_CHANGED - add return value to function comment\r
2146// TODO: EFI_WRITE_PROTECTED - add return value to function comment\r
2147{\r
2148\r
2149 EFI_BLOCK_IO_MEDIA *Media;\r
2150 UINTN BlockSize;\r
2151 UINTN NumberOfBlocks;\r
2152 EFI_STATUS Status;\r
2153 BOOLEAN MediaChange;\r
2154\r
2155 if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
2156 gBS->FreePool (IdeBlkIoDevice->Cache);\r
2157 IdeBlkIoDevice->Cache = NULL;\r
2158 }\r
2159\r
2160 if (Buffer == NULL) {\r
2161 return EFI_INVALID_PARAMETER;\r
2162 }\r
2163\r
2164 if (BufferSize == 0) {\r
2165 return EFI_SUCCESS;\r
2166 }\r
2167\r
2168 //\r
2169 // ATAPI device media is removable,\r
2170 // so it is a must to detect media first before write operation\r
2171 //\r
2172 MediaChange = FALSE;\r
2173 Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);\r
2174 if (EFI_ERROR (Status)) {\r
2175\r
2176 if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
2177 gBS->FreePool (IdeBlkIoDevice->Cache);\r
2178 IdeBlkIoDevice->Cache = NULL;\r
2179 }\r
2180 return Status;\r
2181 }\r
2182 \r
2183 //\r
2184 // Get the intrinsic block size\r
2185 //\r
2186 Media = IdeBlkIoDevice->BlkIo.Media;\r
2187 BlockSize = Media->BlockSize;\r
2188 NumberOfBlocks = BufferSize / BlockSize;\r
2189\r
2190 if (!(Media->MediaPresent)) {\r
2191\r
2192 if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
2193 gBS->FreePool (IdeBlkIoDevice->Cache);\r
2194 IdeBlkIoDevice->Cache = NULL;\r
2195 }\r
2196 return EFI_NO_MEDIA;\r
2197 }\r
2198\r
2199 if ((MediaId != Media->MediaId) || MediaChange) {\r
2200\r
2201 if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
2202 gBS->FreePool (IdeBlkIoDevice->Cache);\r
2203 IdeBlkIoDevice->Cache = NULL;\r
2204 }\r
2205 return EFI_MEDIA_CHANGED;\r
2206 }\r
2207\r
2208 if (Media->ReadOnly) {\r
2209 return EFI_WRITE_PROTECTED;\r
2210 }\r
2211\r
2212 if (BufferSize % BlockSize != 0) {\r
2213 return EFI_BAD_BUFFER_SIZE;\r
2214 }\r
2215\r
2216 if (LBA > Media->LastBlock) {\r
2217 return EFI_INVALID_PARAMETER;\r
2218 }\r
2219\r
2220 if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
2221 return EFI_INVALID_PARAMETER;\r
2222 }\r
2223\r
2224 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
2225 return EFI_INVALID_PARAMETER;\r
2226 }\r
2227\r
2228 //\r
2229 // if all the parameters are valid,\r
2230 // then perform write sectors command to transfer data from host to device.\r
2231 //\r
2232 Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
2233 if (EFI_ERROR (Status)) {\r
2234 return EFI_DEVICE_ERROR;\r
2235 }\r
2236\r
2237 return EFI_SUCCESS;\r
2238\r
2239}\r
2240\r
2241//\r
2242// The following functions are a set of helper functions,\r
2243// which are used to parse sense key returned by the device.\r
2244//\r
2245\r
2246BOOLEAN\r
2247IsNoMedia (\r
2248 IN REQUEST_SENSE_DATA *SenseData,\r
2249 IN UINTN SenseCounts\r
2250 )\r
2251/*++\r
2252\r
2253Routine Description:\r
2254\r
2255 TODO: Add function description\r
2256\r
2257Arguments:\r
2258\r
2259 SenseData - TODO: add argument description\r
2260 SenseCounts - TODO: add argument description\r
2261\r
2262Returns:\r
2263\r
2264 TODO: add return values\r
2265\r
2266--*/\r
2267{\r
2268 REQUEST_SENSE_DATA *SensePointer;\r
2269 UINTN Index;\r
2270 BOOLEAN NoMedia;\r
2271\r
2272 NoMedia = FALSE;\r
2273 SensePointer = SenseData;\r
2274\r
2275 for (Index = 0; Index < SenseCounts; Index++) {\r
2276 //\r
2277 // Sense Key is SK_NOT_READY (0x2),\r
2278 // Additional Sense Code is ASC_NO_MEDIA (0x3A)\r
2279 //\r
2280 if ((SensePointer->sense_key == SK_NOT_READY) &&\r
2281 (SensePointer->addnl_sense_code == ASC_NO_MEDIA)) {\r
2282\r
2283 NoMedia = TRUE;\r
2284 }\r
2285\r
2286 SensePointer++;\r
2287 }\r
2288\r
2289 return NoMedia;\r
2290}\r
2291\r
2292BOOLEAN\r
2293IsMediaError (\r
2294 IN REQUEST_SENSE_DATA *SenseData,\r
2295 IN UINTN SenseCounts\r
2296 )\r
2297/*++\r
2298 Name:\r
2299 IsMediaError\r
2300\r
2301 Purpose: \r
2302 Test if the device meets a media error after media changed\r
2303\r
2304 Parameters:\r
2305 EQUEST_SENSE_DATA IN *SenseData\r
2306 pointer pointing to ATAPI device sense data list.\r
2307 UINTN IN SenseCounts\r
2308 sense data number of the list \r
2309\r
2310 Returns: \r
2311 TRUE\r
2312 Device meets a media error\r
2313\r
2314 FALSE\r
2315 No media error\r
2316--*/\r
2317// TODO: function comment is missing 'Routine Description:'\r
2318// TODO: function comment is missing 'Arguments:'\r
2319// TODO: SenseData - add argument and description to function comment\r
2320// TODO: SenseCounts - add argument and description to function comment\r
2321{\r
2322 REQUEST_SENSE_DATA *SensePointer;\r
2323 UINTN Index;\r
2324 BOOLEAN IsError;\r
2325\r
2326 IsError = FALSE;\r
2327 SensePointer = SenseData;\r
2328\r
2329 for (Index = 0; Index < SenseCounts; Index++) {\r
2330\r
2331 switch (SensePointer->sense_key) {\r
2332\r
2333 case SK_MEDIUM_ERROR:\r
2334 //\r
2335 // Sense Key is SK_MEDIUM_ERROR (0x3)\r
2336 //\r
2337 switch (SensePointer->addnl_sense_code) {\r
2338 case ASC_MEDIA_ERR1:\r
2339 case ASC_MEDIA_ERR2:\r
2340 case ASC_MEDIA_ERR3:\r
2341 case ASC_MEDIA_ERR4:\r
2342 IsError = TRUE;\r
2343 break;\r
2344\r
2345 default:\r
2346 break;\r
2347 }\r
2348\r
2349 break;\r
2350\r
2351 case SK_NOT_READY:\r
2352 //\r
2353 // Sense Key is SK_NOT_READY (0x2)\r
2354 //\r
2355 switch (SensePointer->addnl_sense_code) {\r
2356 //\r
2357 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)\r
2358 //\r
2359 case ASC_MEDIA_UPSIDE_DOWN:\r
2360 IsError = TRUE;\r
2361 break;\r
2362\r
2363 default:\r
2364 break;\r
2365 }\r
2366 break;\r
2367\r
2368 default:\r
2369 break;\r
2370 }\r
2371\r
2372 SensePointer++;\r
2373 }\r
2374\r
2375 return IsError;\r
2376}\r
2377\r
2378BOOLEAN\r
2379IsMediaChange (\r
2380 IN REQUEST_SENSE_DATA *SenseData,\r
2381 IN UINTN SenseCounts\r
2382 )\r
2383/*++\r
2384\r
2385Routine Description:\r
2386\r
2387 TODO: Add function description\r
2388\r
2389Arguments:\r
2390\r
2391 SenseData - TODO: add argument description\r
2392 SenseCounts - TODO: add argument description\r
2393\r
2394Returns:\r
2395\r
2396 TODO: add return values\r
2397\r
2398--*/\r
2399{\r
2400 REQUEST_SENSE_DATA *SensePointer;\r
2401 UINTN Index;\r
2402 BOOLEAN IsMediaChange;\r
2403\r
2404 IsMediaChange = FALSE;\r
2405 SensePointer = SenseData;\r
2406\r
2407 for (Index = 0; Index < SenseCounts; Index++) {\r
2408 //\r
2409 // Sense Key is SK_UNIT_ATTENTION (0x6)\r
2410 //\r
2411 if ((SensePointer->sense_key == SK_UNIT_ATTENTION) &&\r
2412 (SensePointer->addnl_sense_code == ASC_MEDIA_CHANGE)) {\r
2413\r
2414 IsMediaChange = TRUE;\r
2415 }\r
2416\r
2417 SensePointer++;\r
2418 }\r
2419\r
2420 return IsMediaChange;\r
2421}\r
2422\r
2423BOOLEAN\r
2424IsDriveReady (\r
2425 IN REQUEST_SENSE_DATA *SenseData,\r
2426 IN UINTN SenseCounts,\r
2427 OUT BOOLEAN *NeedRetry\r
2428 )\r
2429/*++\r
2430\r
2431Routine Description:\r
2432\r
2433 TODO: Add function description\r
2434\r
2435Arguments:\r
2436\r
2437 SenseData - TODO: add argument description\r
2438 SenseCounts - TODO: add argument description\r
2439 NeedRetry - TODO: add argument description\r
2440\r
2441Returns:\r
2442\r
2443 TODO: add return values\r
2444\r
2445--*/\r
2446{\r
2447 REQUEST_SENSE_DATA *SensePointer;\r
2448 UINTN Index;\r
2449 BOOLEAN IsReady;\r
2450\r
2451 IsReady = TRUE;\r
2452 *NeedRetry = FALSE;\r
2453 SensePointer = SenseData;\r
2454\r
2455 for (Index = 0; Index < SenseCounts; Index++) {\r
2456\r
2457 switch (SensePointer->sense_key) {\r
2458\r
2459 case SK_NOT_READY:\r
2460 //\r
2461 // Sense Key is SK_NOT_READY (0x2)\r
2462 //\r
2463 switch (SensePointer->addnl_sense_code) {\r
2464 case ASC_NOT_READY:\r
2465 //\r
2466 // Additional Sense Code is ASC_NOT_READY (0x4)\r
2467 //\r
2468 switch (SensePointer->addnl_sense_code_qualifier) {\r
2469 case ASCQ_IN_PROGRESS:\r
2470 //\r
2471 // Additional Sense Code Qualifier is ASCQ_IN_PROGRESS (0x1)\r
2472 //\r
2473 IsReady = FALSE;\r
2474 *NeedRetry = TRUE;\r
2475 break;\r
2476\r
2477 default:\r
2478 IsReady = FALSE;\r
2479 *NeedRetry = FALSE;\r
2480 break;\r
2481 }\r
2482 break;\r
2483\r
2484 default:\r
2485 break;\r
2486 }\r
2487 break;\r
2488\r
2489 default:\r
2490 break;\r
2491 }\r
2492\r
2493 SensePointer++;\r
2494 }\r
2495\r
2496 return IsReady;\r
2497}\r
2498\r
2499BOOLEAN\r
2500HaveSenseKey (\r
2501 IN REQUEST_SENSE_DATA *SenseData,\r
2502 IN UINTN SenseCounts\r
2503 )\r
2504/*++\r
2505\r
2506Routine Description:\r
2507\r
2508 TODO: Add function description\r
2509\r
2510Arguments:\r
2511\r
2512 SenseData - TODO: add argument description\r
2513 SenseCounts - TODO: add argument description\r
2514\r
2515Returns:\r
2516\r
2517 TODO: add return values\r
2518\r
2519--*/\r
2520{\r
2521 BOOLEAN Have;\r
2522\r
2523 Have = TRUE;\r
2524\r
2525 //\r
2526 // if first sense key in the Sense Data Array is SK_NO_SENSE,\r
2527 // it indicates there is no more sense key in the Sense Data Array.\r
2528 //\r
2529 if (SenseData->sense_key == SK_NO_SENSE) {\r
2530 Have = FALSE;\r
2531 }\r
2532\r
2533 return Have;\r
2534}\r
2535\r
2536EFI_STATUS\r
2537IsLS120orZipWriteProtected (\r
2538 IN IDE_BLK_IO_DEV *IdeDev,\r
2539 OUT BOOLEAN *WriteProtected\r
2540 )\r
2541/*++\r
2542\r
2543Routine Description:\r
2544\r
2545 TODO: Add function description\r
2546\r
2547Arguments:\r
2548\r
2549 IdeDev - TODO: add argument description\r
2550 WriteProtected - TODO: add argument description\r
2551\r
2552Returns:\r
2553\r
2554 EFI_DEVICE_ERROR - TODO: Add description for return value\r
2555 EFI_DEVICE_ERROR - TODO: Add description for return value\r
2556 EFI_SUCCESS - TODO: Add description for return value\r
2557\r
2558--*/\r
2559{\r
2560 EFI_STATUS Status;\r
2561\r
2562 *WriteProtected = FALSE;\r
2563\r
2564 Status = LS120EnableMediaStatus (IdeDev, TRUE);\r
2565 if (EFI_ERROR (Status)) {\r
2566 return EFI_DEVICE_ERROR;\r
2567 }\r
2568\r
2569 //\r
2570 // the Get Media Status Command is only valid\r
2571 // if a Set Features/Enable Media Status Command has been priviously issued.\r
2572 //\r
2573 if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) {\r
2574\r
2575 *WriteProtected = TRUE;\r
2576 } else {\r
2577\r
2578 *WriteProtected = FALSE;\r
2579 }\r
2580\r
2581 //\r
2582 // After Get Media Status Command completes,\r
2583 // Set Features/Disable Media Command should be sent.\r
2584 //\r
2585 Status = LS120EnableMediaStatus (IdeDev, FALSE);\r
2586 if (EFI_ERROR (Status)) {\r
2587 return EFI_DEVICE_ERROR;\r
2588 }\r
2589\r
2590 return EFI_SUCCESS;\r
2591}\r