2 The helper functions for BlockIo and BlockIo2 protocol.
4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Nonblocking I/O callback funtion when the event is signaled.
20 @param[in] Event The Event this notify function registered to.
21 @param[in] Context Pointer to the context data registered to the
34 gBS
->CloseEvent (Event
);
36 Request
= (SD_REQUEST
*) Context
;
39 DEBUG ((EFI_D_INFO
, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n",
40 Request
->SdMmcCmdBlk
.CommandIndex
, Request
->SdMmcCmdBlk
.CommandArgument
,
41 Request
->Packet
.TransactionStatus
));
44 if (EFI_ERROR (Request
->Packet
.TransactionStatus
)) {
45 Request
->Token
->TransactionStatus
= Request
->Packet
.TransactionStatus
;
48 RemoveEntryList (&Request
->Link
);
51 gBS
->SignalEvent (Request
->Token
->Event
);
58 Send command SET_RELATIVE_ADDRESS to the device to set the device address.
60 @param[in] Device A pointer to the SD_DEVICE instance.
61 @param[out] Rca The relative device address to assign.
63 @retval EFI_SUCCESS The request is executed successfully.
64 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
65 @retval Others The request could not be executed successfully.
75 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
76 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk
;
77 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk
;
78 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet
;
80 PassThru
= Device
->Private
->PassThru
;
82 ZeroMem (&SdMmcCmdBlk
, sizeof (SdMmcCmdBlk
));
83 ZeroMem (&SdMmcStatusBlk
, sizeof (SdMmcStatusBlk
));
84 ZeroMem (&Packet
, sizeof (Packet
));
85 Packet
.SdMmcCmdBlk
= &SdMmcCmdBlk
;
86 Packet
.SdMmcStatusBlk
= &SdMmcStatusBlk
;
87 Packet
.Timeout
= SD_GENERIC_TIMEOUT
;
89 SdMmcCmdBlk
.CommandIndex
= SD_SET_RELATIVE_ADDR
;
90 SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeBcr
;
91 SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR6
;
93 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &Packet
, NULL
);
94 if (!EFI_ERROR (Status
)) {
95 DEBUG ((EFI_D_INFO
, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk
.Resp0
));
96 *Rca
= (UINT16
)(SdMmcStatusBlk
.Resp0
>> 16);
103 Send command SELECT to the device to select/deselect the device.
105 @param[in] Device A pointer to the SD_DEVICE instance.
106 @param[in] Rca The relative device address to use.
108 @retval EFI_SUCCESS The request is executed successfully.
109 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
110 @retval Others The request could not be executed successfully.
115 IN SD_DEVICE
*Device
,
120 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
121 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk
;
122 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk
;
123 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet
;
125 PassThru
= Device
->Private
->PassThru
;
127 ZeroMem (&SdMmcCmdBlk
, sizeof (SdMmcCmdBlk
));
128 ZeroMem (&SdMmcStatusBlk
, sizeof (SdMmcStatusBlk
));
129 ZeroMem (&Packet
, sizeof (Packet
));
130 Packet
.SdMmcCmdBlk
= &SdMmcCmdBlk
;
131 Packet
.SdMmcStatusBlk
= &SdMmcStatusBlk
;
132 Packet
.Timeout
= SD_GENERIC_TIMEOUT
;
134 SdMmcCmdBlk
.CommandIndex
= SD_SELECT_DESELECT_CARD
;
135 SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
137 SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1b
;
139 SdMmcCmdBlk
.CommandArgument
= (UINT32
)Rca
<< 16;
141 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &Packet
, NULL
);
147 Send command SEND_STATUS to the device to get device status.
149 @param[in] Device A pointer to the SD_DEVICE instance.
150 @param[in] Rca The relative device address to use.
151 @param[out] DevStatus The buffer to store the device status.
153 @retval EFI_SUCCESS The request is executed successfully.
154 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
155 @retval Others The request could not be executed successfully.
160 IN SD_DEVICE
*Device
,
162 OUT UINT32
*DevStatus
166 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
167 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk
;
168 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk
;
169 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet
;
171 PassThru
= Device
->Private
->PassThru
;
173 ZeroMem (&SdMmcCmdBlk
, sizeof (SdMmcCmdBlk
));
174 ZeroMem (&SdMmcStatusBlk
, sizeof (SdMmcStatusBlk
));
175 ZeroMem (&Packet
, sizeof (Packet
));
176 Packet
.SdMmcCmdBlk
= &SdMmcCmdBlk
;
177 Packet
.SdMmcStatusBlk
= &SdMmcStatusBlk
;
178 Packet
.Timeout
= SD_GENERIC_TIMEOUT
;
180 SdMmcCmdBlk
.CommandIndex
= SD_SEND_STATUS
;
181 SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
182 SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
183 SdMmcCmdBlk
.CommandArgument
= (UINT32
)Rca
<< 16;
185 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &Packet
, NULL
);
186 if (!EFI_ERROR (Status
)) {
187 CopyMem (DevStatus
, &SdMmcStatusBlk
.Resp0
, sizeof (UINT32
));
193 Send command SEND_CSD to the device to get the CSD register data.
195 @param[in] Device A pointer to the SD_DEVICE instance.
196 @param[in] Rca The relative device address to use.
197 @param[out] Csd The buffer to store the SD_CSD register data.
199 @retval EFI_SUCCESS The request is executed successfully.
200 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
201 @retval Others The request could not be executed successfully.
206 IN SD_DEVICE
*Device
,
212 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
213 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk
;
214 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk
;
215 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet
;
217 PassThru
= Device
->Private
->PassThru
;
219 ZeroMem (&SdMmcCmdBlk
, sizeof (SdMmcCmdBlk
));
220 ZeroMem (&SdMmcStatusBlk
, sizeof (SdMmcStatusBlk
));
221 ZeroMem (&Packet
, sizeof (Packet
));
222 ZeroMem (Csd
, sizeof (SD_CSD
));
224 Packet
.SdMmcCmdBlk
= &SdMmcCmdBlk
;
225 Packet
.SdMmcStatusBlk
= &SdMmcStatusBlk
;
226 Packet
.Timeout
= SD_GENERIC_TIMEOUT
;
228 SdMmcCmdBlk
.CommandIndex
= SD_SEND_CSD
;
229 SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
230 SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR2
;
231 SdMmcCmdBlk
.CommandArgument
= (UINT32
)Rca
<< 16;
233 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &Packet
, NULL
);
235 if (!EFI_ERROR (Status
)) {
237 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
239 CopyMem (((UINT8
*)Csd
) + 1, &SdMmcStatusBlk
.Resp0
, sizeof (SD_CSD
) - 1);
246 Send command SEND_CID to the device to get the CID register data.
248 @param[in] Device A pointer to the SD_DEVICE instance.
249 @param[in] Rca The relative device address to use.
250 @param[out] Cid The buffer to store the SD_CID register data.
252 @retval EFI_SUCCESS The request is executed successfully.
253 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
254 @retval Others The request could not be executed successfully.
259 IN SD_DEVICE
*Device
,
265 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
266 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk
;
267 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk
;
268 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet
;
270 PassThru
= Device
->Private
->PassThru
;
272 ZeroMem (&SdMmcCmdBlk
, sizeof (SdMmcCmdBlk
));
273 ZeroMem (&SdMmcStatusBlk
, sizeof (SdMmcStatusBlk
));
274 ZeroMem (&Packet
, sizeof (Packet
));
275 ZeroMem (Cid
, sizeof (SD_CID
));
277 Packet
.SdMmcCmdBlk
= &SdMmcCmdBlk
;
278 Packet
.SdMmcStatusBlk
= &SdMmcStatusBlk
;
279 Packet
.Timeout
= SD_GENERIC_TIMEOUT
;
281 SdMmcCmdBlk
.CommandIndex
= SD_SEND_CID
;
282 SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
283 SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR2
;
284 SdMmcCmdBlk
.CommandArgument
= (UINT32
)Rca
<< 16;
286 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &Packet
, NULL
);
288 if (!EFI_ERROR (Status
)) {
290 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
292 CopyMem (((UINT8
*)Cid
) + 1, &SdMmcStatusBlk
.Resp0
, sizeof (SD_CID
) - 1);
299 Read/write single block through sync or async I/O request.
301 @param[in] Device A pointer to the SD_DEVICE instance.
302 @param[in] Lba The starting logical block address to be read/written.
303 The caller is responsible for reading/writing to only
304 legitimate locations.
305 @param[in] Buffer A pointer to the destination/source buffer for the data.
306 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
307 @param[in] IsRead Indicates it is a read or write operation.
308 @param[in] Token A pointer to the token associated with the transaction.
309 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
310 This parameter is only meaningful in async I/O request.
312 @retval EFI_SUCCESS The request is executed successfully.
313 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
314 @retval Others The request could not be executed successfully.
319 IN SD_DEVICE
*Device
,
324 IN EFI_BLOCK_IO2_TOKEN
*Token
,
329 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
330 SD_REQUEST
*RwSingleBlkReq
;
333 RwSingleBlkReq
= NULL
;
334 PassThru
= Device
->Private
->PassThru
;
336 RwSingleBlkReq
= AllocateZeroPool (sizeof (SD_REQUEST
));
337 if (RwSingleBlkReq
== NULL
) {
338 Status
= EFI_OUT_OF_RESOURCES
;
342 RwSingleBlkReq
->Signature
= SD_REQUEST_SIGNATURE
;
343 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
344 InsertTailList (&Device
->Queue
, &RwSingleBlkReq
->Link
);
345 gBS
->RestoreTPL (OldTpl
);
346 RwSingleBlkReq
->Packet
.SdMmcCmdBlk
= &RwSingleBlkReq
->SdMmcCmdBlk
;
347 RwSingleBlkReq
->Packet
.SdMmcStatusBlk
= &RwSingleBlkReq
->SdMmcStatusBlk
;
349 // Calculate timeout value through the below formula.
350 // Timeout = (transfer size) / (2MB/s).
351 // Taking 2MB/s as divisor as it's the lowest transfer speed
353 // Refer to SD Physical Layer Simplified spec section 3.4 for details.
355 RwSingleBlkReq
->Packet
.Timeout
= (BufferSize
/ (2 * 1024 * 1024) + 1) * 1000 * 1000;
358 RwSingleBlkReq
->Packet
.InDataBuffer
= Buffer
;
359 RwSingleBlkReq
->Packet
.InTransferLength
= (UINT32
)BufferSize
;
361 RwSingleBlkReq
->SdMmcCmdBlk
.CommandIndex
= SD_READ_SINGLE_BLOCK
;
362 RwSingleBlkReq
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAdtc
;
363 RwSingleBlkReq
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
365 RwSingleBlkReq
->Packet
.OutDataBuffer
= Buffer
;
366 RwSingleBlkReq
->Packet
.OutTransferLength
= (UINT32
)BufferSize
;
368 RwSingleBlkReq
->SdMmcCmdBlk
.CommandIndex
= SD_WRITE_SINGLE_BLOCK
;
369 RwSingleBlkReq
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAdtc
;
370 RwSingleBlkReq
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
373 if (Device
->SectorAddressing
) {
374 RwSingleBlkReq
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)Lba
;
376 RwSingleBlkReq
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)MultU64x32 (Lba
, Device
->BlockMedia
.BlockSize
);
379 RwSingleBlkReq
->IsEnd
= IsEnd
;
380 RwSingleBlkReq
->Token
= Token
;
382 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
383 Status
= gBS
->CreateEvent (
388 &RwSingleBlkReq
->Event
390 if (EFI_ERROR (Status
)) {
394 RwSingleBlkReq
->Event
= NULL
;
397 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &RwSingleBlkReq
->Packet
, RwSingleBlkReq
->Event
);
400 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
402 // For asynchronous operation, only free request and event in error case.
403 // The request and event will be freed in asynchronous callback for success case.
405 if (EFI_ERROR (Status
) && (RwSingleBlkReq
!= NULL
)) {
406 RemoveEntryList (&RwSingleBlkReq
->Link
);
407 if (RwSingleBlkReq
->Event
!= NULL
) {
408 gBS
->CloseEvent (RwSingleBlkReq
->Event
);
410 FreePool (RwSingleBlkReq
);
414 // For synchronous operation, free request whatever the execution result is.
416 if (RwSingleBlkReq
!= NULL
) {
417 RemoveEntryList (&RwSingleBlkReq
->Link
);
418 FreePool (RwSingleBlkReq
);
426 Read/write multiple blocks through sync or async I/O request.
428 @param[in] Device A pointer to the SD_DEVICE instance.
429 @param[in] Lba The starting logical block address to be read/written.
430 The caller is responsible for reading/writing to only
431 legitimate locations.
432 @param[in] Buffer A pointer to the destination/source buffer for the data.
433 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
434 @param[in] IsRead Indicates it is a read or write operation.
435 @param[in] Token A pointer to the token associated with the transaction.
436 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
437 This parameter is only meaningful in async I/O request.
439 @retval EFI_SUCCESS The request is executed successfully.
440 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
441 @retval Others The request could not be executed successfully.
446 IN SD_DEVICE
*Device
,
451 IN EFI_BLOCK_IO2_TOKEN
*Token
,
456 SD_REQUEST
*RwMultiBlkReq
;
457 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
460 RwMultiBlkReq
= NULL
;
462 PassThru
= Device
->Private
->PassThru
;
464 RwMultiBlkReq
= AllocateZeroPool (sizeof (SD_REQUEST
));
465 if (RwMultiBlkReq
== NULL
) {
466 Status
= EFI_OUT_OF_RESOURCES
;
470 RwMultiBlkReq
->Signature
= SD_REQUEST_SIGNATURE
;
471 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
472 InsertTailList (&Device
->Queue
, &RwMultiBlkReq
->Link
);
473 gBS
->RestoreTPL (OldTpl
);
474 RwMultiBlkReq
->Packet
.SdMmcCmdBlk
= &RwMultiBlkReq
->SdMmcCmdBlk
;
475 RwMultiBlkReq
->Packet
.SdMmcStatusBlk
= &RwMultiBlkReq
->SdMmcStatusBlk
;
477 // Calculate timeout value through the below formula.
478 // Timeout = (transfer size) / (2MB/s).
479 // Taking 2MB/s as divisor as it's the lowest transfer speed
481 // Refer to SD Physical Layer Simplified spec section 3.4 for details.
483 RwMultiBlkReq
->Packet
.Timeout
= (BufferSize
/ (2 * 1024 * 1024) + 1) * 1000 * 1000;
486 RwMultiBlkReq
->Packet
.InDataBuffer
= Buffer
;
487 RwMultiBlkReq
->Packet
.InTransferLength
= (UINT32
)BufferSize
;
489 RwMultiBlkReq
->SdMmcCmdBlk
.CommandIndex
= SD_READ_MULTIPLE_BLOCK
;
490 RwMultiBlkReq
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAdtc
;
491 RwMultiBlkReq
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
493 RwMultiBlkReq
->Packet
.OutDataBuffer
= Buffer
;
494 RwMultiBlkReq
->Packet
.OutTransferLength
= (UINT32
)BufferSize
;
496 RwMultiBlkReq
->SdMmcCmdBlk
.CommandIndex
= SD_WRITE_MULTIPLE_BLOCK
;
497 RwMultiBlkReq
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAdtc
;
498 RwMultiBlkReq
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
501 if (Device
->SectorAddressing
) {
502 RwMultiBlkReq
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)Lba
;
504 RwMultiBlkReq
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)MultU64x32 (Lba
, Device
->BlockMedia
.BlockSize
);
507 RwMultiBlkReq
->IsEnd
= IsEnd
;
508 RwMultiBlkReq
->Token
= Token
;
510 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
511 Status
= gBS
->CreateEvent (
516 &RwMultiBlkReq
->Event
518 if (EFI_ERROR (Status
)) {
522 RwMultiBlkReq
->Event
= NULL
;
525 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &RwMultiBlkReq
->Packet
, RwMultiBlkReq
->Event
);
528 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
530 // For asynchronous operation, only free request and event in error case.
531 // The request and event will be freed in asynchronous callback for success case.
533 if (EFI_ERROR (Status
) && (RwMultiBlkReq
!= NULL
)) {
534 RemoveEntryList (&RwMultiBlkReq
->Link
);
535 if (RwMultiBlkReq
->Event
!= NULL
) {
536 gBS
->CloseEvent (RwMultiBlkReq
->Event
);
538 FreePool (RwMultiBlkReq
);
542 // For synchronous operation, free request whatever the execution result is.
544 if (RwMultiBlkReq
!= NULL
) {
545 RemoveEntryList (&RwMultiBlkReq
->Link
);
546 FreePool (RwMultiBlkReq
);
554 This function transfers data from/to the sd memory card device.
556 @param[in] Device A pointer to the SD_DEVICE instance.
557 @param[in] MediaId The media ID that the read/write request is for.
558 @param[in] Lba The starting logical block address to be read/written.
559 The caller is responsible for reading/writing to only
560 legitimate locations.
561 @param[in, out] Buffer A pointer to the destination/source buffer for the data.
562 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
563 @param[in] IsRead Indicates it is a read or write operation.
564 @param[in, out] Token A pointer to the token associated with the transaction.
566 @retval EFI_SUCCESS The data was read/written correctly to the device.
567 @retval EFI_WRITE_PROTECTED The device can not be read/written to.
568 @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
569 @retval EFI_NO_MEDIA There is no media in the device.
570 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
571 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
572 @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,
573 or the buffer is not on proper alignment.
578 IN SD_DEVICE
*Device
,
584 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
588 EFI_BLOCK_IO_MEDIA
*Media
;
596 Status
= EFI_SUCCESS
;
597 Media
= &Device
->BlockMedia
;
600 if (MediaId
!= Media
->MediaId
) {
601 return EFI_MEDIA_CHANGED
;
604 if (!IsRead
&& Media
->ReadOnly
) {
605 return EFI_WRITE_PROTECTED
;
611 if (Buffer
== NULL
) {
612 return EFI_INVALID_PARAMETER
;
615 if (BufferSize
== 0) {
616 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
617 Token
->TransactionStatus
= EFI_SUCCESS
;
618 gBS
->SignalEvent (Token
->Event
);
623 BlockSize
= Media
->BlockSize
;
624 if ((BufferSize
% BlockSize
) != 0) {
625 return EFI_BAD_BUFFER_SIZE
;
628 BlockNum
= BufferSize
/ BlockSize
;
629 if ((Lba
+ BlockNum
- 1) > Media
->LastBlock
) {
630 return EFI_INVALID_PARAMETER
;
633 IoAlign
= Media
->IoAlign
;
634 if (IoAlign
> 0 && (((UINTN
) Buffer
& (IoAlign
- 1)) != 0)) {
635 return EFI_INVALID_PARAMETER
;
638 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
639 Token
->TransactionStatus
= EFI_SUCCESS
;
643 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
645 Remaining
= BlockNum
;
648 while (Remaining
> 0) {
649 if (Remaining
<= MaxBlock
) {
650 BlockNum
= Remaining
;
656 BufferSize
= BlockNum
* BlockSize
;
658 Status
= SdRwSingleBlock (Device
, Lba
, Buffer
, BufferSize
, IsRead
, Token
, LastRw
);
660 Status
= SdRwMultiBlocks (Device
, Lba
, Buffer
, BufferSize
, IsRead
, Token
, LastRw
);
662 if (EFI_ERROR (Status
)) {
665 DEBUG ((EFI_D_INFO
, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", IsRead
? "Read" : "Write", Lba
, BlockNum
, Token
->Event
, Status
));
668 Buffer
= (UINT8
*)Buffer
+ BufferSize
;
669 Remaining
-= BlockNum
;
676 Reset the Block Device.
678 @param This Indicates a pointer to the calling context.
679 @param ExtendedVerification Driver may perform diagnostics on reset.
681 @retval EFI_SUCCESS The device was reset.
682 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
689 IN EFI_BLOCK_IO_PROTOCOL
*This
,
690 IN BOOLEAN ExtendedVerification
695 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
697 Device
= SD_DEVICE_DATA_FROM_BLKIO (This
);
699 PassThru
= Device
->Private
->PassThru
;
700 Status
= PassThru
->ResetDevice (PassThru
, Device
->Slot
);
701 if (EFI_ERROR (Status
)) {
702 Status
= EFI_DEVICE_ERROR
;
709 Read BufferSize bytes from Lba into Buffer.
711 @param This Indicates a pointer to the calling context.
712 @param MediaId Id of the media, changes every time the media is replaced.
713 @param Lba The starting Logical Block Address to read from
714 @param BufferSize Size of Buffer, must be a multiple of device block size.
715 @param Buffer A pointer to the destination buffer for the data. The caller is
716 responsible for either having implicit or explicit ownership of the buffer.
718 @retval EFI_SUCCESS The data was read correctly from the device.
719 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
720 @retval EFI_NO_MEDIA There is no media in the device.
721 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
722 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
723 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
724 or the buffer is not on proper alignment.
730 IN EFI_BLOCK_IO_PROTOCOL
*This
,
740 Device
= SD_DEVICE_DATA_FROM_BLKIO (This
);
742 Status
= SdReadWrite (Device
, MediaId
, Lba
, Buffer
, BufferSize
, TRUE
, NULL
);
747 Write BufferSize bytes from Lba into Buffer.
749 @param This Indicates a pointer to the calling context.
750 @param MediaId The media ID that the write request is for.
751 @param Lba The starting logical block address to be written. The caller is
752 responsible for writing to only legitimate locations.
753 @param BufferSize Size of Buffer, must be a multiple of device block size.
754 @param Buffer A pointer to the source buffer for the data.
756 @retval EFI_SUCCESS The data was written correctly to the device.
757 @retval EFI_WRITE_PROTECTED The device can not be written to.
758 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
759 @retval EFI_NO_MEDIA There is no media in the device.
760 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
761 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
762 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
763 or the buffer is not on proper alignment.
769 IN EFI_BLOCK_IO_PROTOCOL
*This
,
779 Device
= SD_DEVICE_DATA_FROM_BLKIO (This
);
781 Status
= SdReadWrite (Device
, MediaId
, Lba
, Buffer
, BufferSize
, FALSE
, NULL
);
786 Flush the Block Device.
788 @param This Indicates a pointer to the calling context.
790 @retval EFI_SUCCESS All outstanding data was written to the device
791 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
792 @retval EFI_NO_MEDIA There is no media in the device.
798 IN EFI_BLOCK_IO_PROTOCOL
*This
808 Reset the Block Device.
810 @param[in] This Indicates a pointer to the calling context.
811 @param[in] ExtendedVerification Driver may perform diagnostics on reset.
813 @retval EFI_SUCCESS The device was reset.
814 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
821 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
822 IN BOOLEAN ExtendedVerification
827 LIST_ENTRY
*NextLink
;
831 Device
= SD_DEVICE_DATA_FROM_BLKIO2 (This
);
833 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
834 for (Link
= GetFirstNode (&Device
->Queue
);
835 !IsNull (&Device
->Queue
, Link
);
837 NextLink
= GetNextNode (&Device
->Queue
, Link
);
838 RemoveEntryList (Link
);
840 Request
= SD_REQUEST_FROM_LINK (Link
);
842 gBS
->CloseEvent (Request
->Event
);
843 Request
->Token
->TransactionStatus
= EFI_ABORTED
;
845 if (Request
->IsEnd
) {
846 gBS
->SignalEvent (Request
->Token
->Event
);
851 gBS
->RestoreTPL (OldTpl
);
857 Read BufferSize bytes from Lba into Buffer.
859 @param[in] This Indicates a pointer to the calling context.
860 @param[in] MediaId Id of the media, changes every time the media is replaced.
861 @param[in] Lba The starting Logical Block Address to read from.
862 @param[in, out] Token A pointer to the token associated with the transaction.
863 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
864 @param[out] Buffer A pointer to the destination buffer for the data. The caller is
865 responsible for either having implicit or explicit ownership of the buffer.
867 @retval EFI_SUCCESS The read request was queued if Event is not NULL.
868 The data was read correctly from the device if
870 @retval EFI_DEVICE_ERROR The device reported an error while performing
872 @retval EFI_NO_MEDIA There is no media in the device.
873 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
874 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
875 intrinsic block size of the device.
876 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
877 or the buffer is not on proper alignment.
878 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
885 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
888 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
896 Device
= SD_DEVICE_DATA_FROM_BLKIO2 (This
);
898 Status
= SdReadWrite (Device
, MediaId
, Lba
, Buffer
, BufferSize
, TRUE
, Token
);
903 Write BufferSize bytes from Lba into Buffer.
905 @param[in] This Indicates a pointer to the calling context.
906 @param[in] MediaId The media ID that the write request is for.
907 @param[in] Lba The starting logical block address to be written. The
908 caller is responsible for writing to only legitimate
910 @param[in, out] Token A pointer to the token associated with the transaction.
911 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
912 @param[in] Buffer A pointer to the source buffer for the data.
914 @retval EFI_SUCCESS The data was written correctly to the device.
915 @retval EFI_WRITE_PROTECTED The device can not be written to.
916 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
917 @retval EFI_NO_MEDIA There is no media in the device.
918 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
919 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
920 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
921 or the buffer is not on proper alignment.
927 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
930 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
,
938 Device
= SD_DEVICE_DATA_FROM_BLKIO2 (This
);
940 Status
= SdReadWrite (Device
, MediaId
, Lba
, Buffer
, BufferSize
, FALSE
, Token
);
945 Flush the Block Device.
947 @param[in] This Indicates a pointer to the calling context.
948 @param[in, out] Token A pointer to the token associated with the transaction.
950 @retval EFI_SUCCESS All outstanding data was written to the device
951 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
952 @retval EFI_NO_MEDIA There is no media in the device.
958 IN EFI_BLOCK_IO2_PROTOCOL
*This
,
959 IN OUT EFI_BLOCK_IO2_TOKEN
*Token
963 // Signal event and return directly.
965 if (Token
!= NULL
&& Token
->Event
!= NULL
) {
966 Token
->TransactionStatus
= EFI_SUCCESS
;
967 gBS
->SignalEvent (Token
->Event
);
974 Set the erase start address through sync or async I/O request.
976 @param[in] Device A pointer to the SD_DEVICE instance.
977 @param[in] StartLba The starting logical block address to be erased.
978 @param[in] Token A pointer to the token associated with the transaction.
979 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
980 This parameter is only meaningful in async I/O request.
982 @retval EFI_SUCCESS The request is executed successfully.
983 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
984 @retval Others The request could not be executed successfully.
989 IN SD_DEVICE
*Device
,
991 IN EFI_BLOCK_IO2_TOKEN
*Token
,
996 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
997 SD_REQUEST
*EraseBlockStart
;
1000 EraseBlockStart
= NULL
;
1001 PassThru
= Device
->Private
->PassThru
;
1003 EraseBlockStart
= AllocateZeroPool (sizeof (SD_REQUEST
));
1004 if (EraseBlockStart
== NULL
) {
1005 Status
= EFI_OUT_OF_RESOURCES
;
1009 EraseBlockStart
->Signature
= SD_REQUEST_SIGNATURE
;
1010 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1011 InsertTailList (&Device
->Queue
, &EraseBlockStart
->Link
);
1012 gBS
->RestoreTPL (OldTpl
);
1013 EraseBlockStart
->Packet
.SdMmcCmdBlk
= &EraseBlockStart
->SdMmcCmdBlk
;
1014 EraseBlockStart
->Packet
.SdMmcStatusBlk
= &EraseBlockStart
->SdMmcStatusBlk
;
1015 EraseBlockStart
->Packet
.Timeout
= SD_GENERIC_TIMEOUT
;
1017 EraseBlockStart
->SdMmcCmdBlk
.CommandIndex
= SD_ERASE_WR_BLK_START
;
1018 EraseBlockStart
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
1019 EraseBlockStart
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
1021 if (Device
->SectorAddressing
) {
1022 EraseBlockStart
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)StartLba
;
1024 EraseBlockStart
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)MultU64x32 (StartLba
, Device
->BlockMedia
.BlockSize
);
1027 EraseBlockStart
->IsEnd
= IsEnd
;
1028 EraseBlockStart
->Token
= Token
;
1030 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1031 Status
= gBS
->CreateEvent (
1036 &EraseBlockStart
->Event
1038 if (EFI_ERROR (Status
)) {
1042 EraseBlockStart
->Event
= NULL
;
1045 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &EraseBlockStart
->Packet
, EraseBlockStart
->Event
);
1048 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1050 // For asynchronous operation, only free request and event in error case.
1051 // The request and event will be freed in asynchronous callback for success case.
1053 if (EFI_ERROR (Status
) && (EraseBlockStart
!= NULL
)) {
1054 RemoveEntryList (&EraseBlockStart
->Link
);
1055 if (EraseBlockStart
->Event
!= NULL
) {
1056 gBS
->CloseEvent (EraseBlockStart
->Event
);
1058 FreePool (EraseBlockStart
);
1062 // For synchronous operation, free request whatever the execution result is.
1064 if (EraseBlockStart
!= NULL
) {
1065 RemoveEntryList (&EraseBlockStart
->Link
);
1066 FreePool (EraseBlockStart
);
1074 Set the erase end address through sync or async I/O request.
1076 @param[in] Device A pointer to the SD_DEVICE instance.
1077 @param[in] EndLba The ending logical block address to be erased.
1078 @param[in] Token A pointer to the token associated with the transaction.
1079 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1080 This parameter is only meaningful in async I/O request.
1082 @retval EFI_SUCCESS The request is executed successfully.
1083 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1084 @retval Others The request could not be executed successfully.
1089 IN SD_DEVICE
*Device
,
1091 IN EFI_BLOCK_IO2_TOKEN
*Token
,
1096 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
1097 SD_REQUEST
*EraseBlockEnd
;
1100 EraseBlockEnd
= NULL
;
1101 PassThru
= Device
->Private
->PassThru
;
1103 EraseBlockEnd
= AllocateZeroPool (sizeof (SD_REQUEST
));
1104 if (EraseBlockEnd
== NULL
) {
1105 Status
= EFI_OUT_OF_RESOURCES
;
1109 EraseBlockEnd
->Signature
= SD_REQUEST_SIGNATURE
;
1110 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1111 InsertTailList (&Device
->Queue
, &EraseBlockEnd
->Link
);
1112 gBS
->RestoreTPL (OldTpl
);
1113 EraseBlockEnd
->Packet
.SdMmcCmdBlk
= &EraseBlockEnd
->SdMmcCmdBlk
;
1114 EraseBlockEnd
->Packet
.SdMmcStatusBlk
= &EraseBlockEnd
->SdMmcStatusBlk
;
1115 EraseBlockEnd
->Packet
.Timeout
= SD_GENERIC_TIMEOUT
;
1117 EraseBlockEnd
->SdMmcCmdBlk
.CommandIndex
= SD_ERASE_WR_BLK_END
;
1118 EraseBlockEnd
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
1119 EraseBlockEnd
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1
;
1121 if (Device
->SectorAddressing
) {
1122 EraseBlockEnd
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)EndLba
;
1124 EraseBlockEnd
->SdMmcCmdBlk
.CommandArgument
= (UINT32
)MultU64x32 (EndLba
, Device
->BlockMedia
.BlockSize
);
1127 EraseBlockEnd
->IsEnd
= IsEnd
;
1128 EraseBlockEnd
->Token
= Token
;
1130 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1131 Status
= gBS
->CreateEvent (
1136 &EraseBlockEnd
->Event
1138 if (EFI_ERROR (Status
)) {
1142 EraseBlockEnd
->Event
= NULL
;
1145 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &EraseBlockEnd
->Packet
, EraseBlockEnd
->Event
);
1148 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1150 // For asynchronous operation, only free request and event in error case.
1151 // The request and event will be freed in asynchronous callback for success case.
1153 if (EFI_ERROR (Status
) && (EraseBlockEnd
!= NULL
)) {
1154 RemoveEntryList (&EraseBlockEnd
->Link
);
1155 if (EraseBlockEnd
->Event
!= NULL
) {
1156 gBS
->CloseEvent (EraseBlockEnd
->Event
);
1158 FreePool (EraseBlockEnd
);
1162 // For synchronous operation, free request whatever the execution result is.
1164 if (EraseBlockEnd
!= NULL
) {
1165 RemoveEntryList (&EraseBlockEnd
->Link
);
1166 FreePool (EraseBlockEnd
);
1174 Erase specified blocks through sync or async I/O request.
1176 @param[in] Device A pointer to the SD_DEVICE instance.
1177 @param[in] Token A pointer to the token associated with the transaction.
1178 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1179 This parameter is only meaningful in async I/O request.
1181 @retval EFI_SUCCESS The request is executed successfully.
1182 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1183 @retval Others The request could not be executed successfully.
1188 IN SD_DEVICE
*Device
,
1189 IN EFI_BLOCK_IO2_TOKEN
*Token
,
1194 EFI_SD_MMC_PASS_THRU_PROTOCOL
*PassThru
;
1195 SD_REQUEST
*EraseBlock
;
1199 PassThru
= Device
->Private
->PassThru
;
1201 EraseBlock
= AllocateZeroPool (sizeof (SD_REQUEST
));
1202 if (EraseBlock
== NULL
) {
1203 Status
= EFI_OUT_OF_RESOURCES
;
1207 EraseBlock
->Signature
= SD_REQUEST_SIGNATURE
;
1208 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1209 InsertTailList (&Device
->Queue
, &EraseBlock
->Link
);
1210 gBS
->RestoreTPL (OldTpl
);
1211 EraseBlock
->Packet
.SdMmcCmdBlk
= &EraseBlock
->SdMmcCmdBlk
;
1212 EraseBlock
->Packet
.SdMmcStatusBlk
= &EraseBlock
->SdMmcStatusBlk
;
1213 EraseBlock
->Packet
.Timeout
= SD_GENERIC_TIMEOUT
;
1215 EraseBlock
->SdMmcCmdBlk
.CommandIndex
= SD_ERASE
;
1216 EraseBlock
->SdMmcCmdBlk
.CommandType
= SdMmcCommandTypeAc
;
1217 EraseBlock
->SdMmcCmdBlk
.ResponseType
= SdMmcResponseTypeR1b
;
1219 EraseBlock
->IsEnd
= IsEnd
;
1220 EraseBlock
->Token
= Token
;
1222 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1223 Status
= gBS
->CreateEvent (
1230 if (EFI_ERROR (Status
)) {
1234 EraseBlock
->Event
= NULL
;
1237 Status
= PassThru
->PassThru (PassThru
, Device
->Slot
, &EraseBlock
->Packet
, EraseBlock
->Event
);
1240 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1242 // For asynchronous operation, only free request and event in error case.
1243 // The request and event will be freed in asynchronous callback for success case.
1245 if (EFI_ERROR (Status
) && (EraseBlock
!= NULL
)) {
1246 RemoveEntryList (&EraseBlock
->Link
);
1247 if (EraseBlock
->Event
!= NULL
) {
1248 gBS
->CloseEvent (EraseBlock
->Event
);
1250 FreePool (EraseBlock
);
1254 // For synchronous operation, free request whatever the execution result is.
1256 if (EraseBlock
!= NULL
) {
1257 RemoveEntryList (&EraseBlock
->Link
);
1258 FreePool (EraseBlock
);
1266 Erase a specified number of device blocks.
1268 @param[in] This Indicates a pointer to the calling context.
1269 @param[in] MediaId The media ID that the erase request is for.
1270 @param[in] Lba The starting logical block address to be
1271 erased. The caller is responsible for erasing
1272 only legitimate locations.
1273 @param[in, out] Token A pointer to the token associated with the
1275 @param[in] Size The size in bytes to be erased. This must be
1276 a multiple of the physical block size of the
1279 @retval EFI_SUCCESS The erase request was queued if Event is not
1280 NULL. The data was erased correctly to the
1281 device if the Event is NULL.to the device.
1282 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1284 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1285 to perform the erase operation.
1286 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1288 @retval EFI_NO_MEDIA There is no media in the device.
1289 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1295 IN EFI_ERASE_BLOCK_PROTOCOL
*This
,
1298 IN OUT EFI_ERASE_BLOCK_TOKEN
*Token
,
1303 EFI_BLOCK_IO_MEDIA
*Media
;
1309 Status
= EFI_SUCCESS
;
1310 Device
= SD_DEVICE_DATA_FROM_ERASEBLK (This
);
1311 Media
= &Device
->BlockMedia
;
1313 if (MediaId
!= Media
->MediaId
) {
1314 return EFI_MEDIA_CHANGED
;
1317 if (Media
->ReadOnly
) {
1318 return EFI_WRITE_PROTECTED
;
1322 // Check parameters.
1324 BlockSize
= Media
->BlockSize
;
1325 if ((Size
% BlockSize
) != 0) {
1326 return EFI_INVALID_PARAMETER
;
1329 BlockNum
= Size
/ BlockSize
;
1330 if ((Lba
+ BlockNum
- 1) > Media
->LastBlock
) {
1331 return EFI_INVALID_PARAMETER
;
1334 if ((Token
!= NULL
) && (Token
->Event
!= NULL
)) {
1335 Token
->TransactionStatus
= EFI_SUCCESS
;
1338 LastLba
= Lba
+ BlockNum
- 1;
1340 Status
= SdEraseBlockStart (Device
, Lba
, (EFI_BLOCK_IO2_TOKEN
*)Token
, FALSE
);
1341 if (EFI_ERROR (Status
)) {
1345 Status
= SdEraseBlockEnd (Device
, LastLba
, (EFI_BLOCK_IO2_TOKEN
*)Token
, FALSE
);
1346 if (EFI_ERROR (Status
)) {
1350 Status
= SdEraseBlock (Device
, (EFI_BLOCK_IO2_TOKEN
*)Token
, TRUE
);
1351 if (EFI_ERROR (Status
)) {
1355 DEBUG ((EFI_D_ERROR
, "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", Lba
, BlockNum
, Token
->Event
, Status
));