]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
MdeModulePkg/SdDxe: Fix potential NULL pointer access
[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 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 ((DEBUG_BLKIO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n",
674 IsRead ? "Read" : "Write", Lba, BlockNum,
675 (Token != NULL) ? Token->Event : NULL, Status));
676 Lba += BlockNum;
677 Buffer = (UINT8*)Buffer + BufferSize;
678 Remaining -= BlockNum;
679 }
680
681 return Status;
682 }
683
684 /**
685 Reset the Block Device.
686
687 @param This Indicates a pointer to the calling context.
688 @param ExtendedVerification Driver may perform diagnostics on reset.
689
690 @retval EFI_SUCCESS The device was reset.
691 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
692 not be reset.
693
694 **/
695 EFI_STATUS
696 EFIAPI
697 SdReset (
698 IN EFI_BLOCK_IO_PROTOCOL *This,
699 IN BOOLEAN ExtendedVerification
700 )
701 {
702 EFI_STATUS Status;
703 SD_DEVICE *Device;
704 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
705
706 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
707
708 PassThru = Device->Private->PassThru;
709 Status = PassThru->ResetDevice (PassThru, Device->Slot);
710 if (EFI_ERROR (Status)) {
711 Status = EFI_DEVICE_ERROR;
712 }
713
714 return Status;
715 }
716
717 /**
718 Read BufferSize bytes from Lba into Buffer.
719
720 @param This Indicates a pointer to the calling context.
721 @param MediaId Id of the media, changes every time the media is replaced.
722 @param Lba The starting Logical Block Address to read from
723 @param BufferSize Size of Buffer, must be a multiple of device block size.
724 @param Buffer A pointer to the destination buffer for the data. The caller is
725 responsible for either having implicit or explicit ownership of the buffer.
726
727 @retval EFI_SUCCESS The data was read correctly from the device.
728 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
729 @retval EFI_NO_MEDIA There is no media in the device.
730 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
731 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
732 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
733 or the buffer is not on proper alignment.
734
735 **/
736 EFI_STATUS
737 EFIAPI
738 SdReadBlocks (
739 IN EFI_BLOCK_IO_PROTOCOL *This,
740 IN UINT32 MediaId,
741 IN EFI_LBA Lba,
742 IN UINTN BufferSize,
743 OUT VOID *Buffer
744 )
745 {
746 EFI_STATUS Status;
747 SD_DEVICE *Device;
748
749 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
750
751 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);
752 return Status;
753 }
754
755 /**
756 Write BufferSize bytes from Lba into Buffer.
757
758 @param This Indicates a pointer to the calling context.
759 @param MediaId The media ID that the write request is for.
760 @param Lba The starting logical block address to be written. The caller is
761 responsible for writing to only legitimate locations.
762 @param BufferSize Size of Buffer, must be a multiple of device block size.
763 @param Buffer A pointer to the source buffer for the data.
764
765 @retval EFI_SUCCESS The data was written correctly to the device.
766 @retval EFI_WRITE_PROTECTED The device can not be written to.
767 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
768 @retval EFI_NO_MEDIA There is no media in the device.
769 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
770 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
771 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
772 or the buffer is not on proper alignment.
773
774 **/
775 EFI_STATUS
776 EFIAPI
777 SdWriteBlocks (
778 IN EFI_BLOCK_IO_PROTOCOL *This,
779 IN UINT32 MediaId,
780 IN EFI_LBA Lba,
781 IN UINTN BufferSize,
782 IN VOID *Buffer
783 )
784 {
785 EFI_STATUS Status;
786 SD_DEVICE *Device;
787
788 Device = SD_DEVICE_DATA_FROM_BLKIO (This);
789
790 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);
791 return Status;
792 }
793
794 /**
795 Flush the Block Device.
796
797 @param This Indicates a pointer to the calling context.
798
799 @retval EFI_SUCCESS All outstanding data was written to the device
800 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
801 @retval EFI_NO_MEDIA There is no media in the device.
802
803 **/
804 EFI_STATUS
805 EFIAPI
806 SdFlushBlocks (
807 IN EFI_BLOCK_IO_PROTOCOL *This
808 )
809 {
810 //
811 // return directly
812 //
813 return EFI_SUCCESS;
814 }
815
816 /**
817 Reset the Block Device.
818
819 @param[in] This Indicates a pointer to the calling context.
820 @param[in] ExtendedVerification Driver may perform diagnostics on reset.
821
822 @retval EFI_SUCCESS The device was reset.
823 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
824 not be reset.
825
826 **/
827 EFI_STATUS
828 EFIAPI
829 SdResetEx (
830 IN EFI_BLOCK_IO2_PROTOCOL *This,
831 IN BOOLEAN ExtendedVerification
832 )
833 {
834 SD_DEVICE *Device;
835 LIST_ENTRY *Link;
836 LIST_ENTRY *NextLink;
837 SD_REQUEST *Request;
838 EFI_TPL OldTpl;
839
840 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
841
842 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
843 for (Link = GetFirstNode (&Device->Queue);
844 !IsNull (&Device->Queue, Link);
845 Link = NextLink) {
846 NextLink = GetNextNode (&Device->Queue, Link);
847 RemoveEntryList (Link);
848
849 Request = SD_REQUEST_FROM_LINK (Link);
850
851 gBS->CloseEvent (Request->Event);
852 Request->Token->TransactionStatus = EFI_ABORTED;
853
854 if (Request->IsEnd) {
855 gBS->SignalEvent (Request->Token->Event);
856 }
857
858 FreePool (Request);
859 }
860 gBS->RestoreTPL (OldTpl);
861
862 return EFI_SUCCESS;
863 }
864
865 /**
866 Read BufferSize bytes from Lba into Buffer.
867
868 @param[in] This Indicates a pointer to the calling context.
869 @param[in] MediaId Id of the media, changes every time the media is replaced.
870 @param[in] Lba The starting Logical Block Address to read from.
871 @param[in, out] Token A pointer to the token associated with the transaction.
872 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
873 @param[out] Buffer A pointer to the destination buffer for the data. The caller is
874 responsible for either having implicit or explicit ownership of the buffer.
875
876 @retval EFI_SUCCESS The read request was queued if Event is not NULL.
877 The data was read correctly from the device if
878 the Event is NULL.
879 @retval EFI_DEVICE_ERROR The device reported an error while performing
880 the read.
881 @retval EFI_NO_MEDIA There is no media in the device.
882 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
883 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
884 intrinsic block size of the device.
885 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
886 or the buffer is not on proper alignment.
887 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
888 of resources.
889
890 **/
891 EFI_STATUS
892 EFIAPI
893 SdReadBlocksEx (
894 IN EFI_BLOCK_IO2_PROTOCOL *This,
895 IN UINT32 MediaId,
896 IN EFI_LBA Lba,
897 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
898 IN UINTN BufferSize,
899 OUT VOID *Buffer
900 )
901 {
902 EFI_STATUS Status;
903 SD_DEVICE *Device;
904
905 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
906
907 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);
908 return Status;
909 }
910
911 /**
912 Write BufferSize bytes from Lba into Buffer.
913
914 @param[in] This Indicates a pointer to the calling context.
915 @param[in] MediaId The media ID that the write request is for.
916 @param[in] Lba The starting logical block address to be written. The
917 caller is responsible for writing to only legitimate
918 locations.
919 @param[in, out] Token A pointer to the token associated with the transaction.
920 @param[in] BufferSize Size of Buffer, must be a multiple of device block size.
921 @param[in] Buffer A pointer to the source buffer for the data.
922
923 @retval EFI_SUCCESS The data was written correctly to the device.
924 @retval EFI_WRITE_PROTECTED The device can not be written to.
925 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
926 @retval EFI_NO_MEDIA There is no media in the device.
927 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
928 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
929 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
930 or the buffer is not on proper alignment.
931
932 **/
933 EFI_STATUS
934 EFIAPI
935 SdWriteBlocksEx (
936 IN EFI_BLOCK_IO2_PROTOCOL *This,
937 IN UINT32 MediaId,
938 IN EFI_LBA Lba,
939 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
940 IN UINTN BufferSize,
941 IN VOID *Buffer
942 )
943 {
944 EFI_STATUS Status;
945 SD_DEVICE *Device;
946
947 Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);
948
949 Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);
950 return Status;
951 }
952
953 /**
954 Flush the Block Device.
955
956 @param[in] This Indicates a pointer to the calling context.
957 @param[in, out] Token A pointer to the token associated with the transaction.
958
959 @retval EFI_SUCCESS All outstanding data was written to the device
960 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data
961 @retval EFI_NO_MEDIA There is no media in the device.
962
963 **/
964 EFI_STATUS
965 EFIAPI
966 SdFlushBlocksEx (
967 IN EFI_BLOCK_IO2_PROTOCOL *This,
968 IN OUT EFI_BLOCK_IO2_TOKEN *Token
969 )
970 {
971 //
972 // Signal event and return directly.
973 //
974 if (Token != NULL && Token->Event != NULL) {
975 Token->TransactionStatus = EFI_SUCCESS;
976 gBS->SignalEvent (Token->Event);
977 }
978
979 return EFI_SUCCESS;
980 }
981
982 /**
983 Set the erase start address through sync or async I/O request.
984
985 @param[in] Device A pointer to the SD_DEVICE instance.
986 @param[in] StartLba The starting logical block address to be erased.
987 @param[in] Token A pointer to the token associated with the transaction.
988 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
989 This parameter is only meaningful in async I/O request.
990
991 @retval EFI_SUCCESS The request is executed successfully.
992 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
993 @retval Others The request could not be executed successfully.
994
995 **/
996 EFI_STATUS
997 SdEraseBlockStart (
998 IN SD_DEVICE *Device,
999 IN EFI_LBA StartLba,
1000 IN EFI_BLOCK_IO2_TOKEN *Token,
1001 IN BOOLEAN IsEnd
1002 )
1003 {
1004 EFI_STATUS Status;
1005 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1006 SD_REQUEST *EraseBlockStart;
1007 EFI_TPL OldTpl;
1008
1009 EraseBlockStart = NULL;
1010 PassThru = Device->Private->PassThru;
1011
1012 EraseBlockStart = AllocateZeroPool (sizeof (SD_REQUEST));
1013 if (EraseBlockStart == NULL) {
1014 Status = EFI_OUT_OF_RESOURCES;
1015 goto Error;
1016 }
1017
1018 EraseBlockStart->Signature = SD_REQUEST_SIGNATURE;
1019 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1020 InsertTailList (&Device->Queue, &EraseBlockStart->Link);
1021 gBS->RestoreTPL (OldTpl);
1022 EraseBlockStart->Packet.SdMmcCmdBlk = &EraseBlockStart->SdMmcCmdBlk;
1023 EraseBlockStart->Packet.SdMmcStatusBlk = &EraseBlockStart->SdMmcStatusBlk;
1024 EraseBlockStart->Packet.Timeout = SD_GENERIC_TIMEOUT;
1025
1026 EraseBlockStart->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_START;
1027 EraseBlockStart->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1028 EraseBlockStart->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1029
1030 if (Device->SectorAddressing) {
1031 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)StartLba;
1032 } else {
1033 EraseBlockStart->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (StartLba, Device->BlockMedia.BlockSize);
1034 }
1035
1036 EraseBlockStart->IsEnd = IsEnd;
1037 EraseBlockStart->Token = Token;
1038
1039 if ((Token != NULL) && (Token->Event != NULL)) {
1040 Status = gBS->CreateEvent (
1041 EVT_NOTIFY_SIGNAL,
1042 TPL_NOTIFY,
1043 AsyncIoCallback,
1044 EraseBlockStart,
1045 &EraseBlockStart->Event
1046 );
1047 if (EFI_ERROR (Status)) {
1048 goto Error;
1049 }
1050 } else {
1051 EraseBlockStart->Event = NULL;
1052 }
1053
1054 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockStart->Packet, EraseBlockStart->Event);
1055
1056 Error:
1057 if ((Token != NULL) && (Token->Event != NULL)) {
1058 //
1059 // For asynchronous operation, only free request and event in error case.
1060 // The request and event will be freed in asynchronous callback for success case.
1061 //
1062 if (EFI_ERROR (Status) && (EraseBlockStart != NULL)) {
1063 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1064 RemoveEntryList (&EraseBlockStart->Link);
1065 gBS->RestoreTPL (OldTpl);
1066 if (EraseBlockStart->Event != NULL) {
1067 gBS->CloseEvent (EraseBlockStart->Event);
1068 }
1069 FreePool (EraseBlockStart);
1070 }
1071 } else {
1072 //
1073 // For synchronous operation, free request whatever the execution result is.
1074 //
1075 if (EraseBlockStart != NULL) {
1076 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1077 RemoveEntryList (&EraseBlockStart->Link);
1078 gBS->RestoreTPL (OldTpl);
1079 FreePool (EraseBlockStart);
1080 }
1081 }
1082
1083 return Status;
1084 }
1085
1086 /**
1087 Set the erase end address through sync or async I/O request.
1088
1089 @param[in] Device A pointer to the SD_DEVICE instance.
1090 @param[in] EndLba The ending logical block address to be erased.
1091 @param[in] Token A pointer to the token associated with the transaction.
1092 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1093 This parameter is only meaningful in async I/O request.
1094
1095 @retval EFI_SUCCESS The request is executed successfully.
1096 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1097 @retval Others The request could not be executed successfully.
1098
1099 **/
1100 EFI_STATUS
1101 SdEraseBlockEnd (
1102 IN SD_DEVICE *Device,
1103 IN EFI_LBA EndLba,
1104 IN EFI_BLOCK_IO2_TOKEN *Token,
1105 IN BOOLEAN IsEnd
1106 )
1107 {
1108 EFI_STATUS Status;
1109 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1110 SD_REQUEST *EraseBlockEnd;
1111 EFI_TPL OldTpl;
1112
1113 EraseBlockEnd = NULL;
1114 PassThru = Device->Private->PassThru;
1115
1116 EraseBlockEnd = AllocateZeroPool (sizeof (SD_REQUEST));
1117 if (EraseBlockEnd == NULL) {
1118 Status = EFI_OUT_OF_RESOURCES;
1119 goto Error;
1120 }
1121
1122 EraseBlockEnd->Signature = SD_REQUEST_SIGNATURE;
1123 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1124 InsertTailList (&Device->Queue, &EraseBlockEnd->Link);
1125 gBS->RestoreTPL (OldTpl);
1126 EraseBlockEnd->Packet.SdMmcCmdBlk = &EraseBlockEnd->SdMmcCmdBlk;
1127 EraseBlockEnd->Packet.SdMmcStatusBlk = &EraseBlockEnd->SdMmcStatusBlk;
1128 EraseBlockEnd->Packet.Timeout = SD_GENERIC_TIMEOUT;
1129
1130 EraseBlockEnd->SdMmcCmdBlk.CommandIndex = SD_ERASE_WR_BLK_END;
1131 EraseBlockEnd->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1132 EraseBlockEnd->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
1133
1134 if (Device->SectorAddressing) {
1135 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)EndLba;
1136 } else {
1137 EraseBlockEnd->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (EndLba, Device->BlockMedia.BlockSize);
1138 }
1139
1140 EraseBlockEnd->IsEnd = IsEnd;
1141 EraseBlockEnd->Token = Token;
1142
1143 if ((Token != NULL) && (Token->Event != NULL)) {
1144 Status = gBS->CreateEvent (
1145 EVT_NOTIFY_SIGNAL,
1146 TPL_NOTIFY,
1147 AsyncIoCallback,
1148 EraseBlockEnd,
1149 &EraseBlockEnd->Event
1150 );
1151 if (EFI_ERROR (Status)) {
1152 goto Error;
1153 }
1154 } else {
1155 EraseBlockEnd->Event = NULL;
1156 }
1157
1158 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlockEnd->Packet, EraseBlockEnd->Event);
1159
1160 Error:
1161 if ((Token != NULL) && (Token->Event != NULL)) {
1162 //
1163 // For asynchronous operation, only free request and event in error case.
1164 // The request and event will be freed in asynchronous callback for success case.
1165 //
1166 if (EFI_ERROR (Status) && (EraseBlockEnd != NULL)) {
1167 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1168 RemoveEntryList (&EraseBlockEnd->Link);
1169 gBS->RestoreTPL (OldTpl);
1170 if (EraseBlockEnd->Event != NULL) {
1171 gBS->CloseEvent (EraseBlockEnd->Event);
1172 }
1173 FreePool (EraseBlockEnd);
1174 }
1175 } else {
1176 //
1177 // For synchronous operation, free request whatever the execution result is.
1178 //
1179 if (EraseBlockEnd != NULL) {
1180 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1181 RemoveEntryList (&EraseBlockEnd->Link);
1182 gBS->RestoreTPL (OldTpl);
1183 FreePool (EraseBlockEnd);
1184 }
1185 }
1186
1187 return Status;
1188 }
1189
1190 /**
1191 Erase specified blocks through sync or async I/O request.
1192
1193 @param[in] Device A pointer to the SD_DEVICE instance.
1194 @param[in] Token A pointer to the token associated with the transaction.
1195 @param[in] IsEnd A boolean to show whether it's the last cmd in a series of cmds.
1196 This parameter is only meaningful in async I/O request.
1197
1198 @retval EFI_SUCCESS The request is executed successfully.
1199 @retval EFI_OUT_OF_RESOURCES The request could not be executed due to a lack of resources.
1200 @retval Others The request could not be executed successfully.
1201
1202 **/
1203 EFI_STATUS
1204 SdEraseBlock (
1205 IN SD_DEVICE *Device,
1206 IN EFI_BLOCK_IO2_TOKEN *Token,
1207 IN BOOLEAN IsEnd
1208 )
1209 {
1210 EFI_STATUS Status;
1211 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;
1212 SD_REQUEST *EraseBlock;
1213 EFI_TPL OldTpl;
1214
1215 EraseBlock = NULL;
1216 PassThru = Device->Private->PassThru;
1217
1218 EraseBlock = AllocateZeroPool (sizeof (SD_REQUEST));
1219 if (EraseBlock == NULL) {
1220 Status = EFI_OUT_OF_RESOURCES;
1221 goto Error;
1222 }
1223
1224 EraseBlock->Signature = SD_REQUEST_SIGNATURE;
1225 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1226 InsertTailList (&Device->Queue, &EraseBlock->Link);
1227 gBS->RestoreTPL (OldTpl);
1228 EraseBlock->Packet.SdMmcCmdBlk = &EraseBlock->SdMmcCmdBlk;
1229 EraseBlock->Packet.SdMmcStatusBlk = &EraseBlock->SdMmcStatusBlk;
1230 EraseBlock->Packet.Timeout = SD_GENERIC_TIMEOUT;
1231
1232 EraseBlock->SdMmcCmdBlk.CommandIndex = SD_ERASE;
1233 EraseBlock->SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;
1234 EraseBlock->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
1235
1236 EraseBlock->IsEnd = IsEnd;
1237 EraseBlock->Token = Token;
1238
1239 if ((Token != NULL) && (Token->Event != NULL)) {
1240 Status = gBS->CreateEvent (
1241 EVT_NOTIFY_SIGNAL,
1242 TPL_NOTIFY,
1243 AsyncIoCallback,
1244 EraseBlock,
1245 &EraseBlock->Event
1246 );
1247 if (EFI_ERROR (Status)) {
1248 goto Error;
1249 }
1250 } else {
1251 EraseBlock->Event = NULL;
1252 }
1253
1254 Status = PassThru->PassThru (PassThru, Device->Slot, &EraseBlock->Packet, EraseBlock->Event);
1255
1256 Error:
1257 if ((Token != NULL) && (Token->Event != NULL)) {
1258 //
1259 // For asynchronous operation, only free request and event in error case.
1260 // The request and event will be freed in asynchronous callback for success case.
1261 //
1262 if (EFI_ERROR (Status) && (EraseBlock != NULL)) {
1263 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1264 RemoveEntryList (&EraseBlock->Link);
1265 gBS->RestoreTPL (OldTpl);
1266 if (EraseBlock->Event != NULL) {
1267 gBS->CloseEvent (EraseBlock->Event);
1268 }
1269 FreePool (EraseBlock);
1270 }
1271 } else {
1272 //
1273 // For synchronous operation, free request whatever the execution result is.
1274 //
1275 if (EraseBlock != NULL) {
1276 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1277 RemoveEntryList (&EraseBlock->Link);
1278 gBS->RestoreTPL (OldTpl);
1279 FreePool (EraseBlock);
1280 }
1281 }
1282
1283 return Status;
1284 }
1285
1286 /**
1287 Erase a specified number of device blocks.
1288
1289 @param[in] This Indicates a pointer to the calling context.
1290 @param[in] MediaId The media ID that the erase request is for.
1291 @param[in] Lba The starting logical block address to be
1292 erased. The caller is responsible for erasing
1293 only legitimate locations.
1294 @param[in, out] Token A pointer to the token associated with the
1295 transaction.
1296 @param[in] Size The size in bytes to be erased. This must be
1297 a multiple of the physical block size of the
1298 device.
1299
1300 @retval EFI_SUCCESS The erase request was queued if Event is not
1301 NULL. The data was erased correctly to the
1302 device if the Event is NULL.to the device.
1303 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write
1304 protection.
1305 @retval EFI_DEVICE_ERROR The device reported an error while attempting
1306 to perform the erase operation.
1307 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not
1308 valid.
1309 @retval EFI_NO_MEDIA There is no media in the device.
1310 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1311
1312 **/
1313 EFI_STATUS
1314 EFIAPI
1315 SdEraseBlocks (
1316 IN EFI_ERASE_BLOCK_PROTOCOL *This,
1317 IN UINT32 MediaId,
1318 IN EFI_LBA Lba,
1319 IN OUT EFI_ERASE_BLOCK_TOKEN *Token,
1320 IN UINTN Size
1321 )
1322 {
1323 EFI_STATUS Status;
1324 EFI_BLOCK_IO_MEDIA *Media;
1325 UINTN BlockSize;
1326 UINTN BlockNum;
1327 EFI_LBA LastLba;
1328 SD_DEVICE *Device;
1329
1330 Status = EFI_SUCCESS;
1331 Device = SD_DEVICE_DATA_FROM_ERASEBLK (This);
1332 Media = &Device->BlockMedia;
1333
1334 if (MediaId != Media->MediaId) {
1335 return EFI_MEDIA_CHANGED;
1336 }
1337
1338 if (Media->ReadOnly) {
1339 return EFI_WRITE_PROTECTED;
1340 }
1341
1342 //
1343 // Check parameters.
1344 //
1345 BlockSize = Media->BlockSize;
1346 if ((Size % BlockSize) != 0) {
1347 return EFI_INVALID_PARAMETER;
1348 }
1349
1350 BlockNum = Size / BlockSize;
1351 if ((Lba + BlockNum - 1) > Media->LastBlock) {
1352 return EFI_INVALID_PARAMETER;
1353 }
1354
1355 if ((Token != NULL) && (Token->Event != NULL)) {
1356 Token->TransactionStatus = EFI_SUCCESS;
1357 }
1358
1359 LastLba = Lba + BlockNum - 1;
1360
1361 Status = SdEraseBlockStart (Device, Lba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
1362 if (EFI_ERROR (Status)) {
1363 return Status;
1364 }
1365
1366 Status = SdEraseBlockEnd (Device, LastLba, (EFI_BLOCK_IO2_TOKEN*)Token, FALSE);
1367 if (EFI_ERROR (Status)) {
1368 return Status;
1369 }
1370
1371 Status = SdEraseBlock (Device, (EFI_BLOCK_IO2_TOKEN*)Token, TRUE);
1372 if (EFI_ERROR (Status)) {
1373 return Status;
1374 }
1375
1376 DEBUG ((EFI_D_ERROR, "SdEraseBlocks(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", Lba, BlockNum, Token->Event, Status));
1377
1378 return Status;
1379 }
1380