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