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