]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / SdDxe / SdBlockIo.c
1 /** @file
2 The helper functions for BlockIo and BlockIo2 protocol.
3
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "SdDxe.h"
10
11 /**
12 Nonblocking I/O callback function when the event is signaled.
13
14 @param[in] Event The Event this notify function registered to.
15 @param[in] Context Pointer to the context data registered to the
16 Event.
17
18 **/
19 VOID
20 EFIAPI
21 AsyncIoCallback (
22 IN EFI_EVENT Event,
23 IN VOID *Context
24 )
25 {
26 SD_REQUEST *Request;
27
28 gBS->CloseEvent (Event);
29
30 Request = (SD_REQUEST *)Context;
31
32 DEBUG_CODE_BEGIN ();
33 DEBUG ((
34 DEBUG_INFO,
35 "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n",
36 Request->SdMmcCmdBlk.CommandIndex,
37 Request->SdMmcCmdBlk.CommandArgument,
38 Request->Packet.TransactionStatus
39 ));
40 DEBUG_CODE_END ();
41
42 if (EFI_ERROR (Request->Packet.TransactionStatus)) {
43 Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
44 }
45
46 RemoveEntryList (&Request->Link);
47
48 if (Request->IsEnd) {
49 gBS->SignalEvent (Request->Token->Event);
50 }
51
52 FreePool (Request);
53 }
54
55 /**
56 Send command SET_RELATIVE_ADDRESS to the device to set the device address.
57
58 @param[in] Device A pointer to the SD_DEVICE instance.
59 @param[out] Rca The relative device address to assign.
60
61 @retval EFI_SUCCESS The request is executed successfully.
62 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
63 @retval Others The request could not be executed successfully.
64
65 **/
66 EFI_STATUS
67 SdSetRca (
68 IN SD_DEVICE *Device,
69 OUT UINT16 *Rca
70 )
71 {
72 EFI_STATUS Status;
73 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
74 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
75 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
76 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
77
78 PassThru = Device->Private->PassThru;
79
80 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
81 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
82 ZeroMem (&Packet, sizeof (Packet));
83 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
84 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
85 Packet.Timeout = SD_GENERIC_TIMEOUT;
86
87 SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
88 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
89 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
90
91 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
92 if (!EFI_ERROR (Status)) {
93 DEBUG ((DEBUG_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0));
94 *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
95 }
96
97 return Status;
98 }
99
100 /**
101 Send command SELECT to the device to select/deselect the device.
102
103 @param[in] Device A pointer to the SD_DEVICE instance.
104 @param[in] Rca The relative device address to use.
105
106 @retval EFI_SUCCESS The request is executed successfully.
107 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
108 @retval Others The request could not be executed successfully.
109
110 **/
111 EFI_STATUS
112 SdSelect (
113 IN SD_DEVICE *Device,
114 IN UINT16 Rca
115 )
116 {
117 EFI_STATUS Status;
118 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
119 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
120 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
121 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
122
123 PassThru = Device->Private->PassThru;
124
125 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
126 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
127 ZeroMem (&Packet, sizeof (Packet));
128 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
129 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
130 Packet.Timeout = SD_GENERIC_TIMEOUT;
131
132 SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
133 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
134 if (Rca != 0) {
135 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
136 }
137
138 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
139
140 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
141
142 return Status;
143 }
144
145 /**
146 Send command SEND_STATUS to the device to get device status.
147
148 @param[in] Device A pointer to the SD_DEVICE instance.
149 @param[in] Rca The relative device address to use.
150 @param[out] DevStatus The buffer to store the device status.
151
152 @retval EFI_SUCCESS The request is executed successfully.
153 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
154 @retval Others The request could not be executed successfully.
155
156 **/
157 EFI_STATUS
158 SdSendStatus (
159 IN SD_DEVICE *Device,
160 IN UINT16 Rca,
161 OUT UINT32 *DevStatus
162 )
163 {
164 EFI_STATUS Status;
165 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
166 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
167 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;
168 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
169
170 PassThru = Device->Private->PassThru;
171
172 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
173 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
174 ZeroMem (&Packet, sizeof (Packet));
175 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
176 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
177 Packet.Timeout = SD_GENERIC_TIMEOUT;
178
179 SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
180 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
181 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
182 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
183
184 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
185 if (!EFI_ERROR (Status)) {
186 CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));
187 }
188
189 return Status;
190 }
191
192 /**
193 Send command SEND_CSD to the device to get the CSD register data.
194
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.
198
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.
202
203 **/
204 EFI_STATUS
205 SdGetCsd (
206 IN SD_DEVICE *Device,
207 IN UINT16 Rca,
208 OUT SD_CSD *Csd
209 )
210 {
211 EFI_STATUS Status;
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;
216
217 PassThru = Device->Private->PassThru;
218
219 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
220 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
221 ZeroMem (&Packet, sizeof (Packet));
222 ZeroMem (Csd, sizeof (SD_CSD));
223
224 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
225 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
226 Packet.Timeout = SD_GENERIC_TIMEOUT;
227
228 SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;
229 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
230 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
231 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
232
233 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
234
235 if (!EFI_ERROR (Status)) {
236 //
237 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
238 //
239 CopyMem (((UINT8 *)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);
240 }
241
242 return Status;
243 }
244
245 /**
246 Send command SEND_CID to the device to get the CID register data.
247
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.
251
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.
255
256 **/
257 EFI_STATUS
258 SdGetCid (
259 IN SD_DEVICE *Device,
260 IN UINT16 Rca,
261 OUT SD_CID *Cid
262 )
263 {
264 EFI_STATUS Status;
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;
269
270 PassThru = Device->Private->PassThru;
271
272 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
273 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
274 ZeroMem (&Packet, sizeof (Packet));
275 ZeroMem (Cid, sizeof (SD_CID));
276
277 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;
278 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
279 Packet.Timeout = SD_GENERIC_TIMEOUT;
280
281 SdMmcCmdBlk.CommandIndex = SD_SEND_CID;
282 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
283 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
284 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
285
286 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
287
288 if (!EFI_ERROR (Status)) {
289 //
290 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
291 //
292 CopyMem (((UINT8 *)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CID) - 1);
293 }
294
295 return Status;
296 }
297
298 /**
299 Read/write single block through sync or async I/O request.
300
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.
311
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.
315
316 **/
317 EFI_STATUS
318 SdRwSingleBlock (
319 IN SD_DEVICE *Device,
320 IN EFI_LBA Lba,
321 IN VOID *Buffer,
322 IN UINTN BufferSize,
323 IN BOOLEAN IsRead,
324 IN EFI_BLOCK_IO2_TOKEN *Token,
325 IN BOOLEAN IsEnd
326 )
327 {
328 EFI_STATUS Status;
329 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
330 SD_REQUEST *RwSingleBlkReq;
331 EFI_TPL OldTpl;
332
333 RwSingleBlkReq = NULL;
334 PassThru = Device->Private->PassThru;
335
336 RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
337 if (RwSingleBlkReq == NULL) {
338 Status = EFI_OUT_OF_RESOURCES;
339 goto Error;
340 }
341
342 RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;
343 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
344 InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);
345 gBS->RestoreTPL (OldTpl);
346 RwSingleBlkReq->Packet.SdMmcCmdBlk = &RwSingleBlkReq->SdMmcCmdBlk;
347 RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk;
348 //
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
352 // above class 2.
353 // Refer to SD Physical Layer Simplified spec section 3.4 for details.
354 //
355 RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
356
357 if (IsRead) {
358 RwSingleBlkReq->Packet.InDataBuffer = Buffer;
359 RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
360
361 RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;
362 RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
363 RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
364 } else {
365 RwSingleBlkReq->Packet.OutDataBuffer = Buffer;
366 RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
367
368 RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;
369 RwSingleBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
370 RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
371 }
372
373 if (Device->SectorAddressing) {
374 RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
375 } else {
376 RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
377 }
378
379 RwSingleBlkReq->IsEnd = IsEnd;
380 RwSingleBlkReq->Token = Token;
381
382 if ((Token != NULL) && (Token->Event != NULL)) {
383 Status = gBS->CreateEvent (
384 EVT_NOTIFY_SIGNAL,
385 TPL_NOTIFY,
386 AsyncIoCallback,
387 RwSingleBlkReq,
388 &RwSingleBlkReq->Event
389 );
390 if (EFI_ERROR (Status)) {
391 goto Error;
392 }
393 } else {
394 RwSingleBlkReq->Event = NULL;
395 }
396
397 Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->Event);
398
399 Error:
400 if ((Token != NULL) && (Token->Event != NULL)) {
401 //
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.
404 //
405 if (EFI_ERROR (Status) && (RwSingleBlkReq != NULL)) {
406 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
407 RemoveEntryList (&RwSingleBlkReq->Link);
408 gBS->RestoreTPL (OldTpl);
409 if (RwSingleBlkReq->Event != NULL) {
410 gBS->CloseEvent (RwSingleBlkReq->Event);
411 }
412
413 FreePool (RwSingleBlkReq);
414 }
415 } else {
416 //
417 // For synchronous operation, free request whatever the execution result is.
418 //
419 if (RwSingleBlkReq != NULL) {
420 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
421 RemoveEntryList (&RwSingleBlkReq->Link);
422 gBS->RestoreTPL (OldTpl);
423 FreePool (RwSingleBlkReq);
424 }
425 }
426
427 return Status;
428 }
429
430 /**
431 Read/write multiple blocks through sync or async I/O request.
432
433 @param[in] Device A pointer to the SD_DEVICE instance.
434 @param[in] Lba The starting logical block address to be read/written.
435 The caller is responsible for reading/writing to only
436 legitimate locations.
437 @param[in] Buffer A pointer to the destination/source buffer for the data.
438 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
439 @param[in] IsRead Indicates it is a read or write operation.
440 @param[in] Token A pointer to the token associated with the transaction.
441 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
442 This parameter is only meaningful in async I/O request.
443
444 @retval EFI_SUCCESS The request is executed successfully.
445 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
446 @retval Others The request could not be executed successfully.
447
448 **/
449 EFI_STATUS
450 SdRwMultiBlocks (
451 IN SD_DEVICE *Device,
452 IN EFI_LBA Lba,
453 IN VOID *Buffer,
454 IN UINTN BufferSize,
455 IN BOOLEAN IsRead,
456 IN EFI_BLOCK_IO2_TOKEN *Token,
457 IN BOOLEAN IsEnd
458 )
459 {
460 EFI_STATUS Status;
461 SD_REQUEST *RwMultiBlkReq;
462 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
463 EFI_TPL OldTpl;
464
465 RwMultiBlkReq = NULL;
466
467 PassThru = Device->Private->PassThru;
468
469 RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
470 if (RwMultiBlkReq == NULL) {
471 Status = EFI_OUT_OF_RESOURCES;
472 goto Error;
473 }
474
475 RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;
476 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
477 InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);
478 gBS->RestoreTPL (OldTpl);
479 RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;
480 RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;
481 //
482 // Calculate timeout value through the below formula.
483 // Timeout = (transfer size) / (2MB/s).
484 // Taking 2MB/s as divisor as it's the lowest transfer speed
485 // above class 2.
486 // Refer to SD Physical Layer Simplified spec section 3.4 for details.
487 //
488 RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
489
490 if (IsRead) {
491 RwMultiBlkReq->Packet.InDataBuffer = Buffer;
492 RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
493
494 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;
495 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
496 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
497 } else {
498 RwMultiBlkReq->Packet.OutDataBuffer = Buffer;
499 RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
500
501 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;
502 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
503 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
504 }
505
506 if (Device->SectorAddressing) {
507 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
508 } else {
509 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
510 }
511
512 RwMultiBlkReq->IsEnd = IsEnd;
513 RwMultiBlkReq->Token = Token;
514
515 if ((Token != NULL) && (Token->Event != NULL)) {
516 Status = gBS->CreateEvent (
517 EVT_NOTIFY_SIGNAL,
518 TPL_NOTIFY,
519 AsyncIoCallback,
520 RwMultiBlkReq,
521 &RwMultiBlkReq->Event
522 );
523 if (EFI_ERROR (Status)) {
524 goto Error;
525 }
526 } else {
527 RwMultiBlkReq->Event = NULL;
528 }
529
530 Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
531
532 Error:
533 if ((Token != NULL) && (Token->Event != NULL)) {
534 //
535 // For asynchronous operation, only free request and event in error case.
536 // The request and event will be freed in asynchronous callback for success case.
537 //
538 if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
539 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
540 RemoveEntryList (&RwMultiBlkReq->Link);
541 gBS->RestoreTPL (OldTpl);
542 if (RwMultiBlkReq->Event != NULL) {
543 gBS->CloseEvent (RwMultiBlkReq->Event);
544 }
545
546 FreePool (RwMultiBlkReq);
547 }
548 } else {
549 //
550 // For synchronous operation, free request whatever the execution result is.
551 //
552 if (RwMultiBlkReq != NULL) {
553 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
554 RemoveEntryList (&RwMultiBlkReq->Link);
555 gBS->RestoreTPL (OldTpl);
556 FreePool (RwMultiBlkReq);
557 }
558 }
559
560 return Status;
561 }
562
563 /**
564 This function transfers data from/to the sd memory card device.
565
566 @param[in] Device A pointer to the SD_DEVICE instance.
567 @param[in] MediaId The media ID that the read/write request is for.
568 @param[in] Lba The starting logical block address to be read/written.
569 The caller is responsible for reading/writing to only
570 legitimate locations.
571 @param[in, out] Buffer A pointer to the destination/source buffer for the data.
572 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
573 @param[in] IsRead Indicates it is a read or write operation.
574 @param[in, out] Token A pointer to the token associated with the transaction.
575
576 @retval EFI_SUCCESS The data was read/written correctly to the device.
577 @retval EFI_WRITE_PROTECTED The device can not be read/written to.
578 @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
579 @retval EFI_NO_MEDIA There is no media in the device.
580 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
581 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
582 @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,
583 or the buffer is not on proper alignment.
584
585 **/
586 EFI_STATUS
587 SdReadWrite (
588 IN SD_DEVICE *Device,
589 IN UINT32 MediaId,
590 IN EFI_LBA Lba,
591 IN OUT VOID *Buffer,
592 IN UINTN BufferSize,
593 IN BOOLEAN IsRead,
594 IN OUT EFI_BLOCK_IO2_TOKEN *Token
595 )
596 {
597 EFI_STATUS Status;
598 EFI_BLOCK_IO_MEDIA *Media;
599 UINTN BlockSize;
600 UINTN BlockNum;
601 UINTN IoAlign;
602 UINTN Remaining;
603 UINT32 MaxBlock;
604 BOOLEAN LastRw;
605
606 Status = EFI_SUCCESS;
607 Media = &Device->BlockMedia;
608 LastRw = FALSE;
609
610 if (MediaId != Media->MediaId) {
611 return EFI_MEDIA_CHANGED;
612 }
613
614 if (!IsRead && Media->ReadOnly) {
615 return EFI_WRITE_PROTECTED;
616 }
617
618 //
619 // Check parameters.
620 //
621 if (Buffer == NULL) {
622 return EFI_INVALID_PARAMETER;
623 }
624
625 if (BufferSize == 0) {
626 if ((Token != NULL) && (Token->Event != NULL)) {
627 Token->TransactionStatus = EFI_SUCCESS;
628 gBS->SignalEvent (Token->Event);
629 }
630
631 return EFI_SUCCESS;
632 }
633
634 BlockSize = Media->BlockSize;
635 if ((BufferSize % BlockSize) != 0) {
636 return EFI_BAD_BUFFER_SIZE;
637 }
638
639 BlockNum = BufferSize / BlockSize;
640 if ((Lba + BlockNum - 1) > Media->LastBlock) {
641 return EFI_INVALID_PARAMETER;
642 }
643
644 IoAlign = Media->IoAlign;
645 if ((IoAlign > 0) && (((UINTN)Buffer & (IoAlign - 1)) != 0)) {
646 return EFI_INVALID_PARAMETER;
647 }
648
649 if ((Token != NULL) && (Token->Event != NULL)) {
650 Token->TransactionStatus = EFI_SUCCESS;
651 }
652
653 //
654 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
655 //
656 Remaining = BlockNum;
657 MaxBlock = 0xFFFF;
658
659 while (Remaining > 0) {
660 if (Remaining <= MaxBlock) {
661 BlockNum = Remaining;
662 LastRw = TRUE;
663 } else {
664 BlockNum = MaxBlock;
665 }
666
667 BufferSize = BlockNum * BlockSize;
668 if (BlockNum == 1) {
669 Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
670 } else {
671 Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
672 }
673
674 if (EFI_ERROR (Status)) {
675 return Status;
676 }
677
678 DEBUG ((
679 DEBUG_BLKIO,
680 "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
681 IsRead ? "Read" : "Write",
682 Lba,
683 BlockNum,
684 (Token != NULL) ? Token->Event : NULL,
685 Status
686 ));
687 Lba += BlockNum;
688 Buffer = (UINT8 *)Buffer + BufferSize;
689 Remaining -= BlockNum;
690 }
691
692 return Status;
693 }
694
695 /**
696 Reset the Block Device.
697
698 @param This Indicates a pointer to the calling context.
699 @param ExtendedVerification Driver may perform diagnostics on reset.
700
701 @retval EFI_SUCCESS The device was reset.
702 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
703 not be reset.
704
705 **/
706 EFI_STATUS
707 EFIAPI
708 SdReset (
709 IN EFI_BLOCK_IO_PROTOCOL *This,
710 IN BOOLEAN ExtendedVerification
711 )
712 {
713 EFI_STATUS Status;
714 SD_DEVICE *Device;
715 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
716
717 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
718
719 PassThru = Device->Private->PassThru;
720 Status = PassThru->ResetDevice (PassThru, Device->Slot);
721 if (EFI_ERROR (Status)) {
722 Status = EFI_DEVICE_ERROR;
723 }
724
725 return Status;
726 }
727
728 /**
729 Read BufferSize bytes from Lba into Buffer.
730
731 @param This Indicates a pointer to the calling context.
732 @param MediaId Id of the media, changes every time the media is replaced.
733 @param Lba The starting Logical Block Address to read from
734 @param BufferSize Size of Buffer, must be a multiple of device block size.
735 @param Buffer A pointer to the destination buffer for the data. The caller is
736 responsible for either having implicit or explicit ownership of the buffer.
737
738 @retval EFI_SUCCESS The data was read correctly from the device.
739 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
740 @retval EFI_NO_MEDIA There is no media in the device.
741 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
742 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
743 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
744 or the buffer is not on proper alignment.
745
746 **/
747 EFI_STATUS
748 EFIAPI
749 SdReadBlocks (
750 IN EFI_BLOCK_IO_PROTOCOL *This,
751 IN UINT32 MediaId,
752 IN EFI_LBA Lba,
753 IN UINTN BufferSize,
754 OUT VOID *Buffer
755 )
756 {
757 EFI_STATUS Status;
758 SD_DEVICE *Device;
759
760 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
761
762 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
763 return Status;
764 }
765
766 /**
767 Write BufferSize bytes from Lba into Buffer.
768
769 @param This Indicates a pointer to the calling context.
770 @param MediaId The media ID that the write request is for.
771 @param Lba The starting logical block address to be written. The caller is
772 responsible for writing to only legitimate locations.
773 @param BufferSize Size of Buffer, must be a multiple of device block size.
774 @param Buffer A pointer to the source buffer for the data.
775
776 @retval EFI_SUCCESS The data was written correctly to the device.
777 @retval EFI_WRITE_PROTECTED The device can not be written to.
778 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
779 @retval EFI_NO_MEDIA There is no media in the device.
780 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
781 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
782 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
783 or the buffer is not on proper alignment.
784
785 **/
786 EFI_STATUS
787 EFIAPI
788 SdWriteBlocks (
789 IN EFI_BLOCK_IO_PROTOCOL *This,
790 IN UINT32 MediaId,
791 IN EFI_LBA Lba,
792 IN UINTN BufferSize,
793 IN VOID *Buffer
794 )
795 {
796 EFI_STATUS Status;
797 SD_DEVICE *Device;
798
799 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
800
801 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
802 return Status;
803 }
804
805 /**
806 Flush the Block Device.
807
808 @param This Indicates a pointer to the calling context.
809
810 @retval EFI_SUCCESS All outstanding data was written to the device
811 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
812 @retval EFI_NO_MEDIA There is no media in the device.
813
814 **/
815 EFI_STATUS
816 EFIAPI
817 SdFlushBlocks (
818 IN EFI_BLOCK_IO_PROTOCOL *This
819 )
820 {
821 //
822 // return directly
823 //
824 return EFI_SUCCESS;
825 }
826
827 /**
828 Reset the Block Device.
829
830 @param[in] This Indicates a pointer to the calling context.
831 @param[in] ExtendedVerification Driver may perform diagnostics on reset.
832
833 @retval EFI_SUCCESS The device was reset.
834 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
835 not be reset.
836
837 **/
838 EFI_STATUS
839 EFIAPI
840 SdResetEx (
841 IN EFI_BLOCK_IO2_PROTOCOL *This,
842 IN BOOLEAN ExtendedVerification
843 )
844 {
845 SD_DEVICE *Device;
846 LIST_ENTRY *Link;
847 LIST_ENTRY *NextLink;
848 SD_REQUEST *Request;
849 EFI_TPL OldTpl;
850
851 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
852
853 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
854 for (Link = GetFirstNode (&Device->Queue);
855 !IsNull (&Device->Queue, Link);
856 Link = NextLink)
857 {
858 NextLink = GetNextNode (&Device->Queue, Link);
859 RemoveEntryList (Link);
860
861 Request = SD_REQUEST_FROM_LINK (Link);
862
863 gBS->CloseEvent (Request->Event);
864 Request->Token->TransactionStatus = EFI_ABORTED;
865
866 if (Request->IsEnd) {
867 gBS->SignalEvent (Request->Token->Event);
868 }
869
870 FreePool (Request);
871 }
872
873 gBS->RestoreTPL (OldTpl);
874
875 return EFI_SUCCESS;
876 }
877
878 /**
879 Read BufferSize bytes from Lba into Buffer.
880
881 @param[in] This Indicates a pointer to the calling context.
882 @param[in] MediaId Id of the media, changes every time the media is replaced.
883 @param[in] Lba The starting Logical Block Address to read from.
884 @param[in, out] Token A pointer to the token associated with the transaction.
885 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
886 @param[out] Buffer A pointer to the destination buffer for the data. The caller is
887 responsible for either having implicit or explicit ownership of the buffer.
888
889 @retval EFI_SUCCESS The read request was queued if Event is not NULL.
890 The data was read correctly from the device if
891 the Event is NULL.
892 @retval EFI_DEVICE_ERROR The device reported an error while performing
893 the read.
894 @retval EFI_NO_MEDIA There is no media in the device.
895 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
896 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
897 intrinsic block size of the device.
898 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
899 or the buffer is not on proper alignment.
900 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
901 of resources.
902
903 **/
904 EFI_STATUS
905 EFIAPI
906 SdReadBlocksEx (
907 IN EFI_BLOCK_IO2_PROTOCOL *This,
908 IN UINT32 MediaId,
909 IN EFI_LBA Lba,
910 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
911 IN UINTN BufferSize,
912 OUT VOID *Buffer
913 )
914 {
915 EFI_STATUS Status;
916 SD_DEVICE *Device;
917
918 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
919
920 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
921 return Status;
922 }
923
924 /**
925 Write BufferSize bytes from Lba into Buffer.
926
927 @param[in] This Indicates a pointer to the calling context.
928 @param[in] MediaId The media ID that the write request is for.
929 @param[in] Lba The starting logical block address to be written. The
930 caller is responsible for writing to only legitimate
931 locations.
932 @param[in, out] Token A pointer to the token associated with the transaction.
933 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
934 @param[in] Buffer A pointer to the source buffer for the data.
935
936 @retval EFI_SUCCESS The data was written correctly to the device.
937 @retval EFI_WRITE_PROTECTED The device can not be written to.
938 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
939 @retval EFI_NO_MEDIA There is no media in the device.
940 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
941 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
942 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
943 or the buffer is not on proper alignment.
944
945 **/
946 EFI_STATUS
947 EFIAPI
948 SdWriteBlocksEx (
949 IN EFI_BLOCK_IO2_PROTOCOL *This,
950 IN UINT32 MediaId,
951 IN EFI_LBA Lba,
952 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
953 IN UINTN BufferSize,
954 IN VOID *Buffer
955 )
956 {
957 EFI_STATUS Status;
958 SD_DEVICE *Device;
959
960 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
961
962 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
963 return Status;
964 }
965
966 /**
967 Flush the Block Device.
968
969 @param[in] This Indicates a pointer to the calling context.
970 @param[in, out] Token A pointer to the token associated with the transaction.
971
972 @retval EFI_SUCCESS All outstanding data was written to the device
973 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
974 @retval EFI_NO_MEDIA There is no media in the device.
975
976 **/
977 EFI_STATUS
978 EFIAPI
979 SdFlushBlocksEx (
980 IN EFI_BLOCK_IO2_PROTOCOL *This,
981 IN OUT EFI_BLOCK_IO2_TOKEN *Token
982 )
983 {
984 //
985 // Signal event and return directly.
986 //
987 if ((Token != NULL) && (Token->Event != NULL)) {
988 Token->TransactionStatus = EFI_SUCCESS;
989 gBS->SignalEvent (Token->Event);
990 }
991
992 return EFI_SUCCESS;
993 }
994
995 /**
996 Set the erase start address through sync or async I/O request.
997
998 @param[in] Device A pointer to the SD_DEVICE instance.
999 @param[in] StartLba The starting logical block address to be erased.
1000 @param[in] Token A pointer to the token associated with the transaction.
1001 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1002 This parameter is only meaningful in async I/O request.
1003
1004 @retval EFI_SUCCESS The request is executed successfully.
1005 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1006 @retval Others The request could not be executed successfully.
1007
1008 **/
1009 EFI_STATUS
1010 SdEraseBlockStart (
1011 IN SD_DEVICE *Device,
1012 IN EFI_LBA StartLba,
1013 IN EFI_BLOCK_IO2_TOKEN *Token,
1014 IN BOOLEAN IsEnd
1015 )
1016 {
1017 EFI_STATUS Status;
1018 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1019 SD_REQUEST *EraseBlockStart;
1020 EFI_TPL OldTpl;
1021
1022 EraseBlockStart = NULL;
1023 PassThru = Device->Private->PassThru;
1024
1025 EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));
1026 if (EraseBlockStart == NULL) {
1027 Status = EFI_OUT_OF_RESOURCES;
1028 goto Error;
1029 }
1030
1031 EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;
1032 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1033 InsertTailList (&Device->Queue, &EraseBlockStart->Link);
1034 gBS->RestoreTPL (OldTpl);
1035 EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;
1036 EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
1037 EraseBlockStart->Packet.Timeout = SD_GENERIC_TIMEOUT;
1038
1039 EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;
1040 EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1041 EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1042
1043 if (Device->SectorAddressing) {
1044 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
1045 } else {
1046 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->BlockMedia.BlockSize);
1047 }
1048
1049 EraseBlockStart->IsEnd = IsEnd;
1050 EraseBlockStart->Token = Token;
1051
1052 if ((Token != NULL) && (Token->Event != NULL)) {
1053 Status = gBS->CreateEvent (
1054 EVT_NOTIFY_SIGNAL,
1055 TPL_NOTIFY,
1056 AsyncIoCallback,
1057 EraseBlockStart,
1058 &EraseBlockStart->Event
1059 );
1060 if (EFI_ERROR (Status)) {
1061 goto Error;
1062 }
1063 } else {
1064 EraseBlockStart->Event = NULL;
1065 }
1066
1067 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
1068
1069 Error:
1070 if ((Token != NULL) && (Token->Event != NULL)) {
1071 //
1072 // For asynchronous operation, only free request and event in error case.
1073 // The request and event will be freed in asynchronous callback for success case.
1074 //
1075 if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
1076 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1077 RemoveEntryList (&EraseBlockStart->Link);
1078 gBS->RestoreTPL (OldTpl);
1079 if (EraseBlockStart->Event != NULL) {
1080 gBS->CloseEvent (EraseBlockStart->Event);
1081 }
1082
1083 FreePool (EraseBlockStart);
1084 }
1085 } else {
1086 //
1087 // For synchronous operation, free request whatever the execution result is.
1088 //
1089 if (EraseBlockStart != NULL) {
1090 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1091 RemoveEntryList (&EraseBlockStart->Link);
1092 gBS->RestoreTPL (OldTpl);
1093 FreePool (EraseBlockStart);
1094 }
1095 }
1096
1097 return Status;
1098 }
1099
1100 /**
1101 Set the erase end address through sync or async I/O request.
1102
1103 @param[in] Device A pointer to the SD_DEVICE instance.
1104 @param[in] EndLba The ending logical block address to be erased.
1105 @param[in] Token A pointer to the token associated with the transaction.
1106 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1107 This parameter is only meaningful in async I/O request.
1108
1109 @retval EFI_SUCCESS The request is executed successfully.
1110 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1111 @retval Others The request could not be executed successfully.
1112
1113 **/
1114 EFI_STATUS
1115 SdEraseBlockEnd (
1116 IN SD_DEVICE *Device,
1117 IN EFI_LBA EndLba,
1118 IN EFI_BLOCK_IO2_TOKEN *Token,
1119 IN BOOLEAN IsEnd
1120 )
1121 {
1122 EFI_STATUS Status;
1123 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1124 SD_REQUEST *EraseBlockEnd;
1125 EFI_TPL OldTpl;
1126
1127 EraseBlockEnd = NULL;
1128 PassThru = Device->Private->PassThru;
1129
1130 EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));
1131 if (EraseBlockEnd == NULL) {
1132 Status = EFI_OUT_OF_RESOURCES;
1133 goto Error;
1134 }
1135
1136 EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;
1137 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1138 InsertTailList (&Device->Queue, &EraseBlockEnd->Link);
1139 gBS->RestoreTPL (OldTpl);
1140 EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;
1141 EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
1142 EraseBlockEnd->Packet.Timeout = SD_GENERIC_TIMEOUT;
1143
1144 EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;
1145 EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1146 EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1147
1148 if (Device->SectorAddressing) {
1149 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
1150 } else {
1151 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->BlockMedia.BlockSize);
1152 }
1153
1154 EraseBlockEnd->IsEnd = IsEnd;
1155 EraseBlockEnd->Token = Token;
1156
1157 if ((Token != NULL) && (Token->Event != NULL)) {
1158 Status = gBS->CreateEvent (
1159 EVT_NOTIFY_SIGNAL,
1160 TPL_NOTIFY,
1161 AsyncIoCallback,
1162 EraseBlockEnd,
1163 &EraseBlockEnd->Event
1164 );
1165 if (EFI_ERROR (Status)) {
1166 goto Error;
1167 }
1168 } else {
1169 EraseBlockEnd->Event = NULL;
1170 }
1171
1172 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
1173
1174 Error:
1175 if ((Token != NULL) && (Token->Event != NULL)) {
1176 //
1177 // For asynchronous operation, only free request and event in error case.
1178 // The request and event will be freed in asynchronous callback for success case.
1179 //
1180 if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
1181 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1182 RemoveEntryList (&EraseBlockEnd->Link);
1183 gBS->RestoreTPL (OldTpl);
1184 if (EraseBlockEnd->Event != NULL) {
1185 gBS->CloseEvent (EraseBlockEnd->Event);
1186 }
1187
1188 FreePool (EraseBlockEnd);
1189 }
1190 } else {
1191 //
1192 // For synchronous operation, free request whatever the execution result is.
1193 //
1194 if (EraseBlockEnd != NULL) {
1195 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1196 RemoveEntryList (&EraseBlockEnd->Link);
1197 gBS->RestoreTPL (OldTpl);
1198 FreePool (EraseBlockEnd);
1199 }
1200 }
1201
1202 return Status;
1203 }
1204
1205 /**
1206 Erase specified blocks through sync or async I/O request.
1207
1208 @param[in] Device A pointer to the SD_DEVICE instance.
1209 @param[in] Token A pointer to the token associated with the transaction.
1210 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1211 This parameter is only meaningful in async I/O request.
1212
1213 @retval EFI_SUCCESS The request is executed successfully.
1214 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1215 @retval Others The request could not be executed successfully.
1216
1217 **/
1218 EFI_STATUS
1219 SdEraseBlock (
1220 IN SD_DEVICE *Device,
1221 IN EFI_BLOCK_IO2_TOKEN *Token,
1222 IN BOOLEAN IsEnd
1223 )
1224 {
1225 EFI_STATUS Status;
1226 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1227 SD_REQUEST *EraseBlock;
1228 EFI_TPL OldTpl;
1229
1230 EraseBlock = NULL;
1231 PassThru = Device->Private->PassThru;
1232
1233 EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));
1234 if (EraseBlock == NULL) {
1235 Status = EFI_OUT_OF_RESOURCES;
1236 goto Error;
1237 }
1238
1239 EraseBlock->Signature = SD_REQUEST_SIGNATURE;
1240 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1241 InsertTailList (&Device->Queue, &EraseBlock->Link);
1242 gBS->RestoreTPL (OldTpl);
1243 EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;
1244 EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
1245 EraseBlock->Packet.Timeout = SD_GENERIC_TIMEOUT;
1246
1247 EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;
1248 EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1249 EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
1250
1251 EraseBlock->IsEnd = IsEnd;
1252 EraseBlock->Token = Token;
1253
1254 if ((Token != NULL) && (Token->Event != NULL)) {
1255 Status = gBS->CreateEvent (
1256 EVT_NOTIFY_SIGNAL,
1257 TPL_NOTIFY,
1258 AsyncIoCallback,
1259 EraseBlock,
1260 &EraseBlock->Event
1261 );
1262 if (EFI_ERROR (Status)) {
1263 goto Error;
1264 }
1265 } else {
1266 EraseBlock->Event = NULL;
1267 }
1268
1269 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
1270
1271 Error:
1272 if ((Token != NULL) && (Token->Event != NULL)) {
1273 //
1274 // For asynchronous operation, only free request and event in error case.
1275 // The request and event will be freed in asynchronous callback for success case.
1276 //
1277 if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
1278 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1279 RemoveEntryList (&EraseBlock->Link);
1280 gBS->RestoreTPL (OldTpl);
1281 if (EraseBlock->Event != NULL) {
1282 gBS->CloseEvent (EraseBlock->Event);
1283 }
1284
1285 FreePool (EraseBlock);
1286 }
1287 } else {
1288 //
1289 // For synchronous operation, free request whatever the execution result is.
1290 //
1291 if (EraseBlock != NULL) {
1292 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1293 RemoveEntryList (&EraseBlock->Link);
1294 gBS->RestoreTPL (OldTpl);
1295 FreePool (EraseBlock);
1296 }
1297 }
1298
1299 return Status;
1300 }
1301
1302 /**
1303 Erase a specified number of device blocks.
1304
1305 @param[in] This Indicates a pointer to the calling context.
1306 @param[in] MediaId The media ID that the erase request is for.
1307 @param[in] Lba The starting logical block address to be
1308 erased. The caller is responsible for erasing
1309 only legitimate locations.
1310 @param[in, out] Token A pointer to the token associated with the
1311 transaction.
1312 @param[in] Size The size in bytes to be erased. This must be
1313 a multiple of the physical block size of the
1314 device.
1315
1316 @retval EFI_SUCCESS The erase request was queued if Event is not
1317 NULL. The data was erased correctly to the
1318 device if the Event is NULL.to the device.
1319 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1320 protection.
1321 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1322 to perform the erase operation.
1323 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1324 valid.
1325 @retval EFI_NO_MEDIA There is no media in the device.
1326 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1327
1328 **/
1329 EFI_STATUS
1330 EFIAPI
1331 SdEraseBlocks (
1332 IN EFI_ERASE_BLOCK_PROTOCOL *This,
1333 IN UINT32 MediaId,
1334 IN EFI_LBA Lba,
1335 IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
1336 IN UINTN Size
1337 )
1338 {
1339 EFI_STATUS Status;
1340 EFI_BLOCK_IO_MEDIA *Media;
1341 UINTN BlockSize;
1342 UINTN BlockNum;
1343 EFI_LBA LastLba;
1344 SD_DEVICE *Device;
1345
1346 Status = EFI_SUCCESS;
1347 Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);
1348 Media = &Device->BlockMedia;
1349
1350 if (MediaId != Media->MediaId) {
1351 return EFI_MEDIA_CHANGED;
1352 }
1353
1354 if (Media->ReadOnly) {
1355 return EFI_WRITE_PROTECTED;
1356 }
1357
1358 //
1359 // Check parameters.
1360 //
1361 BlockSize = Media->BlockSize;
1362 if ((Size % BlockSize) != 0) {
1363 return EFI_INVALID_PARAMETER;
1364 }
1365
1366 BlockNum = Size / BlockSize;
1367 if ((Lba + BlockNum - 1) > Media->LastBlock) {
1368 return EFI_INVALID_PARAMETER;
1369 }
1370
1371 if ((Token != NULL) && (Token->Event != NULL)) {
1372 Token->TransactionStatus = EFI_SUCCESS;
1373 }
1374
1375 LastLba = Lba + BlockNum - 1;
1376
1377 Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN *)Token, FALSE);
1378 if (EFI_ERROR (Status)) {
1379 return Status;
1380 }
1381
1382 Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN *)Token, FALSE);
1383 if (EFI_ERROR (Status)) {
1384 return Status;
1385 }
1386
1387 Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN *)Token, TRUE);
1388 if (EFI_ERROR (Status)) {
1389 return Status;
1390 }
1391
1392 DEBUG ((
1393 DEBUG_INFO,
1394 "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
1395 Lba,
1396 BlockNum,
1397 (Token != NULL) ? Token->Event : NULL,
1398 Status
1399 ));
1400
1401 return Status;
1402 }