2 Pei USB ATAPI command implementations.
4 Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
5 Copyright (C) 2022 Advanced Micro Devices, Inc. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "UsbBotPeim.h"
17 Sends out ATAPI Inquiry Packet Command to the specified device. This command will
18 return INQUIRY data of the device.
20 @param PeiServices The pointer of EFI_PEI_SERVICES.
21 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
23 @retval EFI_SUCCESS Inquiry command completes successfully.
24 @retval EFI_DEVICE_ERROR Inquiry command failed.
29 IN EFI_PEI_SERVICES
**PeiServices
,
30 IN PEI_BOT_DEVICE
*PeiBotDevice
33 ATAPI_PACKET_COMMAND Packet
;
35 ATAPI_INQUIRY_DATA Idata
;
38 // fill command packet
40 ZeroMem (&Packet
, sizeof (ATAPI_PACKET_COMMAND
));
41 ZeroMem (&Idata
, sizeof (ATAPI_INQUIRY_DATA
));
43 Packet
.Inquiry
.opcode
= ATA_CMD_INQUIRY
;
44 Packet
.Inquiry
.page_code
= 0;
45 Packet
.Inquiry
.allocation_length
= 36;
48 // Send scsi INQUIRY command packet.
49 // According to SCSI Primary Commands-2 spec, host only needs to
50 // retrieve the first 36 bytes for standard INQUIRY data.
52 Status
= PeiAtapiCommand (
56 (UINT8
)sizeof (ATAPI_PACKET_COMMAND
),
63 if (EFI_ERROR (Status
)) {
64 return EFI_DEVICE_ERROR
;
67 if ((Idata
.peripheral_type
& 0x1f) == 0x05) {
68 PeiBotDevice
->DeviceType
= USBCDROM
;
69 PeiBotDevice
->Media
.BlockSize
= 0x800;
70 PeiBotDevice
->Media2
.ReadOnly
= TRUE
;
71 PeiBotDevice
->Media2
.RemovableMedia
= TRUE
;
72 PeiBotDevice
->Media2
.BlockSize
= 0x800;
74 PeiBotDevice
->DeviceType
= USBFLOPPY
;
75 PeiBotDevice
->Media
.BlockSize
= 0x200;
76 PeiBotDevice
->Media2
.ReadOnly
= FALSE
;
77 PeiBotDevice
->Media2
.RemovableMedia
= TRUE
;
78 PeiBotDevice
->Media2
.BlockSize
= 0x200;
85 Sends out ATAPI Test Unit Ready Packet Command to the specified device
86 to find out whether device is accessible.
88 @param PeiServices The pointer of EFI_PEI_SERVICES.
89 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
91 @retval EFI_SUCCESS TestUnit command executed successfully.
92 @retval EFI_DEVICE_ERROR Device cannot be executed TestUnit command successfully.
97 IN EFI_PEI_SERVICES
**PeiServices
,
98 IN PEI_BOT_DEVICE
*PeiBotDevice
101 ATAPI_PACKET_COMMAND Packet
;
105 // fill command packet
107 ZeroMem (&Packet
, sizeof (ATAPI_PACKET_COMMAND
));
108 Packet
.TestUnitReady
.opcode
= ATA_CMD_TEST_UNIT_READY
;
111 // send command packet
113 Status
= PeiAtapiCommand (
117 (UINT8
)sizeof (ATAPI_PACKET_COMMAND
),
124 if (EFI_ERROR (Status
)) {
125 return EFI_DEVICE_ERROR
;
132 Sends out ATAPI Request Sense Packet Command to the specified device.
134 @param PeiServices The pointer of EFI_PEI_SERVICES.
135 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
136 @param SenseCounts Length of sense buffer.
137 @param SenseKeyBuffer Pointer to sense buffer.
139 @retval EFI_SUCCESS Command executed successfully.
140 @retval EFI_DEVICE_ERROR Some device errors happen.
145 IN EFI_PEI_SERVICES
**PeiServices
,
146 IN PEI_BOT_DEVICE
*PeiBotDevice
,
147 OUT UINTN
*SenseCounts
,
148 IN UINT8
*SenseKeyBuffer
152 ATAPI_PACKET_COMMAND Packet
;
155 ATAPI_REQUEST_SENSE_DATA
*Sense
;
160 // fill command packet for Request Sense Packet Command
162 ZeroMem (&Packet
, sizeof (ATAPI_PACKET_COMMAND
));
163 Packet
.RequestSence
.opcode
= ATA_CMD_REQUEST_SENSE
;
164 Packet
.RequestSence
.allocation_length
= (UINT8
)sizeof (ATAPI_REQUEST_SENSE_DATA
);
166 Ptr
= SenseKeyBuffer
;
171 // request sense data from device continuously
172 // until no sense data exists in the device.
175 Sense
= (ATAPI_REQUEST_SENSE_DATA
*)Ptr
;
178 // send out Request Sense Packet Command and get one Sense
181 Status
= PeiAtapiCommand (
185 (UINT8
)sizeof (ATAPI_PACKET_COMMAND
),
187 sizeof (ATAPI_REQUEST_SENSE_DATA
),
193 // failed to get Sense data
195 if (EFI_ERROR (Status
)) {
196 if (*SenseCounts
== 0) {
197 return EFI_DEVICE_ERROR
;
203 if (Sense
->sense_key
!= ATA_SK_NO_SENSE
) {
204 Ptr
+= sizeof (ATAPI_REQUEST_SENSE_DATA
);
206 // Ptr is byte based pointer
210 if (*SenseCounts
== MAXSENSEKEY
) {
215 // when no sense key, skip out the loop
225 Sends out ATAPI Read Capacity Packet Command to the specified device.
226 This command will return the information regarding the capacity of the
229 @param PeiServices The pointer of EFI_PEI_SERVICES.
230 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
232 @retval EFI_SUCCESS Command executed successfully.
233 @retval EFI_DEVICE_ERROR Some device errors happen.
238 IN EFI_PEI_SERVICES
**PeiServices
,
239 IN PEI_BOT_DEVICE
*PeiBotDevice
243 ATAPI_PACKET_COMMAND Packet
;
244 ATAPI_READ_CAPACITY_DATA Data
;
247 ZeroMem (&Data
, sizeof (ATAPI_READ_CAPACITY_DATA
));
248 ZeroMem (&Packet
, sizeof (ATAPI_PACKET_COMMAND
));
250 Packet
.Inquiry
.opcode
= ATA_CMD_READ_CAPACITY
;
253 // send command packet
255 Status
= PeiAtapiCommand (
259 (UINT8
)sizeof (ATAPI_PACKET_COMMAND
),
261 sizeof (ATAPI_READ_CAPACITY_DATA
),
266 if (EFI_ERROR (Status
)) {
267 return EFI_DEVICE_ERROR
;
270 LastBlock
= ((UINT32
)Data
.LastLba3
<< 24) | (Data
.LastLba2
<< 16) | (Data
.LastLba1
<< 8) | Data
.LastLba0
;
272 if (LastBlock
== 0xFFFFFFFF) {
273 DEBUG ((DEBUG_INFO
, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
276 PeiBotDevice
->Media
.LastBlock
= LastBlock
;
277 PeiBotDevice
->Media
.MediaPresent
= TRUE
;
279 PeiBotDevice
->Media2
.LastBlock
= LastBlock
;
280 PeiBotDevice
->Media2
.MediaPresent
= TRUE
;
286 Sends out ATAPI Read Format Capacity Data Command to the specified device.
287 This command will return the information regarding the capacity of the
290 @param PeiServices The pointer of EFI_PEI_SERVICES.
291 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
293 @retval EFI_SUCCESS Command executed successfully.
294 @retval EFI_DEVICE_ERROR Some device errors happen.
298 PeiUsbReadFormattedCapacity (
299 IN EFI_PEI_SERVICES
**PeiServices
,
300 IN PEI_BOT_DEVICE
*PeiBotDevice
304 ATAPI_PACKET_COMMAND Packet
;
305 ATAPI_READ_FORMAT_CAPACITY_DATA FormatData
;
308 ZeroMem (&FormatData
, sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA
));
309 ZeroMem (&Packet
, sizeof (ATAPI_PACKET_COMMAND
));
311 Packet
.ReadFormatCapacity
.opcode
= ATA_CMD_READ_FORMAT_CAPACITY
;
312 Packet
.ReadFormatCapacity
.allocation_length_lo
= 12;
315 // send command packet
317 Status
= PeiAtapiCommand (
321 (UINT8
)sizeof (ATAPI_PACKET_COMMAND
),
323 sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA
),
328 if (EFI_ERROR (Status
)) {
329 return EFI_DEVICE_ERROR
;
332 if (FormatData
.DesCode
== 3) {
334 // Media is not present
336 PeiBotDevice
->Media
.MediaPresent
= FALSE
;
337 PeiBotDevice
->Media
.LastBlock
= 0;
338 PeiBotDevice
->Media2
.MediaPresent
= FALSE
;
339 PeiBotDevice
->Media2
.LastBlock
= 0;
341 LastBlock
= ((UINT32
)FormatData
.LastLba3
<< 24) | (FormatData
.LastLba2
<< 16) | (FormatData
.LastLba1
<< 8) | FormatData
.LastLba0
;
342 if (LastBlock
== 0xFFFFFFFF) {
343 DEBUG ((DEBUG_INFO
, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
346 PeiBotDevice
->Media
.LastBlock
= LastBlock
;
348 PeiBotDevice
->Media
.LastBlock
--;
350 PeiBotDevice
->Media
.MediaPresent
= TRUE
;
352 PeiBotDevice
->Media2
.MediaPresent
= TRUE
;
353 PeiBotDevice
->Media2
.LastBlock
= PeiBotDevice
->Media
.LastBlock
;
360 Execute Read(10) ATAPI command on a specific SCSI target.
362 Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.
364 @param PeiServices The pointer of EFI_PEI_SERVICES.
365 @param PeiBotDevice The pointer to PEI_BOT_DEVICE instance.
366 @param Buffer The pointer to data buffer.
367 @param Lba The start logic block address of reading.
368 @param NumberOfBlocks The block number of reading.
370 @retval EFI_SUCCESS Command executed successfully.
371 @retval EFI_DEVICE_ERROR Some device errors happen.
376 IN EFI_PEI_SERVICES
**PeiServices
,
377 IN PEI_BOT_DEVICE
*PeiBotDevice
,
380 IN UINTN NumberOfBlocks
383 ATAPI_PACKET_COMMAND Packet
;
384 ATAPI_READ10_CMD
*Read10Packet
;
386 UINT32 BlocksRemaining
;
396 // prepare command packet for the Inquiry Packet Command.
398 ZeroMem (&Packet
, sizeof (ATAPI_PACKET_COMMAND
));
399 Read10Packet
= &Packet
.Read10
;
403 BlockSize
= (UINT32
)PeiBotDevice
->Media
.BlockSize
;
405 MaxBlock
= (UINT16
)(MAX_UINT16
/ BlockSize
);
406 ASSERT (NumberOfBlocks
< MAX_UINT32
);
407 BlocksRemaining
= (UINT32
)NumberOfBlocks
;
409 Status
= EFI_SUCCESS
;
410 while (BlocksRemaining
> 0) {
411 SectorCount
= MIN (BlocksRemaining
, MaxBlock
);
414 // fill the Packet data structure
416 Read10Packet
->opcode
= ATA_CMD_READ_10
;
419 // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
420 // Lba0 is MSB, Lba3 is LSB
422 Read10Packet
->Lba3
= (UINT8
)(Lba32
& 0xff);
423 Read10Packet
->Lba2
= (UINT8
)(Lba32
>> 8);
424 Read10Packet
->Lba1
= (UINT8
)(Lba32
>> 16);
425 Read10Packet
->Lba0
= (UINT8
)(Lba32
>> 24);
428 // TranLen0 ~ TranLen1 specify the transfer length in block unit.
429 // TranLen0 is MSB, TranLen is LSB
431 Read10Packet
->TranLen1
= (UINT8
)(SectorCount
& 0xff);
432 Read10Packet
->TranLen0
= (UINT8
)(SectorCount
>> 8);
434 ByteCount
= SectorCount
* BlockSize
;
436 TimeOut
= SectorCount
* 2000;
439 // send command packet
441 Status
= PeiAtapiCommand (
445 (UINT8
)sizeof (ATAPI_PACKET_COMMAND
),
449 (UINT16
)MIN (TimeOut
, MAX_UINT16
)
452 if (Status
!= EFI_SUCCESS
) {
456 ASSERT (Lba32
<= (MAX_UINT32
-SectorCount
));
457 Lba32
+= SectorCount
;
458 PtrBuffer
= (UINT8
*)PtrBuffer
+ SectorCount
* BlockSize
;
459 BlocksRemaining
= BlocksRemaining
- SectorCount
;
466 Check if there is media according to sense data.
468 @param SenseData Pointer to sense data.
469 @param SenseCounts Count of sense data.
471 @retval TRUE No media
472 @retval FALSE Media exists
477 IN ATAPI_REQUEST_SENSE_DATA
*SenseData
,
481 ATAPI_REQUEST_SENSE_DATA
*SensePtr
;
486 SensePtr
= SenseData
;
488 for (Index
= 0; Index
< SenseCounts
; Index
++) {
489 switch (SensePtr
->sense_key
) {
490 case ATA_SK_NOT_READY
:
491 switch (SensePtr
->addnl_sense_code
) {
493 // if no media, fill IdeDev parameter with specific info.
495 case ATA_ASC_NO_MEDIA
:
516 Check if there is media error according to sense data.
518 @param SenseData Pointer to sense data.
519 @param SenseCounts Count of sense data.
521 @retval TRUE Media error
522 @retval FALSE No media error
527 IN ATAPI_REQUEST_SENSE_DATA
*SenseData
,
531 ATAPI_REQUEST_SENSE_DATA
*SensePtr
;
535 SensePtr
= SenseData
;
538 for (Index
= 0; Index
< SenseCounts
; Index
++) {
539 switch (SensePtr
->sense_key
) {
543 case ATA_SK_MEDIUM_ERROR
:
544 switch (SensePtr
->addnl_sense_code
) {
545 case ATA_ASC_MEDIA_ERR1
:
549 case ATA_ASC_MEDIA_ERR2
:
553 case ATA_ASC_MEDIA_ERR3
:
557 case ATA_ASC_MEDIA_ERR4
:
568 // Medium upside-down case
570 case ATA_SK_NOT_READY
:
571 switch (SensePtr
->addnl_sense_code
) {
572 case ATA_ASC_MEDIA_UPSIDE_DOWN
:
593 Check if media is changed according to sense data.
595 @param SenseData Pointer to sense data.
596 @param SenseCounts Count of sense data.
598 @retval TRUE There is media change event.
599 @retval FALSE media is NOT changed.
604 IN ATAPI_REQUEST_SENSE_DATA
*SenseData
,
608 ATAPI_REQUEST_SENSE_DATA
*SensePtr
;
614 SensePtr
= SenseData
;
616 for (Index
= 0; Index
< SenseCounts
; Index
++) {
618 // catch media change sense key and addition sense data
620 switch (SensePtr
->sense_key
) {
621 case ATA_SK_UNIT_ATTENTION
:
622 switch (SensePtr
->addnl_sense_code
) {
623 case ATA_ASC_MEDIA_CHANGE
: