Merge branch 'master' of https://github.com/tianocore/edk2
[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_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 FreePool (RwSingleBlkReq);
413 }
414 } else {
415 //
416 // For synchronous operation, free request whatever the execution result is.
417 //
418 if (RwSingleBlkReq != NULL) {
419 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
420 RemoveEntryList (&RwSingleBlkReq->Link);
421 gBS->RestoreTPL (OldTpl);
422 FreePool (RwSingleBlkReq);
423 }
424 }
425
426 return Status;
427 }
428
429 /**
430 Read/write multiple blocks through sync or async I/O request.
431
432 @param[in] Device A pointer to the SD_DEVICE instance.
433 @param[in] Lba The starting logical block address to be read/written.
434 The caller is responsible for reading/writing to only
435 legitimate locations.
436 @param[in] Buffer A pointer to the destination/source buffer for the data.
437 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
438 @param[in] IsRead Indicates it is a read or write operation.
439 @param[in] Token A pointer to the token associated with the transaction.
440 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
441 This parameter is only meaningful in async I/O request.
442
443 @retval EFI_SUCCESS The request is executed successfully.
444 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
445 @retval Others The request could not be executed successfully.
446
447 **/
448 EFI_STATUS
449 SdRwMultiBlocks (
450 IN SD_DEVICE *Device,
451 IN EFI_LBA Lba,
452 IN VOID *Buffer,
453 IN UINTN BufferSize,
454 IN BOOLEAN IsRead,
455 IN EFI_BLOCK_IO2_TOKEN *Token,
456 IN BOOLEAN IsEnd
457 )
458 {
459 EFI_STATUS Status;
460 SD_REQUEST *RwMultiBlkReq;
461 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
462 EFI_TPL OldTpl;
463
464 RwMultiBlkReq = NULL;
465
466 PassThru = Device->Private->PassThru;
467
468 RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));
469 if (RwMultiBlkReq == NULL) {
470 Status = EFI_OUT_OF_RESOURCES;
471 goto Error;
472 }
473
474 RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;
475 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
476 InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);
477 gBS->RestoreTPL (OldTpl);
478 RwMultiBlkReq->Packet.SdMmcCmdBlk = &RwMultiBlkReq->SdMmcCmdBlk;
479 RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;
480 //
481 // Calculate timeout value through the below formula.
482 // Timeout = (transfer size) / (2MB/s).
483 // Taking 2MB/s as divisor as it's the lowest transfer speed
484 // above class 2.
485 // Refer to SD Physical Layer Simplified spec section 3.4 for details.
486 //
487 RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;
488
489 if (IsRead) {
490 RwMultiBlkReq->Packet.InDataBuffer = Buffer;
491 RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;
492
493 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;
494 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
495 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
496 } else {
497 RwMultiBlkReq->Packet.OutDataBuffer = Buffer;
498 RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;
499
500 RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;
501 RwMultiBlkReq->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;
502 RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
503 }
504
505 if (Device->SectorAddressing) {
506 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;
507 } else {
508 RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);
509 }
510
511 RwMultiBlkReq->IsEnd = IsEnd;
512 RwMultiBlkReq->Token = Token;
513
514 if ((Token != NULL) && (Token->Event != NULL)) {
515 Status = gBS->CreateEvent (
516 EVT_NOTIFY_SIGNAL,
517 TPL_NOTIFY,
518 AsyncIoCallback,
519 RwMultiBlkReq,
520 &RwMultiBlkReq->Event
521 );
522 if (EFI_ERROR (Status)) {
523 goto Error;
524 }
525 } else {
526 RwMultiBlkReq->Event = NULL;
527 }
528
529 Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);
530
531 Error:
532 if ((Token != NULL) && (Token->Event != NULL)) {
533 //
534 // For asynchronous operation, only free request and event in error case.
535 // The request and event will be freed in asynchronous callback for success case.
536 //
537 if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {
538 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
539 RemoveEntryList (&RwMultiBlkReq->Link);
540 gBS->RestoreTPL (OldTpl);
541 if (RwMultiBlkReq->Event != NULL) {
542 gBS->CloseEvent (RwMultiBlkReq->Event);
543 }
544 FreePool (RwMultiBlkReq);
545 }
546 } else {
547 //
548 // For synchronous operation, free request whatever the execution result is.
549 //
550 if (RwMultiBlkReq != NULL) {
551 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
552 RemoveEntryList (&RwMultiBlkReq->Link);
553 gBS->RestoreTPL (OldTpl);
554 FreePool (RwMultiBlkReq);
555 }
556 }
557
558 return Status;
559 }
560
561 /**
562 This function transfers data from/to the sd memory card device.
563
564 @param[in] Device A pointer to the SD_DEVICE instance.
565 @param[in] MediaId The media ID that the read/write request is for.
566 @param[in] Lba The starting logical block address to be read/written.
567 The caller is responsible for reading/writing to only
568 legitimate locations.
569 @param[in, out] Buffer A pointer to the destination/source buffer for the data.
570 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
571 @param[in] IsRead Indicates it is a read or write operation.
572 @param[in, out] Token A pointer to the token associated with the transaction.
573
574 @retval EFI_SUCCESS The data was read/written correctly to the device.
575 @retval EFI_WRITE_PROTECTED The device can not be read/written to.
576 @retval EFI_DEVICE_ERROR The device reported an error while performing the read/write.
577 @retval EFI_NO_MEDIA There is no media in the device.
578 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
579 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
580 @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,
581 or the buffer is not on proper alignment.
582
583 **/
584 EFI_STATUS
585 SdReadWrite (
586 IN SD_DEVICE *Device,
587 IN UINT32 MediaId,
588 IN EFI_LBA Lba,
589 IN OUT VOID *Buffer,
590 IN UINTN BufferSize,
591 IN BOOLEAN IsRead,
592 IN OUT EFI_BLOCK_IO2_TOKEN *Token
593 )
594 {
595 EFI_STATUS Status;
596 EFI_BLOCK_IO_MEDIA *Media;
597 UINTN BlockSize;
598 UINTN BlockNum;
599 UINTN IoAlign;
600 UINTN Remaining;
601 UINT32 MaxBlock;
602 BOOLEAN LastRw;
603
604 Status = EFI_SUCCESS;
605 Media = &Device->BlockMedia;
606 LastRw = FALSE;
607
608 if (MediaId != Media->MediaId) {
609 return EFI_MEDIA_CHANGED;
610 }
611
612 if (!IsRead && Media->ReadOnly) {
613 return EFI_WRITE_PROTECTED;
614 }
615
616 //
617 // Check parameters.
618 //
619 if (Buffer == NULL) {
620 return EFI_INVALID_PARAMETER;
621 }
622
623 if (BufferSize == 0) {
624 if ((Token != NULL) && (Token->Event != NULL)) {
625 Token->TransactionStatus = EFI_SUCCESS;
626 gBS->SignalEvent (Token->Event);
627 }
628 return EFI_SUCCESS;
629 }
630
631 BlockSize = Media->BlockSize;
632 if ((BufferSize % BlockSize) != 0) {
633 return EFI_BAD_BUFFER_SIZE;
634 }
635
636 BlockNum = BufferSize / BlockSize;
637 if ((Lba + BlockNum - 1) > Media->LastBlock) {
638 return EFI_INVALID_PARAMETER;
639 }
640
641 IoAlign = Media->IoAlign;
642 if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
643 return EFI_INVALID_PARAMETER;
644 }
645
646 if ((Token != NULL) && (Token->Event != NULL)) {
647 Token->TransactionStatus = EFI_SUCCESS;
648 }
649
650 //
651 // Start to execute data transfer. The max block number in single cmd is 65535 blocks.
652 //
653 Remaining = BlockNum;
654 MaxBlock = 0xFFFF;
655
656 while (Remaining > 0) {
657 if (Remaining <= MaxBlock) {
658 BlockNum = Remaining;
659 LastRw = TRUE;
660 } else {
661 BlockNum = MaxBlock;
662 }
663
664 BufferSize = BlockNum * BlockSize;
665 if (BlockNum == 1) {
666 Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
667 } else {
668 Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);
669 }
670 if (EFI_ERROR (Status)) {
671 return Status;
672 }
673 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));
674
675 Lba += BlockNum;
676 Buffer = (UINT8*)Buffer + BufferSize;
677 Remaining -= BlockNum;
678 }
679
680 return Status;
681 }
682
683 /**
684 Reset the Block Device.
685
686 @param This Indicates a pointer to the calling context.
687 @param ExtendedVerification Driver may perform diagnostics on reset.
688
689 @retval EFI_SUCCESS The device was reset.
690 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
691 not be reset.
692
693 **/
694 EFI_STATUS
695 EFIAPI
696 SdReset (
697 IN EFI_BLOCK_IO_PROTOCOL *This,
698 IN BOOLEAN ExtendedVerification
699 )
700 {
701 EFI_STATUS Status;
702 SD_DEVICE *Device;
703 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
704
705 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
706
707 PassThru = Device->Private->PassThru;
708 Status = PassThru->ResetDevice (PassThru, Device->Slot);
709 if (EFI_ERROR (Status)) {
710 Status = EFI_DEVICE_ERROR;
711 }
712
713 return Status;
714 }
715
716 /**
717 Read BufferSize bytes from Lba into Buffer.
718
719 @param This Indicates a pointer to the calling context.
720 @param MediaId Id of the media, changes every time the media is replaced.
721 @param Lba The starting Logical Block Address to read from
722 @param BufferSize Size of Buffer, must be a multiple of device block size.
723 @param Buffer A pointer to the destination buffer for the data. The caller is
724 responsible for either having implicit or explicit ownership of the buffer.
725
726 @retval EFI_SUCCESS The data was read correctly from the device.
727 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
728 @retval EFI_NO_MEDIA There is no media in the device.
729 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
730 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
731 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
732 or the buffer is not on proper alignment.
733
734 **/
735 EFI_STATUS
736 EFIAPI
737 SdReadBlocks (
738 IN EFI_BLOCK_IO_PROTOCOL *This,
739 IN UINT32 MediaId,
740 IN EFI_LBA Lba,
741 IN UINTN BufferSize,
742 OUT VOID *Buffer
743 )
744 {
745 EFI_STATUS Status;
746 SD_DEVICE *Device;
747
748 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
749
750 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
751 return Status;
752 }
753
754 /**
755 Write BufferSize bytes from Lba into Buffer.
756
757 @param This Indicates a pointer to the calling context.
758 @param MediaId The media ID that the write request is for.
759 @param Lba The starting logical block address to be written. The caller is
760 responsible for writing to only legitimate locations.
761 @param BufferSize Size of Buffer, must be a multiple of device block size.
762 @param Buffer A pointer to the source buffer for the data.
763
764 @retval EFI_SUCCESS The data was written correctly to the device.
765 @retval EFI_WRITE_PROTECTED The device can not be written to.
766 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
767 @retval EFI_NO_MEDIA There is no media in the device.
768 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
769 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
770 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
771 or the buffer is not on proper alignment.
772
773 **/
774 EFI_STATUS
775 EFIAPI
776 SdWriteBlocks (
777 IN EFI_BLOCK_IO_PROTOCOL *This,
778 IN UINT32 MediaId,
779 IN EFI_LBA Lba,
780 IN UINTN BufferSize,
781 IN VOID *Buffer
782 )
783 {
784 EFI_STATUS Status;
785 SD_DEVICE *Device;
786
787 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
788
789 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
790 return Status;
791 }
792
793 /**
794 Flush the Block Device.
795
796 @param This Indicates a pointer to the calling context.
797
798 @retval EFI_SUCCESS All outstanding data was written to the device
799 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
800 @retval EFI_NO_MEDIA There is no media in the device.
801
802 **/
803 EFI_STATUS
804 EFIAPI
805 SdFlushBlocks (
806 IN EFI_BLOCK_IO_PROTOCOL *This
807 )
808 {
809 //
810 // return directly
811 //
812 return EFI_SUCCESS;
813 }
814
815 /**
816 Reset the Block Device.
817
818 @param[in] This Indicates a pointer to the calling context.
819 @param[in] ExtendedVerification Driver may perform diagnostics on reset.
820
821 @retval EFI_SUCCESS The device was reset.
822 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
823 not be reset.
824
825 **/
826 EFI_STATUS
827 EFIAPI
828 SdResetEx (
829 IN EFI_BLOCK_IO2_PROTOCOL *This,
830 IN BOOLEAN ExtendedVerification
831 )
832 {
833 SD_DEVICE *Device;
834 LIST_ENTRY *Link;
835 LIST_ENTRY *NextLink;
836 SD_REQUEST *Request;
837 EFI_TPL OldTpl;
838
839 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
840
841 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
842 for (Link = GetFirstNode (&Device->Queue);
843 !IsNull (&Device->Queue, Link);
844 Link = NextLink) {
845 NextLink = GetNextNode (&Device->Queue, Link);
846 RemoveEntryList (Link);
847
848 Request = SD_REQUEST_FROM_LINK (Link);
849
850 gBS->CloseEvent (Request->Event);
851 Request->Token->TransactionStatus = EFI_ABORTED;
852
853 if (Request->IsEnd) {
854 gBS->SignalEvent (Request->Token->Event);
855 }
856
857 FreePool (Request);
858 }
859 gBS->RestoreTPL (OldTpl);
860
861 return EFI_SUCCESS;
862 }
863
864 /**
865 Read BufferSize bytes from Lba into Buffer.
866
867 @param[in] This Indicates a pointer to the calling context.
868 @param[in] MediaId Id of the media, changes every time the media is replaced.
869 @param[in] Lba The starting Logical Block Address to read from.
870 @param[in, out] Token A pointer to the token associated with the transaction.
871 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
872 @param[out] Buffer A pointer to the destination buffer for the data. The caller is
873 responsible for either having implicit or explicit ownership of the buffer.
874
875 @retval EFI_SUCCESS The read request was queued if Event is not NULL.
876 The data was read correctly from the device if
877 the Event is NULL.
878 @retval EFI_DEVICE_ERROR The device reported an error while performing
879 the read.
880 @retval EFI_NO_MEDIA There is no media in the device.
881 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
882 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
883 intrinsic block size of the device.
884 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
885 or the buffer is not on proper alignment.
886 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
887 of resources.
888
889 **/
890 EFI_STATUS
891 EFIAPI
892 SdReadBlocksEx (
893 IN EFI_BLOCK_IO2_PROTOCOL *This,
894 IN UINT32 MediaId,
895 IN EFI_LBA Lba,
896 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
897 IN UINTN BufferSize,
898 OUT VOID *Buffer
899 )
900 {
901 EFI_STATUS Status;
902 SD_DEVICE *Device;
903
904 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
905
906 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
907 return Status;
908 }
909
910 /**
911 Write BufferSize bytes from Lba into Buffer.
912
913 @param[in] This Indicates a pointer to the calling context.
914 @param[in] MediaId The media ID that the write request is for.
915 @param[in] Lba The starting logical block address to be written. The
916 caller is responsible for writing to only legitimate
917 locations.
918 @param[in, out] Token A pointer to the token associated with the transaction.
919 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
920 @param[in] Buffer A pointer to the source buffer for the data.
921
922 @retval EFI_SUCCESS The data was written correctly to the device.
923 @retval EFI_WRITE_PROTECTED The device can not be written to.
924 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
925 @retval EFI_NO_MEDIA There is no media in the device.
926 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
927 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
928 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
929 or the buffer is not on proper alignment.
930
931 **/
932 EFI_STATUS
933 EFIAPI
934 SdWriteBlocksEx (
935 IN EFI_BLOCK_IO2_PROTOCOL *This,
936 IN UINT32 MediaId,
937 IN EFI_LBA Lba,
938 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
939 IN UINTN BufferSize,
940 IN VOID *Buffer
941 )
942 {
943 EFI_STATUS Status;
944 SD_DEVICE *Device;
945
946 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
947
948 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
949 return Status;
950 }
951
952 /**
953 Flush the Block Device.
954
955 @param[in] This Indicates a pointer to the calling context.
956 @param[in, out] Token A pointer to the token associated with the transaction.
957
958 @retval EFI_SUCCESS All outstanding data was written to the device
959 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
960 @retval EFI_NO_MEDIA There is no media in the device.
961
962 **/
963 EFI_STATUS
964 EFIAPI
965 SdFlushBlocksEx (
966 IN EFI_BLOCK_IO2_PROTOCOL *This,
967 IN OUT EFI_BLOCK_IO2_TOKEN *Token
968 )
969 {
970 //
971 // Signal event and return directly.
972 //
973 if (Token != NULL && Token->Event != NULL) {
974 Token->TransactionStatus = EFI_SUCCESS;
975 gBS->SignalEvent (Token->Event);
976 }
977
978 return EFI_SUCCESS;
979 }
980
981 /**
982 Set the erase start address through sync or async I/O request.
983
984 @param[in] Device A pointer to the SD_DEVICE instance.
985 @param[in] StartLba The starting logical block address to be erased.
986 @param[in] Token A pointer to the token associated with the transaction.
987 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
988 This parameter is only meaningful in async I/O request.
989
990 @retval EFI_SUCCESS The request is executed successfully.
991 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
992 @retval Others The request could not be executed successfully.
993
994 **/
995 EFI_STATUS
996 SdEraseBlockStart (
997 IN SD_DEVICE *Device,
998 IN EFI_LBA StartLba,
999 IN EFI_BLOCK_IO2_TOKEN *Token,
1000 IN BOOLEAN IsEnd
1001 )
1002 {
1003 EFI_STATUS Status;
1004 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1005 SD_REQUEST *EraseBlockStart;
1006 EFI_TPL OldTpl;
1007
1008 EraseBlockStart = NULL;
1009 PassThru = Device->Private->PassThru;
1010
1011 EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));
1012 if (EraseBlockStart == NULL) {
1013 Status = EFI_OUT_OF_RESOURCES;
1014 goto Error;
1015 }
1016
1017 EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;
1018 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1019 InsertTailList (&Device->Queue, &EraseBlockStart->Link);
1020 gBS->RestoreTPL (OldTpl);
1021 EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;
1022 EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
1023 EraseBlockStart->Packet.Timeout = SD_GENERIC_TIMEOUT;
1024
1025 EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;
1026 EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1027 EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1028
1029 if (Device->SectorAddressing) {
1030 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
1031 } else {
1032 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->BlockMedia.BlockSize);
1033 }
1034
1035 EraseBlockStart->IsEnd = IsEnd;
1036 EraseBlockStart->Token = Token;
1037
1038 if ((Token != NULL) && (Token->Event != NULL)) {
1039 Status = gBS->CreateEvent (
1040 EVT_NOTIFY_SIGNAL,
1041 TPL_NOTIFY,
1042 AsyncIoCallback,
1043 EraseBlockStart,
1044 &EraseBlockStart->Event
1045 );
1046 if (EFI_ERROR (Status)) {
1047 goto Error;
1048 }
1049 } else {
1050 EraseBlockStart->Event = NULL;
1051 }
1052
1053 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
1054
1055 Error:
1056 if ((Token != NULL) && (Token->Event != NULL)) {
1057 //
1058 // For asynchronous operation, only free request and event in error case.
1059 // The request and event will be freed in asynchronous callback for success case.
1060 //
1061 if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
1062 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1063 RemoveEntryList (&EraseBlockStart->Link);
1064 gBS->RestoreTPL (OldTpl);
1065 if (EraseBlockStart->Event != NULL) {
1066 gBS->CloseEvent (EraseBlockStart->Event);
1067 }
1068 FreePool (EraseBlockStart);
1069 }
1070 } else {
1071 //
1072 // For synchronous operation, free request whatever the execution result is.
1073 //
1074 if (EraseBlockStart != NULL) {
1075 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1076 RemoveEntryList (&EraseBlockStart->Link);
1077 gBS->RestoreTPL (OldTpl);
1078 FreePool (EraseBlockStart);
1079 }
1080 }
1081
1082 return Status;
1083 }
1084
1085 /**
1086 Set the erase end address through sync or async I/O request.
1087
1088 @param[in] Device A pointer to the SD_DEVICE instance.
1089 @param[in] EndLba The ending logical block address to be erased.
1090 @param[in] Token A pointer to the token associated with the transaction.
1091 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1092 This parameter is only meaningful in async I/O request.
1093
1094 @retval EFI_SUCCESS The request is executed successfully.
1095 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1096 @retval Others The request could not be executed successfully.
1097
1098 **/
1099 EFI_STATUS
1100 SdEraseBlockEnd (
1101 IN SD_DEVICE *Device,
1102 IN EFI_LBA EndLba,
1103 IN EFI_BLOCK_IO2_TOKEN *Token,
1104 IN BOOLEAN IsEnd
1105 )
1106 {
1107 EFI_STATUS Status;
1108 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1109 SD_REQUEST *EraseBlockEnd;
1110 EFI_TPL OldTpl;
1111
1112 EraseBlockEnd = NULL;
1113 PassThru = Device->Private->PassThru;
1114
1115 EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));
1116 if (EraseBlockEnd == NULL) {
1117 Status = EFI_OUT_OF_RESOURCES;
1118 goto Error;
1119 }
1120
1121 EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;
1122 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1123 InsertTailList (&Device->Queue, &EraseBlockEnd->Link);
1124 gBS->RestoreTPL (OldTpl);
1125 EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;
1126 EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
1127 EraseBlockEnd->Packet.Timeout = SD_GENERIC_TIMEOUT;
1128
1129 EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;
1130 EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1131 EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1132
1133 if (Device->SectorAddressing) {
1134 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
1135 } else {
1136 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->BlockMedia.BlockSize);
1137 }
1138
1139 EraseBlockEnd->IsEnd = IsEnd;
1140 EraseBlockEnd->Token = Token;
1141
1142 if ((Token != NULL) && (Token->Event != NULL)) {
1143 Status = gBS->CreateEvent (
1144 EVT_NOTIFY_SIGNAL,
1145 TPL_NOTIFY,
1146 AsyncIoCallback,
1147 EraseBlockEnd,
1148 &EraseBlockEnd->Event
1149 );
1150 if (EFI_ERROR (Status)) {
1151 goto Error;
1152 }
1153 } else {
1154 EraseBlockEnd->Event = NULL;
1155 }
1156
1157 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
1158
1159 Error:
1160 if ((Token != NULL) && (Token->Event != NULL)) {
1161 //
1162 // For asynchronous operation, only free request and event in error case.
1163 // The request and event will be freed in asynchronous callback for success case.
1164 //
1165 if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
1166 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1167 RemoveEntryList (&EraseBlockEnd->Link);
1168 gBS->RestoreTPL (OldTpl);
1169 if (EraseBlockEnd->Event != NULL) {
1170 gBS->CloseEvent (EraseBlockEnd->Event);
1171 }
1172 FreePool (EraseBlockEnd);
1173 }
1174 } else {
1175 //
1176 // For synchronous operation, free request whatever the execution result is.
1177 //
1178 if (EraseBlockEnd != NULL) {
1179 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1180 RemoveEntryList (&EraseBlockEnd->Link);
1181 gBS->RestoreTPL (OldTpl);
1182 FreePool (EraseBlockEnd);
1183 }
1184 }
1185
1186 return Status;
1187 }
1188
1189 /**
1190 Erase specified blocks through sync or async I/O request.
1191
1192 @param[in] Device A pointer to the SD_DEVICE instance.
1193 @param[in] Token A pointer to the token associated with the transaction.
1194 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1195 This parameter is only meaningful in async I/O request.
1196
1197 @retval EFI_SUCCESS The request is executed successfully.
1198 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1199 @retval Others The request could not be executed successfully.
1200
1201 **/
1202 EFI_STATUS
1203 SdEraseBlock (
1204 IN SD_DEVICE *Device,
1205 IN EFI_BLOCK_IO2_TOKEN *Token,
1206 IN BOOLEAN IsEnd
1207 )
1208 {
1209 EFI_STATUS Status;
1210 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1211 SD_REQUEST *EraseBlock;
1212 EFI_TPL OldTpl;
1213
1214 EraseBlock = NULL;
1215 PassThru = Device->Private->PassThru;
1216
1217 EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));
1218 if (EraseBlock == NULL) {
1219 Status = EFI_OUT_OF_RESOURCES;
1220 goto Error;
1221 }
1222
1223 EraseBlock->Signature = SD_REQUEST_SIGNATURE;
1224 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1225 InsertTailList (&Device->Queue, &EraseBlock->Link);
1226 gBS->RestoreTPL (OldTpl);
1227 EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;
1228 EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
1229 EraseBlock->Packet.Timeout = SD_GENERIC_TIMEOUT;
1230
1231 EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;
1232 EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1233 EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
1234
1235 EraseBlock->IsEnd = IsEnd;
1236 EraseBlock->Token = Token;
1237
1238 if ((Token != NULL) && (Token->Event != NULL)) {
1239 Status = gBS->CreateEvent (
1240 EVT_NOTIFY_SIGNAL,
1241 TPL_NOTIFY,
1242 AsyncIoCallback,
1243 EraseBlock,
1244 &EraseBlock->Event
1245 );
1246 if (EFI_ERROR (Status)) {
1247 goto Error;
1248 }
1249 } else {
1250 EraseBlock->Event = NULL;
1251 }
1252
1253 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
1254
1255 Error:
1256 if ((Token != NULL) && (Token->Event != NULL)) {
1257 //
1258 // For asynchronous operation, only free request and event in error case.
1259 // The request and event will be freed in asynchronous callback for success case.
1260 //
1261 if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
1262 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1263 RemoveEntryList (&EraseBlock->Link);
1264 gBS->RestoreTPL (OldTpl);
1265 if (EraseBlock->Event != NULL) {
1266 gBS->CloseEvent (EraseBlock->Event);
1267 }
1268 FreePool (EraseBlock);
1269 }
1270 } else {
1271 //
1272 // For synchronous operation, free request whatever the execution result is.
1273 //
1274 if (EraseBlock != NULL) {
1275 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1276 RemoveEntryList (&EraseBlock->Link);
1277 gBS->RestoreTPL (OldTpl);
1278 FreePool (EraseBlock);
1279 }
1280 }
1281
1282 return Status;
1283 }
1284
1285 /**
1286 Erase a specified number of device blocks.
1287
1288 @param[in] This Indicates a pointer to the calling context.
1289 @param[in] MediaId The media ID that the erase request is for.
1290 @param[in] Lba The starting logical block address to be
1291 erased. The caller is responsible for erasing
1292 only legitimate locations.
1293 @param[in, out] Token A pointer to the token associated with the
1294 transaction.
1295 @param[in] Size The size in bytes to be erased. This must be
1296 a multiple of the physical block size of the
1297 device.
1298
1299 @retval EFI_SUCCESS The erase request was queued if Event is not
1300 NULL. The data was erased correctly to the
1301 device if the Event is NULL.to the device.
1302 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1303 protection.
1304 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1305 to perform the erase operation.
1306 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1307 valid.
1308 @retval EFI_NO_MEDIA There is no media in the device.
1309 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1310
1311 **/
1312 EFI_STATUS
1313 EFIAPI
1314 SdEraseBlocks (
1315 IN EFI_ERASE_BLOCK_PROTOCOL *This,
1316 IN UINT32 MediaId,
1317 IN EFI_LBA Lba,
1318 IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
1319 IN UINTN Size
1320 )
1321 {
1322 EFI_STATUS Status;
1323 EFI_BLOCK_IO_MEDIA *Media;
1324 UINTN BlockSize;
1325 UINTN BlockNum;
1326 EFI_LBA LastLba;
1327 SD_DEVICE *Device;
1328
1329 Status = EFI_SUCCESS;
1330 Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);
1331 Media = &Device->BlockMedia;
1332
1333 if (MediaId != Media->MediaId) {
1334 return EFI_MEDIA_CHANGED;
1335 }
1336
1337 if (Media->ReadOnly) {
1338 return EFI_WRITE_PROTECTED;
1339 }
1340
1341 //
1342 // Check parameters.
1343 //
1344 BlockSize = Media->BlockSize;
1345 if ((Size % BlockSize) != 0) {
1346 return EFI_INVALID_PARAMETER;
1347 }
1348
1349 BlockNum = Size / BlockSize;
1350 if ((Lba + BlockNum - 1) > Media->LastBlock) {
1351 return EFI_INVALID_PARAMETER;
1352 }
1353
1354 if ((Token != NULL) && (Token->Event != NULL)) {
1355 Token->TransactionStatus = EFI_SUCCESS;
1356 }
1357
1358 LastLba = Lba + BlockNum - 1;
1359
1360 Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
1361 if (EFI_ERROR (Status)) {
1362 return Status;
1363 }
1364
1365 Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
1366 if (EFI_ERROR (Status)) {
1367 return Status;
1368 }
1369
1370 Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
1371 if (EFI_ERROR (Status)) {
1372 return Status;
1373 }
1374
1375 DEBUG ((EFI_D_ERROR, "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", Lba, BlockNum, Token->Event, Status));
1376
1377 return Status;
1378 }
1379