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