]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
Vlv2TbltDevicePkg: fix ASSERT_EFI_ERROR() typos
[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 - 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
9
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.
12
13 **/
14
15 #include "SdDxe.h"
16
17 /**
18 Nonblocking I/O callback funtion when the event is signaled.
19
20 @param[in] Event The Event this notify function registered to.
21 @param[in] Context Pointer to the context data registered to the
22 Event.
23
24 **/
25 VOID
26 EFIAPI
27 AsyncIoCallback (
28 IN EFI_EVENT Event,
29 IN VOID *Context
30 )
31 {
32 SD_REQUEST *Request;
33
34 gBS->CloseEvent (Event);
35
36 Request = (SD_REQUEST *) Context;
37
38 DEBUG_CODE_BEGIN ();
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));
42 DEBUG_CODE_END ();
43
44 if (EFI_ERROR (Request->Packet.TransactionStatus)) {
45 Request->Token->TransactionStatus = Request->Packet.TransactionStatus;
46 }
47
48 RemoveEntryList (&Request->Link);
49
50 if (Request->IsEnd) {
51 gBS->SignalEvent (Request->Token->Event);
52 }
53
54 FreePool (Request);
55 }
56
57 /**
58 Send command SET_RELATIVE_ADDRESS to the device to set the device address.
59
60 @param[in] Device A pointer to the SD_DEVICE instance.
61 @param[out] Rca The relative device address to assign.
62
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.
66
67 **/
68 EFI_STATUS
69 SdSetRca (
70 IN SD_DEVICE *Device,
71 OUT UINT16 *Rca
72 )
73 {
74 EFI_STATUS Status;
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;
79
80 PassThru = Device->Private->PassThru;
81
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;
88
89 SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
90 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;
91 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
92
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);
97 }
98
99 return Status;
100 }
101
102 /**
103 Send command SELECT to the device to select/deselect the device.
104
105 @param[in] Device A pointer to the SD_DEVICE instance.
106 @param[in] Rca The relative device address to use.
107
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.
111
112 **/
113 EFI_STATUS
114 SdSelect (
115 IN SD_DEVICE *Device,
116 IN UINT16 Rca
117 )
118 {
119 EFI_STATUS Status;
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;
124
125 PassThru = Device->Private->PassThru;
126
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;
133
134 SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
135 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
136 if (Rca != 0) {
137 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
138 }
139 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
140
141 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
142
143 return Status;
144 }
145
146 /**
147 Send command SEND_STATUS to the device to get device status.
148
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.
152
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.
156
157 **/
158 EFI_STATUS
159 SdSendStatus (
160 IN SD_DEVICE *Device,
161 IN UINT16 Rca,
162 OUT UINT32 *DevStatus
163 )
164 {
165 EFI_STATUS Status;
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;
170
171 PassThru = Device->Private->PassThru;
172
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;
179
180 SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
181 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
182 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
183 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
184
185 Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);
186 if (!EFI_ERROR (Status)) {
187 CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));
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_CALLBACK);
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_CALLBACK,
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 RemoveEntryList (&RwSingleBlkReq->Link);
407 if (RwSingleBlkReq->Event != NULL) {
408 gBS->CloseEvent (RwSingleBlkReq->Event);
409 }
410 FreePool (RwSingleBlkReq);
411 }
412 } else {
413 //
414 // For synchronous operation, free request whatever the execution result is.
415 //
416 if (RwSingleBlkReq != NULL) {
417 RemoveEntryList (&RwSingleBlkReq->Link);
418 FreePool (RwSingleBlkReq);
419 }
420 }
421
422 return Status;
423 }
424
425 /**
426 Read/write multiple blocks through sync or async I/O request.
427
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.
438
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.
442
443 **/
444 EFI_STATUS
445 SdRwMultiBlocks (
446 IN SD_DEVICE *Device,
447 IN EFI_LBA Lba,
448 IN VOID *Buffer,
449 IN UINTN BufferSize,
450 IN BOOLEAN IsRead,
451 IN EFI_BLOCK_IO2_TOKEN *Token,
452 IN BOOLEAN IsEnd
453 )
454 {
455 EFI_STATUS Status;
456 SD_REQUEST *RwMultiBlkReq;
457 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
458 EFI_TPL OldTpl;
459
460 RwMultiBlkReq = NULL;
461
462 PassThru = Device->Private->PassThru;
463
464 RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
465 if (RwMultiBlkReq == NULL) {
466 Status = EFI_OUT_OF_RESOURCES;
467 goto Error;
468 }
469
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;
476 //
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
480 // above class 2.
481 // Refer to SD Physical Layer Simplified spec section 3.4 for details.
482 //
483 RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
484
485 if (IsRead) {
486 RwMultiBlkReq->Packet.InDataBuffer = Buffer;
487 RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
488
489 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;
490 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
491 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
492 } else {
493 RwMultiBlkReq->Packet.OutDataBuffer = Buffer;
494 RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
495
496 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;
497 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
498 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
499 }
500
501 if (Device->SectorAddressing) {
502 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
503 } else {
504 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
505 }
506
507 RwMultiBlkReq->IsEnd = IsEnd;
508 RwMultiBlkReq->Token = Token;
509
510 if ((Token != NULL) && (Token->Event != NULL)) {
511 Status = gBS->CreateEvent (
512 EVT_NOTIFY_SIGNAL,
513 TPL_CALLBACK,
514 AsyncIoCallback,
515 RwMultiBlkReq,
516 &RwMultiBlkReq->Event
517 );
518 if (EFI_ERROR (Status)) {
519 goto Error;
520 }
521 } else {
522 RwMultiBlkReq->Event = NULL;
523 }
524
525 Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
526
527 Error:
528 if ((Token != NULL) && (Token->Event != NULL)) {
529 //
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.
532 //
533 if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
534 RemoveEntryList (&RwMultiBlkReq->Link);
535 if (RwMultiBlkReq->Event != NULL) {
536 gBS->CloseEvent (RwMultiBlkReq->Event);
537 }
538 FreePool (RwMultiBlkReq);
539 }
540 } else {
541 //
542 // For synchronous operation, free request whatever the execution result is.
543 //
544 if (RwMultiBlkReq != NULL) {
545 RemoveEntryList (&RwMultiBlkReq->Link);
546 FreePool (RwMultiBlkReq);
547 }
548 }
549
550 return Status;
551 }
552
553 /**
554 This function transfers data from/to the sd memory card device.
555
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.
565
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.
574
575 **/
576 EFI_STATUS
577 SdReadWrite (
578 IN SD_DEVICE *Device,
579 IN UINT32 MediaId,
580 IN EFI_LBA Lba,
581 IN OUT VOID *Buffer,
582 IN UINTN BufferSize,
583 IN BOOLEAN IsRead,
584 IN OUT EFI_BLOCK_IO2_TOKEN *Token
585 )
586 {
587 EFI_STATUS Status;
588 EFI_BLOCK_IO_MEDIA *Media;
589 UINTN BlockSize;
590 UINTN BlockNum;
591 UINTN IoAlign;
592 UINTN Remaining;
593 UINT32 MaxBlock;
594 BOOLEAN LastRw;
595
596 Status = EFI_SUCCESS;
597 Media = &Device->BlockMedia;
598 LastRw = FALSE;
599
600 if (MediaId != Media->MediaId) {
601 return EFI_MEDIA_CHANGED;
602 }
603
604 if (!IsRead && Media->ReadOnly) {
605 return EFI_WRITE_PROTECTED;
606 }
607
608 //
609 // Check parameters.
610 //
611 if (Buffer == NULL) {
612 return EFI_INVALID_PARAMETER;
613 }
614
615 if (BufferSize == 0) {
616 if ((Token != NULL) && (Token->Event != NULL)) {
617 Token->TransactionStatus = EFI_SUCCESS;
618 gBS->SignalEvent (Token->Event);
619 }
620 return EFI_SUCCESS;
621 }
622
623 BlockSize = Media->BlockSize;
624 if ((BufferSize % BlockSize) != 0) {
625 return EFI_BAD_BUFFER_SIZE;
626 }
627
628 BlockNum = BufferSize / BlockSize;
629 if ((Lba + BlockNum - 1) > Media->LastBlock) {
630 return EFI_INVALID_PARAMETER;
631 }
632
633 IoAlign = Media->IoAlign;
634 if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
635 return EFI_INVALID_PARAMETER;
636 }
637
638 if ((Token != NULL) && (Token->Event != NULL)) {
639 Token->TransactionStatus = EFI_SUCCESS;
640 }
641
642 //
643 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
644 //
645 Remaining = BlockNum;
646 MaxBlock = 0xFFFF;
647
648 while (Remaining > 0) {
649 if (Remaining <= MaxBlock) {
650 BlockNum = Remaining;
651 LastRw = TRUE;
652 } else {
653 BlockNum = MaxBlock;
654 }
655
656 BufferSize = BlockNum * BlockSize;
657 if (BlockNum == 1) {
658 Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
659 } else {
660 Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
661 }
662 if (EFI_ERROR (Status)) {
663 return Status;
664 }
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));
666
667 Lba += BlockNum;
668 Buffer = (UINT8*)Buffer + BufferSize;
669 Remaining -= BlockNum;
670 }
671
672 return Status;
673 }
674
675 /**
676 Reset the Block Device.
677
678 @param This Indicates a pointer to the calling context.
679 @param ExtendedVerification Driver may perform diagnostics on reset.
680
681 @retval EFI_SUCCESS The device was reset.
682 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
683 not be reset.
684
685 **/
686 EFI_STATUS
687 EFIAPI
688 SdReset (
689 IN EFI_BLOCK_IO_PROTOCOL *This,
690 IN BOOLEAN ExtendedVerification
691 )
692 {
693 EFI_STATUS Status;
694 SD_DEVICE *Device;
695 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
696
697 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
698
699 PassThru = Device->Private->PassThru;
700 Status = PassThru->ResetDevice (PassThru, Device->Slot);
701 if (EFI_ERROR (Status)) {
702 Status = EFI_DEVICE_ERROR;
703 }
704
705 return Status;
706 }
707
708 /**
709 Read BufferSize bytes from Lba into Buffer.
710
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.
717
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.
725
726 **/
727 EFI_STATUS
728 EFIAPI
729 SdReadBlocks (
730 IN EFI_BLOCK_IO_PROTOCOL *This,
731 IN UINT32 MediaId,
732 IN EFI_LBA Lba,
733 IN UINTN BufferSize,
734 OUT VOID *Buffer
735 )
736 {
737 EFI_STATUS Status;
738 SD_DEVICE *Device;
739
740 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
741
742 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
743 return Status;
744 }
745
746 /**
747 Write BufferSize bytes from Lba into Buffer.
748
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.
755
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.
764
765 **/
766 EFI_STATUS
767 EFIAPI
768 SdWriteBlocks (
769 IN EFI_BLOCK_IO_PROTOCOL *This,
770 IN UINT32 MediaId,
771 IN EFI_LBA Lba,
772 IN UINTN BufferSize,
773 IN VOID *Buffer
774 )
775 {
776 EFI_STATUS Status;
777 SD_DEVICE *Device;
778
779 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
780
781 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
782 return Status;
783 }
784
785 /**
786 Flush the Block Device.
787
788 @param This Indicates a pointer to the calling context.
789
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.
793
794 **/
795 EFI_STATUS
796 EFIAPI
797 SdFlushBlocks (
798 IN EFI_BLOCK_IO_PROTOCOL *This
799 )
800 {
801 //
802 // return directly
803 //
804 return EFI_SUCCESS;
805 }
806
807 /**
808 Reset the Block Device.
809
810 @param[in] This Indicates a pointer to the calling context.
811 @param[in] ExtendedVerification Driver may perform diagnostics on reset.
812
813 @retval EFI_SUCCESS The device was reset.
814 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
815 not be reset.
816
817 **/
818 EFI_STATUS
819 EFIAPI
820 SdResetEx (
821 IN EFI_BLOCK_IO2_PROTOCOL *This,
822 IN BOOLEAN ExtendedVerification
823 )
824 {
825 SD_DEVICE *Device;
826 LIST_ENTRY *Link;
827 LIST_ENTRY *NextLink;
828 SD_REQUEST *Request;
829 EFI_TPL OldTpl;
830
831 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
832
833 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
834 for (Link = GetFirstNode (&Device->Queue);
835 !IsNull (&Device->Queue, Link);
836 Link = NextLink) {
837 NextLink = GetNextNode (&Device->Queue, Link);
838 RemoveEntryList (Link);
839
840 Request = SD_REQUEST_FROM_LINK (Link);
841
842 gBS->CloseEvent (Request->Event);
843 Request->Token->TransactionStatus = EFI_ABORTED;
844
845 if (Request->IsEnd) {
846 gBS->SignalEvent (Request->Token->Event);
847 }
848
849 FreePool (Request);
850 }
851 gBS->RestoreTPL (OldTpl);
852
853 return EFI_SUCCESS;
854 }
855
856 /**
857 Read BufferSize bytes from Lba into Buffer.
858
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.
866
867 @retval EFI_SUCCESS The read request was queued if Event is not NULL.
868 The data was read correctly from the device if
869 the Event is NULL.
870 @retval EFI_DEVICE_ERROR The device reported an error while performing
871 the read.
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
879 of resources.
880
881 **/
882 EFI_STATUS
883 EFIAPI
884 SdReadBlocksEx (
885 IN EFI_BLOCK_IO2_PROTOCOL *This,
886 IN UINT32 MediaId,
887 IN EFI_LBA Lba,
888 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
889 IN UINTN BufferSize,
890 OUT VOID *Buffer
891 )
892 {
893 EFI_STATUS Status;
894 SD_DEVICE *Device;
895
896 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
897
898 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
899 return Status;
900 }
901
902 /**
903 Write BufferSize bytes from Lba into Buffer.
904
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
909 locations.
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.
913
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.
922
923 **/
924 EFI_STATUS
925 EFIAPI
926 SdWriteBlocksEx (
927 IN EFI_BLOCK_IO2_PROTOCOL *This,
928 IN UINT32 MediaId,
929 IN EFI_LBA Lba,
930 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
931 IN UINTN BufferSize,
932 IN VOID *Buffer
933 )
934 {
935 EFI_STATUS Status;
936 SD_DEVICE *Device;
937
938 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
939
940 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
941 return Status;
942 }
943
944 /**
945 Flush the Block Device.
946
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.
949
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.
953
954 **/
955 EFI_STATUS
956 EFIAPI
957 SdFlushBlocksEx (
958 IN EFI_BLOCK_IO2_PROTOCOL *This,
959 IN OUT EFI_BLOCK_IO2_TOKEN *Token
960 )
961 {
962 //
963 // Signal event and return directly.
964 //
965 if (Token != NULL && Token->Event != NULL) {
966 Token->TransactionStatus = EFI_SUCCESS;
967 gBS->SignalEvent (Token->Event);
968 }
969
970 return EFI_SUCCESS;
971 }
972
973 /**
974 Set the erase start address through sync or async I/O request.
975
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.
981
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.
985
986 **/
987 EFI_STATUS
988 SdEraseBlockStart (
989 IN SD_DEVICE *Device,
990 IN EFI_LBA StartLba,
991 IN EFI_BLOCK_IO2_TOKEN *Token,
992 IN BOOLEAN IsEnd
993 )
994 {
995 EFI_STATUS Status;
996 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
997 SD_REQUEST *EraseBlockStart;
998 EFI_TPL OldTpl;
999
1000 EraseBlockStart = NULL;
1001 PassThru = Device->Private->PassThru;
1002
1003 EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));
1004 if (EraseBlockStart == NULL) {
1005 Status = EFI_OUT_OF_RESOURCES;
1006 goto Error;
1007 }
1008
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;
1016
1017 EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;
1018 EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1019 EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1020
1021 if (Device->SectorAddressing) {
1022 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
1023 } else {
1024 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->BlockMedia.BlockSize);
1025 }
1026
1027 EraseBlockStart->IsEnd = IsEnd;
1028 EraseBlockStart->Token = Token;
1029
1030 if ((Token != NULL) && (Token->Event != NULL)) {
1031 Status = gBS->CreateEvent (
1032 EVT_NOTIFY_SIGNAL,
1033 TPL_CALLBACK,
1034 AsyncIoCallback,
1035 EraseBlockStart,
1036 &EraseBlockStart->Event
1037 );
1038 if (EFI_ERROR (Status)) {
1039 goto Error;
1040 }
1041 } else {
1042 EraseBlockStart->Event = NULL;
1043 }
1044
1045 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
1046
1047 Error:
1048 if ((Token != NULL) && (Token->Event != NULL)) {
1049 //
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.
1052 //
1053 if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
1054 RemoveEntryList (&EraseBlockStart->Link);
1055 if (EraseBlockStart->Event != NULL) {
1056 gBS->CloseEvent (EraseBlockStart->Event);
1057 }
1058 FreePool (EraseBlockStart);
1059 }
1060 } else {
1061 //
1062 // For synchronous operation, free request whatever the execution result is.
1063 //
1064 if (EraseBlockStart != NULL) {
1065 RemoveEntryList (&EraseBlockStart->Link);
1066 FreePool (EraseBlockStart);
1067 }
1068 }
1069
1070 return Status;
1071 }
1072
1073 /**
1074 Set the erase end address through sync or async I/O request.
1075
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.
1081
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.
1085
1086 **/
1087 EFI_STATUS
1088 SdEraseBlockEnd (
1089 IN SD_DEVICE *Device,
1090 IN EFI_LBA EndLba,
1091 IN EFI_BLOCK_IO2_TOKEN *Token,
1092 IN BOOLEAN IsEnd
1093 )
1094 {
1095 EFI_STATUS Status;
1096 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1097 SD_REQUEST *EraseBlockEnd;
1098 EFI_TPL OldTpl;
1099
1100 EraseBlockEnd = NULL;
1101 PassThru = Device->Private->PassThru;
1102
1103 EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));
1104 if (EraseBlockEnd == NULL) {
1105 Status = EFI_OUT_OF_RESOURCES;
1106 goto Error;
1107 }
1108
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;
1116
1117 EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;
1118 EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1119 EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1120
1121 if (Device->SectorAddressing) {
1122 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
1123 } else {
1124 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->BlockMedia.BlockSize);
1125 }
1126
1127 EraseBlockEnd->IsEnd = IsEnd;
1128 EraseBlockEnd->Token = Token;
1129
1130 if ((Token != NULL) && (Token->Event != NULL)) {
1131 Status = gBS->CreateEvent (
1132 EVT_NOTIFY_SIGNAL,
1133 TPL_CALLBACK,
1134 AsyncIoCallback,
1135 EraseBlockEnd,
1136 &EraseBlockEnd->Event
1137 );
1138 if (EFI_ERROR (Status)) {
1139 goto Error;
1140 }
1141 } else {
1142 EraseBlockEnd->Event = NULL;
1143 }
1144
1145 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
1146
1147 Error:
1148 if ((Token != NULL) && (Token->Event != NULL)) {
1149 //
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.
1152 //
1153 if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
1154 RemoveEntryList (&EraseBlockEnd->Link);
1155 if (EraseBlockEnd->Event != NULL) {
1156 gBS->CloseEvent (EraseBlockEnd->Event);
1157 }
1158 FreePool (EraseBlockEnd);
1159 }
1160 } else {
1161 //
1162 // For synchronous operation, free request whatever the execution result is.
1163 //
1164 if (EraseBlockEnd != NULL) {
1165 RemoveEntryList (&EraseBlockEnd->Link);
1166 FreePool (EraseBlockEnd);
1167 }
1168 }
1169
1170 return Status;
1171 }
1172
1173 /**
1174 Erase specified blocks through sync or async I/O request.
1175
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.
1180
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.
1184
1185 **/
1186 EFI_STATUS
1187 SdEraseBlock (
1188 IN SD_DEVICE *Device,
1189 IN EFI_BLOCK_IO2_TOKEN *Token,
1190 IN BOOLEAN IsEnd
1191 )
1192 {
1193 EFI_STATUS Status;
1194 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1195 SD_REQUEST *EraseBlock;
1196 EFI_TPL OldTpl;
1197
1198 EraseBlock = NULL;
1199 PassThru = Device->Private->PassThru;
1200
1201 EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));
1202 if (EraseBlock == NULL) {
1203 Status = EFI_OUT_OF_RESOURCES;
1204 goto Error;
1205 }
1206
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;
1214
1215 EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;
1216 EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1217 EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
1218
1219 EraseBlock->IsEnd = IsEnd;
1220 EraseBlock->Token = Token;
1221
1222 if ((Token != NULL) && (Token->Event != NULL)) {
1223 Status = gBS->CreateEvent (
1224 EVT_NOTIFY_SIGNAL,
1225 TPL_CALLBACK,
1226 AsyncIoCallback,
1227 EraseBlock,
1228 &EraseBlock->Event
1229 );
1230 if (EFI_ERROR (Status)) {
1231 goto Error;
1232 }
1233 } else {
1234 EraseBlock->Event = NULL;
1235 }
1236
1237 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
1238
1239 Error:
1240 if ((Token != NULL) && (Token->Event != NULL)) {
1241 //
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.
1244 //
1245 if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
1246 RemoveEntryList (&EraseBlock->Link);
1247 if (EraseBlock->Event != NULL) {
1248 gBS->CloseEvent (EraseBlock->Event);
1249 }
1250 FreePool (EraseBlock);
1251 }
1252 } else {
1253 //
1254 // For synchronous operation, free request whatever the execution result is.
1255 //
1256 if (EraseBlock != NULL) {
1257 RemoveEntryList (&EraseBlock->Link);
1258 FreePool (EraseBlock);
1259 }
1260 }
1261
1262 return Status;
1263 }
1264
1265 /**
1266 Erase a specified number of device blocks.
1267
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
1274 transaction.
1275 @param[in] Size The size in bytes to be erased. This must be
1276 a multiple of the physical block size of the
1277 device.
1278
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
1283 protection.
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
1287 valid.
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.
1290
1291 **/
1292 EFI_STATUS
1293 EFIAPI
1294 SdEraseBlocks (
1295 IN EFI_ERASE_BLOCK_PROTOCOL *This,
1296 IN UINT32 MediaId,
1297 IN EFI_LBA Lba,
1298 IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
1299 IN UINTN Size
1300 )
1301 {
1302 EFI_STATUS Status;
1303 EFI_BLOCK_IO_MEDIA *Media;
1304 UINTN BlockSize;
1305 UINTN BlockNum;
1306 EFI_LBA LastLba;
1307 SD_DEVICE *Device;
1308
1309 Status = EFI_SUCCESS;
1310 Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);
1311 Media = &Device->BlockMedia;
1312
1313 if (MediaId != Media->MediaId) {
1314 return EFI_MEDIA_CHANGED;
1315 }
1316
1317 if (Media->ReadOnly) {
1318 return EFI_WRITE_PROTECTED;
1319 }
1320
1321 //
1322 // Check parameters.
1323 //
1324 BlockSize = Media->BlockSize;
1325 if ((Size % BlockSize) != 0) {
1326 return EFI_INVALID_PARAMETER;
1327 }
1328
1329 BlockNum = Size / BlockSize;
1330 if ((Lba + BlockNum - 1) > Media->LastBlock) {
1331 return EFI_INVALID_PARAMETER;
1332 }
1333
1334 if ((Token != NULL) && (Token->Event != NULL)) {
1335 Token->TransactionStatus = EFI_SUCCESS;
1336 }
1337
1338 LastLba = Lba + BlockNum - 1;
1339
1340 Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
1341 if (EFI_ERROR (Status)) {
1342 return Status;
1343 }
1344
1345 Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
1346 if (EFI_ERROR (Status)) {
1347 return Status;
1348 }
1349
1350 Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
1351 if (EFI_ERROR (Status)) {
1352 return Status;
1353 }
1354
1355 DEBUG ((EFI_D_ERROR, "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", Lba, BlockNum, Token->Event, Status));
1356
1357 return Status;
1358 }
1359