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