]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Atapi.c
IntelFrameworkModulePkg/IdeBusDxe: Fix undefined behavior in signed left shift
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / IdeBusDxe / Atapi.c
CommitLineData
ead42efc 1/** @file\r
630d580d 2 This file contains all helper functions on the ATAPI command \r
3 \r
f90c4fff 4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
180a5a35 5 This program and the accompanying materials \r
ead42efc 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
03417d8d 15#include "IdeBus.h"\r
ead42efc 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
630d580d 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
ead42efc 24\r
630d580d 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
ead42efc 30\r
630d580d 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
ead42efc 34**/\r
ead42efc 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
97404058 85 if ((StatusValue & BIT1) != 0) {\r
ead42efc 86 return EFI_NO_MEDIA;\r
87 }\r
88\r
97404058 89 if ((StatusValue & BIT6) != 0) {\r
ead42efc 90 return EFI_WRITE_PROTECTED;\r
91 } else {\r
92 return EFI_SUCCESS;\r
93 }\r
94}\r
ead42efc 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
630d580d 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
ead42efc 101\r
630d580d 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
ead42efc 106**/\r
ead42efc 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
ead42efc 166/**\r
630d580d 167 This function reads the pending data in the device.\r
ead42efc 168\r
630d580d 169 @param IdeDev Indicates the calling context.\r
ead42efc 170\r
630d580d 171 @retval EFI_SUCCESS Successfully read.\r
172 @retval EFI_NOT_READY The BSY is set avoiding reading.\r
ead42efc 173\r
630d580d 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
ead42efc 182\r
630d580d 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
ead42efc 201\r
630d580d 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
ead42efc 218**/\r
219EFI_STATUS\r
630d580d 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
ead42efc 226 )\r
227{\r
ead42efc 228 //\r
630d580d 229 // required transfer data in word unit.\r
ead42efc 230 //\r
630d580d 231 UINT32 RequiredWordCount;\r
ead42efc 232\r
ead42efc 233 //\r
630d580d 234 // actual transfer data in word unit.\r
ead42efc 235 //\r
630d580d 236 UINT32 ActualWordCount;\r
237 UINT32 WordCount;\r
238 EFI_STATUS Status;\r
239 UINT16 *PtrBuffer;\r
ead42efc 240\r
241 //\r
630d580d 242 // No data transfer is premitted.\r
ead42efc 243 //\r
630d580d 244 if (ByteCount == 0) {\r
245 return EFI_SUCCESS;\r
ead42efc 246 }\r
247 //\r
630d580d 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
ead42efc 254 //\r
630d580d 255 // ActuralWordCount means the word count of data really transferred.\r
ead42efc 256 //\r
630d580d 257 ActualWordCount = 0;\r
ead42efc 258\r
630d580d 259 while (ActualWordCount < RequiredWordCount) {\r
260 \r
ead42efc 261 //\r
630d580d 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
ead42efc 264 //\r
630d580d 265 Status = DRQReady2 (IdeDev, TimeOut);\r
266 if (EFI_ERROR (Status)) {\r
267 return CheckErrorStatus (IdeDev);\r
268 }\r
269 \r
ead42efc 270 //\r
630d580d 271 // read Status Register will clear interrupt\r
ead42efc 272 //\r
630d580d 273 IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
ead42efc 274\r
ead42efc 275 //\r
630d580d 276 // get current data transfer size from Cylinder Registers.\r
ead42efc 277 //\r
630d580d 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
ead42efc 282\r
630d580d 283 WordCount = MIN (WordCount, (RequiredWordCount - ActualWordCount));\r
ead42efc 284\r
630d580d 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
ead42efc 300\r
630d580d 301 PtrBuffer += WordCount;\r
302 ActualWordCount += WordCount;\r
303 }\r
ead42efc 304 \r
630d580d 305 if (Read) {\r
ead42efc 306 //\r
630d580d 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
ead42efc 310 //\r
630d580d 311 AtapiReadPendingData (IdeDev);\r
ead42efc 312 }\r
313\r
314 //\r
630d580d 315 // After data transfer is completed, normally, DRQ bit should clear.\r
ead42efc 316 //\r
630d580d 317 Status = DRQClear2 (IdeDev, ATAPITIMEOUT);\r
318 if (EFI_ERROR (Status)) {\r
319 return EFI_DEVICE_ERROR;\r
ead42efc 320 }\r
321\r
630d580d 322 //\r
323 // read status register to check whether error happens.\r
324 //\r
325 return CheckErrorStatus (IdeDev);\r
ead42efc 326}\r
327\r
328/**\r
630d580d 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
ead42efc 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
1e23bd8d 374 (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)\r
ead42efc 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
1e23bd8d 383 // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
ead42efc 384 // determine how many data should be transferred.\r
385 //\r
386 IDEWritePortB (\r
387 IdeDev->PciIo,\r
388 IdeDev->IoPort->CylinderLsb,\r
1e23bd8d 389 (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff)\r
ead42efc 390 );\r
391 IDEWritePortB (\r
392 IdeDev->PciIo,\r
393 IdeDev->IoPort->CylinderMsb,\r
1e23bd8d 394 (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8)\r
ead42efc 395 );\r
396\r
397 //\r
1e23bd8d 398 // ATA_DEFAULT_CTL:0x0a (0000,1010)\r
ead42efc 399 // Disable interrupt\r
400 //\r
1e23bd8d 401 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL);\r
ead42efc 402\r
403 //\r
404 // Send Packet command to inform device\r
405 // that the following data bytes are command packet.\r
406 //\r
1e23bd8d 407 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET);\r
ead42efc 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
ead42efc 430/**\r
630d580d 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
ead42efc 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
1e23bd8d 475 (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD) // ATA_DEFAULT_CMD: 0xa0 (1010,0000)\r
ead42efc 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
1e23bd8d 484 // set the transfersize to ATAPI_MAX_BYTE_COUNT to\r
ead42efc 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
1e23bd8d 490 (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff)\r
ead42efc 491 );\r
492 IDEWritePortB (\r
493 IdeDev->PciIo,\r
494 IdeDev->IoPort->CylinderMsb,\r
1e23bd8d 495 (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8)\r
ead42efc 496 );\r
497\r
498 //\r
499 // DEFAULT_CTL:0x0a (0000,1010)\r
500 // Disable interrupt\r
501 //\r
1e23bd8d 502 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL);\r
ead42efc 503\r
504 //\r
505 // Send Packet command to inform device\r
506 // that the following data bytes are command packet.\r
507 //\r
1e23bd8d 508 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET);\r
ead42efc 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
ead42efc 529/**\r
630d580d 530 Sends out ATAPI Inquiry Packet Command to the specified device. This command will\r
531 return INQUIRY data of the device.\r
ead42efc 532\r
630d580d 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
ead42efc 535\r
630d580d 536 @retval EFI_SUCCESS Inquiry command completes successfully.\r
537 @retval EFI_DEVICE_ERROR Inquiry command failed.\r
ead42efc 538\r
630d580d 539 @note Parameter "IdeDev" will be updated in this function.\r
ead42efc 540\r
630d580d 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
13314ba3 557 Packet.Inquiry.allocation_length = (UINT8) sizeof (ATAPI_INQUIRY_DATA);\r
630d580d 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
ead42efc 580\r
630d580d 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
ead42efc 588\r
630d580d 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
ead42efc 602 \r
630d580d 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
ead42efc 605\r
630d580d 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
ead42efc 612**/\r
613EFI_STATUS\r
630d580d 614ATAPIIdentify (\r
615 IN IDE_BLK_IO_DEV *IdeDev\r
ead42efc 616 )\r
617{\r
630d580d 618 EFI_IDENTIFY_DATA *AtapiIdentifyPointer;\r
619 UINT8 DeviceSelect;\r
620 EFI_STATUS Status;\r
621\r
ead42efc 622 //\r
630d580d 623 // device select bit\r
ead42efc 624 //\r
630d580d 625 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
ead42efc 626\r
630d580d 627 AtapiIdentifyPointer = AllocatePool (sizeof (EFI_IDENTIFY_DATA));\r
628 if (AtapiIdentifyPointer == NULL) {\r
629 return EFI_OUT_OF_RESOURCES;\r
630 }\r
ead42efc 631 //\r
630d580d 632 // Send ATAPI Identify Command to get IDENTIFY data.\r
ead42efc 633 //\r
630d580d 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
ead42efc 653\r
654 //\r
630d580d 655 // Send ATAPI Inquiry Packet Command to get INQUIRY data.\r
ead42efc 656 //\r
630d580d 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
ead42efc 665 }\r
666 //\r
630d580d 667 // Get media removable info from INQUIRY data.\r
ead42efc 668 //\r
630d580d 669 IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->InquiryData->RMB & 0x80) == 0x80);\r
670\r
ead42efc 671 //\r
630d580d 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
ead42efc 680\r
ead42efc 681 //\r
630d580d 682 // device is LS120 or ZIP drive.\r
ead42efc 683 //\r
630d580d 684 IdeDev->Type = IdeMagnetic;\r
ead42efc 685\r
630d580d 686 IdeDev->BlkIo.Media->MediaId = 0;\r
ead42efc 687 //\r
630d580d 688 // Give initial value\r
ead42efc 689 //\r
630d580d 690 IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
ead42efc 691\r
630d580d 692 IdeDev->BlkIo.Media->LastBlock = 0;\r
693 IdeDev->BlkIo.Media->BlockSize = 0x200;\r
694 break;\r
ead42efc 695\r
630d580d 696 //\r
697 // CD-ROM\r
698 //\r
699 case 0x05:\r
ead42efc 700\r
630d580d 701 IdeDev->Type = IdeCdRom;\r
702 IdeDev->BlkIo.Media->MediaId = 0;\r
ead42efc 703 //\r
630d580d 704 // Give initial value\r
ead42efc 705 //\r
630d580d 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
ead42efc 712\r
713 //\r
630d580d 714 // Tape\r
ead42efc 715 //\r
630d580d 716 case 0x01:\r
ead42efc 717\r
718 //\r
630d580d 719 // WORM\r
ead42efc 720 //\r
630d580d 721 case 0x04:\r
722 \r
ead42efc 723 //\r
630d580d 724 // Optical\r
ead42efc 725 //\r
630d580d 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
ead42efc 739\r
740 //\r
630d580d 741 // original sense data numbers\r
ead42efc 742 //\r
630d580d 743 IdeDev->SenseDataNumber = 20;\r
ead42efc 744\r
630d580d 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
ead42efc 755 }\r
756\r
757 return EFI_SUCCESS;\r
758}\r
ead42efc 759/**\r
630d580d 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
ead42efc 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
1e23bd8d 780 ATAPI_REQUEST_SENSE_DATA *Sense;\r
ead42efc 781 UINT16 *Ptr;\r
782 BOOLEAN FetchSenseData;\r
783 ATAPI_PACKET_COMMAND Packet;\r
784\r
785 *SenseCounts = 0;\r
786\r
1e23bd8d 787 ZeroMem (IdeDev->SenseData, sizeof (ATAPI_REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));\r
ead42efc 788 //\r
789 // fill command packet for Request Sense Packet Command\r
790 //\r
791 ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
1e23bd8d 792 Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE;\r
13314ba3 793 Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA);\r
ead42efc 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
1e23bd8d 805 Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;\r
ead42efc 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
1e23bd8d 814 sizeof (ATAPI_REQUEST_SENSE_DATA),\r
ead42efc 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
630d580d 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
ead42efc 959\r
630d580d 960 Status = AtapiRequestSense (IdeDev, &SenseCount);\r
961 if (EFI_ERROR (Status)) {\r
962 return Status;\r
ead42efc 963 }\r
964\r
630d580d 965 ParseSenseData (IdeDev, SenseCount, SResult);\r
ead42efc 966 return EFI_SUCCESS;\r
967}\r
968\r
630d580d 969\r
ead42efc 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
630d580d 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
ead42efc 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
630d580d 987 @retval EFI_NOT_READY Operation succeeds but returned capacity is 0\r
ead42efc 988\r
989 @note Parameter "IdeDev" will be updated in this function.\r
990\r
630d580d 991 \r
ead42efc 992**/\r
993EFI_STATUS\r
994AtapiReadCapacity (\r
995 IN IDE_BLK_IO_DEV *IdeDev,\r
9ebae8ae 996 OUT SENSE_RESULT *SResult \r
ead42efc 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
9ebae8ae 1005 UINTN SenseCount;\r
ead42efc 1006\r
1007 //\r
1008 // used for capacity data returned from ATAPI device\r
1009 //\r
1e23bd8d 1010 ATAPI_READ_CAPACITY_DATA Data;\r
1011 ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;\r
ead42efc 1012\r
ead42efc 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
1e23bd8d 1019 Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;\r
ead42efc 1020 Status = AtapiPacketCommandIn (\r
1021 IdeDev,\r
1022 &Packet,\r
1023 (UINT16 *) &Data,\r
1e23bd8d 1024 sizeof (ATAPI_READ_CAPACITY_DATA),\r
ead42efc 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
1e23bd8d 1033 Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;\r
ead42efc 1034 Packet.ReadFormatCapacity.allocation_length_lo = 12;\r
1035 Status = AtapiPacketCommandIn (\r
1036 IdeDev,\r
1037 &Packet,\r
1038 (UINT16 *) &FormatData,\r
1e23bd8d 1039 sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),\r
ead42efc 1040 ATAPITIMEOUT\r
1041 );\r
1042 }\r
1043\r
1044 if (Status == EFI_TIMEOUT) {\r
ead42efc 1045 return Status;\r
1046 }\r
1047\r
9ebae8ae 1048 SenseStatus = AtapiRequestSense (IdeDev, &SenseCount);\r
ead42efc 1049\r
1050 if (!EFI_ERROR (SenseStatus)) {\r
9ebae8ae 1051 ParseSenseData (IdeDev, SenseCount, SResult); \r
1052 \r
1053 if (!EFI_ERROR (Status) && *SResult == SenseNoSenseKey) {\r
ead42efc 1054 if (IdeDev->Type == IdeCdRom) {\r
1055\r
f90c4fff 1056 IdeDev->BlkIo.Media->LastBlock = ((UINT32) Data.LastLba3 << 24) |\r
ead42efc 1057 (Data.LastLba2 << 16) |\r
1058 (Data.LastLba1 << 8) |\r
1059 Data.LastLba0;\r
1060\r
9b906315 1061 IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
ead42efc 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
f90c4fff 1079 IdeDev->BlkIo.Media->LastBlock = ((UINT32) FormatData.LastLba3 << 24) |\r
ead42efc 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
ead42efc 1108 return EFI_DEVICE_ERROR;\r
1109 }\r
1110}\r
630d580d 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
ead42efc 1160\r
1161/**\r
630d580d 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
ead42efc 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
ead42efc 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
9ebae8ae 1213 Status = AtapiTestUnitReady (IdeDev, &SResult);\r
ead42efc 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
ead42efc 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
9ebae8ae 1287 Status = AtapiReadCapacity (IdeDev, &SResult);\r
ead42efc 1288\r
1289 if (EFI_ERROR (Status)) {\r
1290 RetryTimes--;\r
1291 continue;\r
1292 } else {\r
ead42efc 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
630d580d 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
ead42efc 1425\r
630d580d 1426 @return status is fully dependent on the return status of AtapiPacketCommandIn() function.\r
ead42efc 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
1e23bd8d 1439 ATAPI_READ10_CMD *Read10Packet;\r
ead42efc 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
1e23bd8d 1482 Read10Packet->opcode = ATA_CMD_READ_10;\r
ead42efc 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
630d580d 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
ead42efc 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
1e23bd8d 1556 ATAPI_READ10_CMD *Read10Packet;\r
ead42efc 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
1e23bd8d 1601 Read10Packet->opcode = ATA_CMD_WRITE_10;\r
ead42efc 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
ead42efc 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
630d580d 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
ead42efc 1653\r
630d580d 1654 @retval EFI_SUCCESS Soft reset completes successfully.\r
1655 @retval EFI_DEVICE_ERROR Any step during the reset process is failed.\r
ead42efc 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
1e23bd8d 1671 DeviceSelect = (UINT8) (((BIT7 | BIT5) | (IdeDev->Device << 4)));\r
ead42efc 1672 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);\r
1673\r
1e23bd8d 1674 Command = ATA_CMD_SOFT_RESET;\r
ead42efc 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
630d580d 1699 @param IdeBlkIoDevice Indicates the calling context.\r
1700 @param MediaId The media id that the read request is for.\r
cd57e888 1701 @param Lba The starting logical block address to read from on the device.\r
630d580d 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
ead42efc 1707 \r
630d580d 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
ead42efc 1716**/\r
1717EFI_STATUS\r
1718AtapiBlkIoReadBlocks (\r
1719 IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
1720 IN UINT32 MediaId,\r
cd57e888 1721 IN EFI_LBA Lba,\r
ead42efc 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
cd57e888 1787 if (Lba > Media->LastBlock) {\r
ead42efc 1788 return EFI_INVALID_PARAMETER;\r
1789 }\r
1790\r
cd57e888 1791 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
ead42efc 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
cd57e888 1803 Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r
ead42efc 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
cd57e888 1815 if (Lba == 0 && (IdeBlkIoDevice->Cache == NULL)) {\r
ead42efc 1816 IdeBlkIoDevice->Cache = AllocatePool (BlockSize);\r
261136bc 1817 if (IdeBlkIoDevice->Cache!= NULL) {\r
ead42efc 1818 CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);\r
1819 }\r
1820 }\r
1821\r
1822 return EFI_SUCCESS;\r
1823\r
1824}\r
ead42efc 1825/**\r
1826 This function is the ATAPI implementation for WriteBlocks in the\r
1827 Block I/O Protocol interface.\r
1828\r
630d580d 1829 @param IdeBlkIoDevice Indicates the calling context.\r
1830 @param MediaId The media id that the write request is for.\r
cd57e888 1831 @param Lba The starting logical block address to write onto the device.\r
630d580d 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
ead42efc 1848**/\r
1849EFI_STATUS\r
1850AtapiBlkIoWriteBlocks (\r
1851 IN IDE_BLK_IO_DEV *IdeBlkIoDevice,\r
1852 IN UINT32 MediaId,\r
cd57e888 1853 IN EFI_LBA Lba,\r
ead42efc 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
cd57e888 1865 if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {\r
ead42efc 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
cd57e888 1886 if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {\r
ead42efc 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
cd57e888 1902 if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {\r
ead42efc 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
cd57e888 1911 if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {\r
ead42efc 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
cd57e888 1926 if (Lba > Media->LastBlock) {\r
ead42efc 1927 return EFI_INVALID_PARAMETER;\r
1928 }\r
1929\r
cd57e888 1930 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
ead42efc 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
cd57e888 1942 Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r
ead42efc 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
ead42efc 1951\r
ead42efc 1952\r