]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c
IDEBusDriverBindingStart() calls REPORT_STATUS_CODE_WITH_DEVICE_PATH with NULL device...
[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
a98f11c5 786 \r
787 if (Read) {\r
788 //\r
789 // In the case where the drive wants to send more data than we need to read,\r
790 // the DRQ bit will be set and cause delays from DRQClear2().\r
791 // We need to read data from the drive until it clears DRQ so we can move on.\r
792 //\r
793 AtapiReadPendingData (IdeDev);\r
794 }\r
878ddf1f 795\r
796 //\r
797 // After data transfer is completed, normally, DRQ bit should clear.\r
798 //\r
799 Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
800 if (EFI_ERROR (Status)) {\r
801 return EFI_DEVICE_ERROR;\r
802 }\r
803\r
804 //\r
805 // read status register to check whether error happens.\r
806 //\r
807 return CheckErrorStatus (IdeDev);\r
808}\r
809\r
ed72955c 810/**\r
811 Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
812 to find out whether device is accessible.\r
813\r
a98f11c5 814 @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
815 to record all the information of the IDE device.\r
816 @param[in] *SenseCount Sense count for this packet command\r
ed72955c 817\r
a98f11c5 818 @retval EFI_SUCCESS Device is accessible.\r
819 @retval EFI_DEVICE_ERROR Device is not accessible.\r
ed72955c 820\r
821**/\r
878ddf1f 822EFI_STATUS\r
823AtapiTestUnitReady (\r
a98f11c5 824 IN IDE_BLK_IO_DEV *IdeDev,\r
825 OUT UINTN *SenseCount\r
878ddf1f 826 )\r
878ddf1f 827{\r
828 ATAPI_PACKET_COMMAND Packet;\r
829 EFI_STATUS Status;\r
830\r
a98f11c5 831 *SenseCount = 0;\r
832\r
878ddf1f 833 //\r
834 // fill command packet\r
835 //\r
836 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
837 Packet.TestUnitReady.opcode = TEST_UNIT_READY;\r
838\r
839 //\r
840 // send command packet\r
841 //\r
842 Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);\r
a98f11c5 843 if (EFI_ERROR (Status)) {\r
844 return Status;\r
845 }\r
846\r
847 Status = AtapiRequestSense (IdeDev, SenseCount);\r
848 if (EFI_ERROR (Status)) {\r
849 *SenseCount = 0;\r
850 return Status;\r
851 }\r
852\r
853 return EFI_SUCCESS;\r
878ddf1f 854}\r
855\r
ed72955c 856/**\r
857 Sends out ATAPI Request Sense Packet Command to the specified device.\r
858 This command will return all the current Sense data in the device. \r
859 This function will pack all the Sense data in one single buffer.\r
878ddf1f 860\r
ed72955c 861 @param[in] *IdeDev\r
862 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
863 to record all the information of the IDE device.\r
878ddf1f 864\r
ed72955c 865 @param[out] **SenseBuffers\r
866 allocated in this function, and freed by the calling function.\r
867 This buffer is used to accommodate all the sense data returned \r
868 by the device.\r
878ddf1f 869\r
ed72955c 870 @param[out] *BufUnit\r
871 record the unit size of the sense data block in the SenseBuffers,\r
878ddf1f 872\r
ed72955c 873 @param[out] *BufNumbers\r
874 record the number of units in the SenseBuffers.\r
878ddf1f 875\r
ed72955c 876 @retval EFI_SUCCESS\r
877 Request Sense command completes successfully.\r
878 \r
879 @retval EFI_DEVICE_ERROR\r
880 Request Sense command failed.\r
878ddf1f 881\r
ed72955c 882**/\r
883EFI_STATUS\r
884AtapiRequestSense (\r
885 IN IDE_BLK_IO_DEV *IdeDev,\r
886 OUT UINTN *SenseCounts\r
887 )\r
878ddf1f 888{\r
889 EFI_STATUS Status;\r
890 REQUEST_SENSE_DATA *Sense;\r
891 UINT16 *Ptr;\r
892 BOOLEAN FetchSenseData;\r
893 ATAPI_PACKET_COMMAND Packet;\r
894\r
895 *SenseCounts = 0;\r
896\r
897 ZeroMem (IdeDev->SenseData, sizeof (REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));\r
898 //\r
899 // fill command packet for Request Sense Packet Command\r
900 //\r
901 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
902 Packet.RequestSence.opcode = REQUEST_SENSE;\r
903 Packet.RequestSence.allocation_length = sizeof (REQUEST_SENSE_DATA);\r
904\r
905 //\r
906 // initialize pointer\r
907 //\r
908 Ptr = (UINT16 *) IdeDev->SenseData;\r
909 //\r
910 // request sense data from device continuously until no sense data\r
911 // exists in the device.\r
912 //\r
913 for (FetchSenseData = TRUE; FetchSenseData;) {\r
914\r
915 Sense = (REQUEST_SENSE_DATA *) Ptr;\r
916\r
917 //\r
918 // send out Request Sense Packet Command and get one Sense data form device\r
919 //\r
920 Status = AtapiPacketCommandIn (\r
921 IdeDev,\r
922 &Packet,\r
923 Ptr,\r
924 sizeof (REQUEST_SENSE_DATA),\r
925 ATAPITIMEOUT\r
926 );\r
927 //\r
928 // failed to get Sense data\r
929 //\r
930 if (EFI_ERROR (Status)) {\r
931 if (*SenseCounts == 0) {\r
932 return EFI_DEVICE_ERROR;\r
933 } else {\r
934 return EFI_SUCCESS;\r
935 }\r
936 }\r
937\r
938 (*SenseCounts)++;\r
939 //\r
940 // We limit MAX sense data count to 20 in order to avoid dead loop. Some\r
941 // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.\r
942 // In this case, dead loop occurs if we don't have a gatekeeper. 20 is\r
943 // supposed to be large enough for any ATAPI device.\r
944 //\r
945 if ((Sense->sense_key != SK_NO_SENSE) && ((*SenseCounts) < 20)) {\r
946 //\r
947 // Ptr is word-based pointer\r
948 //\r
a98f11c5 949 Ptr += (sizeof (REQUEST_SENSE_DATA) + 1) >> 1;\r
878ddf1f 950\r
951 } else {\r
952 //\r
953 // when no sense key, skip out the loop\r
954 //\r
955 FetchSenseData = FALSE;\r
956 }\r
957 }\r
958\r
959 return EFI_SUCCESS;\r
960}\r
961\r
ed72955c 962/**\r
963 Sends out ATAPI Read Capacity Packet Command to the specified device.\r
964 This command will return the information regarding the capacity of the\r
965 media in the device.\r
966\r
967 Current device status will impact device's response to the Read Capacity\r
968 Command. For example, if the device once reset, the Read Capacity\r
969 Command will fail. The Sense data record the current device status, so \r
970 if the Read Capacity Command failed, the Sense data must be requested\r
971 and be analyzed to determine if the Read Capacity Command should retry.\r
972\r
a98f11c5 973 @param[in] *IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
974 to record all the information of the IDE device.\r
975 @param[in] SenseCount Sense count for this packet command\r
ed72955c 976\r
a98f11c5 977 @retval EFI_SUCCESS Read Capacity Command finally completes successfully.\r
978 @retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error.\r
ed72955c 979\r
a98f11c5 980 @note Parameter "IdeDev" will be updated in this function.\r
ed72955c 981\r
982 TODO: EFI_NOT_READY - add return value to function comment\r
983**/\r
878ddf1f 984EFI_STATUS\r
985AtapiReadCapacity (\r
a98f11c5 986 IN IDE_BLK_IO_DEV *IdeDev,\r
987 OUT UINTN *SenseCount\r
878ddf1f 988 )\r
878ddf1f 989{\r
990 //\r
991 // status returned by Read Capacity Packet Command\r
992 //\r
993 EFI_STATUS Status;\r
a98f11c5 994 EFI_STATUS SenseStatus;\r
878ddf1f 995 ATAPI_PACKET_COMMAND Packet;\r
996\r
997 //\r
998 // used for capacity data returned from ATAPI device\r
999 //\r
1000 READ_CAPACITY_DATA Data;\r
1001 READ_FORMAT_CAPACITY_DATA FormatData;\r
1002\r
a98f11c5 1003 *SenseCount = 0;\r
1004\r
878ddf1f 1005 ZeroMem (&Data, sizeof (Data));\r
1006 ZeroMem (&FormatData, sizeof (FormatData));\r
1007\r
1008 if (IdeDev->Type == IdeCdRom) {\r
1009\r
1010 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1011 Packet.Inquiry.opcode = READ_CAPACITY;\r
1012 Status = AtapiPacketCommandIn (\r
a98f11c5 1013 IdeDev,\r
1014 &Packet,\r
1015 (UINT16 *) &Data,\r
1016 sizeof (READ_CAPACITY_DATA),\r
1017 ATAPITIMEOUT\r
1018 );\r
878ddf1f 1019\r
1020 } else {\r
1021 //\r
1022 // Type == IdeMagnetic\r
1023 //\r
1024 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1025 Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY;\r
1026 Packet.ReadFormatCapacity.allocation_length_lo = 12;\r
1027 Status = AtapiPacketCommandIn (\r
a98f11c5 1028 IdeDev,\r
1029 &Packet,\r
1030 (UINT16 *) &FormatData,\r
1031 sizeof (READ_FORMAT_CAPACITY_DATA),\r
1032 ATAPITIMEOUT\r
1033 );\r
878ddf1f 1034 }\r
1035\r
a98f11c5 1036 if (Status == EFI_TIMEOUT) {\r
1037 *SenseCount = 0;\r
1038 return Status;\r
1039 }\r
878ddf1f 1040\r
a98f11c5 1041 SenseStatus = AtapiRequestSense (IdeDev, SenseCount);\r
878ddf1f 1042\r
a98f11c5 1043 if (!EFI_ERROR (SenseStatus)) {\r
878ddf1f 1044\r
a98f11c5 1045 if (!EFI_ERROR (Status)) {\r
878ddf1f 1046\r
a98f11c5 1047 if (IdeDev->Type == IdeCdRom) {\r
878ddf1f 1048\r
a98f11c5 1049 IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |\r
1050 (Data.LastLba2 << 16) |\r
1051 (Data.LastLba1 << 8) |\r
1052 Data.LastLba0;\r
878ddf1f 1053\r
878ddf1f 1054 if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
878ddf1f 1055\r
a98f11c5 1056 IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) |\r
1057 (Data.BlockSize2 << 16) |\r
1058 (Data.BlockSize1 << 8) |\r
1059 Data.BlockSize0;\r
878ddf1f 1060\r
1061 IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
1062 } else {\r
1063 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
a98f11c5 1064 return EFI_DEVICE_ERROR;\r
878ddf1f 1065 }\r
1066\r
a98f11c5 1067 IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
1068\r
1069 //\r
1070 // Because the user data portion in the sector of the Data CD supported\r
1071 // is always 0x800\r
1072 //\r
1073 IdeDev->BlkIo.Media->BlockSize = 0x800;\r
1074 }\r
1075\r
1076 if (IdeDev->Type == IdeMagnetic) {\r
1077\r
1078 if (FormatData.DesCode == 3) {\r
1079 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
1080 IdeDev->BlkIo.Media->LastBlock = 0;\r
1081 } else {\r
1082\r
1083 IdeDev->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) |\r
1084 (FormatData.LastLba2 << 16) | \r
1085 (FormatData.LastLba1 << 8) |\r
1086 FormatData.LastLba0;\r
1087 if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
1088 IdeDev->BlkIo.Media->LastBlock--;\r
1089\r
1090 IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |\r
1091 (FormatData.BlockSize1 << 8) |\r
1092 FormatData.BlockSize0;\r
1093\r
1094 IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
1095 } else {\r
1096 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
1097 //\r
1098 // Return EFI_NOT_READY operation succeeds but returned capacity is 0\r
1099 //\r
1100 return EFI_NOT_READY;\r
1101 }\r
1102\r
1103 IdeDev->BlkIo.Media->BlockSize = 0x200;\r
878ddf1f 1104\r
a98f11c5 1105 }\r
878ddf1f 1106 }\r
1107 }\r
1108\r
1109 return EFI_SUCCESS;\r
1110\r
1111 } else {\r
a98f11c5 1112 *SenseCount = 0;\r
878ddf1f 1113 return EFI_DEVICE_ERROR;\r
1114 }\r
1115}\r
1116\r
ed72955c 1117/**\r
1118 Used before read/write blocks from/to ATAPI device media. \r
1119 Since ATAPI device media is removable, it is necessary to detect\r
1120 whether media is present and get current present media's\r
1121 information, and if media has been changed, Block I/O Protocol\r
1122 need to be reinstalled.\r
1123\r
1124 @param[in] *IdeDev\r
1125 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1126 to record all the information of the IDE device.\r
1127\r
1128 @param[out] *MediaChange\r
1129 return value that indicates if the media of the device has been\r
1130 changed.\r
1131\r
1132 @retval EFI_SUCCESS\r
1133 media found successfully.\r
1134 \r
1135 @retval EFI_DEVICE_ERROR\r
1136 any error encounters during media detection.\r
1137 \r
1138 @retval EFI_NO_MEDIA\r
1139 media not found.\r
1140\r
1141 @note\r
1142 parameter IdeDev may be updated in this function.\r
1143\r
1144**/\r
878ddf1f 1145EFI_STATUS\r
1146AtapiDetectMedia (\r
1147 IN IDE_BLK_IO_DEV *IdeDev,\r
1148 OUT BOOLEAN *MediaChange\r
1149 )\r
878ddf1f 1150{\r
a98f11c5 1151 EFI_STATUS Status;\r
1152 EFI_STATUS CleanStateStatus;\r
1153 EFI_BLOCK_IO_MEDIA OldMediaInfo;\r
1154 UINTN RetryTimes;\r
1155 UINTN RetryNotReady;\r
1156 UINTN SenseCount;\r
1157 SENSE_RESULT SResult;\r
1158 BOOLEAN WriteProtected;\r
878ddf1f 1159\r
a98f11c5 1160 CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
1161 *MediaChange = FALSE;\r
878ddf1f 1162 //\r
a98f11c5 1163 // Retry for SenseDeviceNotReadyNeedRetry.\r
1164 // Each retry takes 1s and we limit the upper boundary to\r
1165 // 120 times about 2 min.\r
878ddf1f 1166 //\r
a98f11c5 1167 RetryNotReady = 120;\r
878ddf1f 1168\r
1169 //\r
a98f11c5 1170 // Do Test Unit Ready\r
878ddf1f 1171 //\r
a98f11c5 1172 DoTUR:\r
878ddf1f 1173 //\r
a98f11c5 1174 // Retry 5 times\r
878ddf1f 1175 //\r
a98f11c5 1176 RetryTimes = 5;\r
1177 while (RetryTimes != 0) {\r
878ddf1f 1178\r
a98f11c5 1179 Status = AtapiTestUnitReady (IdeDev, &SenseCount);\r
878ddf1f 1180\r
1181 if (EFI_ERROR (Status)) {\r
878ddf1f 1182 //\r
a98f11c5 1183 // Test Unit Ready error without sense data.\r
1184 // For some devices, this means there's extra data\r
1185 // that has not been read, so we read these extra\r
1186 // data out before going on.\r
878ddf1f 1187 //\r
a98f11c5 1188 CleanStateStatus = AtapiReadPendingData (IdeDev);\r
1189 if (EFI_ERROR (CleanStateStatus)) {\r
878ddf1f 1190 //\r
a98f11c5 1191 // Busy wait failed, try again\r
878ddf1f 1192 //\r
a98f11c5 1193 RetryTimes--;\r
1194 }\r
1195 //\r
1196 // Try again without counting down RetryTimes\r
1197 //\r
1198 continue;\r
1199 } else {\r
1200\r
1201 ParseSenseData (IdeDev, SenseCount, &SResult);\r
1202\r
1203 switch (SResult) {\r
1204 case SenseNoSenseKey:\r
1205 if (IdeDev->BlkIo.Media->MediaPresent) {\r
1206 goto Done;\r
878ddf1f 1207 } else {\r
1208 //\r
a98f11c5 1209 // Media present but the internal structure need refreshed.\r
1210 // Try Read Capacity\r
878ddf1f 1211 //\r
a98f11c5 1212 goto DoRC;\r
1213 }\r
1214 break;\r
1215\r
1216 case SenseDeviceNotReadyNeedRetry:\r
1217 if (--RetryNotReady == 0) {\r
1218 return EFI_DEVICE_ERROR;\r
878ddf1f 1219 }\r
a98f11c5 1220 gBS->Stall (1000 * STALL_1_MILLI_SECOND);\r
1221 continue;\r
1222 break;\r
1223\r
1224 case SenseNoMedia:\r
1225 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
1226 IdeDev->BlkIo.Media->LastBlock = 0;\r
1227 goto Done;\r
1228 break;\r
1229\r
1230 case SenseDeviceNotReadyNoRetry:\r
1231 case SenseMediaError:\r
1232 return EFI_DEVICE_ERROR;\r
1233\r
1234 case SenseMediaChange:\r
1235 IdeDev->BlkIo.Media->MediaId++;\r
1236 goto DoRC;\r
1237 break;\r
1238\r
1239 default:\r
1240 RetryTimes--;\r
1241 break;\r
878ddf1f 1242 }\r
878ddf1f 1243 }\r
1244 }\r
1245\r
a98f11c5 1246 return EFI_DEVICE_ERROR;\r
878ddf1f 1247\r
a98f11c5 1248 //\r
1249 // Do Read Capacity\r
1250 //\r
1251 DoRC:\r
1252 RetryTimes = 5;\r
878ddf1f 1253\r
a98f11c5 1254 while (RetryTimes != 0) {\r
878ddf1f 1255\r
a98f11c5 1256 Status = AtapiReadCapacity (IdeDev, &SenseCount);\r
878ddf1f 1257\r
a98f11c5 1258 if (EFI_ERROR (Status)) {\r
1259 RetryTimes--;\r
1260 continue;\r
878ddf1f 1261 } else {\r
1262\r
a98f11c5 1263 ParseSenseData (IdeDev, SenseCount, &SResult);\r
878ddf1f 1264\r
a98f11c5 1265 switch (SResult) {\r
1266 case SenseNoSenseKey:\r
1267 goto Done;\r
1268 break;\r
878ddf1f 1269\r
a98f11c5 1270 case SenseDeviceNotReadyNeedRetry:\r
878ddf1f 1271 //\r
a98f11c5 1272 // We use Test Unit Ready to retry which\r
1273 // is faster.\r
878ddf1f 1274 //\r
a98f11c5 1275 goto DoTUR;\r
1276 break;\r
878ddf1f 1277\r
a98f11c5 1278 case SenseNoMedia:\r
878ddf1f 1279 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
1280 IdeDev->BlkIo.Media->LastBlock = 0;\r
a98f11c5 1281 goto Done;\r
1282 break;\r
878ddf1f 1283\r
a98f11c5 1284 case SenseDeviceNotReadyNoRetry:\r
1285 case SenseMediaError:\r
878ddf1f 1286 return EFI_DEVICE_ERROR;\r
a98f11c5 1287\r
1288 case SenseMediaChange:\r
878ddf1f 1289 IdeDev->BlkIo.Media->MediaId++;\r
a98f11c5 1290 continue;\r
1291 break;\r
878ddf1f 1292\r
a98f11c5 1293 default:\r
1294 RetryTimes--;\r
1295 break;\r
878ddf1f 1296 }\r
878ddf1f 1297 }\r
878ddf1f 1298 }\r
878ddf1f 1299\r
a98f11c5 1300 return EFI_DEVICE_ERROR;\r
1301\r
1302 Done:\r
878ddf1f 1303 //\r
1304 // the following code is to check the write-protected for LS120 media\r
1305 //\r
1306 if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) {\r
1307\r
1308 Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected);\r
1309 if (!EFI_ERROR (Status)) {\r
1310\r
1311 if (WriteProtected) {\r
1312\r
1313 IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
1314 } else {\r
1315\r
1316 IdeDev->BlkIo.Media->ReadOnly = FALSE;\r
1317 }\r
1318\r
1319 }\r
1320 }\r
1321\r
1322 if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) {\r
1323 //\r
1324 // Media change information got from the device\r
1325 //\r
1326 *MediaChange = TRUE;\r
1327 }\r
1328\r
1329 if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) {\r
1330 *MediaChange = TRUE;\r
1331 IdeDev->BlkIo.Media->MediaId += 1;\r
1332 }\r
1333\r
1334 if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) {\r
1335 *MediaChange = TRUE;\r
1336 IdeDev->BlkIo.Media->MediaId += 1;\r
1337 }\r
1338\r
1339 if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) {\r
1340 *MediaChange = TRUE;\r
1341 IdeDev->BlkIo.Media->MediaId += 1;\r
1342 }\r
1343\r
1344 if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) {\r
1345 if (IdeDev->BlkIo.Media->MediaPresent) {\r
1346 //\r
1347 // when change from no media to media present, reset the MediaId to 1.\r
1348 //\r
1349 IdeDev->BlkIo.Media->MediaId = 1;\r
1350 } else {\r
1351 //\r
1352 // when no media, reset the MediaId to zero.\r
1353 //\r
1354 IdeDev->BlkIo.Media->MediaId = 0;\r
1355 }\r
1356\r
1357 *MediaChange = TRUE;\r
1358 }\r
1359\r
1360 //\r
1361 // if any change on current existing media,\r
1362 // the Block I/O protocol need to be reinstalled.\r
1363 //\r
1364 if (*MediaChange) {\r
1365 gBS->ReinstallProtocolInterface (\r
1366 IdeDev->Handle,\r
1367 &gEfiBlockIoProtocolGuid,\r
1368 &IdeDev->BlkIo,\r
1369 &IdeDev->BlkIo\r
1370 );\r
1371 }\r
1372\r
a98f11c5 1373 if (IdeDev->BlkIo.Media->MediaPresent) {\r
1374 return EFI_SUCCESS;\r
1375 } else {\r
1376 return EFI_NO_MEDIA;\r
1377 }\r
878ddf1f 1378}\r
1379\r
ed72955c 1380/**\r
1381 This function is called by the AtapiBlkIoReadBlocks() to perform\r
1382 read from media in block unit.\r
1383\r
1384 The main command used to access media here is READ(10) Command. \r
1385 READ(10) Command requests that the ATAPI device media transfer \r
1386 specified data to the host. Data is transferred in block(sector) \r
1387 unit. The maximum number of blocks that can be transferred once is\r
1388 65536. This is the main difference between READ(10) and READ(12) \r
1389 Command. The maximum number of blocks in READ(12) is 2 power 32.\r
1390\r
1391 @param[in] *IdeDev\r
1392 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1393 to record all the information of the IDE device.\r
1394\r
1395 @param[in] *Buffer\r
1396 A pointer to the destination buffer for the data. \r
1397\r
1398 @param[in] Lba\r
1399 The starting logical block address to read from \r
1400 on the device media.\r
1401\r
1402 @param[in] NumberOfBlocks\r
1403 The number of transfer data blocks.\r
1404\r
1405 @return status is fully dependent on the return status\r
1406 of AtapiPacketCommandIn() function.\r
1407\r
1408**/\r
878ddf1f 1409EFI_STATUS\r
1410AtapiReadSectors (\r
1411 IN IDE_BLK_IO_DEV *IdeDev,\r
1412 IN VOID *Buffer,\r
1413 IN EFI_LBA Lba,\r
1414 IN UINTN NumberOfBlocks\r
1415 )\r
878ddf1f 1416{\r
1417\r
1418 ATAPI_PACKET_COMMAND Packet;\r
1419 READ10_CMD *Read10Packet;\r
1420 EFI_STATUS Status;\r
1421 UINTN BlocksRemaining;\r
1422 UINT32 Lba32;\r
1423 UINT32 BlockSize;\r
1424 UINT32 ByteCount;\r
1425 UINT16 SectorCount;\r
1426 VOID *PtrBuffer;\r
1427 UINT16 MaxBlock;\r
1428 UINTN TimeOut;\r
1429\r
1430 //\r
1431 // fill command packet for Read(10) command\r
1432 //\r
1433 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1434 Read10Packet = &Packet.Read10;\r
1435 Lba32 = (UINT32) Lba;\r
1436 PtrBuffer = Buffer;\r
1437\r
1438 BlockSize = IdeDev->BlkIo.Media->BlockSize;\r
1439\r
1440 //\r
1441 // limit the data bytes that can be transferred by one Read(10) Command\r
1442 //\r
a98f11c5 1443 MaxBlock = 65535;\r
878ddf1f 1444\r
1445 BlocksRemaining = NumberOfBlocks;\r
1446\r
1447 Status = EFI_SUCCESS;\r
1448 while (BlocksRemaining > 0) {\r
1449\r
1450 if (BlocksRemaining <= MaxBlock) {\r
1451\r
1452 SectorCount = (UINT16) BlocksRemaining;\r
1453 } else {\r
1454\r
1455 SectorCount = MaxBlock;\r
1456 }\r
1457\r
1458 //\r
1459 // fill the Packet data structure\r
1460 //\r
1461\r
1462 Read10Packet->opcode = READ_10;\r
1463\r
1464 //\r
1465 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
1466 // Lba0 is MSB, Lba3 is LSB\r
1467 //\r
1468 Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r
1469 Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r
1470 Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r
1471 Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r
1472\r
1473 //\r
1474 // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
1475 // TranLen0 is MSB, TranLen is LSB\r
1476 //\r
1477 Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r
1478 Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r
1479\r
1480 ByteCount = SectorCount * BlockSize;\r
1481\r
1482 if (IdeDev->Type == IdeCdRom) {\r
1483 TimeOut = CDROMLONGTIMEOUT;\r
1484 } else {\r
1485 TimeOut = ATAPILONGTIMEOUT;\r
1486 }\r
1487\r
1488 Status = AtapiPacketCommandIn (\r
1489 IdeDev,\r
1490 &Packet,\r
1491 (UINT16 *) PtrBuffer,\r
1492 ByteCount,\r
1493 TimeOut\r
1494 );\r
1495 if (EFI_ERROR (Status)) {\r
1496 return Status;\r
1497 }\r
1498\r
1499 Lba32 += SectorCount;\r
1500 PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;\r
1501 BlocksRemaining -= SectorCount;\r
1502 }\r
1503\r
1504 return Status;\r
1505}\r
1506\r
ed72955c 1507/**\r
1508 This function is called by the AtapiBlkIoWriteBlocks() to perform\r
1509 write onto media in block unit.\r
1510 The main command used to access media here is Write(10) Command. \r
1511 Write(10) Command requests that the ATAPI device media transfer \r
1512 specified data to the host. Data is transferred in block (sector) \r
1513 unit. The maximum number of blocks that can be transferred once is\r
1514 65536. \r
1515\r
1516 @param[in] *IdeDev\r
1517 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1518 to record all the information of the IDE device.\r
1519\r
1520 @param[in] *Buffer\r
1521 A pointer to the source buffer for the data. \r
1522\r
1523 @param[in] Lba\r
1524 The starting logical block address to write onto \r
1525 the device media.\r
1526\r
1527 @param[in] NumberOfBlocks\r
1528 The number of transfer data blocks.\r
1529\r
1530 @return status is fully dependent on the return status\r
1531 of AtapiPacketCommandOut() function.\r
1532\r
1533**/\r
878ddf1f 1534EFI_STATUS\r
1535AtapiWriteSectors (\r
1536 IN IDE_BLK_IO_DEV *IdeDev,\r
1537 IN VOID *Buffer,\r
1538 IN EFI_LBA Lba,\r
1539 IN UINTN NumberOfBlocks\r
1540 )\r
878ddf1f 1541{\r
1542\r
1543 ATAPI_PACKET_COMMAND Packet;\r
1544 READ10_CMD *Read10Packet;\r
1545\r
1546 EFI_STATUS Status;\r
1547 UINTN BlocksRemaining;\r
1548 UINT32 Lba32;\r
1549 UINT32 BlockSize;\r
1550 UINT32 ByteCount;\r
1551 UINT16 SectorCount;\r
1552 VOID *PtrBuffer;\r
1553 UINT16 MaxBlock;\r
1554\r
1555 //\r
1556 // fill command packet for Write(10) command\r
1557 // Write(10) command packet has the same data structure as\r
1558 // Read(10) command packet,\r
1559 // so here use the Read10Packet data structure\r
1560 // for the Write(10) command packet.\r
1561 //\r
1562 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1563 Read10Packet = &Packet.Read10;\r
1564\r
1565 Lba32 = (UINT32) Lba;\r
1566 PtrBuffer = Buffer;\r
1567\r
1568 BlockSize = IdeDev->BlkIo.Media->BlockSize;\r
1569\r
1570 //\r
1571 // limit the data bytes that can be transferred by one Read(10) Command\r
1572 //\r
1573 MaxBlock = (UINT16) (65536 / BlockSize);\r
1574\r
1575 BlocksRemaining = NumberOfBlocks;\r
1576\r
1577 Status = EFI_SUCCESS;\r
1578 while (BlocksRemaining > 0) {\r
1579\r
1580 if (BlocksRemaining >= MaxBlock) {\r
1581 SectorCount = MaxBlock;\r
1582 } else {\r
1583 SectorCount = (UINT16) BlocksRemaining;\r
1584 }\r
1585 \r
1586 //\r
1587 // Command code is WRITE_10.\r
1588 //\r
1589 Read10Packet->opcode = WRITE_10;\r
1590\r
1591 //\r
1592 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.\r
1593 // Lba0 is MSB, Lba3 is LSB\r
1594 //\r
1595 Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);\r
1596 Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);\r
1597 Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);\r
1598 Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);\r
1599\r
1600 //\r
1601 // TranLen0 ~ TranLen1 specify the transfer length in block unit.\r
1602 // TranLen0 is MSB, TranLen is LSB\r
1603 //\r
1604 Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);\r
1605 Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);\r
1606\r
1607 ByteCount = SectorCount * BlockSize;\r
1608\r
1609 Status = AtapiPacketCommandOut (\r
1610 IdeDev,\r
1611 &Packet,\r
1612 (UINT16 *) PtrBuffer,\r
1613 ByteCount,\r
1614 ATAPILONGTIMEOUT\r
1615 );\r
1616 if (EFI_ERROR (Status)) {\r
1617 return Status;\r
1618 }\r
1619\r
1620 Lba32 += SectorCount;\r
1621 PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize);\r
1622 BlocksRemaining -= SectorCount;\r
1623 }\r
1624\r
1625 return Status;\r
1626}\r
1627\r
ed72955c 1628/**\r
1629 This function is used to implement the Soft Reset on the specified\r
1630 ATAPI device. Different from the AtaSoftReset(), here reset is a ATA\r
1631 Soft Reset Command special for ATAPI device, and it only take effects\r
1632 on the specified ATAPI device, not on the whole IDE bus.\r
1633 Since the ATAPI soft reset is needed when device is in exceptional\r
1634 condition (such as BSY bit is always set ), I think the Soft Reset\r
1635 command should be sent without waiting for the BSY clear and DRDY\r
1636 set.\r
1637 This function is called by IdeBlkIoReset(), \r
1638 a interface function of Block I/O protocol.\r
1639\r
1640 @param[in] *IdeDev\r
1641 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1642 to record all the information of the IDE device.\r
1643\r
1644 @retval EFI_SUCCESS\r
1645 Soft reset completes successfully.\r
1646 \r
1647 @retval EFI_DEVICE_ERROR\r
1648 Any step during the reset process is failed.\r
1649\r
1650**/\r
878ddf1f 1651EFI_STATUS\r
1652AtapiSoftReset (\r
1653 IN IDE_BLK_IO_DEV *IdeDev\r
1654 )\r
878ddf1f 1655{\r
1656 UINT8 Command;\r
1657 UINT8 DeviceSelect;\r
1658 EFI_STATUS Status;\r
1659\r
1660 //\r
1661 // for ATAPI device, no need to wait DRDY ready after device selecting.\r
1662 // (bit7 and bit5 are both set to 1 for backward compatibility)\r
1663 //\r
1664 DeviceSelect = (UINT8) (((bit7 | bit5) | (IdeDev->Device << 4)));\r
1665 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
1666\r
1667 Command = ATAPI_SOFT_RESET_CMD;\r
1668 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command);\r
1669\r
1670 //\r
1671 // BSY cleared is the only status return to the host by the device\r
1672 // when reset is completed.\r
1673 // slave device needs at most 31s to clear BSY\r
1674 //\r
1675 Status = WaitForBSYClear (IdeDev, 31000);\r
1676 if (EFI_ERROR (Status)) {\r
1677 return EFI_DEVICE_ERROR;\r
1678 }\r
1679 \r
1680 //\r
1681 // stall 5 seconds to make the device status stable\r
1682 //\r
1683 gBS->Stall (5000000);\r
1684\r
1685 return EFI_SUCCESS;\r
1686}\r
1687\r
ed72955c 1688/**\r
1689 This function is the ATAPI implementation for ReadBlocks in the\r
1690 Block I/O Protocol interface.\r
1691\r
1692 @param[in] *IdeBlkIoDev\r
1693 Indicates the calling context.\r
1694\r
1695 @param[in] MediaId\r
1696 The media id that the read request is for.\r
1697\r
1698 @param[in] LBA\r
1699 The starting logical block address to read from \r
1700 on the device.\r
1701\r
1702 @param[in] BufferSize\r
1703 The size of the Buffer in bytes. This must be a\r
1704 multiple of the intrinsic block size of the device.\r
1705\r
1706 @param[out] *Buffer\r
1707 A pointer to the destination buffer for the data. \r
1708 The caller is responsible for either having implicit\r
1709 or explicit ownership of the memory that data is read into.\r
1710\r
1711 @retval EFI_SUCCESS\r
1712 Read Blocks successfully.\r
1713 \r
1714 @retval EFI_DEVICE_ERROR\r
1715 Read Blocks failed.\r
1716 \r
1717 @retval EFI_NO_MEDIA\r
1718 There is no media in the device.\r
1719 \r
1720 @retval EFI_MEDIA_CHANGED\r
1721 The MediaId is not for the current media.\r
1722 \r
1723 @retval EFI_BAD_BUFFER_SIZE\r
1724 The BufferSize parameter is not a multiple of the\r
1725 intrinsic block size of the device.\r
1726 \r
1727 @retval EFI_INVALID_PARAMETER\r
1728 The read request contains LBAs that are not valid,\r
1729 or the data buffer is not valid.\r
1730\r
1731**/\r
878ddf1f 1732EFI_STATUS\r
1733AtapiBlkIoReadBlocks (\r
1734 IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
1735 IN UINT32 MediaId,\r
1736 IN EFI_LBA LBA,\r
1737 IN UINTN BufferSize,\r
1738 OUT VOID *Buffer\r
1739 )\r
878ddf1f 1740{\r
1741 EFI_BLOCK_IO_MEDIA *Media;\r
1742 UINTN BlockSize;\r
1743 UINTN NumberOfBlocks;\r
1744 EFI_STATUS Status;\r
1745\r
1746 BOOLEAN MediaChange;\r
1747\r
1748 if (Buffer == NULL) {\r
1749 return EFI_INVALID_PARAMETER;\r
1750 }\r
1751\r
1752 if (BufferSize == 0) {\r
1753 return EFI_SUCCESS;\r
1754 }\r
1755\r
1756 //\r
1757 // ATAPI device media is removable, so it is a must\r
1758 // to detect media first before read operation\r
1759 //\r
1760 MediaChange = FALSE;\r
1761 Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);\r
1762 if (EFI_ERROR (Status)) {\r
1763\r
1764 if (IdeBlkIoDevice->Cache != NULL) {\r
1765 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1766 IdeBlkIoDevice->Cache = NULL;\r
1767 }\r
1768\r
1769 return Status;\r
1770 }\r
1771 //\r
1772 // Get the intrinsic block size\r
1773 //\r
1774 Media = IdeBlkIoDevice->BlkIo.Media;\r
1775 BlockSize = Media->BlockSize;\r
1776\r
1777 NumberOfBlocks = BufferSize / BlockSize;\r
1778\r
1779 if (!(Media->MediaPresent)) {\r
1780\r
1781 if (IdeBlkIoDevice->Cache != NULL) {\r
1782 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1783 IdeBlkIoDevice->Cache = NULL;\r
1784 }\r
1785 return EFI_NO_MEDIA;\r
1786\r
1787 }\r
1788\r
1789 if ((MediaId != Media->MediaId) || MediaChange) {\r
1790\r
1791 if (IdeBlkIoDevice->Cache != NULL) {\r
1792 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1793 IdeBlkIoDevice->Cache = NULL;\r
1794 }\r
1795 return EFI_MEDIA_CHANGED;\r
1796 }\r
1797\r
1798 if (BufferSize % BlockSize != 0) {\r
1799 return EFI_BAD_BUFFER_SIZE;\r
1800 }\r
1801\r
1802 if (LBA > Media->LastBlock) {\r
1803 return EFI_INVALID_PARAMETER;\r
1804 }\r
1805\r
1806 if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
1807 return EFI_INVALID_PARAMETER;\r
1808 }\r
1809\r
1810 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
1811 return EFI_INVALID_PARAMETER;\r
1812 }\r
1813\r
1814 //\r
1815 // if all the parameters are valid, then perform read sectors command\r
1816 // to transfer data from device to host.\r
1817 //\r
1818 Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
1819 if (EFI_ERROR (Status)) {\r
1820 return EFI_DEVICE_ERROR;\r
1821 }\r
1822 \r
1823 //\r
1824 // Read blocks succeeded\r
1825 //\r
1826 \r
1827 //\r
1828 // save the first block to the cache for performance\r
1829 //\r
1830 if (LBA == 0 && !IdeBlkIoDevice->Cache) {\r
1831 IdeBlkIoDevice->Cache = AllocatePool (BlockSize);\r
1832 if (IdeBlkIoDevice != NULL) {\r
1833 CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);\r
1834 }\r
1835 }\r
1836\r
1837 return EFI_SUCCESS;\r
1838\r
1839}\r
1840\r
ed72955c 1841/**\r
1842 This function is the ATAPI implementation for WriteBlocks in the\r
1843 Block I/O Protocol interface.\r
1844\r
1845 @param[in] *This\r
1846 Indicates the calling context.\r
1847\r
1848 @param[in] MediaId\r
1849 The media id that the write request is for.\r
1850\r
1851 @param[in] LBA\r
1852 The starting logical block address to write onto \r
1853 the device.\r
1854\r
1855 @param[in] BufferSize\r
1856 The size of the Buffer in bytes. This must be a\r
1857 multiple of the intrinsic block size of the device.\r
1858\r
1859 @param[out] *Buffer\r
1860 A pointer to the source buffer for the data. \r
1861 The caller is responsible for either having implicit\r
1862 or explicit ownership of the memory that data is \r
1863 written from.\r
1864\r
1865 @retval EFI_SUCCESS\r
1866 Write Blocks successfully.\r
1867 \r
1868 @retval EFI_DEVICE_ERROR\r
1869 Write Blocks failed.\r
1870 \r
1871 @retval EFI_NO_MEDIA\r
1872 There is no media in the device.\r
1873 \r
1874 @retval EFI_MEDIA_CHANGE\r
1875 The MediaId is not for the current media.\r
1876 \r
1877 @retval EFI_BAD_BUFFER_SIZE\r
1878 The BufferSize parameter is not a multiple of the\r
1879 intrinsic block size of the device.\r
1880 \r
1881 @retval EFI_INVALID_PARAMETER\r
1882 The write request contains LBAs that are not valid,\r
1883 or the data buffer is not valid.\r
1884\r
1885 TODO: EFI_MEDIA_CHANGED - add return value to function comment\r
1886 TODO: EFI_WRITE_PROTECTED - add return value to function comment\r
1887**/\r
878ddf1f 1888EFI_STATUS\r
1889AtapiBlkIoWriteBlocks (\r
1890 IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
1891 IN UINT32 MediaId,\r
1892 IN EFI_LBA LBA,\r
1893 IN UINTN BufferSize,\r
1894 OUT VOID *Buffer\r
1895 )\r
878ddf1f 1896{\r
1897\r
1898 EFI_BLOCK_IO_MEDIA *Media;\r
1899 UINTN BlockSize;\r
1900 UINTN NumberOfBlocks;\r
1901 EFI_STATUS Status;\r
1902 BOOLEAN MediaChange;\r
1903\r
1904 if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
1905 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1906 IdeBlkIoDevice->Cache = NULL;\r
1907 }\r
1908\r
1909 if (Buffer == NULL) {\r
1910 return EFI_INVALID_PARAMETER;\r
1911 }\r
1912\r
1913 if (BufferSize == 0) {\r
1914 return EFI_SUCCESS;\r
1915 }\r
1916\r
1917 //\r
1918 // ATAPI device media is removable,\r
1919 // so it is a must to detect media first before write operation\r
1920 //\r
1921 MediaChange = FALSE;\r
1922 Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);\r
1923 if (EFI_ERROR (Status)) {\r
1924\r
1925 if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
1926 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1927 IdeBlkIoDevice->Cache = NULL;\r
1928 }\r
1929 return Status;\r
1930 }\r
1931 \r
1932 //\r
1933 // Get the intrinsic block size\r
1934 //\r
1935 Media = IdeBlkIoDevice->BlkIo.Media;\r
1936 BlockSize = Media->BlockSize;\r
1937 NumberOfBlocks = BufferSize / BlockSize;\r
1938\r
1939 if (!(Media->MediaPresent)) {\r
1940\r
1941 if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
1942 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1943 IdeBlkIoDevice->Cache = NULL;\r
1944 }\r
1945 return EFI_NO_MEDIA;\r
1946 }\r
1947\r
1948 if ((MediaId != Media->MediaId) || MediaChange) {\r
1949\r
1950 if (LBA == 0 && IdeBlkIoDevice->Cache) {\r
1951 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1952 IdeBlkIoDevice->Cache = NULL;\r
1953 }\r
1954 return EFI_MEDIA_CHANGED;\r
1955 }\r
1956\r
1957 if (Media->ReadOnly) {\r
1958 return EFI_WRITE_PROTECTED;\r
1959 }\r
1960\r
1961 if (BufferSize % BlockSize != 0) {\r
1962 return EFI_BAD_BUFFER_SIZE;\r
1963 }\r
1964\r
1965 if (LBA > Media->LastBlock) {\r
1966 return EFI_INVALID_PARAMETER;\r
1967 }\r
1968\r
1969 if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
1970 return EFI_INVALID_PARAMETER;\r
1971 }\r
1972\r
1973 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
1974 return EFI_INVALID_PARAMETER;\r
1975 }\r
1976\r
1977 //\r
1978 // if all the parameters are valid,\r
1979 // then perform write sectors command to transfer data from host to device.\r
1980 //\r
1981 Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
1982 if (EFI_ERROR (Status)) {\r
1983 return EFI_DEVICE_ERROR;\r
1984 }\r
1985\r
1986 return EFI_SUCCESS;\r
1987\r
1988}\r
1989\r
ed72955c 1990/**\r
a98f11c5 1991 This function is used to parse sense data. Only the first\r
1992 sense data is honoured.\r
878ddf1f 1993\r
a98f11c5 1994 @param[in] IdeDev Indicates the calling context.\r
1995 @param[in] SenseCount Count of sense data.\r
1996 @param[out] Result The parsed result.\r
878ddf1f 1997\r
a98f11c5 1998 @retval EFI_SUCCESS Successfully parsed.\r
1999 @retval EFI_INVALID_PARAMETER Count of sense data is zero.\r
878ddf1f 2000\r
ed72955c 2001**/\r
a98f11c5 2002EFI_STATUS\r
2003ParseSenseData (\r
2004 IN IDE_BLK_IO_DEV *IdeDev,\r
2005 IN UINTN SenseCount,\r
2006 OUT SENSE_RESULT *Result\r
ed72955c 2007 )\r
878ddf1f 2008{\r
a98f11c5 2009 REQUEST_SENSE_DATA *SenseData;\r
878ddf1f 2010\r
a98f11c5 2011 if (SenseCount == 0) {\r
2012 return EFI_INVALID_PARAMETER;\r
878ddf1f 2013 }\r
2014\r
a98f11c5 2015 //\r
2016 // Only use the first sense data\r
2017 //\r
2018 SenseData = IdeDev->SenseData;\r
2019 *Result = SenseOtherSense;\r
878ddf1f 2020\r
a98f11c5 2021 switch (SenseData->sense_key) {\r
2022 case SK_NO_SENSE:\r
2023 *Result = SenseNoSenseKey;\r
2024 break;\r
2025 case SK_NOT_READY:\r
2026 switch (SenseData->addnl_sense_code) {\r
2027 case ASC_NO_MEDIA:\r
2028 *Result = SenseNoMedia;\r
878ddf1f 2029 break;\r
a98f11c5 2030 case ASC_MEDIA_UPSIDE_DOWN:\r
2031 *Result = SenseMediaError;\r
878ddf1f 2032 break;\r
a98f11c5 2033 case ASC_NOT_READY:\r
2034 if (SenseData->addnl_sense_code_qualifier == ASCQ_IN_PROGRESS) {\r
2035 *Result = SenseDeviceNotReadyNeedRetry;\r
2036 } else {\r
2037 *Result = SenseDeviceNotReadyNoRetry;\r
2038 }\r
878ddf1f 2039 break;\r
2040 }\r
a98f11c5 2041 break;\r
2042 case SK_UNIT_ATTENTION:\r
2043 if (SenseData->addnl_sense_code == ASC_MEDIA_CHANGE) {\r
2044 *Result = SenseMediaChange;\r
878ddf1f 2045 }\r
a98f11c5 2046 break;\r
2047 case SK_MEDIUM_ERROR:\r
2048 switch (SenseData->addnl_sense_code) {\r
2049 case ASC_MEDIA_ERR1:\r
2050 case ASC_MEDIA_ERR2:\r
2051 case ASC_MEDIA_ERR3:\r
2052 case ASC_MEDIA_ERR4:\r
2053 *Result = SenseMediaError;\r
878ddf1f 2054 break;\r
2055 }\r
a98f11c5 2056 break;\r
2057 default:\r
2058 break;\r
878ddf1f 2059 }\r
2060\r
a98f11c5 2061 return EFI_SUCCESS;\r
878ddf1f 2062}\r
2063\r
ed72955c 2064/**\r
a98f11c5 2065 This function reads the pending data in the device.\r
878ddf1f 2066\r
a98f11c5 2067 @param[in] IdeDev Indicates the calling context.\r
878ddf1f 2068\r
a98f11c5 2069 @retval EFI_SUCCESS Successfully read.\r
2070 @retval EFI_NOT_READY The BSY is set avoiding reading.\r
878ddf1f 2071\r
ed72955c 2072**/\r
a98f11c5 2073EFI_STATUS\r
2074AtapiReadPendingData (\r
2075 IN IDE_BLK_IO_DEV *IdeDev\r
ed72955c 2076 )\r
878ddf1f 2077{\r
a98f11c5 2078 UINT8 AltRegister;\r
2079 UINT16 TempWordBuffer;\r
878ddf1f 2080\r
a98f11c5 2081 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
2082 if ((AltRegister & BSY) == BSY) {\r
2083 return EFI_NOT_READY;\r
878ddf1f 2084 }\r
a98f11c5 2085 if ((AltRegister & (BSY | DRQ)) == DRQ) {\r
2086 TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r
2087 while ((TempWordBuffer & (BSY | DRQ)) == DRQ) {\r
2088 IDEReadPortWMultiple (\r
2089 IdeDev->PciIo,\r
2090 IdeDev->IoPort->Data, \r
2091 1, \r
2092 &TempWordBuffer\r
2093 );\r
2094 TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r
2095 }\r
2096 }\r
2097 return EFI_SUCCESS;\r
878ddf1f 2098}\r
2099\r
ed72955c 2100/**\r
2101 TODO: Add function description\r
2102\r
2103 @param IdeDev TODO: add argument description\r
2104 @param WriteProtected TODO: add argument description\r
2105\r
2106 @retval EFI_DEVICE_ERROR TODO: Add description for return value\r
2107 @retval EFI_DEVICE_ERROR TODO: Add description for return value\r
2108 @retval EFI_SUCCESS TODO: Add description for return value\r
2109\r
2110**/\r
878ddf1f 2111EFI_STATUS\r
2112IsLS120orZipWriteProtected (\r
2113 IN IDE_BLK_IO_DEV *IdeDev,\r
2114 OUT BOOLEAN *WriteProtected\r
2115 )\r
878ddf1f 2116{\r
2117 EFI_STATUS Status;\r
2118\r
2119 *WriteProtected = FALSE;\r
2120\r
2121 Status = LS120EnableMediaStatus (IdeDev, TRUE);\r
2122 if (EFI_ERROR (Status)) {\r
2123 return EFI_DEVICE_ERROR;\r
2124 }\r
2125\r
2126 //\r
2127 // the Get Media Status Command is only valid\r
2128 // if a Set Features/Enable Media Status Command has been priviously issued.\r
2129 //\r
2130 if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) {\r
2131\r
2132 *WriteProtected = TRUE;\r
2133 } else {\r
2134\r
2135 *WriteProtected = FALSE;\r
2136 }\r
2137\r
2138 //\r
2139 // After Get Media Status Command completes,\r
2140 // Set Features/Disable Media Command should be sent.\r
2141 //\r
2142 Status = LS120EnableMediaStatus (IdeDev, FALSE);\r
2143 if (EFI_ERROR (Status)) {\r
2144 return EFI_DEVICE_ERROR;\r
2145 }\r
2146\r
2147 return EFI_SUCCESS;\r
2148}\r